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