| 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 |