12a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// found in the LICENSE file.
42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/renderer/media/webrtc_local_audio_renderer.h"
62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/debug/trace_event.h"
82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/logging.h"
9868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/message_loop/message_loop_proxy.h"
1068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)#include "base/metrics/histogram.h"
112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/synchronization/lock.h"
122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/renderer/media/audio_device_factory.h"
132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/renderer/media/webrtc_audio_capturer.h"
14c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "media/audio/audio_output_device.h"
152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "media/base/audio_bus.h"
1690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "media/base/audio_fifo.h"
172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace content {
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)namespace {
2168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
2268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)enum LocalRendererSinkStates {
2368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  kSinkStarted = 0,
2468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  kSinkNeverStarted,
2568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  kSinkStatesMax  // Must always be last!
2668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)};
2768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
2868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)}  // namespace
2968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// media::AudioRendererSink::RenderCallback implementation
312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)int WebRtcLocalAudioRenderer::Render(
322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    media::AudioBus* audio_bus, int audio_delay_milliseconds) {
3368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  TRACE_EVENT0("audio", "WebRtcLocalAudioRenderer::Render");
342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::AutoLock auto_lock(thread_lock_);
352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
36f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (!playing_ || !volume_ || !loopback_fifo_) {
372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    audio_bus->Zero();
382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return 0;
392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Provide data by reading from the FIFO if the FIFO contains enough
422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // to fulfill the request.
432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (loopback_fifo_->frames() >= audio_bus->frames()) {
442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    loopback_fifo_->Consume(audio_bus, 0, audio_bus->frames());
452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  } else {
462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    audio_bus->Zero();
472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // This warning is perfectly safe if it happens for the first audio
482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // frames. It should not happen in a steady-state mode.
492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    DVLOG(2) << "loopback FIFO is empty";
502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return audio_bus->frames();
532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void WebRtcLocalAudioRenderer::OnRenderError() {
562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  NOTIMPLEMENTED();
572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
59a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// content::MediaStreamAudioSink implementation
60a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)void WebRtcLocalAudioRenderer::OnData(const int16* audio_data,
61a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                      int sample_rate,
62a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                      int number_of_channels,
63a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                      int number_of_frames) {
64f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  DCHECK(capture_thread_checker_.CalledOnValidThread());
652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  TRACE_EVENT0("audio", "WebRtcLocalAudioRenderer::CaptureData");
662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::AutoLock auto_lock(thread_lock_);
67f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (!playing_ || !volume_ || !loopback_fifo_)
68a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    return;
692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Push captured audio to FIFO so it can be read by a local sink.
71f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (loopback_fifo_->frames() + number_of_frames <=
72f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      loopback_fifo_->max_frames()) {
73f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    scoped_ptr<media::AudioBus> audio_source = media::AudioBus::Create(
74f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        number_of_channels, number_of_frames);
75f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    audio_source->FromInterleaved(audio_data,
76f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                                  audio_source->frames(),
77f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                                  sizeof(audio_data[0]));
78f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    loopback_fifo_->Push(audio_source.get());
79f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
80f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    const base::TimeTicks now = base::TimeTicks::Now();
81f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    total_render_time_ += now - last_render_time_;
82f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    last_render_time_ = now;
83f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  } else {
84f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    DVLOG(1) << "FIFO is full";
852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
88a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)void WebRtcLocalAudioRenderer::OnSetFormat(
892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const media::AudioParameters& params) {
90a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  DVLOG(1) << "WebRtcLocalAudioRenderer::OnSetFormat()";
91f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // If the source is restarted, we might have changed to another capture
92f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // thread.
93f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  capture_thread_checker_.DetachFromThread();
94f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  DCHECK(capture_thread_checker_.CalledOnValidThread());
95f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
96f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // Reset the |source_params_|, |sink_params_| and |loopback_fifo_| to match
97f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // the new format.
98f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  {
99f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    base::AutoLock auto_lock(thread_lock_);
100f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    if (source_params_ == params)
101f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      return;
102f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
103f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    source_params_ = params;
104f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
105a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    sink_params_ = media::AudioParameters(source_params_.format(),
106a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        source_params_.channel_layout(), source_params_.channels(),
107a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        source_params_.input_channels(), source_params_.sample_rate(),
108a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        source_params_.bits_per_sample(),
109f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#if defined(OS_ANDROID)
110a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        // On Android, input and output use the same sample rate. In order to
111a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        // use the low latency mode, we need to use the buffer size suggested by
112a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        // the AudioManager for the sink.  It will later be used to decide
113a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        // the buffer size of the shared memory buffer.
114a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        frames_per_buffer_,
115f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#else
116a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        2 * source_params_.frames_per_buffer(),
117f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#endif
118a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        // If DUCKING is enabled on the source, it needs to be enabled on the
119a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        // sink as well.
120a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        source_params_.effects());
121f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
122f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // TODO(henrika): we could add a more dynamic solution here but I prefer
123f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // a fixed size combined with bad audio at overflow. The alternative is
124f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // that we start to build up latency and that can be more difficult to
125f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // detect. Tests have shown that the FIFO never contains more than 2 or 3
126f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // audio frames but I have selected a max size of ten buffers just
127f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // in case since these tests were performed on a 16 core, 64GB Win 7
128f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // machine. We could also add some sort of error notifier in this area if
129f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // the FIFO overflows.
130f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    loopback_fifo_.reset(new media::AudioFifo(
131f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        params.channels(), 10 * params.frames_per_buffer()));
132f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
133f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
134f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // Post a task on the main render thread to reconfigure the |sink_| with the
135f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // new format.
136f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  message_loop_->PostTask(
137f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      FROM_HERE,
138f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      base::Bind(&WebRtcLocalAudioRenderer::ReconfigureSink, this,
139f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                 params));
1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// WebRtcLocalAudioRenderer::WebRtcLocalAudioRenderer implementation.
1432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)WebRtcLocalAudioRenderer::WebRtcLocalAudioRenderer(
144a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    const blink::WebMediaStreamTrack& audio_track,
14558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    int source_render_view_id,
1465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    int source_render_frame_id,
14758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    int session_id,
14858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    int frames_per_buffer)
149c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    : audio_track_(audio_track),
1502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      source_render_view_id_(source_render_view_id),
1515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      source_render_frame_id_(source_render_frame_id),
15258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      session_id_(session_id),
153f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      message_loop_(base::MessageLoopProxy::current()),
15458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      playing_(false),
15568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      frames_per_buffer_(frames_per_buffer),
15668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      volume_(0.0),
15768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      sink_started_(false) {
1582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DVLOG(1) << "WebRtcLocalAudioRenderer::WebRtcLocalAudioRenderer()";
1592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)WebRtcLocalAudioRenderer::~WebRtcLocalAudioRenderer() {
162f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  DCHECK(message_loop_->BelongsToCurrentThread());
163868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  DCHECK(!sink_.get());
1642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DVLOG(1) << "WebRtcLocalAudioRenderer::~WebRtcLocalAudioRenderer()";
1652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void WebRtcLocalAudioRenderer::Start() {
1682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DVLOG(1) << "WebRtcLocalAudioRenderer::Start()";
169f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  DCHECK(message_loop_->BelongsToCurrentThread());
1702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
171f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // We get audio data from |audio_track_|...
172a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  MediaStreamAudioSink::AddToAudioTrack(this, audio_track_);
173f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // ...and |sink_| will get audio data from us.
174f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  DCHECK(!sink_.get());
1755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  sink_ = AudioDeviceFactory::NewOutputDevice(source_render_view_id_,
1765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                              source_render_frame_id_);
177c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
178f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  base::AutoLock auto_lock(thread_lock_);
179f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  last_render_time_ = base::TimeTicks::Now();
1802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  playing_ = false;
1812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void WebRtcLocalAudioRenderer::Stop() {
1842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DVLOG(1) << "WebRtcLocalAudioRenderer::Stop()";
185f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  DCHECK(message_loop_->BelongsToCurrentThread());
1862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  {
1882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::AutoLock auto_lock(thread_lock_);
1892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    playing_ = false;
190f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    loopback_fifo_.reset();
1912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Stop the output audio stream, i.e, stop asking for data to render.
19468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  // It is safer to call Stop() on the |sink_| to clean up the resources even
19568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  // when the |sink_| is never started.
196f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (sink_) {
197f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    sink_->Stop();
198f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    sink_ = NULL;
199f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
2002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
20168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  if (!sink_started_) {
20268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    UMA_HISTOGRAM_ENUMERATION("Media.LocalRendererSinkStates",
20368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                              kSinkNeverStarted, kSinkStatesMax);
20468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  }
205f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  sink_started_ = false;
20668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
2072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Ensure that the capturer stops feeding us with captured audio.
208a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  MediaStreamAudioSink::RemoveFromAudioTrack(this, audio_track_);
2092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void WebRtcLocalAudioRenderer::Play() {
2122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DVLOG(1) << "WebRtcLocalAudioRenderer::Play()";
213f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  DCHECK(message_loop_->BelongsToCurrentThread());
2142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
215868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (!sink_.get())
2162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
2172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
218f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  {
219f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    base::AutoLock auto_lock(thread_lock_);
220f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // Resumes rendering by ensuring that WebRtcLocalAudioRenderer::Render()
221f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // now reads data from the local FIFO.
222f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    playing_ = true;
223f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    last_render_time_ = base::TimeTicks::Now();
224f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
2252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
226f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // Note: If volume_ is currently muted, the |sink_| will not be started yet.
227f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  MaybeStartSink();
2282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void WebRtcLocalAudioRenderer::Pause() {
2312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DVLOG(1) << "WebRtcLocalAudioRenderer::Pause()";
232f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  DCHECK(message_loop_->BelongsToCurrentThread());
2332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
234868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (!sink_.get())
2352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
2362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
237f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  base::AutoLock auto_lock(thread_lock_);
2382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Temporarily suspends rendering audio.
2392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // WebRtcLocalAudioRenderer::Render() will return early during this state
2402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // and only zeros will be provided to the active sink.
2412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  playing_ = false;
2422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void WebRtcLocalAudioRenderer::SetVolume(float volume) {
2452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DVLOG(1) << "WebRtcLocalAudioRenderer::SetVolume(" << volume << ")";
246f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  DCHECK(message_loop_->BelongsToCurrentThread());
247f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
248f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  {
249f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    base::AutoLock auto_lock(thread_lock_);
250f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // Cache the volume.
251f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    volume_ = volume;
252f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
25368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
25468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  // Lazily start the |sink_| when the local renderer is unmuted during
25568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  // playing.
256f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  MaybeStartSink();
25768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
258868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (sink_.get())
2592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    sink_->SetVolume(volume);
2602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)base::TimeDelta WebRtcLocalAudioRenderer::GetCurrentRenderTime() const {
263f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  DCHECK(message_loop_->BelongsToCurrentThread());
2642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::AutoLock auto_lock(thread_lock_);
265868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (!sink_.get())
2662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return base::TimeDelta();
2672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return total_render_time();
2682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool WebRtcLocalAudioRenderer::IsLocalRenderer() const {
2712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return true;
2722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
274f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void WebRtcLocalAudioRenderer::MaybeStartSink() {
275f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  DCHECK(message_loop_->BelongsToCurrentThread());
276f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  DVLOG(1) << "WebRtcLocalAudioRenderer::MaybeStartSink()";
277f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
278f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (!sink_.get() || !source_params_.IsValid())
27968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    return;
28068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
281f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  base::AutoLock auto_lock(thread_lock_);
282f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
283f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // Clear up the old data in the FIFO.
284f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  loopback_fifo_->Clear();
285f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
286f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (!sink_params_.IsValid() || !playing_ || !volume_ || sink_started_)
287f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return;
288f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
289f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  DVLOG(1) << "WebRtcLocalAudioRenderer::MaybeStartSink() -- Starting sink_.";
290cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  sink_->InitializeWithSessionId(sink_params_, this, session_id_);
29168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  sink_->Start();
29268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  sink_started_ = true;
29368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  UMA_HISTOGRAM_ENUMERATION("Media.LocalRendererSinkStates",
29468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                            kSinkStarted, kSinkStatesMax);
29568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)}
29668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
297f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void WebRtcLocalAudioRenderer::ReconfigureSink(
298f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    const media::AudioParameters& params) {
299f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  DCHECK(message_loop_->BelongsToCurrentThread());
300f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
301f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  DVLOG(1) << "WebRtcLocalAudioRenderer::ReconfigureSink()";
302f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
303f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (!sink_)
304f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return;  // WebRtcLocalAudioRenderer has not yet been started.
305f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
306f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // Stop |sink_| and re-create a new one to be initialized with different audio
307f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // parameters.  Then, invoke MaybeStartSink() to restart everything again.
308f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (sink_started_) {
309f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    sink_->Stop();
310f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    sink_started_ = false;
311f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
3125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  sink_ = AudioDeviceFactory::NewOutputDevice(source_render_view_id_,
3135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                              source_render_frame_id_);
314f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  MaybeStartSink();
315f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
316f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
3172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace content
318