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

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: rebased and added check the thread check on the destructor 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 183 matching lines...) Expand 10 before | Expand all | Expand 10 after
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 sample_rate_(sample_rate),
204 number_of_channels_(0),
204 frames_per_buffer_(frames_per_buffer) { 205 frames_per_buffer_(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. 229 // Use stereo output on all platforms.
230 media::ChannelLayout channel_layout = media::CHANNEL_LAYOUT_STEREO; 230 media::ChannelLayout channel_layout = media::CHANNEL_LAYOUT_STEREO;
231 231
232 // TODO(tommi,henrika): Maybe we should just change |sample_rate_| to be 232 DVLOG(1) << "Audio output hardware sample rate: " << sample_rate_;
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 233
237 // WebRTC does not yet support higher rates than 96000 on the client side 234 // 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, 235 // 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 236 // 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 237 // 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 238 // which will then be resampled by the audio converted on the browser side
242 // to match the native audio layer. 239 // to match the native audio layer.
243 if (sample_rate == 192000) { 240 if (sample_rate_ == 192000) {
244 DVLOG(1) << "Resampling from 48000 to 192000 is required"; 241 DVLOG(1) << "Resampling from 48000 to 192000 is required";
245 sample_rate = 48000; 242 sample_rate_ = 48000;
246 } 243 }
247 media::AudioSampleRate asr = media::AsAudioSampleRate(sample_rate); 244 media::AudioSampleRate asr = media::AsAudioSampleRate(sample_rate_);
248 if (asr != media::kUnexpectedAudioSampleRate) { 245 if (asr != media::kUnexpectedAudioSampleRate) {
249 UMA_HISTOGRAM_ENUMERATION( 246 UMA_HISTOGRAM_ENUMERATION(
250 "WebRTC.AudioOutputSampleRate", asr, media::kUnexpectedAudioSampleRate); 247 "WebRTC.AudioOutputSampleRate", asr, media::kUnexpectedAudioSampleRate);
251 } else { 248 } else {
252 UMA_HISTOGRAM_COUNTS("WebRTC.AudioOutputSampleRateUnexpected", sample_rate); 249 UMA_HISTOGRAM_COUNTS("WebRTC.AudioOutputSampleRateUnexpected",
250 sample_rate_);
253 } 251 }
254 252
255 // Verify that the reported output hardware sample rate is supported 253 // Verify that the reported output hardware sample rate is supported
256 // on the current platform. 254 // on the current platform.
257 if (std::find(&kValidOutputRates[0], 255 if (std::find(&kValidOutputRates[0],
258 &kValidOutputRates[0] + arraysize(kValidOutputRates), 256 &kValidOutputRates[0] + arraysize(kValidOutputRates),
259 sample_rate) == 257 sample_rate_) ==
260 &kValidOutputRates[arraysize(kValidOutputRates)]) { 258 &kValidOutputRates[arraysize(kValidOutputRates)]) {
261 DLOG(ERROR) << sample_rate << " is not a supported output rate."; 259 DLOG(ERROR) << sample_rate_ << " is not a supported output rate.";
262 return false; 260 return false;
263 } 261 }
264 262
265 // Set up audio parameters for the source, i.e., the WebRTC client. 263 // Set up audio parameters for the source, i.e., the WebRTC client.
266 264
267 // The WebRTC client only supports multiples of 10ms as buffer size where 265 // The WebRTC client only supports multiples of 10ms as buffer size where
268 // 10ms is preferred for lowest possible delay. 266 // 10ms is preferred for lowest possible delay.
269 media::AudioParameters source_params; 267 media::AudioParameters source_params;
270 int buffer_size = (sample_rate / 100); 268 const int frames_per_10ms = (sample_rate_ / 100);
271 DVLOG(1) << "Using WebRTC output buffer size: " << buffer_size; 269 DVLOG(1) << "Using WebRTC output buffer size: " << frames_per_10ms;
272 270
273 int channels = ChannelLayoutToChannelCount(channel_layout); 271 number_of_channels_ = ChannelLayoutToChannelCount(channel_layout);
274 source_params.Reset(media::AudioParameters::AUDIO_PCM_LOW_LATENCY, 272 source_params.Reset(media::AudioParameters::AUDIO_PCM_LOW_LATENCY,
275 channel_layout, channels, 0, 273 channel_layout, number_of_channels_, 0,
276 sample_rate, 16, buffer_size); 274 sample_rate_, 16, frames_per_10ms);
277 275
278 // Set up audio parameters for the sink, i.e., the native audio output stream. 276 // Set up 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 277 // 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 278 // 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 279 // 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. 280 // taken care of in this class instead using a pull FIFO.
283 281
284 media::AudioParameters sink_params; 282 media::AudioParameters sink_params;
285 283
286 // Use native output siz as default. 284 // Use native output size as default.
287 buffer_size = frames_per_buffer_;
288 #if defined(OS_ANDROID) 285 #if defined(OS_ANDROID)
289 // TODO(henrika): Keep tuning this scheme and espcicially for low-latency 286 // 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 287 // cases. Might not be possible to come up with the perfect solution using
291 // the render side only. 288 // the render side only.
292 const int frames_per_10ms = (sample_rate / 100); 289 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|: 290 // Examples of low-latency frame sizes and the resulting |buffer_size|:
295 // Nexus 7 : 240 audio frames => 2*480 = 960 291 // Nexus 7 : 240 audio frames => 2*480 = 960
296 // Nexus 10 : 256 => 2*441 = 882 292 // Nexus 10 : 256 => 2*441 = 882
297 // Galaxy Nexus: 144 => 2*441 = 882 293 // Galaxy Nexus: 144 => 2*441 = 882
298 buffer_size = 2 * frames_per_10ms; 294 frames_per_buffer_ = 2 * frames_per_10ms;
299 DVLOG(1) << "Low-latency output detected on Android"; 295 DVLOG(1) << "Low-latency output detected on Android";
300 } 296 }
301 #endif 297 #endif
302 DVLOG(1) << "Using sink output buffer size: " << buffer_size; 298 DVLOG(1) << "Using sink output buffer size: " << frames_per_buffer_;
303 299
304 sink_params.Reset(media::AudioParameters::AUDIO_PCM_LOW_LATENCY, 300 sink_params.Reset(media::AudioParameters::AUDIO_PCM_LOW_LATENCY,
305 channel_layout, channels, 0, sample_rate, 16, buffer_size); 301 channel_layout, number_of_channels_, 0, sample_rate_, 16,
302 frames_per_buffer_);
306 303
307 // Create a FIFO if re-buffering is required to match the source input with 304 // 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 305 // the sink request. The source acts as provider here and the sink as
309 // consumer. 306 // consumer.
310 fifo_delay_milliseconds_ = 0; 307 fifo_delay_milliseconds_ = 0;
311 if (source_params.frames_per_buffer() != sink_params.frames_per_buffer()) { 308 if (source_params.frames_per_buffer() != sink_params.frames_per_buffer()) {
312 DVLOG(1) << "Rebuffering from " << source_params.frames_per_buffer() 309 DVLOG(1) << "Rebuffering from " << source_params.frames_per_buffer()
313 << " to " << sink_params.frames_per_buffer(); 310 << " to " << sink_params.frames_per_buffer();
314 audio_fifo_.reset(new media::AudioPullFifo( 311 audio_fifo_.reset(new media::AudioPullFifo(
315 source_params.channels(), 312 source_params.channels(),
316 source_params.frames_per_buffer(), 313 source_params.frames_per_buffer(),
317 base::Bind( 314 base::Bind(
318 &WebRtcAudioRenderer::SourceCallback, 315 &WebRtcAudioRenderer::SourceCallback,
319 base::Unretained(this)))); 316 base::Unretained(this))));
320 317
321 if (sink_params.frames_per_buffer() > source_params.frames_per_buffer()) { 318 if (sink_params.frames_per_buffer() > source_params.frames_per_buffer()) {
322 int frame_duration_milliseconds = base::Time::kMillisecondsPerSecond / 319 int frame_duration_milliseconds = base::Time::kMillisecondsPerSecond /
323 static_cast<double>(source_params.sample_rate()); 320 static_cast<double>(source_params.sample_rate());
324 fifo_delay_milliseconds_ = (sink_params.frames_per_buffer() - 321 fifo_delay_milliseconds_ = (sink_params.frames_per_buffer() -
325 source_params.frames_per_buffer()) * frame_duration_milliseconds; 322 source_params.frames_per_buffer()) * frame_duration_milliseconds;
326 } 323 }
327 } 324 }
328 325
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; 326 source_ = source;
337 source->SetRenderFormat(source_params);
338 327
339 // Configure the audio rendering client and start rendering. 328 // Configure the audio rendering client and start rendering.
340 sink_ = AudioDeviceFactory::NewOutputDevice( 329 sink_ = AudioDeviceFactory::NewOutputDevice(
341 source_render_view_id_, source_render_frame_id_); 330 source_render_view_id_, source_render_frame_id_);
342 331
343 // TODO(tommi): Rename InitializeUnifiedStream to rather reflect association 332 // TODO(tommi): Rename InitializeUnifiedStream to rather reflect association
344 // with a session. 333 // with a session.
345 DCHECK_GE(session_id_, 0); 334 DCHECK_GE(session_id_, 0);
346 sink_->InitializeUnifiedStream(sink_params, this, session_id_); 335 sink_->InitializeUnifiedStream(sink_params, this, session_id_);
347 336
(...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after
508 DVLOG(2) << "WebRtcAudioRenderer::SourceCallback(" 497 DVLOG(2) << "WebRtcAudioRenderer::SourceCallback("
509 << fifo_frame_delay << ", " 498 << fifo_frame_delay << ", "
510 << audio_bus->frames() << ")"; 499 << audio_bus->frames() << ")";
511 500
512 int output_delay_milliseconds = audio_delay_milliseconds_; 501 int output_delay_milliseconds = audio_delay_milliseconds_;
513 output_delay_milliseconds += fifo_delay_milliseconds_; 502 output_delay_milliseconds += fifo_delay_milliseconds_;
514 DVLOG(2) << "output_delay_milliseconds: " << output_delay_milliseconds; 503 DVLOG(2) << "output_delay_milliseconds: " << output_delay_milliseconds;
515 504
516 // We need to keep render data for the |source_| regardless of |state_|, 505 // We need to keep render data for the |source_| regardless of |state_|,
517 // otherwise the data will be buffered up inside |source_|. 506 // otherwise the data will be buffered up inside |source_|.
518 source_->RenderData(reinterpret_cast<uint8*>(buffer_.get()), 507 source_->RenderData(audio_bus, sample_rate_, output_delay_milliseconds);
519 audio_bus->channels(), audio_bus->frames(),
520 output_delay_milliseconds);
521 508
522 // Avoid filling up the audio bus if we are not playing; instead 509 // 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. 510 // return here and ensure that the returned value in Render() is 0.
524 if (state_ != PLAYING) { 511 if (state_ != PLAYING)
525 audio_bus->Zero(); 512 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 } 513 }
535 514
536 void WebRtcAudioRenderer::UpdateSourceVolume( 515 void WebRtcAudioRenderer::UpdateSourceVolume(
537 webrtc::AudioSourceInterface* source) { 516 webrtc::AudioSourceInterface* source) {
538 DCHECK(thread_checker_.CalledOnValidThread()); 517 DCHECK(thread_checker_.CalledOnValidThread());
539 518
540 // Note: If there are no playing audio renderers, then the volume will be 519 // Note: If there are no playing audio renderers, then the volume will be
541 // set to 0.0. 520 // set to 0.0.
542 float volume = 0.0f; 521 float volume = 0.0f;
543 522
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after
611 if (RemovePlayingState(source, state)) 590 if (RemovePlayingState(source, state))
612 EnterPauseState(); 591 EnterPauseState();
613 } else if (AddPlayingState(source, state)) { 592 } else if (AddPlayingState(source, state)) {
614 EnterPlayState(); 593 EnterPlayState();
615 } 594 }
616 UpdateSourceVolume(source); 595 UpdateSourceVolume(source);
617 } 596 }
618 } 597 }
619 598
620 } // namespace content 599 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698