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

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 volume updating on Mac 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 30 matching lines...) Expand all
41 int channels, 41 int channels,
42 double sample_rate, 42 double sample_rate,
43 CaptureCallback* callback, 43 CaptureCallback* callback,
44 CaptureEventHandler* event_handler) 44 CaptureEventHandler* event_handler)
45 : ScopedLoopObserver(ChildProcess::current()->io_message_loop()), 45 : ScopedLoopObserver(ChildProcess::current()->io_message_loop()),
46 callback_(callback), 46 callback_(callback),
47 event_handler_(event_handler), 47 event_handler_(event_handler),
48 volume_(1.0), 48 volume_(1.0),
49 stream_id_(0), 49 stream_id_(0),
50 session_id_(0), 50 session_id_(0),
51 pending_device_ready_(false) { 51 pending_device_ready_(false) {
scherkus (not reviewing) 2012/03/20 13:49:41 should you initialize agc_is_enabled_ here?
henrika (OOO until Aug 14) 2012/03/21 10:16:04 OOps. Thanks.
52 filter_ = RenderThreadImpl::current()->audio_input_message_filter(); 52 filter_ = RenderThreadImpl::current()->audio_input_message_filter();
53 #if defined(OS_MACOSX) 53 #if defined(OS_MACOSX)
54 DVLOG(1) << "Using AUDIO_PCM_LOW_LATENCY as input mode on Mac OS X."; 54 DVLOG(1) << "Using AUDIO_PCM_LOW_LATENCY as input mode on Mac OS X.";
55 audio_parameters_.format = AudioParameters::AUDIO_PCM_LOW_LATENCY; 55 audio_parameters_.format = AudioParameters::AUDIO_PCM_LOW_LATENCY;
56 #elif defined(OS_WIN) 56 #elif defined(OS_WIN)
57 DVLOG(1) << "Using AUDIO_PCM_LOW_LATENCY as input mode on Windows."; 57 DVLOG(1) << "Using AUDIO_PCM_LOW_LATENCY as input mode on Windows.";
58 audio_parameters_.format = AudioParameters::AUDIO_PCM_LOW_LATENCY; 58 audio_parameters_.format = AudioParameters::AUDIO_PCM_LOW_LATENCY;
59 #else 59 #else
60 // TODO(henrika): add support for AUDIO_PCM_LOW_LATENCY on Linux as well. 60 // TODO(henrika): add support for AUDIO_PCM_LOW_LATENCY on Linux as well.
61 audio_parameters_.format = AudioParameters::AUDIO_PCM_LINEAR; 61 audio_parameters_.format = AudioParameters::AUDIO_PCM_LINEAR;
(...skipping 30 matching lines...) Expand all
92 base::AutoLock auto_lock(audio_thread_lock_); 92 base::AutoLock auto_lock(audio_thread_lock_);
93 callback_ = NULL; // After Stop() returns, we must never deref callback_. 93 callback_ = NULL; // After Stop() returns, we must never deref callback_.
94 audio_thread_.Stop(MessageLoop::current()); 94 audio_thread_.Stop(MessageLoop::current());
95 } 95 }
96 96
97 message_loop()->PostTask(FROM_HERE, 97 message_loop()->PostTask(FROM_HERE,
98 base::Bind(&AudioInputDevice::ShutDownOnIOThread, this)); 98 base::Bind(&AudioInputDevice::ShutDownOnIOThread, this));
99 } 99 }
100 100
101 bool AudioInputDevice::SetVolume(double volume) { 101 bool AudioInputDevice::SetVolume(double volume) {
102 NOTIMPLEMENTED(); 102 if (volume < 0 || volume > 1.0)
103 return false;
104
105 message_loop()->PostTask(FROM_HERE,
106 base::Bind(&AudioInputDevice::SetVolumeOnIOThread, this, volume));
107
108 return true;
109 }
110
111 bool AudioInputDevice::GetVolume(double* volume) {
112 NOTREACHED();
103 return false; 113 return false;
104 } 114 }
105 115
106 bool AudioInputDevice::GetVolume(double* volume) { 116 void AudioInputDevice::SetAutomaticGainControl(bool enabled) {
107 NOTIMPLEMENTED(); 117 DVLOG(1) << "SetAutomaticGainControl(enabled=" << enabled << ")";
108 return false; 118 message_loop()->PostTask(FROM_HERE,
119 base::Bind(&AudioInputDevice::SetAutomaticGainControlOnIOThread,
120 this, enabled));
109 } 121 }
110 122
111 void AudioInputDevice::InitializeOnIOThread() { 123 void AudioInputDevice::InitializeOnIOThread() {
112 DCHECK(message_loop()->BelongsToCurrentThread()); 124 DCHECK(message_loop()->BelongsToCurrentThread());
113 // Make sure we don't call Start() more than once. 125 // Make sure we don't call Start() more than once.
114 DCHECK_EQ(0, stream_id_); 126 DCHECK_EQ(0, stream_id_);
115 if (stream_id_) 127 if (stream_id_)
116 return; 128 return;
117 129
118 stream_id_ = filter_->AddDelegate(this); 130 stream_id_ = filter_->AddDelegate(this);
119 // If |session_id_| is not specified, it will directly create the stream; 131 // If |session_id_| is not specified, it will directly create the stream;
120 // otherwise it will send a AudioInputHostMsg_StartDevice msg to the browser 132 // otherwise it will send a AudioInputHostMsg_StartDevice msg to the browser
121 // and create the stream when getting a OnDeviceReady() callback. 133 // and create the stream when getting a OnDeviceReady() callback.
122 if (!session_id_) { 134 if (!session_id_) {
123 Send(new AudioInputHostMsg_CreateStream( 135 Send(new AudioInputHostMsg_CreateStream(
124 stream_id_, audio_parameters_, AudioManagerBase::kDefaultDeviceId)); 136 stream_id_, audio_parameters_, AudioManagerBase::kDefaultDeviceId,
137 agc_is_enabled_));
125 } else { 138 } else {
126 Send(new AudioInputHostMsg_StartDevice(stream_id_, session_id_)); 139 Send(new AudioInputHostMsg_StartDevice(stream_id_, session_id_));
127 pending_device_ready_ = true; 140 pending_device_ready_ = true;
128 } 141 }
129 } 142 }
130 143
131 void AudioInputDevice::SetSessionIdOnIOThread(int session_id) { 144 void AudioInputDevice::SetSessionIdOnIOThread(int session_id) {
132 DCHECK(message_loop()->BelongsToCurrentThread()); 145 DCHECK(message_loop()->BelongsToCurrentThread());
133 session_id_ = session_id; 146 session_id_ = session_id;
134 } 147 }
135 148
136 void AudioInputDevice::StartOnIOThread() { 149 void AudioInputDevice::StartOnIOThread() {
137 DCHECK(message_loop()->BelongsToCurrentThread()); 150 DCHECK(message_loop()->BelongsToCurrentThread());
138 if (stream_id_) 151 if (stream_id_)
139 Send(new AudioInputHostMsg_RecordStream(stream_id_)); 152 Send(new AudioInputHostMsg_RecordStream(stream_id_));
140 } 153 }
141 154
142 void AudioInputDevice::ShutDownOnIOThread() { 155 void AudioInputDevice::ShutDownOnIOThread() {
143 DCHECK(message_loop()->BelongsToCurrentThread()); 156 DCHECK(message_loop()->BelongsToCurrentThread());
144 // NOTE: |completion| may be NULL. 157 // NOTE: |completion| may be NULL.
145 // Make sure we don't call shutdown more than once. 158 // Make sure we don't call shutdown more than once.
146 if (stream_id_) { 159 if (stream_id_) {
147 filter_->RemoveDelegate(stream_id_); 160 filter_->RemoveDelegate(stream_id_);
148 Send(new AudioInputHostMsg_CloseStream(stream_id_)); 161 Send(new AudioInputHostMsg_CloseStream(stream_id_));
149 162
150 stream_id_ = 0; 163 stream_id_ = 0;
151 session_id_ = 0; 164 session_id_ = 0;
152 pending_device_ready_ = false; 165 pending_device_ready_ = false;
166 agc_is_enabled_ = false;
153 } 167 }
154 168
155 // We can run into an issue where ShutDownOnIOThread is called right after 169 // We can run into an issue where ShutDownOnIOThread is called right after
156 // OnStreamCreated is called in cases where Start/Stop are called before we 170 // OnStreamCreated is called in cases where Start/Stop are called before we
157 // get the OnStreamCreated callback. To handle that corner case, we call 171 // get the OnStreamCreated callback. To handle that corner case, we call
158 // Stop(). In most cases, the thread will already be stopped. 172 // Stop(). In most cases, the thread will already be stopped.
159 // Another situation is when the IO thread goes away before Stop() is called 173 // Another situation is when the IO thread goes away before Stop() is called
160 // in which case, we cannot use the message loop to close the thread handle 174 // in which case, we cannot use the message loop to close the thread handle
161 // and can't not rely on the main thread existing either. 175 // and can't not rely on the main thread existing either.
162 base::ThreadRestrictions::ScopedAllowIO allow_io; 176 base::ThreadRestrictions::ScopedAllowIO allow_io;
163 audio_thread_.Stop(NULL); 177 audio_thread_.Stop(NULL);
164 audio_callback_.reset(); 178 audio_callback_.reset();
165 } 179 }
166 180
167 void AudioInputDevice::SetVolumeOnIOThread(double volume) { 181 void AudioInputDevice::SetVolumeOnIOThread(double volume) {
168 DCHECK(message_loop()->BelongsToCurrentThread()); 182 DCHECK(message_loop()->BelongsToCurrentThread());
169 if (stream_id_) 183 if (stream_id_)
170 Send(new AudioInputHostMsg_SetVolume(stream_id_, volume)); 184 Send(new AudioInputHostMsg_SetVolume(stream_id_, volume));
171 } 185 }
172 186
187 void AudioInputDevice::SetAutomaticGainControlOnIOThread(bool enabled) {
188 DCHECK(message_loop()->BelongsToCurrentThread());
189 if (stream_id_) {
190 // We enter this scope if InitializeOnIOThread() has already been called.
191 // It means that an audio stream already exists but AGC is disabled.
192 // We must therefore modify the current AGC setting for the existing
193 // stream using IPC.
194 Send(new AudioInputHostMsg_SetAutomaticGainControl(stream_id_, enabled));
195 }
196
197 // Always store new AGC setting. This value will be used when a new stream
198 // is initialized and by GetAutomaticGainControl().
199 agc_is_enabled_ = enabled;
200 }
201
173 void AudioInputDevice::OnStreamCreated( 202 void AudioInputDevice::OnStreamCreated(
174 base::SharedMemoryHandle handle, 203 base::SharedMemoryHandle handle,
175 base::SyncSocket::Handle socket_handle, 204 base::SyncSocket::Handle socket_handle,
176 uint32 length) { 205 uint32 length) {
177 DCHECK(message_loop()->BelongsToCurrentThread()); 206 DCHECK(message_loop()->BelongsToCurrentThread());
178 #if defined(OS_WIN) 207 #if defined(OS_WIN)
179 DCHECK(handle); 208 DCHECK(handle);
180 DCHECK(socket_handle); 209 DCHECK(socket_handle);
181 #else 210 #else
182 DCHECK_GE(handle.fd, 0); 211 DCHECK_GE(handle.fd, 0);
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after
254 if (!pending_device_ready_) 283 if (!pending_device_ready_)
255 return; 284 return;
256 285
257 // If AudioInputDeviceManager returns an empty string, it means no device 286 // If AudioInputDeviceManager returns an empty string, it means no device
258 // is ready for start. 287 // is ready for start.
259 if (device_id.empty()) { 288 if (device_id.empty()) {
260 filter_->RemoveDelegate(stream_id_); 289 filter_->RemoveDelegate(stream_id_);
261 stream_id_ = 0; 290 stream_id_ = 0;
262 } else { 291 } else {
263 Send(new AudioInputHostMsg_CreateStream(stream_id_, audio_parameters_, 292 Send(new AudioInputHostMsg_CreateStream(stream_id_, audio_parameters_,
264 device_id)); 293 device_id, agc_is_enabled_));
265 } 294 }
266 295
267 pending_device_ready_ = false; 296 pending_device_ready_ = false;
268 // Notify the client that the device has been started. 297 // Notify the client that the device has been started.
269 if (event_handler_) 298 if (event_handler_)
270 event_handler_->OnDeviceStarted(device_id); 299 event_handler_->OnDeviceStarted(device_id);
271 } 300 }
272 301
273 void AudioInputDevice::Send(IPC::Message* message) { 302 void AudioInputDevice::Send(IPC::Message* message) {
274 filter_->Send(message); 303 filter_->Send(message);
(...skipping 16 matching lines...) Expand all
291 320
292 AudioInputDevice::AudioThreadCallback::~AudioThreadCallback() { 321 AudioInputDevice::AudioThreadCallback::~AudioThreadCallback() {
293 } 322 }
294 323
295 void AudioInputDevice::AudioThreadCallback::MapSharedMemory() { 324 void AudioInputDevice::AudioThreadCallback::MapSharedMemory() {
296 shared_memory_.Map(memory_length_); 325 shared_memory_.Map(memory_length_);
297 } 326 }
298 327
299 void AudioInputDevice::AudioThreadCallback::Process(int pending_data) { 328 void AudioInputDevice::AudioThreadCallback::Process(int pending_data) {
300 int audio_delay_milliseconds = pending_data / bytes_per_ms_; 329 int audio_delay_milliseconds = pending_data / bytes_per_ms_;
301 int16* memory = reinterpret_cast<int16*>(shared_memory_.memory()); 330
331 AudioInputBuffer* buffer =
332 reinterpret_cast<AudioInputBuffer*>(shared_memory_.memory());
tommi (sloooow) - chröme 2012/03/16 13:31:05 indent
henrika (OOO until Aug 14) 2012/03/21 10:16:04 Done.
333
334 // TODO(henrika): uint32 size = buffer->size;
tommi (sloooow) - chröme 2012/03/16 13:31:05 ping
henrika (OOO until Aug 14) 2012/03/21 10:16:04 Added DCHECK which uses the size variable.
335
336 double volume = buffer->volume;
337 int16* memory = reinterpret_cast<int16*>(buffer->audio);
tommi (sloooow) - chröme 2012/03/16 13:31:05 nit: &buffer->audio[0]
henrika (OOO until Aug 14) 2012/03/21 10:16:04 Done.
302 const size_t number_of_frames = audio_parameters_.samples_per_packet; 338 const size_t number_of_frames = audio_parameters_.samples_per_packet;
303 const int bytes_per_sample = sizeof(memory[0]); 339 const int bytes_per_sample = sizeof(memory[0]);
304 340
305 // Deinterleave each channel and convert to 32-bit floating-point 341 // Deinterleave each channel and convert to 32-bit floating-point
306 // with nominal range -1.0 -> +1.0. 342 // with nominal range -1.0 -> +1.0.
307 for (int channel_index = 0; channel_index < audio_parameters_.channels; 343 for (int channel_index = 0; channel_index < audio_parameters_.channels;
308 ++channel_index) { 344 ++channel_index) {
309 media::DeinterleaveAudioChannel(memory, 345 media::DeinterleaveAudioChannel(memory,
310 audio_data_[channel_index], 346 audio_data_[channel_index],
311 audio_parameters_.channels, 347 audio_parameters_.channels,
312 channel_index, 348 channel_index,
313 bytes_per_sample, 349 bytes_per_sample,
314 number_of_frames); 350 number_of_frames);
315 } 351 }
316 352
317 // Deliver captured data to the client in floating point format 353 // Deliver captured data to the client in floating point format
318 // and update the audio-delay measurement. 354 // and update the audio-delay measurement.
319 capture_callback_->Capture(audio_data_, number_of_frames, 355 capture_callback_->Capture(audio_data_, number_of_frames,
320 audio_delay_milliseconds); 356 audio_delay_milliseconds, volume);
321 } 357 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698