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

Side by Side Diff: media/audio/alsa/alsa_output.cc

Issue 2076423004: Remove calls to MessageLoop::current() in media. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: CR Created 4 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
« no previous file with comments | « media/audio/alsa/alsa_output.h ('k') | media/audio/sounds/test_data.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 1 // Copyright 2013 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 // THREAD SAFETY 5 // THREAD SAFETY
6 // 6 //
7 // AlsaPcmOutputStream object is *not* thread-safe and should only be used 7 // AlsaPcmOutputStream object is *not* thread-safe and should only be used
8 // from the audio thread. We DCHECK on this assumption whenever we can. 8 // from the audio thread. We DCHECK on this assumption whenever we can.
9 // 9 //
10 // SEMANTICS OF Close() 10 // SEMANTICS OF Close()
(...skipping 24 matching lines...) Expand all
35 #include "media/audio/alsa/alsa_output.h" 35 #include "media/audio/alsa/alsa_output.h"
36 36
37 #include <stddef.h> 37 #include <stddef.h>
38 38
39 #include <algorithm> 39 #include <algorithm>
40 40
41 #include "base/bind.h" 41 #include "base/bind.h"
42 #include "base/logging.h" 42 #include "base/logging.h"
43 #include "base/memory/free_deleter.h" 43 #include "base/memory/free_deleter.h"
44 #include "base/stl_util.h" 44 #include "base/stl_util.h"
45 #include "base/threading/thread_task_runner_handle.h"
45 #include "base/trace_event/trace_event.h" 46 #include "base/trace_event/trace_event.h"
46 #include "media/audio/alsa/alsa_util.h" 47 #include "media/audio/alsa/alsa_util.h"
47 #include "media/audio/alsa/alsa_wrapper.h" 48 #include "media/audio/alsa/alsa_wrapper.h"
48 #include "media/audio/alsa/audio_manager_alsa.h" 49 #include "media/audio/alsa/audio_manager_alsa.h"
49 #include "media/base/channel_mixer.h" 50 #include "media/base/channel_mixer.h"
50 #include "media/base/data_buffer.h" 51 #include "media/base/data_buffer.h"
51 #include "media/base/seekable_buffer.h" 52 #include "media/base/seekable_buffer.h"
52 53
53 namespace media { 54 namespace media {
54 55
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after
149 bytes_per_frame_(params.GetBytesPerFrame()), 150 bytes_per_frame_(params.GetBytesPerFrame()),
150 packet_size_(params.GetBytesPerBuffer()), 151 packet_size_(params.GetBytesPerBuffer()),
151 latency_(std::max( 152 latency_(std::max(
152 base::TimeDelta::FromMicroseconds(kMinLatencyMicros), 153 base::TimeDelta::FromMicroseconds(kMinLatencyMicros),
153 FramesToTimeDelta(params.frames_per_buffer() * 2, sample_rate_))), 154 FramesToTimeDelta(params.frames_per_buffer() * 2, sample_rate_))),
154 bytes_per_output_frame_(bytes_per_frame_), 155 bytes_per_output_frame_(bytes_per_frame_),
155 alsa_buffer_frames_(0), 156 alsa_buffer_frames_(0),
156 stop_stream_(false), 157 stop_stream_(false),
157 wrapper_(wrapper), 158 wrapper_(wrapper),
158 manager_(manager), 159 manager_(manager),
159 message_loop_(base::MessageLoop::current()), 160 task_runner_(base::ThreadTaskRunnerHandle::Get()),
160 playback_handle_(NULL), 161 playback_handle_(NULL),
161 frames_per_packet_(packet_size_ / bytes_per_frame_), 162 frames_per_packet_(packet_size_ / bytes_per_frame_),
162 state_(kCreated), 163 state_(kCreated),
163 volume_(1.0f), 164 volume_(1.0f),
164 source_callback_(NULL), 165 source_callback_(NULL),
165 audio_bus_(AudioBus::Create(params)), 166 audio_bus_(AudioBus::Create(params)),
166 weak_factory_(this) { 167 weak_factory_(this) {
167 DCHECK(manager_->GetTaskRunner()->BelongsToCurrentThread()); 168 DCHECK(manager_->GetTaskRunner()->BelongsToCurrentThread());
168 DCHECK_EQ(audio_bus_->frames() * bytes_per_frame_, packet_size_); 169 DCHECK_EQ(audio_bus_->frames() * bytes_per_frame_, packet_size_);
169 170
(...skipping 11 matching lines...) Expand all
181 182
182 AlsaPcmOutputStream::~AlsaPcmOutputStream() { 183 AlsaPcmOutputStream::~AlsaPcmOutputStream() {
183 InternalState current_state = state(); 184 InternalState current_state = state();
184 DCHECK(current_state == kCreated || 185 DCHECK(current_state == kCreated ||
185 current_state == kIsClosed || 186 current_state == kIsClosed ||
186 current_state == kInError); 187 current_state == kInError);
187 DCHECK(!playback_handle_); 188 DCHECK(!playback_handle_);
188 } 189 }
189 190
190 bool AlsaPcmOutputStream::Open() { 191 bool AlsaPcmOutputStream::Open() {
191 DCHECK(IsOnAudioThread()); 192 DCHECK(CalledOnValidThread());
192 193
193 if (state() == kInError) 194 if (state() == kInError)
194 return false; 195 return false;
195 196
196 if (!CanTransitionTo(kIsOpened)) { 197 if (!CanTransitionTo(kIsOpened)) {
197 NOTREACHED() << "Invalid state: " << state(); 198 NOTREACHED() << "Invalid state: " << state();
198 return false; 199 return false;
199 } 200 }
200 201
201 // We do not need to check if the transition was successful because 202 // We do not need to check if the transition was successful because
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
239 // Buffer size is at least twice of packet size. 240 // Buffer size is at least twice of packet size.
240 alsa_buffer_frames_ = frames_per_packet_ * 2; 241 alsa_buffer_frames_ = frames_per_packet_ * 2;
241 } else { 242 } else {
242 alsa_buffer_frames_ = buffer_size; 243 alsa_buffer_frames_ = buffer_size;
243 } 244 }
244 245
245 return true; 246 return true;
246 } 247 }
247 248
248 void AlsaPcmOutputStream::Close() { 249 void AlsaPcmOutputStream::Close() {
249 DCHECK(IsOnAudioThread()); 250 DCHECK(CalledOnValidThread());
250 251
251 if (state() != kIsClosed) 252 if (state() != kIsClosed)
252 TransitionTo(kIsClosed); 253 TransitionTo(kIsClosed);
253 254
254 // Shutdown the audio device. 255 // Shutdown the audio device.
255 if (playback_handle_) { 256 if (playback_handle_) {
256 if (alsa_util::CloseDevice(wrapper_, playback_handle_) < 0) { 257 if (alsa_util::CloseDevice(wrapper_, playback_handle_) < 0) {
257 LOG(WARNING) << "Unable to close audio device. Leaking handle."; 258 LOG(WARNING) << "Unable to close audio device. Leaking handle.";
258 } 259 }
259 playback_handle_ = NULL; 260 playback_handle_ = NULL;
260 261
261 // Release the buffer. 262 // Release the buffer.
262 buffer_.reset(); 263 buffer_.reset();
263 264
264 // Signal anything that might already be scheduled to stop. 265 // Signal anything that might already be scheduled to stop.
265 stop_stream_ = true; // Not necessary in production, but unit tests 266 stop_stream_ = true; // Not necessary in production, but unit tests
266 // uses the flag to verify that stream was closed. 267 // uses the flag to verify that stream was closed.
267 } 268 }
268 269
269 weak_factory_.InvalidateWeakPtrs(); 270 weak_factory_.InvalidateWeakPtrs();
270 271
271 // Signal to the manager that we're closed and can be removed. 272 // Signal to the manager that we're closed and can be removed.
272 // Should be last call in the method as it deletes "this". 273 // Should be last call in the method as it deletes "this".
273 manager_->ReleaseOutputStream(this); 274 manager_->ReleaseOutputStream(this);
274 } 275 }
275 276
276 void AlsaPcmOutputStream::Start(AudioSourceCallback* callback) { 277 void AlsaPcmOutputStream::Start(AudioSourceCallback* callback) {
277 DCHECK(IsOnAudioThread()); 278 DCHECK(CalledOnValidThread());
278 279
279 CHECK(callback); 280 CHECK(callback);
280 281
281 if (stop_stream_) 282 if (stop_stream_)
282 return; 283 return;
283 284
284 // Only post the task if we can enter the playing state. 285 // Only post the task if we can enter the playing state.
285 if (TransitionTo(kIsPlaying) != kIsPlaying) 286 if (TransitionTo(kIsPlaying) != kIsPlaying)
286 return; 287 return;
287 288
(...skipping 28 matching lines...) Expand all
316 memset(silent_packet->writable_data(), 0, silent_packet->data_size()); 317 memset(silent_packet->writable_data(), 0, silent_packet->data_size());
317 buffer_->Append(silent_packet); 318 buffer_->Append(silent_packet);
318 WritePacket(); 319 WritePacket();
319 320
320 // Start the callback chain. 321 // Start the callback chain.
321 set_source_callback(callback); 322 set_source_callback(callback);
322 WriteTask(); 323 WriteTask();
323 } 324 }
324 325
325 void AlsaPcmOutputStream::Stop() { 326 void AlsaPcmOutputStream::Stop() {
326 DCHECK(IsOnAudioThread()); 327 DCHECK(CalledOnValidThread());
327 328
328 // Reset the callback, so that it is not called anymore. 329 // Reset the callback, so that it is not called anymore.
329 set_source_callback(NULL); 330 set_source_callback(NULL);
330 weak_factory_.InvalidateWeakPtrs(); 331 weak_factory_.InvalidateWeakPtrs();
331 332
332 TransitionTo(kIsStopped); 333 TransitionTo(kIsStopped);
333 } 334 }
334 335
335 void AlsaPcmOutputStream::SetVolume(double volume) { 336 void AlsaPcmOutputStream::SetVolume(double volume) {
336 DCHECK(IsOnAudioThread()); 337 DCHECK(CalledOnValidThread());
337 338
338 volume_ = static_cast<float>(volume); 339 volume_ = static_cast<float>(volume);
339 } 340 }
340 341
341 void AlsaPcmOutputStream::GetVolume(double* volume) { 342 void AlsaPcmOutputStream::GetVolume(double* volume) {
342 DCHECK(IsOnAudioThread()); 343 DCHECK(CalledOnValidThread());
343 344
344 *volume = volume_; 345 *volume = volume_;
345 } 346 }
346 347
347 void AlsaPcmOutputStream::BufferPacket(bool* source_exhausted) { 348 void AlsaPcmOutputStream::BufferPacket(bool* source_exhausted) {
348 DCHECK(IsOnAudioThread()); 349 DCHECK(CalledOnValidThread());
349 350
350 // If stopped, simulate a 0-length packet. 351 // If stopped, simulate a 0-length packet.
351 if (stop_stream_) { 352 if (stop_stream_) {
352 buffer_->Clear(); 353 buffer_->Clear();
353 *source_exhausted = true; 354 *source_exhausted = true;
354 return; 355 return;
355 } 356 }
356 357
357 *source_exhausted = false; 358 *source_exhausted = false;
358 359
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
412 packet->set_data_size(packet_size); 413 packet->set_data_size(packet_size);
413 // Add the packet to the buffer. 414 // Add the packet to the buffer.
414 buffer_->Append(packet); 415 buffer_->Append(packet);
415 } else { 416 } else {
416 *source_exhausted = true; 417 *source_exhausted = true;
417 } 418 }
418 } 419 }
419 } 420 }
420 421
421 void AlsaPcmOutputStream::WritePacket() { 422 void AlsaPcmOutputStream::WritePacket() {
422 DCHECK(IsOnAudioThread()); 423 DCHECK(CalledOnValidThread());
423 424
424 // If the device is in error, just eat the bytes. 425 // If the device is in error, just eat the bytes.
425 if (stop_stream_) { 426 if (stop_stream_) {
426 buffer_->Clear(); 427 buffer_->Clear();
427 return; 428 return;
428 } 429 }
429 430
430 if (state() != kIsPlaying) 431 if (state() != kIsPlaying)
431 return; 432 return;
432 433
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
471 // This ensures that shorter sounds will still play. 472 // This ensures that shorter sounds will still play.
472 if (playback_handle_ && 473 if (playback_handle_ &&
473 (wrapper_->PcmState(playback_handle_) == SND_PCM_STATE_PREPARED) && 474 (wrapper_->PcmState(playback_handle_) == SND_PCM_STATE_PREPARED) &&
474 GetCurrentDelay() > 0) { 475 GetCurrentDelay() > 0) {
475 wrapper_->PcmStart(playback_handle_); 476 wrapper_->PcmStart(playback_handle_);
476 } 477 }
477 } 478 }
478 } 479 }
479 480
480 void AlsaPcmOutputStream::WriteTask() { 481 void AlsaPcmOutputStream::WriteTask() {
481 DCHECK(IsOnAudioThread()); 482 DCHECK(CalledOnValidThread());
482 483
483 if (stop_stream_) 484 if (stop_stream_)
484 return; 485 return;
485 486
486 if (state() == kIsStopped) 487 if (state() == kIsStopped)
487 return; 488 return;
488 489
489 bool source_exhausted; 490 bool source_exhausted;
490 BufferPacket(&source_exhausted); 491 BufferPacket(&source_exhausted);
491 WritePacket(); 492 WritePacket();
492 493
493 ScheduleNextWrite(source_exhausted); 494 ScheduleNextWrite(source_exhausted);
494 } 495 }
495 496
496 void AlsaPcmOutputStream::ScheduleNextWrite(bool source_exhausted) { 497 void AlsaPcmOutputStream::ScheduleNextWrite(bool source_exhausted) {
497 DCHECK(IsOnAudioThread()); 498 DCHECK(CalledOnValidThread());
498 499
499 if (stop_stream_ || state() != kIsPlaying) 500 if (stop_stream_ || state() != kIsPlaying)
500 return; 501 return;
501 502
502 const uint32_t kTargetFramesAvailable = alsa_buffer_frames_ / 2; 503 const uint32_t kTargetFramesAvailable = alsa_buffer_frames_ / 2;
503 uint32_t available_frames = GetAvailableFrames(); 504 uint32_t available_frames = GetAvailableFrames();
504 505
505 base::TimeDelta next_fill_time; 506 base::TimeDelta next_fill_time;
506 if (buffer_->forward_bytes() && available_frames) { 507 if (buffer_->forward_bytes() && available_frames) {
507 // If we've got data available and ALSA has room, deliver it immediately. 508 // If we've got data available and ALSA has room, deliver it immediately.
(...skipping 12 matching lines...) Expand all
520 } else if (!source_exhausted) { 521 } else if (!source_exhausted) {
521 // The sound card has |kTargetFramesAvailable| or more frames available. 522 // The sound card has |kTargetFramesAvailable| or more frames available.
522 // Invoke the next write immediately to avoid underrun. 523 // Invoke the next write immediately to avoid underrun.
523 next_fill_time = base::TimeDelta(); 524 next_fill_time = base::TimeDelta();
524 } else { 525 } else {
525 // The sound card has frames available, but our source is exhausted, so 526 // The sound card has frames available, but our source is exhausted, so
526 // avoid busy looping by delaying a bit. 527 // avoid busy looping by delaying a bit.
527 next_fill_time = base::TimeDelta::FromMilliseconds(10); 528 next_fill_time = base::TimeDelta::FromMilliseconds(10);
528 } 529 }
529 530
530 message_loop_->PostDelayedTask(FROM_HERE, base::Bind( 531 task_runner_->PostDelayedTask(
531 &AlsaPcmOutputStream::WriteTask, weak_factory_.GetWeakPtr()), 532 FROM_HERE,
533 base::Bind(&AlsaPcmOutputStream::WriteTask, weak_factory_.GetWeakPtr()),
532 next_fill_time); 534 next_fill_time);
533 } 535 }
534 536
535 // static 537 // static
536 base::TimeDelta AlsaPcmOutputStream::FramesToTimeDelta(int frames, 538 base::TimeDelta AlsaPcmOutputStream::FramesToTimeDelta(int frames,
537 double sample_rate) { 539 double sample_rate) {
538 return base::TimeDelta::FromMicroseconds( 540 return base::TimeDelta::FromMicroseconds(
539 frames * base::Time::kMicrosecondsPerSecond / sample_rate); 541 frames * base::Time::kMicrosecondsPerSecond / sample_rate);
540 } 542 }
541 543
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after
620 } 622 }
621 623
622 if (delay < 0) { 624 if (delay < 0) {
623 delay = 0; 625 delay = 0;
624 } 626 }
625 627
626 return delay; 628 return delay;
627 } 629 }
628 630
629 snd_pcm_sframes_t AlsaPcmOutputStream::GetAvailableFrames() { 631 snd_pcm_sframes_t AlsaPcmOutputStream::GetAvailableFrames() {
630 DCHECK(IsOnAudioThread()); 632 DCHECK(CalledOnValidThread());
631 633
632 if (stop_stream_) 634 if (stop_stream_)
633 return 0; 635 return 0;
634 636
635 // Find the number of frames queued in the sound device. 637 // Find the number of frames queued in the sound device.
636 snd_pcm_sframes_t available_frames = 638 snd_pcm_sframes_t available_frames =
637 wrapper_->PcmAvailUpdate(playback_handle_); 639 wrapper_->PcmAvailUpdate(playback_handle_);
638 if (available_frames < 0) { 640 if (available_frames < 0) {
639 available_frames = wrapper_->PcmRecover(playback_handle_, 641 available_frames = wrapper_->PcmRecover(playback_handle_,
640 available_frames, 642 available_frames,
(...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after
753 return to == kIsClosed || to == kInError; 755 return to == kIsClosed || to == kInError;
754 756
755 case kIsClosed: 757 case kIsClosed:
756 default: 758 default:
757 return false; 759 return false;
758 } 760 }
759 } 761 }
760 762
761 AlsaPcmOutputStream::InternalState 763 AlsaPcmOutputStream::InternalState
762 AlsaPcmOutputStream::TransitionTo(InternalState to) { 764 AlsaPcmOutputStream::TransitionTo(InternalState to) {
763 DCHECK(IsOnAudioThread()); 765 DCHECK(CalledOnValidThread());
764 766
765 if (!CanTransitionTo(to)) { 767 if (!CanTransitionTo(to)) {
766 NOTREACHED() << "Cannot transition from: " << state_ << " to: " << to; 768 NOTREACHED() << "Cannot transition from: " << state_ << " to: " << to;
767 state_ = kInError; 769 state_ = kInError;
768 } else { 770 } else {
769 state_ = to; 771 state_ = to;
770 } 772 }
771 return state_; 773 return state_;
772 } 774 }
773 775
774 AlsaPcmOutputStream::InternalState AlsaPcmOutputStream::state() { 776 AlsaPcmOutputStream::InternalState AlsaPcmOutputStream::state() {
775 return state_; 777 return state_;
776 } 778 }
777 779
778 bool AlsaPcmOutputStream::IsOnAudioThread() const {
779 return message_loop_ && message_loop_ == base::MessageLoop::current();
780 }
781
782 int AlsaPcmOutputStream::RunDataCallback(AudioBus* audio_bus, 780 int AlsaPcmOutputStream::RunDataCallback(AudioBus* audio_bus,
783 uint32_t total_bytes_delay) { 781 uint32_t total_bytes_delay) {
784 TRACE_EVENT0("audio", "AlsaPcmOutputStream::RunDataCallback"); 782 TRACE_EVENT0("audio", "AlsaPcmOutputStream::RunDataCallback");
785 783
786 if (source_callback_) 784 if (source_callback_)
787 return source_callback_->OnMoreData(audio_bus, total_bytes_delay, 0); 785 return source_callback_->OnMoreData(audio_bus, total_bytes_delay, 0);
788 786
789 return 0; 787 return 0;
790 } 788 }
791 789
792 void AlsaPcmOutputStream::RunErrorCallback(int code) { 790 void AlsaPcmOutputStream::RunErrorCallback(int code) {
793 if (source_callback_) 791 if (source_callback_)
794 source_callback_->OnError(this); 792 source_callback_->OnError(this);
795 } 793 }
796 794
797 // Changes the AudioSourceCallback to proxy calls to. Pass in NULL to 795 // Changes the AudioSourceCallback to proxy calls to. Pass in NULL to
798 // release ownership of the currently registered callback. 796 // release ownership of the currently registered callback.
799 void AlsaPcmOutputStream::set_source_callback(AudioSourceCallback* callback) { 797 void AlsaPcmOutputStream::set_source_callback(AudioSourceCallback* callback) {
800 DCHECK(IsOnAudioThread()); 798 DCHECK(CalledOnValidThread());
801 source_callback_ = callback; 799 source_callback_ = callback;
802 } 800 }
803 801
804 } // namespace media 802 } // namespace media
OLDNEW
« no previous file with comments | « media/audio/alsa/alsa_output.h ('k') | media/audio/sounds/test_data.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698