Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(159)

Side by Side Diff: media/audio/linux/alsa_output.cc

Issue 3299005: Implement audio recording for Linux via ALSA. (Closed)
Patch Set: . Created 10 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
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
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
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
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
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
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 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698