| 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 |