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 13 namespace media { 14 namespace cast { 15 16 // The LocalVideoFrameInput class posts all incoming video frames to the main 17 // cast thread for processing. 18 class 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. 49 class 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 77 scoped_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 85 CastSenderImpl::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 94 void 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 118 void 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 145 CastSenderImpl::~CastSenderImpl() { 146 VLOG(1) << "CastSenderImpl@" << this << "::~CastSenderImpl()"; 147 } 148 149 scoped_refptr<AudioFrameInput> CastSenderImpl::audio_frame_input() { 150 return audio_frame_input_; 151 } 152 153 scoped_refptr<VideoFrameInput> CastSenderImpl::video_frame_input() { 154 return video_frame_input_; 155 } 156 157 void 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 169 void 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