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.
11 #include "base/at_exit.h"
12 #include "base/command_line.h"
13 #include "base/logging.h"
14 #include "base/memory/ref_counted.h"
15 #include "base/memory/scoped_ptr.h"
16 #include "base/message_loop/message_loop.h"
17 #include "base/threading/thread.h"
18 #include "base/time/default_tick_clock.h"
19 #include "media/base/video_frame.h"
20 #include "media/cast/cast_config.h"
21 #include "media/cast/cast_environment.h"
22 #include "media/cast/cast_receiver.h"
23 #include "media/cast/logging/logging_defines.h"
24 #include "media/cast/test/utility/input_helper.h"
25 #include "media/cast/transport/transport/udp_transport.h"
26 #include "net/base/net_util.h"
29 #include "media/cast/test/linux_output_window.h"
34 // Settings chosen to match default sender settings.
35 #define DEFAULT_SEND_PORT "0"
36 #define DEFAULT_RECEIVE_PORT "2344"
37 #define DEFAULT_SEND_IP "0.0.0.0"
38 #define DEFAULT_RESTART "0"
39 #define DEFAULT_AUDIO_FEEDBACK_SSRC "1"
40 #define DEFAULT_AUDIO_INCOMING_SSRC "2"
41 #define DEFAULT_AUDIO_PAYLOAD_TYPE "127"
42 #define DEFAULT_VIDEO_FEEDBACK_SSRC "12"
43 #define DEFAULT_VIDEO_INCOMING_SSRC "11"
44 #define DEFAULT_VIDEO_PAYLOAD_TYPE "96"
45 #define DEFAULT_VIDEO_CODEC_WIDTH "640"
46 #define DEFAULT_VIDEO_CODEC_HEIGHT "480"
47 #define DEFAULT_VIDEO_CODEC_BITRATE "2000"
49 static const int kAudioSamplingFrequency
= 48000;
51 const int kVideoWindowWidth
= 1280;
52 const int kVideoWindowHeight
= 720;
54 static const int kFrameTimerMs
= 33;
57 void GetPorts(int* tx_port
, int* rx_port
) {
58 test::InputBuilder
tx_input("Enter send port.",
59 DEFAULT_SEND_PORT
, 1, INT_MAX
);
60 *tx_port
= tx_input
.GetIntInput();
62 test::InputBuilder
rx_input("Enter receive port.",
63 DEFAULT_RECEIVE_PORT
, 1, INT_MAX
);
64 *rx_port
= rx_input
.GetIntInput();
67 std::string
GetIpAddress(const std::string display_text
) {
68 test::InputBuilder
input(display_text
, DEFAULT_SEND_IP
, INT_MIN
, INT_MAX
);
69 std::string ip_address
= input
.GetStringInput();
70 // Ensure IP address is either the default value or in correct form.
71 while (ip_address
!= DEFAULT_SEND_IP
&&
72 std::count(ip_address
.begin(), ip_address
.end(), '.') != 3) {
73 ip_address
= input
.GetStringInput();
78 void GetSsrcs(AudioReceiverConfig
* audio_config
) {
79 test::InputBuilder
input_tx("Choose audio sender SSRC.",
80 DEFAULT_AUDIO_FEEDBACK_SSRC
, 1, INT_MAX
);
81 audio_config
->feedback_ssrc
= input_tx
.GetIntInput();
83 test::InputBuilder
input_rx("Choose audio receiver SSRC.",
84 DEFAULT_AUDIO_INCOMING_SSRC
, 1, INT_MAX
);
85 audio_config
->incoming_ssrc
= input_tx
.GetIntInput();
88 void GetSsrcs(VideoReceiverConfig
* video_config
) {
89 test::InputBuilder
input_tx("Choose video sender SSRC.",
90 DEFAULT_VIDEO_FEEDBACK_SSRC
, 1, INT_MAX
);
91 video_config
->feedback_ssrc
= input_tx
.GetIntInput();
93 test::InputBuilder
input_rx("Choose video receiver SSRC.",
94 DEFAULT_VIDEO_INCOMING_SSRC
, 1, INT_MAX
);
95 video_config
->incoming_ssrc
= input_rx
.GetIntInput();
98 void GetPayloadtype(AudioReceiverConfig
* audio_config
) {
99 test::InputBuilder
input("Choose audio receiver payload type.",
100 DEFAULT_AUDIO_PAYLOAD_TYPE
, 96, 127);
101 audio_config
->rtp_payload_type
= input
.GetIntInput();
104 AudioReceiverConfig
GetAudioReceiverConfig() {
105 AudioReceiverConfig audio_config
;
107 GetSsrcs(&audio_config
);
108 GetPayloadtype(&audio_config
);
110 audio_config
.rtcp_c_name
= "audio_receiver@a.b.c.d";
112 VLOG(1) << "Using OPUS 48Khz stereo";
113 audio_config
.use_external_decoder
= false;
114 audio_config
.frequency
= 48000;
115 audio_config
.channels
= 2;
116 audio_config
.codec
= transport::kOpus
;
120 void GetPayloadtype(VideoReceiverConfig
* video_config
) {
121 test::InputBuilder
input("Choose video receiver payload type.",
122 DEFAULT_VIDEO_PAYLOAD_TYPE
, 96, 127);
123 video_config
->rtp_payload_type
= input
.GetIntInput();
126 VideoReceiverConfig
GetVideoReceiverConfig() {
127 VideoReceiverConfig video_config
;
129 GetSsrcs(&video_config
);
130 GetPayloadtype(&video_config
);
132 video_config
.rtcp_c_name
= "video_receiver@a.b.c.d";
134 video_config
.use_external_decoder
= false;
136 VLOG(1) << "Using VP8";
137 video_config
.codec
= transport::kVp8
;
142 class ReceiveProcess
: public base::RefCountedThreadSafe
<ReceiveProcess
> {
144 explicit ReceiveProcess(scoped_refptr
<FrameReceiver
> frame_receiver
)
145 : frame_receiver_(frame_receiver
),
146 #if defined(OS_LINUX)
147 render_(0, 0, kVideoWindowWidth
, kVideoWindowHeight
, "Cast_receiver"),
149 last_playout_time_(),
150 last_render_time_() {}
153 GetAudioFrame(base::TimeDelta::FromMilliseconds(kFrameTimerMs
));
158 virtual ~ReceiveProcess() {}
161 friend class base::RefCountedThreadSafe
<ReceiveProcess
>;
163 void DisplayFrame(const scoped_refptr
<media::VideoFrame
>& video_frame
,
164 const base::TimeTicks
& render_time
) {
166 render_
.RenderFrame(video_frame
);
168 // Print out the delta between frames.
169 if (!last_render_time_
.is_null()){
170 base::TimeDelta time_diff
= render_time
- last_render_time_
;
171 VLOG(0) << " RenderDelay[mS] = " << time_diff
.InMilliseconds();
173 last_render_time_
= render_time
;
177 void ReceiveAudioFrame(scoped_ptr
<PcmAudioFrame
> audio_frame
,
178 const base::TimeTicks
& playout_time
) {
179 // For audio just print the playout delta between audio frames.
180 // Default diff time is kFrameTimerMs.
181 base::TimeDelta time_diff
=
182 base::TimeDelta::FromMilliseconds(kFrameTimerMs
);
183 if (!last_playout_time_
.is_null()){
184 time_diff
= playout_time
- last_playout_time_
;
185 VLOG(0) << " ***PlayoutDelay[mS] = " << time_diff
.InMilliseconds();
187 last_playout_time_
= playout_time
;
188 GetAudioFrame(time_diff
);
191 void GetAudioFrame(base::TimeDelta playout_diff
) {
192 int num_10ms_blocks
= playout_diff
.InMilliseconds() / 10;
193 frame_receiver_
->GetRawAudioFrame(num_10ms_blocks
, kAudioSamplingFrequency
,
194 base::Bind(&ReceiveProcess::ReceiveAudioFrame
, this));
197 void GetVideoFrame() {
198 frame_receiver_
->GetRawVideoFrame(
199 base::Bind(&ReceiveProcess::DisplayFrame
, this));
202 scoped_refptr
<FrameReceiver
> frame_receiver_
;
204 test::LinuxOutputWindow render_
;
206 base::TimeTicks last_playout_time_
;
207 base::TimeTicks last_render_time_
;
213 int main(int argc
, char** argv
) {
214 base::AtExitManager at_exit
;
215 base::MessageLoopForIO main_message_loop
;
216 CommandLine::Init(argc
, argv
);
217 InitLogging(logging::LoggingSettings());
219 VLOG(1) << "Cast Receiver";
220 base::Thread
audio_thread("Cast audio decoder thread");
221 base::Thread
video_thread("Cast video decoder thread");
222 audio_thread
.Start();
223 video_thread
.Start();
225 base::DefaultTickClock clock
;
226 // Enable receiver side threads, and disable logging.
227 scoped_refptr
<media::cast::CastEnvironment
> cast_environment(new
228 media::cast::CastEnvironment(&clock
,
229 main_message_loop
.message_loop_proxy(),
231 audio_thread
.message_loop_proxy(),
233 video_thread
.message_loop_proxy(),
234 main_message_loop
.message_loop_proxy(),
235 media::cast::GetDefaultCastLoggingConfig()));
237 media::cast::AudioReceiverConfig audio_config
=
238 media::cast::GetAudioReceiverConfig();
239 media::cast::VideoReceiverConfig video_config
=
240 media::cast::GetVideoReceiverConfig();
242 int remote_port
, local_port
;
243 media::cast::GetPorts(&remote_port
, &local_port
);
245 LOG(ERROR
) << "Invalid local port.";
249 std::string remote_ip_address
= media::cast::GetIpAddress("Enter remote IP.");
250 std::string local_ip_address
= media::cast::GetIpAddress("Enter local IP.");
251 net::IPAddressNumber remote_ip_number
;
252 net::IPAddressNumber local_ip_number
;
254 if (!net::ParseIPLiteralToNumber(remote_ip_address
, &remote_ip_number
)) {
255 LOG(ERROR
) << "Invalid remote IP address.";
259 if (!net::ParseIPLiteralToNumber(local_ip_address
, &local_ip_number
)) {
260 LOG(ERROR
) << "Invalid local IP address.";
264 net::IPEndPoint
remote_end_point(remote_ip_number
, remote_port
);
265 net::IPEndPoint
local_end_point(local_ip_number
, local_port
);
267 scoped_ptr
<media::cast::transport::UdpTransport
> transport(
268 new media::cast::transport::UdpTransport(
269 main_message_loop
.message_loop_proxy(),
272 scoped_ptr
<media::cast::CastReceiver
> cast_receiver(
273 media::cast::CastReceiver::CreateCastReceiver(
279 media::cast::transport::PacketReceiver
* packet_receiver
=
280 cast_receiver
->packet_receiver();
282 transport
->StartReceiving(packet_receiver
);
284 scoped_refptr
<media::cast::ReceiveProcess
> receive_process(
285 new media::cast::ReceiveProcess(cast_receiver
->frame_receiver()));
286 receive_process
->Start();
287 main_message_loop
.Run();