// Copyright 2015 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 "chrome/renderer/media/cast_receiver_session.h" #include "base/synchronization/waitable_event.h" #include "chrome/renderer/media/cast_receiver_audio_valve.h" #include "content/public/renderer/render_thread.h" #include "media/base/audio_capturer_source.h" #include "media/base/bind_to_current_loop.h" #include "media/base/video_capturer_source.h" #include "third_party/WebKit/public/platform/WebMediaStream.h" #include "third_party/WebKit/public/platform/WebMediaStreamSource.h" #include "third_party/WebKit/public/platform/WebMediaStreamTrack.h" // This is a render thread object. class CastReceiverSession::AudioCapturerSource : public media::AudioCapturerSource { public: AudioCapturerSource( const scoped_refptr cast_receiver_session); void Initialize(const media::AudioParameters& params, CaptureCallback* callback, int session_id) override; void Start() override; void Stop() override; void SetVolume(double volume) override; void SetAutomaticGainControl(bool enable) override; private: ~AudioCapturerSource() override; const scoped_refptr cast_receiver_session_; scoped_refptr audio_valve_; }; // This is a render thread object. class CastReceiverSession::VideoCapturerSource : public media::VideoCapturerSource { public: explicit VideoCapturerSource( const scoped_refptr cast_receiver_session); protected: void GetCurrentSupportedFormats( int max_requested_width, int max_requested_height, double max_requested_frame_rate, const VideoCaptureDeviceFormatsCB& callback) override; void StartCapture( const media::VideoCaptureParams& params, const content::VideoCaptureDeliverFrameCB& frame_callback, scoped_refptr frame_callback_task_runner, const RunningCallback& running_callback) override; void StopCapture() override; private: const scoped_refptr cast_receiver_session_; }; CastReceiverSession::CastReceiverSession() : delegate_(new CastReceiverSessionDelegate()), io_task_runner_( content::RenderThread::Get()->GetIOMessageLoopProxy()) {} CastReceiverSession::~CastReceiverSession() { // We should always be able to delete the object on the IO thread. CHECK(io_task_runner_->DeleteSoon(FROM_HERE, delegate_.release())); } void CastReceiverSession::Start( const media::cast::FrameReceiverConfig& audio_config, const media::cast::FrameReceiverConfig& video_config, const net::IPEndPoint& local_endpoint, const net::IPEndPoint& remote_endpoint, scoped_ptr options, const media::VideoCaptureFormat& capture_format, const StartCB& start_callback, const CastReceiverSessionDelegate::ErrorCallback& error_callback) { audio_config_ = audio_config; video_config_ = video_config; format_ = capture_format; io_task_runner_->PostTask( FROM_HERE, base::Bind(&CastReceiverSessionDelegate::Start, base::Unretained(delegate_.get()), audio_config, video_config, local_endpoint, remote_endpoint, base::Passed(&options), format_, media::BindToCurrentLoop(error_callback))); scoped_refptr audio( new CastReceiverSession::AudioCapturerSource(this)); scoped_ptr video( new CastReceiverSession::VideoCapturerSource(this)); base::MessageLoop::current()->PostTask( FROM_HERE, base::Bind(start_callback, audio, base::Passed(&video))); } void CastReceiverSession::StartAudio( scoped_refptr audio_valve) { io_task_runner_->PostTask( FROM_HERE, base::Bind(&CastReceiverSessionDelegate::StartAudio, base::Unretained(delegate_.get()), audio_valve)); } void CastReceiverSession::StartVideo( content::VideoCaptureDeliverFrameCB frame_callback) { io_task_runner_->PostTask( FROM_HERE, base::Bind(&CastReceiverSessionDelegate::StartVideo, base::Unretained(delegate_.get()), frame_callback)); } void CastReceiverSession::StopVideo() { io_task_runner_->PostTask( FROM_HERE, base::Bind(&CastReceiverSessionDelegate::StopVideo, base::Unretained(delegate_.get()))); } CastReceiverSession::VideoCapturerSource::VideoCapturerSource( const scoped_refptr cast_receiver_session) : cast_receiver_session_(cast_receiver_session) { } void CastReceiverSession::VideoCapturerSource::GetCurrentSupportedFormats( int max_requested_width, int max_requested_height, double max_requested_frame_rate, const VideoCaptureDeviceFormatsCB& callback) { std::vector formats; if (cast_receiver_session_->format_.IsValid()) { formats.push_back(cast_receiver_session_->format_); } callback.Run(formats); } void CastReceiverSession::VideoCapturerSource::StartCapture( const media::VideoCaptureParams& params, const content::VideoCaptureDeliverFrameCB& frame_callback, scoped_refptr frame_callback_task_runner, const RunningCallback& running_callback) { if (frame_callback_task_runner != content::RenderThread::Get()->GetIOMessageLoopProxy()) { DCHECK(false) << "Only IO thread supported right now."; running_callback.Run(false); return; } cast_receiver_session_->StartVideo(frame_callback); running_callback.Run(true); } void CastReceiverSession::VideoCapturerSource::StopCapture() { cast_receiver_session_->StopVideo(); } CastReceiverSession::AudioCapturerSource::AudioCapturerSource( const scoped_refptr cast_receiver_session) : cast_receiver_session_(cast_receiver_session) { } CastReceiverSession::AudioCapturerSource::~AudioCapturerSource() { DCHECK(!audio_valve_); } void CastReceiverSession::AudioCapturerSource::Initialize( const media::AudioParameters& params, CaptureCallback* callback, int session_id) { // TODO(hubbe): Consider converting the audio to whatever the caller wants. if (params.sample_rate() != cast_receiver_session_->audio_config_.rtp_timebase || params.channels() != cast_receiver_session_->audio_config_.channels) { callback->OnCaptureError(); return; } audio_valve_ = new CastReceiverAudioValve(callback); } void CastReceiverSession::AudioCapturerSource::Start() { DCHECK(audio_valve_); cast_receiver_session_->StartAudio(audio_valve_); } void CastReceiverSession::AudioCapturerSource::Stop() { audio_valve_->Stop(); audio_valve_ = nullptr; } void CastReceiverSession::AudioCapturerSource::SetVolume(double volume) { // not supported } void CastReceiverSession::AudioCapturerSource::SetAutomaticGainControl( bool enable) { // not supported }