Index: content/renderer/media/webrtc_local_audio_renderer.cc |
diff --git a/content/renderer/media/webrtc_local_audio_renderer.cc b/content/renderer/media/webrtc_local_audio_renderer.cc |
deleted file mode 100644 |
index f39a017b94db441164f527fba3b8790aca8d46b0..0000000000000000000000000000000000000000 |
--- a/content/renderer/media/webrtc_local_audio_renderer.cc |
+++ /dev/null |
@@ -1,356 +0,0 @@ |
-// Copyright (c) 2012 The Chromium Authors. All rights reserved. |
-// Use of this source code is governed by a BSD-style license that can be |
-// found in the LICENSE file. |
- |
-#include "content/renderer/media/webrtc_local_audio_renderer.h" |
- |
-#include <utility> |
- |
-#include "base/location.h" |
-#include "base/logging.h" |
-#include "base/metrics/histogram.h" |
-#include "base/synchronization/lock.h" |
-#include "base/thread_task_runner_handle.h" |
-#include "base/trace_event/trace_event.h" |
-#include "content/renderer/media/audio_device_factory.h" |
-#include "content/renderer/media/media_stream_dispatcher.h" |
-#include "content/renderer/media/webrtc_audio_capturer.h" |
-#include "content/renderer/media/webrtc_audio_renderer.h" |
-#include "content/renderer/render_frame_impl.h" |
-#include "media/audio/audio_output_device.h" |
-#include "media/base/audio_bus.h" |
-#include "media/base/audio_shifter.h" |
- |
-namespace content { |
- |
-namespace { |
- |
-enum LocalRendererSinkStates { |
- kSinkStarted = 0, |
- kSinkNeverStarted, |
- kSinkStatesMax // Must always be last! |
-}; |
- |
-} // namespace |
- |
-// media::AudioRendererSink::RenderCallback implementation |
-int WebRtcLocalAudioRenderer::Render(media::AudioBus* audio_bus, |
- uint32_t audio_delay_milliseconds, |
- uint32_t frames_skipped) { |
- TRACE_EVENT0("audio", "WebRtcLocalAudioRenderer::Render"); |
- base::AutoLock auto_lock(thread_lock_); |
- |
- if (!playing_ || !volume_ || !audio_shifter_) { |
- audio_bus->Zero(); |
- return 0; |
- } |
- |
- audio_shifter_->Pull( |
- audio_bus, |
- base::TimeTicks::Now() - |
- base::TimeDelta::FromMilliseconds(audio_delay_milliseconds)); |
- |
- return audio_bus->frames(); |
-} |
- |
-void WebRtcLocalAudioRenderer::OnRenderError() { |
- NOTIMPLEMENTED(); |
-} |
- |
-// content::MediaStreamAudioSink implementation |
-void WebRtcLocalAudioRenderer::OnData(const media::AudioBus& audio_bus, |
- base::TimeTicks estimated_capture_time) { |
- DCHECK(capture_thread_checker_.CalledOnValidThread()); |
- DCHECK(!estimated_capture_time.is_null()); |
- |
- TRACE_EVENT0("audio", "WebRtcLocalAudioRenderer::CaptureData"); |
- |
- base::AutoLock auto_lock(thread_lock_); |
- if (!playing_ || !volume_ || !audio_shifter_) |
- return; |
- |
- scoped_ptr<media::AudioBus> audio_data( |
- media::AudioBus::Create(audio_bus.channels(), audio_bus.frames())); |
- audio_bus.CopyTo(audio_data.get()); |
- audio_shifter_->Push(std::move(audio_data), estimated_capture_time); |
- const base::TimeTicks now = base::TimeTicks::Now(); |
- total_render_time_ += now - last_render_time_; |
- last_render_time_ = now; |
-} |
- |
-void WebRtcLocalAudioRenderer::OnSetFormat( |
- const media::AudioParameters& params) { |
- DVLOG(1) << "WebRtcLocalAudioRenderer::OnSetFormat()"; |
- // If the source is restarted, we might have changed to another capture |
- // thread. |
- capture_thread_checker_.DetachFromThread(); |
- DCHECK(capture_thread_checker_.CalledOnValidThread()); |
- |
- // Post a task on the main render thread to reconfigure the |sink_| with the |
- // new format. |
- task_runner_->PostTask( |
- FROM_HERE, |
- base::Bind(&WebRtcLocalAudioRenderer::ReconfigureSink, this, params)); |
-} |
- |
-// WebRtcLocalAudioRenderer::WebRtcLocalAudioRenderer implementation. |
-WebRtcLocalAudioRenderer::WebRtcLocalAudioRenderer( |
- const blink::WebMediaStreamTrack& audio_track, |
- int source_render_frame_id, |
- int session_id, |
- const std::string& device_id, |
- const url::Origin& security_origin) |
- : audio_track_(audio_track), |
- source_render_frame_id_(source_render_frame_id), |
- session_id_(session_id), |
- task_runner_(base::ThreadTaskRunnerHandle::Get()), |
- playing_(false), |
- output_device_id_(device_id), |
- security_origin_(security_origin), |
- volume_(0.0), |
- sink_started_(false) { |
- DVLOG(1) << "WebRtcLocalAudioRenderer::WebRtcLocalAudioRenderer()"; |
-} |
- |
-WebRtcLocalAudioRenderer::~WebRtcLocalAudioRenderer() { |
- DCHECK(task_runner_->BelongsToCurrentThread()); |
- DCHECK(!sink_.get()); |
- DVLOG(1) << "WebRtcLocalAudioRenderer::~WebRtcLocalAudioRenderer()"; |
-} |
- |
-void WebRtcLocalAudioRenderer::Start() { |
- DVLOG(1) << "WebRtcLocalAudioRenderer::Start()"; |
- DCHECK(task_runner_->BelongsToCurrentThread()); |
- |
- // We get audio data from |audio_track_|... |
- MediaStreamAudioSink::AddToAudioTrack(this, audio_track_); |
- // ...and |sink_| will get audio data from us. |
- DCHECK(!sink_.get()); |
- sink_ = |
- AudioDeviceFactory::NewOutputDevice(source_render_frame_id_, session_id_, |
- output_device_id_, security_origin_); |
- |
- base::AutoLock auto_lock(thread_lock_); |
- last_render_time_ = base::TimeTicks::Now(); |
- playing_ = false; |
-} |
- |
-void WebRtcLocalAudioRenderer::Stop() { |
- DVLOG(1) << "WebRtcLocalAudioRenderer::Stop()"; |
- DCHECK(task_runner_->BelongsToCurrentThread()); |
- |
- { |
- base::AutoLock auto_lock(thread_lock_); |
- playing_ = false; |
- audio_shifter_.reset(); |
- } |
- |
- // Stop the output audio stream, i.e, stop asking for data to render. |
- // It is safer to call Stop() on the |sink_| to clean up the resources even |
- // when the |sink_| is never started. |
- if (sink_.get()) { |
- sink_->Stop(); |
- sink_ = NULL; |
- } |
- |
- if (!sink_started_) { |
- UMA_HISTOGRAM_ENUMERATION("Media.LocalRendererSinkStates", |
- kSinkNeverStarted, kSinkStatesMax); |
- } |
- sink_started_ = false; |
- |
- // Ensure that the capturer stops feeding us with captured audio. |
- MediaStreamAudioSink::RemoveFromAudioTrack(this, audio_track_); |
-} |
- |
-void WebRtcLocalAudioRenderer::Play() { |
- DVLOG(1) << "WebRtcLocalAudioRenderer::Play()"; |
- DCHECK(task_runner_->BelongsToCurrentThread()); |
- |
- if (!sink_.get()) |
- return; |
- |
- { |
- base::AutoLock auto_lock(thread_lock_); |
- // Resumes rendering by ensuring that WebRtcLocalAudioRenderer::Render() |
- // now reads data from the local FIFO. |
- playing_ = true; |
- last_render_time_ = base::TimeTicks::Now(); |
- } |
- |
- // Note: If volume_ is currently muted, the |sink_| will not be started yet. |
- MaybeStartSink(); |
-} |
- |
-void WebRtcLocalAudioRenderer::Pause() { |
- DVLOG(1) << "WebRtcLocalAudioRenderer::Pause()"; |
- DCHECK(task_runner_->BelongsToCurrentThread()); |
- |
- if (!sink_.get()) |
- return; |
- |
- base::AutoLock auto_lock(thread_lock_); |
- // Temporarily suspends rendering audio. |
- // WebRtcLocalAudioRenderer::Render() will return early during this state |
- // and only zeros will be provided to the active sink. |
- playing_ = false; |
-} |
- |
-void WebRtcLocalAudioRenderer::SetVolume(float volume) { |
- DVLOG(1) << "WebRtcLocalAudioRenderer::SetVolume(" << volume << ")"; |
- DCHECK(task_runner_->BelongsToCurrentThread()); |
- |
- { |
- base::AutoLock auto_lock(thread_lock_); |
- // Cache the volume. |
- volume_ = volume; |
- } |
- |
- // Lazily start the |sink_| when the local renderer is unmuted during |
- // playing. |
- MaybeStartSink(); |
- |
- if (sink_.get()) |
- sink_->SetVolume(volume); |
-} |
- |
-media::OutputDevice* WebRtcLocalAudioRenderer::GetOutputDevice() { |
- DCHECK(task_runner_->BelongsToCurrentThread()); |
- return this; |
-} |
- |
-base::TimeDelta WebRtcLocalAudioRenderer::GetCurrentRenderTime() const { |
- DCHECK(task_runner_->BelongsToCurrentThread()); |
- base::AutoLock auto_lock(thread_lock_); |
- if (!sink_.get()) |
- return base::TimeDelta(); |
- return total_render_time(); |
-} |
- |
-bool WebRtcLocalAudioRenderer::IsLocalRenderer() const { |
- return true; |
-} |
- |
-void WebRtcLocalAudioRenderer::SwitchOutputDevice( |
- const std::string& device_id, |
- const url::Origin& security_origin, |
- const media::SwitchOutputDeviceCB& callback) { |
- DVLOG(1) << "WebRtcLocalAudioRenderer::SwitchOutputDevice()"; |
- DCHECK(task_runner_->BelongsToCurrentThread()); |
- |
- scoped_refptr<media::AudioOutputDevice> new_sink = |
- AudioDeviceFactory::NewOutputDevice(source_render_frame_id_, session_id_, |
- device_id, security_origin); |
- if (new_sink->GetDeviceStatus() != media::OUTPUT_DEVICE_STATUS_OK) { |
- callback.Run(new_sink->GetDeviceStatus()); |
- return; |
- } |
- |
- output_device_id_ = device_id; |
- security_origin_ = security_origin; |
- bool was_sink_started = sink_started_; |
- |
- if (sink_.get()) |
- sink_->Stop(); |
- |
- sink_started_ = false; |
- sink_ = new_sink; |
- int frames_per_buffer = sink_->GetOutputParameters().frames_per_buffer(); |
- sink_params_ = source_params_; |
- sink_params_.set_frames_per_buffer(WebRtcAudioRenderer::GetOptimalBufferSize( |
- source_params_.sample_rate(), frames_per_buffer)); |
- |
- if (was_sink_started) |
- MaybeStartSink(); |
- |
- callback.Run(media::OUTPUT_DEVICE_STATUS_OK); |
-} |
- |
-media::AudioParameters WebRtcLocalAudioRenderer::GetOutputParameters() { |
- DCHECK(task_runner_->BelongsToCurrentThread()); |
- if (!sink_.get()) |
- return media::AudioParameters(); |
- |
- return sink_->GetOutputParameters(); |
-} |
- |
-media::OutputDeviceStatus WebRtcLocalAudioRenderer::GetDeviceStatus() { |
- DCHECK(task_runner_->BelongsToCurrentThread()); |
- if (!sink_.get()) |
- return media::OUTPUT_DEVICE_STATUS_ERROR_INTERNAL; |
- |
- return sink_->GetDeviceStatus(); |
-} |
- |
-void WebRtcLocalAudioRenderer::MaybeStartSink() { |
- DCHECK(task_runner_->BelongsToCurrentThread()); |
- DVLOG(1) << "WebRtcLocalAudioRenderer::MaybeStartSink()"; |
- |
- if (!sink_.get() || !source_params_.IsValid()) |
- return; |
- |
- { |
- // Clear up the old data in the FIFO. |
- base::AutoLock auto_lock(thread_lock_); |
- audio_shifter_->Flush(); |
- } |
- |
- if (!sink_params_.IsValid() || !playing_ || !volume_ || sink_started_ || |
- sink_->GetDeviceStatus() != media::OUTPUT_DEVICE_STATUS_OK) |
- return; |
- |
- DVLOG(1) << "WebRtcLocalAudioRenderer::MaybeStartSink() -- Starting sink_."; |
- sink_->Initialize(sink_params_, this); |
- sink_->Start(); |
- sink_started_ = true; |
- UMA_HISTOGRAM_ENUMERATION("Media.LocalRendererSinkStates", |
- kSinkStarted, kSinkStatesMax); |
-} |
- |
-void WebRtcLocalAudioRenderer::ReconfigureSink( |
- const media::AudioParameters& params) { |
- DCHECK(task_runner_->BelongsToCurrentThread()); |
- |
- DVLOG(1) << "WebRtcLocalAudioRenderer::ReconfigureSink()"; |
- |
- if (source_params_.Equals(params)) |
- return; |
- |
- // Reset the |source_params_|, |sink_params_| and |loopback_fifo_| to match |
- // the new format. |
- |
- source_params_ = params; |
- { |
- // Note: The max buffer is fairly large, but will rarely be used. |
- // Cast needs the buffer to hold at least one second of audio. |
- // The clock accuracy is set to 20ms because clock accuracy is |
- // ~15ms on windows. |
- media::AudioShifter* const new_shifter = new media::AudioShifter( |
- base::TimeDelta::FromSeconds(2), |
- base::TimeDelta::FromMilliseconds(20), |
- base::TimeDelta::FromSeconds(20), |
- source_params_.sample_rate(), |
- params.channels()); |
- |
- base::AutoLock auto_lock(thread_lock_); |
- audio_shifter_.reset(new_shifter); |
- } |
- |
- if (!sink_.get()) |
- return; // WebRtcLocalAudioRenderer has not yet been started. |
- |
- // Stop |sink_| and re-create a new one to be initialized with different audio |
- // parameters. Then, invoke MaybeStartSink() to restart everything again. |
- sink_->Stop(); |
- sink_started_ = false; |
- sink_ = |
- AudioDeviceFactory::NewOutputDevice(source_render_frame_id_, session_id_, |
- output_device_id_, security_origin_); |
- int frames_per_buffer = sink_->GetOutputParameters().frames_per_buffer(); |
- sink_params_ = source_params_; |
- sink_params_.set_frames_per_buffer(WebRtcAudioRenderer::GetOptimalBufferSize( |
- source_params_.sample_rate(), frames_per_buffer)); |
- MaybeStartSink(); |
-} |
- |
-} // namespace content |