Fix build break
[chromium-blink-merge.git] / content / renderer / media / webrtc_audio_renderer.cc
blobd5591d090a6267cd68fdb4e1b24839cbb833179d
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_audio_renderer.h"
7 #include "base/logging.h"
8 #include "base/metrics/histogram.h"
9 #include "base/string_util.h"
10 #include "content/renderer/media/audio_device_factory.h"
11 #include "content/renderer/media/renderer_audio_output_device.h"
12 #include "content/renderer/media/webrtc_audio_device_impl.h"
13 #include "content/renderer/render_thread_impl.h"
14 #include "media/audio/audio_parameters.h"
15 #include "media/audio/sample_rates.h"
16 #include "media/base/audio_hardware_config.h"
18 #if defined(OS_WIN)
19 #include "base/win/windows_version.h"
20 #include "media/audio/win/core_audio_util_win.h"
21 #endif
23 namespace content {
25 namespace {
27 // Supported hardware sample rates for output sides.
28 #if defined(OS_WIN) || defined(OS_MACOSX)
29 // AudioHardwareConfig::GetOutputSampleRate() asks the audio layer for its
30 // current sample rate (set by the user) on Windows and Mac OS X. The listed
31 // rates below adds restrictions and Initialize() will fail if the user selects
32 // any rate outside these ranges.
33 const int kValidOutputRates[] = {96000, 48000, 44100, 32000, 16000};
34 #elif defined(OS_LINUX) || defined(OS_OPENBSD)
35 const int kValidOutputRates[] = {48000, 44100};
36 #elif defined(OS_ANDROID)
37 // TODO(leozwang): We want to use native sampling rate on Android to achieve
38 // low latency, currently 16000 is used to work around audio problem on some
39 // Android devices.
40 const int kValidOutputRates[] = {48000, 44100, 16000};
41 #else
42 const int kValidOutputRates[] = {44100};
43 #endif
45 // TODO(xians): Merge the following code to WebRtcAudioCapturer, or remove.
46 enum AudioFramesPerBuffer {
47 k160,
48 k320,
49 k440, // WebRTC works internally with 440 audio frames at 44.1kHz.
50 k480,
51 k640,
52 k880,
53 k960,
54 k1440,
55 k1920,
56 kUnexpectedAudioBufferSize // Must always be last!
59 // Helper method to convert integral values to their respective enum values
60 // above, or kUnexpectedAudioBufferSize if no match exists.
61 AudioFramesPerBuffer AsAudioFramesPerBuffer(int frames_per_buffer) {
62 switch (frames_per_buffer) {
63 case 160: return k160;
64 case 320: return k320;
65 case 440: return k440;
66 case 480: return k480;
67 case 640: return k640;
68 case 880: return k880;
69 case 960: return k960;
70 case 1440: return k1440;
71 case 1920: return k1920;
73 return kUnexpectedAudioBufferSize;
76 void AddHistogramFramesPerBuffer(int param) {
77 AudioFramesPerBuffer afpb = AsAudioFramesPerBuffer(param);
78 if (afpb != kUnexpectedAudioBufferSize) {
79 UMA_HISTOGRAM_ENUMERATION("WebRTC.AudioOutputFramesPerBuffer",
80 afpb, kUnexpectedAudioBufferSize);
81 } else {
82 // Report unexpected sample rates using a unique histogram name.
83 UMA_HISTOGRAM_COUNTS("WebRTC.AudioOutputFramesPerBufferUnexpected", param);
87 } // namespace
89 WebRtcAudioRenderer::WebRtcAudioRenderer(int source_render_view_id)
90 : state_(UNINITIALIZED),
91 source_render_view_id_(source_render_view_id),
92 source_(NULL),
93 play_ref_count_(0),
94 audio_delay_milliseconds_(0),
95 frame_duration_milliseconds_(0),
96 fifo_io_ratio_(1) {
99 WebRtcAudioRenderer::~WebRtcAudioRenderer() {
100 DCHECK(thread_checker_.CalledOnValidThread());
101 DCHECK_EQ(state_, UNINITIALIZED);
102 buffer_.reset();
105 bool WebRtcAudioRenderer::Initialize(WebRtcAudioRendererSource* source) {
106 DVLOG(1) << "WebRtcAudioRenderer::Initialize()";
107 DCHECK(thread_checker_.CalledOnValidThread());
108 base::AutoLock auto_lock(lock_);
109 DCHECK_EQ(state_, UNINITIALIZED);
110 DCHECK(source);
111 DCHECK(!sink_);
112 DCHECK(!source_);
114 sink_ = AudioDeviceFactory::NewOutputDevice();
115 DCHECK(sink_);
117 // Use mono on all platforms but Windows for now.
118 // TODO(henrika): Tracking at http://crbug.com/166771.
119 media::ChannelLayout channel_layout = media::CHANNEL_LAYOUT_MONO;
120 #if defined(OS_WIN)
121 channel_layout = media::CHANNEL_LAYOUT_STEREO;
122 #endif
124 // Ask the renderer for the default audio output hardware sample-rate.
125 media::AudioHardwareConfig* hardware_config =
126 RenderThreadImpl::current()->GetAudioHardwareConfig();
127 int sample_rate = hardware_config->GetOutputSampleRate();
128 DVLOG(1) << "Audio output hardware sample rate: " << sample_rate;
129 UMA_HISTOGRAM_ENUMERATION("WebRTC.AudioOutputSampleRate",
130 sample_rate, media::kUnexpectedAudioSampleRate);
132 // Verify that the reported output hardware sample rate is supported
133 // on the current platform.
134 if (std::find(&kValidOutputRates[0],
135 &kValidOutputRates[0] + arraysize(kValidOutputRates),
136 sample_rate) ==
137 &kValidOutputRates[arraysize(kValidOutputRates)]) {
138 DLOG(ERROR) << sample_rate << " is not a supported output rate.";
139 return false;
142 // Set up audio parameters for the source, i.e., the WebRTC client.
143 // The WebRTC client only supports multiples of 10ms as buffer size where
144 // 10ms is preferred for lowest possible delay.
146 media::AudioParameters source_params;
147 int buffer_size = 0;
149 if (sample_rate % 8000 == 0) {
150 buffer_size = (sample_rate / 100);
151 } else if (sample_rate == 44100) {
152 // The resampler in WebRTC does not support 441 as input. We hard code
153 // the size to 440 (~0.9977ms) instead and rely on the internal jitter
154 // buffer in WebRTC to deal with the resulting drift.
155 // TODO(henrika): ensure that WebRTC supports 44100Hz and use 441 instead.
156 buffer_size = 440;
157 } else {
158 return false;
161 int channels = ChannelLayoutToChannelCount(channel_layout);
162 source_params.Reset(media::AudioParameters::AUDIO_PCM_LOW_LATENCY,
163 channel_layout, channels, 0,
164 sample_rate, 16, buffer_size);
166 // Set up audio parameters for the sink, i.e., the native audio output stream.
167 // We strive to open up using native parameters to achieve best possible
168 // performance and to ensure that no FIFO is needed on the browser side to
169 // match the client request. Any mismatch between the source and the sink is
170 // taken care of in this class instead using a pull FIFO.
172 media::AudioParameters sink_params;
174 buffer_size = hardware_config->GetOutputBufferSize();
175 sink_params.Reset(media::AudioParameters::AUDIO_PCM_LOW_LATENCY,
176 channel_layout, channels, 0, sample_rate, 16, buffer_size);
178 // Create a FIFO if re-buffering is required to match the source input with
179 // the sink request. The source acts as provider here and the sink as
180 // consumer.
181 if (source_params.frames_per_buffer() != sink_params.frames_per_buffer()) {
182 DVLOG(1) << "Rebuffering from " << source_params.frames_per_buffer()
183 << " to " << sink_params.frames_per_buffer();
184 audio_fifo_.reset(new media::AudioPullFifo(
185 source_params.channels(),
186 source_params.frames_per_buffer(),
187 base::Bind(
188 &WebRtcAudioRenderer::SourceCallback,
189 base::Unretained(this))));
191 // The I/O ratio is used in delay calculations where one scheme is used
192 // for |fifo_io_ratio_| > 1 and another scheme for < 1.0.
193 fifo_io_ratio_ = static_cast<double>(source_params.frames_per_buffer()) /
194 sink_params.frames_per_buffer();
197 frame_duration_milliseconds_ = base::Time::kMillisecondsPerSecond /
198 static_cast<double>(source_params.sample_rate());
200 // Allocate local audio buffers based on the parameters above.
201 // It is assumed that each audio sample contains 16 bits and each
202 // audio frame contains one or two audio samples depending on the
203 // number of channels.
204 buffer_.reset(
205 new int16[source_params.frames_per_buffer() * source_params.channels()]);
207 source_ = source;
208 source->SetRenderFormat(source_params);
210 // Configure the audio rendering client and start rendering.
211 sink_->Initialize(sink_params, this);
212 sink_->SetSourceRenderView(source_render_view_id_);
213 sink_->Start();
215 // User must call Play() before any audio can be heard.
216 state_ = PAUSED;
218 UMA_HISTOGRAM_ENUMERATION("WebRTC.AudioOutputChannelLayout",
219 source_params.channel_layout(),
220 media::CHANNEL_LAYOUT_MAX);
221 UMA_HISTOGRAM_ENUMERATION("WebRTC.AudioOutputFramesPerBuffer",
222 source_params.frames_per_buffer(),
223 kUnexpectedAudioBufferSize);
224 AddHistogramFramesPerBuffer(source_params.frames_per_buffer());
226 return true;
229 void WebRtcAudioRenderer::Start() {
230 // TODO(xians): refactor to make usage of Start/Stop more symmetric.
231 NOTIMPLEMENTED();
234 void WebRtcAudioRenderer::Play() {
235 DVLOG(1) << "WebRtcAudioRenderer::Play()";
236 DCHECK(thread_checker_.CalledOnValidThread());
237 base::AutoLock auto_lock(lock_);
238 if (state_ == UNINITIALIZED)
239 return;
241 DCHECK(play_ref_count_ == 0 || state_ == PLAYING);
242 ++play_ref_count_;
243 state_ = PLAYING;
245 if (audio_fifo_) {
246 audio_delay_milliseconds_ = 0;
247 audio_fifo_->Clear();
251 void WebRtcAudioRenderer::Pause() {
252 DVLOG(1) << "WebRtcAudioRenderer::Pause()";
253 DCHECK(thread_checker_.CalledOnValidThread());
254 base::AutoLock auto_lock(lock_);
255 if (state_ == UNINITIALIZED)
256 return;
258 DCHECK_EQ(state_, PLAYING);
259 DCHECK_GT(play_ref_count_, 0);
260 if (!--play_ref_count_)
261 state_ = PAUSED;
264 void WebRtcAudioRenderer::Stop() {
265 DVLOG(1) << "WebRtcAudioRenderer::Stop()";
266 DCHECK(thread_checker_.CalledOnValidThread());
267 base::AutoLock auto_lock(lock_);
268 if (state_ == UNINITIALIZED)
269 return;
271 source_->RemoveAudioRenderer(this);
272 source_ = NULL;
273 sink_->Stop();
274 state_ = UNINITIALIZED;
277 void WebRtcAudioRenderer::SetVolume(float volume) {
278 DCHECK(thread_checker_.CalledOnValidThread());
279 base::AutoLock auto_lock(lock_);
280 if (state_ == UNINITIALIZED)
281 return;
283 sink_->SetVolume(volume);
286 base::TimeDelta WebRtcAudioRenderer::GetCurrentRenderTime() const {
287 return base::TimeDelta();
290 bool WebRtcAudioRenderer::IsLocalRenderer() const {
291 return false;
294 int WebRtcAudioRenderer::Render(media::AudioBus* audio_bus,
295 int audio_delay_milliseconds) {
296 base::AutoLock auto_lock(lock_);
297 if (!source_)
298 return 0;
300 DVLOG(2) << "WebRtcAudioRenderer::Render()";
301 DVLOG(2) << "audio_delay_milliseconds: " << audio_delay_milliseconds;
303 if (fifo_io_ratio_ > 1.0)
304 audio_delay_milliseconds_ += audio_delay_milliseconds;
305 else
306 audio_delay_milliseconds_ = audio_delay_milliseconds;
308 if (audio_fifo_)
309 audio_fifo_->Consume(audio_bus, audio_bus->frames());
310 else
311 SourceCallback(0, audio_bus);
313 return (state_ == PLAYING) ? audio_bus->frames() : 0;
316 void WebRtcAudioRenderer::OnRenderError() {
317 NOTIMPLEMENTED();
318 LOG(ERROR) << "OnRenderError()";
321 // Called by AudioPullFifo when more data is necessary.
322 void WebRtcAudioRenderer::SourceCallback(
323 int fifo_frame_delay, media::AudioBus* audio_bus) {
324 DVLOG(2) << "WebRtcAudioRenderer::SourceCallback("
325 << fifo_frame_delay << ", "
326 << audio_bus->frames() << ")";
328 int output_delay_milliseconds = audio_delay_milliseconds_;
329 output_delay_milliseconds += frame_duration_milliseconds_ * fifo_frame_delay;
330 DVLOG(2) << "output_delay_milliseconds: " << output_delay_milliseconds;
332 // We need to keep render data for the |source_| regardless of |state_|,
333 // otherwise the data will be buffered up inside |source_|.
334 source_->RenderData(reinterpret_cast<uint8*>(buffer_.get()),
335 audio_bus->channels(), audio_bus->frames(),
336 output_delay_milliseconds);
338 if (fifo_io_ratio_ > 1.0)
339 audio_delay_milliseconds_ = 0;
341 // Avoid filling up the audio bus if we are not playing; instead
342 // return here and ensure that the returned value in Render() is 0.
343 if (state_ != PLAYING) {
344 audio_bus->Zero();
345 return;
348 // De-interleave each channel and convert to 32-bit floating-point
349 // with nominal range -1.0 -> +1.0 to match the callback format.
350 audio_bus->FromInterleaved(buffer_.get(),
351 audio_bus->frames(),
352 sizeof(buffer_[0]));
355 } // namespace content