191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org/* 291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org * Copyright 2010 The WebRTC Project Authors. All rights reserved. 391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org * 491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org * Use of this source code is governed by a BSD-style license 591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org * that can be found in the LICENSE file in the root of the source 691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org * tree. An additional intellectual property rights grant can be found 791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org * in the file PATENTS. All contributing project authors may 891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org * be found in the AUTHORS file in the root of the source tree. 991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org */ 1091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 1191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org#include "webrtc/sound/pulseaudiosoundsystem.h" 1291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 1391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org#ifdef HAVE_LIBPULSE 1491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 1591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org#include "webrtc/sound/sounddevicelocator.h" 1691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org#include "webrtc/sound/soundinputstreaminterface.h" 1791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org#include "webrtc/sound/soundoutputstreaminterface.h" 1891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org#include "webrtc/base/common.h" 1991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org#include "webrtc/base/fileutils.h" // for GetApplicationName() 2091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org#include "webrtc/base/logging.h" 2191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org#include "webrtc/base/timeutils.h" 2291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org#include "webrtc/base/worker.h" 2391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 2491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.orgnamespace rtc { 2591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 2691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org// First PulseAudio protocol version that supports PA_STREAM_ADJUST_LATENCY. 2791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.orgstatic const uint32_t kAdjustLatencyProtocolVersion = 13; 2891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 2991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org// Lookup table from the rtc format enum in soundsysteminterface.h to 3091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org// Pulse's enums. 3191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.orgstatic const pa_sample_format_t kCricketFormatToPulseFormatTable[] = { 3291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // The order here must match the order in soundsysteminterface.h 3391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org PA_SAMPLE_S16LE, 3491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org}; 3591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 3691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org// Some timing constants for optimal operation. See 3791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org// https://tango.0pointer.de/pipermail/pulseaudio-discuss/2008-January/001170.html 3891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org// for a good explanation of some of the factors that go into this. 3991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 4091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org// Playback. 4191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 4291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org// For playback, there is a round-trip delay to fill the server-side playback 4391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org// buffer, so setting too low of a latency is a buffer underflow risk. We will 4491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org// automatically increase the latency if a buffer underflow does occur, but we 4591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org// also enforce a sane minimum at start-up time. Anything lower would be 4691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org// virtually guaranteed to underflow at least once, so there's no point in 4791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org// allowing lower latencies. 4891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.orgstatic const int kPlaybackLatencyMinimumMsecs = 20; 4991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org// Every time a playback stream underflows, we will reconfigure it with target 5091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org// latency that is greater by this amount. 5191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.orgstatic const int kPlaybackLatencyIncrementMsecs = 20; 5291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org// We also need to configure a suitable request size. Too small and we'd burn 5391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org// CPU from the overhead of transfering small amounts of data at once. Too large 5491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org// and the amount of data remaining in the buffer right before refilling it 5591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org// would be a buffer underflow risk. We set it to half of the buffer size. 5691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.orgstatic const int kPlaybackRequestFactor = 2; 5791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 5891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org// Capture. 5991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 6091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org// For capture, low latency is not a buffer overflow risk, but it makes us burn 6191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org// CPU from the overhead of transfering small amounts of data at once, so we set 6291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org// a recommended value that we use for the kLowLatency constant (but if the user 6391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org// explicitly requests something lower then we will honour it). 6491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org// 1ms takes about 6-7% CPU. 5ms takes about 5%. 10ms takes about 4.x%. 6591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.orgstatic const int kLowCaptureLatencyMsecs = 10; 6691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org// There is a round-trip delay to ack the data to the server, so the 6791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org// server-side buffer needs extra space to prevent buffer overflow. 20ms is 6891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org// sufficient, but there is no penalty to making it bigger, so we make it huge. 6991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org// (750ms is libpulse's default value for the _total_ buffer size in the 7091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org// kNoLatencyRequirements case.) 7191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.orgstatic const int kCaptureBufferExtraMsecs = 750; 7291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 7391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.orgstatic void FillPlaybackBufferAttr(int latency, 7491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org pa_buffer_attr *attr) { 7591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org attr->maxlength = latency; 7691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org attr->tlength = latency; 7791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org attr->minreq = latency / kPlaybackRequestFactor; 7891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org attr->prebuf = attr->tlength - attr->minreq; 7991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org LOG(LS_VERBOSE) << "Configuring latency = " << attr->tlength << ", minreq = " 8091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org << attr->minreq << ", minfill = " << attr->prebuf; 8191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org} 8291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 8391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.orgstatic pa_volume_t CricketVolumeToPulseVolume(int volume) { 8491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // PA's volume space goes from 0% at PA_VOLUME_MUTED (value 0) to 100% at 8591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // PA_VOLUME_NORM (value 0x10000). It can also go beyond 100% up to 8691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // PA_VOLUME_MAX (value UINT32_MAX-1), but using that is probably unwise. 8791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // We just linearly map the 0-255 scale of SoundSystemInterface onto 8891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // PA_VOLUME_MUTED-PA_VOLUME_NORM. If the programmer exceeds kMaxVolume then 8991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // they can access the over-100% features of PA. 9091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org return PA_VOLUME_MUTED + (PA_VOLUME_NORM - PA_VOLUME_MUTED) * 9191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org volume / SoundSystemInterface::kMaxVolume; 9291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org} 9391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 9491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.orgstatic int PulseVolumeToCricketVolume(pa_volume_t pa_volume) { 9591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org return SoundSystemInterface::kMinVolume + 9691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org (SoundSystemInterface::kMaxVolume - SoundSystemInterface::kMinVolume) * 9791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org pa_volume / PA_VOLUME_NORM; 9891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org} 9991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 10091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.orgstatic pa_volume_t MaxChannelVolume(pa_cvolume *channel_volumes) { 10191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org pa_volume_t pa_volume = PA_VOLUME_MUTED; // Minimum possible value. 10291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org for (int i = 0; i < channel_volumes->channels; ++i) { 10391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org if (pa_volume < channel_volumes->values[i]) { 10491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org pa_volume = channel_volumes->values[i]; 10591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 10691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 10791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org return pa_volume; 10891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org} 10991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 11091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.orgclass PulseAudioDeviceLocator : public SoundDeviceLocator { 11191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org public: 11291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org PulseAudioDeviceLocator(const std::string &name, 11391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org const std::string &device_name) 11491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org : SoundDeviceLocator(name, device_name) { 11591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 11691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 11791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org virtual SoundDeviceLocator *Copy() const { 11891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org return new PulseAudioDeviceLocator(*this); 11991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 12091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org}; 12191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 12291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org// Functionality that is common to both PulseAudioInputStream and 12391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org// PulseAudioOutputStream. 12491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.orgclass PulseAudioStream { 12591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org public: 12691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org PulseAudioStream(PulseAudioSoundSystem *pulse, pa_stream *stream, int flags) 12791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org : pulse_(pulse), stream_(stream), flags_(flags) { 12891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 12991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 13091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org ~PulseAudioStream() { 13191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // Close() should have been called during the containing class's destructor. 13291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org ASSERT(stream_ == NULL); 13391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 13491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 13591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // Must be called with the lock held. 13691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org bool Close() { 13791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org if (!IsClosed()) { 13891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // Unset this here so that we don't get a TERMINATED callback. 13991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org symbol_table()->pa_stream_set_state_callback()(stream_, NULL, NULL); 14091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org if (symbol_table()->pa_stream_disconnect()(stream_) != 0) { 14191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org LOG(LS_ERROR) << "Can't disconnect stream"; 14291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // Continue and return true anyways. 14391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 14491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org symbol_table()->pa_stream_unref()(stream_); 14591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org stream_ = NULL; 14691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 14791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org return true; 14891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 14991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 15091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // Must be called with the lock held. 15191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org int LatencyUsecs() { 15291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org if (!(flags_ & SoundSystemInterface::FLAG_REPORT_LATENCY)) { 15391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org return 0; 15491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 15591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 15691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org pa_usec_t latency; 15791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org int negative; 15891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org Lock(); 15991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org int re = symbol_table()->pa_stream_get_latency()(stream_, &latency, 16091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org &negative); 16191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org Unlock(); 16291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org if (re != 0) { 16391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org LOG(LS_ERROR) << "Can't query latency"; 16491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // We'd rather continue playout/capture with an incorrect delay than stop 16591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // it altogether, so return a valid value. 16691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org return 0; 16791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 16891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org if (negative) { 16991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // The delay can be negative for monitoring streams if the captured 17091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // samples haven't been played yet. In such a case, "latency" contains the 17191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // magnitude, so we must negate it to get the real value. 17291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org return -latency; 17391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } else { 17491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org return latency; 17591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 17691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 17791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 17891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org PulseAudioSoundSystem *pulse() { 17991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org return pulse_; 18091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 18191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 18291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org PulseAudioSymbolTable *symbol_table() { 18391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org return &pulse()->symbol_table_; 18491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 18591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 18691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org pa_stream *stream() { 18791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org ASSERT(stream_ != NULL); 18891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org return stream_; 18991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 19091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 19191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org bool IsClosed() { 19291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org return stream_ == NULL; 19391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 19491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 19591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org void Lock() { 19691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org pulse()->Lock(); 19791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 19891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 19991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org void Unlock() { 20091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org pulse()->Unlock(); 20191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 20291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 20391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org private: 20491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org PulseAudioSoundSystem *pulse_; 20591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org pa_stream *stream_; 20691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org int flags_; 20791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 20891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org DISALLOW_COPY_AND_ASSIGN(PulseAudioStream); 20991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org}; 21091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 21191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org// Implementation of an input stream. See soundinputstreaminterface.h regarding 21291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org// thread-safety. 21391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.orgclass PulseAudioInputStream : 21491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org public SoundInputStreamInterface, 21591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org private rtc::Worker { 21691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 21791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org struct GetVolumeCallbackData { 21891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org PulseAudioInputStream *instance; 21991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org pa_cvolume *channel_volumes; 22091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org }; 22191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 22291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org struct GetSourceChannelCountCallbackData { 22391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org PulseAudioInputStream *instance; 22491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org uint8_t *channels; 22591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org }; 22691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 22791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org public: 22891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org PulseAudioInputStream(PulseAudioSoundSystem *pulse, 22991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org pa_stream *stream, 23091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org int flags) 23191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org : stream_(pulse, stream, flags), 23291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org temp_sample_data_(NULL), 23391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org temp_sample_data_size_(0) { 23491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // This callback seems to never be issued, but let's set it anyways. 23591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org symbol_table()->pa_stream_set_overflow_callback()(stream, &OverflowCallback, 23691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org NULL); 23791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 23891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 23991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org virtual ~PulseAudioInputStream() { 24091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org bool success = Close(); 24191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // We need that to live. 24291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org VERIFY(success); 24391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 24491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 24591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org virtual bool StartReading() { 24691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org return StartWork(); 24791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 24891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 24991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org virtual bool StopReading() { 25091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org return StopWork(); 25191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 25291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 25391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org virtual bool GetVolume(int *volume) { 25491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org bool ret = false; 25591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 25691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org Lock(); 25791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 25891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // Unlike output streams, input streams have no concept of a stream volume, 25991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // only a device volume. So we have to retrieve the volume of the device 26091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // itself. 26191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 26291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org pa_cvolume channel_volumes; 26391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 26491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org GetVolumeCallbackData data; 26591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org data.instance = this; 26691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org data.channel_volumes = &channel_volumes; 26791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 26891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org pa_operation *op = symbol_table()->pa_context_get_source_info_by_index()( 26991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org stream_.pulse()->context_, 27091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org symbol_table()->pa_stream_get_device_index()(stream_.stream()), 27191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org &GetVolumeCallbackThunk, 27291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org &data); 27391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org if (!stream_.pulse()->FinishOperation(op)) { 27491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org goto done; 27591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 27691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 27791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org if (data.channel_volumes) { 27891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // This pointer was never unset by the callback, so we must have received 27991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // an empty list of infos. This probably never happens, but we code for it 28091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // anyway. 28191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org LOG(LS_ERROR) << "Did not receive GetVolumeCallback"; 28291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org goto done; 28391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 28491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 28591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // We now have the volume for each channel. Each channel could have a 28691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // different volume if, e.g., the user went and changed the volumes in the 28791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // PA UI. To get a single volume for SoundSystemInterface we just take the 28891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // maximum. Ideally we'd do so with pa_cvolume_max, but it doesn't exist in 28991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // Hardy, so we do it manually. 29091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org pa_volume_t pa_volume; 29191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org pa_volume = MaxChannelVolume(&channel_volumes); 29291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // Now map onto the SoundSystemInterface range. 29391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org *volume = PulseVolumeToCricketVolume(pa_volume); 29491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 29591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org ret = true; 29691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org done: 29791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org Unlock(); 29891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org return ret; 29991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 30091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 30191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org virtual bool SetVolume(int volume) { 30291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org bool ret = false; 30391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org pa_volume_t pa_volume = CricketVolumeToPulseVolume(volume); 30491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 30591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org Lock(); 30691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 30791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // Unlike output streams, input streams have no concept of a stream volume, 30891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // only a device volume. So we have to change the volume of the device 30991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // itself. 31091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 31191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // The device may have a different number of channels than the stream and 31291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // their mapping may be different, so we don't want to use the channel count 31391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // from our sample spec. We could use PA_CHANNELS_MAX to cover our bases, 31491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // and the server allows that even if the device's channel count is lower, 31591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // but some buggy PA clients don't like that (the pavucontrol on Hardy dies 31691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // in an assert if the channel count is different). So instead we look up 31791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // the actual number of channels that the device has. 31891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 31991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org uint8_t channels; 32091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 32191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org GetSourceChannelCountCallbackData data; 32291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org data.instance = this; 32391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org data.channels = &channels; 32491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 32591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org uint32_t device_index = symbol_table()->pa_stream_get_device_index()( 32691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org stream_.stream()); 32791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 32891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org pa_operation *op = symbol_table()->pa_context_get_source_info_by_index()( 32991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org stream_.pulse()->context_, 33091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org device_index, 33191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org &GetSourceChannelCountCallbackThunk, 33291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org &data); 33391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org if (!stream_.pulse()->FinishOperation(op)) { 33491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org goto done; 33591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 33691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 33791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org if (data.channels) { 33891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // This pointer was never unset by the callback, so we must have received 33991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // an empty list of infos. This probably never happens, but we code for it 34091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // anyway. 34191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org LOG(LS_ERROR) << "Did not receive GetSourceChannelCountCallback"; 34291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org goto done; 34391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 34491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 34591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org pa_cvolume channel_volumes; 34691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org symbol_table()->pa_cvolume_set()(&channel_volumes, channels, pa_volume); 34791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 34891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org op = symbol_table()->pa_context_set_source_volume_by_index()( 34991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org stream_.pulse()->context_, 35091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org device_index, 35191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org &channel_volumes, 35291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // This callback merely logs errors. 35391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org &SetVolumeCallback, 35491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org NULL); 35591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org if (!op) { 35691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org LOG(LS_ERROR) << "pa_context_set_source_volume_by_index()"; 35791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org goto done; 35891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 35991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // Don't need to wait for this to complete. 36091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org symbol_table()->pa_operation_unref()(op); 36191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 36291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org ret = true; 36391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org done: 36491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org Unlock(); 36591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org return ret; 36691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 36791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 36891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org virtual bool Close() { 36991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org if (!StopReading()) { 37091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org return false; 37191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 37291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org bool ret = true; 37391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org if (!stream_.IsClosed()) { 37491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org Lock(); 37591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org ret = stream_.Close(); 37691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org Unlock(); 37791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 37891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org return ret; 37991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 38091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 38191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org virtual int LatencyUsecs() { 38291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org return stream_.LatencyUsecs(); 38391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 38491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 38591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org private: 38691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org void Lock() { 38791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org stream_.Lock(); 38891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 38991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 39091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org void Unlock() { 39191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org stream_.Unlock(); 39291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 39391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 39491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org PulseAudioSymbolTable *symbol_table() { 39591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org return stream_.symbol_table(); 39691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 39791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 39891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org void EnableReadCallback() { 39991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org symbol_table()->pa_stream_set_read_callback()( 40091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org stream_.stream(), 40191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org &ReadCallbackThunk, 40291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org this); 40391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 40491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 40591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org void DisableReadCallback() { 40691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org symbol_table()->pa_stream_set_read_callback()( 40791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org stream_.stream(), 40891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org NULL, 40991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org NULL); 41091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 41191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 41291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org static void ReadCallbackThunk(pa_stream *unused1, 41391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org size_t unused2, 41491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org void *userdata) { 41591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org PulseAudioInputStream *instance = 41691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org static_cast<PulseAudioInputStream *>(userdata); 41791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org instance->OnReadCallback(); 41891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 41991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 42091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org void OnReadCallback() { 42191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // We get the data pointer and size now in order to save one Lock/Unlock 42291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // on OnMessage. 42391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org if (symbol_table()->pa_stream_peek()(stream_.stream(), 42491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org &temp_sample_data_, 42591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org &temp_sample_data_size_) != 0) { 42691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org LOG(LS_ERROR) << "Can't read data!"; 42791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org return; 42891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 42991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // Since we consume the data asynchronously on a different thread, we have 43091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // to temporarily disable the read callback or else Pulse will call it 43191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // continuously until we consume the data. We re-enable it below. 43291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org DisableReadCallback(); 43391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org HaveWork(); 43491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 43591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 43691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // Inherited from Worker. 43791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org virtual void OnStart() { 43891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org Lock(); 43991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org EnableReadCallback(); 44091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org Unlock(); 44191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 44291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 44391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // Inherited from Worker. 44491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org virtual void OnHaveWork() { 44591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org ASSERT(temp_sample_data_ && temp_sample_data_size_); 44691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org SignalSamplesRead(temp_sample_data_, 44791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org temp_sample_data_size_, 44891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org this); 44991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org temp_sample_data_ = NULL; 45091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org temp_sample_data_size_ = 0; 45191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 45291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org Lock(); 45391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org for (;;) { 45491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // Ack the last thing we read. 45591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org if (symbol_table()->pa_stream_drop()(stream_.stream()) != 0) { 45691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org LOG(LS_ERROR) << "Can't ack read data"; 45791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 45891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 45991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org if (symbol_table()->pa_stream_readable_size()(stream_.stream()) <= 0) { 46091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // Then that was all the data. 46191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org break; 46291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 46391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 46491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // Else more data. 46591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org const void *sample_data; 46691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org size_t sample_data_size; 46791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org if (symbol_table()->pa_stream_peek()(stream_.stream(), 46891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org &sample_data, 46991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org &sample_data_size) != 0) { 47091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org LOG(LS_ERROR) << "Can't read data!"; 47191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org break; 47291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 47391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 47491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // Drop lock for sigslot dispatch, which could take a while. 47591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org Unlock(); 47691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org SignalSamplesRead(sample_data, sample_data_size, this); 47791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org Lock(); 47891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 47991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // Return to top of loop for the ack and the check for more data. 48091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 48191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org EnableReadCallback(); 48291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org Unlock(); 48391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 48491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 48591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // Inherited from Worker. 48691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org virtual void OnStop() { 48791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org Lock(); 48891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org DisableReadCallback(); 48991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org Unlock(); 49091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 49191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 49291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org static void OverflowCallback(pa_stream *stream, 49391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org void *userdata) { 49491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org LOG(LS_WARNING) << "Buffer overflow on capture stream " << stream; 49591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 49691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 49791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org static void GetVolumeCallbackThunk(pa_context *unused, 49891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org const pa_source_info *info, 49991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org int eol, 50091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org void *userdata) { 50191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org GetVolumeCallbackData *data = 50291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org static_cast<GetVolumeCallbackData *>(userdata); 50391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org data->instance->OnGetVolumeCallback(info, eol, &data->channel_volumes); 50491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 50591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 50691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org void OnGetVolumeCallback(const pa_source_info *info, 50791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org int eol, 50891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org pa_cvolume **channel_volumes) { 50991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org if (eol) { 51091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // List is over. Wake GetVolume(). 51191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org stream_.pulse()->Signal(); 51291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org return; 51391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 51491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 51591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org if (*channel_volumes) { 51691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org **channel_volumes = info->volume; 51791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // Unset the pointer so that we know that we have have already copied the 51891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // volume. 51991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org *channel_volumes = NULL; 52091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } else { 52191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // We have received an additional callback after the first one, which 52291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // doesn't make sense for a single source. This probably never happens, 52391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // but we code for it anyway. 52491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org LOG(LS_WARNING) << "Ignoring extra GetVolumeCallback"; 52591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 52691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 52791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 52891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org static void GetSourceChannelCountCallbackThunk(pa_context *unused, 52991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org const pa_source_info *info, 53091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org int eol, 53191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org void *userdata) { 53291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org GetSourceChannelCountCallbackData *data = 53391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org static_cast<GetSourceChannelCountCallbackData *>(userdata); 53491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org data->instance->OnGetSourceChannelCountCallback(info, eol, &data->channels); 53591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 53691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 53791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org void OnGetSourceChannelCountCallback(const pa_source_info *info, 53891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org int eol, 53991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org uint8_t **channels) { 54091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org if (eol) { 54191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // List is over. Wake SetVolume(). 54291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org stream_.pulse()->Signal(); 54391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org return; 54491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 54591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 54691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org if (*channels) { 54791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org **channels = info->channel_map.channels; 54891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // Unset the pointer so that we know that we have have already copied the 54991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // channel count. 55091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org *channels = NULL; 55191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } else { 55291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // We have received an additional callback after the first one, which 55391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // doesn't make sense for a single source. This probably never happens, 55491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // but we code for it anyway. 55591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org LOG(LS_WARNING) << "Ignoring extra GetSourceChannelCountCallback"; 55691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 55791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 55891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 55991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org static void SetVolumeCallback(pa_context *unused1, 56091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org int success, 56191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org void *unused2) { 56291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org if (!success) { 56391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org LOG(LS_ERROR) << "Failed to change capture volume"; 56491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 56591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 56691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 56791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org PulseAudioStream stream_; 56891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // Temporary storage for passing data between threads. 56991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org const void *temp_sample_data_; 57091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org size_t temp_sample_data_size_; 57191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 57291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org DISALLOW_COPY_AND_ASSIGN(PulseAudioInputStream); 57391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org}; 57491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 57591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org// Implementation of an output stream. See soundoutputstreaminterface.h 57691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org// regarding thread-safety. 57791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.orgclass PulseAudioOutputStream : 57891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org public SoundOutputStreamInterface, 57991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org private rtc::Worker { 58091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 58191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org struct GetVolumeCallbackData { 58291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org PulseAudioOutputStream *instance; 58391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org pa_cvolume *channel_volumes; 58491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org }; 58591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 58691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org public: 58791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org PulseAudioOutputStream(PulseAudioSoundSystem *pulse, 58891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org pa_stream *stream, 58991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org int flags, 59091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org int latency) 59191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org : stream_(pulse, stream, flags), 59291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org configured_latency_(latency), 59391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org temp_buffer_space_(0) { 59491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org symbol_table()->pa_stream_set_underflow_callback()(stream, 59591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org &UnderflowCallbackThunk, 59691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org this); 59791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 59891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 59991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org virtual ~PulseAudioOutputStream() { 60091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org bool success = Close(); 60191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // We need that to live. 60291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org VERIFY(success); 60391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 60491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 60591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org virtual bool EnableBufferMonitoring() { 60691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org return StartWork(); 60791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 60891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 60991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org virtual bool DisableBufferMonitoring() { 61091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org return StopWork(); 61191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 61291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 61391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org virtual bool WriteSamples(const void *sample_data, 61491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org size_t size) { 61591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org bool ret = true; 61691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org Lock(); 61791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org if (symbol_table()->pa_stream_write()(stream_.stream(), 61891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org sample_data, 61991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org size, 62091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org NULL, 62191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 0, 62291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org PA_SEEK_RELATIVE) != 0) { 62391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org LOG(LS_ERROR) << "Unable to write"; 62491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org ret = false; 62591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 62691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org Unlock(); 62791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org return ret; 62891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 62991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 63091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org virtual bool GetVolume(int *volume) { 63191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org bool ret = false; 63291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 63391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org Lock(); 63491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 63591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org pa_cvolume channel_volumes; 63691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 63791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org GetVolumeCallbackData data; 63891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org data.instance = this; 63991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org data.channel_volumes = &channel_volumes; 64091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 64191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org pa_operation *op = symbol_table()->pa_context_get_sink_input_info()( 64291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org stream_.pulse()->context_, 64391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org symbol_table()->pa_stream_get_index()(stream_.stream()), 64491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org &GetVolumeCallbackThunk, 64591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org &data); 64691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org if (!stream_.pulse()->FinishOperation(op)) { 64791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org goto done; 64891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 64991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 65091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org if (data.channel_volumes) { 65191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // This pointer was never unset by the callback, so we must have received 65291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // an empty list of infos. This probably never happens, but we code for it 65391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // anyway. 65491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org LOG(LS_ERROR) << "Did not receive GetVolumeCallback"; 65591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org goto done; 65691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 65791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 65891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // We now have the volume for each channel. Each channel could have a 65991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // different volume if, e.g., the user went and changed the volumes in the 66091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // PA UI. To get a single volume for SoundSystemInterface we just take the 66191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // maximum. Ideally we'd do so with pa_cvolume_max, but it doesn't exist in 66291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // Hardy, so we do it manually. 66391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org pa_volume_t pa_volume; 66491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org pa_volume = MaxChannelVolume(&channel_volumes); 66591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // Now map onto the SoundSystemInterface range. 66691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org *volume = PulseVolumeToCricketVolume(pa_volume); 66791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 66891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org ret = true; 66991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org done: 67091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org Unlock(); 67191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org return ret; 67291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 67391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 67491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org virtual bool SetVolume(int volume) { 67591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org bool ret = false; 67691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org pa_volume_t pa_volume = CricketVolumeToPulseVolume(volume); 67791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 67891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org Lock(); 67991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 68091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org const pa_sample_spec *spec = symbol_table()->pa_stream_get_sample_spec()( 68191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org stream_.stream()); 68291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org if (!spec) { 68391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org LOG(LS_ERROR) << "pa_stream_get_sample_spec()"; 68491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org goto done; 68591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 68691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 68791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org pa_cvolume channel_volumes; 68891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org symbol_table()->pa_cvolume_set()(&channel_volumes, spec->channels, 68991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org pa_volume); 69091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 69191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org pa_operation *op; 69291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org op = symbol_table()->pa_context_set_sink_input_volume()( 69391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org stream_.pulse()->context_, 69491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org symbol_table()->pa_stream_get_index()(stream_.stream()), 69591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org &channel_volumes, 69691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // This callback merely logs errors. 69791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org &SetVolumeCallback, 69891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org NULL); 69991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org if (!op) { 70091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org LOG(LS_ERROR) << "pa_context_set_sink_input_volume()"; 70191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org goto done; 70291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 70391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // Don't need to wait for this to complete. 70491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org symbol_table()->pa_operation_unref()(op); 70591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 70691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org ret = true; 70791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org done: 70891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org Unlock(); 70991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org return ret; 71091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 71191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 71291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org virtual bool Close() { 71391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org if (!DisableBufferMonitoring()) { 71491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org return false; 71591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 71691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org bool ret = true; 71791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org if (!stream_.IsClosed()) { 71891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org Lock(); 71991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org symbol_table()->pa_stream_set_underflow_callback()(stream_.stream(), 72091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org NULL, 72191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org NULL); 72291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org ret = stream_.Close(); 72391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org Unlock(); 72491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 72591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org return ret; 72691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 72791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 72891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org virtual int LatencyUsecs() { 72991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org return stream_.LatencyUsecs(); 73091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 73191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 73291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org#if 0 73391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // TODO: Versions 0.9.16 and later of Pulse have a new API for 73491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // zero-copy writes, but Hardy is not new enough to have that so we can't 73591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // rely on it. Perhaps auto-detect if it's present or not and use it if we 73691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // can? 73791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 73891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org virtual bool GetWriteBuffer(void **buffer, size_t *size) { 73991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org bool ret = true; 74091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org Lock(); 74191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org if (symbol_table()->pa_stream_begin_write()(stream_.stream(), buffer, size) 74291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org != 0) { 74391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org LOG(LS_ERROR) << "Can't get write buffer"; 74491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org ret = false; 74591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 74691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org Unlock(); 74791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org return ret; 74891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 74991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 75091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // Releases the caller's hold on the write buffer. "written" must be the 75191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // amount of data that was written. 75291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org virtual bool ReleaseWriteBuffer(void *buffer, size_t written) { 75391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org bool ret = true; 75491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org Lock(); 75591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org if (written == 0) { 75691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org if (symbol_table()->pa_stream_cancel_write()(stream_.stream()) != 0) { 75791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org LOG(LS_ERROR) << "Can't cancel write"; 75891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org ret = false; 75991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 76091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } else { 76191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org if (symbol_table()->pa_stream_write()(stream_.stream(), 76291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org buffer, 76391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org written, 76491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org NULL, 76591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 0, 76691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org PA_SEEK_RELATIVE) != 0) { 76791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org LOG(LS_ERROR) << "Unable to write"; 76891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org ret = false; 76991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 77091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 77191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org Unlock(); 77291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org return ret; 77391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 77491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org#endif 77591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 77691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org private: 77791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org void Lock() { 77891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org stream_.Lock(); 77991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 78091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 78191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org void Unlock() { 78291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org stream_.Unlock(); 78391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 78491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 78591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org PulseAudioSymbolTable *symbol_table() { 78691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org return stream_.symbol_table(); 78791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 78891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 78991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org void EnableWriteCallback() { 79091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org pa_stream_state_t state = symbol_table()->pa_stream_get_state()( 79191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org stream_.stream()); 79291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org if (state == PA_STREAM_READY) { 79391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // May already have available space. Must check. 79491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org temp_buffer_space_ = symbol_table()->pa_stream_writable_size()( 79591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org stream_.stream()); 79691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org if (temp_buffer_space_ > 0) { 79791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // Yup, there is already space available, so if we register a write 79891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // callback then it will not receive any event. So dispatch one ourself 79991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // instead. 80091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org HaveWork(); 80191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org return; 80291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 80391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 80491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org symbol_table()->pa_stream_set_write_callback()( 80591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org stream_.stream(), 80691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org &WriteCallbackThunk, 80791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org this); 80891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 80991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 81091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org void DisableWriteCallback() { 81191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org symbol_table()->pa_stream_set_write_callback()( 81291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org stream_.stream(), 81391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org NULL, 81491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org NULL); 81591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 81691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 81791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org static void WriteCallbackThunk(pa_stream *unused, 81891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org size_t buffer_space, 81991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org void *userdata) { 82091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org PulseAudioOutputStream *instance = 82191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org static_cast<PulseAudioOutputStream *>(userdata); 82291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org instance->OnWriteCallback(buffer_space); 82391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 82491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 82591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org void OnWriteCallback(size_t buffer_space) { 82691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org temp_buffer_space_ = buffer_space; 82791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // Since we write the data asynchronously on a different thread, we have 82891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // to temporarily disable the write callback or else Pulse will call it 82991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // continuously until we write the data. We re-enable it below. 83091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org DisableWriteCallback(); 83191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org HaveWork(); 83291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 83391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 83491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // Inherited from Worker. 83591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org virtual void OnStart() { 83691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org Lock(); 83791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org EnableWriteCallback(); 83891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org Unlock(); 83991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 84091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 84191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // Inherited from Worker. 84291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org virtual void OnHaveWork() { 84391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org ASSERT(temp_buffer_space_ > 0); 84491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 84591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org SignalBufferSpace(temp_buffer_space_, this); 84691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 84791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org temp_buffer_space_ = 0; 84891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org Lock(); 84991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org EnableWriteCallback(); 85091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org Unlock(); 85191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 85291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 85391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // Inherited from Worker. 85491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org virtual void OnStop() { 85591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org Lock(); 85691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org DisableWriteCallback(); 85791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org Unlock(); 85891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 85991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 86091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org static void UnderflowCallbackThunk(pa_stream *unused, 86191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org void *userdata) { 86291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org PulseAudioOutputStream *instance = 86391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org static_cast<PulseAudioOutputStream *>(userdata); 86491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org instance->OnUnderflowCallback(); 86591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 86691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 86791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org void OnUnderflowCallback() { 86891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org LOG(LS_WARNING) << "Buffer underflow on playback stream " 86991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org << stream_.stream(); 87091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 87191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org if (configured_latency_ == SoundSystemInterface::kNoLatencyRequirements) { 87291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // We didn't configure a pa_buffer_attr before, so switching to one now 87391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // would be questionable. 87491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org return; 87591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 87691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 87791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // Otherwise reconfigure the stream with a higher target latency. 87891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 87991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org const pa_sample_spec *spec = symbol_table()->pa_stream_get_sample_spec()( 88091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org stream_.stream()); 88191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org if (!spec) { 88291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org LOG(LS_ERROR) << "pa_stream_get_sample_spec()"; 88391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org return; 88491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 88591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 88691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org size_t bytes_per_sec = symbol_table()->pa_bytes_per_second()(spec); 88791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 88891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org int new_latency = configured_latency_ + 88991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org bytes_per_sec * kPlaybackLatencyIncrementMsecs / 89091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org rtc::kNumMicrosecsPerSec; 89191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 89291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org pa_buffer_attr new_attr = {0}; 89391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org FillPlaybackBufferAttr(new_latency, &new_attr); 89491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 89591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org pa_operation *op = symbol_table()->pa_stream_set_buffer_attr()( 89691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org stream_.stream(), 89791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org &new_attr, 89891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // No callback. 89991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org NULL, 90091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org NULL); 90191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org if (!op) { 90291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org LOG(LS_ERROR) << "pa_stream_set_buffer_attr()"; 90391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org return; 90491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 90591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // Don't need to wait for this to complete. 90691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org symbol_table()->pa_operation_unref()(op); 90791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 90891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // Save the new latency in case we underflow again. 90991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org configured_latency_ = new_latency; 91091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 91191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 91291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org static void GetVolumeCallbackThunk(pa_context *unused, 91391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org const pa_sink_input_info *info, 91491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org int eol, 91591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org void *userdata) { 91691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org GetVolumeCallbackData *data = 91791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org static_cast<GetVolumeCallbackData *>(userdata); 91891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org data->instance->OnGetVolumeCallback(info, eol, &data->channel_volumes); 91991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 92091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 92191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org void OnGetVolumeCallback(const pa_sink_input_info *info, 92291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org int eol, 92391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org pa_cvolume **channel_volumes) { 92491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org if (eol) { 92591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // List is over. Wake GetVolume(). 92691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org stream_.pulse()->Signal(); 92791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org return; 92891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 92991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 93091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org if (*channel_volumes) { 93191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org **channel_volumes = info->volume; 93291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // Unset the pointer so that we know that we have have already copied the 93391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // volume. 93491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org *channel_volumes = NULL; 93591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } else { 93691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // We have received an additional callback after the first one, which 93791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // doesn't make sense for a single sink input. This probably never 93891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // happens, but we code for it anyway. 93991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org LOG(LS_WARNING) << "Ignoring extra GetVolumeCallback"; 94091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 94191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 94291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 94391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org static void SetVolumeCallback(pa_context *unused1, 94491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org int success, 94591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org void *unused2) { 94691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org if (!success) { 94791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org LOG(LS_ERROR) << "Failed to change playback volume"; 94891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 94991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 95091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 95191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org PulseAudioStream stream_; 95291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org int configured_latency_; 95391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // Temporary storage for passing data between threads. 95491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org size_t temp_buffer_space_; 95591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 95691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org DISALLOW_COPY_AND_ASSIGN(PulseAudioOutputStream); 95791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org}; 95891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 95991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.orgPulseAudioSoundSystem::PulseAudioSoundSystem() 96091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org : mainloop_(NULL), context_(NULL) { 96191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org} 96291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 96391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.orgPulseAudioSoundSystem::~PulseAudioSoundSystem() { 96491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org Terminate(); 96591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org} 96691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 96791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.orgbool PulseAudioSoundSystem::Init() { 96891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org if (IsInitialized()) { 96991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org return true; 97091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 97191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 97291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // Load libpulse. 97391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org if (!symbol_table_.Load()) { 97491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // Most likely the Pulse library and sound server are not installed on 97591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // this system. 97691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org LOG(LS_WARNING) << "Failed to load symbol table"; 97791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org return false; 97891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 97991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 98091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // Now create and start the Pulse event thread. 98191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org mainloop_ = symbol_table_.pa_threaded_mainloop_new()(); 98291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org if (!mainloop_) { 98391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org LOG(LS_ERROR) << "Can't create mainloop"; 98491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org goto fail0; 98591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 98691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 98791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org if (symbol_table_.pa_threaded_mainloop_start()(mainloop_) != 0) { 98891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org LOG(LS_ERROR) << "Can't start mainloop"; 98991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org goto fail1; 99091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 99191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 99291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org Lock(); 99391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org context_ = CreateNewConnection(); 99491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org Unlock(); 99591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 99691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org if (!context_) { 99791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org goto fail2; 99891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 99991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 100091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // Otherwise we're now ready! 100191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org return true; 100291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 100391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org fail2: 100491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org symbol_table_.pa_threaded_mainloop_stop()(mainloop_); 100591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org fail1: 100691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org symbol_table_.pa_threaded_mainloop_free()(mainloop_); 100791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org mainloop_ = NULL; 100891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org fail0: 100991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org return false; 101091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org} 101191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 101291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.orgvoid PulseAudioSoundSystem::Terminate() { 101391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org if (!IsInitialized()) { 101491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org return; 101591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 101691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 101791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org Lock(); 101891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org symbol_table_.pa_context_disconnect()(context_); 101991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org symbol_table_.pa_context_unref()(context_); 102091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org Unlock(); 102191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org context_ = NULL; 102291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org symbol_table_.pa_threaded_mainloop_stop()(mainloop_); 102391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org symbol_table_.pa_threaded_mainloop_free()(mainloop_); 102491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org mainloop_ = NULL; 102591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 102691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // We do not unload the symbol table because we may need it again soon if 102791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // Init() is called again. 102891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org} 102991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 103091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.orgbool PulseAudioSoundSystem::EnumeratePlaybackDevices( 103191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org SoundDeviceLocatorList *devices) { 103291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org return EnumerateDevices<pa_sink_info>( 103391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org devices, 103491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org symbol_table_.pa_context_get_sink_info_list(), 103591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org &EnumeratePlaybackDevicesCallbackThunk); 103691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org} 103791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 103891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.orgbool PulseAudioSoundSystem::EnumerateCaptureDevices( 103991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org SoundDeviceLocatorList *devices) { 104091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org return EnumerateDevices<pa_source_info>( 104191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org devices, 104291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org symbol_table_.pa_context_get_source_info_list(), 104391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org &EnumerateCaptureDevicesCallbackThunk); 104491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org} 104591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 104691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.orgbool PulseAudioSoundSystem::GetDefaultPlaybackDevice( 104791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org SoundDeviceLocator **device) { 104891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org return GetDefaultDevice<&pa_server_info::default_sink_name>(device); 104991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org} 105091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 105191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.orgbool PulseAudioSoundSystem::GetDefaultCaptureDevice( 105291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org SoundDeviceLocator **device) { 105391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org return GetDefaultDevice<&pa_server_info::default_source_name>(device); 105491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org} 105591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 105691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.orgSoundOutputStreamInterface *PulseAudioSoundSystem::OpenPlaybackDevice( 105791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org const SoundDeviceLocator *device, 105891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org const OpenParams ¶ms) { 105991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org return OpenDevice<SoundOutputStreamInterface>( 106091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org device, 106191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org params, 106291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org "Playback", 106391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org &PulseAudioSoundSystem::ConnectOutputStream); 106491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org} 106591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 106691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.orgSoundInputStreamInterface *PulseAudioSoundSystem::OpenCaptureDevice( 106791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org const SoundDeviceLocator *device, 106891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org const OpenParams ¶ms) { 106991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org return OpenDevice<SoundInputStreamInterface>( 107091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org device, 107191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org params, 107291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org "Capture", 107391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org &PulseAudioSoundSystem::ConnectInputStream); 107491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org} 107591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 107691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.orgconst char *PulseAudioSoundSystem::GetName() const { 107791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org return "PulseAudio"; 107891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org} 107991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 108091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.orginline bool PulseAudioSoundSystem::IsInitialized() { 108191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org return mainloop_ != NULL; 108291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org} 108391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 108491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.orgstruct ConnectToPulseCallbackData { 108591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org PulseAudioSoundSystem *instance; 108691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org bool connect_done; 108791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org}; 108891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 108991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.orgvoid PulseAudioSoundSystem::ConnectToPulseCallbackThunk( 109091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org pa_context *context, void *userdata) { 109191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org ConnectToPulseCallbackData *data = 109291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org static_cast<ConnectToPulseCallbackData *>(userdata); 109391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org data->instance->OnConnectToPulseCallback(context, &data->connect_done); 109491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org} 109591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 109691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.orgvoid PulseAudioSoundSystem::OnConnectToPulseCallback( 109791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org pa_context *context, bool *connect_done) { 109891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org pa_context_state_t state = symbol_table_.pa_context_get_state()(context); 109991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org if (state == PA_CONTEXT_READY || 110091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org state == PA_CONTEXT_FAILED || 110191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org state == PA_CONTEXT_TERMINATED) { 110291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // Connection process has reached a terminal state. Wake ConnectToPulse(). 110391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org *connect_done = true; 110491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org Signal(); 110591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 110691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org} 110791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 110891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org// Must be called with the lock held. 110991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.orgbool PulseAudioSoundSystem::ConnectToPulse(pa_context *context) { 111091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org bool ret = true; 111191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org ConnectToPulseCallbackData data; 111291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // Have to put this up here to satisfy the compiler. 111391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org pa_context_state_t state; 111491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 111591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org data.instance = this; 111691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org data.connect_done = false; 111791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 111891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org symbol_table_.pa_context_set_state_callback()(context, 111991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org &ConnectToPulseCallbackThunk, 112091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org &data); 112191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 112291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // Connect to PulseAudio sound server. 112391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org if (symbol_table_.pa_context_connect()( 112491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org context, 112591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org NULL, // Default server 112691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org PA_CONTEXT_NOAUTOSPAWN, 112791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org NULL) != 0) { // No special fork handling needed 112891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org LOG(LS_ERROR) << "Can't start connection to PulseAudio sound server"; 112991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org ret = false; 113091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org goto done; 113191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 113291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 113391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // Wait for the connection state machine to reach a terminal state. 113491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org do { 113591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org Wait(); 113691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } while (!data.connect_done); 113791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 113891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // Now check to see what final state we reached. 113991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org state = symbol_table_.pa_context_get_state()(context); 114091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 114191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org if (state != PA_CONTEXT_READY) { 114291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org if (state == PA_CONTEXT_FAILED) { 114391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org LOG(LS_ERROR) << "Failed to connect to PulseAudio sound server"; 114491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } else if (state == PA_CONTEXT_TERMINATED) { 114591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org LOG(LS_ERROR) << "PulseAudio connection terminated early"; 114691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } else { 114791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // Shouldn't happen, because we only signal on one of those three states. 114891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org LOG(LS_ERROR) << "Unknown problem connecting to PulseAudio"; 114991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 115091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org ret = false; 115191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 115291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 115391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org done: 115491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // We unset our callback for safety just in case the state might somehow 115591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // change later, because the pointer to "data" will be invalid after return 115691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // from this function. 115791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org symbol_table_.pa_context_set_state_callback()(context, NULL, NULL); 115891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org return ret; 115991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org} 116091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 116191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org// Must be called with the lock held. 116291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.orgpa_context *PulseAudioSoundSystem::CreateNewConnection() { 116391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // Create connection context. 116491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org std::string app_name; 116591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // TODO: Pulse etiquette says this name should be localized. Do 116691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // we care? 116791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org rtc::Filesystem::GetApplicationName(&app_name); 116891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org pa_context *context = symbol_table_.pa_context_new()( 116991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org symbol_table_.pa_threaded_mainloop_get_api()(mainloop_), 117091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org app_name.c_str()); 117191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org if (!context) { 117291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org LOG(LS_ERROR) << "Can't create context"; 117391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org goto fail0; 117491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 117591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 117691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // Now connect. 117791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org if (!ConnectToPulse(context)) { 117891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org goto fail1; 117991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 118091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 118191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // Otherwise the connection succeeded and is ready. 118291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org return context; 118391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 118491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org fail1: 118591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org symbol_table_.pa_context_unref()(context); 118691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org fail0: 118791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org return NULL; 118891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org} 118991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 119091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.orgstruct EnumerateDevicesCallbackData { 119191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org PulseAudioSoundSystem *instance; 119291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org SoundSystemInterface::SoundDeviceLocatorList *devices; 119391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org}; 119491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 119591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.orgvoid PulseAudioSoundSystem::EnumeratePlaybackDevicesCallbackThunk( 119691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org pa_context *unused, 119791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org const pa_sink_info *info, 119891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org int eol, 119991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org void *userdata) { 120091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org EnumerateDevicesCallbackData *data = 120191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org static_cast<EnumerateDevicesCallbackData *>(userdata); 120291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org data->instance->OnEnumeratePlaybackDevicesCallback(data->devices, info, eol); 120391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org} 120491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 120591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.orgvoid PulseAudioSoundSystem::EnumerateCaptureDevicesCallbackThunk( 120691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org pa_context *unused, 120791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org const pa_source_info *info, 120891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org int eol, 120991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org void *userdata) { 121091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org EnumerateDevicesCallbackData *data = 121191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org static_cast<EnumerateDevicesCallbackData *>(userdata); 121291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org data->instance->OnEnumerateCaptureDevicesCallback(data->devices, info, eol); 121391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org} 121491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 121591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.orgvoid PulseAudioSoundSystem::OnEnumeratePlaybackDevicesCallback( 121691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org SoundDeviceLocatorList *devices, 121791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org const pa_sink_info *info, 121891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org int eol) { 121991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org if (eol) { 122091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // List is over. Wake EnumerateDevices(). 122191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org Signal(); 122291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org return; 122391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 122491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 122591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // Else this is the next device. 122691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org devices->push_back( 122791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org new PulseAudioDeviceLocator(info->description, info->name)); 122891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org} 122991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 123091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.orgvoid PulseAudioSoundSystem::OnEnumerateCaptureDevicesCallback( 123191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org SoundDeviceLocatorList *devices, 123291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org const pa_source_info *info, 123391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org int eol) { 123491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org if (eol) { 123591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // List is over. Wake EnumerateDevices(). 123691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org Signal(); 123791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org return; 123891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 123991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 124091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org if (info->monitor_of_sink != PA_INVALID_INDEX) { 124191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // We don't want to list monitor sources, since they are almost certainly 124291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // not what the user wants for voice conferencing. 124391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org return; 124491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 124591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 124691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // Else this is the next device. 124791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org devices->push_back( 124891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org new PulseAudioDeviceLocator(info->description, info->name)); 124991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org} 125091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 125191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.orgtemplate <typename InfoStruct> 125291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.orgbool PulseAudioSoundSystem::EnumerateDevices( 125391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org SoundDeviceLocatorList *devices, 125491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org pa_operation *(*enumerate_fn)( 125591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org pa_context *c, 125691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org void (*callback_fn)( 125791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org pa_context *c, 125891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org const InfoStruct *i, 125991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org int eol, 126091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org void *userdata), 126191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org void *userdata), 126291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org void (*callback_fn)( 126391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org pa_context *c, 126491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org const InfoStruct *i, 126591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org int eol, 126691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org void *userdata)) { 126791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org ClearSoundDeviceLocatorList(devices); 126891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org if (!IsInitialized()) { 126991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org return false; 127091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 127191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 127291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org EnumerateDevicesCallbackData data; 127391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org data.instance = this; 127491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org data.devices = devices; 127591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 127691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org Lock(); 127791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org pa_operation *op = (*enumerate_fn)( 127891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org context_, 127991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org callback_fn, 128091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org &data); 128191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org bool ret = FinishOperation(op); 128291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org Unlock(); 128391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org return ret; 128491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org} 128591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 128691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.orgstruct GetDefaultDeviceCallbackData { 128791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org PulseAudioSoundSystem *instance; 128891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org SoundDeviceLocator **device; 128991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org}; 129091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 129191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.orgtemplate <const char *(pa_server_info::*field)> 129291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.orgvoid PulseAudioSoundSystem::GetDefaultDeviceCallbackThunk( 129391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org pa_context *unused, 129491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org const pa_server_info *info, 129591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org void *userdata) { 129691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org GetDefaultDeviceCallbackData *data = 129791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org static_cast<GetDefaultDeviceCallbackData *>(userdata); 129891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org data->instance->OnGetDefaultDeviceCallback<field>(info, data->device); 129991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org} 130091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 130191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.orgtemplate <const char *(pa_server_info::*field)> 130291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.orgvoid PulseAudioSoundSystem::OnGetDefaultDeviceCallback( 130391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org const pa_server_info *info, 130491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org SoundDeviceLocator **device) { 130591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org if (info) { 130691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org const char *dev = info->*field; 130791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org if (dev) { 130891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org *device = new PulseAudioDeviceLocator("Default device", dev); 130991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 131091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 131191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org Signal(); 131291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org} 131391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 131491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.orgtemplate <const char *(pa_server_info::*field)> 131591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.orgbool PulseAudioSoundSystem::GetDefaultDevice(SoundDeviceLocator **device) { 131691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org if (!IsInitialized()) { 131791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org return false; 131891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 131991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org bool ret; 132091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org *device = NULL; 132191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org GetDefaultDeviceCallbackData data; 132291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org data.instance = this; 132391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org data.device = device; 132491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org Lock(); 132591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org pa_operation *op = symbol_table_.pa_context_get_server_info()( 132691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org context_, 132791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org &GetDefaultDeviceCallbackThunk<field>, 132891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org &data); 132991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org ret = FinishOperation(op); 133091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org Unlock(); 133191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org return ret && (*device != NULL); 133291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org} 133391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 133491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.orgvoid PulseAudioSoundSystem::StreamStateChangedCallbackThunk( 133591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org pa_stream *stream, 133691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org void *userdata) { 133791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org PulseAudioSoundSystem *instance = 133891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org static_cast<PulseAudioSoundSystem *>(userdata); 133991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org instance->OnStreamStateChangedCallback(stream); 134091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org} 134191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 134291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.orgvoid PulseAudioSoundSystem::OnStreamStateChangedCallback(pa_stream *stream) { 134391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org pa_stream_state_t state = symbol_table_.pa_stream_get_state()(stream); 134491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org if (state == PA_STREAM_READY) { 134591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org LOG(LS_INFO) << "Pulse stream " << stream << " ready"; 134691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } else if (state == PA_STREAM_FAILED || 134791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org state == PA_STREAM_TERMINATED || 134891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org state == PA_STREAM_UNCONNECTED) { 134991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org LOG(LS_ERROR) << "Pulse stream " << stream << " failed to connect: " 135091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org << LastError(); 135191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 135291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org} 135391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 135491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.orgtemplate <typename StreamInterface> 135591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.orgStreamInterface *PulseAudioSoundSystem::OpenDevice( 135691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org const SoundDeviceLocator *device, 135791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org const OpenParams ¶ms, 135891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org const char *stream_name, 135991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org StreamInterface *(PulseAudioSoundSystem::*connect_fn)( 136091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org pa_stream *stream, 136191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org const char *dev, 136291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org int flags, 136391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org pa_stream_flags_t pa_flags, 136491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org int latency, 136591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org const pa_sample_spec &spec)) { 136691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org if (!IsInitialized()) { 136791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org return NULL; 136891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 136991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 137091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org const char *dev = static_cast<const PulseAudioDeviceLocator *>(device)-> 137191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org device_name().c_str(); 137291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 137391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org StreamInterface *stream_interface = NULL; 137491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 137591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org ASSERT(params.format < ARRAY_SIZE(kCricketFormatToPulseFormatTable)); 137691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 137791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org pa_sample_spec spec; 137891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org spec.format = kCricketFormatToPulseFormatTable[params.format]; 137991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org spec.rate = params.freq; 138091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org spec.channels = params.channels; 138191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 138291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org int pa_flags = 0; 138391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org if (params.flags & FLAG_REPORT_LATENCY) { 138491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org pa_flags |= PA_STREAM_INTERPOLATE_TIMING | 138591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org PA_STREAM_AUTO_TIMING_UPDATE; 138691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 138791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 138891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org if (params.latency != kNoLatencyRequirements) { 138991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // If configuring a specific latency then we want to specify 139091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // PA_STREAM_ADJUST_LATENCY to make the server adjust parameters 139191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // automatically to reach that target latency. However, that flag doesn't 139291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // exist in Ubuntu 8.04 and many people still use that, so we have to check 139391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // the protocol version of libpulse. 139491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org if (symbol_table_.pa_context_get_protocol_version()(context_) >= 139591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org kAdjustLatencyProtocolVersion) { 139691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org pa_flags |= PA_STREAM_ADJUST_LATENCY; 139791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 139891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 139991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 140091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org Lock(); 140191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 140291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org pa_stream *stream = symbol_table_.pa_stream_new()(context_, stream_name, 140391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org &spec, NULL); 140491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org if (!stream) { 140591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org LOG(LS_ERROR) << "Can't create pa_stream"; 140691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org goto done; 140791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 140891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 140991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // Set a state callback to log errors. 141091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org symbol_table_.pa_stream_set_state_callback()(stream, 141191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org &StreamStateChangedCallbackThunk, 141291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org this); 141391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 141491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org stream_interface = (this->*connect_fn)( 141591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org stream, 141691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org dev, 141791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org params.flags, 141891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org static_cast<pa_stream_flags_t>(pa_flags), 141991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org params.latency, 142091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org spec); 142191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org if (!stream_interface) { 142291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org LOG(LS_ERROR) << "Can't connect stream to " << dev; 142391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org symbol_table_.pa_stream_unref()(stream); 142491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 142591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 142691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org done: 142791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org Unlock(); 142891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org return stream_interface; 142991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org} 143091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 143191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org// Must be called with the lock held. 143291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.orgSoundOutputStreamInterface *PulseAudioSoundSystem::ConnectOutputStream( 143391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org pa_stream *stream, 143491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org const char *dev, 143591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org int flags, 143691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org pa_stream_flags_t pa_flags, 143791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org int latency, 143891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org const pa_sample_spec &spec) { 143991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org pa_buffer_attr attr = {0}; 144091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org pa_buffer_attr *pattr = NULL; 144191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org if (latency != kNoLatencyRequirements) { 144291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // kLowLatency is 0, so we treat it the same as a request for zero latency. 144391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org ssize_t bytes_per_sec = symbol_table_.pa_bytes_per_second()(&spec); 144491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org latency = rtc::_max( 144591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org latency, 144691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org static_cast<int>( 144791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org bytes_per_sec * kPlaybackLatencyMinimumMsecs / 144891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org rtc::kNumMicrosecsPerSec)); 144991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org FillPlaybackBufferAttr(latency, &attr); 145091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org pattr = &attr; 145191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 145291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org if (symbol_table_.pa_stream_connect_playback()( 145391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org stream, 145491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org dev, 145591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org pattr, 145691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org pa_flags, 145791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // Let server choose volume 145891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org NULL, 145991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // Not synchronized to any other playout 146091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org NULL) != 0) { 146191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org return NULL; 146291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 146391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org return new PulseAudioOutputStream(this, stream, flags, latency); 146491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org} 146591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 146691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org// Must be called with the lock held. 146791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.orgSoundInputStreamInterface *PulseAudioSoundSystem::ConnectInputStream( 146891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org pa_stream *stream, 146991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org const char *dev, 147091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org int flags, 147191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org pa_stream_flags_t pa_flags, 147291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org int latency, 147391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org const pa_sample_spec &spec) { 147491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org pa_buffer_attr attr = {0}; 147591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org pa_buffer_attr *pattr = NULL; 147691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org if (latency != kNoLatencyRequirements) { 147791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org size_t bytes_per_sec = symbol_table_.pa_bytes_per_second()(&spec); 147891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org if (latency == kLowLatency) { 147991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org latency = bytes_per_sec * kLowCaptureLatencyMsecs / 148091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org rtc::kNumMicrosecsPerSec; 148191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 148291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // Note: fragsize specifies a maximum transfer size, not a minimum, so it is 148391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org // not possible to force a high latency setting, only a low one. 148491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org attr.fragsize = latency; 148591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org attr.maxlength = latency + bytes_per_sec * kCaptureBufferExtraMsecs / 148691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org rtc::kNumMicrosecsPerSec; 148791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org LOG(LS_VERBOSE) << "Configuring latency = " << attr.fragsize 148891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org << ", maxlength = " << attr.maxlength; 148991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org pattr = &attr; 149091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 149191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org if (symbol_table_.pa_stream_connect_record()(stream, 149291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org dev, 149391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org pattr, 149491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org pa_flags) != 0) { 149591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org return NULL; 149691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 149791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org return new PulseAudioInputStream(this, stream, flags); 149891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org} 149991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 150091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org// Must be called with the lock held. 150191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.orgbool PulseAudioSoundSystem::FinishOperation(pa_operation *op) { 150291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org if (!op) { 150391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org LOG(LS_ERROR) << "Failed to start operation"; 150491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org return false; 150591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } 150691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 150791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org do { 150891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org Wait(); 150991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org } while (symbol_table_.pa_operation_get_state()(op) == PA_OPERATION_RUNNING); 151091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 151191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org symbol_table_.pa_operation_unref()(op); 151291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 151391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org return true; 151491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org} 151591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 151691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.orginline void PulseAudioSoundSystem::Lock() { 151791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org symbol_table_.pa_threaded_mainloop_lock()(mainloop_); 151891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org} 151991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 152091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.orginline void PulseAudioSoundSystem::Unlock() { 152191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org symbol_table_.pa_threaded_mainloop_unlock()(mainloop_); 152291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org} 152391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 152491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org// Must be called with the lock held. 152591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.orginline void PulseAudioSoundSystem::Wait() { 152691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org symbol_table_.pa_threaded_mainloop_wait()(mainloop_); 152791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org} 152891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 152991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org// Must be called with the lock held. 153091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.orginline void PulseAudioSoundSystem::Signal() { 153191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org symbol_table_.pa_threaded_mainloop_signal()(mainloop_, 0); 153291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org} 153391bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 153491bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org// Must be called with the lock held. 153591bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.orgconst char *PulseAudioSoundSystem::LastError() { 153691bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org return symbol_table_.pa_strerror()(symbol_table_.pa_context_errno()( 153791bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org context_)); 153891bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org} 153991bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 154091bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org} // namespace rtc 154191bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org 154291bac0462eaaa118674708a9c2b7e8f467edcb75henrike@webrtc.org#endif // HAVE_LIBPULSE 1543