Remove Unused AsTextButtonBorder RTTI helper.
[chromium-blink-merge.git] / media / cast / test / sender.cc
blob603b2de847c0124afda6e6dec1ff6becb689b513
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.
5 // Test application that simulates a cast sender - Data can be either generated
6 // or read from a file.
8 #include "base/at_exit.h"
9 #include "base/logging.h"
10 #include "base/memory/scoped_ptr.h"
11 #include "base/threading/thread.h"
12 #include "base/time/default_tick_clock.h"
13 #include "media/base/video_frame.h"
14 #include "media/cast/cast_config.h"
15 #include "media/cast/cast_environment.h"
16 #include "media/cast/cast_sender.h"
17 #include "media/cast/logging/logging_defines.h"
18 #include "media/cast/test/utility/audio_utility.h"
19 #include "media/cast/test/utility/input_builder.h"
20 #include "media/cast/test/utility/video_utility.h"
21 #include "media/cast/transport/cast_transport_defines.h"
22 #include "media/cast/transport/cast_transport_sender.h"
23 #include "media/cast/transport/transport/udp_transport.h"
24 #include "ui/gfx/size.h"
26 namespace media {
27 namespace cast {
28 // Settings chosen to match default receiver settings.
29 #define DEFAULT_RECEIVER_PORT "2344"
30 #define DEFAULT_RECEIVER_IP "127.0.0.1"
31 #define DEFAULT_READ_FROM_FILE "0"
32 #define DEFAULT_AUDIO_SENDER_SSRC "1"
33 #define DEFAULT_AUDIO_RECEIVER_SSRC "2"
34 #define DEFAULT_AUDIO_PAYLOAD_TYPE "127"
35 #define DEFAULT_VIDEO_SENDER_SSRC "11"
36 #define DEFAULT_VIDEO_RECEIVER_SSRC "12"
37 #define DEFAULT_VIDEO_PAYLOAD_TYPE "96"
38 #define DEFAULT_VIDEO_CODEC_WIDTH "1280"
39 #define DEFAULT_VIDEO_CODEC_HEIGHT "720"
40 #define DEFAULT_VIDEO_CODEC_BITRATE "2000"
41 #define DEFAULT_VIDEO_CODEC_MAX_BITRATE "4000"
42 #define DEFAULT_VIDEO_CODEC_MIN_BITRATE "1000"
44 namespace {
45 static const int kAudioChannels = 2;
46 static const int kAudioSamplingFrequency = 48000;
47 static const int kSoundFrequency = 1234; // Frequency of sinusoid wave.
48 // The tests are commonly implemented with |kFrameTimerMs| RunTask function;
49 // a normal video is 30 fps hence the 33 ms between frames.
50 static const float kSoundVolume = 0.5f;
51 static const int kFrameTimerMs = 33;
53 // Dummy callback function that does nothing except to accept ownership of
54 // |audio_bus| for destruction. This guarantees that the audio_bus is valid for
55 // the entire duration of the encode/send process (not equivalent to DoNothing).
56 void OwnThatAudioBus(scoped_ptr<AudioBus> audio_bus) {}
57 } // namespace
59 void GetPort(int* port) {
60 test::InputBuilder input(
61 "Enter receiver port.", DEFAULT_RECEIVER_PORT, 1, INT_MAX);
62 *port = input.GetIntInput();
65 std::string GetIpAddress(const std::string display_text) {
66 test::InputBuilder input(display_text, DEFAULT_RECEIVER_IP, INT_MIN, INT_MAX);
67 std::string ip_address = input.GetStringInput();
68 // Verify correct form:
69 while (std::count(ip_address.begin(), ip_address.end(), '.') != 3) {
70 ip_address = input.GetStringInput();
72 return ip_address;
75 bool ReadFromFile() {
76 test::InputBuilder input(
77 "Enter 1 to read from file.", DEFAULT_READ_FROM_FILE, 0, 1);
78 return (1 == input.GetIntInput());
81 std::string GetVideoFile() {
82 test::InputBuilder input(
83 "Enter file and path to raw video file.", "", INT_MIN, INT_MAX);
84 return input.GetStringInput();
87 void GetSsrcs(AudioSenderConfig* audio_config) {
88 test::InputBuilder input_tx(
89 "Choose audio sender SSRC.", DEFAULT_AUDIO_SENDER_SSRC, 1, INT_MAX);
90 audio_config->sender_ssrc = input_tx.GetIntInput();
92 test::InputBuilder input_rx(
93 "Choose audio receiver SSRC.", DEFAULT_AUDIO_RECEIVER_SSRC, 1, INT_MAX);
94 audio_config->incoming_feedback_ssrc = input_rx.GetIntInput();
97 void GetSsrcs(VideoSenderConfig* video_config) {
98 test::InputBuilder input_tx(
99 "Choose video sender SSRC.", DEFAULT_VIDEO_SENDER_SSRC, 1, INT_MAX);
100 video_config->sender_ssrc = input_tx.GetIntInput();
102 test::InputBuilder input_rx(
103 "Choose video receiver SSRC.", DEFAULT_VIDEO_RECEIVER_SSRC, 1, INT_MAX);
104 video_config->incoming_feedback_ssrc = input_rx.GetIntInput();
107 void GetPayloadtype(AudioSenderConfig* audio_config) {
108 test::InputBuilder input(
109 "Choose audio sender payload type.", DEFAULT_AUDIO_PAYLOAD_TYPE, 96, 127);
110 audio_config->rtp_config.payload_type = input.GetIntInput();
113 AudioSenderConfig GetAudioSenderConfig() {
114 AudioSenderConfig audio_config;
116 GetSsrcs(&audio_config);
117 GetPayloadtype(&audio_config);
119 audio_config.rtcp_c_name = "audio_sender@a.b.c.d";
121 VLOG(0) << "Using OPUS 48Khz stereo at 64kbit/s";
122 audio_config.use_external_encoder = false;
123 audio_config.frequency = kAudioSamplingFrequency;
124 audio_config.channels = kAudioChannels;
125 audio_config.bitrate = 64000;
126 audio_config.codec = transport::kOpus;
127 return audio_config;
130 void GetPayloadtype(VideoSenderConfig* video_config) {
131 test::InputBuilder input(
132 "Choose video sender payload type.", DEFAULT_VIDEO_PAYLOAD_TYPE, 96, 127);
133 video_config->rtp_config.payload_type = input.GetIntInput();
136 void GetVideoCodecSize(VideoSenderConfig* video_config) {
137 test::InputBuilder input_width(
138 "Choose video width.", DEFAULT_VIDEO_CODEC_WIDTH, 144, 1920);
139 video_config->width = input_width.GetIntInput();
141 test::InputBuilder input_height(
142 "Choose video height.", DEFAULT_VIDEO_CODEC_HEIGHT, 176, 1080);
143 video_config->height = input_height.GetIntInput();
146 void GetVideoBitrates(VideoSenderConfig* video_config) {
147 test::InputBuilder input_start_br(
148 "Choose start bitrate[kbps].", DEFAULT_VIDEO_CODEC_BITRATE, 0, INT_MAX);
149 video_config->start_bitrate = input_start_br.GetIntInput() * 1000;
151 test::InputBuilder input_max_br(
152 "Choose max bitrate[kbps].", DEFAULT_VIDEO_CODEC_MAX_BITRATE, 0, INT_MAX);
153 video_config->max_bitrate = input_max_br.GetIntInput() * 1000;
155 test::InputBuilder input_min_br(
156 "Choose min bitrate[kbps].", DEFAULT_VIDEO_CODEC_MIN_BITRATE, 0, INT_MAX);
157 video_config->min_bitrate = input_min_br.GetIntInput() * 1000;
160 VideoSenderConfig GetVideoSenderConfig() {
161 VideoSenderConfig video_config;
163 GetSsrcs(&video_config);
164 GetPayloadtype(&video_config);
165 GetVideoCodecSize(&video_config);
166 GetVideoBitrates(&video_config);
168 video_config.rtcp_c_name = "video_sender@a.b.c.d";
170 video_config.use_external_encoder = false;
172 VLOG(0) << "Using VP8 at 30 fps";
173 video_config.min_qp = 4;
174 video_config.max_qp = 40;
175 video_config.max_frame_rate = 30;
176 video_config.codec = transport::kVp8;
177 video_config.max_number_of_video_buffers_used = 1;
178 video_config.number_of_cores = 1;
179 return video_config;
182 class SendProcess {
183 public:
184 SendProcess(scoped_refptr<base::SingleThreadTaskRunner> thread_proxy,
185 base::TickClock* clock,
186 const VideoSenderConfig& video_config,
187 FrameInput* frame_input)
188 : test_app_thread_proxy_(thread_proxy),
189 video_config_(video_config),
190 audio_diff_(kFrameTimerMs),
191 frame_input_(frame_input),
192 synthetic_count_(0),
193 clock_(clock),
194 start_time_(),
195 send_time_(),
196 weak_factory_(this) {
197 audio_bus_factory_.reset(new TestAudioBusFactory(kAudioChannels,
198 kAudioSamplingFrequency,
199 kSoundFrequency,
200 kSoundVolume));
201 if (ReadFromFile()) {
202 std::string video_file_name = GetVideoFile();
203 video_file_ = fopen(video_file_name.c_str(), "r");
204 if (video_file_ == NULL) {
205 VLOG(1) << "Failed to open file";
206 exit(-1);
208 } else {
209 video_file_ = NULL;
213 ~SendProcess() {
214 if (video_file_)
215 fclose(video_file_);
218 void SendFrame() {
219 // Make sure that we don't drift.
220 int num_10ms_blocks = audio_diff_ / 10;
221 // Avoid drift.
222 audio_diff_ += kFrameTimerMs - num_10ms_blocks * 10;
224 scoped_ptr<AudioBus> audio_bus(audio_bus_factory_->NextAudioBus(
225 base::TimeDelta::FromMilliseconds(10) * num_10ms_blocks));
226 AudioBus* const audio_bus_ptr = audio_bus.get();
227 frame_input_->InsertAudio(
228 audio_bus_ptr,
229 clock_->NowTicks(),
230 base::Bind(&OwnThatAudioBus, base::Passed(&audio_bus)));
232 gfx::Size size(video_config_.width, video_config_.height);
233 // TODO(mikhal): Use the provided timestamp.
234 if (start_time_.is_null())
235 start_time_ = clock_->NowTicks();
236 base::TimeDelta time_diff = clock_->NowTicks() - start_time_;
237 scoped_refptr<media::VideoFrame> video_frame =
238 media::VideoFrame::CreateFrame(
239 VideoFrame::I420, size, gfx::Rect(size), size, time_diff);
240 if (video_file_) {
241 if (!PopulateVideoFrameFromFile(video_frame, video_file_))
242 return;
243 } else {
244 PopulateVideoFrame(video_frame, synthetic_count_);
245 ++synthetic_count_;
248 // Time the sending of the frame to match the set frame rate.
249 // Sleep if that time has yet to elapse.
250 base::TimeTicks now = clock_->NowTicks();
251 base::TimeDelta video_frame_time =
252 base::TimeDelta::FromMilliseconds(kFrameTimerMs);
253 base::TimeDelta elapsed_time = now - send_time_;
254 if (elapsed_time < video_frame_time) {
255 VLOG(1) << "Wait" << (video_frame_time - elapsed_time).InMilliseconds();
256 test_app_thread_proxy_->PostDelayedTask(
257 FROM_HERE,
258 base::Bind(&SendProcess::SendVideoFrameOnTime,
259 base::Unretained(this),
260 video_frame),
261 video_frame_time - elapsed_time);
262 } else {
263 test_app_thread_proxy_->PostTask(
264 FROM_HERE,
265 base::Bind(&SendProcess::SendVideoFrameOnTime,
266 base::Unretained(this),
267 video_frame));
271 void SendVideoFrameOnTime(scoped_refptr<media::VideoFrame> video_frame) {
272 send_time_ = clock_->NowTicks();
273 frame_input_->InsertRawVideoFrame(video_frame, send_time_);
274 test_app_thread_proxy_->PostTask(
275 FROM_HERE, base::Bind(&SendProcess::SendFrame, base::Unretained(this)));
278 private:
279 scoped_refptr<base::SingleThreadTaskRunner> test_app_thread_proxy_;
280 const VideoSenderConfig video_config_;
281 int audio_diff_;
282 const scoped_refptr<FrameInput> frame_input_;
283 FILE* video_file_;
284 uint8 synthetic_count_;
285 base::TickClock* const clock_; // Not owned by this class.
286 base::TimeTicks start_time_;
287 base::TimeTicks send_time_;
288 scoped_ptr<TestAudioBusFactory> audio_bus_factory_;
289 base::WeakPtrFactory<SendProcess> weak_factory_;
292 } // namespace cast
293 } // namespace media
295 namespace {
296 void UpdateCastTransportStatus(
297 media::cast::transport::CastTransportStatus status) {}
299 void InitializationResult(media::cast::CastInitializationStatus result) {
300 CHECK_EQ(result, media::cast::STATUS_INITIALIZED);
301 VLOG(1) << "Cast Sender initialized";
304 net::IPEndPoint CreateUDPAddress(std::string ip_str, int port) {
305 net::IPAddressNumber ip_number;
306 CHECK(net::ParseIPLiteralToNumber(ip_str, &ip_number));
307 return net::IPEndPoint(ip_number, port);
310 } // namespace
312 int main(int argc, char** argv) {
313 base::AtExitManager at_exit;
314 VLOG(1) << "Cast Sender";
315 base::Thread test_thread("Cast sender test app thread");
316 base::Thread audio_thread("Cast audio encoder thread");
317 base::Thread video_thread("Cast video encoder thread");
318 test_thread.Start();
319 audio_thread.Start();
320 video_thread.Start();
322 scoped_ptr<base::TickClock> clock(new base::DefaultTickClock());
323 base::MessageLoopForIO io_message_loop;
325 int remote_port;
326 media::cast::GetPort(&remote_port);
328 std::string remote_ip_address =
329 media::cast::GetIpAddress("Enter receiver IP.");
331 media::cast::AudioSenderConfig audio_config =
332 media::cast::GetAudioSenderConfig();
333 media::cast::VideoSenderConfig video_config =
334 media::cast::GetVideoSenderConfig();
336 // Setting up transport config.
337 media::cast::transport::CastTransportConfig config;
338 config.receiver_endpoint = CreateUDPAddress(remote_ip_address, remote_port);
339 config.local_endpoint = CreateUDPAddress("0.0.0.0", 0);
340 config.audio_ssrc = audio_config.sender_ssrc;
341 config.video_ssrc = video_config.sender_ssrc;
342 config.audio_rtp_config = audio_config.rtp_config;
343 config.video_rtp_config = video_config.rtp_config;
345 scoped_ptr<media::cast::transport::CastTransportSender> transport_sender(
346 media::cast::transport::CastTransportSender::CreateCastTransportSender(
347 clock.get(),
348 config,
349 base::Bind(&UpdateCastTransportStatus),
350 io_message_loop.message_loop_proxy()));
352 // Enable main and send side threads only. Disable logging.
353 // Running transport on the main thread.
354 scoped_refptr<media::cast::CastEnvironment> cast_environment(
355 new media::cast::CastEnvironment(
356 clock.Pass(),
357 io_message_loop.message_loop_proxy(),
358 audio_thread.message_loop_proxy(),
359 NULL,
360 video_thread.message_loop_proxy(),
361 NULL,
362 io_message_loop.message_loop_proxy(),
363 media::cast::GetDefaultCastSenderLoggingConfig()));
365 scoped_ptr<media::cast::CastSender> cast_sender(
366 media::cast::CastSender::CreateCastSender(
367 cast_environment,
368 &audio_config,
369 &video_config,
370 NULL, // gpu_factories.
371 base::Bind(&InitializationResult),
372 transport_sender.get()));
374 transport_sender->SetPacketReceiver(cast_sender->packet_receiver());
376 media::cast::FrameInput* frame_input = cast_sender->frame_input();
377 scoped_ptr<media::cast::SendProcess> send_process(
378 new media::cast::SendProcess(test_thread.message_loop_proxy(),
379 cast_environment->Clock(),
380 video_config,
381 frame_input));
383 test_thread.message_loop_proxy()->PostTask(
384 FROM_HERE,
385 base::Bind(&media::cast::SendProcess::SendFrame,
386 base::Unretained(send_process.get())));
388 io_message_loop.Run();
389 return 0;