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(); | |
scherkus (not reviewing)
2011/04/11 18:22:39
final question: are we sure this won't clobber any
davejcool
2011/04/13 01:24:05
If there is something in buffer_, it must be from
| |
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 ((wrapper_->PcmState(playback_handle_) == SND_PCM_STATE_PREPARED) && | |
598 GetCurrentDelay() > 0) { | |
599 wrapper_->PcmStart(playback_handle_); | |
600 } | |
582 } | 601 } |
583 } | 602 } |
584 | 603 |
585 void AlsaPcmOutputStream::WriteTask() { | 604 void AlsaPcmOutputStream::WriteTask() { |
586 DCHECK_EQ(message_loop_, MessageLoop::current()); | 605 DCHECK_EQ(message_loop_, MessageLoop::current()); |
587 | 606 |
588 if (stop_stream_) { | 607 if (stop_stream_) { |
589 return; | 608 return; |
590 } | 609 } |
591 | 610 |
611 if (shared_data_.state() == kIsStopped) { | |
612 return; | |
613 } | |
614 | |
592 bool source_exhausted; | 615 bool source_exhausted; |
593 BufferPacket(&source_exhausted); | 616 BufferPacket(&source_exhausted); |
594 WritePacket(); | 617 WritePacket(); |
595 | 618 |
596 ScheduleNextWrite(source_exhausted); | 619 ScheduleNextWrite(source_exhausted); |
597 } | 620 } |
598 | 621 |
599 void AlsaPcmOutputStream::ScheduleNextWrite(bool source_exhausted) { | 622 void AlsaPcmOutputStream::ScheduleNextWrite(bool source_exhausted) { |
600 DCHECK_EQ(message_loop_, MessageLoop::current()); | 623 DCHECK_EQ(message_loop_, MessageLoop::current()); |
601 | 624 |
(...skipping 311 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
913 } | 936 } |
914 | 937 |
915 // Changes the AudioSourceCallback to proxy calls to. Pass in NULL to | 938 // Changes the AudioSourceCallback to proxy calls to. Pass in NULL to |
916 // release ownership of the currently registered callback. | 939 // release ownership of the currently registered callback. |
917 void AlsaPcmOutputStream::SharedData::set_source_callback( | 940 void AlsaPcmOutputStream::SharedData::set_source_callback( |
918 AudioSourceCallback* callback) { | 941 AudioSourceCallback* callback) { |
919 DCHECK_EQ(MessageLoop::current(), state_transition_loop_); | 942 DCHECK_EQ(MessageLoop::current(), state_transition_loop_); |
920 base::AutoLock l(lock_); | 943 base::AutoLock l(lock_); |
921 source_callback_ = callback; | 944 source_callback_ = callback; |
922 } | 945 } |
OLD | NEW |