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