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