OLD | NEW |
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 <utility> | 7 #include <utility> |
8 | 8 |
9 #include "base/bind.h" | 9 #include "base/bind.h" |
10 #include "base/bind_helpers.h" | 10 #include "base/bind_helpers.h" |
(...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
160 const std::string& device_id, | 160 const std::string& device_id, |
161 const url::Origin& security_origin) | 161 const url::Origin& security_origin) |
162 : state_(UNINITIALIZED), | 162 : state_(UNINITIALIZED), |
163 source_render_frame_id_(source_render_frame_id), | 163 source_render_frame_id_(source_render_frame_id), |
164 session_id_(session_id), | 164 session_id_(session_id), |
165 signaling_thread_(signaling_thread), | 165 signaling_thread_(signaling_thread), |
166 media_stream_(media_stream), | 166 media_stream_(media_stream), |
167 source_(NULL), | 167 source_(NULL), |
168 play_ref_count_(0), | 168 play_ref_count_(0), |
169 start_ref_count_(0), | 169 start_ref_count_(0), |
| 170 audio_delay_milliseconds_(0), |
170 sink_params_(kFormat, kChannelLayout, 0, kBitsPerSample, 0), | 171 sink_params_(kFormat, kChannelLayout, 0, kBitsPerSample, 0), |
171 output_device_id_(device_id), | 172 output_device_id_(device_id), |
172 security_origin_(security_origin) { | 173 security_origin_(security_origin) { |
173 WebRtcLogMessage(base::StringPrintf( | 174 WebRtcLogMessage(base::StringPrintf( |
174 "WAR::WAR. source_render_frame_id=%d, session_id=%d, effects=%i", | 175 "WAR::WAR. source_render_frame_id=%d, session_id=%d, effects=%i", |
175 source_render_frame_id, session_id, sink_params_.effects())); | 176 source_render_frame_id, session_id, sink_params_.effects())); |
176 } | 177 } |
177 | 178 |
178 WebRtcAudioRenderer::~WebRtcAudioRenderer() { | 179 WebRtcAudioRenderer::~WebRtcAudioRenderer() { |
179 DCHECK(thread_checker_.CalledOnValidThread()); | 180 DCHECK(thread_checker_.CalledOnValidThread()); |
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
260 if (state_ == UNINITIALIZED) | 261 if (state_ == UNINITIALIZED) |
261 return; | 262 return; |
262 | 263 |
263 DCHECK(play_ref_count_ == 0 || state_ == PLAYING); | 264 DCHECK(play_ref_count_ == 0 || state_ == PLAYING); |
264 ++play_ref_count_; | 265 ++play_ref_count_; |
265 | 266 |
266 if (state_ != PLAYING) { | 267 if (state_ != PLAYING) { |
267 state_ = PLAYING; | 268 state_ = PLAYING; |
268 | 269 |
269 if (audio_fifo_) { | 270 if (audio_fifo_) { |
270 audio_delay_ = base::TimeDelta(); | 271 audio_delay_milliseconds_ = 0; |
271 audio_fifo_->Clear(); | 272 audio_fifo_->Clear(); |
272 } | 273 } |
273 } | 274 } |
274 } | 275 } |
275 | 276 |
276 void WebRtcAudioRenderer::Pause() { | 277 void WebRtcAudioRenderer::Pause() { |
277 DVLOG(1) << "WebRtcAudioRenderer::Pause()"; | 278 DVLOG(1) << "WebRtcAudioRenderer::Pause()"; |
278 DCHECK(thread_checker_.CalledOnValidThread()); | 279 DCHECK(thread_checker_.CalledOnValidThread()); |
279 if (!playing_state_.playing()) | 280 if (!playing_state_.playing()) |
280 return; | 281 return; |
(...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
393 base::AutoLock auto_lock(lock_); | 394 base::AutoLock auto_lock(lock_); |
394 source_->AudioRendererThreadStopped(); | 395 source_->AudioRendererThreadStopped(); |
395 } | 396 } |
396 PrepareSink(); | 397 PrepareSink(); |
397 sink_->Start(); | 398 sink_->Start(); |
398 sink_->Play(); // Not all the sinks play on start. | 399 sink_->Play(); // Not all the sinks play on start. |
399 | 400 |
400 callback.Run(media::OUTPUT_DEVICE_STATUS_OK); | 401 callback.Run(media::OUTPUT_DEVICE_STATUS_OK); |
401 } | 402 } |
402 | 403 |
403 int WebRtcAudioRenderer::Render(base::TimeDelta delay, | 404 int WebRtcAudioRenderer::Render(media::AudioBus* audio_bus, |
404 base::TimeTicks delay_timestamp, | 405 uint32_t frames_delayed, |
405 int prior_frames_skipped, | 406 uint32_t frames_skipped) { |
406 media::AudioBus* audio_bus) { | |
407 DCHECK(sink_->CurrentThreadIsRenderingThread()); | 407 DCHECK(sink_->CurrentThreadIsRenderingThread()); |
408 base::AutoLock auto_lock(lock_); | 408 base::AutoLock auto_lock(lock_); |
409 if (!source_) | 409 if (!source_) |
410 return 0; | 410 return 0; |
411 | 411 |
| 412 // TODO(grunell): Converting from frames to milliseconds will potentially lose |
| 413 // hundreds of microseconds which may cause audio video drift. Update |
| 414 // this class and all usage of render delay msec -> frames (possibly even |
| 415 // using a double type for frames). See http://crbug.com/586540 |
| 416 uint32_t audio_delay_milliseconds = static_cast<double>(frames_delayed) * |
| 417 base::Time::kMillisecondsPerSecond / |
| 418 sink_params_.sample_rate(); |
| 419 |
412 DVLOG(2) << "WebRtcAudioRenderer::Render()"; | 420 DVLOG(2) << "WebRtcAudioRenderer::Render()"; |
413 DVLOG(2) << "audio_delay: " << delay; | 421 DVLOG(2) << "audio_delay_milliseconds: " << audio_delay_milliseconds; |
414 | 422 |
415 audio_delay_ = delay; | 423 DCHECK_LE(audio_delay_milliseconds, static_cast<uint32_t>(INT_MAX)); |
| 424 audio_delay_milliseconds_ = static_cast<int>(audio_delay_milliseconds); |
416 | 425 |
417 // If there are skipped frames, pull and throw away the same amount. We always | 426 // If there are skipped frames, pull and throw away the same amount. We always |
418 // pull 10 ms of data from the source (see PrepareSink()), so the fifo is only | 427 // pull 10 ms of data from the source (see PrepareSink()), so the fifo is only |
419 // required if the number of frames to drop doesn't correspond to 10 ms. | 428 // required if the number of frames to drop doesn't correspond to 10 ms. |
420 if (prior_frames_skipped > 0) { | 429 if (frames_skipped > 0) { |
421 const int source_frames_per_buffer = sink_params_.sample_rate() / 100; | 430 const uint32_t source_frames_per_buffer = |
422 if (!audio_fifo_ && prior_frames_skipped != source_frames_per_buffer) { | 431 static_cast<uint32_t>(sink_params_.sample_rate() / 100); |
| 432 if (!audio_fifo_ && frames_skipped != source_frames_per_buffer) { |
423 audio_fifo_.reset(new media::AudioPullFifo( | 433 audio_fifo_.reset(new media::AudioPullFifo( |
424 kChannels, source_frames_per_buffer, | 434 kChannels, source_frames_per_buffer, |
425 base::Bind(&WebRtcAudioRenderer::SourceCallback, | 435 base::Bind(&WebRtcAudioRenderer::SourceCallback, |
426 base::Unretained(this)))); | 436 base::Unretained(this)))); |
427 } | 437 } |
428 | 438 |
429 std::unique_ptr<media::AudioBus> drop_bus = | 439 std::unique_ptr<media::AudioBus> drop_bus = |
430 media::AudioBus::Create(audio_bus->channels(), prior_frames_skipped); | 440 media::AudioBus::Create(audio_bus->channels(), frames_skipped); |
431 if (audio_fifo_) | 441 if (audio_fifo_) |
432 audio_fifo_->Consume(drop_bus.get(), drop_bus->frames()); | 442 audio_fifo_->Consume(drop_bus.get(), drop_bus->frames()); |
433 else | 443 else |
434 SourceCallback(0, drop_bus.get()); | 444 SourceCallback(0, drop_bus.get()); |
435 } | 445 } |
436 | 446 |
437 // Pull the data we will deliver. | 447 // Pull the data we will deliver. |
438 if (audio_fifo_) | 448 if (audio_fifo_) |
439 audio_fifo_->Consume(audio_bus, audio_bus->frames()); | 449 audio_fifo_->Consume(audio_bus, audio_bus->frames()); |
440 else | 450 else |
441 SourceCallback(0, audio_bus); | 451 SourceCallback(0, audio_bus); |
442 | 452 |
443 return (state_ == PLAYING) ? audio_bus->frames() : 0; | 453 return (state_ == PLAYING) ? audio_bus->frames() : 0; |
444 } | 454 } |
445 | 455 |
446 void WebRtcAudioRenderer::OnRenderError() { | 456 void WebRtcAudioRenderer::OnRenderError() { |
447 NOTIMPLEMENTED(); | 457 NOTIMPLEMENTED(); |
448 LOG(ERROR) << "OnRenderError()"; | 458 LOG(ERROR) << "OnRenderError()"; |
449 } | 459 } |
450 | 460 |
451 // Called by AudioPullFifo when more data is necessary. | 461 // Called by AudioPullFifo when more data is necessary. |
452 void WebRtcAudioRenderer::SourceCallback( | 462 void WebRtcAudioRenderer::SourceCallback( |
453 int fifo_frame_delay, media::AudioBus* audio_bus) { | 463 int fifo_frame_delay, media::AudioBus* audio_bus) { |
454 DCHECK(sink_->CurrentThreadIsRenderingThread()); | 464 DCHECK(sink_->CurrentThreadIsRenderingThread()); |
455 base::TimeTicks start_time = base::TimeTicks::Now(); | 465 base::TimeTicks start_time = base::TimeTicks::Now(); |
456 DVLOG(2) << "WebRtcAudioRenderer::SourceCallback(" | 466 DVLOG(2) << "WebRtcAudioRenderer::SourceCallback(" |
457 << fifo_frame_delay << ", " | 467 << fifo_frame_delay << ", " |
458 << audio_bus->frames() << ")"; | 468 << audio_bus->frames() << ")"; |
459 | 469 |
460 int output_delay_milliseconds = audio_delay_.InMilliseconds(); | 470 int output_delay_milliseconds = audio_delay_milliseconds_; |
461 // TODO(grunell): This integer division by sample_rate will cause loss of | 471 // TODO(grunell): This integer division by sample_rate will cause loss of |
462 // partial milliseconds, and may cause avsync drift. http://crbug.com/586540 | 472 // partial milliseconds, and may cause avsync drift. http://crbug.com/586540 |
463 output_delay_milliseconds += fifo_frame_delay * | 473 output_delay_milliseconds += fifo_frame_delay * |
464 base::Time::kMillisecondsPerSecond / | 474 base::Time::kMillisecondsPerSecond / |
465 sink_params_.sample_rate(); | 475 sink_params_.sample_rate(); |
466 DVLOG(2) << "output_delay_milliseconds: " << output_delay_milliseconds; | 476 DVLOG(2) << "output_delay_milliseconds: " << output_delay_milliseconds; |
467 | 477 |
468 // We need to keep render data for the |source_| regardless of |state_|, | 478 // We need to keep render data for the |source_| regardless of |state_|, |
469 // otherwise the data will be buffered up inside |source_|. | 479 // otherwise the data will be buffered up inside |source_|. |
470 source_->RenderData(audio_bus, sink_params_.sample_rate(), | 480 source_->RenderData(audio_bus, sink_params_.sample_rate(), |
(...skipping 187 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
658 sink_params_ = new_sink_params; | 668 sink_params_ = new_sink_params; |
659 } | 669 } |
660 | 670 |
661 // Specify the latency info to be passed to the browser side. | 671 // Specify the latency info to be passed to the browser side. |
662 new_sink_params.set_latency_tag(AudioDeviceFactory::GetSourceLatencyType( | 672 new_sink_params.set_latency_tag(AudioDeviceFactory::GetSourceLatencyType( |
663 AudioDeviceFactory::AudioDeviceFactory::kSourceWebRtc)); | 673 AudioDeviceFactory::AudioDeviceFactory::kSourceWebRtc)); |
664 sink_->Initialize(new_sink_params, this); | 674 sink_->Initialize(new_sink_params, this); |
665 } | 675 } |
666 | 676 |
667 } // namespace content | 677 } // namespace content |
OLD | NEW |