pulse_output.cc revision 868fa2fe829687343ffae624259930155e16dbd8
1f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 2f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 3f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// found in the LICENSE file. 4f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 5f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "media/audio/pulse/pulse_output.h" 6f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 7f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include <pulse/pulseaudio.h> 8f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 9f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "base/message_loop.h" 10f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "media/audio/audio_manager_base.h" 11f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "media/audio/audio_parameters.h" 12f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "media/audio/pulse/pulse_util.h" 13f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 14f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)namespace media { 15f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 16f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)using pulse::AutoPulseLock; 17f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)using pulse::WaitForOperationCompletion; 18f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 19f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// static, pa_stream_notify_cb 20f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void PulseAudioOutputStream::StreamNotifyCallback(pa_stream* s, void* p_this) { 21f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) PulseAudioOutputStream* stream = static_cast<PulseAudioOutputStream*>(p_this); 22f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 23f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // Forward unexpected failures to the AudioSourceCallback if available. All 24f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // these variables are only modified under pa_threaded_mainloop_lock() so this 25f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // should be thread safe. 26f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (s && stream->source_callback_ && 27f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) pa_stream_get_state(s) == PA_STREAM_FAILED) { 28f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) stream->source_callback_->OnError(stream); 29f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 30f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 31f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) pa_threaded_mainloop_signal(stream->pa_mainloop_, 0); 32f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)} 33f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 34f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// static, pa_stream_request_cb_t 35f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void PulseAudioOutputStream::StreamRequestCallback(pa_stream* s, size_t len, 36f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) void* p_this) { 37f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // Fulfill write request; must always result in a pa_stream_write() call. 38f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) static_cast<PulseAudioOutputStream*>(p_this)->FulfillWriteRequest(len); 39f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)} 40f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 41f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)PulseAudioOutputStream::PulseAudioOutputStream(const AudioParameters& params, 42f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) AudioManagerBase* manager) 43f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) : params_(params), 44f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) manager_(manager), 45f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) pa_context_(NULL), 46f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) pa_mainloop_(NULL), 47f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) pa_stream_(NULL), 48f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) volume_(1.0f), 49f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) source_callback_(NULL) { 50f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) DCHECK(manager_->GetMessageLoop()->BelongsToCurrentThread()); 51f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 52f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) CHECK(params_.IsValid()); 53f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) audio_bus_ = AudioBus::Create(params_); 54f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)} 55f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 56f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)PulseAudioOutputStream::~PulseAudioOutputStream() { 57f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // All internal structures should already have been freed in Close(), which 58f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // calls AudioManagerBase::ReleaseOutputStream() which deletes this object. 59f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) DCHECK(!pa_stream_); 60f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) DCHECK(!pa_context_); 61f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) DCHECK(!pa_mainloop_); 62f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)} 63f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 64f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)bool PulseAudioOutputStream::Open() { 65f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) DCHECK(manager_->GetMessageLoop()->BelongsToCurrentThread()); 66f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) return pulse::CreateOutputStream(&pa_mainloop_, &pa_context_, &pa_stream_, 67f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) params_, &StreamNotifyCallback, 68f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) &StreamRequestCallback, this); 69f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)} 70f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 71f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void PulseAudioOutputStream::Reset() { 72f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (!pa_mainloop_) { 73f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) DCHECK(!pa_stream_); 74f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) DCHECK(!pa_context_); 75f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) return; 76f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 77f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 78f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) { 79f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) AutoPulseLock auto_lock(pa_mainloop_); 80f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 81f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // Close the stream. 82f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (pa_stream_) { 83f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // Ensure all samples are played out before shutdown. 84f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) pa_operation* operation = pa_stream_flush( 85f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) pa_stream_, &pulse::StreamSuccessCallback, pa_mainloop_); 86f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) WaitForOperationCompletion(pa_mainloop_, operation); 87f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 88f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // Release PulseAudio structures. 89f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) pa_stream_disconnect(pa_stream_); 90f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) pa_stream_set_write_callback(pa_stream_, NULL, NULL); 91f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) pa_stream_set_state_callback(pa_stream_, NULL, NULL); 92f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) pa_stream_unref(pa_stream_); 93f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) pa_stream_ = NULL; 94f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 95f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 96f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (pa_context_) { 97f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) pa_context_disconnect(pa_context_); 98f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) pa_context_set_state_callback(pa_context_, NULL, NULL); 99f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) pa_context_unref(pa_context_); 100f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) pa_context_ = NULL; 101f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 102f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 103f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 104f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) pa_threaded_mainloop_stop(pa_mainloop_); 105f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) pa_threaded_mainloop_free(pa_mainloop_); 106f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) pa_mainloop_ = NULL; 107f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)} 108f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 109f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void PulseAudioOutputStream::Close() { 110f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) DCHECK(manager_->GetMessageLoop()->BelongsToCurrentThread()); 111f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 112f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) Reset(); 113f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 114f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // Signal to the manager that we're closed and can be removed. 115f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // This should be the last call in the function as it deletes "this". 116f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) manager_->ReleaseOutputStream(this); 117f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)} 118f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 119f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void PulseAudioOutputStream::FulfillWriteRequest(size_t requested_bytes) { 120f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) int bytes_remaining = requested_bytes; 121f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) while (bytes_remaining > 0) { 122f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) void* buffer = NULL; 123f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) size_t bytes_to_fill = params_.GetBytesPerBuffer(); 124f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) CHECK_GE(pa_stream_begin_write(pa_stream_, &buffer, &bytes_to_fill), 0); 125f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) CHECK_EQ(bytes_to_fill, static_cast<size_t>(params_.GetBytesPerBuffer())); 126f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 127f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) int frames_filled = 0; 128f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (source_callback_) { 129f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) uint32 hardware_delay = pulse::GetHardwareLatencyInBytes( 130f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) pa_stream_, params_.sample_rate(), 131f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) params_.GetBytesPerFrame()); 132f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) frames_filled = source_callback_->OnMoreData( 133f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) audio_bus_.get(), AudioBuffersState(0, hardware_delay)); 134f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 135f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 136f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // Zero any unfilled data so it plays back as silence. 137f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (frames_filled < audio_bus_->frames()) { 138f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) audio_bus_->ZeroFramesPartial( 139f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) frames_filled, audio_bus_->frames() - frames_filled); 140f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 141f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 142f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // Note: If this ever changes to output raw float the data must be clipped 143f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // and sanitized since it may come from an untrusted source such as NaCl. 144f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) audio_bus_->Scale(volume_); 145f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) audio_bus_->ToInterleaved( 146f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) audio_bus_->frames(), params_.bits_per_sample() / 8, buffer); 147f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 148f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (pa_stream_write(pa_stream_, buffer, bytes_to_fill, NULL, 0LL, 149f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) PA_SEEK_RELATIVE) < 0) { 150f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (source_callback_) { 151f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) source_callback_->OnError(this); 152f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 153f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 154f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 155f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) bytes_remaining -= bytes_to_fill; 156f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 157f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)} 158f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 159f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void PulseAudioOutputStream::Start(AudioSourceCallback* callback) { 160f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) DCHECK(manager_->GetMessageLoop()->BelongsToCurrentThread()); 161f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) CHECK(callback); 162f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) CHECK(pa_stream_); 163f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 164f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) AutoPulseLock auto_lock(pa_mainloop_); 165f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 166f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // Ensure the context and stream are ready. 167f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (pa_context_get_state(pa_context_) != PA_CONTEXT_READY && 168f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) pa_stream_get_state(pa_stream_) != PA_STREAM_READY) { 169f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) callback->OnError(this); 170f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) return; 171f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 172f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 173f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) source_callback_ = callback; 174f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 175f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // Uncork (resume) the stream. 176f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) pa_operation* operation = pa_stream_cork( 177f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) pa_stream_, 0, &pulse::StreamSuccessCallback, pa_mainloop_); 178f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) WaitForOperationCompletion(pa_mainloop_, operation); 179f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)} 180f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 181f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void PulseAudioOutputStream::Stop() { 182f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) DCHECK(manager_->GetMessageLoop()->BelongsToCurrentThread()); 183f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 184f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // Cork (pause) the stream. Waiting for the main loop lock will ensure 185f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // outstanding callbacks have completed. 186f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) AutoPulseLock auto_lock(pa_mainloop_); 187f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 188f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // Set |source_callback_| to NULL so all FulfillWriteRequest() calls which may 189f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // occur while waiting on the flush and cork exit immediately. 190f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) source_callback_ = NULL; 191f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 192f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // Flush the stream prior to cork, doing so after will cause hangs. Write 193f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // callbacks are suspended while inside pa_threaded_mainloop_lock() so this 194f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // is all thread safe. 195f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) pa_operation* operation = pa_stream_flush( 196f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) pa_stream_, &pulse::StreamSuccessCallback, pa_mainloop_); 197f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) WaitForOperationCompletion(pa_mainloop_, operation); 198f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 199f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) operation = pa_stream_cork(pa_stream_, 1, &pulse::StreamSuccessCallback, 200f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) pa_mainloop_); 201f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) WaitForOperationCompletion(pa_mainloop_, operation); 202f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)} 203f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 204f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void PulseAudioOutputStream::SetVolume(double volume) { 205f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) DCHECK(manager_->GetMessageLoop()->BelongsToCurrentThread()); 206f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 207f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) volume_ = static_cast<float>(volume); 208f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)} 209f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 210f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void PulseAudioOutputStream::GetVolume(double* volume) { 211f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) DCHECK(manager_->GetMessageLoop()->BelongsToCurrentThread()); 212f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 213f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) *volume = volume_; 214f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)} 215f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 216f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)} // namespace media 217f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)