1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "media/audio/pulse/pulse_unified.h"
7 #include "base/message_loop/message_loop.h"
8 #include "base/time/time.h"
9 #include "media/audio/audio_manager_base.h"
10 #include "media/audio/audio_parameters.h"
11 #include "media/audio/pulse/pulse_util.h"
12 #include "media/base/seekable_buffer.h"
16 using pulse::AutoPulseLock
;
17 using pulse::WaitForOperationCompletion
;
19 static const int kFifoSizeInPackets
= 10;
21 // static, pa_stream_notify_cb
22 void PulseAudioUnifiedStream::StreamNotifyCallback(pa_stream
* s
,
24 PulseAudioUnifiedStream
* stream
=
25 static_cast<PulseAudioUnifiedStream
*>(user_data
);
27 // Forward unexpected failures to the AudioSourceCallback if available. All
28 // these variables are only modified under pa_threaded_mainloop_lock() so this
29 // should be thread safe.
30 if (s
&& stream
->source_callback_
&&
31 pa_stream_get_state(s
) == PA_STREAM_FAILED
) {
32 stream
->source_callback_
->OnError(stream
);
35 pa_threaded_mainloop_signal(stream
->pa_mainloop_
, 0);
38 // static, used by pa_stream_set_read_callback.
39 void PulseAudioUnifiedStream::ReadCallback(pa_stream
* handle
, size_t length
,
41 static_cast<PulseAudioUnifiedStream
*>(user_data
)->ReadData();
44 PulseAudioUnifiedStream::PulseAudioUnifiedStream(
45 const AudioParameters
& params
,
46 const std::string
& input_device_id
,
47 AudioManagerBase
* manager
)
49 input_device_id_(input_device_id
),
56 source_callback_(NULL
) {
57 DCHECK(manager_
->GetMessageLoop()->BelongsToCurrentThread());
58 CHECK(params_
.IsValid());
59 input_bus_
= AudioBus::Create(params_
);
60 output_bus_
= AudioBus::Create(params_
);
63 PulseAudioUnifiedStream::~PulseAudioUnifiedStream() {
64 // All internal structures should already have been freed in Close(), which
65 // calls AudioManagerBase::ReleaseOutputStream() which deletes this object.
66 DCHECK(!input_stream_
);
67 DCHECK(!output_stream_
);
69 DCHECK(!pa_mainloop_
);
72 bool PulseAudioUnifiedStream::Open() {
73 DCHECK(manager_
->GetMessageLoop()->BelongsToCurrentThread());
74 // Prepare the recording buffers for the callbacks.
75 fifo_
.reset(new media::SeekableBuffer(
76 0, kFifoSizeInPackets
* params_
.GetBytesPerBuffer()));
77 input_data_buffer_
.reset(new uint8
[params_
.GetBytesPerBuffer()]);
79 if (!pulse::CreateOutputStream(&pa_mainloop_
, &pa_context_
, &output_stream_
,
80 params_
, &StreamNotifyCallback
, NULL
, this))
83 if (!pulse::CreateInputStream(pa_mainloop_
, pa_context_
, &input_stream_
,
84 params_
, input_device_id_
,
85 &StreamNotifyCallback
, this))
90 DCHECK(input_stream_
);
91 DCHECK(output_stream_
);
95 void PulseAudioUnifiedStream::Reset() {
97 DCHECK(!input_stream_
);
98 DCHECK(!output_stream_
);
104 AutoPulseLock
auto_lock(pa_mainloop_
);
106 // Close the input stream.
108 // Disable all the callbacks before disconnecting.
109 pa_stream_set_state_callback(input_stream_
, NULL
, NULL
);
110 pa_stream_flush(input_stream_
, NULL
, NULL
);
111 pa_stream_disconnect(input_stream_
);
113 // Release PulseAudio structures.
114 pa_stream_unref(input_stream_
);
115 input_stream_
= NULL
;
118 // Close the ouput stream.
119 if (output_stream_
) {
120 // Release PulseAudio output stream structures.
121 pa_stream_set_state_callback(output_stream_
, NULL
, NULL
);
122 pa_stream_disconnect(output_stream_
);
123 pa_stream_unref(output_stream_
);
124 output_stream_
= NULL
;
128 pa_context_disconnect(pa_context_
);
129 pa_context_set_state_callback(pa_context_
, NULL
, NULL
);
130 pa_context_unref(pa_context_
);
135 pa_threaded_mainloop_stop(pa_mainloop_
);
136 pa_threaded_mainloop_free(pa_mainloop_
);
140 void PulseAudioUnifiedStream::Close() {
141 DCHECK(manager_
->GetMessageLoop()->BelongsToCurrentThread());
144 // Signal to the manager that we're closed and can be removed.
145 // This should be the last call in the function as it deletes "this".
146 manager_
->ReleaseOutputStream(this);
149 void PulseAudioUnifiedStream::WriteData(size_t requested_bytes
) {
150 CHECK_EQ(requested_bytes
, static_cast<size_t>(params_
.GetBytesPerBuffer()));
153 int frames_filled
= 0;
154 if (source_callback_
) {
155 CHECK_GE(pa_stream_begin_write(
156 output_stream_
, &buffer
, &requested_bytes
), 0);
157 uint32 hardware_delay
= pulse::GetHardwareLatencyInBytes(
158 output_stream_
, params_
.sample_rate(),
159 params_
.GetBytesPerFrame());
160 fifo_
->Read(input_data_buffer_
.get(), requested_bytes
);
161 input_bus_
->FromInterleaved(
162 input_data_buffer_
.get(), params_
.frames_per_buffer(), 2);
164 frames_filled
= source_callback_
->OnMoreIOData(
167 AudioBuffersState(0, hardware_delay
));
170 // Zero the unfilled data so it plays back as silence.
171 if (frames_filled
< output_bus_
->frames()) {
172 output_bus_
->ZeroFramesPartial(
173 frames_filled
, output_bus_
->frames() - frames_filled
);
176 // Note: If this ever changes to output raw float the data must be clipped
177 // and sanitized since it may come from an untrusted source such as NaCl.
178 output_bus_
->Scale(volume_
);
179 output_bus_
->ToInterleaved(
180 output_bus_
->frames(), params_
.bits_per_sample() / 8, buffer
);
182 if (pa_stream_write(output_stream_
, buffer
, requested_bytes
, NULL
, 0LL,
183 PA_SEEK_RELATIVE
) < 0) {
184 if (source_callback_
) {
185 source_callback_
->OnError(this);
190 void PulseAudioUnifiedStream::ReadData() {
193 const void* data
= NULL
;
194 pa_stream_peek(input_stream_
, &data
, &length
);
195 if (!data
|| length
== 0)
198 fifo_
->Append(reinterpret_cast<const uint8
*>(data
), length
);
200 // Deliver the recording data to the renderer and drive the playout.
201 int packet_size
= params_
.GetBytesPerBuffer();
202 while (fifo_
->forward_bytes() >= packet_size
) {
203 WriteData(packet_size
);
206 // Checks if we still have data.
207 pa_stream_drop(input_stream_
);
208 } while (pa_stream_readable_size(input_stream_
) > 0);
210 pa_threaded_mainloop_signal(pa_mainloop_
, 0);
213 void PulseAudioUnifiedStream::Start(AudioSourceCallback
* callback
) {
214 DCHECK(manager_
->GetMessageLoop()->BelongsToCurrentThread());
216 CHECK(input_stream_
);
217 CHECK(output_stream_
);
218 AutoPulseLock
auto_lock(pa_mainloop_
);
220 // Ensure the context and stream are ready.
221 if (pa_context_get_state(pa_context_
) != PA_CONTEXT_READY
&&
222 pa_stream_get_state(output_stream_
) != PA_STREAM_READY
&&
223 pa_stream_get_state(input_stream_
) != PA_STREAM_READY
) {
224 callback
->OnError(this);
228 source_callback_
= callback
;
232 // Uncork (resume) the input stream.
233 pa_stream_set_read_callback(input_stream_
, &ReadCallback
, this);
234 pa_stream_readable_size(input_stream_
);
235 pa_operation
* operation
= pa_stream_cork(input_stream_
, 0, NULL
, NULL
);
236 WaitForOperationCompletion(pa_mainloop_
, operation
);
238 // Uncork (resume) the output stream.
239 // We use the recording stream to drive the playback, so we do not need to
240 // register the write callback using pa_stream_set_write_callback().
241 operation
= pa_stream_cork(output_stream_
, 0,
242 &pulse::StreamSuccessCallback
, pa_mainloop_
);
243 WaitForOperationCompletion(pa_mainloop_
, operation
);
246 void PulseAudioUnifiedStream::Stop() {
247 DCHECK(manager_
->GetMessageLoop()->BelongsToCurrentThread());
249 // Cork (pause) the stream. Waiting for the main loop lock will ensure
250 // outstanding callbacks have completed.
251 AutoPulseLock
auto_lock(pa_mainloop_
);
253 // Set |source_callback_| to NULL so all FulfillWriteRequest() calls which may
254 // occur while waiting on the flush and cork exit immediately.
255 source_callback_
= NULL
;
257 // Set the read callback to NULL before flushing the stream, otherwise it
258 // will cause deadlock on the operation.
259 pa_stream_set_read_callback(input_stream_
, NULL
, NULL
);
260 pa_operation
* operation
= pa_stream_flush(
261 input_stream_
, &pulse::StreamSuccessCallback
, pa_mainloop_
);
262 WaitForOperationCompletion(pa_mainloop_
, operation
);
264 operation
= pa_stream_cork(input_stream_
, 1, &pulse::StreamSuccessCallback
,
266 WaitForOperationCompletion(pa_mainloop_
, operation
);
268 // Flush the stream prior to cork, doing so after will cause hangs. Write
269 // callbacks are suspended while inside pa_threaded_mainloop_lock() so this
270 // is all thread safe.
271 operation
= pa_stream_flush(
272 output_stream_
, &pulse::StreamSuccessCallback
, pa_mainloop_
);
273 WaitForOperationCompletion(pa_mainloop_
, operation
);
275 operation
= pa_stream_cork(output_stream_
, 1, &pulse::StreamSuccessCallback
,
277 WaitForOperationCompletion(pa_mainloop_
, operation
);
280 void PulseAudioUnifiedStream::SetVolume(double volume
) {
281 DCHECK(manager_
->GetMessageLoop()->BelongsToCurrentThread());
283 volume_
= static_cast<float>(volume
);
286 void PulseAudioUnifiedStream::GetVolume(double* volume
) {
287 DCHECK(manager_
->GetMessageLoop()->BelongsToCurrentThread());