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
3 // found in the LICENSE file.
5 #include "media/audio/pulse/pulse_output.h"
7 #include <pulse/pulseaudio.h>
9 #include "base/message_loop/message_loop.h"
10 #include "media/audio/audio_manager_base.h"
11 #include "media/audio/audio_parameters.h"
12 #include "media/audio/pulse/pulse_util.h"
16 using pulse::AutoPulseLock
;
17 using pulse::WaitForOperationCompletion
;
19 // static, pa_stream_notify_cb
20 void PulseAudioOutputStream::StreamNotifyCallback(pa_stream
* s
, void* p_this
) {
21 PulseAudioOutputStream
* stream
= static_cast<PulseAudioOutputStream
*>(p_this
);
23 // Forward unexpected failures to the AudioSourceCallback if available. All
24 // these variables are only modified under pa_threaded_mainloop_lock() so this
25 // should be thread safe.
26 if (s
&& stream
->source_callback_
&&
27 pa_stream_get_state(s
) == PA_STREAM_FAILED
) {
28 stream
->source_callback_
->OnError(stream
);
31 pa_threaded_mainloop_signal(stream
->pa_mainloop_
, 0);
34 // static, pa_stream_request_cb_t
35 void PulseAudioOutputStream::StreamRequestCallback(pa_stream
* s
, size_t len
,
37 // Fulfill write request; must always result in a pa_stream_write() call.
38 static_cast<PulseAudioOutputStream
*>(p_this
)->FulfillWriteRequest(len
);
41 PulseAudioOutputStream::PulseAudioOutputStream(const AudioParameters
& params
,
42 AudioManagerBase
* manager
)
49 source_callback_(NULL
) {
50 DCHECK(manager_
->GetMessageLoop()->BelongsToCurrentThread());
52 CHECK(params_
.IsValid());
53 audio_bus_
= AudioBus::Create(params_
);
56 PulseAudioOutputStream::~PulseAudioOutputStream() {
57 // All internal structures should already have been freed in Close(), which
58 // calls AudioManagerBase::ReleaseOutputStream() which deletes this object.
61 DCHECK(!pa_mainloop_
);
64 bool PulseAudioOutputStream::Open() {
65 DCHECK(manager_
->GetMessageLoop()->BelongsToCurrentThread());
66 return pulse::CreateOutputStream(&pa_mainloop_
, &pa_context_
, &pa_stream_
,
67 params_
, &StreamNotifyCallback
,
68 &StreamRequestCallback
, this);
71 void PulseAudioOutputStream::Reset() {
79 AutoPulseLock
auto_lock(pa_mainloop_
);
83 // Ensure all samples are played out before shutdown.
84 pa_operation
* operation
= pa_stream_flush(
85 pa_stream_
, &pulse::StreamSuccessCallback
, pa_mainloop_
);
86 WaitForOperationCompletion(pa_mainloop_
, operation
);
88 // Release PulseAudio structures.
89 pa_stream_disconnect(pa_stream_
);
90 pa_stream_set_write_callback(pa_stream_
, NULL
, NULL
);
91 pa_stream_set_state_callback(pa_stream_
, NULL
, NULL
);
92 pa_stream_unref(pa_stream_
);
97 pa_context_disconnect(pa_context_
);
98 pa_context_set_state_callback(pa_context_
, NULL
, NULL
);
99 pa_context_unref(pa_context_
);
104 pa_threaded_mainloop_stop(pa_mainloop_
);
105 pa_threaded_mainloop_free(pa_mainloop_
);
109 void PulseAudioOutputStream::Close() {
110 DCHECK(manager_
->GetMessageLoop()->BelongsToCurrentThread());
114 // Signal to the manager that we're closed and can be removed.
115 // This should be the last call in the function as it deletes "this".
116 manager_
->ReleaseOutputStream(this);
119 void PulseAudioOutputStream::FulfillWriteRequest(size_t requested_bytes
) {
120 int bytes_remaining
= requested_bytes
;
121 while (bytes_remaining
> 0) {
123 size_t bytes_to_fill
= params_
.GetBytesPerBuffer();
124 CHECK_GE(pa_stream_begin_write(pa_stream_
, &buffer
, &bytes_to_fill
), 0);
125 CHECK_EQ(bytes_to_fill
, static_cast<size_t>(params_
.GetBytesPerBuffer()));
127 int frames_filled
= 0;
128 if (source_callback_
) {
129 uint32 hardware_delay
= pulse::GetHardwareLatencyInBytes(
130 pa_stream_
, params_
.sample_rate(),
131 params_
.GetBytesPerFrame());
132 frames_filled
= source_callback_
->OnMoreData(
133 audio_bus_
.get(), AudioBuffersState(0, hardware_delay
));
136 // Zero any unfilled data so it plays back as silence.
137 if (frames_filled
< audio_bus_
->frames()) {
138 audio_bus_
->ZeroFramesPartial(
139 frames_filled
, audio_bus_
->frames() - frames_filled
);
142 // Note: If this ever changes to output raw float the data must be clipped
143 // and sanitized since it may come from an untrusted source such as NaCl.
144 audio_bus_
->Scale(volume_
);
145 audio_bus_
->ToInterleaved(
146 audio_bus_
->frames(), params_
.bits_per_sample() / 8, buffer
);
148 if (pa_stream_write(pa_stream_
, buffer
, bytes_to_fill
, NULL
, 0LL,
149 PA_SEEK_RELATIVE
) < 0) {
150 if (source_callback_
) {
151 source_callback_
->OnError(this);
155 bytes_remaining
-= bytes_to_fill
;
159 void PulseAudioOutputStream::Start(AudioSourceCallback
* callback
) {
160 DCHECK(manager_
->GetMessageLoop()->BelongsToCurrentThread());
164 AutoPulseLock
auto_lock(pa_mainloop_
);
166 // Ensure the context and stream are ready.
167 if (pa_context_get_state(pa_context_
) != PA_CONTEXT_READY
&&
168 pa_stream_get_state(pa_stream_
) != PA_STREAM_READY
) {
169 callback
->OnError(this);
173 source_callback_
= callback
;
175 // Uncork (resume) the stream.
176 pa_operation
* operation
= pa_stream_cork(
177 pa_stream_
, 0, &pulse::StreamSuccessCallback
, pa_mainloop_
);
178 WaitForOperationCompletion(pa_mainloop_
, operation
);
181 void PulseAudioOutputStream::Stop() {
182 DCHECK(manager_
->GetMessageLoop()->BelongsToCurrentThread());
184 // Cork (pause) the stream. Waiting for the main loop lock will ensure
185 // outstanding callbacks have completed.
186 AutoPulseLock
auto_lock(pa_mainloop_
);
188 // Set |source_callback_| to NULL so all FulfillWriteRequest() calls which may
189 // occur while waiting on the flush and cork exit immediately.
190 source_callback_
= NULL
;
192 // Flush the stream prior to cork, doing so after will cause hangs. Write
193 // callbacks are suspended while inside pa_threaded_mainloop_lock() so this
194 // is all thread safe.
195 pa_operation
* operation
= pa_stream_flush(
196 pa_stream_
, &pulse::StreamSuccessCallback
, pa_mainloop_
);
197 WaitForOperationCompletion(pa_mainloop_
, operation
);
199 operation
= pa_stream_cork(pa_stream_
, 1, &pulse::StreamSuccessCallback
,
201 WaitForOperationCompletion(pa_mainloop_
, operation
);
204 void PulseAudioOutputStream::SetVolume(double volume
) {
205 DCHECK(manager_
->GetMessageLoop()->BelongsToCurrentThread());
207 volume_
= static_cast<float>(volume
);
210 void PulseAudioOutputStream::GetVolume(double* volume
) {
211 DCHECK(manager_
->GetMessageLoop()->BelongsToCurrentThread());