Fix build break
[chromium-blink-merge.git] / content / renderer / media / webrtc_local_audio_renderer.cc
blobcc5ba771048fe41e710ce2ef80f8376f11022aae
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "content/renderer/media/webrtc_local_audio_renderer.h"
7 #include "base/debug/trace_event.h"
8 #include "base/logging.h"
9 #include "base/message_loop_proxy.h"
10 #include "base/synchronization/lock.h"
11 #include "content/renderer/media/audio_device_factory.h"
12 #include "content/renderer/media/renderer_audio_output_device.h"
13 #include "content/renderer/media/webrtc_audio_capturer.h"
14 #include "media/base/audio_bus.h"
16 namespace content {
18 // media::AudioRendererSink::RenderCallback implementation
19 int WebRtcLocalAudioRenderer::Render(
20 media::AudioBus* audio_bus, int audio_delay_milliseconds) {
21 base::AutoLock auto_lock(thread_lock_);
23 if (!playing_) {
24 audio_bus->Zero();
25 return 0;
28 TRACE_EVENT0("audio", "WebRtcLocalAudioRenderer::Render");
30 base::Time now = base::Time::Now();
31 total_render_time_ += now - last_render_time_;
32 last_render_time_ = now;
34 DCHECK(loopback_fifo_.get() != NULL);
36 // Provide data by reading from the FIFO if the FIFO contains enough
37 // to fulfill the request.
38 if (loopback_fifo_->frames() >= audio_bus->frames()) {
39 loopback_fifo_->Consume(audio_bus, 0, audio_bus->frames());
40 } else {
41 audio_bus->Zero();
42 // This warning is perfectly safe if it happens for the first audio
43 // frames. It should not happen in a steady-state mode.
44 DVLOG(2) << "loopback FIFO is empty";
47 return audio_bus->frames();
50 void WebRtcLocalAudioRenderer::OnRenderError() {
51 NOTIMPLEMENTED();
54 // content::WebRtcAudioCapturerSink implementation
55 void WebRtcLocalAudioRenderer::CaptureData(const int16* audio_data,
56 int number_of_channels,
57 int number_of_frames,
58 int audio_delay_milliseconds,
59 double volume) {
60 TRACE_EVENT0("audio", "WebRtcLocalAudioRenderer::CaptureData");
61 base::AutoLock auto_lock(thread_lock_);
63 if (!playing_ || !track_is_enabled_) {
64 return;
67 // Push captured audio to FIFO so it can be read by a local sink.
68 if (loopback_fifo_ && track_is_enabled_) {
69 if (loopback_fifo_->frames() + number_of_frames <=
70 loopback_fifo_->max_frames()) {
71 scoped_ptr<media::AudioBus> audio_source = media::AudioBus::Create(
72 number_of_channels, number_of_frames);
73 audio_source->FromInterleaved(audio_data,
74 audio_source->frames(),
75 sizeof(audio_data[0]));
76 loopback_fifo_->Push(audio_source.get());
77 } else {
78 DVLOG(1) << "FIFO is full";
83 void WebRtcLocalAudioRenderer::SetCaptureFormat(
84 const media::AudioParameters& params) {
85 NOTIMPLEMENTED() << "WebRtcLocalAudioRenderer::SetCaptureFormat()";
88 // webrtc::ObserverInterface implementation
89 void WebRtcLocalAudioRenderer::OnChanged() {
90 DVLOG(1) << "WebRtcLocalAudioRenderer::OnChanged()";
91 DCHECK(thread_checker_.CalledOnValidThread());
92 base::AutoLock auto_lock(thread_lock_);
93 track_is_enabled_ = audio_track_->enabled();
96 // WebRtcLocalAudioRenderer::WebRtcLocalAudioRenderer implementation.
97 WebRtcLocalAudioRenderer::WebRtcLocalAudioRenderer(
98 const scoped_refptr<WebRtcAudioCapturer>& source,
99 webrtc::AudioTrackInterface* audio_track,
100 int source_render_view_id)
101 : source_(source),
102 audio_track_(audio_track),
103 source_render_view_id_(source_render_view_id),
104 playing_(false),
105 track_is_enabled_(true) {
106 DVLOG(1) << "WebRtcLocalAudioRenderer::WebRtcLocalAudioRenderer()";
109 WebRtcLocalAudioRenderer::~WebRtcLocalAudioRenderer() {
110 DCHECK(thread_checker_.CalledOnValidThread());
111 DCHECK(!sink_);
112 DVLOG(1) << "WebRtcLocalAudioRenderer::~WebRtcLocalAudioRenderer()";
115 void WebRtcLocalAudioRenderer::Start() {
116 DVLOG(1) << "WebRtcLocalAudioRenderer::Start()";
117 DCHECK(thread_checker_.CalledOnValidThread());
118 DCHECK(source_);
120 if (audio_track_) {
121 audio_track_->RegisterObserver(this);
122 track_is_enabled_ = audio_track_->enabled();
125 base::AutoLock auto_lock(thread_lock_);
126 DCHECK(!sink_);
128 // Add this class as sink to the capturer to ensure that we receive
129 // WebRtcAudioCapturerSink::CaptureData() callbacks for captured audio.
130 source_->AddCapturerSink(this);
132 // Use the capturing source audio parameters when opening the output audio
133 // device. Any mismatch will be compensated for by the audio output back-end.
134 // Note that the buffer size is modified to make the full-duplex scheme less
135 // resource intensive. By doubling the buffer size (compared to the capture
136 // side), the callback frequency of browser side callbacks will be lower and
137 // tests have shown that it resolves issues with audio glitches for some
138 // cases where resampling is needed on the output side.
139 // TODO(henrika): verify this scheme on as many different devices and
140 // combinations of sample rates as possible
141 media::AudioParameters source_params = source_->audio_parameters();
143 // TODO(henrika): we could add a more dynamic solution here but I prefer
144 // a fixed size combined with bad audio at overflow. The alternative is
145 // that we start to build up latency and that can be more difficult to
146 // detect. Tests have shown that the FIFO never contains more than 2 or 3
147 // audio frames but I have selected a max size of ten buffers just
148 // in case since these tests were performed on a 16 core, 64GB Win 7
149 // machine. We could also add some sort of error notifier in this area if
150 // the FIFO overflows.
151 DCHECK(!loopback_fifo_);
152 loopback_fifo_.reset(new media::AudioFifo(
153 source_params.channels(),
154 10 * source_params.frames_per_buffer()));
156 media::AudioParameters sink_params(source_params.format(),
157 source_params.channel_layout(),
158 source_params.sample_rate(),
159 source_params.bits_per_sample(),
160 2 * source_params.frames_per_buffer());
161 sink_ = AudioDeviceFactory::NewOutputDevice();
162 // TODO(henrika): we could utilize the unified audio here instead and do
163 // sink_->InitializeIO(sink_params, 2, callback_.get());
164 // It would then be possible to avoid using the WebRtcAudioCapturer.
165 sink_->Initialize(sink_params, this);
166 sink_->SetSourceRenderView(source_render_view_id_);
168 // Start the capturer and local rendering. Note that, the capturer is owned
169 // by the WebRTC ADM and might already bee running.
170 source_->Start();
171 sink_->Start();
173 last_render_time_ = base::Time::Now();
174 playing_ = false;
177 void WebRtcLocalAudioRenderer::Stop() {
178 DVLOG(1) << "WebRtcLocalAudioRenderer::Stop()";
179 DCHECK(thread_checker_.CalledOnValidThread());
181 if (!sink_)
182 return;
185 base::AutoLock auto_lock(thread_lock_);
186 playing_ = false;
188 if (loopback_fifo_.get() != NULL) {
189 loopback_fifo_->Clear();
190 loopback_fifo_.reset();
194 // Stop the output audio stream, i.e, stop asking for data to render.
195 sink_->Stop();
196 sink_ = NULL;
198 // Ensure that the capturer stops feeding us with captured audio.
199 // Note that, we do not stop the capturer here since it may still be used by
200 // the WebRTC ADM.
201 source_->RemoveCapturerSink(this);
202 source_ = NULL;
204 if (audio_track_) {
205 audio_track_->UnregisterObserver(this);
206 audio_track_ = NULL;
210 void WebRtcLocalAudioRenderer::Play() {
211 DVLOG(1) << "WebRtcLocalAudioRenderer::Play()";
212 DCHECK(thread_checker_.CalledOnValidThread());
213 base::AutoLock auto_lock(thread_lock_);
215 if (!sink_)
216 return;
218 // Resumes rendering by ensuring that WebRtcLocalAudioRenderer::Render()
219 // now reads data from the local FIFO.
220 playing_ = true;
221 last_render_time_ = base::Time::Now();
223 if (loopback_fifo_)
224 loopback_fifo_->Clear();
227 void WebRtcLocalAudioRenderer::Pause() {
228 DVLOG(1) << "WebRtcLocalAudioRenderer::Pause()";
229 DCHECK(thread_checker_.CalledOnValidThread());
230 base::AutoLock auto_lock(thread_lock_);
232 if (!sink_)
233 return;
235 // Temporarily suspends rendering audio.
236 // WebRtcLocalAudioRenderer::Render() will return early during this state
237 // and only zeros will be provided to the active sink.
238 playing_ = false;
241 void WebRtcLocalAudioRenderer::SetVolume(float volume) {
242 DVLOG(1) << "WebRtcLocalAudioRenderer::SetVolume(" << volume << ")";
243 DCHECK(thread_checker_.CalledOnValidThread());
244 base::AutoLock auto_lock(thread_lock_);
245 if (sink_)
246 sink_->SetVolume(volume);
249 base::TimeDelta WebRtcLocalAudioRenderer::GetCurrentRenderTime() const {
250 DCHECK(thread_checker_.CalledOnValidThread());
251 base::AutoLock auto_lock(thread_lock_);
252 if (!sink_)
253 return base::TimeDelta();
254 return total_render_time();
257 bool WebRtcLocalAudioRenderer::IsLocalRenderer() const {
258 return true;
261 } // namespace content