Chromium Code Reviews| 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 #include "media/audio/pulse/pulse_input.h" | 5 #include "media/audio/pulse/pulse_input.h" |
| 6 | 6 |
| 7 #include <pulse/pulseaudio.h> | 7 #include <pulse/pulseaudio.h> |
| 8 | 8 |
| 9 #include "base/logging.h" | 9 #include "base/logging.h" |
| 10 #include "media/audio/pulse/audio_manager_pulse.h" | 10 #include "media/audio/pulse/audio_manager_pulse.h" |
| 11 #include "media/audio/pulse/pulse_util.h" | 11 #include "media/audio/pulse/pulse_util.h" |
| 12 #include "media/base/seekable_buffer.h" | 12 #include "media/base/audio_block_fifo.h" |
| 13 | 13 |
| 14 namespace media { | 14 namespace media { |
| 15 | 15 |
| 16 using pulse::AutoPulseLock; | 16 using pulse::AutoPulseLock; |
| 17 using pulse::WaitForOperationCompletion; | 17 using pulse::WaitForOperationCompletion; |
| 18 | 18 |
| 19 // Number of blocks of buffers used in the |fifo_|. | |
| 20 const int kNumberOfBlocksBufferInFifo = 2; | |
| 21 | |
| 19 PulseAudioInputStream::PulseAudioInputStream(AudioManagerPulse* audio_manager, | 22 PulseAudioInputStream::PulseAudioInputStream(AudioManagerPulse* audio_manager, |
| 20 const std::string& device_name, | 23 const std::string& device_name, |
| 21 const AudioParameters& params, | 24 const AudioParameters& params, |
| 22 pa_threaded_mainloop* mainloop, | 25 pa_threaded_mainloop* mainloop, |
| 23 pa_context* context) | 26 pa_context* context) |
| 24 : audio_manager_(audio_manager), | 27 : audio_manager_(audio_manager), |
| 25 callback_(NULL), | 28 callback_(NULL), |
| 26 device_name_(device_name), | 29 device_name_(device_name), |
| 27 params_(params), | 30 params_(params), |
| 28 channels_(0), | 31 channels_(0), |
| 29 volume_(0.0), | 32 volume_(0.0), |
| 30 stream_started_(false), | 33 stream_started_(false), |
| 31 pa_mainloop_(mainloop), | 34 pa_mainloop_(mainloop), |
| 32 pa_context_(context), | 35 pa_context_(context), |
| 33 handle_(NULL), | 36 handle_(NULL), |
| 34 context_state_changed_(false) { | 37 context_state_changed_(false) { |
| 35 DCHECK(mainloop); | 38 DCHECK(mainloop); |
| 36 DCHECK(context); | 39 DCHECK(context); |
| 37 CHECK(params_.IsValid()); | 40 CHECK(params_.IsValid()); |
| 38 audio_bus_ = AudioBus::Create(params_); | |
| 39 } | 41 } |
| 40 | 42 |
| 41 PulseAudioInputStream::~PulseAudioInputStream() { | 43 PulseAudioInputStream::~PulseAudioInputStream() { |
| 42 // All internal structures should already have been freed in Close(), | 44 // All internal structures should already have been freed in Close(), |
| 43 // which calls AudioManagerPulse::Release which deletes this object. | 45 // which calls AudioManagerPulse::Release which deletes this object. |
| 44 DCHECK(!handle_); | 46 DCHECK(!handle_); |
| 45 } | 47 } |
| 46 | 48 |
| 47 bool PulseAudioInputStream::Open() { | 49 bool PulseAudioInputStream::Open() { |
| 48 DCHECK(thread_checker_.CalledOnValidThread()); | 50 DCHECK(thread_checker_.CalledOnValidThread()); |
| 49 AutoPulseLock auto_lock(pa_mainloop_); | 51 AutoPulseLock auto_lock(pa_mainloop_); |
| 50 if (!pulse::CreateInputStream(pa_mainloop_, pa_context_, &handle_, params_, | 52 if (!pulse::CreateInputStream(pa_mainloop_, pa_context_, &handle_, params_, |
| 51 device_name_, &StreamNotifyCallback, this)) { | 53 device_name_, &StreamNotifyCallback, this)) { |
| 52 return false; | 54 return false; |
| 53 } | 55 } |
| 54 | 56 |
| 55 DCHECK(handle_); | 57 DCHECK(handle_); |
| 56 | 58 |
| 57 buffer_.reset(new media::SeekableBuffer(0, 2 * params_.GetBytesPerBuffer())); | 59 fifo_.reset(new AudioBlockFifo(params_.channels(), |
|
DaleCurtis
2014/07/18 18:21:54
Avoid dynamic allocation during construction?
no longer working on chromium
2014/07/21 15:13:30
Done.
| |
| 58 audio_data_buffer_.reset(new uint8[params_.GetBytesPerBuffer()]); | 60 params_.frames_per_buffer(), |
| 61 kNumberOfBlocksBufferInFifo)); | |
| 59 return true; | 62 return true; |
| 60 } | 63 } |
| 61 | 64 |
| 62 void PulseAudioInputStream::Start(AudioInputCallback* callback) { | 65 void PulseAudioInputStream::Start(AudioInputCallback* callback) { |
| 63 DCHECK(thread_checker_.CalledOnValidThread()); | 66 DCHECK(thread_checker_.CalledOnValidThread()); |
| 64 DCHECK(callback); | 67 DCHECK(callback); |
| 65 DCHECK(handle_); | 68 DCHECK(handle_); |
| 66 | 69 |
| 67 // AGC needs to be started out of the lock. | 70 // AGC needs to be started out of the lock. |
| 68 StartAgc(); | 71 StartAgc(); |
| 69 | 72 |
| 70 AutoPulseLock auto_lock(pa_mainloop_); | 73 AutoPulseLock auto_lock(pa_mainloop_); |
| 71 | 74 |
| 72 if (stream_started_) | 75 if (stream_started_) |
| 73 return; | 76 return; |
| 74 | 77 |
| 75 // Clean up the old buffer. | 78 // Clean up the old buffer. |
| 76 pa_stream_drop(handle_); | 79 pa_stream_drop(handle_); |
| 77 buffer_->Clear(); | 80 fifo_->Clear(); |
| 78 | 81 |
| 79 // Start the streaming. | 82 // Start the streaming. |
| 80 callback_ = callback; | 83 callback_ = callback; |
| 81 pa_stream_set_read_callback(handle_, &ReadCallback, this); | 84 pa_stream_set_read_callback(handle_, &ReadCallback, this); |
| 82 pa_stream_readable_size(handle_); | 85 pa_stream_readable_size(handle_); |
| 83 stream_started_ = true; | 86 stream_started_ = true; |
| 84 | 87 |
| 85 pa_operation* operation = pa_stream_cork(handle_, 0, NULL, NULL); | 88 pa_operation* operation = pa_stream_cork(handle_, 0, NULL, NULL); |
| 86 WaitForOperationCompletion(pa_mainloop_, operation); | 89 WaitForOperationCompletion(pa_mainloop_, operation); |
| 87 } | 90 } |
| (...skipping 170 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 258 GetAgcVolume(&normalized_volume); | 261 GetAgcVolume(&normalized_volume); |
| 259 normalized_volume = volume_ / GetMaxVolume(); | 262 normalized_volume = volume_ / GetMaxVolume(); |
| 260 | 263 |
| 261 do { | 264 do { |
| 262 size_t length = 0; | 265 size_t length = 0; |
| 263 const void* data = NULL; | 266 const void* data = NULL; |
| 264 pa_stream_peek(handle_, &data, &length); | 267 pa_stream_peek(handle_, &data, &length); |
| 265 if (!data || length == 0) | 268 if (!data || length == 0) |
| 266 break; | 269 break; |
| 267 | 270 |
| 268 buffer_->Append(reinterpret_cast<const uint8*>(data), length); | 271 const int number_of_frames = length / params_.GetBytesPerFrame(); |
| 272 fifo_->Push(data, number_of_frames, params_.bits_per_sample() / 8); | |
| 269 | 273 |
| 270 // Checks if we still have data. | 274 // Checks if we still have data. |
| 271 pa_stream_drop(handle_); | 275 pa_stream_drop(handle_); |
| 272 } while (pa_stream_readable_size(handle_) > 0); | 276 } while (pa_stream_readable_size(handle_) > 0); |
| 273 | 277 |
| 274 int packet_size = params_.GetBytesPerBuffer(); | 278 while (fifo_->available_blocks()) { |
| 275 while (buffer_->forward_bytes() >= packet_size) { | 279 const AudioBus* audio_bus = fifo_->Consume(); |
| 276 buffer_->Read(audio_data_buffer_.get(), packet_size); | 280 |
| 277 audio_bus_->FromInterleaved(audio_data_buffer_.get(), | 281 // Compensate the audio delay caused by the FIFO. |
| 278 audio_bus_->frames(), | 282 hardware_delay += fifo_->available_frames() * params_.GetBytesPerFrame(); |
| 279 params_.bits_per_sample() / 8); | |
| 280 callback_->OnData( | 283 callback_->OnData( |
| 281 this, audio_bus_.get(), hardware_delay, normalized_volume); | 284 this, audio_bus, hardware_delay, normalized_volume); |
| 282 | |
| 283 if (buffer_->forward_bytes() < packet_size) | |
| 284 break; | |
| 285 | 285 |
| 286 // TODO(xians): Remove once PPAPI is using circular buffers. | 286 // TODO(xians): Remove once PPAPI is using circular buffers. |
| 287 DVLOG(1) << "OnData is being called consecutively, sleep 5ms to " | 287 DVLOG(1) << "OnData is being called consecutively, sleep 5ms to " |
| 288 << "wait until render consumes the data"; | 288 << "wait until render consumes the data"; |
| 289 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(5)); | 289 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(5)); |
| 290 } | 290 } |
| 291 | 291 |
| 292 pa_threaded_mainloop_signal(pa_mainloop_, 0); | 292 pa_threaded_mainloop_signal(pa_mainloop_, 0); |
| 293 } | 293 } |
| 294 | 294 |
| 295 } // namespace media | 295 } // namespace media |
| OLD | NEW |