audio_pipe_reader.cc revision c2e0dbddbe15c98d52c4786dac06cb8952a8ae6d
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "remoting/host/linux/audio_pipe_reader.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <fcntl.h>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <sys/stat.h>
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <sys/types.h>
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <unistd.h>
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/files/file_path.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/posix/eintr_wrapper.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/stl_util.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace remoting {
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// PulseAudio's module-pipe-sink must be configured to use the following
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// parameters for the sink we read from.
232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const int kSamplesPerSecond = 48000;
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kChannels = 2;
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kBytesPerSample = 2;
262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const int kSampleBytesPerSecond =
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    kSamplesPerSecond * kChannels * kBytesPerSample;
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Read data from the pipe every 40ms.
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kCapturingPeriodMs = 40;
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Size of the pipe buffer in milliseconds.
332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const int kPipeBufferSizeMs = kCapturingPeriodMs * 2;
342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Size of the pipe buffer in bytes.
362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const int kPipeBufferSizeBytes = kPipeBufferSizeMs * kSampleBytesPerSecond /
372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::Time::kMillisecondsPerSecond;
382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if !defined(F_SETPIPE_SZ)
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// F_SETPIPE_SZ is supported only starting linux 2.6.35, but we want to be able
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// to compile this code on machines with older kernel.
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define F_SETPIPE_SZ 1031
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif  // defined(F_SETPIPE_SZ)
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// static
482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)scoped_refptr<AudioPipeReader> AudioPipeReader::Create(
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_refptr<base::SingleThreadTaskRunner> task_runner,
502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const base::FilePath& pipe_name) {
512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Create a reference to the new AudioPipeReader before posting the
522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // StartOnAudioThread task, otherwise it may be deleted on the audio
532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // thread before we return.
542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_refptr<AudioPipeReader> pipe_reader =
552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      new AudioPipeReader(task_runner);
562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  task_runner->PostTask(FROM_HERE, base::Bind(
572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      &AudioPipeReader::StartOnAudioThread, pipe_reader, pipe_name));
582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return pipe_reader;
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void AudioPipeReader::StartOnAudioThread(const base::FilePath& pipe_name) {
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(task_runner_->BelongsToCurrentThread());
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pipe_fd_ = HANDLE_EINTR(open(
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pipe_name.value().c_str(), O_RDONLY | O_NONBLOCK));
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (pipe_fd_ < 0) {
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "Failed to open " << pipe_name.value();
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Set buffer size for the pipe.
722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int result = HANDLE_EINTR(
732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      fcntl(pipe_fd_, F_SETPIPE_SZ, kPipeBufferSizeBytes));
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (result < 0) {
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PLOG(ERROR) << "fcntl";
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  WaitForPipeReadable();
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)AudioPipeReader::AudioPipeReader(
822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    scoped_refptr<base::SingleThreadTaskRunner> task_runner)
832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    : task_runner_(task_runner),
842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      observers_(new ObserverListThreadSafe<StreamObserver>()) {
852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)AudioPipeReader::~AudioPipeReader() {
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AudioPipeReader::AddObserver(StreamObserver* observer) {
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  observers_->AddObserver(observer);
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AudioPipeReader::RemoveObserver(StreamObserver* observer) {
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  observers_->RemoveObserver(observer);
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AudioPipeReader::OnFileCanReadWithoutBlocking(int fd) {
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_EQ(fd, pipe_fd_);
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  StartTimer();
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AudioPipeReader::OnFileCanWriteWithoutBlocking(int fd) {
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  NOTREACHED();
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AudioPipeReader::StartTimer() {
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(task_runner_->BelongsToCurrentThread());
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  started_time_ = base::TimeTicks::Now();
1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  last_capture_position_ = 0;
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  timer_.Start(FROM_HERE, base::TimeDelta::FromMilliseconds(kCapturingPeriodMs),
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               this, &AudioPipeReader::DoCapture);
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AudioPipeReader::DoCapture() {
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(task_runner_->BelongsToCurrentThread());
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_GT(pipe_fd_, 0);
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Calculate how much we need read from the pipe. Pulseaudio doesn't control
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // how much data it writes to the pipe, so we need to pace the stream, so
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // that we read the exact number of the samples per second we need.
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::TimeDelta stream_position = base::TimeTicks::Now() - started_time_;
1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int64 stream_position_bytes = stream_position.InMilliseconds() *
1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      kSampleBytesPerSecond / base::Time::kMillisecondsPerSecond;
1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int64 bytes_to_read = stream_position_bytes - last_capture_position_;
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string data = left_over_bytes_;
1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  size_t pos = data.size();
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  left_over_bytes_.clear();
1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  data.resize(pos + bytes_to_read);
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  while (pos < data.size()) {
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int read_result = HANDLE_EINTR(
1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)       read(pipe_fd_, string_as_array(&data) + pos, data.size() - pos));
1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (read_result > 0) {
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pos += read_result;
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (read_result < 0 && errno != EWOULDBLOCK && errno != EAGAIN)
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        PLOG(ERROR) << "read";
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Stop reading from the pipe if PulseAudio isn't writing anything.
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (pos == 0) {
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    WaitForPipeReadable();
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Save any incomplete samples we've read for later. Each packet should
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // contain integer number of samples.
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int incomplete_samples_bytes = pos % (kChannels * kBytesPerSample);
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  left_over_bytes_.assign(data, pos - incomplete_samples_bytes,
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          incomplete_samples_bytes);
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  data.resize(pos - incomplete_samples_bytes);
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  last_capture_position_ += data.size();
1572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Normally PulseAudio will keep pipe buffer full, so we should always be able
1582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // to read |bytes_to_read| bytes, but in case it's misbehaving we need to make
1592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // sure that |stream_position_bytes| doesn't go out of sync with the current
1602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // stream position.
1612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (stream_position_bytes - last_capture_position_ > kPipeBufferSizeBytes)
1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    last_capture_position_ = stream_position_bytes - kPipeBufferSizeBytes;
1632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK_LE(last_capture_position_, stream_position_bytes);
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Dispatch asynchronous notification to the stream observers.
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_refptr<base::RefCountedString> data_ref =
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::RefCountedString::TakeString(&data);
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  observers_->Notify(&StreamObserver::OnDataRead, data_ref);
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AudioPipeReader::WaitForPipeReadable() {
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  timer_.Stop();
173c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::MessageLoopForIO::current()->WatchFileDescriptor(
174c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      pipe_fd_,
175c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      false,
176c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      base::MessageLoopForIO::WATCH_READ,
177c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      &file_descriptor_watcher_,
178c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      this);
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// static
1822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void AudioPipeReaderTraits::Destruct(const AudioPipeReader* audio_pipe_reader) {
1832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  audio_pipe_reader->task_runner_->DeleteSoon(FROM_HERE, audio_pipe_reader);
1842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace remoting
187