| 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 |