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 |