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 164 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
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 sample_rate_(params.sample_rate()), |
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.GetBytesPerBuffer()), |
192 micros_per_packet_(FramesToMicros( | 192 micros_per_packet_(FramesToMicros( |
193 params.samples_per_packet, sample_rate_)), | 193 params.frames_per_buffer(), sample_rate_)), |
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.sample_rate() > kAlsaMaxSampleRate || |
| 211 params.sample_rate() <= 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 Loading... |
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_, sample_rate_, |
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 331 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
605 // base/metrics/histogram.h. | 604 // base/metrics/histogram.h. |
606 manager_->GetMessageLoop()->PostDelayedTask( | 605 manager_->GetMessageLoop()->PostDelayedTask( |
607 FROM_HERE, | 606 FROM_HERE, |
608 base::Bind(&AlsaPcmOutputStream::WriteTask, | 607 base::Bind(&AlsaPcmOutputStream::WriteTask, |
609 weak_factory_.GetWeakPtr()), | 608 weak_factory_.GetWeakPtr()), |
610 base::TimeDelta::FromMilliseconds(next_fill_time_ms)); | 609 base::TimeDelta::FromMilliseconds(next_fill_time_ms)); |
611 } | 610 } |
612 } | 611 } |
613 } | 612 } |
614 | 613 |
615 uint32 AlsaPcmOutputStream::FramesToMicros(uint32 frames, uint32 sample_rate) { | 614 uint32 AlsaPcmOutputStream::FramesToMicros(uint32 frames, |
| 615 uint32 sample_rate) { |
616 return frames * base::Time::kMicrosecondsPerSecond / sample_rate; | 616 return frames * base::Time::kMicrosecondsPerSecond / sample_rate; |
617 } | 617 } |
618 | 618 |
619 uint32 AlsaPcmOutputStream::FramesToMillis(uint32 frames, uint32 sample_rate) { | 619 uint32 AlsaPcmOutputStream::FramesToMillis(uint32 frames, |
| 620 uint32 sample_rate) { |
620 return frames * base::Time::kMillisecondsPerSecond / sample_rate; | 621 return frames * base::Time::kMillisecondsPerSecond / sample_rate; |
621 } | 622 } |
622 | 623 |
623 std::string AlsaPcmOutputStream::FindDeviceForChannels(uint32 channels) { | 624 std::string AlsaPcmOutputStream::FindDeviceForChannels(uint32 channels) { |
624 // Constants specified by the ALSA API for device hints. | 625 // Constants specified by the ALSA API for device hints. |
625 static const int kGetAllDevices = -1; | 626 static const int kGetAllDevices = -1; |
626 static const char kPcmInterfaceName[] = "pcm"; | 627 static const char kPcmInterfaceName[] = "pcm"; |
627 static const char kIoHintName[] = "IOID"; | 628 static const char kIoHintName[] = "IOID"; |
628 static const char kNameHintName[] = "NAME"; | 629 static const char kNameHintName[] = "NAME"; |
629 | 630 |
(...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
755 // | 756 // |
756 // TODO(ajwong): We need a SupportsFolding() function. | 757 // TODO(ajwong): We need a SupportsFolding() function. |
757 uint32 default_channels = channels_; | 758 uint32 default_channels = channels_; |
758 if (default_channels > 2 && default_channels <= 8) { | 759 if (default_channels > 2 && default_channels <= 8) { |
759 should_downmix_ = true; | 760 should_downmix_ = true; |
760 default_channels = 2; | 761 default_channels = 2; |
761 } | 762 } |
762 | 763 |
763 // Step 3. | 764 // Step 3. |
764 device_name_ = kDefaultDevice; | 765 device_name_ = kDefaultDevice; |
765 if ((handle = alsa_util::OpenPlaybackDevice(wrapper_, device_name_.c_str(), | 766 if ((handle = alsa_util::OpenPlaybackDevice( |
766 default_channels, sample_rate_, | 767 wrapper_, device_name_.c_str(), default_channels, sample_rate_, |
767 pcm_format_, latency)) != NULL) { | 768 pcm_format_, latency)) != NULL) { |
768 return handle; | 769 return handle; |
769 } | 770 } |
770 | 771 |
771 // Step 4. | 772 // Step 4. |
772 device_name_ = kPlugPrefix + device_name_; | 773 device_name_ = kPlugPrefix + device_name_; |
773 if ((handle = alsa_util::OpenPlaybackDevice(wrapper_, device_name_.c_str(), | 774 if ((handle = alsa_util::OpenPlaybackDevice( |
774 default_channels, sample_rate_, | 775 wrapper_, device_name_.c_str(), default_channels, sample_rate_, |
775 pcm_format_, latency)) != NULL) { | 776 pcm_format_, latency)) != NULL) { |
776 return handle; | 777 return handle; |
777 } | 778 } |
778 | 779 |
779 // Unable to open any device. | 780 // Unable to open any device. |
780 device_name_.clear(); | 781 device_name_.clear(); |
781 return NULL; | 782 return NULL; |
782 } | 783 } |
783 | 784 |
784 bool AlsaPcmOutputStream::CanTransitionTo(InternalState to) { | 785 bool AlsaPcmOutputStream::CanTransitionTo(InternalState to) { |
785 switch (state_) { | 786 switch (state_) { |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
844 if (source_callback_) | 845 if (source_callback_) |
845 source_callback_->OnError(this, code); | 846 source_callback_->OnError(this, code); |
846 } | 847 } |
847 | 848 |
848 // Changes the AudioSourceCallback to proxy calls to. Pass in NULL to | 849 // Changes the AudioSourceCallback to proxy calls to. Pass in NULL to |
849 // release ownership of the currently registered callback. | 850 // release ownership of the currently registered callback. |
850 void AlsaPcmOutputStream::set_source_callback(AudioSourceCallback* callback) { | 851 void AlsaPcmOutputStream::set_source_callback(AudioSourceCallback* callback) { |
851 DCHECK(IsOnAudioThread()); | 852 DCHECK(IsOnAudioThread()); |
852 source_callback_ = callback; | 853 source_callback_ = callback; |
853 } | 854 } |
OLD | NEW |