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

Side by Side Diff: content/renderer/media/audio_input_device.cc

Issue 9702019: Adds Analog Gain Control (AGC) to the WebRTC client. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Improved AGC comments Created 8 years, 9 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 | Annotate | Revision Log
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/renderer/media/audio_input_device.h" 5 #include "content/renderer/media/audio_input_device.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/message_loop.h" 8 #include "base/message_loop.h"
9 #include "base/threading/thread_restrictions.h" 9 #include "base/threading/thread_restrictions.h"
10 #include "base/time.h" 10 #include "base/time.h"
(...skipping 29 matching lines...) Expand all
40 AudioInputDevice::AudioInputDevice(const AudioParameters& params, 40 AudioInputDevice::AudioInputDevice(const AudioParameters& params,
41 CaptureCallback* callback, 41 CaptureCallback* callback,
42 CaptureEventHandler* event_handler) 42 CaptureEventHandler* event_handler)
43 : ScopedLoopObserver(ChildProcess::current()->io_message_loop()), 43 : ScopedLoopObserver(ChildProcess::current()->io_message_loop()),
44 audio_parameters_(params), 44 audio_parameters_(params),
45 callback_(callback), 45 callback_(callback),
46 event_handler_(event_handler), 46 event_handler_(event_handler),
47 volume_(1.0), 47 volume_(1.0),
48 stream_id_(0), 48 stream_id_(0),
49 session_id_(0), 49 session_id_(0),
50 pending_device_ready_(false) { 50 pending_device_ready_(false),
51 agc_is_enabled_(false) {
tommi (sloooow) - chröme 2012/03/26 15:26:40 indent is off.
henrika (OOO until Aug 14) 2012/03/27 09:20:38 Done.
51 filter_ = RenderThreadImpl::current()->audio_input_message_filter(); 52 filter_ = RenderThreadImpl::current()->audio_input_message_filter();
52 } 53 }
53 54
54 AudioInputDevice::~AudioInputDevice() { 55 AudioInputDevice::~AudioInputDevice() {
55 // TODO(henrika): The current design requires that the user calls 56 // TODO(henrika): The current design requires that the user calls
56 // Stop before deleting this class. 57 // Stop before deleting this class.
57 CHECK_EQ(0, stream_id_); 58 CHECK_EQ(0, stream_id_);
58 } 59 }
59 60
60 void AudioInputDevice::Start() { 61 void AudioInputDevice::Start() {
(...skipping 14 matching lines...) Expand all
75 { 76 {
76 base::AutoLock auto_lock(audio_thread_lock_); 77 base::AutoLock auto_lock(audio_thread_lock_);
77 audio_thread_.Stop(MessageLoop::current()); 78 audio_thread_.Stop(MessageLoop::current());
78 } 79 }
79 80
80 message_loop()->PostTask(FROM_HERE, 81 message_loop()->PostTask(FROM_HERE,
81 base::Bind(&AudioInputDevice::ShutDownOnIOThread, this)); 82 base::Bind(&AudioInputDevice::ShutDownOnIOThread, this));
82 } 83 }
83 84
84 bool AudioInputDevice::SetVolume(double volume) { 85 bool AudioInputDevice::SetVolume(double volume) {
85 NOTIMPLEMENTED(); 86 if (volume < 0 || volume > 1.0)
87 return false;
88
89 message_loop()->PostTask(FROM_HERE,
90 base::Bind(&AudioInputDevice::SetVolumeOnIOThread, this, volume));
91
92 return true;
93 }
94
95 bool AudioInputDevice::GetVolume(double* volume) {
96 NOTREACHED();
86 return false; 97 return false;
87 } 98 }
88 99
89 bool AudioInputDevice::GetVolume(double* volume) { 100 void AudioInputDevice::SetAutomaticGainControl(bool enabled) {
90 NOTIMPLEMENTED(); 101 DVLOG(1) << "SetAutomaticGainControl(enabled=" << enabled << ")";
91 return false; 102 message_loop()->PostTask(FROM_HERE,
103 base::Bind(&AudioInputDevice::SetAutomaticGainControlOnIOThread,
104 this, enabled));
92 } 105 }
93 106
94 void AudioInputDevice::InitializeOnIOThread() { 107 void AudioInputDevice::InitializeOnIOThread() {
95 DCHECK(message_loop()->BelongsToCurrentThread()); 108 DCHECK(message_loop()->BelongsToCurrentThread());
96 // Make sure we don't call Start() more than once. 109 // Make sure we don't call Start() more than once.
97 DCHECK_EQ(0, stream_id_); 110 DCHECK_EQ(0, stream_id_);
98 if (stream_id_) 111 if (stream_id_)
99 return; 112 return;
100 113
101 stream_id_ = filter_->AddDelegate(this); 114 stream_id_ = filter_->AddDelegate(this);
102 // If |session_id_| is not specified, it will directly create the stream; 115 // If |session_id_| is not specified, it will directly create the stream;
103 // otherwise it will send a AudioInputHostMsg_StartDevice msg to the browser 116 // otherwise it will send a AudioInputHostMsg_StartDevice msg to the browser
104 // and create the stream when getting a OnDeviceReady() callback. 117 // and create the stream when getting a OnDeviceReady() callback.
105 if (!session_id_) { 118 if (!session_id_) {
106 Send(new AudioInputHostMsg_CreateStream( 119 Send(new AudioInputHostMsg_CreateStream(
107 stream_id_, audio_parameters_, AudioManagerBase::kDefaultDeviceId)); 120 stream_id_, audio_parameters_, AudioManagerBase::kDefaultDeviceId,
121 agc_is_enabled_));
108 } else { 122 } else {
109 Send(new AudioInputHostMsg_StartDevice(stream_id_, session_id_)); 123 Send(new AudioInputHostMsg_StartDevice(stream_id_, session_id_));
110 pending_device_ready_ = true; 124 pending_device_ready_ = true;
111 } 125 }
112 } 126 }
113 127
114 void AudioInputDevice::SetSessionIdOnIOThread(int session_id) { 128 void AudioInputDevice::SetSessionIdOnIOThread(int session_id) {
115 DCHECK(message_loop()->BelongsToCurrentThread()); 129 DCHECK(message_loop()->BelongsToCurrentThread());
116 session_id_ = session_id; 130 session_id_ = session_id;
117 } 131 }
118 132
119 void AudioInputDevice::StartOnIOThread() { 133 void AudioInputDevice::StartOnIOThread() {
120 DCHECK(message_loop()->BelongsToCurrentThread()); 134 DCHECK(message_loop()->BelongsToCurrentThread());
121 if (stream_id_) 135 if (stream_id_)
122 Send(new AudioInputHostMsg_RecordStream(stream_id_)); 136 Send(new AudioInputHostMsg_RecordStream(stream_id_));
123 } 137 }
124 138
125 void AudioInputDevice::ShutDownOnIOThread() { 139 void AudioInputDevice::ShutDownOnIOThread() {
126 DCHECK(message_loop()->BelongsToCurrentThread()); 140 DCHECK(message_loop()->BelongsToCurrentThread());
127 // NOTE: |completion| may be NULL. 141 // NOTE: |completion| may be NULL.
128 // Make sure we don't call shutdown more than once. 142 // Make sure we don't call shutdown more than once.
129 if (stream_id_) { 143 if (stream_id_) {
130 filter_->RemoveDelegate(stream_id_); 144 filter_->RemoveDelegate(stream_id_);
131 Send(new AudioInputHostMsg_CloseStream(stream_id_)); 145 Send(new AudioInputHostMsg_CloseStream(stream_id_));
132 146
133 stream_id_ = 0; 147 stream_id_ = 0;
134 session_id_ = 0; 148 session_id_ = 0;
135 pending_device_ready_ = false; 149 pending_device_ready_ = false;
150 agc_is_enabled_ = false;
136 } 151 }
137 152
138 // We can run into an issue where ShutDownOnIOThread is called right after 153 // We can run into an issue where ShutDownOnIOThread is called right after
139 // OnStreamCreated is called in cases where Start/Stop are called before we 154 // OnStreamCreated is called in cases where Start/Stop are called before we
140 // get the OnStreamCreated callback. To handle that corner case, we call 155 // get the OnStreamCreated callback. To handle that corner case, we call
141 // Stop(). In most cases, the thread will already be stopped. 156 // Stop(). In most cases, the thread will already be stopped.
142 // Another situation is when the IO thread goes away before Stop() is called 157 // Another situation is when the IO thread goes away before Stop() is called
143 // in which case, we cannot use the message loop to close the thread handle 158 // in which case, we cannot use the message loop to close the thread handle
144 // and can't not rely on the main thread existing either. 159 // and can't not rely on the main thread existing either.
145 base::ThreadRestrictions::ScopedAllowIO allow_io; 160 base::ThreadRestrictions::ScopedAllowIO allow_io;
146 audio_thread_.Stop(NULL); 161 audio_thread_.Stop(NULL);
147 audio_callback_.reset(); 162 audio_callback_.reset();
148 } 163 }
149 164
150 void AudioInputDevice::SetVolumeOnIOThread(double volume) { 165 void AudioInputDevice::SetVolumeOnIOThread(double volume) {
151 DCHECK(message_loop()->BelongsToCurrentThread()); 166 DCHECK(message_loop()->BelongsToCurrentThread());
152 if (stream_id_) 167 if (stream_id_)
153 Send(new AudioInputHostMsg_SetVolume(stream_id_, volume)); 168 Send(new AudioInputHostMsg_SetVolume(stream_id_, volume));
154 } 169 }
155 170
171 void AudioInputDevice::SetAutomaticGainControlOnIOThread(bool enabled) {
172 DCHECK(message_loop()->BelongsToCurrentThread());
173 // The state of the AGC can not be modified while capturing is active.
tommi (sloooow) - chröme 2012/03/26 15:26:40 Are the reasons for this still valid?
henrika (OOO until Aug 14) 2012/03/27 09:20:38 Yes, I have removed locks in on the media side und
174 DCHECK_EQ(0, stream_id_);
scherkus (not reviewing) 2012/03/26 22:41:04 want to move that comment into a DCHECK() message?
henrika (OOO until Aug 14) 2012/03/27 09:20:38 Done.
175 if (stream_id_)
176 return;
177
178 // We simply store the new AGC setting here. This value will be used when
179 // a new stream is initialized and by GetAutomaticGainControl().
180 agc_is_enabled_ = enabled;
181 }
182
156 void AudioInputDevice::OnStreamCreated( 183 void AudioInputDevice::OnStreamCreated(
157 base::SharedMemoryHandle handle, 184 base::SharedMemoryHandle handle,
158 base::SyncSocket::Handle socket_handle, 185 base::SyncSocket::Handle socket_handle,
159 uint32 length) { 186 uint32 length) {
160 DCHECK(message_loop()->BelongsToCurrentThread()); 187 DCHECK(message_loop()->BelongsToCurrentThread());
161 #if defined(OS_WIN) 188 #if defined(OS_WIN)
162 DCHECK(handle); 189 DCHECK(handle);
163 DCHECK(socket_handle); 190 DCHECK(socket_handle);
164 #else 191 #else
165 DCHECK_GE(handle.fd, 0); 192 DCHECK_GE(handle.fd, 0);
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after
243 if (!pending_device_ready_) 270 if (!pending_device_ready_)
244 return; 271 return;
245 272
246 // If AudioInputDeviceManager returns an empty string, it means no device 273 // If AudioInputDeviceManager returns an empty string, it means no device
247 // is ready for start. 274 // is ready for start.
248 if (device_id.empty()) { 275 if (device_id.empty()) {
249 filter_->RemoveDelegate(stream_id_); 276 filter_->RemoveDelegate(stream_id_);
250 stream_id_ = 0; 277 stream_id_ = 0;
251 } else { 278 } else {
252 Send(new AudioInputHostMsg_CreateStream(stream_id_, audio_parameters_, 279 Send(new AudioInputHostMsg_CreateStream(stream_id_, audio_parameters_,
253 device_id)); 280 device_id, agc_is_enabled_));
254 } 281 }
255 282
256 pending_device_ready_ = false; 283 pending_device_ready_ = false;
257 // Notify the client that the device has been started. 284 // Notify the client that the device has been started.
258 if (event_handler_) 285 if (event_handler_)
259 event_handler_->OnDeviceStarted(device_id); 286 event_handler_->OnDeviceStarted(device_id);
260 } 287 }
261 288
262 void AudioInputDevice::Send(IPC::Message* message) { 289 void AudioInputDevice::Send(IPC::Message* message) {
263 filter_->Send(message); 290 filter_->Send(message);
(...skipping 15 matching lines...) Expand all
279 } 306 }
280 307
281 AudioInputDevice::AudioThreadCallback::~AudioThreadCallback() { 308 AudioInputDevice::AudioThreadCallback::~AudioThreadCallback() {
282 } 309 }
283 310
284 void AudioInputDevice::AudioThreadCallback::MapSharedMemory() { 311 void AudioInputDevice::AudioThreadCallback::MapSharedMemory() {
285 shared_memory_.Map(memory_length_); 312 shared_memory_.Map(memory_length_);
286 } 313 }
287 314
288 void AudioInputDevice::AudioThreadCallback::Process(int pending_data) { 315 void AudioInputDevice::AudioThreadCallback::Process(int pending_data) {
316
tommi (sloooow) - chröme 2012/03/26 15:26:40 remove this empty line
henrika (OOO until Aug 14) 2012/03/27 09:20:38 Done.
317 // The shared memory represents parameters, size of the data buffer and the
318 // actual data buffer containing audio data. Map the memory into this
319 // structure and parse out parameters and data area.
320 AudioInputBuffer* buffer =
321 reinterpret_cast<AudioInputBuffer*>(shared_memory_.memory());
322 uint32 size = buffer->params.size;
323 DCHECK_EQ(size, memory_length_ - sizeof(AudioInputBufferParameters));
324 double volume = buffer->params.volume;
325
289 int audio_delay_milliseconds = pending_data / bytes_per_ms_; 326 int audio_delay_milliseconds = pending_data / bytes_per_ms_;
290 int16* memory = reinterpret_cast<int16*>(shared_memory_.memory()); 327 int16* memory = reinterpret_cast<int16*>(buffer->audio);
tommi (sloooow) - chröme 2012/03/26 15:26:40 nit: &buffer->audio[0]
henrika (OOO until Aug 14) 2012/03/27 09:20:38 Done.
291 const size_t number_of_frames = audio_parameters_.frames_per_buffer(); 328 const size_t number_of_frames = audio_parameters_.frames_per_buffer();
292 const int bytes_per_sample = sizeof(memory[0]); 329 const int bytes_per_sample = sizeof(memory[0]);
293 330
294 // Deinterleave each channel and convert to 32-bit floating-point 331 // Deinterleave each channel and convert to 32-bit floating-point
295 // with nominal range -1.0 -> +1.0. 332 // with nominal range -1.0 -> +1.0.
296 for (int channel_index = 0; channel_index < audio_parameters_.channels(); 333 for (int channel_index = 0; channel_index < audio_parameters_.channels();
297 ++channel_index) { 334 ++channel_index) {
298 media::DeinterleaveAudioChannel(memory, 335 media::DeinterleaveAudioChannel(memory,
299 audio_data_[channel_index], 336 audio_data_[channel_index],
300 audio_parameters_.channels(), 337 audio_parameters_.channels(),
301 channel_index, 338 channel_index,
302 bytes_per_sample, 339 bytes_per_sample,
303 number_of_frames); 340 number_of_frames);
304 } 341 }
305 342
306 // Deliver captured data to the client in floating point format 343 // Deliver captured data to the client in floating point format
307 // and update the audio-delay measurement. 344 // and update the audio-delay measurement.
308 capture_callback_->Capture(audio_data_, number_of_frames, 345 capture_callback_->Capture(audio_data_, number_of_frames,
309 audio_delay_milliseconds); 346 audio_delay_milliseconds, volume);
310 } 347 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698