1// Copyright 2013 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "media/cast/cast_sender_impl.h" 6 7#include "base/bind.h" 8#include "base/callback.h" 9#include "base/logging.h" 10#include "base/message_loop/message_loop.h" 11#include "media/base/video_frame.h" 12 13namespace media { 14namespace cast { 15 16// The LocalVideoFrameInput class posts all incoming video frames to the main 17// cast thread for processing. 18class LocalVideoFrameInput : public VideoFrameInput { 19 public: 20 LocalVideoFrameInput(scoped_refptr<CastEnvironment> cast_environment, 21 base::WeakPtr<VideoSender> video_sender) 22 : cast_environment_(cast_environment), video_sender_(video_sender) {} 23 24 virtual void InsertRawVideoFrame( 25 const scoped_refptr<media::VideoFrame>& video_frame, 26 const base::TimeTicks& capture_time) OVERRIDE { 27 cast_environment_->PostTask(CastEnvironment::MAIN, 28 FROM_HERE, 29 base::Bind(&VideoSender::InsertRawVideoFrame, 30 video_sender_, 31 video_frame, 32 capture_time)); 33 } 34 35 protected: 36 virtual ~LocalVideoFrameInput() {} 37 38 private: 39 friend class base::RefCountedThreadSafe<LocalVideoFrameInput>; 40 41 scoped_refptr<CastEnvironment> cast_environment_; 42 base::WeakPtr<VideoSender> video_sender_; 43 44 DISALLOW_COPY_AND_ASSIGN(LocalVideoFrameInput); 45}; 46 47// The LocalAudioFrameInput class posts all incoming audio frames to the main 48// cast thread for processing. Therefore frames can be inserted from any thread. 49class LocalAudioFrameInput : public AudioFrameInput { 50 public: 51 LocalAudioFrameInput(scoped_refptr<CastEnvironment> cast_environment, 52 base::WeakPtr<AudioSender> audio_sender) 53 : cast_environment_(cast_environment), audio_sender_(audio_sender) {} 54 55 virtual void InsertAudio(scoped_ptr<AudioBus> audio_bus, 56 const base::TimeTicks& recorded_time) OVERRIDE { 57 cast_environment_->PostTask(CastEnvironment::MAIN, 58 FROM_HERE, 59 base::Bind(&AudioSender::InsertAudio, 60 audio_sender_, 61 base::Passed(&audio_bus), 62 recorded_time)); 63 } 64 65 protected: 66 virtual ~LocalAudioFrameInput() {} 67 68 private: 69 friend class base::RefCountedThreadSafe<LocalAudioFrameInput>; 70 71 scoped_refptr<CastEnvironment> cast_environment_; 72 base::WeakPtr<AudioSender> audio_sender_; 73 74 DISALLOW_COPY_AND_ASSIGN(LocalAudioFrameInput); 75}; 76 77scoped_ptr<CastSender> CastSender::Create( 78 scoped_refptr<CastEnvironment> cast_environment, 79 CastTransportSender* const transport_sender) { 80 CHECK(cast_environment.get()); 81 return scoped_ptr<CastSender>( 82 new CastSenderImpl(cast_environment, transport_sender)); 83} 84 85CastSenderImpl::CastSenderImpl( 86 scoped_refptr<CastEnvironment> cast_environment, 87 CastTransportSender* const transport_sender) 88 : cast_environment_(cast_environment), 89 transport_sender_(transport_sender), 90 weak_factory_(this) { 91 CHECK(cast_environment.get()); 92} 93 94void CastSenderImpl::InitializeAudio( 95 const AudioSenderConfig& audio_config, 96 const CastInitializationCallback& cast_initialization_cb) { 97 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); 98 CHECK(audio_config.use_external_encoder || 99 cast_environment_->HasAudioThread()); 100 101 VLOG(1) << "CastSenderImpl@" << this << "::InitializeAudio()"; 102 103 audio_sender_.reset( 104 new AudioSender(cast_environment_, audio_config, transport_sender_)); 105 106 const CastInitializationStatus status = audio_sender_->InitializationResult(); 107 if (status == STATUS_AUDIO_INITIALIZED) { 108 audio_frame_input_ = 109 new LocalAudioFrameInput(cast_environment_, audio_sender_->AsWeakPtr()); 110 } 111 cast_initialization_cb.Run(status); 112 if (video_sender_) { 113 DCHECK(audio_sender_->GetTargetPlayoutDelay() == 114 video_sender_->GetTargetPlayoutDelay()); 115 } 116} 117 118void CastSenderImpl::InitializeVideo( 119 const VideoSenderConfig& video_config, 120 const CastInitializationCallback& cast_initialization_cb, 121 const CreateVideoEncodeAcceleratorCallback& create_vea_cb, 122 const CreateVideoEncodeMemoryCallback& create_video_encode_mem_cb) { 123 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); 124 CHECK(video_config.use_external_encoder || 125 cast_environment_->HasVideoThread()); 126 127 VLOG(1) << "CastSenderImpl@" << this << "::InitializeVideo()"; 128 129 video_sender_.reset(new VideoSender( 130 cast_environment_, 131 video_config, 132 base::Bind(&CastSenderImpl::OnVideoInitialized, 133 weak_factory_.GetWeakPtr(), cast_initialization_cb), 134 create_vea_cb, 135 create_video_encode_mem_cb, 136 transport_sender_, 137 base::Bind(&CastSenderImpl::SetTargetPlayoutDelay, 138 weak_factory_.GetWeakPtr()))); 139 if (audio_sender_) { 140 DCHECK(audio_sender_->GetTargetPlayoutDelay() == 141 video_sender_->GetTargetPlayoutDelay()); 142 } 143} 144 145CastSenderImpl::~CastSenderImpl() { 146 VLOG(1) << "CastSenderImpl@" << this << "::~CastSenderImpl()"; 147} 148 149scoped_refptr<AudioFrameInput> CastSenderImpl::audio_frame_input() { 150 return audio_frame_input_; 151} 152 153scoped_refptr<VideoFrameInput> CastSenderImpl::video_frame_input() { 154 return video_frame_input_; 155} 156 157void CastSenderImpl::SetTargetPlayoutDelay( 158 base::TimeDelta new_target_playout_delay) { 159 VLOG(1) << "CastSenderImpl@" << this << "::SetTargetPlayoutDelay(" 160 << new_target_playout_delay.InMilliseconds() << " ms)"; 161 if (audio_sender_) { 162 audio_sender_->SetTargetPlayoutDelay(new_target_playout_delay); 163 } 164 if (video_sender_) { 165 video_sender_->SetTargetPlayoutDelay(new_target_playout_delay); 166 } 167} 168 169void CastSenderImpl::OnVideoInitialized( 170 const CastInitializationCallback& initialization_cb, 171 media::cast::CastInitializationStatus result) { 172 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); 173 video_frame_input_ = 174 new LocalVideoFrameInput(cast_environment_, video_sender_->AsWeakPtr()); 175 initialization_cb.Run(result); 176} 177 178} // namespace cast 179} // namespace media 180