Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(493)

Side by Side Diff: content/browser/renderer_host/media/audio_input_sync_writer.cc

Issue 1302423006: Ensure that data is not overwritten in the audio input shared memory ring buffer that sits on the b… (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Code review and rebase. Added unit test, and refactorings for that. Created 5 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "content/browser/renderer_host/media/audio_input_sync_writer.h" 5 #include "content/browser/renderer_host/media/audio_input_sync_writer.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 8
9 #include "base/memory/shared_memory.h" 9 #include "base/metrics/histogram.h"
10 #include "base/strings/stringprintf.h"
10 #include "content/browser/renderer_host/media/media_stream_manager.h" 11 #include "content/browser/renderer_host/media/media_stream_manager.h"
11 12
12 using media::AudioBus; 13 using media::AudioBus;
13 14
14 namespace content { 15 namespace content {
15 16
16 AudioInputSyncWriter::AudioInputSyncWriter(base::SharedMemory* shared_memory, 17 namespace {
18
19 // TODO BEFORE COMMIT: Which value makes sense? I.e. how long can we accept
20 // blocking the soundcard thread and wait before dropping data.
21 const base::TimeDelta kReadCheckTimeout =
DaleCurtis 2015/09/02 16:18:50 This is a static initializer, you'll need to keep
Henrik Grunell 2015/09/03 14:32:33 I've removed this and changed the verification alg
22 base::TimeDelta::FromMilliseconds(10);
23
24 // Used to log if any audio glitches have been detected during an audio session.
25 // Elements in this enum should not be added, deleted or rearranged.
26 enum AudioGlitchResult {
27 AUDIO_CAPTURER_NO_AUDIO_GLITCHES = 0,
28 AUDIO_CAPTURER_AUDIO_GLITCHES = 1,
29 AUDIO_CAPTURER_AUDIO_GLITCHES_MAX = AUDIO_CAPTURER_AUDIO_GLITCHES
30 };
31
32 } // namespace
33
34 AudioInputSyncWriter::AudioInputSyncWriter(void* shared_memory,
35 size_t shared_memory_size,
17 int shared_memory_segment_count, 36 int shared_memory_segment_count,
18 const media::AudioParameters& params) 37 const media::AudioParameters& params)
19 : shared_memory_(shared_memory), 38 : shared_memory_(static_cast<uint8*>(shared_memory)),
20 shared_memory_segment_count_(shared_memory_segment_count), 39 shared_memory_segment_count_(shared_memory_segment_count),
21 current_segment_id_(0), 40 current_segment_id_(0),
22 creation_time_(base::Time::Now()), 41 creation_time_(base::Time::Now()),
23 audio_bus_memory_size_(AudioBus::CalculateMemorySize(params)), 42 audio_bus_memory_size_(AudioBus::CalculateMemorySize(params)),
24 next_buffer_id_(0) { 43 next_buffer_id_(0),
44 next_read_buffer_index_(0),
45 expected_buffer_reads_(0),
46 read_verification_count_(0),
47 read_verification_error_count_(0) {
25 DCHECK_GT(shared_memory_segment_count, 0); 48 DCHECK_GT(shared_memory_segment_count, 0);
26 DCHECK_EQ(shared_memory->requested_size() % shared_memory_segment_count, 0u); 49 DCHECK_EQ(shared_memory_size % shared_memory_segment_count, 0u);
27 shared_memory_segment_size_ = 50 shared_memory_segment_size_ =
28 shared_memory->requested_size() / shared_memory_segment_count; 51 shared_memory_size / shared_memory_segment_count;
29 DVLOG(1) << "SharedMemory::requested_size: " 52 DVLOG(1) << "shared_memory_size: " << shared_memory_size;
30 << shared_memory->requested_size();
31 DVLOG(1) << "shared_memory_segment_count: " << shared_memory_segment_count; 53 DVLOG(1) << "shared_memory_segment_count: " << shared_memory_segment_count;
32 DVLOG(1) << "audio_bus_memory_size: " << audio_bus_memory_size_; 54 DVLOG(1) << "audio_bus_memory_size: " << audio_bus_memory_size_;
33 55
34 // Create vector of audio buses by wrapping existing blocks of memory. 56 // Create vector of audio buses by wrapping existing blocks of memory.
35 uint8* ptr = static_cast<uint8*>(shared_memory_->memory()); 57 uint8* ptr = shared_memory_;
36 for (int i = 0; i < shared_memory_segment_count; ++i) { 58 for (int i = 0; i < shared_memory_segment_count; ++i) {
37 CHECK((reinterpret_cast<uintptr_t>(ptr) & 59 CHECK((reinterpret_cast<uintptr_t>(ptr) &
38 (media::AudioBus::kChannelAlignment - 1)) == 0U); 60 (media::AudioBus::kChannelAlignment - 1)) == 0U);
39 media::AudioInputBuffer* buffer = 61 media::AudioInputBuffer* buffer =
40 reinterpret_cast<media::AudioInputBuffer*>(ptr); 62 reinterpret_cast<media::AudioInputBuffer*>(ptr);
41 scoped_ptr<media::AudioBus> audio_bus = 63 scoped_ptr<media::AudioBus> audio_bus =
42 media::AudioBus::WrapMemory(params, buffer->audio); 64 media::AudioBus::WrapMemory(params, buffer->audio);
43 audio_buses_.push_back(audio_bus.release()); 65 audio_buses_.push_back(audio_bus.release());
44 ptr += shared_memory_segment_size_; 66 ptr += shared_memory_segment_size_;
45 } 67 }
46 } 68 }
47 69
48 AudioInputSyncWriter::~AudioInputSyncWriter() {} 70 AudioInputSyncWriter::~AudioInputSyncWriter() {
71 if (read_verification_count_ == 0)
72 return;
73
74 UMA_HISTOGRAM_PERCENTAGE(
75 "Media.AudioCapturerMissedReadDeadline",
76 100.0 * read_verification_error_count_ / read_verification_count_);
77
78 UMA_HISTOGRAM_ENUMERATION("Media.AudioCapturerAudioGlitches",
79 read_verification_error_count_ == 0 ?
80 AUDIO_CAPTURER_NO_AUDIO_GLITCHES :
81 AUDIO_CAPTURER_AUDIO_GLITCHES,
82 AUDIO_CAPTURER_AUDIO_GLITCHES_MAX + 1);
83
84 std::string log_string = base::StringPrintf(
85 "AISW: number of detected audio glitches: %lu out of %lu",
86 read_verification_error_count_,
87 read_verification_count_);
88 MediaStreamManager::SendMessageToNativeLog(log_string);
89 DVLOG(1) << log_string;
90 }
49 91
50 void AudioInputSyncWriter::Write(const media::AudioBus* data, 92 void AudioInputSyncWriter::Write(const media::AudioBus* data,
51 double volume, 93 double volume,
52 bool key_pressed, 94 bool key_pressed,
53 uint32 hardware_delay_bytes) { 95 uint32 hardware_delay_bytes) {
54 #if !defined(OS_ANDROID) 96 #if !defined(OS_ANDROID)
55 static const base::TimeDelta kLogDelayThreadhold = 97 static const base::TimeDelta kLogDelayThreadhold =
56 base::TimeDelta::FromMilliseconds(500); 98 base::TimeDelta::FromMilliseconds(500);
57 99
58 std::ostringstream oss; 100 std::ostringstream oss;
59 if (last_write_time_.is_null()) { 101 if (last_write_time_.is_null()) {
60 // This is the first time Write is called. 102 // This is the first time Write is called.
61 base::TimeDelta interval = base::Time::Now() - creation_time_; 103 base::TimeDelta interval = base::Time::Now() - creation_time_;
62 oss << "AISW::Write: audio input data received for the first time: delay " 104 oss << "AISW::Write: audio input data received for the first time: delay "
63 "= " << interval.InMilliseconds() << "ms"; 105 "= " << interval.InMilliseconds() << "ms";
64 106
65 } else { 107 } else {
66 base::TimeDelta interval = base::Time::Now() - last_write_time_; 108 base::TimeDelta interval = base::Time::Now() - last_write_time_;
67 if (interval > kLogDelayThreadhold) { 109 if (interval > kLogDelayThreadhold) {
68 oss << "AISW::Write: audio input data delay unexpectedly long: delay = " 110 oss << "AISW::Write: audio input data delay unexpectedly long: delay = "
69 << interval.InMilliseconds() << "ms"; 111 << interval.InMilliseconds() << "ms";
70 } 112 }
71 } 113 }
72 if (!oss.str().empty()) { 114 if (!oss.str().empty()) {
73 MediaStreamManager::SendMessageToNativeLog(oss.str()); 115 AddToNativeLog(oss.str());
74 DVLOG(1) << oss.str(); 116 DVLOG(1) << oss.str();
75 } 117 }
76 118
77 last_write_time_ = base::Time::Now(); 119 last_write_time_ = base::Time::Now();
78 #endif 120 #endif
79 121
122 // Check that the renderer side has read data so that we don't overwrite.
123 // The renderer side sends a signal over the socket each time it has read
124 // data. Here, we count the number of reads we expect to have been done. When
125 // we reach |shared_memory_segment_count_|, we do a socket receive, which
126 // normally is in queue. If we timeout, there's a problem with being able to
127 // read at the high enough pace, and we throw away the audio buffer.
128 if (expected_buffer_reads_ ==
129 static_cast<int>(shared_memory_segment_count_)) {
130 ++read_verification_count_;
131 ++next_read_buffer_index_;
132 size_t bytes_received = 0;
133 uint32 index_read = 0;
134 bytes_received = socket_->ReceiveWithTimeout(
DaleCurtis 2015/09/02 16:18:50 This will work, but I suspect during periods of hi
Henrik Grunell 2015/09/03 14:32:33 It can't really work like on the output side since
135 &index_read, sizeof(index_read), kReadCheckTimeout);
136 if (bytes_received != sizeof(index_read)) {
137 const std::string error_message =
138 "Verifying shared memory read timed out. Dropping audio data.";
139 LOG(ERROR) << error_message;
140 AddToNativeLog(error_message);
141 ++read_verification_error_count_;
142 return;
143 } else if (index_read != next_read_buffer_index_) {
DaleCurtis 2015/09/02 16:18:50 Hmm, this should never happen right? I think this
Henrik Grunell 2015/09/03 14:32:33 Right, done.
144 const std::string error_message = base::StringPrintf(
145 "Shared memory read index mismatch. Expected = %u. Actual = %u",
146 next_read_buffer_index_, index_read);
147 LOG(ERROR) << error_message;
148 AddToNativeLog(error_message);
149 ++read_verification_error_count_;
150 next_read_buffer_index_ = index_read + 1;
151 }
152 --expected_buffer_reads_;
153 DCHECK_GE(expected_buffer_reads_, 0);
154 }
155
80 // Write audio parameters to shared memory. 156 // Write audio parameters to shared memory.
81 uint8* ptr = static_cast<uint8*>(shared_memory_->memory()); 157 uint8* ptr = shared_memory_;
82 ptr += current_segment_id_ * shared_memory_segment_size_; 158 ptr += current_segment_id_ * shared_memory_segment_size_;
83 media::AudioInputBuffer* buffer = 159 media::AudioInputBuffer* buffer =
84 reinterpret_cast<media::AudioInputBuffer*>(ptr); 160 reinterpret_cast<media::AudioInputBuffer*>(ptr);
85 buffer->params.volume = volume; 161 buffer->params.volume = volume;
86 buffer->params.size = audio_bus_memory_size_; 162 buffer->params.size = audio_bus_memory_size_;
87 buffer->params.key_pressed = key_pressed; 163 buffer->params.key_pressed = key_pressed;
88 buffer->params.hardware_delay_bytes = hardware_delay_bytes; 164 buffer->params.hardware_delay_bytes = hardware_delay_bytes;
89 buffer->params.id = next_buffer_id_++; 165 buffer->params.id = next_buffer_id_++;
90 166
91 // Copy data from the native audio layer into shared memory using pre- 167 // Copy data from the native audio layer into shared memory using pre-
92 // allocated audio buses. 168 // allocated audio buses.
93 media::AudioBus* audio_bus = audio_buses_[current_segment_id_]; 169 media::AudioBus* audio_bus = audio_buses_[current_segment_id_];
94 data->CopyTo(audio_bus); 170 data->CopyTo(audio_bus);
95 171
96 socket_->Send(&current_segment_id_, sizeof(current_segment_id_)); 172 socket_->Send(&current_segment_id_, sizeof(current_segment_id_));
97 173
98 if (++current_segment_id_ >= shared_memory_segment_count_) 174 if (++current_segment_id_ >= shared_memory_segment_count_)
99 current_segment_id_ = 0; 175 current_segment_id_ = 0;
176
177 ++expected_buffer_reads_;
178 DCHECK_LE(expected_buffer_reads_,
179 static_cast<int>(shared_memory_segment_count_));
100 } 180 }
101 181
102 void AudioInputSyncWriter::Close() { 182 void AudioInputSyncWriter::Close() {
103 socket_->Close(); 183 socket_->Close();
104 } 184 }
105 185
106 bool AudioInputSyncWriter::Init() { 186 bool AudioInputSyncWriter::Init() {
107 socket_.reset(new base::CancelableSyncSocket()); 187 socket_.reset(new base::CancelableSyncSocket());
108 foreign_socket_.reset(new base::CancelableSyncSocket()); 188 foreign_socket_.reset(new base::CancelableSyncSocket());
109 return base::CancelableSyncSocket::CreatePair(socket_.get(), 189 return base::CancelableSyncSocket::CreatePair(socket_.get(),
110 foreign_socket_.get()); 190 foreign_socket_.get());
111 } 191 }
112 192
113 bool AudioInputSyncWriter::PrepareForeignSocket( 193 bool AudioInputSyncWriter::PrepareForeignSocket(
114 base::ProcessHandle process_handle, 194 base::ProcessHandle process_handle,
115 base::SyncSocket::TransitDescriptor* descriptor) { 195 base::SyncSocket::TransitDescriptor* descriptor) {
116 return foreign_socket_->PrepareTransitDescriptor(process_handle, descriptor); 196 return foreign_socket_->PrepareTransitDescriptor(process_handle, descriptor);
117 } 197 }
118 198
199 void AudioInputSyncWriter::AddToNativeLog(const std::string& message) {
200 MediaStreamManager::SendMessageToNativeLog(message);
201 }
119 202
120 } // namespace content 203 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698