| 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 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 75 | 75 |
| 76 #include "media/audio/linux/alsa_output.h" | 76 #include "media/audio/linux/alsa_output.h" |
| 77 | 77 |
| 78 #include <algorithm> | 78 #include <algorithm> |
| 79 | 79 |
| 80 #include "base/logging.h" | 80 #include "base/logging.h" |
| 81 #include "base/message_loop.h" | 81 #include "base/message_loop.h" |
| 82 #include "base/stl_util-inl.h" | 82 #include "base/stl_util-inl.h" |
| 83 #include "base/time.h" | 83 #include "base/time.h" |
| 84 #include "media/audio/audio_util.h" | 84 #include "media/audio/audio_util.h" |
| 85 #include "media/audio/linux/alsa_util.h" |
| 85 #include "media/audio/linux/alsa_wrapper.h" | 86 #include "media/audio/linux/alsa_wrapper.h" |
| 86 #include "media/audio/linux/audio_manager_linux.h" | 87 #include "media/audio/linux/audio_manager_linux.h" |
| 87 #include "media/base/data_buffer.h" | 88 #include "media/base/data_buffer.h" |
| 88 #include "media/base/seekable_buffer.h" | 89 #include "media/base/seekable_buffer.h" |
| 89 | 90 |
| 90 // Amount of time to wait if we've exhausted the data source. This is to avoid | 91 // Amount of time to wait if we've exhausted the data source. This is to avoid |
| 91 // busy looping. | 92 // busy looping. |
| 92 static const uint32 kNoDataSleepMilliseconds = 10; | 93 static const uint32 kNoDataSleepMilliseconds = 10; |
| 93 | 94 |
| 94 // According to the linux nanosleep manpage, nanosleep on linux can miss the | 95 // According to the linux nanosleep manpage, nanosleep on linux can miss the |
| (...skipping 17 matching lines...) Expand all Loading... |
| 112 // kSleepErrorMilliseconds, double that for our minimum required latency. | 113 // kSleepErrorMilliseconds, double that for our minimum required latency. |
| 113 const uint32 AlsaPcmOutputStream::kMinLatencyMicros = | 114 const uint32 AlsaPcmOutputStream::kMinLatencyMicros = |
| 114 kSleepErrorMilliseconds * 2 * 1000; | 115 kSleepErrorMilliseconds * 2 * 1000; |
| 115 | 116 |
| 116 namespace { | 117 namespace { |
| 117 | 118 |
| 118 // ALSA is currently limited to 48Khz. | 119 // ALSA is currently limited to 48Khz. |
| 119 // TODO(fbarchard): Resample audio from higher frequency to 48000. | 120 // TODO(fbarchard): Resample audio from higher frequency to 48000. |
| 120 const int kAlsaMaxSampleRate = 48000; | 121 const int kAlsaMaxSampleRate = 48000; |
| 121 | 122 |
| 122 snd_pcm_format_t BitsToFormat(char bits_per_sample) { | |
| 123 switch (bits_per_sample) { | |
| 124 case 8: | |
| 125 return SND_PCM_FORMAT_U8; | |
| 126 | |
| 127 case 16: | |
| 128 return SND_PCM_FORMAT_S16; | |
| 129 | |
| 130 case 24: | |
| 131 return SND_PCM_FORMAT_S24; | |
| 132 | |
| 133 case 32: | |
| 134 return SND_PCM_FORMAT_S32; | |
| 135 | |
| 136 default: | |
| 137 return SND_PCM_FORMAT_UNKNOWN; | |
| 138 } | |
| 139 } | |
| 140 | |
| 141 // While the "default" device may support multi-channel audio, in Alsa, only | 123 // While the "default" device may support multi-channel audio, in Alsa, only |
| 142 // the device names surround40, surround41, surround50, etc, have a defined | 124 // the device names surround40, surround41, surround50, etc, have a defined |
| 143 // channel mapping according to Lennart: | 125 // channel mapping according to Lennart: |
| 144 // | 126 // |
| 145 // http://0pointer.de/blog/projects/guide-to-sound-apis.html | 127 // http://0pointer.de/blog/projects/guide-to-sound-apis.html |
| 146 // | 128 // |
| 147 // This function makes a best guess at the specific > 2 channel device name | 129 // This function makes a best guess at the specific > 2 channel device name |
| 148 // based on the number of channels requested. NULL is returned if no device | 130 // based on the number of channels requested. NULL is returned if no device |
| 149 // can be found to match the channel numbers. In this case, using | 131 // can be found to match the channel numbers. In this case, using |
| 150 // kDefaultDevice is probably the best bet. | 132 // kDefaultDevice is probably the best bet. |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 236 return os; | 218 return os; |
| 237 } | 219 } |
| 238 | 220 |
| 239 AlsaPcmOutputStream::AlsaPcmOutputStream(const std::string& device_name, | 221 AlsaPcmOutputStream::AlsaPcmOutputStream(const std::string& device_name, |
| 240 AudioParameters params, | 222 AudioParameters params, |
| 241 AlsaWrapper* wrapper, | 223 AlsaWrapper* wrapper, |
| 242 AudioManagerLinux* manager, | 224 AudioManagerLinux* manager, |
| 243 MessageLoop* message_loop) | 225 MessageLoop* message_loop) |
| 244 : shared_data_(MessageLoop::current()), | 226 : shared_data_(MessageLoop::current()), |
| 245 requested_device_name_(device_name), | 227 requested_device_name_(device_name), |
| 246 pcm_format_(BitsToFormat(params.bits_per_sample)), | 228 pcm_format_(alsa_util::BitsToFormat(params.bits_per_sample)), |
| 247 channels_(params.channels), | 229 channels_(params.channels), |
| 248 sample_rate_(params.sample_rate), | 230 sample_rate_(params.sample_rate), |
| 249 bytes_per_sample_(params.bits_per_sample / 8), | 231 bytes_per_sample_(params.bits_per_sample / 8), |
| 250 bytes_per_frame_(channels_ * params.bits_per_sample / 8), | 232 bytes_per_frame_(channels_ * params.bits_per_sample / 8), |
| 251 should_downmix_(false), | 233 should_downmix_(false), |
| 252 latency_micros_(0), | 234 latency_micros_(0), |
| 253 micros_per_packet_(0), | 235 micros_per_packet_(0), |
| 254 bytes_per_output_frame_(bytes_per_frame_), | 236 bytes_per_output_frame_(bytes_per_frame_), |
| 255 alsa_buffer_frames_(0), | 237 alsa_buffer_frames_(0), |
| 256 stop_stream_(false), | 238 stop_stream_(false), |
| (...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 384 FramesToMicros(packet_size / bytes_per_frame_, sample_rate_); | 366 FramesToMicros(packet_size / bytes_per_frame_, sample_rate_); |
| 385 latency_micros_ = std::max(AlsaPcmOutputStream::kMinLatencyMicros, | 367 latency_micros_ = std::max(AlsaPcmOutputStream::kMinLatencyMicros, |
| 386 micros_per_packet_ * 2); | 368 micros_per_packet_ * 2); |
| 387 if (requested_device_name_ == kAutoSelectDevice) { | 369 if (requested_device_name_ == kAutoSelectDevice) { |
| 388 playback_handle_ = AutoSelectDevice(latency_micros_); | 370 playback_handle_ = AutoSelectDevice(latency_micros_); |
| 389 if (playback_handle_) { | 371 if (playback_handle_) { |
| 390 LOG(INFO) << "Auto-selected device: " << device_name_; | 372 LOG(INFO) << "Auto-selected device: " << device_name_; |
| 391 } | 373 } |
| 392 } else { | 374 } else { |
| 393 device_name_ = requested_device_name_; | 375 device_name_ = requested_device_name_; |
| 394 playback_handle_ = OpenDevice(device_name_, channels_, latency_micros_); | 376 playback_handle_ = alsa_util::OpenPlaybackDevice(wrapper_, |
| 377 device_name_.c_str(), |
| 378 channels_, sample_rate_, |
| 379 pcm_format_, |
| 380 latency_micros_); |
| 395 } | 381 } |
| 396 | 382 |
| 397 // Finish initializing the stream if the device was opened successfully. | 383 // Finish initializing the stream if the device was opened successfully. |
| 398 if (playback_handle_ == NULL) { | 384 if (playback_handle_ == NULL) { |
| 399 stop_stream_ = true; | 385 stop_stream_ = true; |
| 400 } else { | 386 } else { |
| 401 bytes_per_output_frame_ = should_downmix_ ? 2 * bytes_per_sample_ : | 387 bytes_per_output_frame_ = should_downmix_ ? 2 * bytes_per_sample_ : |
| 402 bytes_per_frame_; | 388 bytes_per_frame_; |
| 403 uint32 output_packet_size = frames_per_packet_ * bytes_per_output_frame_; | 389 uint32 output_packet_size = frames_per_packet_ * bytes_per_output_frame_; |
| 404 buffer_.reset(new media::SeekableBuffer(0, output_packet_size)); | 390 buffer_.reset(new media::SeekableBuffer(0, output_packet_size)); |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 447 | 433 |
| 448 ScheduleNextWrite(false); | 434 ScheduleNextWrite(false); |
| 449 } | 435 } |
| 450 | 436 |
| 451 void AlsaPcmOutputStream::CloseTask() { | 437 void AlsaPcmOutputStream::CloseTask() { |
| 452 // NOTE: Keep this function idempotent to handle errors that might cause | 438 // NOTE: Keep this function idempotent to handle errors that might cause |
| 453 // multiple CloseTasks to be posted. | 439 // multiple CloseTasks to be posted. |
| 454 DCHECK_EQ(message_loop_, MessageLoop::current()); | 440 DCHECK_EQ(message_loop_, MessageLoop::current()); |
| 455 | 441 |
| 456 // Shutdown the audio device. | 442 // Shutdown the audio device. |
| 457 if (playback_handle_ && !CloseDevice(playback_handle_)) { | 443 if (playback_handle_ && |
| 444 alsa_util::CloseDevice(wrapper_, playback_handle_) < 0) { |
| 458 LOG(WARNING) << "Unable to close audio device. Leaking handle."; | 445 LOG(WARNING) << "Unable to close audio device. Leaking handle."; |
| 459 } | 446 } |
| 460 playback_handle_ = NULL; | 447 playback_handle_ = NULL; |
| 461 | 448 |
| 462 // Release the buffer. | 449 // Release the buffer. |
| 463 buffer_.reset(); | 450 buffer_.reset(); |
| 464 | 451 |
| 465 // Signal anything that might already be scheduled to stop. | 452 // Signal anything that might already be scheduled to stop. |
| 466 stop_stream_ = true; | 453 stop_stream_ = true; |
| 467 } | 454 } |
| (...skipping 252 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 720 wrapper_->DeviceNameFreeHint(hints); | 707 wrapper_->DeviceNameFreeHint(hints); |
| 721 hints = NULL; | 708 hints = NULL; |
| 722 } else { | 709 } else { |
| 723 LOG(ERROR) << "Unable to get hints for devices: " | 710 LOG(ERROR) << "Unable to get hints for devices: " |
| 724 << wrapper_->StrError(error); | 711 << wrapper_->StrError(error); |
| 725 } | 712 } |
| 726 | 713 |
| 727 return guessed_device; | 714 return guessed_device; |
| 728 } | 715 } |
| 729 | 716 |
| 730 snd_pcm_t* AlsaPcmOutputStream::OpenDevice(const std::string& device_name, | |
| 731 uint32 channels, | |
| 732 unsigned int latency) { | |
| 733 snd_pcm_t* handle = NULL; | |
| 734 int error = wrapper_->PcmOpen(&handle, device_name.c_str(), | |
| 735 SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK); | |
| 736 if (error < 0) { | |
| 737 LOG(ERROR) << "Cannot open audio device (" << device_name << "): " | |
| 738 << wrapper_->StrError(error); | |
| 739 return NULL; | |
| 740 } | |
| 741 | |
| 742 // Configure the device for software resampling. | |
| 743 if ((error = wrapper_->PcmSetParams(handle, | |
| 744 pcm_format_, | |
| 745 SND_PCM_ACCESS_RW_INTERLEAVED, | |
| 746 channels, | |
| 747 sample_rate_, | |
| 748 1, // soft_resample -- let ALSA resample | |
| 749 latency)) < 0) { | |
| 750 LOG(ERROR) << "Unable to set PCM parameters for (" << device_name | |
| 751 << "): " << wrapper_->StrError(error) | |
| 752 << " -- Format: " << pcm_format_ | |
| 753 << " Channels: " << channels | |
| 754 << " Latency (us): " << latency; | |
| 755 if (!CloseDevice(handle)) { | |
| 756 // TODO(ajwong): Retry on certain errors? | |
| 757 LOG(WARNING) << "Unable to close audio device. Leaking handle."; | |
| 758 } | |
| 759 return NULL; | |
| 760 } | |
| 761 | |
| 762 return handle; | |
| 763 } | |
| 764 | |
| 765 bool AlsaPcmOutputStream::CloseDevice(snd_pcm_t* handle) { | |
| 766 std::string name = wrapper_->PcmName(handle); | |
| 767 int error = wrapper_->PcmClose(handle); | |
| 768 if (error < 0) { | |
| 769 LOG(ERROR) << "Error closing audio device (" << name << "): " | |
| 770 << wrapper_->StrError(error); | |
| 771 return false; | |
| 772 } | |
| 773 | |
| 774 return true; | |
| 775 } | |
| 776 | |
| 777 snd_pcm_sframes_t AlsaPcmOutputStream::GetAvailableFrames() { | 717 snd_pcm_sframes_t AlsaPcmOutputStream::GetAvailableFrames() { |
| 778 DCHECK_EQ(message_loop_, MessageLoop::current()); | 718 DCHECK_EQ(message_loop_, MessageLoop::current()); |
| 779 | 719 |
| 780 if (stop_stream_) { | 720 if (stop_stream_) { |
| 781 return 0; | 721 return 0; |
| 782 } | 722 } |
| 783 | 723 |
| 784 // Find the number of frames queued in the sound device. | 724 // Find the number of frames queued in the sound device. |
| 785 snd_pcm_sframes_t available_frames = | 725 snd_pcm_sframes_t available_frames = |
| 786 wrapper_->PcmAvailUpdate(playback_handle_); | 726 wrapper_->PcmAvailUpdate(playback_handle_); |
| (...skipping 18 matching lines...) Expand all Loading... |
| 805 // 2) If that fails, attempt the "plug:" version of it incase ALSA can | 745 // 2) If that fails, attempt the "plug:" version of it incase ALSA can |
| 806 // remap do some software conversion to make it work. | 746 // remap do some software conversion to make it work. |
| 807 // 3) Fallback to kDefaultDevice. | 747 // 3) Fallback to kDefaultDevice. |
| 808 // 4) If that fails too, try the "plug:" version of kDefaultDevice. | 748 // 4) If that fails too, try the "plug:" version of kDefaultDevice. |
| 809 // 5) Give up. | 749 // 5) Give up. |
| 810 snd_pcm_t* handle = NULL; | 750 snd_pcm_t* handle = NULL; |
| 811 device_name_ = FindDeviceForChannels(channels_); | 751 device_name_ = FindDeviceForChannels(channels_); |
| 812 | 752 |
| 813 // Step 1. | 753 // Step 1. |
| 814 if (!device_name_.empty()) { | 754 if (!device_name_.empty()) { |
| 815 if ((handle = OpenDevice(device_name_, channels_, latency)) != NULL) { | 755 if ((handle = alsa_util::OpenPlaybackDevice(wrapper_, device_name_.c_str(), |
| 756 channels_, sample_rate_, |
| 757 pcm_format_, |
| 758 latency)) != NULL) { |
| 816 return handle; | 759 return handle; |
| 817 } | 760 } |
| 818 | 761 |
| 819 // Step 2. | 762 // Step 2. |
| 820 device_name_ = kPlugPrefix + device_name_; | 763 device_name_ = kPlugPrefix + device_name_; |
| 821 if ((handle = OpenDevice(device_name_, channels_, latency)) != NULL) { | 764 if ((handle = alsa_util::OpenPlaybackDevice(wrapper_, device_name_.c_str(), |
| 765 channels_, sample_rate_, |
| 766 pcm_format_, |
| 767 latency)) != NULL) { |
| 822 return handle; | 768 return handle; |
| 823 } | 769 } |
| 824 } | 770 } |
| 825 | 771 |
| 826 // For the kDefaultDevice device, we can only reliably depend on 2-channel | 772 // For the kDefaultDevice device, we can only reliably depend on 2-channel |
| 827 // output to have the correct ordering according to Lennart. For the channel | 773 // output to have the correct ordering according to Lennart. For the channel |
| 828 // formats that we know how to downmix from (5 channel to 6 channel), setup | 774 // formats that we know how to downmix from (5 channel to 6 channel), setup |
| 829 // downmixing. | 775 // downmixing. |
| 830 // | 776 // |
| 831 // TODO(ajwong): We need a SupportsFolding() function. | 777 // TODO(ajwong): We need a SupportsFolding() function. |
| 832 uint32 default_channels = channels_; | 778 uint32 default_channels = channels_; |
| 833 if (default_channels >= 5 && default_channels <= 6) { | 779 if (default_channels >= 5 && default_channels <= 6) { |
| 834 should_downmix_ = true; | 780 should_downmix_ = true; |
| 835 default_channels = 2; | 781 default_channels = 2; |
| 836 } | 782 } |
| 837 | 783 |
| 838 // Step 3. | 784 // Step 3. |
| 839 device_name_ = kDefaultDevice; | 785 device_name_ = kDefaultDevice; |
| 840 if ((handle = OpenDevice(device_name_, default_channels, latency)) != NULL) { | 786 if ((handle = alsa_util::OpenPlaybackDevice(wrapper_, device_name_.c_str(), |
| 787 default_channels, sample_rate_, |
| 788 pcm_format_, latency)) != NULL) { |
| 841 return handle; | 789 return handle; |
| 842 } | 790 } |
| 843 | 791 |
| 844 // Step 4. | 792 // Step 4. |
| 845 device_name_ = kPlugPrefix + device_name_; | 793 device_name_ = kPlugPrefix + device_name_; |
| 846 if ((handle = OpenDevice(device_name_, default_channels, latency)) != NULL) { | 794 if ((handle = alsa_util::OpenPlaybackDevice(wrapper_, device_name_.c_str(), |
| 795 default_channels, sample_rate_, |
| 796 pcm_format_, latency)) != NULL) { |
| 847 return handle; | 797 return handle; |
| 848 } | 798 } |
| 849 | 799 |
| 850 // Unable to open any device. | 800 // Unable to open any device. |
| 851 device_name_.clear(); | 801 device_name_.clear(); |
| 852 return NULL; | 802 return NULL; |
| 853 } | 803 } |
| 854 | 804 |
| 855 AudioManagerLinux* AlsaPcmOutputStream::manager() { | 805 AudioManagerLinux* AlsaPcmOutputStream::manager() { |
| 856 DCHECK_EQ(MessageLoop::current(), client_thread_loop_); | 806 DCHECK_EQ(MessageLoop::current(), client_thread_loop_); |
| (...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 956 } | 906 } |
| 957 | 907 |
| 958 // Changes the AudioSourceCallback to proxy calls to. Pass in NULL to | 908 // Changes the AudioSourceCallback to proxy calls to. Pass in NULL to |
| 959 // release ownership of the currently registered callback. | 909 // release ownership of the currently registered callback. |
| 960 void AlsaPcmOutputStream::SharedData::set_source_callback( | 910 void AlsaPcmOutputStream::SharedData::set_source_callback( |
| 961 AudioSourceCallback* callback) { | 911 AudioSourceCallback* callback) { |
| 962 DCHECK_EQ(MessageLoop::current(), state_transition_loop_); | 912 DCHECK_EQ(MessageLoop::current(), state_transition_loop_); |
| 963 AutoLock l(lock_); | 913 AutoLock l(lock_); |
| 964 source_callback_ = callback; | 914 source_callback_ = callback; |
| 965 } | 915 } |
| OLD | NEW |