OLD | NEW |
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 133 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
144 // Since we expect to only be able to wake up with a resolution of | 144 // Since we expect to only be able to wake up with a resolution of |
145 // kSleepErrorMilliseconds, double that for our minimum required latency. | 145 // kSleepErrorMilliseconds, double that for our minimum required latency. |
146 const uint32 AlsaPcmOutputStream::kMinLatencyMicros = | 146 const uint32 AlsaPcmOutputStream::kMinLatencyMicros = |
147 kSleepErrorMilliseconds * 2 * 1000; | 147 kSleepErrorMilliseconds * 2 * 1000; |
148 | 148 |
149 AlsaPcmOutputStream::AlsaPcmOutputStream(const std::string& device_name, | 149 AlsaPcmOutputStream::AlsaPcmOutputStream(const std::string& device_name, |
150 const AudioParameters& params, | 150 const AudioParameters& params, |
151 AlsaWrapper* wrapper, | 151 AlsaWrapper* wrapper, |
152 AudioManagerLinux* manager) | 152 AudioManagerLinux* manager) |
153 : requested_device_name_(device_name), | 153 : requested_device_name_(device_name), |
154 pcm_format_(alsa_util::BitsToFormat(params.bits_per_sample)), | 154 pcm_format_(alsa_util::BitsToFormat(params.bits_per_sample())), |
155 channels_(params.channels), | 155 channels_(params.channels()), |
156 sample_rate_(params.sample_rate), | 156 sample_rate_(params.sample_rate()), |
157 bytes_per_sample_(params.bits_per_sample / 8), | 157 bytes_per_sample_(params.bits_per_sample() / 8), |
158 bytes_per_frame_(channels_ * params.bits_per_sample / 8), | 158 bytes_per_frame_(channels_ * params.bits_per_sample() / 8), |
159 should_downmix_(false), | 159 should_downmix_(false), |
160 packet_size_(params.GetPacketSize()), | 160 packet_size_(params.GetBytesPerBuffer()), |
161 micros_per_packet_(FramesToMicros( | 161 micros_per_packet_(FramesToMicros( |
162 params.samples_per_packet, sample_rate_)), | 162 params.frames_per_buffer(), sample_rate_)), |
163 latency_micros_(std::max(AlsaPcmOutputStream::kMinLatencyMicros, | 163 latency_micros_(std::max(AlsaPcmOutputStream::kMinLatencyMicros, |
164 micros_per_packet_ * 2)), | 164 micros_per_packet_ * 2)), |
165 bytes_per_output_frame_(bytes_per_frame_), | 165 bytes_per_output_frame_(bytes_per_frame_), |
166 alsa_buffer_frames_(0), | 166 alsa_buffer_frames_(0), |
167 stop_stream_(false), | 167 stop_stream_(false), |
168 wrapper_(wrapper), | 168 wrapper_(wrapper), |
169 manager_(manager), | 169 manager_(manager), |
170 playback_handle_(NULL), | 170 playback_handle_(NULL), |
171 frames_per_packet_(packet_size_ / bytes_per_frame_), | 171 frames_per_packet_(packet_size_ / bytes_per_frame_), |
172 ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)), | 172 ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)), |
173 state_(kCreated), | 173 state_(kCreated), |
174 volume_(1.0f), | 174 volume_(1.0f), |
175 source_callback_(NULL) { | 175 source_callback_(NULL) { |
176 DCHECK(IsOnAudioThread()); | 176 DCHECK(IsOnAudioThread()); |
177 | 177 |
178 // Sanity check input values. | 178 // Sanity check input values. |
179 if ((params.sample_rate > kAlsaMaxSampleRate) || (params.sample_rate <= 0)) { | 179 if (params.sample_rate() > kAlsaMaxSampleRate || |
| 180 params.sample_rate() <= 0) { |
180 LOG(WARNING) << "Unsupported audio frequency."; | 181 LOG(WARNING) << "Unsupported audio frequency."; |
181 TransitionTo(kInError); | 182 TransitionTo(kInError); |
182 } | 183 } |
183 | 184 |
184 if (AudioParameters::AUDIO_PCM_LINEAR != params.format && | 185 if (AudioParameters::AUDIO_PCM_LINEAR != params.format() && |
185 AudioParameters::AUDIO_PCM_LOW_LATENCY != params.format) { | 186 AudioParameters::AUDIO_PCM_LOW_LATENCY != params.format()) { |
186 LOG(WARNING) << "Unsupported audio format"; | 187 LOG(WARNING) << "Unsupported audio format"; |
187 TransitionTo(kInError); | 188 TransitionTo(kInError); |
188 } | 189 } |
189 | 190 |
190 if (pcm_format_ == SND_PCM_FORMAT_UNKNOWN) { | 191 if (pcm_format_ == SND_PCM_FORMAT_UNKNOWN) { |
191 LOG(WARNING) << "Unsupported bits per sample: " << params.bits_per_sample; | 192 LOG(WARNING) << "Unsupported bits per sample: " << params.bits_per_sample(); |
192 TransitionTo(kInError); | 193 TransitionTo(kInError); |
193 } | 194 } |
194 } | 195 } |
195 | 196 |
196 AlsaPcmOutputStream::~AlsaPcmOutputStream() { | 197 AlsaPcmOutputStream::~AlsaPcmOutputStream() { |
197 InternalState current_state = state(); | 198 InternalState current_state = state(); |
198 DCHECK(current_state == kCreated || | 199 DCHECK(current_state == kCreated || |
199 current_state == kIsClosed || | 200 current_state == kIsClosed || |
200 current_state == kInError); | 201 current_state == kInError); |
201 DCHECK(!playback_handle_); | 202 DCHECK(!playback_handle_); |
(...skipping 16 matching lines...) Expand all Loading... |
218 // transition out from under us. | 219 // transition out from under us. |
219 TransitionTo(kIsOpened); | 220 TransitionTo(kIsOpened); |
220 | 221 |
221 // Try to open the device. | 222 // Try to open the device. |
222 if (requested_device_name_ == kAutoSelectDevice) { | 223 if (requested_device_name_ == kAutoSelectDevice) { |
223 playback_handle_ = AutoSelectDevice(latency_micros_); | 224 playback_handle_ = AutoSelectDevice(latency_micros_); |
224 if (playback_handle_) | 225 if (playback_handle_) |
225 DVLOG(1) << "Auto-selected device: " << device_name_; | 226 DVLOG(1) << "Auto-selected device: " << device_name_; |
226 } else { | 227 } else { |
227 device_name_ = requested_device_name_; | 228 device_name_ = requested_device_name_; |
228 playback_handle_ = alsa_util::OpenPlaybackDevice(wrapper_, | 229 playback_handle_ = alsa_util::OpenPlaybackDevice( |
229 device_name_.c_str(), | 230 wrapper_, device_name_.c_str(), channels_, sample_rate_, |
230 channels_, sample_rate_, | 231 pcm_format_, latency_micros_); |
231 pcm_format_, | |
232 latency_micros_); | |
233 } | 232 } |
234 | 233 |
235 // Finish initializing the stream if the device was opened successfully. | 234 // Finish initializing the stream if the device was opened successfully. |
236 if (playback_handle_ == NULL) { | 235 if (playback_handle_ == NULL) { |
237 stop_stream_ = true; | 236 stop_stream_ = true; |
238 TransitionTo(kInError); | 237 TransitionTo(kInError); |
239 return false; | 238 return false; |
240 } else { | 239 } else { |
241 bytes_per_output_frame_ = should_downmix_ ? 2 * bytes_per_sample_ : | 240 bytes_per_output_frame_ = should_downmix_ ? 2 * bytes_per_sample_ : |
242 bytes_per_frame_; | 241 bytes_per_frame_; |
(...skipping 307 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
550 // base/metrics/histogram.h. | 549 // base/metrics/histogram.h. |
551 manager_->GetMessageLoop()->PostDelayedTask( | 550 manager_->GetMessageLoop()->PostDelayedTask( |
552 FROM_HERE, | 551 FROM_HERE, |
553 base::Bind(&AlsaPcmOutputStream::WriteTask, | 552 base::Bind(&AlsaPcmOutputStream::WriteTask, |
554 weak_factory_.GetWeakPtr()), | 553 weak_factory_.GetWeakPtr()), |
555 base::TimeDelta::FromMilliseconds(next_fill_time_ms)); | 554 base::TimeDelta::FromMilliseconds(next_fill_time_ms)); |
556 } | 555 } |
557 } | 556 } |
558 } | 557 } |
559 | 558 |
560 uint32 AlsaPcmOutputStream::FramesToMicros(uint32 frames, uint32 sample_rate) { | 559 uint32 AlsaPcmOutputStream::FramesToMicros(uint32 frames, |
| 560 uint32 sample_rate) { |
561 return frames * base::Time::kMicrosecondsPerSecond / sample_rate; | 561 return frames * base::Time::kMicrosecondsPerSecond / sample_rate; |
562 } | 562 } |
563 | 563 |
564 uint32 AlsaPcmOutputStream::FramesToMillis(uint32 frames, uint32 sample_rate) { | 564 uint32 AlsaPcmOutputStream::FramesToMillis(uint32 frames, |
| 565 uint32 sample_rate) { |
565 return frames * base::Time::kMillisecondsPerSecond / sample_rate; | 566 return frames * base::Time::kMillisecondsPerSecond / sample_rate; |
566 } | 567 } |
567 | 568 |
568 std::string AlsaPcmOutputStream::FindDeviceForChannels(uint32 channels) { | 569 std::string AlsaPcmOutputStream::FindDeviceForChannels(uint32 channels) { |
569 // Constants specified by the ALSA API for device hints. | 570 // Constants specified by the ALSA API for device hints. |
570 static const int kGetAllDevices = -1; | 571 static const int kGetAllDevices = -1; |
571 static const char kPcmInterfaceName[] = "pcm"; | 572 static const char kPcmInterfaceName[] = "pcm"; |
572 static const char kIoHintName[] = "IOID"; | 573 static const char kIoHintName[] = "IOID"; |
573 static const char kNameHintName[] = "NAME"; | 574 static const char kNameHintName[] = "NAME"; |
574 | 575 |
(...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
700 // | 701 // |
701 // TODO(ajwong): We need a SupportsFolding() function. | 702 // TODO(ajwong): We need a SupportsFolding() function. |
702 uint32 default_channels = channels_; | 703 uint32 default_channels = channels_; |
703 if (default_channels > 2 && default_channels <= 8) { | 704 if (default_channels > 2 && default_channels <= 8) { |
704 should_downmix_ = true; | 705 should_downmix_ = true; |
705 default_channels = 2; | 706 default_channels = 2; |
706 } | 707 } |
707 | 708 |
708 // Step 3. | 709 // Step 3. |
709 device_name_ = kDefaultDevice; | 710 device_name_ = kDefaultDevice; |
710 if ((handle = alsa_util::OpenPlaybackDevice(wrapper_, device_name_.c_str(), | 711 if ((handle = alsa_util::OpenPlaybackDevice( |
711 default_channels, sample_rate_, | 712 wrapper_, device_name_.c_str(), default_channels, sample_rate_, |
712 pcm_format_, latency)) != NULL) { | 713 pcm_format_, latency)) != NULL) { |
713 return handle; | 714 return handle; |
714 } | 715 } |
715 | 716 |
716 // Step 4. | 717 // Step 4. |
717 device_name_ = kPlugPrefix + device_name_; | 718 device_name_ = kPlugPrefix + device_name_; |
718 if ((handle = alsa_util::OpenPlaybackDevice(wrapper_, device_name_.c_str(), | 719 if ((handle = alsa_util::OpenPlaybackDevice( |
719 default_channels, sample_rate_, | 720 wrapper_, device_name_.c_str(), default_channels, sample_rate_, |
720 pcm_format_, latency)) != NULL) { | 721 pcm_format_, latency)) != NULL) { |
721 return handle; | 722 return handle; |
722 } | 723 } |
723 | 724 |
724 // Unable to open any device. | 725 // Unable to open any device. |
725 device_name_.clear(); | 726 device_name_.clear(); |
726 return NULL; | 727 return NULL; |
727 } | 728 } |
728 | 729 |
729 bool AlsaPcmOutputStream::CanTransitionTo(InternalState to) { | 730 bool AlsaPcmOutputStream::CanTransitionTo(InternalState to) { |
730 switch (state_) { | 731 switch (state_) { |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
789 if (source_callback_) | 790 if (source_callback_) |
790 source_callback_->OnError(this, code); | 791 source_callback_->OnError(this, code); |
791 } | 792 } |
792 | 793 |
793 // Changes the AudioSourceCallback to proxy calls to. Pass in NULL to | 794 // Changes the AudioSourceCallback to proxy calls to. Pass in NULL to |
794 // release ownership of the currently registered callback. | 795 // release ownership of the currently registered callback. |
795 void AlsaPcmOutputStream::set_source_callback(AudioSourceCallback* callback) { | 796 void AlsaPcmOutputStream::set_source_callback(AudioSourceCallback* callback) { |
796 DCHECK(IsOnAudioThread()); | 797 DCHECK(IsOnAudioThread()); |
797 source_callback_ = callback; | 798 source_callback_ = callback; |
798 } | 799 } |
OLD | NEW |