OLD | NEW |
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_output_device.h" | 5 #include "media/audio/audio_output_device.h" |
6 | 6 |
7 #include <stddef.h> | 7 #include <stddef.h> |
8 #include <stdint.h> | 8 #include <stdint.h> |
9 | 9 |
10 #include <cmath> | 10 #include <cmath> |
(...skipping 28 matching lines...) Expand all Loading... |
39 void MapSharedMemory() override; | 39 void MapSharedMemory() override; |
40 | 40 |
41 // Called whenever we receive notifications about pending data. | 41 // Called whenever we receive notifications about pending data. |
42 void Process(uint32_t pending_data) override; | 42 void Process(uint32_t pending_data) override; |
43 | 43 |
44 // Returns whether the current thread is the audio device thread or not. | 44 // Returns whether the current thread is the audio device thread or not. |
45 // Will always return true if DCHECKs are not enabled. | 45 // Will always return true if DCHECKs are not enabled. |
46 bool CurrentThreadIsAudioDeviceThread(); | 46 bool CurrentThreadIsAudioDeviceThread(); |
47 | 47 |
48 private: | 48 private: |
| 49 const int bytes_per_frame_; |
49 AudioRendererSink::RenderCallback* render_callback_; | 50 AudioRendererSink::RenderCallback* render_callback_; |
50 std::unique_ptr<AudioBus> output_bus_; | 51 std::unique_ptr<AudioBus> output_bus_; |
51 uint64_t callback_num_; | 52 uint64_t callback_num_; |
52 | 53 |
53 DISALLOW_COPY_AND_ASSIGN(AudioThreadCallback); | 54 DISALLOW_COPY_AND_ASSIGN(AudioThreadCallback); |
54 }; | 55 }; |
55 | 56 |
56 AudioOutputDevice::AudioOutputDevice( | 57 AudioOutputDevice::AudioOutputDevice( |
57 std::unique_ptr<AudioOutputIPC> ipc, | 58 std::unique_ptr<AudioOutputIPC> ipc, |
58 const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner, | 59 const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner, |
(...skipping 29 matching lines...) Expand all Loading... |
88 } | 89 } |
89 | 90 |
90 void AudioOutputDevice::Initialize(const AudioParameters& params, | 91 void AudioOutputDevice::Initialize(const AudioParameters& params, |
91 RenderCallback* callback) { | 92 RenderCallback* callback) { |
92 DCHECK(!callback_) << "Calling Initialize() twice?"; | 93 DCHECK(!callback_) << "Calling Initialize() twice?"; |
93 DCHECK(params.IsValid()); | 94 DCHECK(params.IsValid()); |
94 audio_parameters_ = params; | 95 audio_parameters_ = params; |
95 callback_ = callback; | 96 callback_ = callback; |
96 } | 97 } |
97 | 98 |
98 AudioOutputDevice::~AudioOutputDevice() { | 99 AudioOutputDevice::~AudioOutputDevice() {} |
99 // The current design requires that the user calls Stop() before deleting | |
100 // this class. | |
101 DCHECK(audio_thread_.IsStopped()); | |
102 } | |
103 | 100 |
104 void AudioOutputDevice::RequestDeviceAuthorization() { | 101 void AudioOutputDevice::RequestDeviceAuthorization() { |
105 task_runner()->PostTask( | 102 task_runner()->PostTask( |
106 FROM_HERE, | 103 FROM_HERE, |
107 base::Bind(&AudioOutputDevice::RequestDeviceAuthorizationOnIOThread, | 104 base::Bind(&AudioOutputDevice::RequestDeviceAuthorizationOnIOThread, |
108 this)); | 105 this)); |
109 } | 106 } |
110 | 107 |
111 void AudioOutputDevice::Start() { | 108 void AudioOutputDevice::Start() { |
112 DCHECK(callback_) << "Initialize hasn't been called"; | 109 DCHECK(callback_) << "Initialize hasn't been called"; |
113 task_runner()->PostTask(FROM_HERE, | 110 task_runner()->PostTask(FROM_HERE, |
114 base::Bind(&AudioOutputDevice::CreateStreamOnIOThread, this, | 111 base::Bind(&AudioOutputDevice::CreateStreamOnIOThread, this, |
115 audio_parameters_)); | 112 audio_parameters_)); |
116 } | 113 } |
117 | 114 |
118 void AudioOutputDevice::Stop() { | 115 void AudioOutputDevice::Stop() { |
119 { | 116 { |
120 base::AutoLock auto_lock(audio_thread_lock_); | 117 base::AutoLock auto_lock(audio_thread_lock_); |
121 audio_thread_.Stop(base::MessageLoop::current()); | 118 audio_thread_.reset(); |
122 stopping_hack_ = true; | 119 stopping_hack_ = true; |
123 } | 120 } |
124 | 121 |
125 task_runner()->PostTask(FROM_HERE, | 122 task_runner()->PostTask(FROM_HERE, |
126 base::Bind(&AudioOutputDevice::ShutDownOnIOThread, this)); | 123 base::Bind(&AudioOutputDevice::ShutDownOnIOThread, this)); |
127 } | 124 } |
128 | 125 |
129 void AudioOutputDevice::Play() { | 126 void AudioOutputDevice::Play() { |
130 task_runner()->PostTask(FROM_HERE, | 127 task_runner()->PostTask(FROM_HERE, |
131 base::Bind(&AudioOutputDevice::PlayOnIOThread, this)); | 128 base::Bind(&AudioOutputDevice::PlayOnIOThread, this)); |
(...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
260 // 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 |
261 // 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 |
262 // get the OnStreamCreated callback. To handle that corner case, we call | 259 // get the OnStreamCreated callback. To handle that corner case, we call |
263 // Stop(). In most cases, the thread will already be stopped. | 260 // Stop(). In most cases, the thread will already be stopped. |
264 // | 261 // |
265 // Another situation is when the IO thread goes away before Stop() is called | 262 // Another situation is when the IO thread goes away before Stop() is called |
266 // in which case, we cannot use the message loop to close the thread handle | 263 // in which case, we cannot use the message loop to close the thread handle |
267 // and can't rely on the main thread existing either. | 264 // and can't rely on the main thread existing either. |
268 base::AutoLock auto_lock_(audio_thread_lock_); | 265 base::AutoLock auto_lock_(audio_thread_lock_); |
269 base::ThreadRestrictions::ScopedAllowIO allow_io; | 266 base::ThreadRestrictions::ScopedAllowIO allow_io; |
270 audio_thread_.Stop(NULL); | 267 audio_thread_.reset(); |
271 audio_callback_.reset(); | 268 audio_callback_.reset(); |
272 stopping_hack_ = false; | 269 stopping_hack_ = false; |
273 } | 270 } |
274 | 271 |
275 void AudioOutputDevice::SetVolumeOnIOThread(double volume) { | 272 void AudioOutputDevice::SetVolumeOnIOThread(double volume) { |
276 DCHECK(task_runner()->BelongsToCurrentThread()); | 273 DCHECK(task_runner()->BelongsToCurrentThread()); |
277 if (state_ >= CREATING_STREAM) | 274 if (state_ >= CREATING_STREAM) |
278 ipc_->SetVolume(volume); | 275 ipc_->SetVolume(volume); |
279 } | 276 } |
280 | 277 |
(...skipping 11 matching lines...) Expand all Loading... |
292 case AUDIO_OUTPUT_IPC_DELEGATE_STATE_PAUSED: | 289 case AUDIO_OUTPUT_IPC_DELEGATE_STATE_PAUSED: |
293 break; | 290 break; |
294 case AUDIO_OUTPUT_IPC_DELEGATE_STATE_ERROR: | 291 case AUDIO_OUTPUT_IPC_DELEGATE_STATE_ERROR: |
295 DLOG(WARNING) << "AudioOutputDevice::OnStateChanged(ERROR)"; | 292 DLOG(WARNING) << "AudioOutputDevice::OnStateChanged(ERROR)"; |
296 // Don't dereference the callback object if the audio thread | 293 // Don't dereference the callback object if the audio thread |
297 // is stopped or stopping. That could mean that the callback | 294 // is stopped or stopping. That could mean that the callback |
298 // object has been deleted. | 295 // object has been deleted. |
299 // TODO(tommi): Add an explicit contract for clearing the callback | 296 // TODO(tommi): Add an explicit contract for clearing the callback |
300 // object. Possibly require calling Initialize again or provide | 297 // object. Possibly require calling Initialize again or provide |
301 // a callback object via Start() and clear it in Stop(). | 298 // a callback object via Start() and clear it in Stop(). |
302 if (!audio_thread_.IsStopped()) | 299 { |
303 callback_->OnRenderError(); | 300 base::AutoLock auto_lock_(audio_thread_lock_); |
| 301 if (audio_thread_) |
| 302 callback_->OnRenderError(); |
| 303 } |
304 break; | 304 break; |
305 default: | 305 default: |
306 NOTREACHED(); | 306 NOTREACHED(); |
307 break; | 307 break; |
308 } | 308 } |
309 } | 309 } |
310 | 310 |
311 void AudioOutputDevice::OnDeviceAuthorized( | 311 void AudioOutputDevice::OnDeviceAuthorized( |
312 OutputDeviceStatus device_status, | 312 OutputDeviceStatus device_status, |
313 const media::AudioParameters& output_params, | 313 const media::AudioParameters& output_params, |
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
393 // freed memory is a mess. AudioRendererSink should be non-refcounted so that | 393 // freed memory is a mess. AudioRendererSink should be non-refcounted so that |
394 // owners (WebRtcAudioDeviceImpl, AudioRendererImpl, etc...) can Stop() and | 394 // owners (WebRtcAudioDeviceImpl, AudioRendererImpl, etc...) can Stop() and |
395 // delete as they see fit. AudioOutputDevice should internally use WeakPtr | 395 // delete as they see fit. AudioOutputDevice should internally use WeakPtr |
396 // to handle teardown and thread hopping. See http://crbug.com/151051 for | 396 // to handle teardown and thread hopping. See http://crbug.com/151051 for |
397 // details. | 397 // details. |
398 { | 398 { |
399 base::AutoLock auto_lock(audio_thread_lock_); | 399 base::AutoLock auto_lock(audio_thread_lock_); |
400 if (stopping_hack_) | 400 if (stopping_hack_) |
401 return; | 401 return; |
402 | 402 |
403 DCHECK(audio_thread_.IsStopped()); | 403 DCHECK(!audio_thread_); |
| 404 DCHECK(!audio_callback_); |
| 405 |
404 audio_callback_.reset(new AudioOutputDevice::AudioThreadCallback( | 406 audio_callback_.reset(new AudioOutputDevice::AudioThreadCallback( |
405 audio_parameters_, handle, length, callback_)); | 407 audio_parameters_, handle, length, callback_)); |
406 audio_thread_.Start(audio_callback_.get(), socket_handle, | 408 audio_thread_.reset(new AudioDeviceThread( |
407 "AudioOutputDevice", true); | 409 audio_callback_.get(), socket_handle, "AudioOutputDevice")); |
408 state_ = PAUSED; | 410 state_ = PAUSED; |
409 | 411 |
410 // We handle the case where Play() and/or Pause() may have been called | 412 // We handle the case where Play() and/or Pause() may have been called |
411 // multiple times before OnStreamCreated() gets called. | 413 // multiple times before OnStreamCreated() gets called. |
412 if (play_on_start_) | 414 if (play_on_start_) |
413 PlayOnIOThread(); | 415 PlayOnIOThread(); |
414 } | 416 } |
415 } | 417 } |
416 | 418 |
417 void AudioOutputDevice::OnIPCClosed() { | 419 void AudioOutputDevice::OnIPCClosed() { |
(...skipping 11 matching lines...) Expand all Loading... |
429 } | 431 } |
430 | 432 |
431 // AudioOutputDevice::AudioThreadCallback | 433 // AudioOutputDevice::AudioThreadCallback |
432 | 434 |
433 AudioOutputDevice::AudioThreadCallback::AudioThreadCallback( | 435 AudioOutputDevice::AudioThreadCallback::AudioThreadCallback( |
434 const AudioParameters& audio_parameters, | 436 const AudioParameters& audio_parameters, |
435 base::SharedMemoryHandle memory, | 437 base::SharedMemoryHandle memory, |
436 int memory_length, | 438 int memory_length, |
437 AudioRendererSink::RenderCallback* render_callback) | 439 AudioRendererSink::RenderCallback* render_callback) |
438 : AudioDeviceThread::Callback(audio_parameters, memory, memory_length, 1), | 440 : AudioDeviceThread::Callback(audio_parameters, memory, memory_length, 1), |
| 441 bytes_per_frame_(audio_parameters.GetBytesPerFrame()), |
439 render_callback_(render_callback), | 442 render_callback_(render_callback), |
440 callback_num_(0) {} | 443 callback_num_(0) {} |
441 | 444 |
442 AudioOutputDevice::AudioThreadCallback::~AudioThreadCallback() { | 445 AudioOutputDevice::AudioThreadCallback::~AudioThreadCallback() { |
443 } | 446 } |
444 | 447 |
445 void AudioOutputDevice::AudioThreadCallback::MapSharedMemory() { | 448 void AudioOutputDevice::AudioThreadCallback::MapSharedMemory() { |
446 CHECK_EQ(total_segments_, 1); | 449 CHECK_EQ(total_segments_, 1); |
447 CHECK(shared_memory_.Map(memory_length_)); | 450 CHECK(shared_memory_.Map(memory_length_)); |
448 DCHECK_EQ(static_cast<size_t>(memory_length_), | 451 DCHECK_EQ(static_cast<size_t>(memory_length_), |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
487 render_callback_->Render(output_bus_.get(), std::round(frames_delayed), | 490 render_callback_->Render(output_bus_.get(), std::round(frames_delayed), |
488 frames_skipped); | 491 frames_skipped); |
489 } | 492 } |
490 | 493 |
491 bool AudioOutputDevice::AudioThreadCallback:: | 494 bool AudioOutputDevice::AudioThreadCallback:: |
492 CurrentThreadIsAudioDeviceThread() { | 495 CurrentThreadIsAudioDeviceThread() { |
493 return thread_checker_.CalledOnValidThread(); | 496 return thread_checker_.CalledOnValidThread(); |
494 } | 497 } |
495 | 498 |
496 } // namespace media | 499 } // namespace media |
OLD | NEW |