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

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

Powered by Google App Engine
This is Rietveld 408576698