OLD | NEW |
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 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 358 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
369 shared_data_.set_volume(static_cast<float>(volume)); | 369 shared_data_.set_volume(static_cast<float>(volume)); |
370 } | 370 } |
371 | 371 |
372 void AlsaPcmOutputStream::GetVolume(double* volume) { | 372 void AlsaPcmOutputStream::GetVolume(double* volume) { |
373 DCHECK_EQ(MessageLoop::current(), client_thread_loop_); | 373 DCHECK_EQ(MessageLoop::current(), client_thread_loop_); |
374 | 374 |
375 *volume = shared_data_.volume(); | 375 *volume = shared_data_.volume(); |
376 } | 376 } |
377 | 377 |
378 void AlsaPcmOutputStream::OpenTask(uint32 packet_size) { | 378 void AlsaPcmOutputStream::OpenTask(uint32 packet_size) { |
379 DCHECK_EQ(message_loop_, MessageLoop::current()); | 379 DCHECK_EQ(MessageLoop::current(), message_loop_); |
380 | 380 |
381 // Initialize the configuration variables. | 381 // Initialize the configuration variables. |
382 packet_size_ = packet_size; | 382 packet_size_ = packet_size; |
383 frames_per_packet_ = packet_size_ / bytes_per_frame_; | 383 frames_per_packet_ = packet_size_ / bytes_per_frame_; |
384 | 384 |
385 // Try to open the device. | 385 // Try to open the device. |
386 micros_per_packet_ = | 386 micros_per_packet_ = |
387 FramesToMicros(packet_size / bytes_per_frame_, sample_rate_); | 387 FramesToMicros(packet_size / bytes_per_frame_, sample_rate_); |
388 latency_micros_ = std::max(AlsaPcmOutputStream::kMinLatencyMicros, | 388 latency_micros_ = std::max(AlsaPcmOutputStream::kMinLatencyMicros, |
389 micros_per_packet_ * 2); | 389 micros_per_packet_ * 2); |
(...skipping 25 matching lines...) Expand all Loading... |
415 LOG(ERROR) << "Failed to get playback buffer size from ALSA: " | 415 LOG(ERROR) << "Failed to get playback buffer size from ALSA: " |
416 << wrapper_->StrError(error); | 416 << wrapper_->StrError(error); |
417 alsa_buffer_frames_ = frames_per_packet_; | 417 alsa_buffer_frames_ = frames_per_packet_; |
418 } else { | 418 } else { |
419 alsa_buffer_frames_ = buffer_size; | 419 alsa_buffer_frames_ = buffer_size; |
420 } | 420 } |
421 } | 421 } |
422 } | 422 } |
423 | 423 |
424 void AlsaPcmOutputStream::StartTask() { | 424 void AlsaPcmOutputStream::StartTask() { |
425 DCHECK_EQ(message_loop_, MessageLoop::current()); | 425 DCHECK_EQ(MessageLoop::current(), message_loop_); |
426 | 426 |
427 if (stop_stream_) { | 427 if (stop_stream_) { |
428 return; | 428 return; |
429 } | 429 } |
430 | 430 |
431 // When starting again, drop all packets in the device and prepare it again | 431 // When starting again, drop all packets in the device and prepare it again |
432 // incase we are restarting from a pause state and need to flush old data. | 432 // incase we are restarting from a pause state and need to flush old data. |
433 int error = wrapper_->PcmDrop(playback_handle_); | 433 int error = wrapper_->PcmDrop(playback_handle_); |
434 if (error < 0 && error != -EAGAIN) { | 434 if (error < 0 && error != -EAGAIN) { |
435 LOG(ERROR) << "Failure clearing playback device (" | 435 LOG(ERROR) << "Failure clearing playback device (" |
(...skipping 11 matching lines...) Expand all Loading... |
447 stop_stream_ = true; | 447 stop_stream_ = true; |
448 return; | 448 return; |
449 } | 449 } |
450 | 450 |
451 ScheduleNextWrite(false); | 451 ScheduleNextWrite(false); |
452 } | 452 } |
453 | 453 |
454 void AlsaPcmOutputStream::CloseTask() { | 454 void AlsaPcmOutputStream::CloseTask() { |
455 // NOTE: Keep this function idempotent to handle errors that might cause | 455 // NOTE: Keep this function idempotent to handle errors that might cause |
456 // multiple CloseTasks to be posted. | 456 // multiple CloseTasks to be posted. |
457 DCHECK_EQ(message_loop_, MessageLoop::current()); | 457 DCHECK_EQ(MessageLoop::current(), message_loop_); |
458 | 458 |
459 // Shutdown the audio device. | 459 // Shutdown the audio device. |
460 if (playback_handle_ && !CloseDevice(playback_handle_)) { | 460 if (playback_handle_ && !CloseDevice(playback_handle_)) { |
461 LOG(WARNING) << "Unable to close audio device. Leaking handle."; | 461 LOG(WARNING) << "Unable to close audio device. Leaking handle."; |
462 } | 462 } |
463 playback_handle_ = NULL; | 463 playback_handle_ = NULL; |
464 | 464 |
465 // Release the buffer. | 465 // Release the buffer. |
466 buffer_.reset(); | 466 buffer_.reset(); |
467 | 467 |
468 // Signal anything that might already be scheduled to stop. | 468 // Signal anything that might already be scheduled to stop. |
469 stop_stream_ = true; | 469 stop_stream_ = true; |
470 } | 470 } |
471 | 471 |
472 void AlsaPcmOutputStream::BufferPacket(bool* source_exhausted) { | 472 void AlsaPcmOutputStream::BufferPacket(bool* source_exhausted) { |
473 DCHECK_EQ(message_loop_, MessageLoop::current()); | 473 DCHECK_EQ(MessageLoop::current(), message_loop_); |
474 | 474 |
475 // If stopped, simulate a 0-lengthed packet. | 475 // If stopped, simulate a 0-lengthed packet. |
476 if (stop_stream_) { | 476 if (stop_stream_) { |
477 buffer_->Clear(); | 477 buffer_->Clear(); |
478 *source_exhausted = true; | 478 *source_exhausted = true; |
479 return; | 479 return; |
480 } | 480 } |
481 | 481 |
482 *source_exhausted = false; | 482 *source_exhausted = false; |
483 | 483 |
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
551 packet->SetDataSize(packet_size); | 551 packet->SetDataSize(packet_size); |
552 // Add the packet to the buffer. | 552 // Add the packet to the buffer. |
553 buffer_->Append(packet); | 553 buffer_->Append(packet); |
554 } else { | 554 } else { |
555 *source_exhausted = true; | 555 *source_exhausted = true; |
556 } | 556 } |
557 } | 557 } |
558 } | 558 } |
559 | 559 |
560 void AlsaPcmOutputStream::WritePacket() { | 560 void AlsaPcmOutputStream::WritePacket() { |
561 DCHECK_EQ(message_loop_, MessageLoop::current()); | 561 DCHECK_EQ(MessageLoop::current(), message_loop_); |
562 | 562 |
563 // If the device is in error, just eat the bytes. | 563 // If the device is in error, just eat the bytes. |
564 if (stop_stream_) { | 564 if (stop_stream_) { |
565 buffer_->Clear(); | 565 buffer_->Clear(); |
566 return; | 566 return; |
567 } | 567 } |
568 | 568 |
569 CHECK_EQ(buffer_->forward_bytes() % bytes_per_output_frame_, 0u); | 569 CHECK_EQ(buffer_->forward_bytes() % bytes_per_output_frame_, 0u); |
570 | 570 |
571 const uint8* buffer_data; | 571 const uint8* buffer_data; |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
604 frames_written = frames; | 604 frames_written = frames; |
605 } | 605 } |
606 | 606 |
607 // Seek forward in the buffer after we've written some data to ALSA. | 607 // Seek forward in the buffer after we've written some data to ALSA. |
608 buffer_->Seek(frames_written * bytes_per_output_frame_); | 608 buffer_->Seek(frames_written * bytes_per_output_frame_); |
609 } | 609 } |
610 } | 610 } |
611 } | 611 } |
612 | 612 |
613 void AlsaPcmOutputStream::WriteTask() { | 613 void AlsaPcmOutputStream::WriteTask() { |
614 DCHECK_EQ(message_loop_, MessageLoop::current()); | 614 DCHECK_EQ(MessageLoop::current(), message_loop_); |
615 | 615 |
616 if (stop_stream_) { | 616 if (stop_stream_) { |
617 return; | 617 return; |
618 } | 618 } |
619 | 619 |
620 bool source_exhausted; | 620 bool source_exhausted; |
621 BufferPacket(&source_exhausted); | 621 BufferPacket(&source_exhausted); |
622 WritePacket(); | 622 WritePacket(); |
623 | 623 |
624 ScheduleNextWrite(source_exhausted); | 624 ScheduleNextWrite(source_exhausted); |
625 } | 625 } |
626 | 626 |
627 void AlsaPcmOutputStream::ScheduleNextWrite(bool source_exhausted) { | 627 void AlsaPcmOutputStream::ScheduleNextWrite(bool source_exhausted) { |
628 DCHECK_EQ(message_loop_, MessageLoop::current()); | 628 DCHECK_EQ(MessageLoop::current(), message_loop_); |
629 | 629 |
630 if (stop_stream_) { | 630 if (stop_stream_) { |
631 return; | 631 return; |
632 } | 632 } |
633 | 633 |
634 // Next write is scheduled for the moment when half of the buffer is | 634 // Next write is scheduled for the moment when half of the buffer is |
635 // available. | 635 // available. |
636 uint32 frames_avail_wanted = alsa_buffer_frames_ / 2; | 636 uint32 frames_avail_wanted = alsa_buffer_frames_ / 2; |
637 uint32 available_frames = GetAvailableFrames(); | 637 uint32 available_frames = GetAvailableFrames(); |
638 uint32 next_fill_time_ms = 0; | 638 uint32 next_fill_time_ms = 0; |
(...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
771 if (error < 0) { | 771 if (error < 0) { |
772 LOG(ERROR) << "Error closing audio device (" << name << "): " | 772 LOG(ERROR) << "Error closing audio device (" << name << "): " |
773 << wrapper_->StrError(error); | 773 << wrapper_->StrError(error); |
774 return false; | 774 return false; |
775 } | 775 } |
776 | 776 |
777 return true; | 777 return true; |
778 } | 778 } |
779 | 779 |
780 snd_pcm_sframes_t AlsaPcmOutputStream::GetAvailableFrames() { | 780 snd_pcm_sframes_t AlsaPcmOutputStream::GetAvailableFrames() { |
781 DCHECK_EQ(message_loop_, MessageLoop::current()); | 781 DCHECK_EQ(MessageLoop::current(), message_loop_); |
782 | 782 |
783 if (stop_stream_) { | 783 if (stop_stream_) { |
784 return 0; | 784 return 0; |
785 } | 785 } |
786 | 786 |
787 // Find the number of frames queued in the sound device. | 787 // Find the number of frames queued in the sound device. |
788 snd_pcm_sframes_t available_frames = | 788 snd_pcm_sframes_t available_frames = |
789 wrapper_->PcmAvailUpdate(playback_handle_); | 789 wrapper_->PcmAvailUpdate(playback_handle_); |
790 if (available_frames < 0) { | 790 if (available_frames < 0) { |
791 available_frames = wrapper_->PcmRecover(playback_handle_, | 791 available_frames = wrapper_->PcmRecover(playback_handle_, |
(...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
959 } | 959 } |
960 | 960 |
961 // Changes the AudioSourceCallback to proxy calls to. Pass in NULL to | 961 // Changes the AudioSourceCallback to proxy calls to. Pass in NULL to |
962 // release ownership of the currently registered callback. | 962 // release ownership of the currently registered callback. |
963 void AlsaPcmOutputStream::SharedData::set_source_callback( | 963 void AlsaPcmOutputStream::SharedData::set_source_callback( |
964 AudioSourceCallback* callback) { | 964 AudioSourceCallback* callback) { |
965 DCHECK_EQ(MessageLoop::current(), state_transition_loop_); | 965 DCHECK_EQ(MessageLoop::current(), state_transition_loop_); |
966 AutoLock l(lock_); | 966 AutoLock l(lock_); |
967 source_callback_ = callback; | 967 source_callback_ = callback; |
968 } | 968 } |
OLD | NEW |