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

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

Issue 10790121: First step towards moving AudioDevice from content/ to media/audio. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: relaxing the notreached back to log(error) since nacl tests will otherwise fail Created 8 years, 5 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 27 matching lines...) Expand all
38 }; 38 };
39 39
40 AudioInputDevice::AudioInputDevice(const media::AudioParameters& params, 40 AudioInputDevice::AudioInputDevice(const media::AudioParameters& params,
41 CaptureCallback* callback, 41 CaptureCallback* callback,
42 CaptureEventHandler* event_handler) 42 CaptureEventHandler* event_handler)
43 : ScopedLoopObserver( 43 : ScopedLoopObserver(
44 ChildProcess::current()->io_message_loop()->message_loop_proxy()), 44 ChildProcess::current()->io_message_loop()->message_loop_proxy()),
45 audio_parameters_(params), 45 audio_parameters_(params),
46 callback_(callback), 46 callback_(callback),
47 event_handler_(event_handler), 47 event_handler_(event_handler),
48 volume_(1.0),
49 stream_id_(0), 48 stream_id_(0),
50 session_id_(0), 49 session_id_(0),
51 pending_device_ready_(false), 50 pending_device_ready_(false),
52 agc_is_enabled_(false) { 51 agc_is_enabled_(false) {
53 filter_ = RenderThreadImpl::current()->audio_input_message_filter(); 52 // TODO(tommi): This needs to be updated to match AudioDevice.
53 ipc_ = RenderThreadImpl::current()->audio_input_message_filter();
54 } 54 }
55 55
56 void AudioInputDevice::SetDevice(int session_id) { 56 void AudioInputDevice::SetDevice(int session_id) {
57 DVLOG(1) << "SetDevice (session_id=" << session_id << ")"; 57 DVLOG(1) << "SetDevice (session_id=" << session_id << ")";
58 message_loop()->PostTask(FROM_HERE, 58 message_loop()->PostTask(FROM_HERE,
59 base::Bind(&AudioInputDevice::SetSessionIdOnIOThread, this, session_id)); 59 base::Bind(&AudioInputDevice::SetSessionIdOnIOThread, this, session_id));
60 } 60 }
61 61
62 void AudioInputDevice::Start() { 62 void AudioInputDevice::Start() {
63 DVLOG(1) << "Start()"; 63 DVLOG(1) << "Start()";
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after
126 audio_thread_.Start(audio_callback_.get(), socket_handle, "AudioInputDevice"); 126 audio_thread_.Start(audio_callback_.get(), socket_handle, "AudioInputDevice");
127 127
128 MessageLoop::current()->PostTask(FROM_HERE, 128 MessageLoop::current()->PostTask(FROM_HERE,
129 base::Bind(&AudioInputDevice::StartOnIOThread, this)); 129 base::Bind(&AudioInputDevice::StartOnIOThread, this));
130 } 130 }
131 131
132 void AudioInputDevice::OnVolume(double volume) { 132 void AudioInputDevice::OnVolume(double volume) {
133 NOTIMPLEMENTED(); 133 NOTIMPLEMENTED();
134 } 134 }
135 135
136 void AudioInputDevice::OnStateChanged(AudioStreamState state) { 136 void AudioInputDevice::OnStateChanged(
137 media::AudioInputDeviceIPCDelegate::State state) {
137 DCHECK(message_loop()->BelongsToCurrentThread()); 138 DCHECK(message_loop()->BelongsToCurrentThread());
138 139
139 // Do nothing if the stream has been closed. 140 // Do nothing if the stream has been closed.
140 if (!stream_id_) 141 if (!stream_id_)
141 return; 142 return;
142 143
143 switch (state) { 144 switch (state) {
144 // TODO(xians): This should really be kAudioStreamStopped since the stream 145 case media::AudioInputDeviceIPCDelegate::kStopped:
145 // has been closed at this point.
146 case kAudioStreamPaused:
147 // TODO(xians): Should we just call ShutDownOnIOThread here instead? 146 // TODO(xians): Should we just call ShutDownOnIOThread here instead?
148 filter_->RemoveDelegate(stream_id_); 147 ipc_->RemoveDelegate(stream_id_);
149 148
150 audio_thread_.Stop(MessageLoop::current()); 149 audio_thread_.Stop(MessageLoop::current());
151 audio_callback_.reset(); 150 audio_callback_.reset();
152 151
153 if (event_handler_) 152 if (event_handler_)
154 event_handler_->OnDeviceStopped(); 153 event_handler_->OnDeviceStopped();
155 154
156 stream_id_ = 0; 155 stream_id_ = 0;
157 pending_device_ready_ = false; 156 pending_device_ready_ = false;
158 break; 157 break;
159 case kAudioStreamPlaying: 158 case media::AudioInputDeviceIPCDelegate::kRecording:
160 NOTIMPLEMENTED(); 159 NOTIMPLEMENTED();
161 break; 160 break;
162 case kAudioStreamError: 161 case media::AudioInputDeviceIPCDelegate::kError:
163 DLOG(WARNING) << "AudioInputDevice::OnStateChanged(kError)"; 162 DLOG(WARNING) << "AudioInputDevice::OnStateChanged(kError)";
164 // Don't dereference the callback object if the audio thread 163 // Don't dereference the callback object if the audio thread
165 // is stopped or stopping. That could mean that the callback 164 // is stopped or stopping. That could mean that the callback
166 // object has been deleted. 165 // object has been deleted.
167 // TODO(tommi): Add an explicit contract for clearing the callback 166 // TODO(tommi): Add an explicit contract for clearing the callback
168 // object. Possibly require calling Initialize again or provide 167 // object. Possibly require calling Initialize again or provide
169 // a callback object via Start() and clear it in Stop(). 168 // a callback object via Start() and clear it in Stop().
170 if (!audio_thread_.IsStopped()) 169 if (!audio_thread_.IsStopped())
171 callback_->OnCaptureError(); 170 callback_->OnCaptureError();
172 break; 171 break;
173 default: 172 default:
174 NOTREACHED(); 173 NOTREACHED();
175 break; 174 break;
176 } 175 }
177 } 176 }
178 177
179 void AudioInputDevice::OnDeviceReady(const std::string& device_id) { 178 void AudioInputDevice::OnDeviceReady(const std::string& device_id) {
180 DCHECK(message_loop()->BelongsToCurrentThread()); 179 DCHECK(message_loop()->BelongsToCurrentThread());
181 DVLOG(1) << "OnDeviceReady (device_id=" << device_id << ")"; 180 DVLOG(1) << "OnDeviceReady (device_id=" << device_id << ")";
182 181
183 // Takes care of the case when Stop() is called before OnDeviceReady(). 182 // Takes care of the case when Stop() is called before OnDeviceReady().
184 if (!pending_device_ready_) 183 if (!pending_device_ready_)
185 return; 184 return;
186 185
187 // If AudioInputDeviceManager returns an empty string, it means no device 186 // If AudioInputDeviceManager returns an empty string, it means no device
188 // is ready for start. 187 // is ready for start.
189 if (device_id.empty()) { 188 if (device_id.empty()) {
190 filter_->RemoveDelegate(stream_id_); 189 ipc_->RemoveDelegate(stream_id_);
191 stream_id_ = 0; 190 stream_id_ = 0;
192 } else { 191 } else {
193 Send(new AudioInputHostMsg_CreateStream(stream_id_, audio_parameters_, 192 ipc_->CreateStream(stream_id_, audio_parameters_, device_id,
194 device_id, agc_is_enabled_)); 193 agc_is_enabled_);
scherkus (not reviewing) 2012/07/24 17:57:48 indenting
tommi (sloooow) - chröme 2012/07/25 13:46:17 Done.
195 } 194 }
196 195
197 pending_device_ready_ = false; 196 pending_device_ready_ = false;
198 // Notify the client that the device has been started. 197 // Notify the client that the device has been started.
199 if (event_handler_) 198 if (event_handler_)
200 event_handler_->OnDeviceStarted(device_id); 199 event_handler_->OnDeviceStarted(device_id);
201 } 200 }
202 201
202 void AudioInputDevice::OnIPCClosed() {
203 ipc_ = NULL;
scherkus (not reviewing) 2012/07/24 17:57:48 FYI we seem to guard against calling ipc_ with str
tommi (sloooow) - chröme 2012/07/25 13:46:17 The stream_id_ checks are not really meant to guar
204 }
205
203 AudioInputDevice::~AudioInputDevice() { 206 AudioInputDevice::~AudioInputDevice() {
204 // TODO(henrika): The current design requires that the user calls 207 // TODO(henrika): The current design requires that the user calls
205 // Stop before deleting this class. 208 // Stop before deleting this class.
206 CHECK_EQ(0, stream_id_); 209 CHECK_EQ(0, stream_id_);
207 } 210 }
208 211
209 void AudioInputDevice::InitializeOnIOThread() { 212 void AudioInputDevice::InitializeOnIOThread() {
210 DCHECK(message_loop()->BelongsToCurrentThread()); 213 DCHECK(message_loop()->BelongsToCurrentThread());
211 // Make sure we don't call Start() more than once. 214 // Make sure we don't call Start() more than once.
212 DCHECK_EQ(0, stream_id_); 215 DCHECK_EQ(0, stream_id_);
213 if (stream_id_) 216 if (stream_id_)
214 return; 217 return;
215 218
216 stream_id_ = filter_->AddDelegate(this); 219 stream_id_ = ipc_->AddDelegate(this);
217 // If |session_id_| is not specified, it will directly create the stream; 220 // If |session_id_| is not specified, it will directly create the stream;
218 // otherwise it will send a AudioInputHostMsg_StartDevice msg to the browser 221 // otherwise it will send a AudioInputHostMsg_StartDevice msg to the browser
219 // and create the stream when getting a OnDeviceReady() callback. 222 // and create the stream when getting a OnDeviceReady() callback.
220 if (!session_id_) { 223 if (!session_id_) {
221 Send(new AudioInputHostMsg_CreateStream( 224 ipc_->CreateStream(stream_id_, audio_parameters_,
222 stream_id_, audio_parameters_, 225 media::AudioManagerBase::kDefaultDeviceId, agc_is_enabled_);
223 media::AudioManagerBase::kDefaultDeviceId,
224 agc_is_enabled_));
225 } else { 226 } else {
226 Send(new AudioInputHostMsg_StartDevice(stream_id_, session_id_)); 227 ipc_->StartDevice(stream_id_, session_id_);
227 pending_device_ready_ = true; 228 pending_device_ready_ = true;
228 } 229 }
229 } 230 }
230 231
231 void AudioInputDevice::SetSessionIdOnIOThread(int session_id) { 232 void AudioInputDevice::SetSessionIdOnIOThread(int session_id) {
232 DCHECK(message_loop()->BelongsToCurrentThread()); 233 DCHECK(message_loop()->BelongsToCurrentThread());
233 session_id_ = session_id; 234 session_id_ = session_id;
234 } 235 }
235 236
236 void AudioInputDevice::StartOnIOThread() { 237 void AudioInputDevice::StartOnIOThread() {
237 DCHECK(message_loop()->BelongsToCurrentThread()); 238 DCHECK(message_loop()->BelongsToCurrentThread());
238 if (stream_id_) 239 if (stream_id_)
239 Send(new AudioInputHostMsg_RecordStream(stream_id_)); 240 ipc_->RecordStream(stream_id_);
240 } 241 }
241 242
242 void AudioInputDevice::ShutDownOnIOThread() { 243 void AudioInputDevice::ShutDownOnIOThread() {
243 DCHECK(message_loop()->BelongsToCurrentThread()); 244 DCHECK(message_loop()->BelongsToCurrentThread());
244 // NOTE: |completion| may be NULL. 245 // NOTE: |completion| may be NULL.
245 // Make sure we don't call shutdown more than once. 246 // Make sure we don't call shutdown more than once.
246 if (stream_id_) { 247 if (stream_id_) {
247 filter_->RemoveDelegate(stream_id_); 248 ipc_->CloseStream(stream_id_);
248 Send(new AudioInputHostMsg_CloseStream(stream_id_)); 249 ipc_->RemoveDelegate(stream_id_);
249 250
250 stream_id_ = 0; 251 stream_id_ = 0;
251 session_id_ = 0; 252 session_id_ = 0;
252 pending_device_ready_ = false; 253 pending_device_ready_ = false;
253 agc_is_enabled_ = false; 254 agc_is_enabled_ = false;
254 } 255 }
255 256
256 // We can run into an issue where ShutDownOnIOThread is called right after 257 // We can run into an issue where ShutDownOnIOThread is called right after
257 // OnStreamCreated is called in cases where Start/Stop are called before we 258 // OnStreamCreated is called in cases where Start/Stop are called before we
258 // get the OnStreamCreated callback. To handle that corner case, we call 259 // get the OnStreamCreated callback. To handle that corner case, we call
259 // Stop(). In most cases, the thread will already be stopped. 260 // Stop(). In most cases, the thread will already be stopped.
260 // Another situation is when the IO thread goes away before Stop() is called 261 // Another situation is when the IO thread goes away before Stop() is called
261 // in which case, we cannot use the message loop to close the thread handle 262 // in which case, we cannot use the message loop to close the thread handle
262 // and can't not rely on the main thread existing either. 263 // and can't not rely on the main thread existing either.
263 base::ThreadRestrictions::ScopedAllowIO allow_io; 264 base::ThreadRestrictions::ScopedAllowIO allow_io;
264 audio_thread_.Stop(NULL); 265 audio_thread_.Stop(NULL);
265 audio_callback_.reset(); 266 audio_callback_.reset();
266 } 267 }
267 268
268 void AudioInputDevice::SetVolumeOnIOThread(double volume) { 269 void AudioInputDevice::SetVolumeOnIOThread(double volume) {
269 DCHECK(message_loop()->BelongsToCurrentThread()); 270 DCHECK(message_loop()->BelongsToCurrentThread());
270 if (stream_id_) 271 if (stream_id_)
271 Send(new AudioInputHostMsg_SetVolume(stream_id_, volume)); 272 ipc_->SetVolume(stream_id_, volume);
272 } 273 }
273 274
274 void AudioInputDevice::SetAutomaticGainControlOnIOThread(bool enabled) { 275 void AudioInputDevice::SetAutomaticGainControlOnIOThread(bool enabled) {
275 DCHECK(message_loop()->BelongsToCurrentThread()); 276 DCHECK(message_loop()->BelongsToCurrentThread());
276 DCHECK_EQ(0, stream_id_) << 277 DCHECK_EQ(0, stream_id_) <<
277 "The AGC state can not be modified while capturing is active."; 278 "The AGC state can not be modified while capturing is active.";
278 if (stream_id_) 279 if (stream_id_)
279 return; 280 return;
280 281
281 // We simply store the new AGC setting here. This value will be used when 282 // We simply store the new AGC setting here. This value will be used when
282 // a new stream is initialized and by GetAutomaticGainControl(). 283 // a new stream is initialized and by GetAutomaticGainControl().
283 agc_is_enabled_ = enabled; 284 agc_is_enabled_ = enabled;
284 } 285 }
285 286
286 void AudioInputDevice::Send(IPC::Message* message) {
287 filter_->Send(message);
288 }
289
290 void AudioInputDevice::WillDestroyCurrentMessageLoop() { 287 void AudioInputDevice::WillDestroyCurrentMessageLoop() {
291 LOG(ERROR) << "IO loop going away before the input device has been stopped"; 288 LOG(ERROR) << "IO loop going away before the input device has been stopped";
292 ShutDownOnIOThread(); 289 ShutDownOnIOThread();
293 } 290 }
294 291
295 // AudioInputDevice::AudioThreadCallback 292 // AudioInputDevice::AudioThreadCallback
296 AudioInputDevice::AudioThreadCallback::AudioThreadCallback( 293 AudioInputDevice::AudioThreadCallback::AudioThreadCallback(
297 const media::AudioParameters& audio_parameters, 294 const media::AudioParameters& audio_parameters,
298 base::SharedMemoryHandle memory, 295 base::SharedMemoryHandle memory,
299 int memory_length, 296 int memory_length,
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
334 channel_index, 331 channel_index,
335 bytes_per_sample, 332 bytes_per_sample,
336 number_of_frames); 333 number_of_frames);
337 } 334 }
338 335
339 // Deliver captured data to the client in floating point format 336 // Deliver captured data to the client in floating point format
340 // and update the audio-delay measurement. 337 // and update the audio-delay measurement.
341 capture_callback_->Capture(audio_data_, number_of_frames, 338 capture_callback_->Capture(audio_data_, number_of_frames,
342 audio_delay_milliseconds, volume); 339 audio_delay_milliseconds, volume);
343 } 340 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698