166a358217004e1580453e46ce99041533e994985henrike@webrtc.org/* 266a358217004e1580453e46ce99041533e994985henrike@webrtc.org * Copyright 2010 The WebRTC Project Authors. All rights reserved. 366a358217004e1580453e46ce99041533e994985henrike@webrtc.org * 466a358217004e1580453e46ce99041533e994985henrike@webrtc.org * Use of this source code is governed by a BSD-style license 566a358217004e1580453e46ce99041533e994985henrike@webrtc.org * that can be found in the LICENSE file in the root of the source 666a358217004e1580453e46ce99041533e994985henrike@webrtc.org * tree. An additional intellectual property rights grant can be found 766a358217004e1580453e46ce99041533e994985henrike@webrtc.org * in the file PATENTS. All contributing project authors may 866a358217004e1580453e46ce99041533e994985henrike@webrtc.org * be found in the AUTHORS file in the root of the source tree. 966a358217004e1580453e46ce99041533e994985henrike@webrtc.org */ 1066a358217004e1580453e46ce99041533e994985henrike@webrtc.org 1166a358217004e1580453e46ce99041533e994985henrike@webrtc.org#include "webrtc/sound/pulseaudiosoundsystem.h" 1266a358217004e1580453e46ce99041533e994985henrike@webrtc.org 1366a358217004e1580453e46ce99041533e994985henrike@webrtc.org#ifdef HAVE_LIBPULSE 1466a358217004e1580453e46ce99041533e994985henrike@webrtc.org 15ff689be3c0c59c1be29aaa0697aa0f762566d6c6andresp@webrtc.org#include <algorithm> 160f2e939a92fc1a70a67a9fc141d1f1d006bcded9jbauch#include <string> 175237aaf243d29732f59557361b7a993c0a18cf0etfarina 185237aaf243d29732f59557361b7a993c0a18cf0etfarina#include "webrtc/base/arraysize.h" 1966a358217004e1580453e46ce99041533e994985henrike@webrtc.org#include "webrtc/base/common.h" 2066a358217004e1580453e46ce99041533e994985henrike@webrtc.org#include "webrtc/base/fileutils.h" // for GetApplicationName() 2166a358217004e1580453e46ce99041533e994985henrike@webrtc.org#include "webrtc/base/logging.h" 2266a358217004e1580453e46ce99041533e994985henrike@webrtc.org#include "webrtc/base/timeutils.h" 2366a358217004e1580453e46ce99041533e994985henrike@webrtc.org#include "webrtc/base/worker.h" 245237aaf243d29732f59557361b7a993c0a18cf0etfarina#include "webrtc/sound/sounddevicelocator.h" 255237aaf243d29732f59557361b7a993c0a18cf0etfarina#include "webrtc/sound/soundinputstreaminterface.h" 265237aaf243d29732f59557361b7a993c0a18cf0etfarina#include "webrtc/sound/soundoutputstreaminterface.h" 2766a358217004e1580453e46ce99041533e994985henrike@webrtc.org 2866a358217004e1580453e46ce99041533e994985henrike@webrtc.orgnamespace rtc { 2966a358217004e1580453e46ce99041533e994985henrike@webrtc.org 3066a358217004e1580453e46ce99041533e994985henrike@webrtc.org// First PulseAudio protocol version that supports PA_STREAM_ADJUST_LATENCY. 3166a358217004e1580453e46ce99041533e994985henrike@webrtc.orgstatic const uint32_t kAdjustLatencyProtocolVersion = 13; 3266a358217004e1580453e46ce99041533e994985henrike@webrtc.org 3366a358217004e1580453e46ce99041533e994985henrike@webrtc.org// Lookup table from the rtc format enum in soundsysteminterface.h to 3466a358217004e1580453e46ce99041533e994985henrike@webrtc.org// Pulse's enums. 3566a358217004e1580453e46ce99041533e994985henrike@webrtc.orgstatic const pa_sample_format_t kCricketFormatToPulseFormatTable[] = { 3666a358217004e1580453e46ce99041533e994985henrike@webrtc.org // The order here must match the order in soundsysteminterface.h 3766a358217004e1580453e46ce99041533e994985henrike@webrtc.org PA_SAMPLE_S16LE, 3866a358217004e1580453e46ce99041533e994985henrike@webrtc.org}; 3966a358217004e1580453e46ce99041533e994985henrike@webrtc.org 4066a358217004e1580453e46ce99041533e994985henrike@webrtc.org// Some timing constants for optimal operation. See 4166a358217004e1580453e46ce99041533e994985henrike@webrtc.org// https://tango.0pointer.de/pipermail/pulseaudio-discuss/2008-January/001170.html 4266a358217004e1580453e46ce99041533e994985henrike@webrtc.org// for a good explanation of some of the factors that go into this. 4366a358217004e1580453e46ce99041533e994985henrike@webrtc.org 4466a358217004e1580453e46ce99041533e994985henrike@webrtc.org// Playback. 4566a358217004e1580453e46ce99041533e994985henrike@webrtc.org 4666a358217004e1580453e46ce99041533e994985henrike@webrtc.org// For playback, there is a round-trip delay to fill the server-side playback 4766a358217004e1580453e46ce99041533e994985henrike@webrtc.org// buffer, so setting too low of a latency is a buffer underflow risk. We will 4866a358217004e1580453e46ce99041533e994985henrike@webrtc.org// automatically increase the latency if a buffer underflow does occur, but we 4966a358217004e1580453e46ce99041533e994985henrike@webrtc.org// also enforce a sane minimum at start-up time. Anything lower would be 5066a358217004e1580453e46ce99041533e994985henrike@webrtc.org// virtually guaranteed to underflow at least once, so there's no point in 5166a358217004e1580453e46ce99041533e994985henrike@webrtc.org// allowing lower latencies. 5266a358217004e1580453e46ce99041533e994985henrike@webrtc.orgstatic const int kPlaybackLatencyMinimumMsecs = 20; 5366a358217004e1580453e46ce99041533e994985henrike@webrtc.org// Every time a playback stream underflows, we will reconfigure it with target 5466a358217004e1580453e46ce99041533e994985henrike@webrtc.org// latency that is greater by this amount. 5566a358217004e1580453e46ce99041533e994985henrike@webrtc.orgstatic const int kPlaybackLatencyIncrementMsecs = 20; 5666a358217004e1580453e46ce99041533e994985henrike@webrtc.org// We also need to configure a suitable request size. Too small and we'd burn 5766a358217004e1580453e46ce99041533e994985henrike@webrtc.org// CPU from the overhead of transfering small amounts of data at once. Too large 5866a358217004e1580453e46ce99041533e994985henrike@webrtc.org// and the amount of data remaining in the buffer right before refilling it 5966a358217004e1580453e46ce99041533e994985henrike@webrtc.org// would be a buffer underflow risk. We set it to half of the buffer size. 6066a358217004e1580453e46ce99041533e994985henrike@webrtc.orgstatic const int kPlaybackRequestFactor = 2; 6166a358217004e1580453e46ce99041533e994985henrike@webrtc.org 6266a358217004e1580453e46ce99041533e994985henrike@webrtc.org// Capture. 6366a358217004e1580453e46ce99041533e994985henrike@webrtc.org 6466a358217004e1580453e46ce99041533e994985henrike@webrtc.org// For capture, low latency is not a buffer overflow risk, but it makes us burn 6566a358217004e1580453e46ce99041533e994985henrike@webrtc.org// CPU from the overhead of transfering small amounts of data at once, so we set 6666a358217004e1580453e46ce99041533e994985henrike@webrtc.org// a recommended value that we use for the kLowLatency constant (but if the user 6766a358217004e1580453e46ce99041533e994985henrike@webrtc.org// explicitly requests something lower then we will honour it). 6866a358217004e1580453e46ce99041533e994985henrike@webrtc.org// 1ms takes about 6-7% CPU. 5ms takes about 5%. 10ms takes about 4.x%. 6966a358217004e1580453e46ce99041533e994985henrike@webrtc.orgstatic const int kLowCaptureLatencyMsecs = 10; 7066a358217004e1580453e46ce99041533e994985henrike@webrtc.org// There is a round-trip delay to ack the data to the server, so the 7166a358217004e1580453e46ce99041533e994985henrike@webrtc.org// server-side buffer needs extra space to prevent buffer overflow. 20ms is 7266a358217004e1580453e46ce99041533e994985henrike@webrtc.org// sufficient, but there is no penalty to making it bigger, so we make it huge. 7366a358217004e1580453e46ce99041533e994985henrike@webrtc.org// (750ms is libpulse's default value for the _total_ buffer size in the 7466a358217004e1580453e46ce99041533e994985henrike@webrtc.org// kNoLatencyRequirements case.) 7566a358217004e1580453e46ce99041533e994985henrike@webrtc.orgstatic const int kCaptureBufferExtraMsecs = 750; 7666a358217004e1580453e46ce99041533e994985henrike@webrtc.org 7766a358217004e1580453e46ce99041533e994985henrike@webrtc.orgstatic void FillPlaybackBufferAttr(int latency, 7866a358217004e1580453e46ce99041533e994985henrike@webrtc.org pa_buffer_attr *attr) { 7966a358217004e1580453e46ce99041533e994985henrike@webrtc.org attr->maxlength = latency; 8066a358217004e1580453e46ce99041533e994985henrike@webrtc.org attr->tlength = latency; 8166a358217004e1580453e46ce99041533e994985henrike@webrtc.org attr->minreq = latency / kPlaybackRequestFactor; 8266a358217004e1580453e46ce99041533e994985henrike@webrtc.org attr->prebuf = attr->tlength - attr->minreq; 8366a358217004e1580453e46ce99041533e994985henrike@webrtc.org LOG(LS_VERBOSE) << "Configuring latency = " << attr->tlength << ", minreq = " 8466a358217004e1580453e46ce99041533e994985henrike@webrtc.org << attr->minreq << ", minfill = " << attr->prebuf; 8566a358217004e1580453e46ce99041533e994985henrike@webrtc.org} 8666a358217004e1580453e46ce99041533e994985henrike@webrtc.org 8766a358217004e1580453e46ce99041533e994985henrike@webrtc.orgstatic pa_volume_t CricketVolumeToPulseVolume(int volume) { 8866a358217004e1580453e46ce99041533e994985henrike@webrtc.org // PA's volume space goes from 0% at PA_VOLUME_MUTED (value 0) to 100% at 8966a358217004e1580453e46ce99041533e994985henrike@webrtc.org // PA_VOLUME_NORM (value 0x10000). It can also go beyond 100% up to 9066a358217004e1580453e46ce99041533e994985henrike@webrtc.org // PA_VOLUME_MAX (value UINT32_MAX-1), but using that is probably unwise. 9166a358217004e1580453e46ce99041533e994985henrike@webrtc.org // We just linearly map the 0-255 scale of SoundSystemInterface onto 9266a358217004e1580453e46ce99041533e994985henrike@webrtc.org // PA_VOLUME_MUTED-PA_VOLUME_NORM. If the programmer exceeds kMaxVolume then 9366a358217004e1580453e46ce99041533e994985henrike@webrtc.org // they can access the over-100% features of PA. 9466a358217004e1580453e46ce99041533e994985henrike@webrtc.org return PA_VOLUME_MUTED + (PA_VOLUME_NORM - PA_VOLUME_MUTED) * 9566a358217004e1580453e46ce99041533e994985henrike@webrtc.org volume / SoundSystemInterface::kMaxVolume; 9666a358217004e1580453e46ce99041533e994985henrike@webrtc.org} 9766a358217004e1580453e46ce99041533e994985henrike@webrtc.org 9866a358217004e1580453e46ce99041533e994985henrike@webrtc.orgstatic int PulseVolumeToCricketVolume(pa_volume_t pa_volume) { 9966a358217004e1580453e46ce99041533e994985henrike@webrtc.org return SoundSystemInterface::kMinVolume + 10066a358217004e1580453e46ce99041533e994985henrike@webrtc.org (SoundSystemInterface::kMaxVolume - SoundSystemInterface::kMinVolume) * 10166a358217004e1580453e46ce99041533e994985henrike@webrtc.org pa_volume / PA_VOLUME_NORM; 10266a358217004e1580453e46ce99041533e994985henrike@webrtc.org} 10366a358217004e1580453e46ce99041533e994985henrike@webrtc.org 10466a358217004e1580453e46ce99041533e994985henrike@webrtc.orgstatic pa_volume_t MaxChannelVolume(pa_cvolume *channel_volumes) { 10566a358217004e1580453e46ce99041533e994985henrike@webrtc.org pa_volume_t pa_volume = PA_VOLUME_MUTED; // Minimum possible value. 10666a358217004e1580453e46ce99041533e994985henrike@webrtc.org for (int i = 0; i < channel_volumes->channels; ++i) { 10766a358217004e1580453e46ce99041533e994985henrike@webrtc.org if (pa_volume < channel_volumes->values[i]) { 10866a358217004e1580453e46ce99041533e994985henrike@webrtc.org pa_volume = channel_volumes->values[i]; 10966a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 11066a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 11166a358217004e1580453e46ce99041533e994985henrike@webrtc.org return pa_volume; 11266a358217004e1580453e46ce99041533e994985henrike@webrtc.org} 11366a358217004e1580453e46ce99041533e994985henrike@webrtc.org 11466a358217004e1580453e46ce99041533e994985henrike@webrtc.orgclass PulseAudioDeviceLocator : public SoundDeviceLocator { 11566a358217004e1580453e46ce99041533e994985henrike@webrtc.org public: 11666a358217004e1580453e46ce99041533e994985henrike@webrtc.org PulseAudioDeviceLocator(const std::string &name, 11766a358217004e1580453e46ce99041533e994985henrike@webrtc.org const std::string &device_name) 11866a358217004e1580453e46ce99041533e994985henrike@webrtc.org : SoundDeviceLocator(name, device_name) { 11966a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 12066a358217004e1580453e46ce99041533e994985henrike@webrtc.org 12166a358217004e1580453e46ce99041533e994985henrike@webrtc.org virtual SoundDeviceLocator *Copy() const { 12266a358217004e1580453e46ce99041533e994985henrike@webrtc.org return new PulseAudioDeviceLocator(*this); 12366a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 12466a358217004e1580453e46ce99041533e994985henrike@webrtc.org}; 12566a358217004e1580453e46ce99041533e994985henrike@webrtc.org 12666a358217004e1580453e46ce99041533e994985henrike@webrtc.org// Functionality that is common to both PulseAudioInputStream and 12766a358217004e1580453e46ce99041533e994985henrike@webrtc.org// PulseAudioOutputStream. 12866a358217004e1580453e46ce99041533e994985henrike@webrtc.orgclass PulseAudioStream { 12966a358217004e1580453e46ce99041533e994985henrike@webrtc.org public: 13066a358217004e1580453e46ce99041533e994985henrike@webrtc.org PulseAudioStream(PulseAudioSoundSystem *pulse, pa_stream *stream, int flags) 13166a358217004e1580453e46ce99041533e994985henrike@webrtc.org : pulse_(pulse), stream_(stream), flags_(flags) { 13266a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 13366a358217004e1580453e46ce99041533e994985henrike@webrtc.org 13466a358217004e1580453e46ce99041533e994985henrike@webrtc.org ~PulseAudioStream() { 13566a358217004e1580453e46ce99041533e994985henrike@webrtc.org // Close() should have been called during the containing class's destructor. 13666a358217004e1580453e46ce99041533e994985henrike@webrtc.org ASSERT(stream_ == NULL); 13766a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 13866a358217004e1580453e46ce99041533e994985henrike@webrtc.org 13966a358217004e1580453e46ce99041533e994985henrike@webrtc.org // Must be called with the lock held. 14066a358217004e1580453e46ce99041533e994985henrike@webrtc.org bool Close() { 14166a358217004e1580453e46ce99041533e994985henrike@webrtc.org if (!IsClosed()) { 14266a358217004e1580453e46ce99041533e994985henrike@webrtc.org // Unset this here so that we don't get a TERMINATED callback. 14366a358217004e1580453e46ce99041533e994985henrike@webrtc.org symbol_table()->pa_stream_set_state_callback()(stream_, NULL, NULL); 14466a358217004e1580453e46ce99041533e994985henrike@webrtc.org if (symbol_table()->pa_stream_disconnect()(stream_) != 0) { 14566a358217004e1580453e46ce99041533e994985henrike@webrtc.org LOG(LS_ERROR) << "Can't disconnect stream"; 14666a358217004e1580453e46ce99041533e994985henrike@webrtc.org // Continue and return true anyways. 14766a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 14866a358217004e1580453e46ce99041533e994985henrike@webrtc.org symbol_table()->pa_stream_unref()(stream_); 14966a358217004e1580453e46ce99041533e994985henrike@webrtc.org stream_ = NULL; 15066a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 15166a358217004e1580453e46ce99041533e994985henrike@webrtc.org return true; 15266a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 15366a358217004e1580453e46ce99041533e994985henrike@webrtc.org 15466a358217004e1580453e46ce99041533e994985henrike@webrtc.org // Must be called with the lock held. 15566a358217004e1580453e46ce99041533e994985henrike@webrtc.org int LatencyUsecs() { 15666a358217004e1580453e46ce99041533e994985henrike@webrtc.org if (!(flags_ & SoundSystemInterface::FLAG_REPORT_LATENCY)) { 15766a358217004e1580453e46ce99041533e994985henrike@webrtc.org return 0; 15866a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 15966a358217004e1580453e46ce99041533e994985henrike@webrtc.org 16066a358217004e1580453e46ce99041533e994985henrike@webrtc.org pa_usec_t latency; 16166a358217004e1580453e46ce99041533e994985henrike@webrtc.org int negative; 16266a358217004e1580453e46ce99041533e994985henrike@webrtc.org Lock(); 16366a358217004e1580453e46ce99041533e994985henrike@webrtc.org int re = symbol_table()->pa_stream_get_latency()(stream_, &latency, 16466a358217004e1580453e46ce99041533e994985henrike@webrtc.org &negative); 16566a358217004e1580453e46ce99041533e994985henrike@webrtc.org Unlock(); 16666a358217004e1580453e46ce99041533e994985henrike@webrtc.org if (re != 0) { 16766a358217004e1580453e46ce99041533e994985henrike@webrtc.org LOG(LS_ERROR) << "Can't query latency"; 16866a358217004e1580453e46ce99041533e994985henrike@webrtc.org // We'd rather continue playout/capture with an incorrect delay than stop 16966a358217004e1580453e46ce99041533e994985henrike@webrtc.org // it altogether, so return a valid value. 17066a358217004e1580453e46ce99041533e994985henrike@webrtc.org return 0; 17166a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 17266a358217004e1580453e46ce99041533e994985henrike@webrtc.org if (negative) { 17366a358217004e1580453e46ce99041533e994985henrike@webrtc.org // The delay can be negative for monitoring streams if the captured 17466a358217004e1580453e46ce99041533e994985henrike@webrtc.org // samples haven't been played yet. In such a case, "latency" contains the 17566a358217004e1580453e46ce99041533e994985henrike@webrtc.org // magnitude, so we must negate it to get the real value. 17666a358217004e1580453e46ce99041533e994985henrike@webrtc.org return -latency; 17766a358217004e1580453e46ce99041533e994985henrike@webrtc.org } else { 17866a358217004e1580453e46ce99041533e994985henrike@webrtc.org return latency; 17966a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 18066a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 18166a358217004e1580453e46ce99041533e994985henrike@webrtc.org 18266a358217004e1580453e46ce99041533e994985henrike@webrtc.org PulseAudioSoundSystem *pulse() { 18366a358217004e1580453e46ce99041533e994985henrike@webrtc.org return pulse_; 18466a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 18566a358217004e1580453e46ce99041533e994985henrike@webrtc.org 18666a358217004e1580453e46ce99041533e994985henrike@webrtc.org PulseAudioSymbolTable *symbol_table() { 18766a358217004e1580453e46ce99041533e994985henrike@webrtc.org return &pulse()->symbol_table_; 18866a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 18966a358217004e1580453e46ce99041533e994985henrike@webrtc.org 19066a358217004e1580453e46ce99041533e994985henrike@webrtc.org pa_stream *stream() { 19166a358217004e1580453e46ce99041533e994985henrike@webrtc.org ASSERT(stream_ != NULL); 19266a358217004e1580453e46ce99041533e994985henrike@webrtc.org return stream_; 19366a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 19466a358217004e1580453e46ce99041533e994985henrike@webrtc.org 19566a358217004e1580453e46ce99041533e994985henrike@webrtc.org bool IsClosed() { 19666a358217004e1580453e46ce99041533e994985henrike@webrtc.org return stream_ == NULL; 19766a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 19866a358217004e1580453e46ce99041533e994985henrike@webrtc.org 19966a358217004e1580453e46ce99041533e994985henrike@webrtc.org void Lock() { 20066a358217004e1580453e46ce99041533e994985henrike@webrtc.org pulse()->Lock(); 20166a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 20266a358217004e1580453e46ce99041533e994985henrike@webrtc.org 20366a358217004e1580453e46ce99041533e994985henrike@webrtc.org void Unlock() { 20466a358217004e1580453e46ce99041533e994985henrike@webrtc.org pulse()->Unlock(); 20566a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 20666a358217004e1580453e46ce99041533e994985henrike@webrtc.org 20766a358217004e1580453e46ce99041533e994985henrike@webrtc.org private: 20866a358217004e1580453e46ce99041533e994985henrike@webrtc.org PulseAudioSoundSystem *pulse_; 20966a358217004e1580453e46ce99041533e994985henrike@webrtc.org pa_stream *stream_; 21066a358217004e1580453e46ce99041533e994985henrike@webrtc.org int flags_; 21166a358217004e1580453e46ce99041533e994985henrike@webrtc.org 2123c089d751ede283e21e186885eaf705c3257ccd2henrikg RTC_DISALLOW_COPY_AND_ASSIGN(PulseAudioStream); 21366a358217004e1580453e46ce99041533e994985henrike@webrtc.org}; 21466a358217004e1580453e46ce99041533e994985henrike@webrtc.org 21566a358217004e1580453e46ce99041533e994985henrike@webrtc.org// Implementation of an input stream. See soundinputstreaminterface.h regarding 21666a358217004e1580453e46ce99041533e994985henrike@webrtc.org// thread-safety. 21766a358217004e1580453e46ce99041533e994985henrike@webrtc.orgclass PulseAudioInputStream : 21866a358217004e1580453e46ce99041533e994985henrike@webrtc.org public SoundInputStreamInterface, 21966a358217004e1580453e46ce99041533e994985henrike@webrtc.org private rtc::Worker { 22066a358217004e1580453e46ce99041533e994985henrike@webrtc.org public: 22166a358217004e1580453e46ce99041533e994985henrike@webrtc.org PulseAudioInputStream(PulseAudioSoundSystem *pulse, 22266a358217004e1580453e46ce99041533e994985henrike@webrtc.org pa_stream *stream, 22366a358217004e1580453e46ce99041533e994985henrike@webrtc.org int flags) 22466a358217004e1580453e46ce99041533e994985henrike@webrtc.org : stream_(pulse, stream, flags), 22566a358217004e1580453e46ce99041533e994985henrike@webrtc.org temp_sample_data_(NULL), 22666a358217004e1580453e46ce99041533e994985henrike@webrtc.org temp_sample_data_size_(0) { 22766a358217004e1580453e46ce99041533e994985henrike@webrtc.org // This callback seems to never be issued, but let's set it anyways. 22866a358217004e1580453e46ce99041533e994985henrike@webrtc.org symbol_table()->pa_stream_set_overflow_callback()(stream, &OverflowCallback, 22966a358217004e1580453e46ce99041533e994985henrike@webrtc.org NULL); 23066a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 23166a358217004e1580453e46ce99041533e994985henrike@webrtc.org 23266a358217004e1580453e46ce99041533e994985henrike@webrtc.org virtual ~PulseAudioInputStream() { 23366a358217004e1580453e46ce99041533e994985henrike@webrtc.org bool success = Close(); 23466a358217004e1580453e46ce99041533e994985henrike@webrtc.org // We need that to live. 23566a358217004e1580453e46ce99041533e994985henrike@webrtc.org VERIFY(success); 23666a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 23766a358217004e1580453e46ce99041533e994985henrike@webrtc.org 23866a358217004e1580453e46ce99041533e994985henrike@webrtc.org virtual bool StartReading() { 23966a358217004e1580453e46ce99041533e994985henrike@webrtc.org return StartWork(); 24066a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 24166a358217004e1580453e46ce99041533e994985henrike@webrtc.org 24266a358217004e1580453e46ce99041533e994985henrike@webrtc.org virtual bool StopReading() { 24366a358217004e1580453e46ce99041533e994985henrike@webrtc.org return StopWork(); 24466a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 24566a358217004e1580453e46ce99041533e994985henrike@webrtc.org 24666a358217004e1580453e46ce99041533e994985henrike@webrtc.org virtual bool GetVolume(int *volume) { 24766a358217004e1580453e46ce99041533e994985henrike@webrtc.org bool ret = false; 24866a358217004e1580453e46ce99041533e994985henrike@webrtc.org 24966a358217004e1580453e46ce99041533e994985henrike@webrtc.org Lock(); 25066a358217004e1580453e46ce99041533e994985henrike@webrtc.org 25166a358217004e1580453e46ce99041533e994985henrike@webrtc.org // Unlike output streams, input streams have no concept of a stream volume, 25266a358217004e1580453e46ce99041533e994985henrike@webrtc.org // only a device volume. So we have to retrieve the volume of the device 25366a358217004e1580453e46ce99041533e994985henrike@webrtc.org // itself. 25466a358217004e1580453e46ce99041533e994985henrike@webrtc.org 25566a358217004e1580453e46ce99041533e994985henrike@webrtc.org pa_cvolume channel_volumes; 25666a358217004e1580453e46ce99041533e994985henrike@webrtc.org 25766a358217004e1580453e46ce99041533e994985henrike@webrtc.org GetVolumeCallbackData data; 25866a358217004e1580453e46ce99041533e994985henrike@webrtc.org data.instance = this; 25966a358217004e1580453e46ce99041533e994985henrike@webrtc.org data.channel_volumes = &channel_volumes; 26066a358217004e1580453e46ce99041533e994985henrike@webrtc.org 26166a358217004e1580453e46ce99041533e994985henrike@webrtc.org pa_operation *op = symbol_table()->pa_context_get_source_info_by_index()( 26266a358217004e1580453e46ce99041533e994985henrike@webrtc.org stream_.pulse()->context_, 26366a358217004e1580453e46ce99041533e994985henrike@webrtc.org symbol_table()->pa_stream_get_device_index()(stream_.stream()), 26466a358217004e1580453e46ce99041533e994985henrike@webrtc.org &GetVolumeCallbackThunk, 26566a358217004e1580453e46ce99041533e994985henrike@webrtc.org &data); 26666a358217004e1580453e46ce99041533e994985henrike@webrtc.org if (!stream_.pulse()->FinishOperation(op)) { 26766a358217004e1580453e46ce99041533e994985henrike@webrtc.org goto done; 26866a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 26966a358217004e1580453e46ce99041533e994985henrike@webrtc.org 27066a358217004e1580453e46ce99041533e994985henrike@webrtc.org if (data.channel_volumes) { 27166a358217004e1580453e46ce99041533e994985henrike@webrtc.org // This pointer was never unset by the callback, so we must have received 27266a358217004e1580453e46ce99041533e994985henrike@webrtc.org // an empty list of infos. This probably never happens, but we code for it 27366a358217004e1580453e46ce99041533e994985henrike@webrtc.org // anyway. 27466a358217004e1580453e46ce99041533e994985henrike@webrtc.org LOG(LS_ERROR) << "Did not receive GetVolumeCallback"; 27566a358217004e1580453e46ce99041533e994985henrike@webrtc.org goto done; 27666a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 27766a358217004e1580453e46ce99041533e994985henrike@webrtc.org 27866a358217004e1580453e46ce99041533e994985henrike@webrtc.org // We now have the volume for each channel. Each channel could have a 27966a358217004e1580453e46ce99041533e994985henrike@webrtc.org // different volume if, e.g., the user went and changed the volumes in the 28066a358217004e1580453e46ce99041533e994985henrike@webrtc.org // PA UI. To get a single volume for SoundSystemInterface we just take the 28166a358217004e1580453e46ce99041533e994985henrike@webrtc.org // maximum. Ideally we'd do so with pa_cvolume_max, but it doesn't exist in 28266a358217004e1580453e46ce99041533e994985henrike@webrtc.org // Hardy, so we do it manually. 28366a358217004e1580453e46ce99041533e994985henrike@webrtc.org pa_volume_t pa_volume; 28466a358217004e1580453e46ce99041533e994985henrike@webrtc.org pa_volume = MaxChannelVolume(&channel_volumes); 28566a358217004e1580453e46ce99041533e994985henrike@webrtc.org // Now map onto the SoundSystemInterface range. 28666a358217004e1580453e46ce99041533e994985henrike@webrtc.org *volume = PulseVolumeToCricketVolume(pa_volume); 28766a358217004e1580453e46ce99041533e994985henrike@webrtc.org 28866a358217004e1580453e46ce99041533e994985henrike@webrtc.org ret = true; 28966a358217004e1580453e46ce99041533e994985henrike@webrtc.org done: 29066a358217004e1580453e46ce99041533e994985henrike@webrtc.org Unlock(); 29166a358217004e1580453e46ce99041533e994985henrike@webrtc.org return ret; 29266a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 29366a358217004e1580453e46ce99041533e994985henrike@webrtc.org 29466a358217004e1580453e46ce99041533e994985henrike@webrtc.org virtual bool SetVolume(int volume) { 29566a358217004e1580453e46ce99041533e994985henrike@webrtc.org bool ret = false; 29666a358217004e1580453e46ce99041533e994985henrike@webrtc.org pa_volume_t pa_volume = CricketVolumeToPulseVolume(volume); 29766a358217004e1580453e46ce99041533e994985henrike@webrtc.org 29866a358217004e1580453e46ce99041533e994985henrike@webrtc.org Lock(); 29966a358217004e1580453e46ce99041533e994985henrike@webrtc.org 30066a358217004e1580453e46ce99041533e994985henrike@webrtc.org // Unlike output streams, input streams have no concept of a stream volume, 30166a358217004e1580453e46ce99041533e994985henrike@webrtc.org // only a device volume. So we have to change the volume of the device 30266a358217004e1580453e46ce99041533e994985henrike@webrtc.org // itself. 30366a358217004e1580453e46ce99041533e994985henrike@webrtc.org 30466a358217004e1580453e46ce99041533e994985henrike@webrtc.org // The device may have a different number of channels than the stream and 30566a358217004e1580453e46ce99041533e994985henrike@webrtc.org // their mapping may be different, so we don't want to use the channel count 30666a358217004e1580453e46ce99041533e994985henrike@webrtc.org // from our sample spec. We could use PA_CHANNELS_MAX to cover our bases, 30766a358217004e1580453e46ce99041533e994985henrike@webrtc.org // and the server allows that even if the device's channel count is lower, 30866a358217004e1580453e46ce99041533e994985henrike@webrtc.org // but some buggy PA clients don't like that (the pavucontrol on Hardy dies 30966a358217004e1580453e46ce99041533e994985henrike@webrtc.org // in an assert if the channel count is different). So instead we look up 31066a358217004e1580453e46ce99041533e994985henrike@webrtc.org // the actual number of channels that the device has. 31166a358217004e1580453e46ce99041533e994985henrike@webrtc.org 31266a358217004e1580453e46ce99041533e994985henrike@webrtc.org uint8_t channels; 31366a358217004e1580453e46ce99041533e994985henrike@webrtc.org 31466a358217004e1580453e46ce99041533e994985henrike@webrtc.org GetSourceChannelCountCallbackData data; 31566a358217004e1580453e46ce99041533e994985henrike@webrtc.org data.instance = this; 31666a358217004e1580453e46ce99041533e994985henrike@webrtc.org data.channels = &channels; 31766a358217004e1580453e46ce99041533e994985henrike@webrtc.org 31866a358217004e1580453e46ce99041533e994985henrike@webrtc.org uint32_t device_index = symbol_table()->pa_stream_get_device_index()( 31966a358217004e1580453e46ce99041533e994985henrike@webrtc.org stream_.stream()); 32066a358217004e1580453e46ce99041533e994985henrike@webrtc.org 32166a358217004e1580453e46ce99041533e994985henrike@webrtc.org pa_operation *op = symbol_table()->pa_context_get_source_info_by_index()( 32266a358217004e1580453e46ce99041533e994985henrike@webrtc.org stream_.pulse()->context_, 32366a358217004e1580453e46ce99041533e994985henrike@webrtc.org device_index, 32466a358217004e1580453e46ce99041533e994985henrike@webrtc.org &GetSourceChannelCountCallbackThunk, 32566a358217004e1580453e46ce99041533e994985henrike@webrtc.org &data); 32666a358217004e1580453e46ce99041533e994985henrike@webrtc.org if (!stream_.pulse()->FinishOperation(op)) { 32766a358217004e1580453e46ce99041533e994985henrike@webrtc.org goto done; 32866a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 32966a358217004e1580453e46ce99041533e994985henrike@webrtc.org 33066a358217004e1580453e46ce99041533e994985henrike@webrtc.org if (data.channels) { 33166a358217004e1580453e46ce99041533e994985henrike@webrtc.org // This pointer was never unset by the callback, so we must have received 33266a358217004e1580453e46ce99041533e994985henrike@webrtc.org // an empty list of infos. This probably never happens, but we code for it 33366a358217004e1580453e46ce99041533e994985henrike@webrtc.org // anyway. 33466a358217004e1580453e46ce99041533e994985henrike@webrtc.org LOG(LS_ERROR) << "Did not receive GetSourceChannelCountCallback"; 33566a358217004e1580453e46ce99041533e994985henrike@webrtc.org goto done; 33666a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 33766a358217004e1580453e46ce99041533e994985henrike@webrtc.org 33866a358217004e1580453e46ce99041533e994985henrike@webrtc.org pa_cvolume channel_volumes; 33966a358217004e1580453e46ce99041533e994985henrike@webrtc.org symbol_table()->pa_cvolume_set()(&channel_volumes, channels, pa_volume); 34066a358217004e1580453e46ce99041533e994985henrike@webrtc.org 34166a358217004e1580453e46ce99041533e994985henrike@webrtc.org op = symbol_table()->pa_context_set_source_volume_by_index()( 34266a358217004e1580453e46ce99041533e994985henrike@webrtc.org stream_.pulse()->context_, 34366a358217004e1580453e46ce99041533e994985henrike@webrtc.org device_index, 34466a358217004e1580453e46ce99041533e994985henrike@webrtc.org &channel_volumes, 34566a358217004e1580453e46ce99041533e994985henrike@webrtc.org // This callback merely logs errors. 34666a358217004e1580453e46ce99041533e994985henrike@webrtc.org &SetVolumeCallback, 34766a358217004e1580453e46ce99041533e994985henrike@webrtc.org NULL); 34866a358217004e1580453e46ce99041533e994985henrike@webrtc.org if (!op) { 34966a358217004e1580453e46ce99041533e994985henrike@webrtc.org LOG(LS_ERROR) << "pa_context_set_source_volume_by_index()"; 35066a358217004e1580453e46ce99041533e994985henrike@webrtc.org goto done; 35166a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 35266a358217004e1580453e46ce99041533e994985henrike@webrtc.org // Don't need to wait for this to complete. 35366a358217004e1580453e46ce99041533e994985henrike@webrtc.org symbol_table()->pa_operation_unref()(op); 35466a358217004e1580453e46ce99041533e994985henrike@webrtc.org 35566a358217004e1580453e46ce99041533e994985henrike@webrtc.org ret = true; 35666a358217004e1580453e46ce99041533e994985henrike@webrtc.org done: 35766a358217004e1580453e46ce99041533e994985henrike@webrtc.org Unlock(); 35866a358217004e1580453e46ce99041533e994985henrike@webrtc.org return ret; 35966a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 36066a358217004e1580453e46ce99041533e994985henrike@webrtc.org 36166a358217004e1580453e46ce99041533e994985henrike@webrtc.org virtual bool Close() { 36266a358217004e1580453e46ce99041533e994985henrike@webrtc.org if (!StopReading()) { 36366a358217004e1580453e46ce99041533e994985henrike@webrtc.org return false; 36466a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 36566a358217004e1580453e46ce99041533e994985henrike@webrtc.org bool ret = true; 36666a358217004e1580453e46ce99041533e994985henrike@webrtc.org if (!stream_.IsClosed()) { 36766a358217004e1580453e46ce99041533e994985henrike@webrtc.org Lock(); 36866a358217004e1580453e46ce99041533e994985henrike@webrtc.org ret = stream_.Close(); 36966a358217004e1580453e46ce99041533e994985henrike@webrtc.org Unlock(); 37066a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 37166a358217004e1580453e46ce99041533e994985henrike@webrtc.org return ret; 37266a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 37366a358217004e1580453e46ce99041533e994985henrike@webrtc.org 37466a358217004e1580453e46ce99041533e994985henrike@webrtc.org virtual int LatencyUsecs() { 37566a358217004e1580453e46ce99041533e994985henrike@webrtc.org return stream_.LatencyUsecs(); 37666a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 37766a358217004e1580453e46ce99041533e994985henrike@webrtc.org 37866a358217004e1580453e46ce99041533e994985henrike@webrtc.org private: 3790f2e939a92fc1a70a67a9fc141d1f1d006bcded9jbauch struct GetVolumeCallbackData { 3800f2e939a92fc1a70a67a9fc141d1f1d006bcded9jbauch PulseAudioInputStream* instance; 3810f2e939a92fc1a70a67a9fc141d1f1d006bcded9jbauch pa_cvolume* channel_volumes; 3820f2e939a92fc1a70a67a9fc141d1f1d006bcded9jbauch }; 3830f2e939a92fc1a70a67a9fc141d1f1d006bcded9jbauch 3840f2e939a92fc1a70a67a9fc141d1f1d006bcded9jbauch struct GetSourceChannelCountCallbackData { 3850f2e939a92fc1a70a67a9fc141d1f1d006bcded9jbauch PulseAudioInputStream* instance; 3860f2e939a92fc1a70a67a9fc141d1f1d006bcded9jbauch uint8_t* channels; 3870f2e939a92fc1a70a67a9fc141d1f1d006bcded9jbauch }; 3880f2e939a92fc1a70a67a9fc141d1f1d006bcded9jbauch 38966a358217004e1580453e46ce99041533e994985henrike@webrtc.org void Lock() { 39066a358217004e1580453e46ce99041533e994985henrike@webrtc.org stream_.Lock(); 39166a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 39266a358217004e1580453e46ce99041533e994985henrike@webrtc.org 39366a358217004e1580453e46ce99041533e994985henrike@webrtc.org void Unlock() { 39466a358217004e1580453e46ce99041533e994985henrike@webrtc.org stream_.Unlock(); 39566a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 39666a358217004e1580453e46ce99041533e994985henrike@webrtc.org 39766a358217004e1580453e46ce99041533e994985henrike@webrtc.org PulseAudioSymbolTable *symbol_table() { 39866a358217004e1580453e46ce99041533e994985henrike@webrtc.org return stream_.symbol_table(); 39966a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 40066a358217004e1580453e46ce99041533e994985henrike@webrtc.org 40166a358217004e1580453e46ce99041533e994985henrike@webrtc.org void EnableReadCallback() { 40266a358217004e1580453e46ce99041533e994985henrike@webrtc.org symbol_table()->pa_stream_set_read_callback()( 40366a358217004e1580453e46ce99041533e994985henrike@webrtc.org stream_.stream(), 40466a358217004e1580453e46ce99041533e994985henrike@webrtc.org &ReadCallbackThunk, 40566a358217004e1580453e46ce99041533e994985henrike@webrtc.org this); 40666a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 40766a358217004e1580453e46ce99041533e994985henrike@webrtc.org 40866a358217004e1580453e46ce99041533e994985henrike@webrtc.org void DisableReadCallback() { 40966a358217004e1580453e46ce99041533e994985henrike@webrtc.org symbol_table()->pa_stream_set_read_callback()( 41066a358217004e1580453e46ce99041533e994985henrike@webrtc.org stream_.stream(), 41166a358217004e1580453e46ce99041533e994985henrike@webrtc.org NULL, 41266a358217004e1580453e46ce99041533e994985henrike@webrtc.org NULL); 41366a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 41466a358217004e1580453e46ce99041533e994985henrike@webrtc.org 41566a358217004e1580453e46ce99041533e994985henrike@webrtc.org static void ReadCallbackThunk(pa_stream *unused1, 41666a358217004e1580453e46ce99041533e994985henrike@webrtc.org size_t unused2, 41766a358217004e1580453e46ce99041533e994985henrike@webrtc.org void *userdata) { 41866a358217004e1580453e46ce99041533e994985henrike@webrtc.org PulseAudioInputStream *instance = 41966a358217004e1580453e46ce99041533e994985henrike@webrtc.org static_cast<PulseAudioInputStream *>(userdata); 42066a358217004e1580453e46ce99041533e994985henrike@webrtc.org instance->OnReadCallback(); 42166a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 42266a358217004e1580453e46ce99041533e994985henrike@webrtc.org 42366a358217004e1580453e46ce99041533e994985henrike@webrtc.org void OnReadCallback() { 42466a358217004e1580453e46ce99041533e994985henrike@webrtc.org // We get the data pointer and size now in order to save one Lock/Unlock 42566a358217004e1580453e46ce99041533e994985henrike@webrtc.org // on OnMessage. 42666a358217004e1580453e46ce99041533e994985henrike@webrtc.org if (symbol_table()->pa_stream_peek()(stream_.stream(), 42766a358217004e1580453e46ce99041533e994985henrike@webrtc.org &temp_sample_data_, 42866a358217004e1580453e46ce99041533e994985henrike@webrtc.org &temp_sample_data_size_) != 0) { 42966a358217004e1580453e46ce99041533e994985henrike@webrtc.org LOG(LS_ERROR) << "Can't read data!"; 43066a358217004e1580453e46ce99041533e994985henrike@webrtc.org return; 43166a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 43266a358217004e1580453e46ce99041533e994985henrike@webrtc.org // Since we consume the data asynchronously on a different thread, we have 43366a358217004e1580453e46ce99041533e994985henrike@webrtc.org // to temporarily disable the read callback or else Pulse will call it 43466a358217004e1580453e46ce99041533e994985henrike@webrtc.org // continuously until we consume the data. We re-enable it below. 43566a358217004e1580453e46ce99041533e994985henrike@webrtc.org DisableReadCallback(); 43666a358217004e1580453e46ce99041533e994985henrike@webrtc.org HaveWork(); 43766a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 43866a358217004e1580453e46ce99041533e994985henrike@webrtc.org 43966a358217004e1580453e46ce99041533e994985henrike@webrtc.org // Inherited from Worker. 44066a358217004e1580453e46ce99041533e994985henrike@webrtc.org virtual void OnStart() { 44166a358217004e1580453e46ce99041533e994985henrike@webrtc.org Lock(); 44266a358217004e1580453e46ce99041533e994985henrike@webrtc.org EnableReadCallback(); 44366a358217004e1580453e46ce99041533e994985henrike@webrtc.org Unlock(); 44466a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 44566a358217004e1580453e46ce99041533e994985henrike@webrtc.org 44666a358217004e1580453e46ce99041533e994985henrike@webrtc.org // Inherited from Worker. 44766a358217004e1580453e46ce99041533e994985henrike@webrtc.org virtual void OnHaveWork() { 44866a358217004e1580453e46ce99041533e994985henrike@webrtc.org ASSERT(temp_sample_data_ && temp_sample_data_size_); 44966a358217004e1580453e46ce99041533e994985henrike@webrtc.org SignalSamplesRead(temp_sample_data_, 45066a358217004e1580453e46ce99041533e994985henrike@webrtc.org temp_sample_data_size_, 45166a358217004e1580453e46ce99041533e994985henrike@webrtc.org this); 45266a358217004e1580453e46ce99041533e994985henrike@webrtc.org temp_sample_data_ = NULL; 45366a358217004e1580453e46ce99041533e994985henrike@webrtc.org temp_sample_data_size_ = 0; 45466a358217004e1580453e46ce99041533e994985henrike@webrtc.org 45566a358217004e1580453e46ce99041533e994985henrike@webrtc.org Lock(); 45666a358217004e1580453e46ce99041533e994985henrike@webrtc.org for (;;) { 45766a358217004e1580453e46ce99041533e994985henrike@webrtc.org // Ack the last thing we read. 45866a358217004e1580453e46ce99041533e994985henrike@webrtc.org if (symbol_table()->pa_stream_drop()(stream_.stream()) != 0) { 45966a358217004e1580453e46ce99041533e994985henrike@webrtc.org LOG(LS_ERROR) << "Can't ack read data"; 46066a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 46166a358217004e1580453e46ce99041533e994985henrike@webrtc.org 46266a358217004e1580453e46ce99041533e994985henrike@webrtc.org if (symbol_table()->pa_stream_readable_size()(stream_.stream()) <= 0) { 46366a358217004e1580453e46ce99041533e994985henrike@webrtc.org // Then that was all the data. 46466a358217004e1580453e46ce99041533e994985henrike@webrtc.org break; 46566a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 46666a358217004e1580453e46ce99041533e994985henrike@webrtc.org 46766a358217004e1580453e46ce99041533e994985henrike@webrtc.org // Else more data. 46866a358217004e1580453e46ce99041533e994985henrike@webrtc.org const void *sample_data; 46966a358217004e1580453e46ce99041533e994985henrike@webrtc.org size_t sample_data_size; 47066a358217004e1580453e46ce99041533e994985henrike@webrtc.org if (symbol_table()->pa_stream_peek()(stream_.stream(), 47166a358217004e1580453e46ce99041533e994985henrike@webrtc.org &sample_data, 47266a358217004e1580453e46ce99041533e994985henrike@webrtc.org &sample_data_size) != 0) { 47366a358217004e1580453e46ce99041533e994985henrike@webrtc.org LOG(LS_ERROR) << "Can't read data!"; 47466a358217004e1580453e46ce99041533e994985henrike@webrtc.org break; 47566a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 47666a358217004e1580453e46ce99041533e994985henrike@webrtc.org 47766a358217004e1580453e46ce99041533e994985henrike@webrtc.org // Drop lock for sigslot dispatch, which could take a while. 47866a358217004e1580453e46ce99041533e994985henrike@webrtc.org Unlock(); 47966a358217004e1580453e46ce99041533e994985henrike@webrtc.org SignalSamplesRead(sample_data, sample_data_size, this); 48066a358217004e1580453e46ce99041533e994985henrike@webrtc.org Lock(); 48166a358217004e1580453e46ce99041533e994985henrike@webrtc.org 48266a358217004e1580453e46ce99041533e994985henrike@webrtc.org // Return to top of loop for the ack and the check for more data. 48366a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 48466a358217004e1580453e46ce99041533e994985henrike@webrtc.org EnableReadCallback(); 48566a358217004e1580453e46ce99041533e994985henrike@webrtc.org Unlock(); 48666a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 48766a358217004e1580453e46ce99041533e994985henrike@webrtc.org 48866a358217004e1580453e46ce99041533e994985henrike@webrtc.org // Inherited from Worker. 48966a358217004e1580453e46ce99041533e994985henrike@webrtc.org virtual void OnStop() { 49066a358217004e1580453e46ce99041533e994985henrike@webrtc.org Lock(); 49166a358217004e1580453e46ce99041533e994985henrike@webrtc.org DisableReadCallback(); 49266a358217004e1580453e46ce99041533e994985henrike@webrtc.org Unlock(); 49366a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 49466a358217004e1580453e46ce99041533e994985henrike@webrtc.org 49566a358217004e1580453e46ce99041533e994985henrike@webrtc.org static void OverflowCallback(pa_stream *stream, 49666a358217004e1580453e46ce99041533e994985henrike@webrtc.org void *userdata) { 49766a358217004e1580453e46ce99041533e994985henrike@webrtc.org LOG(LS_WARNING) << "Buffer overflow on capture stream " << stream; 49866a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 49966a358217004e1580453e46ce99041533e994985henrike@webrtc.org 50066a358217004e1580453e46ce99041533e994985henrike@webrtc.org static void GetVolumeCallbackThunk(pa_context *unused, 50166a358217004e1580453e46ce99041533e994985henrike@webrtc.org const pa_source_info *info, 50266a358217004e1580453e46ce99041533e994985henrike@webrtc.org int eol, 50366a358217004e1580453e46ce99041533e994985henrike@webrtc.org void *userdata) { 50466a358217004e1580453e46ce99041533e994985henrike@webrtc.org GetVolumeCallbackData *data = 50566a358217004e1580453e46ce99041533e994985henrike@webrtc.org static_cast<GetVolumeCallbackData *>(userdata); 50666a358217004e1580453e46ce99041533e994985henrike@webrtc.org data->instance->OnGetVolumeCallback(info, eol, &data->channel_volumes); 50766a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 50866a358217004e1580453e46ce99041533e994985henrike@webrtc.org 50966a358217004e1580453e46ce99041533e994985henrike@webrtc.org void OnGetVolumeCallback(const pa_source_info *info, 51066a358217004e1580453e46ce99041533e994985henrike@webrtc.org int eol, 51166a358217004e1580453e46ce99041533e994985henrike@webrtc.org pa_cvolume **channel_volumes) { 51266a358217004e1580453e46ce99041533e994985henrike@webrtc.org if (eol) { 51366a358217004e1580453e46ce99041533e994985henrike@webrtc.org // List is over. Wake GetVolume(). 51466a358217004e1580453e46ce99041533e994985henrike@webrtc.org stream_.pulse()->Signal(); 51566a358217004e1580453e46ce99041533e994985henrike@webrtc.org return; 51666a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 51766a358217004e1580453e46ce99041533e994985henrike@webrtc.org 51866a358217004e1580453e46ce99041533e994985henrike@webrtc.org if (*channel_volumes) { 51966a358217004e1580453e46ce99041533e994985henrike@webrtc.org **channel_volumes = info->volume; 52066a358217004e1580453e46ce99041533e994985henrike@webrtc.org // Unset the pointer so that we know that we have have already copied the 52166a358217004e1580453e46ce99041533e994985henrike@webrtc.org // volume. 52266a358217004e1580453e46ce99041533e994985henrike@webrtc.org *channel_volumes = NULL; 52366a358217004e1580453e46ce99041533e994985henrike@webrtc.org } else { 52466a358217004e1580453e46ce99041533e994985henrike@webrtc.org // We have received an additional callback after the first one, which 52566a358217004e1580453e46ce99041533e994985henrike@webrtc.org // doesn't make sense for a single source. This probably never happens, 52666a358217004e1580453e46ce99041533e994985henrike@webrtc.org // but we code for it anyway. 52766a358217004e1580453e46ce99041533e994985henrike@webrtc.org LOG(LS_WARNING) << "Ignoring extra GetVolumeCallback"; 52866a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 52966a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 53066a358217004e1580453e46ce99041533e994985henrike@webrtc.org 53166a358217004e1580453e46ce99041533e994985henrike@webrtc.org static void GetSourceChannelCountCallbackThunk(pa_context *unused, 53266a358217004e1580453e46ce99041533e994985henrike@webrtc.org const pa_source_info *info, 53366a358217004e1580453e46ce99041533e994985henrike@webrtc.org int eol, 53466a358217004e1580453e46ce99041533e994985henrike@webrtc.org void *userdata) { 53566a358217004e1580453e46ce99041533e994985henrike@webrtc.org GetSourceChannelCountCallbackData *data = 53666a358217004e1580453e46ce99041533e994985henrike@webrtc.org static_cast<GetSourceChannelCountCallbackData *>(userdata); 53766a358217004e1580453e46ce99041533e994985henrike@webrtc.org data->instance->OnGetSourceChannelCountCallback(info, eol, &data->channels); 53866a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 53966a358217004e1580453e46ce99041533e994985henrike@webrtc.org 54066a358217004e1580453e46ce99041533e994985henrike@webrtc.org void OnGetSourceChannelCountCallback(const pa_source_info *info, 54166a358217004e1580453e46ce99041533e994985henrike@webrtc.org int eol, 54266a358217004e1580453e46ce99041533e994985henrike@webrtc.org uint8_t **channels) { 54366a358217004e1580453e46ce99041533e994985henrike@webrtc.org if (eol) { 54466a358217004e1580453e46ce99041533e994985henrike@webrtc.org // List is over. Wake SetVolume(). 54566a358217004e1580453e46ce99041533e994985henrike@webrtc.org stream_.pulse()->Signal(); 54666a358217004e1580453e46ce99041533e994985henrike@webrtc.org return; 54766a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 54866a358217004e1580453e46ce99041533e994985henrike@webrtc.org 54966a358217004e1580453e46ce99041533e994985henrike@webrtc.org if (*channels) { 55066a358217004e1580453e46ce99041533e994985henrike@webrtc.org **channels = info->channel_map.channels; 55166a358217004e1580453e46ce99041533e994985henrike@webrtc.org // Unset the pointer so that we know that we have have already copied the 55266a358217004e1580453e46ce99041533e994985henrike@webrtc.org // channel count. 55366a358217004e1580453e46ce99041533e994985henrike@webrtc.org *channels = NULL; 55466a358217004e1580453e46ce99041533e994985henrike@webrtc.org } else { 55566a358217004e1580453e46ce99041533e994985henrike@webrtc.org // We have received an additional callback after the first one, which 55666a358217004e1580453e46ce99041533e994985henrike@webrtc.org // doesn't make sense for a single source. This probably never happens, 55766a358217004e1580453e46ce99041533e994985henrike@webrtc.org // but we code for it anyway. 55866a358217004e1580453e46ce99041533e994985henrike@webrtc.org LOG(LS_WARNING) << "Ignoring extra GetSourceChannelCountCallback"; 55966a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 56066a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 56166a358217004e1580453e46ce99041533e994985henrike@webrtc.org 56266a358217004e1580453e46ce99041533e994985henrike@webrtc.org static void SetVolumeCallback(pa_context *unused1, 56366a358217004e1580453e46ce99041533e994985henrike@webrtc.org int success, 56466a358217004e1580453e46ce99041533e994985henrike@webrtc.org void *unused2) { 56566a358217004e1580453e46ce99041533e994985henrike@webrtc.org if (!success) { 56666a358217004e1580453e46ce99041533e994985henrike@webrtc.org LOG(LS_ERROR) << "Failed to change capture volume"; 56766a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 56866a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 56966a358217004e1580453e46ce99041533e994985henrike@webrtc.org 57066a358217004e1580453e46ce99041533e994985henrike@webrtc.org PulseAudioStream stream_; 57166a358217004e1580453e46ce99041533e994985henrike@webrtc.org // Temporary storage for passing data between threads. 57266a358217004e1580453e46ce99041533e994985henrike@webrtc.org const void *temp_sample_data_; 57366a358217004e1580453e46ce99041533e994985henrike@webrtc.org size_t temp_sample_data_size_; 57466a358217004e1580453e46ce99041533e994985henrike@webrtc.org 5753c089d751ede283e21e186885eaf705c3257ccd2henrikg RTC_DISALLOW_COPY_AND_ASSIGN(PulseAudioInputStream); 57666a358217004e1580453e46ce99041533e994985henrike@webrtc.org}; 57766a358217004e1580453e46ce99041533e994985henrike@webrtc.org 57866a358217004e1580453e46ce99041533e994985henrike@webrtc.org// Implementation of an output stream. See soundoutputstreaminterface.h 57966a358217004e1580453e46ce99041533e994985henrike@webrtc.org// regarding thread-safety. 58066a358217004e1580453e46ce99041533e994985henrike@webrtc.orgclass PulseAudioOutputStream : 58166a358217004e1580453e46ce99041533e994985henrike@webrtc.org public SoundOutputStreamInterface, 58266a358217004e1580453e46ce99041533e994985henrike@webrtc.org private rtc::Worker { 58366a358217004e1580453e46ce99041533e994985henrike@webrtc.org public: 58466a358217004e1580453e46ce99041533e994985henrike@webrtc.org PulseAudioOutputStream(PulseAudioSoundSystem *pulse, 58566a358217004e1580453e46ce99041533e994985henrike@webrtc.org pa_stream *stream, 58666a358217004e1580453e46ce99041533e994985henrike@webrtc.org int flags, 58766a358217004e1580453e46ce99041533e994985henrike@webrtc.org int latency) 58866a358217004e1580453e46ce99041533e994985henrike@webrtc.org : stream_(pulse, stream, flags), 58966a358217004e1580453e46ce99041533e994985henrike@webrtc.org configured_latency_(latency), 59066a358217004e1580453e46ce99041533e994985henrike@webrtc.org temp_buffer_space_(0) { 59166a358217004e1580453e46ce99041533e994985henrike@webrtc.org symbol_table()->pa_stream_set_underflow_callback()(stream, 59266a358217004e1580453e46ce99041533e994985henrike@webrtc.org &UnderflowCallbackThunk, 59366a358217004e1580453e46ce99041533e994985henrike@webrtc.org this); 59466a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 59566a358217004e1580453e46ce99041533e994985henrike@webrtc.org 59666a358217004e1580453e46ce99041533e994985henrike@webrtc.org virtual ~PulseAudioOutputStream() { 59766a358217004e1580453e46ce99041533e994985henrike@webrtc.org bool success = Close(); 59866a358217004e1580453e46ce99041533e994985henrike@webrtc.org // We need that to live. 59966a358217004e1580453e46ce99041533e994985henrike@webrtc.org VERIFY(success); 60066a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 60166a358217004e1580453e46ce99041533e994985henrike@webrtc.org 60266a358217004e1580453e46ce99041533e994985henrike@webrtc.org virtual bool EnableBufferMonitoring() { 60366a358217004e1580453e46ce99041533e994985henrike@webrtc.org return StartWork(); 60466a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 60566a358217004e1580453e46ce99041533e994985henrike@webrtc.org 60666a358217004e1580453e46ce99041533e994985henrike@webrtc.org virtual bool DisableBufferMonitoring() { 60766a358217004e1580453e46ce99041533e994985henrike@webrtc.org return StopWork(); 60866a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 60966a358217004e1580453e46ce99041533e994985henrike@webrtc.org 61066a358217004e1580453e46ce99041533e994985henrike@webrtc.org virtual bool WriteSamples(const void *sample_data, 61166a358217004e1580453e46ce99041533e994985henrike@webrtc.org size_t size) { 61266a358217004e1580453e46ce99041533e994985henrike@webrtc.org bool ret = true; 61366a358217004e1580453e46ce99041533e994985henrike@webrtc.org Lock(); 61466a358217004e1580453e46ce99041533e994985henrike@webrtc.org if (symbol_table()->pa_stream_write()(stream_.stream(), 61566a358217004e1580453e46ce99041533e994985henrike@webrtc.org sample_data, 61666a358217004e1580453e46ce99041533e994985henrike@webrtc.org size, 61766a358217004e1580453e46ce99041533e994985henrike@webrtc.org NULL, 61866a358217004e1580453e46ce99041533e994985henrike@webrtc.org 0, 61966a358217004e1580453e46ce99041533e994985henrike@webrtc.org PA_SEEK_RELATIVE) != 0) { 62066a358217004e1580453e46ce99041533e994985henrike@webrtc.org LOG(LS_ERROR) << "Unable to write"; 62166a358217004e1580453e46ce99041533e994985henrike@webrtc.org ret = false; 62266a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 62366a358217004e1580453e46ce99041533e994985henrike@webrtc.org Unlock(); 62466a358217004e1580453e46ce99041533e994985henrike@webrtc.org return ret; 62566a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 62666a358217004e1580453e46ce99041533e994985henrike@webrtc.org 62766a358217004e1580453e46ce99041533e994985henrike@webrtc.org virtual bool GetVolume(int *volume) { 62866a358217004e1580453e46ce99041533e994985henrike@webrtc.org bool ret = false; 62966a358217004e1580453e46ce99041533e994985henrike@webrtc.org 63066a358217004e1580453e46ce99041533e994985henrike@webrtc.org Lock(); 63166a358217004e1580453e46ce99041533e994985henrike@webrtc.org 63266a358217004e1580453e46ce99041533e994985henrike@webrtc.org pa_cvolume channel_volumes; 63366a358217004e1580453e46ce99041533e994985henrike@webrtc.org 63466a358217004e1580453e46ce99041533e994985henrike@webrtc.org GetVolumeCallbackData data; 63566a358217004e1580453e46ce99041533e994985henrike@webrtc.org data.instance = this; 63666a358217004e1580453e46ce99041533e994985henrike@webrtc.org data.channel_volumes = &channel_volumes; 63766a358217004e1580453e46ce99041533e994985henrike@webrtc.org 63866a358217004e1580453e46ce99041533e994985henrike@webrtc.org pa_operation *op = symbol_table()->pa_context_get_sink_input_info()( 63966a358217004e1580453e46ce99041533e994985henrike@webrtc.org stream_.pulse()->context_, 64066a358217004e1580453e46ce99041533e994985henrike@webrtc.org symbol_table()->pa_stream_get_index()(stream_.stream()), 64166a358217004e1580453e46ce99041533e994985henrike@webrtc.org &GetVolumeCallbackThunk, 64266a358217004e1580453e46ce99041533e994985henrike@webrtc.org &data); 64366a358217004e1580453e46ce99041533e994985henrike@webrtc.org if (!stream_.pulse()->FinishOperation(op)) { 64466a358217004e1580453e46ce99041533e994985henrike@webrtc.org goto done; 64566a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 64666a358217004e1580453e46ce99041533e994985henrike@webrtc.org 64766a358217004e1580453e46ce99041533e994985henrike@webrtc.org if (data.channel_volumes) { 64866a358217004e1580453e46ce99041533e994985henrike@webrtc.org // This pointer was never unset by the callback, so we must have received 64966a358217004e1580453e46ce99041533e994985henrike@webrtc.org // an empty list of infos. This probably never happens, but we code for it 65066a358217004e1580453e46ce99041533e994985henrike@webrtc.org // anyway. 65166a358217004e1580453e46ce99041533e994985henrike@webrtc.org LOG(LS_ERROR) << "Did not receive GetVolumeCallback"; 65266a358217004e1580453e46ce99041533e994985henrike@webrtc.org goto done; 65366a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 65466a358217004e1580453e46ce99041533e994985henrike@webrtc.org 65566a358217004e1580453e46ce99041533e994985henrike@webrtc.org // We now have the volume for each channel. Each channel could have a 65666a358217004e1580453e46ce99041533e994985henrike@webrtc.org // different volume if, e.g., the user went and changed the volumes in the 65766a358217004e1580453e46ce99041533e994985henrike@webrtc.org // PA UI. To get a single volume for SoundSystemInterface we just take the 65866a358217004e1580453e46ce99041533e994985henrike@webrtc.org // maximum. Ideally we'd do so with pa_cvolume_max, but it doesn't exist in 65966a358217004e1580453e46ce99041533e994985henrike@webrtc.org // Hardy, so we do it manually. 66066a358217004e1580453e46ce99041533e994985henrike@webrtc.org pa_volume_t pa_volume; 66166a358217004e1580453e46ce99041533e994985henrike@webrtc.org pa_volume = MaxChannelVolume(&channel_volumes); 66266a358217004e1580453e46ce99041533e994985henrike@webrtc.org // Now map onto the SoundSystemInterface range. 66366a358217004e1580453e46ce99041533e994985henrike@webrtc.org *volume = PulseVolumeToCricketVolume(pa_volume); 66466a358217004e1580453e46ce99041533e994985henrike@webrtc.org 66566a358217004e1580453e46ce99041533e994985henrike@webrtc.org ret = true; 66666a358217004e1580453e46ce99041533e994985henrike@webrtc.org done: 66766a358217004e1580453e46ce99041533e994985henrike@webrtc.org Unlock(); 66866a358217004e1580453e46ce99041533e994985henrike@webrtc.org return ret; 66966a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 67066a358217004e1580453e46ce99041533e994985henrike@webrtc.org 67166a358217004e1580453e46ce99041533e994985henrike@webrtc.org virtual bool SetVolume(int volume) { 67266a358217004e1580453e46ce99041533e994985henrike@webrtc.org bool ret = false; 67366a358217004e1580453e46ce99041533e994985henrike@webrtc.org pa_volume_t pa_volume = CricketVolumeToPulseVolume(volume); 67466a358217004e1580453e46ce99041533e994985henrike@webrtc.org 67566a358217004e1580453e46ce99041533e994985henrike@webrtc.org Lock(); 67666a358217004e1580453e46ce99041533e994985henrike@webrtc.org 67766a358217004e1580453e46ce99041533e994985henrike@webrtc.org const pa_sample_spec *spec = symbol_table()->pa_stream_get_sample_spec()( 67866a358217004e1580453e46ce99041533e994985henrike@webrtc.org stream_.stream()); 67966a358217004e1580453e46ce99041533e994985henrike@webrtc.org if (!spec) { 68066a358217004e1580453e46ce99041533e994985henrike@webrtc.org LOG(LS_ERROR) << "pa_stream_get_sample_spec()"; 68166a358217004e1580453e46ce99041533e994985henrike@webrtc.org goto done; 68266a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 68366a358217004e1580453e46ce99041533e994985henrike@webrtc.org 68466a358217004e1580453e46ce99041533e994985henrike@webrtc.org pa_cvolume channel_volumes; 68566a358217004e1580453e46ce99041533e994985henrike@webrtc.org symbol_table()->pa_cvolume_set()(&channel_volumes, spec->channels, 68666a358217004e1580453e46ce99041533e994985henrike@webrtc.org pa_volume); 68766a358217004e1580453e46ce99041533e994985henrike@webrtc.org 68866a358217004e1580453e46ce99041533e994985henrike@webrtc.org pa_operation *op; 68966a358217004e1580453e46ce99041533e994985henrike@webrtc.org op = symbol_table()->pa_context_set_sink_input_volume()( 69066a358217004e1580453e46ce99041533e994985henrike@webrtc.org stream_.pulse()->context_, 69166a358217004e1580453e46ce99041533e994985henrike@webrtc.org symbol_table()->pa_stream_get_index()(stream_.stream()), 69266a358217004e1580453e46ce99041533e994985henrike@webrtc.org &channel_volumes, 69366a358217004e1580453e46ce99041533e994985henrike@webrtc.org // This callback merely logs errors. 69466a358217004e1580453e46ce99041533e994985henrike@webrtc.org &SetVolumeCallback, 69566a358217004e1580453e46ce99041533e994985henrike@webrtc.org NULL); 69666a358217004e1580453e46ce99041533e994985henrike@webrtc.org if (!op) { 69766a358217004e1580453e46ce99041533e994985henrike@webrtc.org LOG(LS_ERROR) << "pa_context_set_sink_input_volume()"; 69866a358217004e1580453e46ce99041533e994985henrike@webrtc.org goto done; 69966a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 70066a358217004e1580453e46ce99041533e994985henrike@webrtc.org // Don't need to wait for this to complete. 70166a358217004e1580453e46ce99041533e994985henrike@webrtc.org symbol_table()->pa_operation_unref()(op); 70266a358217004e1580453e46ce99041533e994985henrike@webrtc.org 70366a358217004e1580453e46ce99041533e994985henrike@webrtc.org ret = true; 70466a358217004e1580453e46ce99041533e994985henrike@webrtc.org done: 70566a358217004e1580453e46ce99041533e994985henrike@webrtc.org Unlock(); 70666a358217004e1580453e46ce99041533e994985henrike@webrtc.org return ret; 70766a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 70866a358217004e1580453e46ce99041533e994985henrike@webrtc.org 70966a358217004e1580453e46ce99041533e994985henrike@webrtc.org virtual bool Close() { 71066a358217004e1580453e46ce99041533e994985henrike@webrtc.org if (!DisableBufferMonitoring()) { 71166a358217004e1580453e46ce99041533e994985henrike@webrtc.org return false; 71266a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 71366a358217004e1580453e46ce99041533e994985henrike@webrtc.org bool ret = true; 71466a358217004e1580453e46ce99041533e994985henrike@webrtc.org if (!stream_.IsClosed()) { 71566a358217004e1580453e46ce99041533e994985henrike@webrtc.org Lock(); 71666a358217004e1580453e46ce99041533e994985henrike@webrtc.org symbol_table()->pa_stream_set_underflow_callback()(stream_.stream(), 71766a358217004e1580453e46ce99041533e994985henrike@webrtc.org NULL, 71866a358217004e1580453e46ce99041533e994985henrike@webrtc.org NULL); 71966a358217004e1580453e46ce99041533e994985henrike@webrtc.org ret = stream_.Close(); 72066a358217004e1580453e46ce99041533e994985henrike@webrtc.org Unlock(); 72166a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 72266a358217004e1580453e46ce99041533e994985henrike@webrtc.org return ret; 72366a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 72466a358217004e1580453e46ce99041533e994985henrike@webrtc.org 72566a358217004e1580453e46ce99041533e994985henrike@webrtc.org virtual int LatencyUsecs() { 72666a358217004e1580453e46ce99041533e994985henrike@webrtc.org return stream_.LatencyUsecs(); 72766a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 72866a358217004e1580453e46ce99041533e994985henrike@webrtc.org 72966a358217004e1580453e46ce99041533e994985henrike@webrtc.org#if 0 7300f2e939a92fc1a70a67a9fc141d1f1d006bcded9jbauch // TODO(henrika): Versions 0.9.16 and later of Pulse have a new API for 73166a358217004e1580453e46ce99041533e994985henrike@webrtc.org // zero-copy writes, but Hardy is not new enough to have that so we can't 73266a358217004e1580453e46ce99041533e994985henrike@webrtc.org // rely on it. Perhaps auto-detect if it's present or not and use it if we 73366a358217004e1580453e46ce99041533e994985henrike@webrtc.org // can? 73466a358217004e1580453e46ce99041533e994985henrike@webrtc.org 73566a358217004e1580453e46ce99041533e994985henrike@webrtc.org virtual bool GetWriteBuffer(void **buffer, size_t *size) { 73666a358217004e1580453e46ce99041533e994985henrike@webrtc.org bool ret = true; 73766a358217004e1580453e46ce99041533e994985henrike@webrtc.org Lock(); 73866a358217004e1580453e46ce99041533e994985henrike@webrtc.org if (symbol_table()->pa_stream_begin_write()(stream_.stream(), buffer, size) 73966a358217004e1580453e46ce99041533e994985henrike@webrtc.org != 0) { 74066a358217004e1580453e46ce99041533e994985henrike@webrtc.org LOG(LS_ERROR) << "Can't get write buffer"; 74166a358217004e1580453e46ce99041533e994985henrike@webrtc.org ret = false; 74266a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 74366a358217004e1580453e46ce99041533e994985henrike@webrtc.org Unlock(); 74466a358217004e1580453e46ce99041533e994985henrike@webrtc.org return ret; 74566a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 74666a358217004e1580453e46ce99041533e994985henrike@webrtc.org 74766a358217004e1580453e46ce99041533e994985henrike@webrtc.org // Releases the caller's hold on the write buffer. "written" must be the 74866a358217004e1580453e46ce99041533e994985henrike@webrtc.org // amount of data that was written. 74966a358217004e1580453e46ce99041533e994985henrike@webrtc.org virtual bool ReleaseWriteBuffer(void *buffer, size_t written) { 75066a358217004e1580453e46ce99041533e994985henrike@webrtc.org bool ret = true; 75166a358217004e1580453e46ce99041533e994985henrike@webrtc.org Lock(); 75266a358217004e1580453e46ce99041533e994985henrike@webrtc.org if (written == 0) { 75366a358217004e1580453e46ce99041533e994985henrike@webrtc.org if (symbol_table()->pa_stream_cancel_write()(stream_.stream()) != 0) { 75466a358217004e1580453e46ce99041533e994985henrike@webrtc.org LOG(LS_ERROR) << "Can't cancel write"; 75566a358217004e1580453e46ce99041533e994985henrike@webrtc.org ret = false; 75666a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 75766a358217004e1580453e46ce99041533e994985henrike@webrtc.org } else { 75866a358217004e1580453e46ce99041533e994985henrike@webrtc.org if (symbol_table()->pa_stream_write()(stream_.stream(), 75966a358217004e1580453e46ce99041533e994985henrike@webrtc.org buffer, 76066a358217004e1580453e46ce99041533e994985henrike@webrtc.org written, 76166a358217004e1580453e46ce99041533e994985henrike@webrtc.org NULL, 76266a358217004e1580453e46ce99041533e994985henrike@webrtc.org 0, 76366a358217004e1580453e46ce99041533e994985henrike@webrtc.org PA_SEEK_RELATIVE) != 0) { 76466a358217004e1580453e46ce99041533e994985henrike@webrtc.org LOG(LS_ERROR) << "Unable to write"; 76566a358217004e1580453e46ce99041533e994985henrike@webrtc.org ret = false; 76666a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 76766a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 76866a358217004e1580453e46ce99041533e994985henrike@webrtc.org Unlock(); 76966a358217004e1580453e46ce99041533e994985henrike@webrtc.org return ret; 77066a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 77166a358217004e1580453e46ce99041533e994985henrike@webrtc.org#endif 77266a358217004e1580453e46ce99041533e994985henrike@webrtc.org 77366a358217004e1580453e46ce99041533e994985henrike@webrtc.org private: 7740f2e939a92fc1a70a67a9fc141d1f1d006bcded9jbauch struct GetVolumeCallbackData { 7750f2e939a92fc1a70a67a9fc141d1f1d006bcded9jbauch PulseAudioOutputStream* instance; 7760f2e939a92fc1a70a67a9fc141d1f1d006bcded9jbauch pa_cvolume* channel_volumes; 7770f2e939a92fc1a70a67a9fc141d1f1d006bcded9jbauch }; 7780f2e939a92fc1a70a67a9fc141d1f1d006bcded9jbauch 77966a358217004e1580453e46ce99041533e994985henrike@webrtc.org void Lock() { 78066a358217004e1580453e46ce99041533e994985henrike@webrtc.org stream_.Lock(); 78166a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 78266a358217004e1580453e46ce99041533e994985henrike@webrtc.org 78366a358217004e1580453e46ce99041533e994985henrike@webrtc.org void Unlock() { 78466a358217004e1580453e46ce99041533e994985henrike@webrtc.org stream_.Unlock(); 78566a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 78666a358217004e1580453e46ce99041533e994985henrike@webrtc.org 78766a358217004e1580453e46ce99041533e994985henrike@webrtc.org PulseAudioSymbolTable *symbol_table() { 78866a358217004e1580453e46ce99041533e994985henrike@webrtc.org return stream_.symbol_table(); 78966a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 79066a358217004e1580453e46ce99041533e994985henrike@webrtc.org 79166a358217004e1580453e46ce99041533e994985henrike@webrtc.org void EnableWriteCallback() { 79266a358217004e1580453e46ce99041533e994985henrike@webrtc.org pa_stream_state_t state = symbol_table()->pa_stream_get_state()( 79366a358217004e1580453e46ce99041533e994985henrike@webrtc.org stream_.stream()); 79466a358217004e1580453e46ce99041533e994985henrike@webrtc.org if (state == PA_STREAM_READY) { 79566a358217004e1580453e46ce99041533e994985henrike@webrtc.org // May already have available space. Must check. 79666a358217004e1580453e46ce99041533e994985henrike@webrtc.org temp_buffer_space_ = symbol_table()->pa_stream_writable_size()( 79766a358217004e1580453e46ce99041533e994985henrike@webrtc.org stream_.stream()); 79866a358217004e1580453e46ce99041533e994985henrike@webrtc.org if (temp_buffer_space_ > 0) { 79966a358217004e1580453e46ce99041533e994985henrike@webrtc.org // Yup, there is already space available, so if we register a write 80066a358217004e1580453e46ce99041533e994985henrike@webrtc.org // callback then it will not receive any event. So dispatch one ourself 80166a358217004e1580453e46ce99041533e994985henrike@webrtc.org // instead. 80266a358217004e1580453e46ce99041533e994985henrike@webrtc.org HaveWork(); 80366a358217004e1580453e46ce99041533e994985henrike@webrtc.org return; 80466a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 80566a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 80666a358217004e1580453e46ce99041533e994985henrike@webrtc.org symbol_table()->pa_stream_set_write_callback()( 80766a358217004e1580453e46ce99041533e994985henrike@webrtc.org stream_.stream(), 80866a358217004e1580453e46ce99041533e994985henrike@webrtc.org &WriteCallbackThunk, 80966a358217004e1580453e46ce99041533e994985henrike@webrtc.org this); 81066a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 81166a358217004e1580453e46ce99041533e994985henrike@webrtc.org 81266a358217004e1580453e46ce99041533e994985henrike@webrtc.org void DisableWriteCallback() { 81366a358217004e1580453e46ce99041533e994985henrike@webrtc.org symbol_table()->pa_stream_set_write_callback()( 81466a358217004e1580453e46ce99041533e994985henrike@webrtc.org stream_.stream(), 81566a358217004e1580453e46ce99041533e994985henrike@webrtc.org NULL, 81666a358217004e1580453e46ce99041533e994985henrike@webrtc.org NULL); 81766a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 81866a358217004e1580453e46ce99041533e994985henrike@webrtc.org 81966a358217004e1580453e46ce99041533e994985henrike@webrtc.org static void WriteCallbackThunk(pa_stream *unused, 82066a358217004e1580453e46ce99041533e994985henrike@webrtc.org size_t buffer_space, 82166a358217004e1580453e46ce99041533e994985henrike@webrtc.org void *userdata) { 82266a358217004e1580453e46ce99041533e994985henrike@webrtc.org PulseAudioOutputStream *instance = 82366a358217004e1580453e46ce99041533e994985henrike@webrtc.org static_cast<PulseAudioOutputStream *>(userdata); 82466a358217004e1580453e46ce99041533e994985henrike@webrtc.org instance->OnWriteCallback(buffer_space); 82566a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 82666a358217004e1580453e46ce99041533e994985henrike@webrtc.org 82766a358217004e1580453e46ce99041533e994985henrike@webrtc.org void OnWriteCallback(size_t buffer_space) { 82866a358217004e1580453e46ce99041533e994985henrike@webrtc.org temp_buffer_space_ = buffer_space; 82966a358217004e1580453e46ce99041533e994985henrike@webrtc.org // Since we write the data asynchronously on a different thread, we have 83066a358217004e1580453e46ce99041533e994985henrike@webrtc.org // to temporarily disable the write callback or else Pulse will call it 83166a358217004e1580453e46ce99041533e994985henrike@webrtc.org // continuously until we write the data. We re-enable it below. 83266a358217004e1580453e46ce99041533e994985henrike@webrtc.org DisableWriteCallback(); 83366a358217004e1580453e46ce99041533e994985henrike@webrtc.org HaveWork(); 83466a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 83566a358217004e1580453e46ce99041533e994985henrike@webrtc.org 83666a358217004e1580453e46ce99041533e994985henrike@webrtc.org // Inherited from Worker. 83766a358217004e1580453e46ce99041533e994985henrike@webrtc.org virtual void OnStart() { 83866a358217004e1580453e46ce99041533e994985henrike@webrtc.org Lock(); 83966a358217004e1580453e46ce99041533e994985henrike@webrtc.org EnableWriteCallback(); 84066a358217004e1580453e46ce99041533e994985henrike@webrtc.org Unlock(); 84166a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 84266a358217004e1580453e46ce99041533e994985henrike@webrtc.org 84366a358217004e1580453e46ce99041533e994985henrike@webrtc.org // Inherited from Worker. 84466a358217004e1580453e46ce99041533e994985henrike@webrtc.org virtual void OnHaveWork() { 84566a358217004e1580453e46ce99041533e994985henrike@webrtc.org ASSERT(temp_buffer_space_ > 0); 84666a358217004e1580453e46ce99041533e994985henrike@webrtc.org 84766a358217004e1580453e46ce99041533e994985henrike@webrtc.org SignalBufferSpace(temp_buffer_space_, this); 84866a358217004e1580453e46ce99041533e994985henrike@webrtc.org 84966a358217004e1580453e46ce99041533e994985henrike@webrtc.org temp_buffer_space_ = 0; 85066a358217004e1580453e46ce99041533e994985henrike@webrtc.org Lock(); 85166a358217004e1580453e46ce99041533e994985henrike@webrtc.org EnableWriteCallback(); 85266a358217004e1580453e46ce99041533e994985henrike@webrtc.org Unlock(); 85366a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 85466a358217004e1580453e46ce99041533e994985henrike@webrtc.org 85566a358217004e1580453e46ce99041533e994985henrike@webrtc.org // Inherited from Worker. 85666a358217004e1580453e46ce99041533e994985henrike@webrtc.org virtual void OnStop() { 85766a358217004e1580453e46ce99041533e994985henrike@webrtc.org Lock(); 85866a358217004e1580453e46ce99041533e994985henrike@webrtc.org DisableWriteCallback(); 85966a358217004e1580453e46ce99041533e994985henrike@webrtc.org Unlock(); 86066a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 86166a358217004e1580453e46ce99041533e994985henrike@webrtc.org 86266a358217004e1580453e46ce99041533e994985henrike@webrtc.org static void UnderflowCallbackThunk(pa_stream *unused, 86366a358217004e1580453e46ce99041533e994985henrike@webrtc.org void *userdata) { 86466a358217004e1580453e46ce99041533e994985henrike@webrtc.org PulseAudioOutputStream *instance = 86566a358217004e1580453e46ce99041533e994985henrike@webrtc.org static_cast<PulseAudioOutputStream *>(userdata); 86666a358217004e1580453e46ce99041533e994985henrike@webrtc.org instance->OnUnderflowCallback(); 86766a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 86866a358217004e1580453e46ce99041533e994985henrike@webrtc.org 86966a358217004e1580453e46ce99041533e994985henrike@webrtc.org void OnUnderflowCallback() { 87066a358217004e1580453e46ce99041533e994985henrike@webrtc.org LOG(LS_WARNING) << "Buffer underflow on playback stream " 87166a358217004e1580453e46ce99041533e994985henrike@webrtc.org << stream_.stream(); 87266a358217004e1580453e46ce99041533e994985henrike@webrtc.org 87366a358217004e1580453e46ce99041533e994985henrike@webrtc.org if (configured_latency_ == SoundSystemInterface::kNoLatencyRequirements) { 87466a358217004e1580453e46ce99041533e994985henrike@webrtc.org // We didn't configure a pa_buffer_attr before, so switching to one now 87566a358217004e1580453e46ce99041533e994985henrike@webrtc.org // would be questionable. 87666a358217004e1580453e46ce99041533e994985henrike@webrtc.org return; 87766a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 87866a358217004e1580453e46ce99041533e994985henrike@webrtc.org 87966a358217004e1580453e46ce99041533e994985henrike@webrtc.org // Otherwise reconfigure the stream with a higher target latency. 88066a358217004e1580453e46ce99041533e994985henrike@webrtc.org 88166a358217004e1580453e46ce99041533e994985henrike@webrtc.org const pa_sample_spec *spec = symbol_table()->pa_stream_get_sample_spec()( 88266a358217004e1580453e46ce99041533e994985henrike@webrtc.org stream_.stream()); 88366a358217004e1580453e46ce99041533e994985henrike@webrtc.org if (!spec) { 88466a358217004e1580453e46ce99041533e994985henrike@webrtc.org LOG(LS_ERROR) << "pa_stream_get_sample_spec()"; 88566a358217004e1580453e46ce99041533e994985henrike@webrtc.org return; 88666a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 88766a358217004e1580453e46ce99041533e994985henrike@webrtc.org 88866a358217004e1580453e46ce99041533e994985henrike@webrtc.org size_t bytes_per_sec = symbol_table()->pa_bytes_per_second()(spec); 88966a358217004e1580453e46ce99041533e994985henrike@webrtc.org 89066a358217004e1580453e46ce99041533e994985henrike@webrtc.org int new_latency = configured_latency_ + 89166a358217004e1580453e46ce99041533e994985henrike@webrtc.org bytes_per_sec * kPlaybackLatencyIncrementMsecs / 89266a358217004e1580453e46ce99041533e994985henrike@webrtc.org rtc::kNumMicrosecsPerSec; 89366a358217004e1580453e46ce99041533e994985henrike@webrtc.org 89466a358217004e1580453e46ce99041533e994985henrike@webrtc.org pa_buffer_attr new_attr = {0}; 89566a358217004e1580453e46ce99041533e994985henrike@webrtc.org FillPlaybackBufferAttr(new_latency, &new_attr); 89666a358217004e1580453e46ce99041533e994985henrike@webrtc.org 89766a358217004e1580453e46ce99041533e994985henrike@webrtc.org pa_operation *op = symbol_table()->pa_stream_set_buffer_attr()( 89866a358217004e1580453e46ce99041533e994985henrike@webrtc.org stream_.stream(), 89966a358217004e1580453e46ce99041533e994985henrike@webrtc.org &new_attr, 90066a358217004e1580453e46ce99041533e994985henrike@webrtc.org // No callback. 90166a358217004e1580453e46ce99041533e994985henrike@webrtc.org NULL, 90266a358217004e1580453e46ce99041533e994985henrike@webrtc.org NULL); 90366a358217004e1580453e46ce99041533e994985henrike@webrtc.org if (!op) { 90466a358217004e1580453e46ce99041533e994985henrike@webrtc.org LOG(LS_ERROR) << "pa_stream_set_buffer_attr()"; 90566a358217004e1580453e46ce99041533e994985henrike@webrtc.org return; 90666a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 90766a358217004e1580453e46ce99041533e994985henrike@webrtc.org // Don't need to wait for this to complete. 90866a358217004e1580453e46ce99041533e994985henrike@webrtc.org symbol_table()->pa_operation_unref()(op); 90966a358217004e1580453e46ce99041533e994985henrike@webrtc.org 91066a358217004e1580453e46ce99041533e994985henrike@webrtc.org // Save the new latency in case we underflow again. 91166a358217004e1580453e46ce99041533e994985henrike@webrtc.org configured_latency_ = new_latency; 91266a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 91366a358217004e1580453e46ce99041533e994985henrike@webrtc.org 91466a358217004e1580453e46ce99041533e994985henrike@webrtc.org static void GetVolumeCallbackThunk(pa_context *unused, 91566a358217004e1580453e46ce99041533e994985henrike@webrtc.org const pa_sink_input_info *info, 91666a358217004e1580453e46ce99041533e994985henrike@webrtc.org int eol, 91766a358217004e1580453e46ce99041533e994985henrike@webrtc.org void *userdata) { 91866a358217004e1580453e46ce99041533e994985henrike@webrtc.org GetVolumeCallbackData *data = 91966a358217004e1580453e46ce99041533e994985henrike@webrtc.org static_cast<GetVolumeCallbackData *>(userdata); 92066a358217004e1580453e46ce99041533e994985henrike@webrtc.org data->instance->OnGetVolumeCallback(info, eol, &data->channel_volumes); 92166a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 92266a358217004e1580453e46ce99041533e994985henrike@webrtc.org 92366a358217004e1580453e46ce99041533e994985henrike@webrtc.org void OnGetVolumeCallback(const pa_sink_input_info *info, 92466a358217004e1580453e46ce99041533e994985henrike@webrtc.org int eol, 92566a358217004e1580453e46ce99041533e994985henrike@webrtc.org pa_cvolume **channel_volumes) { 92666a358217004e1580453e46ce99041533e994985henrike@webrtc.org if (eol) { 92766a358217004e1580453e46ce99041533e994985henrike@webrtc.org // List is over. Wake GetVolume(). 92866a358217004e1580453e46ce99041533e994985henrike@webrtc.org stream_.pulse()->Signal(); 92966a358217004e1580453e46ce99041533e994985henrike@webrtc.org return; 93066a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 93166a358217004e1580453e46ce99041533e994985henrike@webrtc.org 93266a358217004e1580453e46ce99041533e994985henrike@webrtc.org if (*channel_volumes) { 93366a358217004e1580453e46ce99041533e994985henrike@webrtc.org **channel_volumes = info->volume; 93466a358217004e1580453e46ce99041533e994985henrike@webrtc.org // Unset the pointer so that we know that we have have already copied the 93566a358217004e1580453e46ce99041533e994985henrike@webrtc.org // volume. 93666a358217004e1580453e46ce99041533e994985henrike@webrtc.org *channel_volumes = NULL; 93766a358217004e1580453e46ce99041533e994985henrike@webrtc.org } else { 93866a358217004e1580453e46ce99041533e994985henrike@webrtc.org // We have received an additional callback after the first one, which 93966a358217004e1580453e46ce99041533e994985henrike@webrtc.org // doesn't make sense for a single sink input. This probably never 94066a358217004e1580453e46ce99041533e994985henrike@webrtc.org // happens, but we code for it anyway. 94166a358217004e1580453e46ce99041533e994985henrike@webrtc.org LOG(LS_WARNING) << "Ignoring extra GetVolumeCallback"; 94266a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 94366a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 94466a358217004e1580453e46ce99041533e994985henrike@webrtc.org 94566a358217004e1580453e46ce99041533e994985henrike@webrtc.org static void SetVolumeCallback(pa_context *unused1, 94666a358217004e1580453e46ce99041533e994985henrike@webrtc.org int success, 94766a358217004e1580453e46ce99041533e994985henrike@webrtc.org void *unused2) { 94866a358217004e1580453e46ce99041533e994985henrike@webrtc.org if (!success) { 94966a358217004e1580453e46ce99041533e994985henrike@webrtc.org LOG(LS_ERROR) << "Failed to change playback volume"; 95066a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 95166a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 95266a358217004e1580453e46ce99041533e994985henrike@webrtc.org 95366a358217004e1580453e46ce99041533e994985henrike@webrtc.org PulseAudioStream stream_; 95466a358217004e1580453e46ce99041533e994985henrike@webrtc.org int configured_latency_; 95566a358217004e1580453e46ce99041533e994985henrike@webrtc.org // Temporary storage for passing data between threads. 95666a358217004e1580453e46ce99041533e994985henrike@webrtc.org size_t temp_buffer_space_; 95766a358217004e1580453e46ce99041533e994985henrike@webrtc.org 9583c089d751ede283e21e186885eaf705c3257ccd2henrikg RTC_DISALLOW_COPY_AND_ASSIGN(PulseAudioOutputStream); 95966a358217004e1580453e46ce99041533e994985henrike@webrtc.org}; 96066a358217004e1580453e46ce99041533e994985henrike@webrtc.org 96166a358217004e1580453e46ce99041533e994985henrike@webrtc.orgPulseAudioSoundSystem::PulseAudioSoundSystem() 96266a358217004e1580453e46ce99041533e994985henrike@webrtc.org : mainloop_(NULL), context_(NULL) { 96366a358217004e1580453e46ce99041533e994985henrike@webrtc.org} 96466a358217004e1580453e46ce99041533e994985henrike@webrtc.org 96566a358217004e1580453e46ce99041533e994985henrike@webrtc.orgPulseAudioSoundSystem::~PulseAudioSoundSystem() { 96666a358217004e1580453e46ce99041533e994985henrike@webrtc.org Terminate(); 96766a358217004e1580453e46ce99041533e994985henrike@webrtc.org} 96866a358217004e1580453e46ce99041533e994985henrike@webrtc.org 96966a358217004e1580453e46ce99041533e994985henrike@webrtc.orgbool PulseAudioSoundSystem::Init() { 97066a358217004e1580453e46ce99041533e994985henrike@webrtc.org if (IsInitialized()) { 97166a358217004e1580453e46ce99041533e994985henrike@webrtc.org return true; 97266a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 97366a358217004e1580453e46ce99041533e994985henrike@webrtc.org 97466a358217004e1580453e46ce99041533e994985henrike@webrtc.org // Load libpulse. 97566a358217004e1580453e46ce99041533e994985henrike@webrtc.org if (!symbol_table_.Load()) { 97666a358217004e1580453e46ce99041533e994985henrike@webrtc.org // Most likely the Pulse library and sound server are not installed on 97766a358217004e1580453e46ce99041533e994985henrike@webrtc.org // this system. 97866a358217004e1580453e46ce99041533e994985henrike@webrtc.org LOG(LS_WARNING) << "Failed to load symbol table"; 97966a358217004e1580453e46ce99041533e994985henrike@webrtc.org return false; 98066a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 98166a358217004e1580453e46ce99041533e994985henrike@webrtc.org 98266a358217004e1580453e46ce99041533e994985henrike@webrtc.org // Now create and start the Pulse event thread. 98366a358217004e1580453e46ce99041533e994985henrike@webrtc.org mainloop_ = symbol_table_.pa_threaded_mainloop_new()(); 98466a358217004e1580453e46ce99041533e994985henrike@webrtc.org if (!mainloop_) { 98566a358217004e1580453e46ce99041533e994985henrike@webrtc.org LOG(LS_ERROR) << "Can't create mainloop"; 98666a358217004e1580453e46ce99041533e994985henrike@webrtc.org goto fail0; 98766a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 98866a358217004e1580453e46ce99041533e994985henrike@webrtc.org 98966a358217004e1580453e46ce99041533e994985henrike@webrtc.org if (symbol_table_.pa_threaded_mainloop_start()(mainloop_) != 0) { 99066a358217004e1580453e46ce99041533e994985henrike@webrtc.org LOG(LS_ERROR) << "Can't start mainloop"; 99166a358217004e1580453e46ce99041533e994985henrike@webrtc.org goto fail1; 99266a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 99366a358217004e1580453e46ce99041533e994985henrike@webrtc.org 99466a358217004e1580453e46ce99041533e994985henrike@webrtc.org Lock(); 99566a358217004e1580453e46ce99041533e994985henrike@webrtc.org context_ = CreateNewConnection(); 99666a358217004e1580453e46ce99041533e994985henrike@webrtc.org Unlock(); 99766a358217004e1580453e46ce99041533e994985henrike@webrtc.org 99866a358217004e1580453e46ce99041533e994985henrike@webrtc.org if (!context_) { 99966a358217004e1580453e46ce99041533e994985henrike@webrtc.org goto fail2; 100066a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 100166a358217004e1580453e46ce99041533e994985henrike@webrtc.org 100266a358217004e1580453e46ce99041533e994985henrike@webrtc.org // Otherwise we're now ready! 100366a358217004e1580453e46ce99041533e994985henrike@webrtc.org return true; 100466a358217004e1580453e46ce99041533e994985henrike@webrtc.org 100566a358217004e1580453e46ce99041533e994985henrike@webrtc.org fail2: 100666a358217004e1580453e46ce99041533e994985henrike@webrtc.org symbol_table_.pa_threaded_mainloop_stop()(mainloop_); 100766a358217004e1580453e46ce99041533e994985henrike@webrtc.org fail1: 100866a358217004e1580453e46ce99041533e994985henrike@webrtc.org symbol_table_.pa_threaded_mainloop_free()(mainloop_); 100966a358217004e1580453e46ce99041533e994985henrike@webrtc.org mainloop_ = NULL; 101066a358217004e1580453e46ce99041533e994985henrike@webrtc.org fail0: 101166a358217004e1580453e46ce99041533e994985henrike@webrtc.org return false; 101266a358217004e1580453e46ce99041533e994985henrike@webrtc.org} 101366a358217004e1580453e46ce99041533e994985henrike@webrtc.org 101466a358217004e1580453e46ce99041533e994985henrike@webrtc.orgvoid PulseAudioSoundSystem::Terminate() { 101566a358217004e1580453e46ce99041533e994985henrike@webrtc.org if (!IsInitialized()) { 101666a358217004e1580453e46ce99041533e994985henrike@webrtc.org return; 101766a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 101866a358217004e1580453e46ce99041533e994985henrike@webrtc.org 101966a358217004e1580453e46ce99041533e994985henrike@webrtc.org Lock(); 102066a358217004e1580453e46ce99041533e994985henrike@webrtc.org symbol_table_.pa_context_disconnect()(context_); 102166a358217004e1580453e46ce99041533e994985henrike@webrtc.org symbol_table_.pa_context_unref()(context_); 102266a358217004e1580453e46ce99041533e994985henrike@webrtc.org Unlock(); 102366a358217004e1580453e46ce99041533e994985henrike@webrtc.org context_ = NULL; 102466a358217004e1580453e46ce99041533e994985henrike@webrtc.org symbol_table_.pa_threaded_mainloop_stop()(mainloop_); 102566a358217004e1580453e46ce99041533e994985henrike@webrtc.org symbol_table_.pa_threaded_mainloop_free()(mainloop_); 102666a358217004e1580453e46ce99041533e994985henrike@webrtc.org mainloop_ = NULL; 102766a358217004e1580453e46ce99041533e994985henrike@webrtc.org 102866a358217004e1580453e46ce99041533e994985henrike@webrtc.org // We do not unload the symbol table because we may need it again soon if 102966a358217004e1580453e46ce99041533e994985henrike@webrtc.org // Init() is called again. 103066a358217004e1580453e46ce99041533e994985henrike@webrtc.org} 103166a358217004e1580453e46ce99041533e994985henrike@webrtc.org 103266a358217004e1580453e46ce99041533e994985henrike@webrtc.orgbool PulseAudioSoundSystem::EnumeratePlaybackDevices( 103366a358217004e1580453e46ce99041533e994985henrike@webrtc.org SoundDeviceLocatorList *devices) { 103466a358217004e1580453e46ce99041533e994985henrike@webrtc.org return EnumerateDevices<pa_sink_info>( 103566a358217004e1580453e46ce99041533e994985henrike@webrtc.org devices, 103666a358217004e1580453e46ce99041533e994985henrike@webrtc.org symbol_table_.pa_context_get_sink_info_list(), 103766a358217004e1580453e46ce99041533e994985henrike@webrtc.org &EnumeratePlaybackDevicesCallbackThunk); 103866a358217004e1580453e46ce99041533e994985henrike@webrtc.org} 103966a358217004e1580453e46ce99041533e994985henrike@webrtc.org 104066a358217004e1580453e46ce99041533e994985henrike@webrtc.orgbool PulseAudioSoundSystem::EnumerateCaptureDevices( 104166a358217004e1580453e46ce99041533e994985henrike@webrtc.org SoundDeviceLocatorList *devices) { 104266a358217004e1580453e46ce99041533e994985henrike@webrtc.org return EnumerateDevices<pa_source_info>( 104366a358217004e1580453e46ce99041533e994985henrike@webrtc.org devices, 104466a358217004e1580453e46ce99041533e994985henrike@webrtc.org symbol_table_.pa_context_get_source_info_list(), 104566a358217004e1580453e46ce99041533e994985henrike@webrtc.org &EnumerateCaptureDevicesCallbackThunk); 104666a358217004e1580453e46ce99041533e994985henrike@webrtc.org} 104766a358217004e1580453e46ce99041533e994985henrike@webrtc.org 104866a358217004e1580453e46ce99041533e994985henrike@webrtc.orgbool PulseAudioSoundSystem::GetDefaultPlaybackDevice( 104966a358217004e1580453e46ce99041533e994985henrike@webrtc.org SoundDeviceLocator **device) { 105066a358217004e1580453e46ce99041533e994985henrike@webrtc.org return GetDefaultDevice<&pa_server_info::default_sink_name>(device); 105166a358217004e1580453e46ce99041533e994985henrike@webrtc.org} 105266a358217004e1580453e46ce99041533e994985henrike@webrtc.org 105366a358217004e1580453e46ce99041533e994985henrike@webrtc.orgbool PulseAudioSoundSystem::GetDefaultCaptureDevice( 105466a358217004e1580453e46ce99041533e994985henrike@webrtc.org SoundDeviceLocator **device) { 105566a358217004e1580453e46ce99041533e994985henrike@webrtc.org return GetDefaultDevice<&pa_server_info::default_source_name>(device); 105666a358217004e1580453e46ce99041533e994985henrike@webrtc.org} 105766a358217004e1580453e46ce99041533e994985henrike@webrtc.org 105866a358217004e1580453e46ce99041533e994985henrike@webrtc.orgSoundOutputStreamInterface *PulseAudioSoundSystem::OpenPlaybackDevice( 105966a358217004e1580453e46ce99041533e994985henrike@webrtc.org const SoundDeviceLocator *device, 106066a358217004e1580453e46ce99041533e994985henrike@webrtc.org const OpenParams ¶ms) { 106166a358217004e1580453e46ce99041533e994985henrike@webrtc.org return OpenDevice<SoundOutputStreamInterface>( 106266a358217004e1580453e46ce99041533e994985henrike@webrtc.org device, 106366a358217004e1580453e46ce99041533e994985henrike@webrtc.org params, 106466a358217004e1580453e46ce99041533e994985henrike@webrtc.org "Playback", 106566a358217004e1580453e46ce99041533e994985henrike@webrtc.org &PulseAudioSoundSystem::ConnectOutputStream); 106666a358217004e1580453e46ce99041533e994985henrike@webrtc.org} 106766a358217004e1580453e46ce99041533e994985henrike@webrtc.org 106866a358217004e1580453e46ce99041533e994985henrike@webrtc.orgSoundInputStreamInterface *PulseAudioSoundSystem::OpenCaptureDevice( 106966a358217004e1580453e46ce99041533e994985henrike@webrtc.org const SoundDeviceLocator *device, 107066a358217004e1580453e46ce99041533e994985henrike@webrtc.org const OpenParams ¶ms) { 107166a358217004e1580453e46ce99041533e994985henrike@webrtc.org return OpenDevice<SoundInputStreamInterface>( 107266a358217004e1580453e46ce99041533e994985henrike@webrtc.org device, 107366a358217004e1580453e46ce99041533e994985henrike@webrtc.org params, 107466a358217004e1580453e46ce99041533e994985henrike@webrtc.org "Capture", 107566a358217004e1580453e46ce99041533e994985henrike@webrtc.org &PulseAudioSoundSystem::ConnectInputStream); 107666a358217004e1580453e46ce99041533e994985henrike@webrtc.org} 107766a358217004e1580453e46ce99041533e994985henrike@webrtc.org 107866a358217004e1580453e46ce99041533e994985henrike@webrtc.orgconst char *PulseAudioSoundSystem::GetName() const { 107966a358217004e1580453e46ce99041533e994985henrike@webrtc.org return "PulseAudio"; 108066a358217004e1580453e46ce99041533e994985henrike@webrtc.org} 108166a358217004e1580453e46ce99041533e994985henrike@webrtc.org 108266a358217004e1580453e46ce99041533e994985henrike@webrtc.orginline bool PulseAudioSoundSystem::IsInitialized() { 108366a358217004e1580453e46ce99041533e994985henrike@webrtc.org return mainloop_ != NULL; 108466a358217004e1580453e46ce99041533e994985henrike@webrtc.org} 108566a358217004e1580453e46ce99041533e994985henrike@webrtc.org 108666a358217004e1580453e46ce99041533e994985henrike@webrtc.orgstruct ConnectToPulseCallbackData { 108766a358217004e1580453e46ce99041533e994985henrike@webrtc.org PulseAudioSoundSystem *instance; 108866a358217004e1580453e46ce99041533e994985henrike@webrtc.org bool connect_done; 108966a358217004e1580453e46ce99041533e994985henrike@webrtc.org}; 109066a358217004e1580453e46ce99041533e994985henrike@webrtc.org 109166a358217004e1580453e46ce99041533e994985henrike@webrtc.orgvoid PulseAudioSoundSystem::ConnectToPulseCallbackThunk( 109266a358217004e1580453e46ce99041533e994985henrike@webrtc.org pa_context *context, void *userdata) { 109366a358217004e1580453e46ce99041533e994985henrike@webrtc.org ConnectToPulseCallbackData *data = 109466a358217004e1580453e46ce99041533e994985henrike@webrtc.org static_cast<ConnectToPulseCallbackData *>(userdata); 109566a358217004e1580453e46ce99041533e994985henrike@webrtc.org data->instance->OnConnectToPulseCallback(context, &data->connect_done); 109666a358217004e1580453e46ce99041533e994985henrike@webrtc.org} 109766a358217004e1580453e46ce99041533e994985henrike@webrtc.org 109866a358217004e1580453e46ce99041533e994985henrike@webrtc.orgvoid PulseAudioSoundSystem::OnConnectToPulseCallback( 109966a358217004e1580453e46ce99041533e994985henrike@webrtc.org pa_context *context, bool *connect_done) { 110066a358217004e1580453e46ce99041533e994985henrike@webrtc.org pa_context_state_t state = symbol_table_.pa_context_get_state()(context); 110166a358217004e1580453e46ce99041533e994985henrike@webrtc.org if (state == PA_CONTEXT_READY || 110266a358217004e1580453e46ce99041533e994985henrike@webrtc.org state == PA_CONTEXT_FAILED || 110366a358217004e1580453e46ce99041533e994985henrike@webrtc.org state == PA_CONTEXT_TERMINATED) { 110466a358217004e1580453e46ce99041533e994985henrike@webrtc.org // Connection process has reached a terminal state. Wake ConnectToPulse(). 110566a358217004e1580453e46ce99041533e994985henrike@webrtc.org *connect_done = true; 110666a358217004e1580453e46ce99041533e994985henrike@webrtc.org Signal(); 110766a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 110866a358217004e1580453e46ce99041533e994985henrike@webrtc.org} 110966a358217004e1580453e46ce99041533e994985henrike@webrtc.org 111066a358217004e1580453e46ce99041533e994985henrike@webrtc.org// Must be called with the lock held. 111166a358217004e1580453e46ce99041533e994985henrike@webrtc.orgbool PulseAudioSoundSystem::ConnectToPulse(pa_context *context) { 111266a358217004e1580453e46ce99041533e994985henrike@webrtc.org bool ret = true; 111366a358217004e1580453e46ce99041533e994985henrike@webrtc.org ConnectToPulseCallbackData data; 111466a358217004e1580453e46ce99041533e994985henrike@webrtc.org // Have to put this up here to satisfy the compiler. 111566a358217004e1580453e46ce99041533e994985henrike@webrtc.org pa_context_state_t state; 111666a358217004e1580453e46ce99041533e994985henrike@webrtc.org 111766a358217004e1580453e46ce99041533e994985henrike@webrtc.org data.instance = this; 111866a358217004e1580453e46ce99041533e994985henrike@webrtc.org data.connect_done = false; 111966a358217004e1580453e46ce99041533e994985henrike@webrtc.org 112066a358217004e1580453e46ce99041533e994985henrike@webrtc.org symbol_table_.pa_context_set_state_callback()(context, 112166a358217004e1580453e46ce99041533e994985henrike@webrtc.org &ConnectToPulseCallbackThunk, 112266a358217004e1580453e46ce99041533e994985henrike@webrtc.org &data); 112366a358217004e1580453e46ce99041533e994985henrike@webrtc.org 112466a358217004e1580453e46ce99041533e994985henrike@webrtc.org // Connect to PulseAudio sound server. 112566a358217004e1580453e46ce99041533e994985henrike@webrtc.org if (symbol_table_.pa_context_connect()( 112666a358217004e1580453e46ce99041533e994985henrike@webrtc.org context, 112766a358217004e1580453e46ce99041533e994985henrike@webrtc.org NULL, // Default server 112866a358217004e1580453e46ce99041533e994985henrike@webrtc.org PA_CONTEXT_NOAUTOSPAWN, 112966a358217004e1580453e46ce99041533e994985henrike@webrtc.org NULL) != 0) { // No special fork handling needed 113066a358217004e1580453e46ce99041533e994985henrike@webrtc.org LOG(LS_ERROR) << "Can't start connection to PulseAudio sound server"; 113166a358217004e1580453e46ce99041533e994985henrike@webrtc.org ret = false; 113266a358217004e1580453e46ce99041533e994985henrike@webrtc.org goto done; 113366a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 113466a358217004e1580453e46ce99041533e994985henrike@webrtc.org 113566a358217004e1580453e46ce99041533e994985henrike@webrtc.org // Wait for the connection state machine to reach a terminal state. 113666a358217004e1580453e46ce99041533e994985henrike@webrtc.org do { 113766a358217004e1580453e46ce99041533e994985henrike@webrtc.org Wait(); 113866a358217004e1580453e46ce99041533e994985henrike@webrtc.org } while (!data.connect_done); 113966a358217004e1580453e46ce99041533e994985henrike@webrtc.org 114066a358217004e1580453e46ce99041533e994985henrike@webrtc.org // Now check to see what final state we reached. 114166a358217004e1580453e46ce99041533e994985henrike@webrtc.org state = symbol_table_.pa_context_get_state()(context); 114266a358217004e1580453e46ce99041533e994985henrike@webrtc.org 114366a358217004e1580453e46ce99041533e994985henrike@webrtc.org if (state != PA_CONTEXT_READY) { 114466a358217004e1580453e46ce99041533e994985henrike@webrtc.org if (state == PA_CONTEXT_FAILED) { 114566a358217004e1580453e46ce99041533e994985henrike@webrtc.org LOG(LS_ERROR) << "Failed to connect to PulseAudio sound server"; 114666a358217004e1580453e46ce99041533e994985henrike@webrtc.org } else if (state == PA_CONTEXT_TERMINATED) { 114766a358217004e1580453e46ce99041533e994985henrike@webrtc.org LOG(LS_ERROR) << "PulseAudio connection terminated early"; 114866a358217004e1580453e46ce99041533e994985henrike@webrtc.org } else { 114966a358217004e1580453e46ce99041533e994985henrike@webrtc.org // Shouldn't happen, because we only signal on one of those three states. 115066a358217004e1580453e46ce99041533e994985henrike@webrtc.org LOG(LS_ERROR) << "Unknown problem connecting to PulseAudio"; 115166a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 115266a358217004e1580453e46ce99041533e994985henrike@webrtc.org ret = false; 115366a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 115466a358217004e1580453e46ce99041533e994985henrike@webrtc.org 115566a358217004e1580453e46ce99041533e994985henrike@webrtc.org done: 115666a358217004e1580453e46ce99041533e994985henrike@webrtc.org // We unset our callback for safety just in case the state might somehow 115766a358217004e1580453e46ce99041533e994985henrike@webrtc.org // change later, because the pointer to "data" will be invalid after return 115866a358217004e1580453e46ce99041533e994985henrike@webrtc.org // from this function. 115966a358217004e1580453e46ce99041533e994985henrike@webrtc.org symbol_table_.pa_context_set_state_callback()(context, NULL, NULL); 116066a358217004e1580453e46ce99041533e994985henrike@webrtc.org return ret; 116166a358217004e1580453e46ce99041533e994985henrike@webrtc.org} 116266a358217004e1580453e46ce99041533e994985henrike@webrtc.org 116366a358217004e1580453e46ce99041533e994985henrike@webrtc.org// Must be called with the lock held. 116466a358217004e1580453e46ce99041533e994985henrike@webrtc.orgpa_context *PulseAudioSoundSystem::CreateNewConnection() { 116566a358217004e1580453e46ce99041533e994985henrike@webrtc.org // Create connection context. 116666a358217004e1580453e46ce99041533e994985henrike@webrtc.org std::string app_name; 11670f2e939a92fc1a70a67a9fc141d1f1d006bcded9jbauch // TODO(henrika): Pulse etiquette says this name should be localized. Do 116866a358217004e1580453e46ce99041533e994985henrike@webrtc.org // we care? 116966a358217004e1580453e46ce99041533e994985henrike@webrtc.org rtc::Filesystem::GetApplicationName(&app_name); 117066a358217004e1580453e46ce99041533e994985henrike@webrtc.org pa_context *context = symbol_table_.pa_context_new()( 117166a358217004e1580453e46ce99041533e994985henrike@webrtc.org symbol_table_.pa_threaded_mainloop_get_api()(mainloop_), 117266a358217004e1580453e46ce99041533e994985henrike@webrtc.org app_name.c_str()); 117366a358217004e1580453e46ce99041533e994985henrike@webrtc.org if (!context) { 117466a358217004e1580453e46ce99041533e994985henrike@webrtc.org LOG(LS_ERROR) << "Can't create context"; 117566a358217004e1580453e46ce99041533e994985henrike@webrtc.org goto fail0; 117666a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 117766a358217004e1580453e46ce99041533e994985henrike@webrtc.org 117866a358217004e1580453e46ce99041533e994985henrike@webrtc.org // Now connect. 117966a358217004e1580453e46ce99041533e994985henrike@webrtc.org if (!ConnectToPulse(context)) { 118066a358217004e1580453e46ce99041533e994985henrike@webrtc.org goto fail1; 118166a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 118266a358217004e1580453e46ce99041533e994985henrike@webrtc.org 118366a358217004e1580453e46ce99041533e994985henrike@webrtc.org // Otherwise the connection succeeded and is ready. 118466a358217004e1580453e46ce99041533e994985henrike@webrtc.org return context; 118566a358217004e1580453e46ce99041533e994985henrike@webrtc.org 118666a358217004e1580453e46ce99041533e994985henrike@webrtc.org fail1: 118766a358217004e1580453e46ce99041533e994985henrike@webrtc.org symbol_table_.pa_context_unref()(context); 118866a358217004e1580453e46ce99041533e994985henrike@webrtc.org fail0: 118966a358217004e1580453e46ce99041533e994985henrike@webrtc.org return NULL; 119066a358217004e1580453e46ce99041533e994985henrike@webrtc.org} 119166a358217004e1580453e46ce99041533e994985henrike@webrtc.org 119266a358217004e1580453e46ce99041533e994985henrike@webrtc.orgstruct EnumerateDevicesCallbackData { 119366a358217004e1580453e46ce99041533e994985henrike@webrtc.org PulseAudioSoundSystem *instance; 119466a358217004e1580453e46ce99041533e994985henrike@webrtc.org SoundSystemInterface::SoundDeviceLocatorList *devices; 119566a358217004e1580453e46ce99041533e994985henrike@webrtc.org}; 119666a358217004e1580453e46ce99041533e994985henrike@webrtc.org 119766a358217004e1580453e46ce99041533e994985henrike@webrtc.orgvoid PulseAudioSoundSystem::EnumeratePlaybackDevicesCallbackThunk( 119866a358217004e1580453e46ce99041533e994985henrike@webrtc.org pa_context *unused, 119966a358217004e1580453e46ce99041533e994985henrike@webrtc.org const pa_sink_info *info, 120066a358217004e1580453e46ce99041533e994985henrike@webrtc.org int eol, 120166a358217004e1580453e46ce99041533e994985henrike@webrtc.org void *userdata) { 120266a358217004e1580453e46ce99041533e994985henrike@webrtc.org EnumerateDevicesCallbackData *data = 120366a358217004e1580453e46ce99041533e994985henrike@webrtc.org static_cast<EnumerateDevicesCallbackData *>(userdata); 120466a358217004e1580453e46ce99041533e994985henrike@webrtc.org data->instance->OnEnumeratePlaybackDevicesCallback(data->devices, info, eol); 120566a358217004e1580453e46ce99041533e994985henrike@webrtc.org} 120666a358217004e1580453e46ce99041533e994985henrike@webrtc.org 120766a358217004e1580453e46ce99041533e994985henrike@webrtc.orgvoid PulseAudioSoundSystem::EnumerateCaptureDevicesCallbackThunk( 120866a358217004e1580453e46ce99041533e994985henrike@webrtc.org pa_context *unused, 120966a358217004e1580453e46ce99041533e994985henrike@webrtc.org const pa_source_info *info, 121066a358217004e1580453e46ce99041533e994985henrike@webrtc.org int eol, 121166a358217004e1580453e46ce99041533e994985henrike@webrtc.org void *userdata) { 121266a358217004e1580453e46ce99041533e994985henrike@webrtc.org EnumerateDevicesCallbackData *data = 121366a358217004e1580453e46ce99041533e994985henrike@webrtc.org static_cast<EnumerateDevicesCallbackData *>(userdata); 121466a358217004e1580453e46ce99041533e994985henrike@webrtc.org data->instance->OnEnumerateCaptureDevicesCallback(data->devices, info, eol); 121566a358217004e1580453e46ce99041533e994985henrike@webrtc.org} 121666a358217004e1580453e46ce99041533e994985henrike@webrtc.org 121766a358217004e1580453e46ce99041533e994985henrike@webrtc.orgvoid PulseAudioSoundSystem::OnEnumeratePlaybackDevicesCallback( 121866a358217004e1580453e46ce99041533e994985henrike@webrtc.org SoundDeviceLocatorList *devices, 121966a358217004e1580453e46ce99041533e994985henrike@webrtc.org const pa_sink_info *info, 122066a358217004e1580453e46ce99041533e994985henrike@webrtc.org int eol) { 122166a358217004e1580453e46ce99041533e994985henrike@webrtc.org if (eol) { 122266a358217004e1580453e46ce99041533e994985henrike@webrtc.org // List is over. Wake EnumerateDevices(). 122366a358217004e1580453e46ce99041533e994985henrike@webrtc.org Signal(); 122466a358217004e1580453e46ce99041533e994985henrike@webrtc.org return; 122566a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 122666a358217004e1580453e46ce99041533e994985henrike@webrtc.org 122766a358217004e1580453e46ce99041533e994985henrike@webrtc.org // Else this is the next device. 122866a358217004e1580453e46ce99041533e994985henrike@webrtc.org devices->push_back( 122966a358217004e1580453e46ce99041533e994985henrike@webrtc.org new PulseAudioDeviceLocator(info->description, info->name)); 123066a358217004e1580453e46ce99041533e994985henrike@webrtc.org} 123166a358217004e1580453e46ce99041533e994985henrike@webrtc.org 123266a358217004e1580453e46ce99041533e994985henrike@webrtc.orgvoid PulseAudioSoundSystem::OnEnumerateCaptureDevicesCallback( 123366a358217004e1580453e46ce99041533e994985henrike@webrtc.org SoundDeviceLocatorList *devices, 123466a358217004e1580453e46ce99041533e994985henrike@webrtc.org const pa_source_info *info, 123566a358217004e1580453e46ce99041533e994985henrike@webrtc.org int eol) { 123666a358217004e1580453e46ce99041533e994985henrike@webrtc.org if (eol) { 123766a358217004e1580453e46ce99041533e994985henrike@webrtc.org // List is over. Wake EnumerateDevices(). 123866a358217004e1580453e46ce99041533e994985henrike@webrtc.org Signal(); 123966a358217004e1580453e46ce99041533e994985henrike@webrtc.org return; 124066a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 124166a358217004e1580453e46ce99041533e994985henrike@webrtc.org 124266a358217004e1580453e46ce99041533e994985henrike@webrtc.org if (info->monitor_of_sink != PA_INVALID_INDEX) { 124366a358217004e1580453e46ce99041533e994985henrike@webrtc.org // We don't want to list monitor sources, since they are almost certainly 124466a358217004e1580453e46ce99041533e994985henrike@webrtc.org // not what the user wants for voice conferencing. 124566a358217004e1580453e46ce99041533e994985henrike@webrtc.org return; 124666a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 124766a358217004e1580453e46ce99041533e994985henrike@webrtc.org 124866a358217004e1580453e46ce99041533e994985henrike@webrtc.org // Else this is the next device. 124966a358217004e1580453e46ce99041533e994985henrike@webrtc.org devices->push_back( 125066a358217004e1580453e46ce99041533e994985henrike@webrtc.org new PulseAudioDeviceLocator(info->description, info->name)); 125166a358217004e1580453e46ce99041533e994985henrike@webrtc.org} 125266a358217004e1580453e46ce99041533e994985henrike@webrtc.org 125366a358217004e1580453e46ce99041533e994985henrike@webrtc.orgtemplate <typename InfoStruct> 125466a358217004e1580453e46ce99041533e994985henrike@webrtc.orgbool PulseAudioSoundSystem::EnumerateDevices( 125566a358217004e1580453e46ce99041533e994985henrike@webrtc.org SoundDeviceLocatorList *devices, 125666a358217004e1580453e46ce99041533e994985henrike@webrtc.org pa_operation *(*enumerate_fn)( 125766a358217004e1580453e46ce99041533e994985henrike@webrtc.org pa_context *c, 125866a358217004e1580453e46ce99041533e994985henrike@webrtc.org void (*callback_fn)( 125966a358217004e1580453e46ce99041533e994985henrike@webrtc.org pa_context *c, 126066a358217004e1580453e46ce99041533e994985henrike@webrtc.org const InfoStruct *i, 126166a358217004e1580453e46ce99041533e994985henrike@webrtc.org int eol, 126266a358217004e1580453e46ce99041533e994985henrike@webrtc.org void *userdata), 126366a358217004e1580453e46ce99041533e994985henrike@webrtc.org void *userdata), 126466a358217004e1580453e46ce99041533e994985henrike@webrtc.org void (*callback_fn)( 126566a358217004e1580453e46ce99041533e994985henrike@webrtc.org pa_context *c, 126666a358217004e1580453e46ce99041533e994985henrike@webrtc.org const InfoStruct *i, 126766a358217004e1580453e46ce99041533e994985henrike@webrtc.org int eol, 126866a358217004e1580453e46ce99041533e994985henrike@webrtc.org void *userdata)) { 126966a358217004e1580453e46ce99041533e994985henrike@webrtc.org ClearSoundDeviceLocatorList(devices); 127066a358217004e1580453e46ce99041533e994985henrike@webrtc.org if (!IsInitialized()) { 127166a358217004e1580453e46ce99041533e994985henrike@webrtc.org return false; 127266a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 127366a358217004e1580453e46ce99041533e994985henrike@webrtc.org 127466a358217004e1580453e46ce99041533e994985henrike@webrtc.org EnumerateDevicesCallbackData data; 127566a358217004e1580453e46ce99041533e994985henrike@webrtc.org data.instance = this; 127666a358217004e1580453e46ce99041533e994985henrike@webrtc.org data.devices = devices; 127766a358217004e1580453e46ce99041533e994985henrike@webrtc.org 127866a358217004e1580453e46ce99041533e994985henrike@webrtc.org Lock(); 127966a358217004e1580453e46ce99041533e994985henrike@webrtc.org pa_operation *op = (*enumerate_fn)( 128066a358217004e1580453e46ce99041533e994985henrike@webrtc.org context_, 128166a358217004e1580453e46ce99041533e994985henrike@webrtc.org callback_fn, 128266a358217004e1580453e46ce99041533e994985henrike@webrtc.org &data); 128366a358217004e1580453e46ce99041533e994985henrike@webrtc.org bool ret = FinishOperation(op); 128466a358217004e1580453e46ce99041533e994985henrike@webrtc.org Unlock(); 128566a358217004e1580453e46ce99041533e994985henrike@webrtc.org return ret; 128666a358217004e1580453e46ce99041533e994985henrike@webrtc.org} 128766a358217004e1580453e46ce99041533e994985henrike@webrtc.org 128866a358217004e1580453e46ce99041533e994985henrike@webrtc.orgstruct GetDefaultDeviceCallbackData { 128966a358217004e1580453e46ce99041533e994985henrike@webrtc.org PulseAudioSoundSystem *instance; 129066a358217004e1580453e46ce99041533e994985henrike@webrtc.org SoundDeviceLocator **device; 129166a358217004e1580453e46ce99041533e994985henrike@webrtc.org}; 129266a358217004e1580453e46ce99041533e994985henrike@webrtc.org 129366a358217004e1580453e46ce99041533e994985henrike@webrtc.orgtemplate <const char *(pa_server_info::*field)> 129466a358217004e1580453e46ce99041533e994985henrike@webrtc.orgvoid PulseAudioSoundSystem::GetDefaultDeviceCallbackThunk( 129566a358217004e1580453e46ce99041533e994985henrike@webrtc.org pa_context *unused, 129666a358217004e1580453e46ce99041533e994985henrike@webrtc.org const pa_server_info *info, 129766a358217004e1580453e46ce99041533e994985henrike@webrtc.org void *userdata) { 129866a358217004e1580453e46ce99041533e994985henrike@webrtc.org GetDefaultDeviceCallbackData *data = 129966a358217004e1580453e46ce99041533e994985henrike@webrtc.org static_cast<GetDefaultDeviceCallbackData *>(userdata); 130066a358217004e1580453e46ce99041533e994985henrike@webrtc.org data->instance->OnGetDefaultDeviceCallback<field>(info, data->device); 130166a358217004e1580453e46ce99041533e994985henrike@webrtc.org} 130266a358217004e1580453e46ce99041533e994985henrike@webrtc.org 130366a358217004e1580453e46ce99041533e994985henrike@webrtc.orgtemplate <const char *(pa_server_info::*field)> 130466a358217004e1580453e46ce99041533e994985henrike@webrtc.orgvoid PulseAudioSoundSystem::OnGetDefaultDeviceCallback( 130566a358217004e1580453e46ce99041533e994985henrike@webrtc.org const pa_server_info *info, 130666a358217004e1580453e46ce99041533e994985henrike@webrtc.org SoundDeviceLocator **device) { 130766a358217004e1580453e46ce99041533e994985henrike@webrtc.org if (info) { 130866a358217004e1580453e46ce99041533e994985henrike@webrtc.org const char *dev = info->*field; 130966a358217004e1580453e46ce99041533e994985henrike@webrtc.org if (dev) { 131066a358217004e1580453e46ce99041533e994985henrike@webrtc.org *device = new PulseAudioDeviceLocator("Default device", dev); 131166a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 131266a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 131366a358217004e1580453e46ce99041533e994985henrike@webrtc.org Signal(); 131466a358217004e1580453e46ce99041533e994985henrike@webrtc.org} 131566a358217004e1580453e46ce99041533e994985henrike@webrtc.org 131666a358217004e1580453e46ce99041533e994985henrike@webrtc.orgtemplate <const char *(pa_server_info::*field)> 131766a358217004e1580453e46ce99041533e994985henrike@webrtc.orgbool PulseAudioSoundSystem::GetDefaultDevice(SoundDeviceLocator **device) { 131866a358217004e1580453e46ce99041533e994985henrike@webrtc.org if (!IsInitialized()) { 131966a358217004e1580453e46ce99041533e994985henrike@webrtc.org return false; 132066a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 132166a358217004e1580453e46ce99041533e994985henrike@webrtc.org bool ret; 132266a358217004e1580453e46ce99041533e994985henrike@webrtc.org *device = NULL; 132366a358217004e1580453e46ce99041533e994985henrike@webrtc.org GetDefaultDeviceCallbackData data; 132466a358217004e1580453e46ce99041533e994985henrike@webrtc.org data.instance = this; 132566a358217004e1580453e46ce99041533e994985henrike@webrtc.org data.device = device; 132666a358217004e1580453e46ce99041533e994985henrike@webrtc.org Lock(); 132766a358217004e1580453e46ce99041533e994985henrike@webrtc.org pa_operation *op = symbol_table_.pa_context_get_server_info()( 132866a358217004e1580453e46ce99041533e994985henrike@webrtc.org context_, 132966a358217004e1580453e46ce99041533e994985henrike@webrtc.org &GetDefaultDeviceCallbackThunk<field>, 133066a358217004e1580453e46ce99041533e994985henrike@webrtc.org &data); 133166a358217004e1580453e46ce99041533e994985henrike@webrtc.org ret = FinishOperation(op); 133266a358217004e1580453e46ce99041533e994985henrike@webrtc.org Unlock(); 133366a358217004e1580453e46ce99041533e994985henrike@webrtc.org return ret && (*device != NULL); 133466a358217004e1580453e46ce99041533e994985henrike@webrtc.org} 133566a358217004e1580453e46ce99041533e994985henrike@webrtc.org 133666a358217004e1580453e46ce99041533e994985henrike@webrtc.orgvoid PulseAudioSoundSystem::StreamStateChangedCallbackThunk( 133766a358217004e1580453e46ce99041533e994985henrike@webrtc.org pa_stream *stream, 133866a358217004e1580453e46ce99041533e994985henrike@webrtc.org void *userdata) { 133966a358217004e1580453e46ce99041533e994985henrike@webrtc.org PulseAudioSoundSystem *instance = 134066a358217004e1580453e46ce99041533e994985henrike@webrtc.org static_cast<PulseAudioSoundSystem *>(userdata); 134166a358217004e1580453e46ce99041533e994985henrike@webrtc.org instance->OnStreamStateChangedCallback(stream); 134266a358217004e1580453e46ce99041533e994985henrike@webrtc.org} 134366a358217004e1580453e46ce99041533e994985henrike@webrtc.org 134466a358217004e1580453e46ce99041533e994985henrike@webrtc.orgvoid PulseAudioSoundSystem::OnStreamStateChangedCallback(pa_stream *stream) { 134566a358217004e1580453e46ce99041533e994985henrike@webrtc.org pa_stream_state_t state = symbol_table_.pa_stream_get_state()(stream); 134666a358217004e1580453e46ce99041533e994985henrike@webrtc.org if (state == PA_STREAM_READY) { 134766a358217004e1580453e46ce99041533e994985henrike@webrtc.org LOG(LS_INFO) << "Pulse stream " << stream << " ready"; 134866a358217004e1580453e46ce99041533e994985henrike@webrtc.org } else if (state == PA_STREAM_FAILED || 134966a358217004e1580453e46ce99041533e994985henrike@webrtc.org state == PA_STREAM_TERMINATED || 135066a358217004e1580453e46ce99041533e994985henrike@webrtc.org state == PA_STREAM_UNCONNECTED) { 135166a358217004e1580453e46ce99041533e994985henrike@webrtc.org LOG(LS_ERROR) << "Pulse stream " << stream << " failed to connect: " 135266a358217004e1580453e46ce99041533e994985henrike@webrtc.org << LastError(); 135366a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 135466a358217004e1580453e46ce99041533e994985henrike@webrtc.org} 135566a358217004e1580453e46ce99041533e994985henrike@webrtc.org 135666a358217004e1580453e46ce99041533e994985henrike@webrtc.orgtemplate <typename StreamInterface> 135766a358217004e1580453e46ce99041533e994985henrike@webrtc.orgStreamInterface *PulseAudioSoundSystem::OpenDevice( 135866a358217004e1580453e46ce99041533e994985henrike@webrtc.org const SoundDeviceLocator *device, 135966a358217004e1580453e46ce99041533e994985henrike@webrtc.org const OpenParams ¶ms, 136066a358217004e1580453e46ce99041533e994985henrike@webrtc.org const char *stream_name, 136166a358217004e1580453e46ce99041533e994985henrike@webrtc.org StreamInterface *(PulseAudioSoundSystem::*connect_fn)( 136266a358217004e1580453e46ce99041533e994985henrike@webrtc.org pa_stream *stream, 136366a358217004e1580453e46ce99041533e994985henrike@webrtc.org const char *dev, 136466a358217004e1580453e46ce99041533e994985henrike@webrtc.org int flags, 136566a358217004e1580453e46ce99041533e994985henrike@webrtc.org pa_stream_flags_t pa_flags, 136666a358217004e1580453e46ce99041533e994985henrike@webrtc.org int latency, 136766a358217004e1580453e46ce99041533e994985henrike@webrtc.org const pa_sample_spec &spec)) { 136866a358217004e1580453e46ce99041533e994985henrike@webrtc.org if (!IsInitialized()) { 136966a358217004e1580453e46ce99041533e994985henrike@webrtc.org return NULL; 137066a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 137166a358217004e1580453e46ce99041533e994985henrike@webrtc.org 137266a358217004e1580453e46ce99041533e994985henrike@webrtc.org const char *dev = static_cast<const PulseAudioDeviceLocator *>(device)-> 137366a358217004e1580453e46ce99041533e994985henrike@webrtc.org device_name().c_str(); 137466a358217004e1580453e46ce99041533e994985henrike@webrtc.org 137566a358217004e1580453e46ce99041533e994985henrike@webrtc.org StreamInterface *stream_interface = NULL; 137666a358217004e1580453e46ce99041533e994985henrike@webrtc.org 13775237aaf243d29732f59557361b7a993c0a18cf0etfarina ASSERT(params.format < arraysize(kCricketFormatToPulseFormatTable)); 137866a358217004e1580453e46ce99041533e994985henrike@webrtc.org 137966a358217004e1580453e46ce99041533e994985henrike@webrtc.org pa_sample_spec spec; 138066a358217004e1580453e46ce99041533e994985henrike@webrtc.org spec.format = kCricketFormatToPulseFormatTable[params.format]; 138166a358217004e1580453e46ce99041533e994985henrike@webrtc.org spec.rate = params.freq; 138266a358217004e1580453e46ce99041533e994985henrike@webrtc.org spec.channels = params.channels; 138366a358217004e1580453e46ce99041533e994985henrike@webrtc.org 138466a358217004e1580453e46ce99041533e994985henrike@webrtc.org int pa_flags = 0; 138566a358217004e1580453e46ce99041533e994985henrike@webrtc.org if (params.flags & FLAG_REPORT_LATENCY) { 138666a358217004e1580453e46ce99041533e994985henrike@webrtc.org pa_flags |= PA_STREAM_INTERPOLATE_TIMING | 138766a358217004e1580453e46ce99041533e994985henrike@webrtc.org PA_STREAM_AUTO_TIMING_UPDATE; 138866a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 138966a358217004e1580453e46ce99041533e994985henrike@webrtc.org 139066a358217004e1580453e46ce99041533e994985henrike@webrtc.org if (params.latency != kNoLatencyRequirements) { 139166a358217004e1580453e46ce99041533e994985henrike@webrtc.org // If configuring a specific latency then we want to specify 139266a358217004e1580453e46ce99041533e994985henrike@webrtc.org // PA_STREAM_ADJUST_LATENCY to make the server adjust parameters 139366a358217004e1580453e46ce99041533e994985henrike@webrtc.org // automatically to reach that target latency. However, that flag doesn't 139466a358217004e1580453e46ce99041533e994985henrike@webrtc.org // exist in Ubuntu 8.04 and many people still use that, so we have to check 139566a358217004e1580453e46ce99041533e994985henrike@webrtc.org // the protocol version of libpulse. 139666a358217004e1580453e46ce99041533e994985henrike@webrtc.org if (symbol_table_.pa_context_get_protocol_version()(context_) >= 139766a358217004e1580453e46ce99041533e994985henrike@webrtc.org kAdjustLatencyProtocolVersion) { 139866a358217004e1580453e46ce99041533e994985henrike@webrtc.org pa_flags |= PA_STREAM_ADJUST_LATENCY; 139966a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 140066a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 140166a358217004e1580453e46ce99041533e994985henrike@webrtc.org 140266a358217004e1580453e46ce99041533e994985henrike@webrtc.org Lock(); 140366a358217004e1580453e46ce99041533e994985henrike@webrtc.org 140466a358217004e1580453e46ce99041533e994985henrike@webrtc.org pa_stream *stream = symbol_table_.pa_stream_new()(context_, stream_name, 140566a358217004e1580453e46ce99041533e994985henrike@webrtc.org &spec, NULL); 140666a358217004e1580453e46ce99041533e994985henrike@webrtc.org if (!stream) { 140766a358217004e1580453e46ce99041533e994985henrike@webrtc.org LOG(LS_ERROR) << "Can't create pa_stream"; 140866a358217004e1580453e46ce99041533e994985henrike@webrtc.org goto done; 140966a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 141066a358217004e1580453e46ce99041533e994985henrike@webrtc.org 141166a358217004e1580453e46ce99041533e994985henrike@webrtc.org // Set a state callback to log errors. 141266a358217004e1580453e46ce99041533e994985henrike@webrtc.org symbol_table_.pa_stream_set_state_callback()(stream, 141366a358217004e1580453e46ce99041533e994985henrike@webrtc.org &StreamStateChangedCallbackThunk, 141466a358217004e1580453e46ce99041533e994985henrike@webrtc.org this); 141566a358217004e1580453e46ce99041533e994985henrike@webrtc.org 141666a358217004e1580453e46ce99041533e994985henrike@webrtc.org stream_interface = (this->*connect_fn)( 141766a358217004e1580453e46ce99041533e994985henrike@webrtc.org stream, 141866a358217004e1580453e46ce99041533e994985henrike@webrtc.org dev, 141966a358217004e1580453e46ce99041533e994985henrike@webrtc.org params.flags, 142066a358217004e1580453e46ce99041533e994985henrike@webrtc.org static_cast<pa_stream_flags_t>(pa_flags), 142166a358217004e1580453e46ce99041533e994985henrike@webrtc.org params.latency, 142266a358217004e1580453e46ce99041533e994985henrike@webrtc.org spec); 142366a358217004e1580453e46ce99041533e994985henrike@webrtc.org if (!stream_interface) { 142466a358217004e1580453e46ce99041533e994985henrike@webrtc.org LOG(LS_ERROR) << "Can't connect stream to " << dev; 142566a358217004e1580453e46ce99041533e994985henrike@webrtc.org symbol_table_.pa_stream_unref()(stream); 142666a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 142766a358217004e1580453e46ce99041533e994985henrike@webrtc.org 142866a358217004e1580453e46ce99041533e994985henrike@webrtc.org done: 142966a358217004e1580453e46ce99041533e994985henrike@webrtc.org Unlock(); 143066a358217004e1580453e46ce99041533e994985henrike@webrtc.org return stream_interface; 143166a358217004e1580453e46ce99041533e994985henrike@webrtc.org} 143266a358217004e1580453e46ce99041533e994985henrike@webrtc.org 143366a358217004e1580453e46ce99041533e994985henrike@webrtc.org// Must be called with the lock held. 143466a358217004e1580453e46ce99041533e994985henrike@webrtc.orgSoundOutputStreamInterface *PulseAudioSoundSystem::ConnectOutputStream( 143566a358217004e1580453e46ce99041533e994985henrike@webrtc.org pa_stream *stream, 143666a358217004e1580453e46ce99041533e994985henrike@webrtc.org const char *dev, 143766a358217004e1580453e46ce99041533e994985henrike@webrtc.org int flags, 143866a358217004e1580453e46ce99041533e994985henrike@webrtc.org pa_stream_flags_t pa_flags, 143966a358217004e1580453e46ce99041533e994985henrike@webrtc.org int latency, 144066a358217004e1580453e46ce99041533e994985henrike@webrtc.org const pa_sample_spec &spec) { 144166a358217004e1580453e46ce99041533e994985henrike@webrtc.org pa_buffer_attr attr = {0}; 144266a358217004e1580453e46ce99041533e994985henrike@webrtc.org pa_buffer_attr *pattr = NULL; 144366a358217004e1580453e46ce99041533e994985henrike@webrtc.org if (latency != kNoLatencyRequirements) { 144466a358217004e1580453e46ce99041533e994985henrike@webrtc.org // kLowLatency is 0, so we treat it the same as a request for zero latency. 144566a358217004e1580453e46ce99041533e994985henrike@webrtc.org ssize_t bytes_per_sec = symbol_table_.pa_bytes_per_second()(&spec); 1446ff689be3c0c59c1be29aaa0697aa0f762566d6c6andresp@webrtc.org latency = std::max( 1447ff689be3c0c59c1be29aaa0697aa0f762566d6c6andresp@webrtc.org latency, static_cast<int>(bytes_per_sec * kPlaybackLatencyMinimumMsecs / 1448ff689be3c0c59c1be29aaa0697aa0f762566d6c6andresp@webrtc.org rtc::kNumMicrosecsPerSec)); 144966a358217004e1580453e46ce99041533e994985henrike@webrtc.org FillPlaybackBufferAttr(latency, &attr); 145066a358217004e1580453e46ce99041533e994985henrike@webrtc.org pattr = &attr; 145166a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 145266a358217004e1580453e46ce99041533e994985henrike@webrtc.org if (symbol_table_.pa_stream_connect_playback()( 145366a358217004e1580453e46ce99041533e994985henrike@webrtc.org stream, 145466a358217004e1580453e46ce99041533e994985henrike@webrtc.org dev, 145566a358217004e1580453e46ce99041533e994985henrike@webrtc.org pattr, 145666a358217004e1580453e46ce99041533e994985henrike@webrtc.org pa_flags, 145766a358217004e1580453e46ce99041533e994985henrike@webrtc.org // Let server choose volume 145866a358217004e1580453e46ce99041533e994985henrike@webrtc.org NULL, 145966a358217004e1580453e46ce99041533e994985henrike@webrtc.org // Not synchronized to any other playout 146066a358217004e1580453e46ce99041533e994985henrike@webrtc.org NULL) != 0) { 146166a358217004e1580453e46ce99041533e994985henrike@webrtc.org return NULL; 146266a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 146366a358217004e1580453e46ce99041533e994985henrike@webrtc.org return new PulseAudioOutputStream(this, stream, flags, latency); 146466a358217004e1580453e46ce99041533e994985henrike@webrtc.org} 146566a358217004e1580453e46ce99041533e994985henrike@webrtc.org 146666a358217004e1580453e46ce99041533e994985henrike@webrtc.org// Must be called with the lock held. 146766a358217004e1580453e46ce99041533e994985henrike@webrtc.orgSoundInputStreamInterface *PulseAudioSoundSystem::ConnectInputStream( 146866a358217004e1580453e46ce99041533e994985henrike@webrtc.org pa_stream *stream, 146966a358217004e1580453e46ce99041533e994985henrike@webrtc.org const char *dev, 147066a358217004e1580453e46ce99041533e994985henrike@webrtc.org int flags, 147166a358217004e1580453e46ce99041533e994985henrike@webrtc.org pa_stream_flags_t pa_flags, 147266a358217004e1580453e46ce99041533e994985henrike@webrtc.org int latency, 147366a358217004e1580453e46ce99041533e994985henrike@webrtc.org const pa_sample_spec &spec) { 147466a358217004e1580453e46ce99041533e994985henrike@webrtc.org pa_buffer_attr attr = {0}; 147566a358217004e1580453e46ce99041533e994985henrike@webrtc.org pa_buffer_attr *pattr = NULL; 147666a358217004e1580453e46ce99041533e994985henrike@webrtc.org if (latency != kNoLatencyRequirements) { 147766a358217004e1580453e46ce99041533e994985henrike@webrtc.org size_t bytes_per_sec = symbol_table_.pa_bytes_per_second()(&spec); 147866a358217004e1580453e46ce99041533e994985henrike@webrtc.org if (latency == kLowLatency) { 147966a358217004e1580453e46ce99041533e994985henrike@webrtc.org latency = bytes_per_sec * kLowCaptureLatencyMsecs / 148066a358217004e1580453e46ce99041533e994985henrike@webrtc.org rtc::kNumMicrosecsPerSec; 148166a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 148266a358217004e1580453e46ce99041533e994985henrike@webrtc.org // Note: fragsize specifies a maximum transfer size, not a minimum, so it is 148366a358217004e1580453e46ce99041533e994985henrike@webrtc.org // not possible to force a high latency setting, only a low one. 148466a358217004e1580453e46ce99041533e994985henrike@webrtc.org attr.fragsize = latency; 148566a358217004e1580453e46ce99041533e994985henrike@webrtc.org attr.maxlength = latency + bytes_per_sec * kCaptureBufferExtraMsecs / 148666a358217004e1580453e46ce99041533e994985henrike@webrtc.org rtc::kNumMicrosecsPerSec; 148766a358217004e1580453e46ce99041533e994985henrike@webrtc.org LOG(LS_VERBOSE) << "Configuring latency = " << attr.fragsize 148866a358217004e1580453e46ce99041533e994985henrike@webrtc.org << ", maxlength = " << attr.maxlength; 148966a358217004e1580453e46ce99041533e994985henrike@webrtc.org pattr = &attr; 149066a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 149166a358217004e1580453e46ce99041533e994985henrike@webrtc.org if (symbol_table_.pa_stream_connect_record()(stream, 149266a358217004e1580453e46ce99041533e994985henrike@webrtc.org dev, 149366a358217004e1580453e46ce99041533e994985henrike@webrtc.org pattr, 149466a358217004e1580453e46ce99041533e994985henrike@webrtc.org pa_flags) != 0) { 149566a358217004e1580453e46ce99041533e994985henrike@webrtc.org return NULL; 149666a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 149766a358217004e1580453e46ce99041533e994985henrike@webrtc.org return new PulseAudioInputStream(this, stream, flags); 149866a358217004e1580453e46ce99041533e994985henrike@webrtc.org} 149966a358217004e1580453e46ce99041533e994985henrike@webrtc.org 150066a358217004e1580453e46ce99041533e994985henrike@webrtc.org// Must be called with the lock held. 150166a358217004e1580453e46ce99041533e994985henrike@webrtc.orgbool PulseAudioSoundSystem::FinishOperation(pa_operation *op) { 150266a358217004e1580453e46ce99041533e994985henrike@webrtc.org if (!op) { 150366a358217004e1580453e46ce99041533e994985henrike@webrtc.org LOG(LS_ERROR) << "Failed to start operation"; 150466a358217004e1580453e46ce99041533e994985henrike@webrtc.org return false; 150566a358217004e1580453e46ce99041533e994985henrike@webrtc.org } 150666a358217004e1580453e46ce99041533e994985henrike@webrtc.org 150766a358217004e1580453e46ce99041533e994985henrike@webrtc.org do { 150866a358217004e1580453e46ce99041533e994985henrike@webrtc.org Wait(); 150966a358217004e1580453e46ce99041533e994985henrike@webrtc.org } while (symbol_table_.pa_operation_get_state()(op) == PA_OPERATION_RUNNING); 151066a358217004e1580453e46ce99041533e994985henrike@webrtc.org 151166a358217004e1580453e46ce99041533e994985henrike@webrtc.org symbol_table_.pa_operation_unref()(op); 151266a358217004e1580453e46ce99041533e994985henrike@webrtc.org 151366a358217004e1580453e46ce99041533e994985henrike@webrtc.org return true; 151466a358217004e1580453e46ce99041533e994985henrike@webrtc.org} 151566a358217004e1580453e46ce99041533e994985henrike@webrtc.org 151666a358217004e1580453e46ce99041533e994985henrike@webrtc.orginline void PulseAudioSoundSystem::Lock() { 151766a358217004e1580453e46ce99041533e994985henrike@webrtc.org symbol_table_.pa_threaded_mainloop_lock()(mainloop_); 151866a358217004e1580453e46ce99041533e994985henrike@webrtc.org} 151966a358217004e1580453e46ce99041533e994985henrike@webrtc.org 152066a358217004e1580453e46ce99041533e994985henrike@webrtc.orginline void PulseAudioSoundSystem::Unlock() { 152166a358217004e1580453e46ce99041533e994985henrike@webrtc.org symbol_table_.pa_threaded_mainloop_unlock()(mainloop_); 152266a358217004e1580453e46ce99041533e994985henrike@webrtc.org} 152366a358217004e1580453e46ce99041533e994985henrike@webrtc.org 152466a358217004e1580453e46ce99041533e994985henrike@webrtc.org// Must be called with the lock held. 152566a358217004e1580453e46ce99041533e994985henrike@webrtc.orginline void PulseAudioSoundSystem::Wait() { 152666a358217004e1580453e46ce99041533e994985henrike@webrtc.org symbol_table_.pa_threaded_mainloop_wait()(mainloop_); 152766a358217004e1580453e46ce99041533e994985henrike@webrtc.org} 152866a358217004e1580453e46ce99041533e994985henrike@webrtc.org 152966a358217004e1580453e46ce99041533e994985henrike@webrtc.org// Must be called with the lock held. 153066a358217004e1580453e46ce99041533e994985henrike@webrtc.orginline void PulseAudioSoundSystem::Signal() { 153166a358217004e1580453e46ce99041533e994985henrike@webrtc.org symbol_table_.pa_threaded_mainloop_signal()(mainloop_, 0); 153266a358217004e1580453e46ce99041533e994985henrike@webrtc.org} 153366a358217004e1580453e46ce99041533e994985henrike@webrtc.org 153466a358217004e1580453e46ce99041533e994985henrike@webrtc.org// Must be called with the lock held. 153566a358217004e1580453e46ce99041533e994985henrike@webrtc.orgconst char *PulseAudioSoundSystem::LastError() { 153666a358217004e1580453e46ce99041533e994985henrike@webrtc.org return symbol_table_.pa_strerror()(symbol_table_.pa_context_errno()( 153766a358217004e1580453e46ce99041533e994985henrike@webrtc.org context_)); 153866a358217004e1580453e46ce99041533e994985henrike@webrtc.org} 153966a358217004e1580453e46ce99041533e994985henrike@webrtc.org 154066a358217004e1580453e46ce99041533e994985henrike@webrtc.org} // namespace rtc 154166a358217004e1580453e46ce99041533e994985henrike@webrtc.org 154266a358217004e1580453e46ce99041533e994985henrike@webrtc.org#endif // HAVE_LIBPULSE 1543