Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(506)

Side by Side Diff: content/renderer/media/webrtc_audio_renderer.cc

Issue 139303016: Feed the render data to MediaStreamAudioProcessor and used AudioBus in render callback (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: checked echo_control_mobile()->is_enabled()) for android and ios Created 6 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "content/renderer/media/webrtc_audio_renderer.h" 5 #include "content/renderer/media/webrtc_audio_renderer.h"
6 6
7 #include "base/logging.h" 7 #include "base/logging.h"
8 #include "base/metrics/histogram.h" 8 #include "base/metrics/histogram.h"
9 #include "base/strings/string_util.h" 9 #include "base/strings/string_util.h"
10 #include "base/strings/stringprintf.h" 10 #include "base/strings/stringprintf.h"
(...skipping 182 matching lines...) Expand 10 before | Expand all | Expand 10 after
193 : state_(UNINITIALIZED), 193 : state_(UNINITIALIZED),
194 source_render_view_id_(source_render_view_id), 194 source_render_view_id_(source_render_view_id),
195 source_render_frame_id_(source_render_frame_id), 195 source_render_frame_id_(source_render_frame_id),
196 session_id_(session_id), 196 session_id_(session_id),
197 media_stream_(media_stream), 197 media_stream_(media_stream),
198 source_(NULL), 198 source_(NULL),
199 play_ref_count_(0), 199 play_ref_count_(0),
200 start_ref_count_(0), 200 start_ref_count_(0),
201 audio_delay_milliseconds_(0), 201 audio_delay_milliseconds_(0),
202 fifo_delay_milliseconds_(0), 202 fifo_delay_milliseconds_(0),
203 sample_rate_(sample_rate), 203 sink_params_(media::AudioParameters::AUDIO_PCM_LOW_LATENCY,
204 frames_per_buffer_(frames_per_buffer) { 204 media::CHANNEL_LAYOUT_STEREO, sample_rate, 16,
205 frames_per_buffer) {
205 WebRtcLogMessage(base::StringPrintf( 206 WebRtcLogMessage(base::StringPrintf(
206 "WAR::WAR. source_render_view_id=%d" 207 "WAR::WAR. source_render_view_id=%d"
207 ", session_id=%d, sample_rate=%d, frames_per_buffer=%d", 208 ", session_id=%d, sample_rate=%d, frames_per_buffer=%d",
208 source_render_view_id, 209 source_render_view_id,
209 session_id, 210 session_id,
210 sample_rate, 211 sample_rate,
211 frames_per_buffer)); 212 frames_per_buffer));
212 } 213 }
213 214
214 WebRtcAudioRenderer::~WebRtcAudioRenderer() { 215 WebRtcAudioRenderer::~WebRtcAudioRenderer() {
215 DCHECK(thread_checker_.CalledOnValidThread()); 216 DCHECK(thread_checker_.CalledOnValidThread());
216 DCHECK_EQ(state_, UNINITIALIZED); 217 DCHECK_EQ(state_, UNINITIALIZED);
217 buffer_.reset();
218 } 218 }
219 219
220 bool WebRtcAudioRenderer::Initialize(WebRtcAudioRendererSource* source) { 220 bool WebRtcAudioRenderer::Initialize(WebRtcAudioRendererSource* source) {
221 DVLOG(1) << "WebRtcAudioRenderer::Initialize()"; 221 DVLOG(1) << "WebRtcAudioRenderer::Initialize()";
222 DCHECK(thread_checker_.CalledOnValidThread()); 222 DCHECK(thread_checker_.CalledOnValidThread());
223 base::AutoLock auto_lock(lock_); 223 base::AutoLock auto_lock(lock_);
224 DCHECK_EQ(state_, UNINITIALIZED); 224 DCHECK_EQ(state_, UNINITIALIZED);
225 DCHECK(source); 225 DCHECK(source);
226 DCHECK(!sink_.get()); 226 DCHECK(!sink_.get());
227 DCHECK(!source_); 227 DCHECK(!source_);
228 228
229 // Use stereo output on all platforms.
230 media::ChannelLayout channel_layout = media::CHANNEL_LAYOUT_STEREO;
231
232 // TODO(tommi,henrika): Maybe we should just change |sample_rate_| to be
233 // immutable and change its value instead of using a temporary?
234 int sample_rate = sample_rate_;
235 DVLOG(1) << "Audio output hardware sample rate: " << sample_rate;
236
237 // WebRTC does not yet support higher rates than 96000 on the client side 229 // WebRTC does not yet support higher rates than 96000 on the client side
238 // and 48000 is the preferred sample rate. Therefore, if 192000 is detected, 230 // and 48000 is the preferred sample rate. Therefore, if 192000 is detected,
239 // we change the rate to 48000 instead. The consequence is that the native 231 // we change the rate to 48000 instead. The consequence is that the native
240 // layer will be opened up at 192kHz but WebRTC will provide data at 48kHz 232 // layer will be opened up at 192kHz but WebRTC will provide data at 48kHz
241 // which will then be resampled by the audio converted on the browser side 233 // which will then be resampled by the audio converted on the browser side
242 // to match the native audio layer. 234 // to match the native audio layer.
235 int sample_rate = sink_params_.sample_rate();
236 DVLOG(1) << "Audio output hardware sample rate: " << sample_rate;
243 if (sample_rate == 192000) { 237 if (sample_rate == 192000) {
244 DVLOG(1) << "Resampling from 48000 to 192000 is required"; 238 DVLOG(1) << "Resampling from 48000 to 192000 is required";
245 sample_rate = 48000; 239 sample_rate = 48000;
246 } 240 }
247 media::AudioSampleRate asr = media::AsAudioSampleRate(sample_rate); 241 media::AudioSampleRate asr = media::AsAudioSampleRate(sample_rate);
248 if (asr != media::kUnexpectedAudioSampleRate) { 242 if (asr != media::kUnexpectedAudioSampleRate) {
249 UMA_HISTOGRAM_ENUMERATION( 243 UMA_HISTOGRAM_ENUMERATION(
250 "WebRTC.AudioOutputSampleRate", asr, media::kUnexpectedAudioSampleRate); 244 "WebRTC.AudioOutputSampleRate", asr, media::kUnexpectedAudioSampleRate);
251 } else { 245 } else {
252 UMA_HISTOGRAM_COUNTS("WebRTC.AudioOutputSampleRateUnexpected", sample_rate); 246 UMA_HISTOGRAM_COUNTS("WebRTC.AudioOutputSampleRateUnexpected",
247 sample_rate);
253 } 248 }
254 249
255 // Verify that the reported output hardware sample rate is supported 250 // Verify that the reported output hardware sample rate is supported
256 // on the current platform. 251 // on the current platform.
257 if (std::find(&kValidOutputRates[0], 252 if (std::find(&kValidOutputRates[0],
258 &kValidOutputRates[0] + arraysize(kValidOutputRates), 253 &kValidOutputRates[0] + arraysize(kValidOutputRates),
259 sample_rate) == 254 sample_rate) ==
260 &kValidOutputRates[arraysize(kValidOutputRates)]) { 255 &kValidOutputRates[arraysize(kValidOutputRates)]) {
261 DLOG(ERROR) << sample_rate << " is not a supported output rate."; 256 DLOG(ERROR) << sample_rate << " is not a supported output rate.";
262 return false; 257 return false;
263 } 258 }
264 259
265 // Set up audio parameters for the source, i.e., the WebRTC client. 260 // Set up audio parameters for the source, i.e., the WebRTC client.
266 261
267 // The WebRTC client only supports multiples of 10ms as buffer size where 262 // The WebRTC client only supports multiples of 10ms as buffer size where
268 // 10ms is preferred for lowest possible delay. 263 // 10ms is preferred for lowest possible delay.
269 media::AudioParameters source_params; 264 media::AudioParameters source_params;
270 int buffer_size = (sample_rate / 100); 265 const int frames_per_10ms = (sample_rate / 100);
271 DVLOG(1) << "Using WebRTC output buffer size: " << buffer_size; 266 DVLOG(1) << "Using WebRTC output buffer size: " << frames_per_10ms;
272 267
273 int channels = ChannelLayoutToChannelCount(channel_layout);
274 source_params.Reset(media::AudioParameters::AUDIO_PCM_LOW_LATENCY, 268 source_params.Reset(media::AudioParameters::AUDIO_PCM_LOW_LATENCY,
275 channel_layout, channels, 0, 269 sink_params_.channel_layout(), sink_params_.channels(), 0,
276 sample_rate, 16, buffer_size); 270 sample_rate, 16, frames_per_10ms);
277 271
278 // Set up audio parameters for the sink, i.e., the native audio output stream. 272 // Update audio parameters for the sink, i.e., the native audio output stream.
279 // We strive to open up using native parameters to achieve best possible 273 // We strive to open up using native parameters to achieve best possible
280 // performance and to ensure that no FIFO is needed on the browser side to 274 // performance and to ensure that no FIFO is needed on the browser side to
281 // match the client request. Any mismatch between the source and the sink is 275 // match the client request. Any mismatch between the source and the sink is
282 // taken care of in this class instead using a pull FIFO. 276 // taken care of in this class instead using a pull FIFO.
283 277
284 media::AudioParameters sink_params; 278 // Use native output size as default.
285 279 int frames_per_buffer = sink_params_.frames_per_buffer();
286 // Use native output siz as default.
287 buffer_size = frames_per_buffer_;
288 #if defined(OS_ANDROID) 280 #if defined(OS_ANDROID)
289 // TODO(henrika): Keep tuning this scheme and espcicially for low-latency 281 // TODO(henrika): Keep tuning this scheme and espcicially for low-latency
290 // cases. Might not be possible to come up with the perfect solution using 282 // cases. Might not be possible to come up with the perfect solution using
291 // the render side only. 283 // the render side only.
292 const int frames_per_10ms = (sample_rate / 100); 284 if (frames_per_buffer < 2 * frames_per_10ms) {
293 if (buffer_size < 2 * frames_per_10ms) {
294 // Examples of low-latency frame sizes and the resulting |buffer_size|: 285 // Examples of low-latency frame sizes and the resulting |buffer_size|:
295 // Nexus 7 : 240 audio frames => 2*480 = 960 286 // Nexus 7 : 240 audio frames => 2*480 = 960
296 // Nexus 10 : 256 => 2*441 = 882 287 // Nexus 10 : 256 => 2*441 = 882
297 // Galaxy Nexus: 144 => 2*441 = 882 288 // Galaxy Nexus: 144 => 2*441 = 882
298 buffer_size = 2 * frames_per_10ms; 289 frames_per_buffer = 2 * frames_per_10ms;
299 DVLOG(1) << "Low-latency output detected on Android"; 290 DVLOG(1) << "Low-latency output detected on Android";
300 } 291 }
301 #endif 292 #endif
302 DVLOG(1) << "Using sink output buffer size: " << buffer_size; 293 DVLOG(1) << "Using sink output buffer size: " << frames_per_buffer;
303 294
304 sink_params.Reset(media::AudioParameters::AUDIO_PCM_LOW_LATENCY, 295 sink_params_.Reset(sink_params_.format(), sink_params_.channel_layout(),
305 channel_layout, channels, 0, sample_rate, 16, buffer_size); 296 sink_params_.channels(), 0, sample_rate, 16,
297 frames_per_buffer);
306 298
307 // Create a FIFO if re-buffering is required to match the source input with 299 // Create a FIFO if re-buffering is required to match the source input with
308 // the sink request. The source acts as provider here and the sink as 300 // the sink request. The source acts as provider here and the sink as
309 // consumer. 301 // consumer.
310 fifo_delay_milliseconds_ = 0; 302 fifo_delay_milliseconds_ = 0;
311 if (source_params.frames_per_buffer() != sink_params.frames_per_buffer()) { 303 if (source_params.frames_per_buffer() != sink_params_.frames_per_buffer()) {
312 DVLOG(1) << "Rebuffering from " << source_params.frames_per_buffer() 304 DVLOG(1) << "Rebuffering from " << source_params.frames_per_buffer()
313 << " to " << sink_params.frames_per_buffer(); 305 << " to " << sink_params_.frames_per_buffer();
314 audio_fifo_.reset(new media::AudioPullFifo( 306 audio_fifo_.reset(new media::AudioPullFifo(
315 source_params.channels(), 307 source_params.channels(),
316 source_params.frames_per_buffer(), 308 source_params.frames_per_buffer(),
317 base::Bind( 309 base::Bind(
318 &WebRtcAudioRenderer::SourceCallback, 310 &WebRtcAudioRenderer::SourceCallback,
319 base::Unretained(this)))); 311 base::Unretained(this))));
320 312
321 if (sink_params.frames_per_buffer() > source_params.frames_per_buffer()) { 313 if (sink_params_.frames_per_buffer() > source_params.frames_per_buffer()) {
322 int frame_duration_milliseconds = base::Time::kMillisecondsPerSecond / 314 int frame_duration_milliseconds = base::Time::kMillisecondsPerSecond /
323 static_cast<double>(source_params.sample_rate()); 315 static_cast<double>(source_params.sample_rate());
324 fifo_delay_milliseconds_ = (sink_params.frames_per_buffer() - 316 fifo_delay_milliseconds_ = (sink_params_.frames_per_buffer() -
325 source_params.frames_per_buffer()) * frame_duration_milliseconds; 317 source_params.frames_per_buffer()) * frame_duration_milliseconds;
326 } 318 }
327 } 319 }
328 320
329 // Allocate local audio buffers based on the parameters above.
330 // It is assumed that each audio sample contains 16 bits and each
331 // audio frame contains one or two audio samples depending on the
332 // number of channels.
333 buffer_.reset(
334 new int16[source_params.frames_per_buffer() * source_params.channels()]);
335
336 source_ = source; 321 source_ = source;
337 source->SetRenderFormat(source_params);
338 322
339 // Configure the audio rendering client and start rendering. 323 // Configure the audio rendering client and start rendering.
340 sink_ = AudioDeviceFactory::NewOutputDevice( 324 sink_ = AudioDeviceFactory::NewOutputDevice(
341 source_render_view_id_, source_render_frame_id_); 325 source_render_view_id_, source_render_frame_id_);
342 326
343 // TODO(tommi): Rename InitializeUnifiedStream to rather reflect association 327 // TODO(tommi): Rename InitializeUnifiedStream to rather reflect association
344 // with a session. 328 // with a session.
345 DCHECK_GE(session_id_, 0); 329 DCHECK_GE(session_id_, 0);
346 sink_->InitializeUnifiedStream(sink_params, this, session_id_); 330 sink_->InitializeUnifiedStream(sink_params_, this, session_id_);
347 331
348 sink_->Start(); 332 sink_->Start();
349 333
350 // User must call Play() before any audio can be heard. 334 // User must call Play() before any audio can be heard.
351 state_ = PAUSED; 335 state_ = PAUSED;
352 336
353 UMA_HISTOGRAM_ENUMERATION("WebRTC.AudioOutputChannelLayout", 337 UMA_HISTOGRAM_ENUMERATION("WebRTC.AudioOutputChannelLayout",
354 source_params.channel_layout(), 338 source_params.channel_layout(),
355 media::CHANNEL_LAYOUT_MAX); 339 media::CHANNEL_LAYOUT_MAX);
356 UMA_HISTOGRAM_ENUMERATION("WebRTC.AudioOutputFramesPerBuffer", 340 UMA_HISTOGRAM_ENUMERATION("WebRTC.AudioOutputFramesPerBuffer",
(...skipping 151 matching lines...) Expand 10 before | Expand all | Expand 10 after
508 DVLOG(2) << "WebRtcAudioRenderer::SourceCallback(" 492 DVLOG(2) << "WebRtcAudioRenderer::SourceCallback("
509 << fifo_frame_delay << ", " 493 << fifo_frame_delay << ", "
510 << audio_bus->frames() << ")"; 494 << audio_bus->frames() << ")";
511 495
512 int output_delay_milliseconds = audio_delay_milliseconds_; 496 int output_delay_milliseconds = audio_delay_milliseconds_;
513 output_delay_milliseconds += fifo_delay_milliseconds_; 497 output_delay_milliseconds += fifo_delay_milliseconds_;
514 DVLOG(2) << "output_delay_milliseconds: " << output_delay_milliseconds; 498 DVLOG(2) << "output_delay_milliseconds: " << output_delay_milliseconds;
515 499
516 // We need to keep render data for the |source_| regardless of |state_|, 500 // We need to keep render data for the |source_| regardless of |state_|,
517 // otherwise the data will be buffered up inside |source_|. 501 // otherwise the data will be buffered up inside |source_|.
518 source_->RenderData(reinterpret_cast<uint8*>(buffer_.get()), 502 source_->RenderData(audio_bus, sink_params_.sample_rate(),
519 audio_bus->channels(), audio_bus->frames(),
520 output_delay_milliseconds); 503 output_delay_milliseconds);
521 504
522 // Avoid filling up the audio bus if we are not playing; instead 505 // Avoid filling up the audio bus if we are not playing; instead
523 // return here and ensure that the returned value in Render() is 0. 506 // return here and ensure that the returned value in Render() is 0.
524 if (state_ != PLAYING) { 507 if (state_ != PLAYING)
525 audio_bus->Zero(); 508 audio_bus->Zero();
526 return;
527 }
528
529 // De-interleave each channel and convert to 32-bit floating-point
530 // with nominal range -1.0 -> +1.0 to match the callback format.
531 audio_bus->FromInterleaved(buffer_.get(),
532 audio_bus->frames(),
533 sizeof(buffer_[0]));
534 } 509 }
535 510
536 void WebRtcAudioRenderer::UpdateSourceVolume( 511 void WebRtcAudioRenderer::UpdateSourceVolume(
537 webrtc::AudioSourceInterface* source) { 512 webrtc::AudioSourceInterface* source) {
538 DCHECK(thread_checker_.CalledOnValidThread()); 513 DCHECK(thread_checker_.CalledOnValidThread());
539 514
540 // Note: If there are no playing audio renderers, then the volume will be 515 // Note: If there are no playing audio renderers, then the volume will be
541 // set to 0.0. 516 // set to 0.0.
542 float volume = 0.0f; 517 float volume = 0.0f;
543 518
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after
611 if (RemovePlayingState(source, state)) 586 if (RemovePlayingState(source, state))
612 EnterPauseState(); 587 EnterPauseState();
613 } else if (AddPlayingState(source, state)) { 588 } else if (AddPlayingState(source, state)) {
614 EnterPlayState(); 589 EnterPlayState();
615 } 590 }
616 UpdateSourceVolume(source); 591 UpdateSourceVolume(source);
617 } 592 }
618 } 593 }
619 594
620 } // namespace content 595 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698