audio_pipe_reader.cc revision 5821806d5e7f356e8fa4b058a389a808ea183019
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)
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/eintr_wrapper.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/file_path.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.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.
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kSamplingRate = 48000;
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kChannels = 2;
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kBytesPerSample = 2;
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Read data from the pipe every 40ms.
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kCapturingPeriodMs = 40;
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if !defined(F_SETPIPE_SZ)
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// F_SETPIPE_SZ is supported only starting linux 2.6.35, but we want to be able
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// to compile this code on machines with older kernel.
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define F_SETPIPE_SZ 1031
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif  // defined(F_SETPIPE_SZ)
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int IsPacketOfSilence(const std::string& data) {
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const int64* int_buf = reinterpret_cast<const int64*>(data.data());
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < data.size() / sizeof(int64); i++) {
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (int_buf[i] != 0)
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = data.size() - data.size() % sizeof(int64);
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       i < data.size(); i++) {
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (data.data()[i] != 0)
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)AudioPipeReader::AudioPipeReader(
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_refptr<base::SingleThreadTaskRunner> task_runner,
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const FilePath& pipe_name)
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : task_runner_(task_runner),
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      observers_(new ObserverListThreadSafe<StreamObserver>()) {
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  task_runner_->PostTask(FROM_HERE, base::Bind(
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      &AudioPipeReader::StartOnAudioThread, this, pipe_name));
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AudioPipeReader::StartOnAudioThread(const 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)
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Set buffer size for the pipe to the double of what's required for samples
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // of each capturing period.
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int pipe_buffer_size = 2 * kCapturingPeriodMs * kSamplingRate * kChannels *
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     kBytesPerSample / base::Time::kMillisecondsPerSecond;
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int result = HANDLE_EINTR(fcntl(pipe_fd_, F_SETPIPE_SZ, pipe_buffer_size));
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (result < 0) {
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PLOG(ERROR) << "fcntl";
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  WaitForPipeReadable();
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)AudioPipeReader::~AudioPipeReader() {
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AudioPipeReader::AddObserver(StreamObserver* observer) {
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  observers_->AddObserver(observer);
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AudioPipeReader::RemoveObserver(StreamObserver* observer) {
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  observers_->RemoveObserver(observer);
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AudioPipeReader::OnFileCanReadWithoutBlocking(int fd) {
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_EQ(fd, pipe_fd_);
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  StartTimer();
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AudioPipeReader::OnFileCanWriteWithoutBlocking(int fd) {
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  NOTREACHED();
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AudioPipeReader::StartTimer() {
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(task_runner_->BelongsToCurrentThread());
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  started_time_ = base::TimeTicks::Now();
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  last_capture_samples_ = 0;
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  timer_.Start(FROM_HERE, base::TimeDelta::FromMilliseconds(kCapturingPeriodMs),
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               this, &AudioPipeReader::DoCapture);
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AudioPipeReader::DoCapture() {
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(task_runner_->BelongsToCurrentThread());
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_GT(pipe_fd_, 0);
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Calculate how much we need read from the pipe. Pulseaudio doesn't control
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // how much data it writes to the pipe, so we need to pace the stream, so
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // that we read the exact number of the samples per second we need.
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::TimeDelta stream_position = base::TimeTicks::Now() - started_time_;
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int64 stream_position_samples = stream_position.InMilliseconds() *
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      kSamplingRate / base::Time::kMillisecondsPerSecond;
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int64 samples_to_capture =
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      stream_position_samples - last_capture_samples_;
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  last_capture_samples_ = stream_position_samples;
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int64 read_size =
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      samples_to_capture * kChannels * kBytesPerSample;
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string data = left_over_bytes_;
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int pos = data.size();
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  left_over_bytes_.clear();
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  data.resize(read_size);
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (pos < read_size) {
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int read_result = HANDLE_EINTR(
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       read(pipe_fd_, string_as_array(&data) + pos, read_size - pos));
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (read_result >= 0) {
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pos += read_result;
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (errno != EWOULDBLOCK && errno != EAGAIN)
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        PLOG(ERROR) << "read";
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (pos == 0) {
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    WaitForPipeReadable();
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Save any incomplete samples we've read for later. Each packet should
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // contain integer number of samples.
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int incomplete_samples_bytes = pos % (kChannels * kBytesPerSample);
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  left_over_bytes_.assign(data, pos - incomplete_samples_bytes,
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          incomplete_samples_bytes);
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  data.resize(pos - incomplete_samples_bytes);
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (IsPacketOfSilence(data))
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Dispatch asynchronous notification to the stream observers.
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_refptr<base::RefCountedString> data_ref =
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::RefCountedString::TakeString(&data);
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  observers_->Notify(&StreamObserver::OnDataRead, data_ref);
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AudioPipeReader::WaitForPipeReadable() {
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  timer_.Stop();
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MessageLoopForIO::current()->WatchFileDescriptor(
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pipe_fd_, false, MessageLoopForIO::WATCH_READ,
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      &file_descriptor_watcher_, this);
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace remoting
172