1 // Copyright 2014 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/test/utility/in_process_receiver.h" 6 7 #include "base/bind_helpers.h" 8 #include "base/synchronization/waitable_event.h" 9 #include "base/time/time.h" 10 #include "media/base/video_frame.h" 11 #include "media/cast/cast_config.h" 12 #include "media/cast/cast_environment.h" 13 #include "media/cast/cast_receiver.h" 14 #include "media/cast/transport/cast_transport_config.h" 15 #include "media/cast/transport/transport/udp_transport.h" 16 17 using media::cast::transport::CastTransportStatus; 18 using media::cast::transport::UdpTransport; 19 20 namespace media { 21 namespace cast { 22 23 InProcessReceiver::InProcessReceiver( 24 const scoped_refptr<CastEnvironment>& cast_environment, 25 const net::IPEndPoint& local_end_point, 26 const net::IPEndPoint& remote_end_point, 27 const FrameReceiverConfig& audio_config, 28 const FrameReceiverConfig& video_config) 29 : cast_environment_(cast_environment), 30 local_end_point_(local_end_point), 31 remote_end_point_(remote_end_point), 32 audio_config_(audio_config), 33 video_config_(video_config), 34 weak_factory_(this) {} 35 36 InProcessReceiver::~InProcessReceiver() { 37 Stop(); 38 } 39 40 void InProcessReceiver::Start() { 41 cast_environment_->PostTask(CastEnvironment::MAIN, 42 FROM_HERE, 43 base::Bind(&InProcessReceiver::StartOnMainThread, 44 base::Unretained(this))); 45 } 46 47 void InProcessReceiver::Stop() { 48 base::WaitableEvent event(false, false); 49 if (cast_environment_->CurrentlyOn(CastEnvironment::MAIN)) { 50 StopOnMainThread(&event); 51 } else { 52 cast_environment_->PostTask(CastEnvironment::MAIN, 53 FROM_HERE, 54 base::Bind(&InProcessReceiver::StopOnMainThread, 55 base::Unretained(this), 56 &event)); 57 event.Wait(); 58 } 59 } 60 61 void InProcessReceiver::StopOnMainThread(base::WaitableEvent* event) { 62 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); 63 cast_receiver_.reset(NULL); 64 transport_.reset(NULL); 65 weak_factory_.InvalidateWeakPtrs(); 66 event->Signal(); 67 } 68 69 void InProcessReceiver::UpdateCastTransportStatus(CastTransportStatus status) { 70 LOG_IF(ERROR, status == media::cast::transport::TRANSPORT_SOCKET_ERROR) 71 << "Transport socket error occurred. InProcessReceiver is likely dead."; 72 VLOG(1) << "CastTransportStatus is now " << status; 73 } 74 75 void InProcessReceiver::StartOnMainThread() { 76 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); 77 78 DCHECK(!transport_ && !cast_receiver_); 79 transport_.reset( 80 new UdpTransport(NULL, 81 cast_environment_->GetTaskRunner(CastEnvironment::MAIN), 82 local_end_point_, 83 remote_end_point_, 84 base::Bind(&InProcessReceiver::UpdateCastTransportStatus, 85 base::Unretained(this)))); 86 cast_receiver_ = CastReceiver::Create( 87 cast_environment_, audio_config_, video_config_, transport_.get()); 88 89 // TODO(hubbe): Make the cast receiver do this automatically. 90 transport_->StartReceiving(cast_receiver_->packet_receiver()); 91 92 PullNextAudioFrame(); 93 PullNextVideoFrame(); 94 } 95 96 void InProcessReceiver::GotAudioFrame(scoped_ptr<AudioBus> audio_frame, 97 const base::TimeTicks& playout_time, 98 bool is_continuous) { 99 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); 100 if (audio_frame.get()) 101 OnAudioFrame(audio_frame.Pass(), playout_time, is_continuous); 102 PullNextAudioFrame(); 103 } 104 105 void InProcessReceiver::GotVideoFrame( 106 const scoped_refptr<VideoFrame>& video_frame, 107 const base::TimeTicks& playout_time, 108 bool is_continuous) { 109 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); 110 if (video_frame) 111 OnVideoFrame(video_frame, playout_time, is_continuous); 112 PullNextVideoFrame(); 113 } 114 115 void InProcessReceiver::PullNextAudioFrame() { 116 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); 117 cast_receiver_->RequestDecodedAudioFrame( 118 base::Bind(&InProcessReceiver::GotAudioFrame, 119 weak_factory_.GetWeakPtr())); 120 } 121 122 void InProcessReceiver::PullNextVideoFrame() { 123 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); 124 cast_receiver_->RequestDecodedVideoFrame(base::Bind( 125 &InProcessReceiver::GotVideoFrame, weak_factory_.GetWeakPtr())); 126 } 127 128 } // namespace cast 129 } // namespace media 130