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/audio_capturer_linux.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/files/file_path.h"
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/lazy_instance.h"
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "remoting/proto/audio.pb.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace remoting {
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// PulseAudio's module-pipe-sink must be configured to use the following
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// parameters for the sink we read from.
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const AudioPacket_SamplingRate kSamplingRate = AudioPacket::SAMPLING_RATE_48000;
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)base::LazyInstance<scoped_refptr<AudioPipeReader> >::Leaky
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    g_pulseaudio_pipe_sink_reader = LAZY_INSTANCE_INITIALIZER;
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// TODO(wez): Remove this and have the DesktopEnvironmentFactory own the
262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// AudioPipeReader rather than having it process-global.
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// See crbug.com/161373 and crbug.com/104544.
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AudioCapturerLinux::InitializePipeReader(
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_refptr<base::SingleThreadTaskRunner> task_runner,
302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const base::FilePath& pipe_name) {
312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_refptr<AudioPipeReader> pipe_reader;
322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!pipe_name.empty())
332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    pipe_reader = AudioPipeReader::Create(task_runner, pipe_name);
342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  g_pulseaudio_pipe_sink_reader.Get() = pipe_reader;
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)AudioCapturerLinux::AudioCapturerLinux(
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_refptr<AudioPipeReader> pipe_reader)
392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    : pipe_reader_(pipe_reader),
402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      silence_detector_(0) {
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)AudioCapturerLinux::~AudioCapturerLinux() {
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool AudioCapturerLinux::Start(const PacketCapturedCallback& callback) {
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  callback_ = callback;
482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  silence_detector_.Reset(kSamplingRate, AudioPacket::CHANNELS_STEREO);
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pipe_reader_->AddObserver(this);
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AudioCapturerLinux::Stop() {
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pipe_reader_->RemoveObserver(this);
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  callback_.Reset();
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool AudioCapturerLinux::IsStarted() {
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return !callback_.is_null();
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AudioCapturerLinux::OnDataRead(
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_refptr<base::RefCountedString> data) {
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!callback_.is_null());
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (silence_detector_.IsSilence(
672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          reinterpret_cast<const int16*>(data->data().data()),
682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          data->data().size() / sizeof(int16))) {
692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<AudioPacket> packet(new AudioPacket());
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  packet->add_data(data->data());
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  packet->set_encoding(AudioPacket::ENCODING_RAW);
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  packet->set_sampling_rate(kSamplingRate);
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  packet->set_bytes_per_sample(AudioPacket::BYTES_PER_SAMPLE_2);
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  packet->set_channels(AudioPacket::CHANNELS_STEREO);
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  callback_.Run(packet.Pass());
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool AudioCapturer::IsSupported() {
82868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  return g_pulseaudio_pipe_sink_reader.Get().get() != NULL;
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)scoped_ptr<AudioCapturer> AudioCapturer::Create() {
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_refptr<AudioPipeReader> reader =
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      g_pulseaudio_pipe_sink_reader.Get();
88868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (!reader.get())
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return scoped_ptr<AudioCapturer>();
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return scoped_ptr<AudioCapturer>(new AudioCapturerLinux(reader));
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace remoting
94