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 <algorithm> 6 #include <climits> 7 #include <cstdarg> 8 #include <cstdio> 9 #include <string> 10 11 #include "base/at_exit.h" 12 #include "base/logging.h" 13 #include "base/memory/ref_counted.h" 14 #include "base/memory/scoped_ptr.h" 15 #include "base/message_loop/message_loop.h" 16 #include "base/threading/thread.h" 17 #include "base/time/default_tick_clock.h" 18 #include "media/base/video_frame.h" 19 #include "media/cast/cast_config.h" 20 #include "media/cast/cast_environment.h" 21 #include "media/cast/cast_receiver.h" 22 #include "media/cast/logging/logging_defines.h" 23 #include "media/cast/test/transport/transport.h" 24 #include "media/cast/test/utility/input_helper.h" 25 26 #if defined(OS_LINUX) 27 #include "media/cast/test/linux_output_window.h" 28 #endif // OS_LINUX 29 30 namespace media { 31 namespace cast { 32 // Settings chosen to match default sender settings. 33 #define DEFAULT_SEND_PORT "2346" 34 #define DEFAULT_RECEIVE_PORT "2344" 35 #define DEFAULT_SEND_IP "127.0.0.1" 36 #define DEFAULT_RESTART "0" 37 #define DEFAULT_AUDIO_FEEDBACK_SSRC "1" 38 #define DEFAULT_AUDIO_INCOMING_SSRC "2" 39 #define DEFAULT_AUDIO_PAYLOAD_TYPE "127" 40 #define DEFAULT_VIDEO_FEEDBACK_SSRC "12" 41 #define DEFAULT_VIDEO_INCOMING_SSRC "11" 42 #define DEFAULT_VIDEO_PAYLOAD_TYPE "96" 43 #define DEFAULT_VIDEO_CODEC_WIDTH "640" 44 #define DEFAULT_VIDEO_CODEC_HEIGHT "480" 45 #define DEFAULT_VIDEO_CODEC_BITRATE "2000" 46 47 static const int kAudioSamplingFrequency = 48000; 48 #if defined(OS_LINUX) 49 const int kVideoWindowWidth = 1280; 50 const int kVideoWindowHeight = 720; 51 #endif // OS_LINUX 52 static const int kFrameTimerMs = 33; 53 54 55 void GetPorts(int* tx_port, int* rx_port) { 56 test::InputBuilder tx_input("Enter send port.", 57 DEFAULT_SEND_PORT, 1, INT_MAX); 58 *tx_port = tx_input.GetIntInput(); 59 60 test::InputBuilder rx_input("Enter receive port.", 61 DEFAULT_RECEIVE_PORT, 1, INT_MAX); 62 *rx_port = rx_input.GetIntInput(); 63 } 64 65 std::string GetIpAddress(const std::string display_text) { 66 test::InputBuilder input(display_text, DEFAULT_SEND_IP, 67 INT_MIN, INT_MAX); 68 std::string ip_address = input.GetStringInput(); 69 // Ensure correct form: 70 while (std::count(ip_address.begin(), ip_address.end(), '.') != 3) { 71 ip_address = input.GetStringInput(); 72 } 73 return ip_address; 74 } 75 76 void GetSsrcs(AudioReceiverConfig* audio_config) { 77 test::InputBuilder input_tx("Choose audio sender SSRC.", 78 DEFAULT_AUDIO_FEEDBACK_SSRC, 1, INT_MAX); 79 audio_config->feedback_ssrc = input_tx.GetIntInput(); 80 81 test::InputBuilder input_rx("Choose audio receiver SSRC.", 82 DEFAULT_AUDIO_INCOMING_SSRC, 1, INT_MAX); 83 audio_config->incoming_ssrc = input_tx.GetIntInput(); 84 } 85 86 void GetSsrcs(VideoReceiverConfig* video_config) { 87 test::InputBuilder input_tx("Choose video sender SSRC.", 88 DEFAULT_VIDEO_FEEDBACK_SSRC, 1, INT_MAX); 89 video_config->feedback_ssrc = input_tx.GetIntInput(); 90 91 test::InputBuilder input_rx("Choose video receiver SSRC.", 92 DEFAULT_VIDEO_INCOMING_SSRC, 1, INT_MAX); 93 video_config->incoming_ssrc = input_rx.GetIntInput(); 94 } 95 96 void GetPayloadtype(AudioReceiverConfig* audio_config) { 97 test::InputBuilder input("Choose audio receiver payload type.", 98 DEFAULT_AUDIO_PAYLOAD_TYPE, 96, 127); 99 audio_config->rtp_payload_type = input.GetIntInput(); 100 } 101 102 AudioReceiverConfig GetAudioReceiverConfig() { 103 AudioReceiverConfig audio_config; 104 105 GetSsrcs(&audio_config); 106 GetPayloadtype(&audio_config); 107 108 audio_config.rtcp_c_name = "audio_receiver (at) a.b.c.d"; 109 110 VLOG(1) << "Using OPUS 48Khz stereo"; 111 audio_config.use_external_decoder = false; 112 audio_config.frequency = 48000; 113 audio_config.channels = 2; 114 audio_config.codec = kOpus; 115 return audio_config; 116 } 117 118 void GetPayloadtype(VideoReceiverConfig* video_config) { 119 test::InputBuilder input("Choose video receiver payload type.", 120 DEFAULT_VIDEO_PAYLOAD_TYPE, 96, 127); 121 video_config->rtp_payload_type = input.GetIntInput(); 122 } 123 124 VideoReceiverConfig GetVideoReceiverConfig() { 125 VideoReceiverConfig video_config; 126 127 GetSsrcs(&video_config); 128 GetPayloadtype(&video_config); 129 130 video_config.rtcp_c_name = "video_receiver (at) a.b.c.d"; 131 132 video_config.use_external_decoder = false; 133 134 VLOG(1) << "Using VP8"; 135 video_config.codec = kVp8; 136 return video_config; 137 } 138 139 140 class ReceiveProcess : public base::RefCountedThreadSafe<ReceiveProcess> { 141 public: 142 explicit ReceiveProcess(scoped_refptr<FrameReceiver> frame_receiver) 143 : frame_receiver_(frame_receiver), 144 #if defined(OS_LINUX) 145 render_(0, 0, kVideoWindowWidth, kVideoWindowHeight, "Cast_receiver"), 146 #endif // OS_LINUX 147 last_playout_time_(), 148 last_render_time_() {} 149 150 void Start() { 151 GetAudioFrame(base::TimeDelta::FromMilliseconds(kFrameTimerMs)); 152 GetVideoFrame(); 153 } 154 155 protected: 156 virtual ~ReceiveProcess() {} 157 158 private: 159 friend class base::RefCountedThreadSafe<ReceiveProcess>; 160 161 void DisplayFrame(const scoped_refptr<media::VideoFrame>& video_frame, 162 const base::TimeTicks& render_time) { 163 #ifdef OS_LINUX 164 render_.RenderFrame(video_frame); 165 #endif // OS_LINUX 166 // Print out the delta between frames. 167 if (!last_render_time_.is_null()){ 168 base::TimeDelta time_diff = render_time - last_render_time_; 169 VLOG(0) << " RenderDelay[mS] = " << time_diff.InMilliseconds(); 170 } 171 last_render_time_ = render_time; 172 GetVideoFrame(); 173 } 174 175 void ReceiveAudioFrame(scoped_ptr<PcmAudioFrame> audio_frame, 176 const base::TimeTicks& playout_time) { 177 // For audio just print the playout delta between audio frames. 178 // Default diff time is kFrameTimerMs. 179 base::TimeDelta time_diff = 180 base::TimeDelta::FromMilliseconds(kFrameTimerMs); 181 if (!last_playout_time_.is_null()){ 182 time_diff = playout_time - last_playout_time_; 183 VLOG(0) << " ***PlayoutDelay[mS] = " << time_diff.InMilliseconds(); 184 } 185 last_playout_time_ = playout_time; 186 GetAudioFrame(time_diff); 187 } 188 189 void GetAudioFrame(base::TimeDelta playout_diff) { 190 int num_10ms_blocks = playout_diff.InMilliseconds() / 10; 191 frame_receiver_->GetRawAudioFrame(num_10ms_blocks, kAudioSamplingFrequency, 192 base::Bind(&ReceiveProcess::ReceiveAudioFrame, this)); 193 } 194 195 void GetVideoFrame() { 196 frame_receiver_->GetRawVideoFrame( 197 base::Bind(&ReceiveProcess::DisplayFrame, this)); 198 } 199 200 scoped_refptr<FrameReceiver> frame_receiver_; 201 #ifdef OS_LINUX 202 test::LinuxOutputWindow render_; 203 #endif // OS_LINUX 204 base::TimeTicks last_playout_time_; 205 base::TimeTicks last_render_time_; 206 }; 207 208 } // namespace cast 209 } // namespace media 210 211 int main(int argc, char** argv) { 212 base::AtExitManager at_exit; 213 base::MessageLoopForIO main_message_loop; 214 VLOG(1) << "Cast Receiver"; 215 base::Thread main_thread("Cast main send thread"); 216 base::Thread audio_thread("Cast audio decoder thread"); 217 base::Thread video_thread("Cast video decoder thread"); 218 main_thread.Start(); 219 audio_thread.Start(); 220 video_thread.Start(); 221 222 base::DefaultTickClock clock; 223 // Enable receiver side threads, and disable logging. 224 scoped_refptr<media::cast::CastEnvironment> cast_environment(new 225 media::cast::CastEnvironment(&clock, 226 main_thread.message_loop_proxy(), 227 NULL, 228 audio_thread.message_loop_proxy(), 229 NULL, 230 video_thread.message_loop_proxy(), 231 media::cast::GetDefaultCastLoggingConfig())); 232 233 media::cast::AudioReceiverConfig audio_config = 234 media::cast::GetAudioReceiverConfig(); 235 media::cast::VideoReceiverConfig video_config = 236 media::cast::GetVideoReceiverConfig(); 237 238 scoped_ptr<media::cast::test::Transport> transport( 239 new media::cast::test::Transport(main_message_loop.message_loop_proxy())); 240 scoped_ptr<media::cast::CastReceiver> cast_receiver( 241 media::cast::CastReceiver::CreateCastReceiver( 242 cast_environment, 243 audio_config, 244 video_config, 245 transport->packet_sender())); 246 247 media::cast::PacketReceiver* packet_receiver = 248 cast_receiver->packet_receiver(); 249 250 int send_to_port, receive_port; 251 media::cast::GetPorts(&send_to_port, &receive_port); 252 std::string ip_address = media::cast::GetIpAddress("Enter destination IP."); 253 std::string local_ip_address = media::cast::GetIpAddress("Enter local IP."); 254 transport->SetLocalReceiver(packet_receiver, ip_address, local_ip_address, 255 receive_port); 256 transport->SetSendDestination(ip_address, send_to_port); 257 258 scoped_refptr<media::cast::ReceiveProcess> receive_process( 259 new media::cast::ReceiveProcess(cast_receiver->frame_receiver())); 260 receive_process->Start(); 261 main_message_loop.Run(); 262 transport->StopReceiving(); 263 return 0; 264 } 265