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