| 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 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 84 // | 84 // |
| 85 // This function makes a best guess at the specific > 2 channel device name | 85 // This function makes a best guess at the specific > 2 channel device name |
| 86 // based on the number of channels requested. NULL is returned if no device | 86 // based on the number of channels requested. NULL is returned if no device |
| 87 // can be found to match the channel numbers. In this case, using | 87 // can be found to match the channel numbers. In this case, using |
| 88 // kDefaultDevice is probably the best bet. | 88 // kDefaultDevice is probably the best bet. |
| 89 // | 89 // |
| 90 // A five channel source is assumed to be surround50 instead of surround41 | 90 // A five channel source is assumed to be surround50 instead of surround41 |
| 91 // (which is also 5 channels). | 91 // (which is also 5 channels). |
| 92 // | 92 // |
| 93 // TODO(ajwong): The source data should have enough info to tell us if we want | 93 // TODO(ajwong): The source data should have enough info to tell us if we want |
| 94 // surround41 versus surround51, etc., instead of needing us to guess base don | 94 // surround41 versus surround51, etc., instead of needing us to guess based on |
| 95 // channel number. Fix API to pass that data down. | 95 // channel number. Fix API to pass that data down. |
| 96 static const char* GuessSpecificDeviceName(uint32 channels) { | 96 static const char* GuessSpecificDeviceName(uint32 channels) { |
| 97 switch (channels) { | 97 switch (channels) { |
| 98 case 8: | 98 case 8: |
| 99 return "surround71"; | 99 return "surround71"; |
| 100 | 100 |
| 101 case 7: | 101 case 7: |
| 102 return "surround70"; | 102 return "surround70"; |
| 103 | 103 |
| 104 case 6: | 104 case 6: |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 168 alsa_buffer_frames_(0), | 168 alsa_buffer_frames_(0), |
| 169 stop_stream_(false), | 169 stop_stream_(false), |
| 170 wrapper_(wrapper), | 170 wrapper_(wrapper), |
| 171 manager_(manager), | 171 manager_(manager), |
| 172 message_loop_(MessageLoop::current()), | 172 message_loop_(MessageLoop::current()), |
| 173 playback_handle_(NULL), | 173 playback_handle_(NULL), |
| 174 frames_per_packet_(packet_size_ / bytes_per_frame_), | 174 frames_per_packet_(packet_size_ / bytes_per_frame_), |
| 175 ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)), | 175 ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)), |
| 176 state_(kCreated), | 176 state_(kCreated), |
| 177 volume_(1.0f), | 177 volume_(1.0f), |
| 178 source_callback_(NULL) { | 178 source_callback_(NULL), |
| 179 audio_bus_(AudioBus::Create(params)) { |
| 179 DCHECK(manager_->GetMessageLoop()->BelongsToCurrentThread()); | 180 DCHECK(manager_->GetMessageLoop()->BelongsToCurrentThread()); |
| 181 DCHECK_EQ(audio_bus_->frames() * bytes_per_frame_, packet_size_); |
| 180 | 182 |
| 181 // Sanity check input values. | 183 // Sanity check input values. |
| 182 if (params.sample_rate() > kAlsaMaxSampleRate || | 184 if (params.sample_rate() > kAlsaMaxSampleRate || |
| 183 params.sample_rate() <= 0) { | 185 params.sample_rate() <= 0) { |
| 184 LOG(WARNING) << "Unsupported audio frequency."; | 186 LOG(WARNING) << "Unsupported audio frequency."; |
| 185 TransitionTo(kInError); | 187 TransitionTo(kInError); |
| 186 } | 188 } |
| 187 | 189 |
| 188 if (AudioParameters::AUDIO_PCM_LINEAR != params.format() && | 190 if (AudioParameters::AUDIO_PCM_LINEAR != params.format() && |
| 189 AudioParameters::AUDIO_PCM_LOW_LATENCY != params.format()) { | 191 AudioParameters::AUDIO_PCM_LOW_LATENCY != params.format()) { |
| (...skipping 179 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 369 // Before making a request to source for data we need to determine the | 371 // Before making a request to source for data we need to determine the |
| 370 // delay (in bytes) for the requested data to be played. | 372 // delay (in bytes) for the requested data to be played. |
| 371 | 373 |
| 372 uint32 buffer_delay = buffer_->forward_bytes() * bytes_per_frame_ / | 374 uint32 buffer_delay = buffer_->forward_bytes() * bytes_per_frame_ / |
| 373 bytes_per_output_frame_; | 375 bytes_per_output_frame_; |
| 374 | 376 |
| 375 uint32 hardware_delay = GetCurrentDelay() * bytes_per_frame_; | 377 uint32 hardware_delay = GetCurrentDelay() * bytes_per_frame_; |
| 376 | 378 |
| 377 scoped_refptr<media::DataBuffer> packet = | 379 scoped_refptr<media::DataBuffer> packet = |
| 378 new media::DataBuffer(packet_size_); | 380 new media::DataBuffer(packet_size_); |
| 379 int packet_size = RunDataCallback(packet->GetWritableData(), | 381 int frames_filled = RunDataCallback( |
| 380 packet->GetBufferSize(), | 382 audio_bus_.get(), AudioBuffersState(buffer_delay, hardware_delay)); |
| 381 AudioBuffersState(buffer_delay, | 383 size_t packet_size = frames_filled * bytes_per_frame_; |
| 382 hardware_delay)); | 384 DCHECK_LE(packet_size, packet_size_); |
| 383 CHECK_LE(packet_size, packet->GetBufferSize()); | 385 audio_bus_->ToInterleaved( |
| 386 frames_filled, bytes_per_sample_, packet->GetWritableData()); |
| 384 | 387 |
| 385 // Reset the |last_fill_time| to avoid back to back RunDataCallback(). | 388 // Reset the |last_fill_time| to avoid back to back RunDataCallback(). |
| 386 last_fill_time_ = base::Time::Now(); | 389 last_fill_time_ = base::Time::Now(); |
| 387 | 390 |
| 388 // This should not happen, but in case it does, drop any trailing bytes | 391 // TODO(dalecurtis): Channel downmixing, upmixing, should be done in mixer; |
| 389 // that aren't large enough to make a frame. Without this, packet writing | 392 // volume adjust should use SSE optimized vector_fmul() prior to interleave. |
| 390 // may stall because the last few bytes in the packet may never get used by | |
| 391 // WritePacket. | |
| 392 DCHECK_EQ(0u, packet_size % bytes_per_frame_); | |
| 393 packet_size = (packet_size / bytes_per_frame_) * bytes_per_frame_; | |
| 394 | |
| 395 if (should_downmix_) { | 393 if (should_downmix_) { |
| 396 if (media::FoldChannels(packet->GetWritableData(), | 394 if (media::FoldChannels(packet->GetWritableData(), |
| 397 packet_size, | 395 packet_size, |
| 398 channels_, | 396 channels_, |
| 399 bytes_per_sample_, | 397 bytes_per_sample_, |
| 400 volume_)) { | 398 volume_)) { |
| 401 // Adjust packet size for downmix. | 399 // Adjust packet size for downmix. |
| 402 packet_size = packet_size / bytes_per_frame_ * bytes_per_output_frame_; | 400 packet_size = packet_size / bytes_per_frame_ * bytes_per_output_frame_; |
| 403 } else { | 401 } else { |
| 404 LOG(ERROR) << "Folding failed"; | 402 LOG(ERROR) << "Folding failed"; |
| (...skipping 372 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 777 } | 775 } |
| 778 | 776 |
| 779 AlsaPcmOutputStream::InternalState AlsaPcmOutputStream::state() { | 777 AlsaPcmOutputStream::InternalState AlsaPcmOutputStream::state() { |
| 780 return state_; | 778 return state_; |
| 781 } | 779 } |
| 782 | 780 |
| 783 bool AlsaPcmOutputStream::IsOnAudioThread() const { | 781 bool AlsaPcmOutputStream::IsOnAudioThread() const { |
| 784 return message_loop_ && message_loop_ == MessageLoop::current(); | 782 return message_loop_ && message_loop_ == MessageLoop::current(); |
| 785 } | 783 } |
| 786 | 784 |
| 787 uint32 AlsaPcmOutputStream::RunDataCallback(uint8* dest, | 785 int AlsaPcmOutputStream::RunDataCallback(AudioBus* audio_bus, |
| 788 uint32 max_size, | 786 AudioBuffersState buffers_state) { |
| 789 AudioBuffersState buffers_state) { | |
| 790 TRACE_EVENT0("audio", "AlsaPcmOutputStream::RunDataCallback"); | 787 TRACE_EVENT0("audio", "AlsaPcmOutputStream::RunDataCallback"); |
| 791 | 788 |
| 792 if (source_callback_) | 789 if (source_callback_) |
| 793 return source_callback_->OnMoreData(dest, max_size, buffers_state); | 790 return source_callback_->OnMoreData(audio_bus, buffers_state); |
| 794 | 791 |
| 795 return 0; | 792 return 0; |
| 796 } | 793 } |
| 797 | 794 |
| 798 void AlsaPcmOutputStream::RunErrorCallback(int code) { | 795 void AlsaPcmOutputStream::RunErrorCallback(int code) { |
| 799 if (source_callback_) | 796 if (source_callback_) |
| 800 source_callback_->OnError(this, code); | 797 source_callback_->OnError(this, code); |
| 801 } | 798 } |
| 802 | 799 |
| 803 // Changes the AudioSourceCallback to proxy calls to. Pass in NULL to | 800 // Changes the AudioSourceCallback to proxy calls to. Pass in NULL to |
| 804 // release ownership of the currently registered callback. | 801 // release ownership of the currently registered callback. |
| 805 void AlsaPcmOutputStream::set_source_callback(AudioSourceCallback* callback) { | 802 void AlsaPcmOutputStream::set_source_callback(AudioSourceCallback* callback) { |
| 806 DCHECK(IsOnAudioThread()); | 803 DCHECK(IsOnAudioThread()); |
| 807 source_callback_ = callback; | 804 source_callback_ = callback; |
| 808 } | 805 } |
| 809 | 806 |
| 810 } // namespace media | 807 } // namespace media |
| OLD | NEW |