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

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

Issue 9655018: Make AudioParameters a class instead of a struct (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fix tests Created 8 years, 9 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 | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 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 // AlsaPcmOutputStream object is *not* thread-safe and should only be used 7 // AlsaPcmOutputStream object is *not* thread-safe and should only be used
8 // from the audio thread. We DCHECK on this assumption whenever we can. 8 // from the audio thread. We DCHECK on this assumption whenever we can.
9 // 9 //
10 // SEMANTICS OF Close() 10 // SEMANTICS OF Close()
(...skipping 164 matching lines...) Expand 10 before | Expand all | Expand 10 after
175 // Since we expect to only be able to wake up with a resolution of 175 // Since we expect to only be able to wake up with a resolution of
176 // kSleepErrorMilliseconds, double that for our minimum required latency. 176 // kSleepErrorMilliseconds, double that for our minimum required latency.
177 const uint32 AlsaPcmOutputStream::kMinLatencyMicros = 177 const uint32 AlsaPcmOutputStream::kMinLatencyMicros =
178 kSleepErrorMilliseconds * 2 * 1000; 178 kSleepErrorMilliseconds * 2 * 1000;
179 179
180 AlsaPcmOutputStream::AlsaPcmOutputStream(const std::string& device_name, 180 AlsaPcmOutputStream::AlsaPcmOutputStream(const std::string& device_name,
181 const AudioParameters& params, 181 const AudioParameters& params,
182 AlsaWrapper* wrapper, 182 AlsaWrapper* wrapper,
183 AudioManagerLinux* manager) 183 AudioManagerLinux* manager)
184 : requested_device_name_(device_name), 184 : requested_device_name_(device_name),
185 pcm_format_(alsa_util::BitsToFormat(params.bits_per_sample)), 185 pcm_format_(alsa_util::BitsToFormat(params.bits_per_sample())),
186 channels_(params.channels), 186 channels_(params.channels()),
187 sample_rate_(params.sample_rate), 187 samples_per_second_(params.samples_per_second()),
188 bytes_per_sample_(params.bits_per_sample / 8), 188 bytes_per_sample_(params.bits_per_sample() / 8),
189 bytes_per_frame_(channels_ * params.bits_per_sample / 8), 189 bytes_per_frame_(channels_ * params.bits_per_sample() / 8),
190 should_downmix_(false), 190 should_downmix_(false),
191 packet_size_(params.GetPacketSize()), 191 packet_size_(params.GetPacketSize()),
192 micros_per_packet_(FramesToMicros( 192 micros_per_packet_(FramesToMicros(
193 params.samples_per_packet, sample_rate_)), 193 params.samples_per_packet(), samples_per_second_)),
194 latency_micros_(std::max(AlsaPcmOutputStream::kMinLatencyMicros, 194 latency_micros_(std::max(AlsaPcmOutputStream::kMinLatencyMicros,
195 micros_per_packet_ * 2)), 195 micros_per_packet_ * 2)),
196 bytes_per_output_frame_(bytes_per_frame_), 196 bytes_per_output_frame_(bytes_per_frame_),
197 alsa_buffer_frames_(0), 197 alsa_buffer_frames_(0),
198 stop_stream_(false), 198 stop_stream_(false),
199 wrapper_(wrapper), 199 wrapper_(wrapper),
200 manager_(manager), 200 manager_(manager),
201 playback_handle_(NULL), 201 playback_handle_(NULL),
202 frames_per_packet_(packet_size_ / bytes_per_frame_), 202 frames_per_packet_(packet_size_ / bytes_per_frame_),
203 ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)), 203 ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)),
204 state_(kCreated), 204 state_(kCreated),
205 volume_(1.0f), 205 volume_(1.0f),
206 source_callback_(NULL) { 206 source_callback_(NULL) {
207 DCHECK(IsOnAudioThread()); 207 DCHECK(IsOnAudioThread());
208 208
209 // Sanity check input values. 209 // Sanity check input values.
210 if ((params.sample_rate > kAlsaMaxSampleRate) || (params.sample_rate <= 0)) { 210 if (params.samples_per_second() > kAlsaMaxSampleRate ||
211 params.samples_per_second() <= 0) {
211 LOG(WARNING) << "Unsupported audio frequency."; 212 LOG(WARNING) << "Unsupported audio frequency.";
212 TransitionTo(kInError); 213 TransitionTo(kInError);
213 } 214 }
214 215
215 if (AudioParameters::AUDIO_PCM_LINEAR != params.format && 216 if (AudioParameters::AUDIO_PCM_LINEAR != params.format() &&
216 AudioParameters::AUDIO_PCM_LOW_LATENCY != params.format) { 217 AudioParameters::AUDIO_PCM_LOW_LATENCY != params.format()) {
217 LOG(WARNING) << "Unsupported audio format"; 218 LOG(WARNING) << "Unsupported audio format";
218 TransitionTo(kInError); 219 TransitionTo(kInError);
219 } 220 }
220 221
221 if (pcm_format_ == SND_PCM_FORMAT_UNKNOWN) { 222 if (pcm_format_ == SND_PCM_FORMAT_UNKNOWN) {
222 LOG(WARNING) << "Unsupported bits per sample: " << params.bits_per_sample; 223 LOG(WARNING) << "Unsupported bits per sample: " << params.bits_per_sample();
223 TransitionTo(kInError); 224 TransitionTo(kInError);
224 } 225 }
225 } 226 }
226 227
227 AlsaPcmOutputStream::~AlsaPcmOutputStream() { 228 AlsaPcmOutputStream::~AlsaPcmOutputStream() {
228 InternalState current_state = state(); 229 InternalState current_state = state();
229 DCHECK(current_state == kCreated || 230 DCHECK(current_state == kCreated ||
230 current_state == kIsClosed || 231 current_state == kIsClosed ||
231 current_state == kInError); 232 current_state == kInError);
232 DCHECK(!playback_handle_); 233 DCHECK(!playback_handle_);
(...skipping 16 matching lines...) Expand all
249 // transition out from under us. 250 // transition out from under us.
250 TransitionTo(kIsOpened); 251 TransitionTo(kIsOpened);
251 252
252 // Try to open the device. 253 // Try to open the device.
253 if (requested_device_name_ == kAutoSelectDevice) { 254 if (requested_device_name_ == kAutoSelectDevice) {
254 playback_handle_ = AutoSelectDevice(latency_micros_); 255 playback_handle_ = AutoSelectDevice(latency_micros_);
255 if (playback_handle_) 256 if (playback_handle_)
256 DVLOG(1) << "Auto-selected device: " << device_name_; 257 DVLOG(1) << "Auto-selected device: " << device_name_;
257 } else { 258 } else {
258 device_name_ = requested_device_name_; 259 device_name_ = requested_device_name_;
259 playback_handle_ = alsa_util::OpenPlaybackDevice(wrapper_, 260 playback_handle_ = alsa_util::OpenPlaybackDevice(
260 device_name_.c_str(), 261 wrapper_, device_name_.c_str(), channels_, samples_per_second_,
261 channels_, sample_rate_, 262 pcm_format_, latency_micros_);
262 pcm_format_,
263 latency_micros_);
264 } 263 }
265 264
266 // Finish initializing the stream if the device was opened successfully. 265 // Finish initializing the stream if the device was opened successfully.
267 if (playback_handle_ == NULL) { 266 if (playback_handle_ == NULL) {
268 stop_stream_ = true; 267 stop_stream_ = true;
269 TransitionTo(kInError); 268 TransitionTo(kInError);
270 return false; 269 return false;
271 } else { 270 } else {
272 bytes_per_output_frame_ = should_downmix_ ? 2 * bytes_per_sample_ : 271 bytes_per_output_frame_ = should_downmix_ ? 2 * bytes_per_sample_ :
273 bytes_per_frame_; 272 bytes_per_frame_;
(...skipping 284 matching lines...) Expand 10 before | Expand all | Expand 10 after
558 if (stop_stream_) 557 if (stop_stream_)
559 return; 558 return;
560 559
561 uint32 frames_avail_wanted = alsa_buffer_frames_ / 2; 560 uint32 frames_avail_wanted = alsa_buffer_frames_ / 2;
562 uint32 available_frames = GetAvailableFrames(); 561 uint32 available_frames = GetAvailableFrames();
563 uint32 frames_in_buffer = buffer_->forward_bytes() / bytes_per_output_frame_; 562 uint32 frames_in_buffer = buffer_->forward_bytes() / bytes_per_output_frame_;
564 563
565 // Next write is initially scheduled for the moment when half of a packet 564 // Next write is initially scheduled for the moment when half of a packet
566 // has been played out. 565 // has been played out.
567 uint32 next_fill_time_ms = 566 uint32 next_fill_time_ms =
568 FramesToMillis(frames_per_packet_ / 2, sample_rate_); 567 FramesToMillis(frames_per_packet_ / 2, samples_per_second_);
569 568
570 if (frames_in_buffer && (frames_in_buffer <= available_frames)) { 569 if (frames_in_buffer && (frames_in_buffer <= available_frames)) {
571 // There is data in the current buffer, consume them immediately if we have 570 // There is data in the current buffer, consume them immediately if we have
572 // enough space in the soundcard. 571 // enough space in the soundcard.
573 next_fill_time_ms = 0; 572 next_fill_time_ms = 0;
574 } else { 573 } else {
575 // Otherwise schedule the next write for the moment when half of the alsa 574 // Otherwise schedule the next write for the moment when half of the alsa
576 // buffer becomes available. 575 // buffer becomes available.
577 if (available_frames < frames_avail_wanted) { 576 if (available_frames < frames_avail_wanted) {
578 uint32 frames_until_empty_enough = frames_avail_wanted - available_frames; 577 uint32 frames_until_empty_enough = frames_avail_wanted - available_frames;
579 next_fill_time_ms = 578 next_fill_time_ms =
580 FramesToMillis(frames_until_empty_enough, sample_rate_); 579 FramesToMillis(frames_until_empty_enough, samples_per_second_);
581 580
582 // Adjust for time resolution. 581 // Adjust for time resolution.
583 if (next_fill_time_ms > kNoDataSleepMilliseconds) 582 if (next_fill_time_ms > kNoDataSleepMilliseconds)
584 next_fill_time_ms -= kNoDataSleepMilliseconds; 583 next_fill_time_ms -= kNoDataSleepMilliseconds;
585 584
586 // Avoid back-to-back writing. 585 // Avoid back-to-back writing.
587 if (next_fill_time_ms < kMinIntervalBetweenOnMoreDataCallsInMs) 586 if (next_fill_time_ms < kMinIntervalBetweenOnMoreDataCallsInMs)
588 next_fill_time_ms = kMinIntervalBetweenOnMoreDataCallsInMs; 587 next_fill_time_ms = kMinIntervalBetweenOnMoreDataCallsInMs;
589 } else if (available_frames == alsa_buffer_frames_) { 588 } else if (available_frames == alsa_buffer_frames_) {
590 // Buffer is empty, invoke next write immediately. 589 // Buffer is empty, invoke next write immediately.
(...skipping 15 matching lines...) Expand all
606 // base/metrics/histogram.h. 605 // base/metrics/histogram.h.
607 manager_->GetMessageLoop()->PostDelayedTask( 606 manager_->GetMessageLoop()->PostDelayedTask(
608 FROM_HERE, 607 FROM_HERE,
609 base::Bind(&AlsaPcmOutputStream::WriteTask, 608 base::Bind(&AlsaPcmOutputStream::WriteTask,
610 weak_factory_.GetWeakPtr()), 609 weak_factory_.GetWeakPtr()),
611 base::TimeDelta::FromMilliseconds(next_fill_time_ms)); 610 base::TimeDelta::FromMilliseconds(next_fill_time_ms));
612 } 611 }
613 } 612 }
614 } 613 }
615 614
616 uint32 AlsaPcmOutputStream::FramesToMicros(uint32 frames, uint32 sample_rate) { 615 uint32 AlsaPcmOutputStream::FramesToMicros(uint32 frames,
617 return frames * base::Time::kMicrosecondsPerSecond / sample_rate; 616 uint32 samples_per_second) {
617 return frames * base::Time::kMicrosecondsPerSecond / samples_per_second;
618 } 618 }
619 619
620 uint32 AlsaPcmOutputStream::FramesToMillis(uint32 frames, uint32 sample_rate) { 620 uint32 AlsaPcmOutputStream::FramesToMillis(uint32 frames,
621 return frames * base::Time::kMillisecondsPerSecond / sample_rate; 621 uint32 samples_per_second) {
622 return frames * base::Time::kMillisecondsPerSecond / samples_per_second;
622 } 623 }
623 624
624 std::string AlsaPcmOutputStream::FindDeviceForChannels(uint32 channels) { 625 std::string AlsaPcmOutputStream::FindDeviceForChannels(uint32 channels) {
625 // Constants specified by the ALSA API for device hints. 626 // Constants specified by the ALSA API for device hints.
626 static const int kGetAllDevices = -1; 627 static const int kGetAllDevices = -1;
627 static const char kPcmInterfaceName[] = "pcm"; 628 static const char kPcmInterfaceName[] = "pcm";
628 static const char kIoHintName[] = "IOID"; 629 static const char kIoHintName[] = "IOID";
629 static const char kNameHintName[] = "NAME"; 630 static const char kNameHintName[] = "NAME";
630 631
631 const char* wanted_device = GuessSpecificDeviceName(channels); 632 const char* wanted_device = GuessSpecificDeviceName(channels);
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after
726 // remap do some software conversion to make it work. 727 // remap do some software conversion to make it work.
727 // 3) Fallback to kDefaultDevice. 728 // 3) Fallback to kDefaultDevice.
728 // 4) If that fails too, try the "plug:" version of kDefaultDevice. 729 // 4) If that fails too, try the "plug:" version of kDefaultDevice.
729 // 5) Give up. 730 // 5) Give up.
730 snd_pcm_t* handle = NULL; 731 snd_pcm_t* handle = NULL;
731 device_name_ = FindDeviceForChannels(channels_); 732 device_name_ = FindDeviceForChannels(channels_);
732 733
733 // Step 1. 734 // Step 1.
734 if (!device_name_.empty()) { 735 if (!device_name_.empty()) {
735 if ((handle = alsa_util::OpenPlaybackDevice(wrapper_, device_name_.c_str(), 736 if ((handle = alsa_util::OpenPlaybackDevice(wrapper_, device_name_.c_str(),
736 channels_, sample_rate_, 737 channels_, samples_per_second_,
737 pcm_format_, 738 pcm_format_,
738 latency)) != NULL) { 739 latency)) != NULL) {
739 return handle; 740 return handle;
740 } 741 }
741 742
742 // Step 2. 743 // Step 2.
743 device_name_ = kPlugPrefix + device_name_; 744 device_name_ = kPlugPrefix + device_name_;
744 if ((handle = alsa_util::OpenPlaybackDevice(wrapper_, device_name_.c_str(), 745 if ((handle = alsa_util::OpenPlaybackDevice(wrapper_, device_name_.c_str(),
745 channels_, sample_rate_, 746 channels_, samples_per_second_,
746 pcm_format_, 747 pcm_format_,
747 latency)) != NULL) { 748 latency)) != NULL) {
748 return handle; 749 return handle;
749 } 750 }
750 } 751 }
751 752
752 // For the kDefaultDevice device, we can only reliably depend on 2-channel 753 // For the kDefaultDevice device, we can only reliably depend on 2-channel
753 // output to have the correct ordering according to Lennart. For the channel 754 // output to have the correct ordering according to Lennart. For the channel
754 // formats that we know how to downmix from (3 channel to 8 channel), setup 755 // formats that we know how to downmix from (3 channel to 8 channel), setup
755 // downmixing. 756 // downmixing.
756 // 757 //
757 // TODO(ajwong): We need a SupportsFolding() function. 758 // TODO(ajwong): We need a SupportsFolding() function.
758 uint32 default_channels = channels_; 759 uint32 default_channels = channels_;
759 if (default_channels > 2 && default_channels <= 8) { 760 if (default_channels > 2 && default_channels <= 8) {
760 should_downmix_ = true; 761 should_downmix_ = true;
761 default_channels = 2; 762 default_channels = 2;
762 } 763 }
763 764
764 // Step 3. 765 // Step 3.
765 device_name_ = kDefaultDevice; 766 device_name_ = kDefaultDevice;
766 if ((handle = alsa_util::OpenPlaybackDevice(wrapper_, device_name_.c_str(), 767 if ((handle = alsa_util::OpenPlaybackDevice(
767 default_channels, sample_rate_, 768 wrapper_, device_name_.c_str(), default_channels, samples_per_second_,
768 pcm_format_, latency)) != NULL) { 769 pcm_format_, latency)) != NULL) {
769 return handle; 770 return handle;
770 } 771 }
771 772
772 // Step 4. 773 // Step 4.
773 device_name_ = kPlugPrefix + device_name_; 774 device_name_ = kPlugPrefix + device_name_;
774 if ((handle = alsa_util::OpenPlaybackDevice(wrapper_, device_name_.c_str(), 775 if ((handle = alsa_util::OpenPlaybackDevice(
775 default_channels, sample_rate_, 776 wrapper_, device_name_.c_str(), default_channels, samples_per_second_,
776 pcm_format_, latency)) != NULL) { 777 pcm_format_, latency)) != NULL) {
777 return handle; 778 return handle;
778 } 779 }
779 780
780 // Unable to open any device. 781 // Unable to open any device.
781 device_name_.clear(); 782 device_name_.clear();
782 return NULL; 783 return NULL;
783 } 784 }
784 785
785 bool AlsaPcmOutputStream::CanTransitionTo(InternalState to) { 786 bool AlsaPcmOutputStream::CanTransitionTo(InternalState to) {
786 switch (state_) { 787 switch (state_) {
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after
845 if (source_callback_) 846 if (source_callback_)
846 source_callback_->OnError(this, code); 847 source_callback_->OnError(this, code);
847 } 848 }
848 849
849 // Changes the AudioSourceCallback to proxy calls to. Pass in NULL to 850 // Changes the AudioSourceCallback to proxy calls to. Pass in NULL to
850 // release ownership of the currently registered callback. 851 // release ownership of the currently registered callback.
851 void AlsaPcmOutputStream::set_source_callback(AudioSourceCallback* callback) { 852 void AlsaPcmOutputStream::set_source_callback(AudioSourceCallback* callback) {
852 DCHECK(IsOnAudioThread()); 853 DCHECK(IsOnAudioThread());
853 source_callback_ = callback; 854 source_callback_ = callback;
854 } 855 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698