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

Side by Side Diff: media/audio/audio_input_device.cc

Issue 12440027: Do not pass the string device_id via IPC message to create an audio input stream (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: ready for review Created 7 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 "media/audio/audio_input_device.h" 5 #include "media/audio/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 23 matching lines...) Expand all
34 CaptureCallback* capture_callback_; 34 CaptureCallback* capture_callback_;
35 scoped_ptr<AudioBus> audio_bus_; 35 scoped_ptr<AudioBus> audio_bus_;
36 DISALLOW_COPY_AND_ASSIGN(AudioThreadCallback); 36 DISALLOW_COPY_AND_ASSIGN(AudioThreadCallback);
37 }; 37 };
38 38
39 AudioInputDevice::AudioInputDevice( 39 AudioInputDevice::AudioInputDevice(
40 AudioInputIPC* ipc, 40 AudioInputIPC* ipc,
41 const scoped_refptr<base::MessageLoopProxy>& io_loop) 41 const scoped_refptr<base::MessageLoopProxy>& io_loop)
42 : ScopedLoopObserver(io_loop), 42 : ScopedLoopObserver(io_loop),
43 callback_(NULL), 43 callback_(NULL),
44 event_handler_(NULL),
45 ipc_(ipc), 44 ipc_(ipc),
46 stream_id_(0), 45 stream_id_(0),
47 session_id_(0), 46 session_id_(0),
48 pending_device_ready_(false),
49 agc_is_enabled_(false) { 47 agc_is_enabled_(false) {
50 CHECK(ipc_); 48 CHECK(ipc_);
51 } 49 }
52 50
53 void AudioInputDevice::Initialize(const AudioParameters& params, 51 void AudioInputDevice::Initialize(const AudioParameters& params,
54 CaptureCallback* callback, 52 CaptureCallback* callback,
55 CaptureEventHandler* event_handler) { 53 int session_id) {
56 DCHECK(!callback_); 54 DCHECK(!callback_);
57 DCHECK(!event_handler_); 55 DCHECK_EQ(0, session_id_);
58 audio_parameters_ = params; 56 audio_parameters_ = params;
59 callback_ = callback; 57 callback_ = callback;
60 event_handler_ = event_handler; 58 session_id_ = session_id;
61 }
62
63 void AudioInputDevice::SetDevice(int session_id) {
64 DVLOG(1) << "SetDevice (session_id=" << session_id << ")";
65 message_loop()->PostTask(FROM_HERE,
66 base::Bind(&AudioInputDevice::SetSessionIdOnIOThread, this, session_id));
67 } 59 }
68 60
69 void AudioInputDevice::Start() { 61 void AudioInputDevice::Start() {
70 DVLOG(1) << "Start()"; 62 DVLOG(1) << "Start()";
71 message_loop()->PostTask(FROM_HERE, 63 message_loop()->PostTask(FROM_HERE,
72 base::Bind(&AudioInputDevice::InitializeOnIOThread, this)); 64 base::Bind(&AudioInputDevice::InitializeOnIOThread, this));
73 } 65 }
74 66
75 void AudioInputDevice::Stop() { 67 void AudioInputDevice::Stop() {
76 DVLOG(1) << "Stop()"; 68 DVLOG(1) << "Stop()";
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after
148 return; 140 return;
149 141
150 switch (state) { 142 switch (state) {
151 case AudioInputIPCDelegate::kStopped: 143 case AudioInputIPCDelegate::kStopped:
152 // TODO(xians): Should we just call ShutDownOnIOThread here instead? 144 // TODO(xians): Should we just call ShutDownOnIOThread here instead?
153 ipc_->RemoveDelegate(stream_id_); 145 ipc_->RemoveDelegate(stream_id_);
154 146
155 audio_thread_.Stop(MessageLoop::current()); 147 audio_thread_.Stop(MessageLoop::current());
156 audio_callback_.reset(); 148 audio_callback_.reset();
157 149
158 if (event_handler_)
159 event_handler_->OnDeviceStopped();
160
161 stream_id_ = 0; 150 stream_id_ = 0;
162 pending_device_ready_ = false;
163 break; 151 break;
164 case AudioInputIPCDelegate::kRecording: 152 case AudioInputIPCDelegate::kRecording:
165 NOTIMPLEMENTED(); 153 NOTIMPLEMENTED();
166 break; 154 break;
167 case AudioInputIPCDelegate::kError: 155 case AudioInputIPCDelegate::kError:
168 DLOG(WARNING) << "AudioInputDevice::OnStateChanged(kError)"; 156 DLOG(WARNING) << "AudioInputDevice::OnStateChanged(kError)";
169 // Don't dereference the callback object if the audio thread 157 // Don't dereference the callback object if the audio thread
170 // is stopped or stopping. That could mean that the callback 158 // is stopped or stopping. That could mean that the callback
171 // object has been deleted. 159 // object has been deleted.
172 // TODO(tommi): Add an explicit contract for clearing the callback 160 // TODO(tommi): Add an explicit contract for clearing the callback
173 // object. Possibly require calling Initialize again or provide 161 // object. Possibly require calling Initialize again or provide
174 // a callback object via Start() and clear it in Stop(). 162 // a callback object via Start() and clear it in Stop().
175 if (!audio_thread_.IsStopped()) 163 if (!audio_thread_.IsStopped())
176 callback_->OnCaptureError(); 164 callback_->OnCaptureError();
177 break; 165 break;
178 default: 166 default:
179 NOTREACHED(); 167 NOTREACHED();
180 break; 168 break;
181 } 169 }
182 } 170 }
183 171
184 void AudioInputDevice::OnDeviceReady(const std::string& device_id) {
185 DCHECK(message_loop()->BelongsToCurrentThread());
186 DVLOG(1) << "OnDeviceReady (device_id=" << device_id << ")";
187
188 // Takes care of the case when Stop() is called before OnDeviceReady().
189 if (!pending_device_ready_)
190 return;
191
192 // If AudioInputDeviceManager returns an empty string, it means no device
193 // is ready for start.
194 if (device_id.empty()) {
195 ipc_->RemoveDelegate(stream_id_);
196 stream_id_ = 0;
197 } else {
198 ipc_->CreateStream(stream_id_, audio_parameters_, device_id,
199 agc_is_enabled_);
200 }
201
202 pending_device_ready_ = false;
203 // Notify the client that the device has been started.
204 if (event_handler_)
205 event_handler_->OnDeviceStarted(device_id);
206 }
207
208 void AudioInputDevice::OnIPCClosed() { 172 void AudioInputDevice::OnIPCClosed() {
209 ipc_ = NULL; 173 ipc_ = NULL;
210 } 174 }
211 175
212 AudioInputDevice::~AudioInputDevice() { 176 AudioInputDevice::~AudioInputDevice() {
213 // TODO(henrika): The current design requires that the user calls 177 // TODO(henrika): The current design requires that the user calls
214 // Stop before deleting this class. 178 // Stop before deleting this class.
215 CHECK_EQ(0, stream_id_); 179 CHECK_EQ(0, stream_id_);
216 } 180 }
217 181
218 void AudioInputDevice::InitializeOnIOThread() { 182 void AudioInputDevice::InitializeOnIOThread() {
219 DCHECK(message_loop()->BelongsToCurrentThread()); 183 DCHECK(message_loop()->BelongsToCurrentThread());
220 // Make sure we don't call Start() more than once. 184 // Make sure we don't call Start() more than once.
221 DCHECK_EQ(0, stream_id_); 185 DCHECK_EQ(0, stream_id_);
222 if (stream_id_) 186 if (stream_id_)
223 return; 187 return;
224 188
189 if (session_id_ <= 0) {
190 DLOG(WARNING) << "Invalid session id for the input stream " << session_id_;
191 return;
192 }
193
225 stream_id_ = ipc_->AddDelegate(this); 194 stream_id_ = ipc_->AddDelegate(this);
226 // If |session_id_| is not specified, it will directly create the stream; 195 ipc_->CreateStream(stream_id_, session_id_, audio_parameters_,
227 // otherwise it will send a AudioInputHostMsg_StartDevice msg to the browser 196 agc_is_enabled_);
228 // and create the stream when getting a OnDeviceReady() callback.
229 if (!session_id_) {
230 ipc_->CreateStream(stream_id_, audio_parameters_,
231 AudioManagerBase::kDefaultDeviceId, agc_is_enabled_);
232 } else {
233 ipc_->StartDevice(stream_id_, session_id_);
234 pending_device_ready_ = true;
235 }
236 }
237
238 void AudioInputDevice::SetSessionIdOnIOThread(int session_id) {
239 DCHECK(message_loop()->BelongsToCurrentThread());
240 session_id_ = session_id;
241 } 197 }
242 198
243 void AudioInputDevice::StartOnIOThread() { 199 void AudioInputDevice::StartOnIOThread() {
244 DCHECK(message_loop()->BelongsToCurrentThread()); 200 DCHECK(message_loop()->BelongsToCurrentThread());
245 if (stream_id_) 201 if (stream_id_)
246 ipc_->RecordStream(stream_id_); 202 ipc_->RecordStream(stream_id_);
247 } 203 }
248 204
249 void AudioInputDevice::ShutDownOnIOThread() { 205 void AudioInputDevice::ShutDownOnIOThread() {
250 DCHECK(message_loop()->BelongsToCurrentThread()); 206 DCHECK(message_loop()->BelongsToCurrentThread());
251 // NOTE: |completion| may be NULL. 207 // NOTE: |completion| may be NULL.
252 // Make sure we don't call shutdown more than once. 208 // Make sure we don't call shutdown more than once.
253 if (stream_id_) { 209 if (stream_id_) {
254 if (ipc_) { 210 if (ipc_) {
255 ipc_->CloseStream(stream_id_); 211 ipc_->CloseStream(stream_id_);
256 ipc_->RemoveDelegate(stream_id_); 212 ipc_->RemoveDelegate(stream_id_);
257 } 213 }
258 214
259 stream_id_ = 0; 215 stream_id_ = 0;
260 session_id_ = 0;
261 pending_device_ready_ = false;
262 agc_is_enabled_ = false; 216 agc_is_enabled_ = false;
263 } 217 }
264 218
265 // We can run into an issue where ShutDownOnIOThread is called right after 219 // We can run into an issue where ShutDownOnIOThread is called right after
266 // OnStreamCreated is called in cases where Start/Stop are called before we 220 // OnStreamCreated is called in cases where Start/Stop are called before we
267 // get the OnStreamCreated callback. To handle that corner case, we call 221 // get the OnStreamCreated callback. To handle that corner case, we call
268 // Stop(). In most cases, the thread will already be stopped. 222 // Stop(). In most cases, the thread will already be stopped.
269 // Another situation is when the IO thread goes away before Stop() is called 223 // Another situation is when the IO thread goes away before Stop() is called
270 // in which case, we cannot use the message loop to close the thread handle 224 // in which case, we cannot use the message loop to close the thread handle
271 // and can't not rely on the main thread existing either. 225 // and can't not rely on the main thread existing either.
272 base::ThreadRestrictions::ScopedAllowIO allow_io; 226 base::ThreadRestrictions::ScopedAllowIO allow_io;
273 audio_thread_.Stop(NULL); 227 audio_thread_.Stop(NULL);
274 audio_callback_.reset(); 228 audio_callback_.reset();
229 session_id_ = 0;
275 } 230 }
276 231
277 void AudioInputDevice::SetVolumeOnIOThread(double volume) { 232 void AudioInputDevice::SetVolumeOnIOThread(double volume) {
278 DCHECK(message_loop()->BelongsToCurrentThread()); 233 DCHECK(message_loop()->BelongsToCurrentThread());
279 if (stream_id_) 234 if (stream_id_)
280 ipc_->SetVolume(stream_id_, volume); 235 ipc_->SetVolume(stream_id_, volume);
281 } 236 }
282 237
283 void AudioInputDevice::SetAutomaticGainControlOnIOThread(bool enabled) { 238 void AudioInputDevice::SetAutomaticGainControlOnIOThread(bool enabled) {
284 DCHECK(message_loop()->BelongsToCurrentThread()); 239 DCHECK(message_loop()->BelongsToCurrentThread());
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
333 // with nominal range -1.0 -> +1.0. 288 // with nominal range -1.0 -> +1.0.
334 audio_bus_->FromInterleaved(memory, audio_bus_->frames(), bytes_per_sample); 289 audio_bus_->FromInterleaved(memory, audio_bus_->frames(), bytes_per_sample);
335 290
336 // Deliver captured data to the client in floating point format 291 // Deliver captured data to the client in floating point format
337 // and update the audio-delay measurement. 292 // and update the audio-delay measurement.
338 capture_callback_->Capture(audio_bus_.get(), 293 capture_callback_->Capture(audio_bus_.get(),
339 audio_delay_milliseconds, volume); 294 audio_delay_milliseconds, volume);
340 } 295 }
341 296
342 } // namespace media 297 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698