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