blob: 11c125f63748078254a0fbdba0b9c89c06d31ecb [file] [log] [blame]
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00001// 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.
4
5#include "content/renderer/media/webrtc_local_audio_renderer.h"
6
7#include "base/debug/trace_event.h"
8#include "base/logging.h"
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +01009#include "base/message_loop/message_loop_proxy.h"
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000010#include "base/synchronization/lock.h"
11#include "content/renderer/media/audio_device_factory.h"
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000012#include "content/renderer/media/webrtc_audio_capturer.h"
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +010013#include "content/renderer/render_thread_impl.h"
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +010014#include "media/audio/audio_output_device.h"
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000015#include "media/base/audio_bus.h"
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +010016#include "media/base/audio_fifo.h"
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +010017#include "media/base/audio_hardware_config.h"
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000018
19namespace content {
20
21// media::AudioRendererSink::RenderCallback implementation
22int WebRtcLocalAudioRenderer::Render(
23 media::AudioBus* audio_bus, int audio_delay_milliseconds) {
24 base::AutoLock auto_lock(thread_lock_);
25
26 if (!playing_) {
27 audio_bus->Zero();
28 return 0;
29 }
30
31 TRACE_EVENT0("audio", "WebRtcLocalAudioRenderer::Render");
32
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000033 DCHECK(loopback_fifo_.get() != NULL);
34
35 // Provide data by reading from the FIFO if the FIFO contains enough
36 // to fulfill the request.
37 if (loopback_fifo_->frames() >= audio_bus->frames()) {
38 loopback_fifo_->Consume(audio_bus, 0, audio_bus->frames());
39 } else {
40 audio_bus->Zero();
41 // This warning is perfectly safe if it happens for the first audio
42 // frames. It should not happen in a steady-state mode.
43 DVLOG(2) << "loopback FIFO is empty";
44 }
45
46 return audio_bus->frames();
47}
48
49void WebRtcLocalAudioRenderer::OnRenderError() {
50 NOTIMPLEMENTED();
51}
52
53// content::WebRtcAudioCapturerSink implementation
Ben Murdochbb1529c2013-08-08 10:24:53 +010054int WebRtcLocalAudioRenderer::CaptureData(const std::vector<int>& channels,
55 const int16* audio_data,
56 int sample_rate,
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000057 int number_of_channels,
58 int number_of_frames,
59 int audio_delay_milliseconds,
Ben Murdochbb1529c2013-08-08 10:24:53 +010060 int current_volume,
61 bool need_audio_processing) {
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000062 TRACE_EVENT0("audio", "WebRtcLocalAudioRenderer::CaptureData");
63 base::AutoLock auto_lock(thread_lock_);
64
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +010065 if (!playing_)
Ben Murdochbb1529c2013-08-08 10:24:53 +010066 return 0;
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000067
68 // Push captured audio to FIFO so it can be read by a local sink.
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +010069 if (loopback_fifo_) {
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000070 if (loopback_fifo_->frames() + number_of_frames <=
71 loopback_fifo_->max_frames()) {
72 scoped_ptr<media::AudioBus> audio_source = media::AudioBus::Create(
73 number_of_channels, number_of_frames);
74 audio_source->FromInterleaved(audio_data,
75 audio_source->frames(),
76 sizeof(audio_data[0]));
77 loopback_fifo_->Push(audio_source.get());
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +010078
79 base::Time now = base::Time::Now();
80 total_render_time_ += now - last_render_time_;
81 last_render_time_ = now;
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000082 } else {
83 DVLOG(1) << "FIFO is full";
84 }
85 }
Ben Murdochbb1529c2013-08-08 10:24:53 +010086
87 return 0;
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000088}
89
90void WebRtcLocalAudioRenderer::SetCaptureFormat(
91 const media::AudioParameters& params) {
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +010092 audio_params_ = params;
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000093}
94
95// WebRtcLocalAudioRenderer::WebRtcLocalAudioRenderer implementation.
96WebRtcLocalAudioRenderer::WebRtcLocalAudioRenderer(
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +010097 WebRtcLocalAudioTrack* audio_track,
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000098 int source_render_view_id)
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +010099 : audio_track_(audio_track),
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000100 source_render_view_id_(source_render_view_id),
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100101 playing_(false) {
102 DCHECK(audio_track);
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000103 DVLOG(1) << "WebRtcLocalAudioRenderer::WebRtcLocalAudioRenderer()";
104}
105
106WebRtcLocalAudioRenderer::~WebRtcLocalAudioRenderer() {
107 DCHECK(thread_checker_.CalledOnValidThread());
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100108 DCHECK(!sink_.get());
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000109 DVLOG(1) << "WebRtcLocalAudioRenderer::~WebRtcLocalAudioRenderer()";
110}
111
112void WebRtcLocalAudioRenderer::Start() {
113 DVLOG(1) << "WebRtcLocalAudioRenderer::Start()";
114 DCHECK(thread_checker_.CalledOnValidThread());
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100115 // Add this class as sink to the audio track to ensure that we receive
116 // WebRtcAudioCapturerSink::CaptureData() callbacks for captured audio.
117 // |audio_params_| will be updated right after the AddCapturerAudioTrack().
118 audio_track_->AddSink(this);
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000119
120 base::AutoLock auto_lock(thread_lock_);
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100121 DCHECK(!sink_.get());
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000122
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000123 // TODO(henrika): we could add a more dynamic solution here but I prefer
124 // a fixed size combined with bad audio at overflow. The alternative is
125 // that we start to build up latency and that can be more difficult to
126 // detect. Tests have shown that the FIFO never contains more than 2 or 3
127 // audio frames but I have selected a max size of ten buffers just
128 // in case since these tests were performed on a 16 core, 64GB Win 7
129 // machine. We could also add some sort of error notifier in this area if
130 // the FIFO overflows.
131 DCHECK(!loopback_fifo_);
132 loopback_fifo_.reset(new media::AudioFifo(
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100133 audio_params_.channels(), 10 * audio_params_.frames_per_buffer()));
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000134
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100135#if defined(OS_ANDROID)
136 media::AudioHardwareConfig* hardware_config =
137 RenderThreadImpl::current()->GetAudioHardwareConfig();
138#endif
139
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100140 media::AudioParameters sink_params(audio_params_.format(),
141 audio_params_.channel_layout(),
142 audio_params_.sample_rate(),
143 audio_params_.bits_per_sample(),
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100144#if defined(OS_ANDROID)
145 // On Android, input and output are using same sampling rate. In order to
146 // achieve low latency mode, we need use buffer size suggested by
147 // AudioManager for the sink paramters which will be used to decide
148 // buffer size for shared memory buffer.
149 hardware_config->GetOutputBufferSize()
150#else
151 2 * audio_params_.frames_per_buffer()
152#endif
153 );
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100154 sink_ = AudioDeviceFactory::NewOutputDevice(source_render_view_id_);
155
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000156 // TODO(henrika): we could utilize the unified audio here instead and do
157 // sink_->InitializeIO(sink_params, 2, callback_.get());
158 // It would then be possible to avoid using the WebRtcAudioCapturer.
159 sink_->Initialize(sink_params, this);
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000160
161 // Start the capturer and local rendering. Note that, the capturer is owned
162 // by the WebRTC ADM and might already bee running.
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000163 sink_->Start();
164
165 last_render_time_ = base::Time::Now();
166 playing_ = false;
167}
168
169void WebRtcLocalAudioRenderer::Stop() {
170 DVLOG(1) << "WebRtcLocalAudioRenderer::Stop()";
171 DCHECK(thread_checker_.CalledOnValidThread());
172
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100173 if (!sink_.get())
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000174 return;
175
176 {
177 base::AutoLock auto_lock(thread_lock_);
178 playing_ = false;
179
180 if (loopback_fifo_.get() != NULL) {
181 loopback_fifo_->Clear();
182 loopback_fifo_.reset();
183 }
184 }
185
186 // Stop the output audio stream, i.e, stop asking for data to render.
187 sink_->Stop();
188 sink_ = NULL;
189
190 // Ensure that the capturer stops feeding us with captured audio.
191 // Note that, we do not stop the capturer here since it may still be used by
192 // the WebRTC ADM.
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100193 audio_track_->RemoveSink(this);
194 audio_track_ = NULL;
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000195}
196
197void WebRtcLocalAudioRenderer::Play() {
198 DVLOG(1) << "WebRtcLocalAudioRenderer::Play()";
199 DCHECK(thread_checker_.CalledOnValidThread());
200 base::AutoLock auto_lock(thread_lock_);
201
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100202 if (!sink_.get())
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000203 return;
204
205 // Resumes rendering by ensuring that WebRtcLocalAudioRenderer::Render()
206 // now reads data from the local FIFO.
207 playing_ = true;
208 last_render_time_ = base::Time::Now();
209
210 if (loopback_fifo_)
211 loopback_fifo_->Clear();
212}
213
214void WebRtcLocalAudioRenderer::Pause() {
215 DVLOG(1) << "WebRtcLocalAudioRenderer::Pause()";
216 DCHECK(thread_checker_.CalledOnValidThread());
217 base::AutoLock auto_lock(thread_lock_);
218
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100219 if (!sink_.get())
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000220 return;
221
222 // Temporarily suspends rendering audio.
223 // WebRtcLocalAudioRenderer::Render() will return early during this state
224 // and only zeros will be provided to the active sink.
225 playing_ = false;
226}
227
228void WebRtcLocalAudioRenderer::SetVolume(float volume) {
229 DVLOG(1) << "WebRtcLocalAudioRenderer::SetVolume(" << volume << ")";
230 DCHECK(thread_checker_.CalledOnValidThread());
231 base::AutoLock auto_lock(thread_lock_);
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100232 if (sink_.get())
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000233 sink_->SetVolume(volume);
234}
235
236base::TimeDelta WebRtcLocalAudioRenderer::GetCurrentRenderTime() const {
237 DCHECK(thread_checker_.CalledOnValidThread());
238 base::AutoLock auto_lock(thread_lock_);
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100239 if (!sink_.get())
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000240 return base::TimeDelta();
241 return total_render_time();
242}
243
244bool WebRtcLocalAudioRenderer::IsLocalRenderer() const {
245 return true;
246}
247
248} // namespace content