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 &params) {
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 &params) {
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 &params,
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