Files.app: Remove wait for startup animation.
[chromium-blink-merge.git] / media / audio / pulse / pulse_output.cc
blob5168f356a3cc4ab9124241c3600eb696ebfe44ad
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/single_thread_task_runner.h"
10 #include "media/audio/audio_manager_base.h"
11 #include "media/audio/pulse/pulse_util.h"
13 namespace media {
15 using pulse::AutoPulseLock;
16 using pulse::WaitForOperationCompletion;
18 // static, pa_stream_notify_cb
19 void PulseAudioOutputStream::StreamNotifyCallback(pa_stream* s, void* p_this) {
20 PulseAudioOutputStream* stream = static_cast<PulseAudioOutputStream*>(p_this);
22 // Forward unexpected failures to the AudioSourceCallback if available. All
23 // these variables are only modified under pa_threaded_mainloop_lock() so this
24 // should be thread safe.
25 if (s && stream->source_callback_ &&
26 pa_stream_get_state(s) == PA_STREAM_FAILED) {
27 stream->source_callback_->OnError(stream);
30 pa_threaded_mainloop_signal(stream->pa_mainloop_, 0);
33 // static, pa_stream_request_cb_t
34 void PulseAudioOutputStream::StreamRequestCallback(pa_stream* s, size_t len,
35 void* p_this) {
36 // Fulfill write request; must always result in a pa_stream_write() call.
37 static_cast<PulseAudioOutputStream*>(p_this)->FulfillWriteRequest(len);
40 PulseAudioOutputStream::PulseAudioOutputStream(const AudioParameters& params,
41 const std::string& device_id,
42 AudioManagerBase* manager)
43 : params_(params),
44 device_id_(device_id),
45 manager_(manager),
46 pa_context_(NULL),
47 pa_mainloop_(NULL),
48 pa_stream_(NULL),
49 volume_(1.0f),
50 source_callback_(NULL) {
51 CHECK(params_.IsValid());
52 audio_bus_ = AudioBus::Create(params_);
55 PulseAudioOutputStream::~PulseAudioOutputStream() {
56 // All internal structures should already have been freed in Close(), which
57 // calls AudioManagerBase::ReleaseOutputStream() which deletes this object.
58 DCHECK(!pa_stream_);
59 DCHECK(!pa_context_);
60 DCHECK(!pa_mainloop_);
63 bool PulseAudioOutputStream::Open() {
64 DCHECK(thread_checker_.CalledOnValidThread());
65 return pulse::CreateOutputStream(&pa_mainloop_, &pa_context_, &pa_stream_,
66 params_, device_id_, &StreamNotifyCallback,
67 &StreamRequestCallback, this);
70 void PulseAudioOutputStream::Reset() {
71 if (!pa_mainloop_) {
72 DCHECK(!pa_stream_);
73 DCHECK(!pa_context_);
74 return;
78 AutoPulseLock auto_lock(pa_mainloop_);
80 // Close the stream.
81 if (pa_stream_) {
82 // Ensure all samples are played out before shutdown.
83 pa_operation* operation = pa_stream_flush(
84 pa_stream_, &pulse::StreamSuccessCallback, pa_mainloop_);
85 WaitForOperationCompletion(pa_mainloop_, operation);
87 // Release PulseAudio structures.
88 pa_stream_disconnect(pa_stream_);
89 pa_stream_set_write_callback(pa_stream_, NULL, NULL);
90 pa_stream_set_state_callback(pa_stream_, NULL, NULL);
91 pa_stream_unref(pa_stream_);
92 pa_stream_ = NULL;
95 if (pa_context_) {
96 pa_context_disconnect(pa_context_);
97 pa_context_set_state_callback(pa_context_, NULL, NULL);
98 pa_context_unref(pa_context_);
99 pa_context_ = NULL;
103 pa_threaded_mainloop_stop(pa_mainloop_);
104 pa_threaded_mainloop_free(pa_mainloop_);
105 pa_mainloop_ = NULL;
108 void PulseAudioOutputStream::Close() {
109 DCHECK(thread_checker_.CalledOnValidThread());
111 Reset();
113 // Signal to the manager that we're closed and can be removed.
114 // This should be the last call in the function as it deletes "this".
115 manager_->ReleaseOutputStream(this);
118 void PulseAudioOutputStream::FulfillWriteRequest(size_t requested_bytes) {
119 int bytes_remaining = requested_bytes;
120 while (bytes_remaining > 0) {
121 void* buffer = NULL;
122 size_t bytes_to_fill = params_.GetBytesPerBuffer();
123 CHECK_GE(pa_stream_begin_write(pa_stream_, &buffer, &bytes_to_fill), 0);
124 CHECK_EQ(bytes_to_fill, static_cast<size_t>(params_.GetBytesPerBuffer()));
126 // NOTE: |bytes_to_fill| may be larger than |requested_bytes| now, this is
127 // okay since pa_stream_begin_write() is the authoritative source on how
128 // much can be written.
130 int frames_filled = 0;
131 if (source_callback_) {
132 const uint32 hardware_delay = pulse::GetHardwareLatencyInBytes(
133 pa_stream_, params_.sample_rate(), params_.GetBytesPerFrame());
134 frames_filled = source_callback_->OnMoreData(
135 audio_bus_.get(), hardware_delay);
137 // Zero any unfilled data so it plays back as silence.
138 if (frames_filled < audio_bus_->frames()) {
139 audio_bus_->ZeroFramesPartial(
140 frames_filled, audio_bus_->frames() - frames_filled);
143 // Note: If this ever changes to output raw float the data must be clipped
144 // and sanitized since it may come from an untrusted source such as NaCl.
145 audio_bus_->Scale(volume_);
146 audio_bus_->ToInterleaved(
147 audio_bus_->frames(), params_.bits_per_sample() / 8, buffer);
148 } else {
149 memset(buffer, 0, bytes_to_fill);
152 if (pa_stream_write(pa_stream_, buffer, bytes_to_fill, NULL, 0LL,
153 PA_SEEK_RELATIVE) < 0) {
154 if (source_callback_) {
155 source_callback_->OnError(this);
159 // NOTE: As mentioned above, |bytes_remaining| may be negative after this.
160 bytes_remaining -= bytes_to_fill;
162 // Despite telling Pulse to only request certain buffer sizes, it will not
163 // always obey. In these cases we need to avoid back to back reads from
164 // the renderer as it won't have time to complete the request.
166 // We can't defer the callback as Pulse will never call us again until we've
167 // satisfied writing the requested number of bytes.
169 // TODO(dalecurtis): It might be worth choosing the sleep duration based on
170 // the hardware latency return above. Watch http://crbug.com/366433 to see
171 // if a more complicated wait process is necessary. We may also need to see
172 // if a PostDelayedTask should be used here to avoid blocking the PulseAudio
173 // command thread.
174 if (source_callback_ && bytes_remaining > 0)
175 base::PlatformThread::Sleep(params_.GetBufferDuration() / 4);
179 void PulseAudioOutputStream::Start(AudioSourceCallback* callback) {
180 DCHECK(thread_checker_.CalledOnValidThread());
181 CHECK(callback);
182 CHECK(pa_stream_);
184 AutoPulseLock auto_lock(pa_mainloop_);
186 // Ensure the context and stream are ready.
187 if (pa_context_get_state(pa_context_) != PA_CONTEXT_READY &&
188 pa_stream_get_state(pa_stream_) != PA_STREAM_READY) {
189 callback->OnError(this);
190 return;
193 source_callback_ = callback;
195 // Uncork (resume) the stream.
196 pa_operation* operation = pa_stream_cork(
197 pa_stream_, 0, &pulse::StreamSuccessCallback, pa_mainloop_);
198 WaitForOperationCompletion(pa_mainloop_, operation);
201 void PulseAudioOutputStream::Stop() {
202 DCHECK(thread_checker_.CalledOnValidThread());
204 // Cork (pause) the stream. Waiting for the main loop lock will ensure
205 // outstanding callbacks have completed.
206 AutoPulseLock auto_lock(pa_mainloop_);
208 // Set |source_callback_| to NULL so all FulfillWriteRequest() calls which may
209 // occur while waiting on the flush and cork exit immediately.
210 source_callback_ = NULL;
212 // Flush the stream prior to cork, doing so after will cause hangs. Write
213 // callbacks are suspended while inside pa_threaded_mainloop_lock() so this
214 // is all thread safe.
215 pa_operation* operation = pa_stream_flush(
216 pa_stream_, &pulse::StreamSuccessCallback, pa_mainloop_);
217 WaitForOperationCompletion(pa_mainloop_, operation);
219 operation = pa_stream_cork(pa_stream_, 1, &pulse::StreamSuccessCallback,
220 pa_mainloop_);
221 WaitForOperationCompletion(pa_mainloop_, operation);
224 void PulseAudioOutputStream::SetVolume(double volume) {
225 DCHECK(thread_checker_.CalledOnValidThread());
227 volume_ = static_cast<float>(volume);
230 void PulseAudioOutputStream::GetVolume(double* volume) {
231 DCHECK(thread_checker_.CalledOnValidThread());
233 *volume = volume_;
236 } // namespace media