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