OLD | NEW |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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 // The AlsaPcmOutputStream object's internal state is accessed by two threads: | 7 // The AlsaPcmOutputStream object's internal state is accessed by two threads: |
8 // | 8 // |
9 // client thread - creates the object and calls the public APIs. | 9 // client thread - creates the object and calls the public APIs. |
10 // message loop thread - executes all the internal tasks including querying | 10 // message loop thread - executes all the internal tasks including querying |
(...skipping 377 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
388 } | 388 } |
389 } | 389 } |
390 | 390 |
391 void AlsaPcmOutputStream::StartTask() { | 391 void AlsaPcmOutputStream::StartTask() { |
392 DCHECK_EQ(message_loop_, MessageLoop::current()); | 392 DCHECK_EQ(message_loop_, MessageLoop::current()); |
393 | 393 |
394 if (stop_stream_) { | 394 if (stop_stream_) { |
395 return; | 395 return; |
396 } | 396 } |
397 | 397 |
| 398 if (shared_data_.state() != kIsPlaying) { |
| 399 return; |
| 400 } |
| 401 |
| 402 // Before starting, the buffer might have audio from previous user of this |
| 403 // device. |
| 404 buffer_->Clear(); |
| 405 |
398 // When starting again, drop all packets in the device and prepare it again | 406 // When starting again, drop all packets in the device and prepare it again |
399 // incase we are restarting from a pause state and need to flush old data. | 407 // incase we are restarting from a pause state and need to flush old data. |
400 int error = wrapper_->PcmDrop(playback_handle_); | 408 int error = wrapper_->PcmDrop(playback_handle_); |
401 if (error < 0 && error != -EAGAIN) { | 409 if (error < 0 && error != -EAGAIN) { |
402 LOG(ERROR) << "Failure clearing playback device (" | 410 LOG(ERROR) << "Failure clearing playback device (" |
403 << wrapper_->PcmName(playback_handle_) << "): " | 411 << wrapper_->PcmName(playback_handle_) << "): " |
404 << wrapper_->StrError(error); | 412 << wrapper_->StrError(error); |
405 stop_stream_ = true; | 413 stop_stream_ = true; |
406 return; | 414 return; |
407 } | 415 } |
(...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
531 | 539 |
532 void AlsaPcmOutputStream::WritePacket() { | 540 void AlsaPcmOutputStream::WritePacket() { |
533 DCHECK_EQ(message_loop_, MessageLoop::current()); | 541 DCHECK_EQ(message_loop_, MessageLoop::current()); |
534 | 542 |
535 // If the device is in error, just eat the bytes. | 543 // If the device is in error, just eat the bytes. |
536 if (stop_stream_) { | 544 if (stop_stream_) { |
537 buffer_->Clear(); | 545 buffer_->Clear(); |
538 return; | 546 return; |
539 } | 547 } |
540 | 548 |
| 549 if (shared_data_.state() == kIsStopped) { |
| 550 return; |
| 551 } |
| 552 |
541 CHECK_EQ(buffer_->forward_bytes() % bytes_per_output_frame_, 0u); | 553 CHECK_EQ(buffer_->forward_bytes() % bytes_per_output_frame_, 0u); |
542 | 554 |
543 const uint8* buffer_data; | 555 const uint8* buffer_data; |
544 size_t buffer_size; | 556 size_t buffer_size; |
545 if (buffer_->GetCurrentChunk(&buffer_data, &buffer_size)) { | 557 if (buffer_->GetCurrentChunk(&buffer_data, &buffer_size)) { |
546 buffer_size = buffer_size - (buffer_size % bytes_per_output_frame_); | 558 buffer_size = buffer_size - (buffer_size % bytes_per_output_frame_); |
547 snd_pcm_sframes_t frames = buffer_size / bytes_per_output_frame_; | 559 snd_pcm_sframes_t frames = buffer_size / bytes_per_output_frame_; |
548 | 560 |
549 DCHECK_GT(frames, 0); | 561 DCHECK_GT(frames, 0); |
550 | 562 |
(...skipping 21 matching lines...) Expand all Loading... |
572 } else { | 584 } else { |
573 if (frames_written > frames) { | 585 if (frames_written > frames) { |
574 LOG(WARNING) | 586 LOG(WARNING) |
575 << "snd_pcm_writei() has written more frame that we asked."; | 587 << "snd_pcm_writei() has written more frame that we asked."; |
576 frames_written = frames; | 588 frames_written = frames; |
577 } | 589 } |
578 | 590 |
579 // Seek forward in the buffer after we've written some data to ALSA. | 591 // Seek forward in the buffer after we've written some data to ALSA. |
580 buffer_->Seek(frames_written * bytes_per_output_frame_); | 592 buffer_->Seek(frames_written * bytes_per_output_frame_); |
581 } | 593 } |
| 594 } else { |
| 595 // If nothing left to write and playback hasn't started yet, start it now. |
| 596 // This ensures that shorter sounds will still play. |
| 597 if (playback_handle_ && |
| 598 (wrapper_->PcmState(playback_handle_) == SND_PCM_STATE_PREPARED) && |
| 599 GetCurrentDelay() > 0) { |
| 600 wrapper_->PcmStart(playback_handle_); |
| 601 } |
582 } | 602 } |
583 } | 603 } |
584 | 604 |
585 void AlsaPcmOutputStream::WriteTask() { | 605 void AlsaPcmOutputStream::WriteTask() { |
586 DCHECK_EQ(message_loop_, MessageLoop::current()); | 606 DCHECK_EQ(message_loop_, MessageLoop::current()); |
587 | 607 |
588 if (stop_stream_) { | 608 if (stop_stream_) { |
589 return; | 609 return; |
590 } | 610 } |
591 | 611 |
| 612 if (shared_data_.state() == kIsStopped) { |
| 613 return; |
| 614 } |
| 615 |
592 bool source_exhausted; | 616 bool source_exhausted; |
593 BufferPacket(&source_exhausted); | 617 BufferPacket(&source_exhausted); |
594 WritePacket(); | 618 WritePacket(); |
595 | 619 |
596 ScheduleNextWrite(source_exhausted); | 620 ScheduleNextWrite(source_exhausted); |
597 } | 621 } |
598 | 622 |
599 void AlsaPcmOutputStream::ScheduleNextWrite(bool source_exhausted) { | 623 void AlsaPcmOutputStream::ScheduleNextWrite(bool source_exhausted) { |
600 DCHECK_EQ(message_loop_, MessageLoop::current()); | 624 DCHECK_EQ(message_loop_, MessageLoop::current()); |
601 | 625 |
(...skipping 311 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
913 } | 937 } |
914 | 938 |
915 // Changes the AudioSourceCallback to proxy calls to. Pass in NULL to | 939 // Changes the AudioSourceCallback to proxy calls to. Pass in NULL to |
916 // release ownership of the currently registered callback. | 940 // release ownership of the currently registered callback. |
917 void AlsaPcmOutputStream::SharedData::set_source_callback( | 941 void AlsaPcmOutputStream::SharedData::set_source_callback( |
918 AudioSourceCallback* callback) { | 942 AudioSourceCallback* callback) { |
919 DCHECK_EQ(MessageLoop::current(), state_transition_loop_); | 943 DCHECK_EQ(MessageLoop::current(), state_transition_loop_); |
920 base::AutoLock l(lock_); | 944 base::AutoLock l(lock_); |
921 source_callback_ = callback; | 945 source_callback_ = callback; |
922 } | 946 } |
OLD | NEW |