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