OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 // Test application that simulates a cast sender - Data can be either generated | 5 // Test application that simulates a cast sender - Data can be either generated |
6 // or read from a file. | 6 // or read from a file. |
7 | 7 |
8 #include <queue> | 8 #include <queue> |
9 | 9 |
10 #include "base/at_exit.h" | 10 #include "base/at_exit.h" |
(...skipping 20 matching lines...) Expand all Loading... |
31 #include "media/cast/logging/receiver_time_offset_estimator_impl.h" | 31 #include "media/cast/logging/receiver_time_offset_estimator_impl.h" |
32 #include "media/cast/logging/stats_event_subscriber.h" | 32 #include "media/cast/logging/stats_event_subscriber.h" |
33 #include "media/cast/net/cast_transport_defines.h" | 33 #include "media/cast/net/cast_transport_defines.h" |
34 #include "media/cast/net/cast_transport_sender.h" | 34 #include "media/cast/net/cast_transport_sender.h" |
35 #include "media/cast/net/udp_transport.h" | 35 #include "media/cast/net/udp_transport.h" |
36 #include "media/cast/test/fake_media_source.h" | 36 #include "media/cast/test/fake_media_source.h" |
37 #include "media/cast/test/utility/default_config.h" | 37 #include "media/cast/test/utility/default_config.h" |
38 #include "media/cast/test/utility/input_builder.h" | 38 #include "media/cast/test/utility/input_builder.h" |
39 | 39 |
40 namespace { | 40 namespace { |
41 static const int kAudioChannels = 2; | |
42 static const int kAudioSamplingFrequency = 48000; | |
43 | 41 |
44 // The max allowed size of serialized log. | 42 // The max allowed size of serialized log. |
45 const int kMaxSerializedLogBytes = 10 * 1000 * 1000; | 43 const int kMaxSerializedLogBytes = 10 * 1000 * 1000; |
46 | 44 |
47 // Flags for this program: | 45 // Flags for this program: |
48 // | 46 // |
49 // --address=xx.xx.xx.xx | 47 // --address=xx.xx.xx.xx |
50 // IP address of receiver. | 48 // IP address of receiver. |
51 // | 49 // |
52 // --port=xxxx | 50 // --port=xxxx |
53 // Port number of receiver. | 51 // Port number of receiver. |
54 // | 52 // |
55 // --source-file=xxx.webm | 53 // --source-file=xxx.webm |
56 // WebM file as source of video frames. | 54 // WebM file as source of video frames. |
57 // | 55 // |
58 // --fps=xx | 56 // --fps=xx |
59 // Override framerate of the video stream. | 57 // Override framerate of the video stream. |
| 58 // |
| 59 // --vary-frame-sizes |
| 60 // Randomly vary the video frame sizes at random points in time. Has no |
| 61 // effect if --source-file is being used. |
60 const char kSwitchAddress[] = "address"; | 62 const char kSwitchAddress[] = "address"; |
61 const char kSwitchPort[] = "port"; | 63 const char kSwitchPort[] = "port"; |
62 const char kSwitchSourceFile[] = "source-file"; | 64 const char kSwitchSourceFile[] = "source-file"; |
63 const char kSwitchFps[] = "fps"; | 65 const char kSwitchFps[] = "fps"; |
64 | 66 const char kSwitchVaryFrameSizes[] = "vary-frame-sizes"; |
65 media::cast::AudioSenderConfig GetAudioSenderConfig() { | |
66 media::cast::AudioSenderConfig audio_config; | |
67 | |
68 audio_config.use_external_encoder = false; | |
69 audio_config.frequency = kAudioSamplingFrequency; | |
70 audio_config.channels = kAudioChannels; | |
71 audio_config.bitrate = 0; // Use Opus auto-VBR mode. | |
72 audio_config.codec = media::cast::CODEC_AUDIO_OPUS; | |
73 audio_config.ssrc = 1; | |
74 audio_config.receiver_ssrc = 2; | |
75 audio_config.rtp_payload_type = 127; | |
76 // TODO(miu): The default in cast_defines.h is 100. Should this be 100, and | |
77 // should receiver.cc's config also be 100? | |
78 audio_config.max_playout_delay = base::TimeDelta::FromMilliseconds(300); | |
79 return audio_config; | |
80 } | |
81 | |
82 media::cast::VideoSenderConfig GetVideoSenderConfig() { | |
83 media::cast::VideoSenderConfig video_config; | |
84 | |
85 video_config.use_external_encoder = false; | |
86 | |
87 // Resolution. | |
88 video_config.width = 1280; | |
89 video_config.height = 720; | |
90 video_config.max_frame_rate = 30; | |
91 | |
92 // Bitrates. | |
93 video_config.max_bitrate = 2500000; | |
94 video_config.min_bitrate = 100000; | |
95 video_config.start_bitrate = video_config.min_bitrate; | |
96 | |
97 // Codec. | |
98 video_config.codec = media::cast::CODEC_VIDEO_VP8; | |
99 video_config.max_number_of_video_buffers_used = 1; | |
100 video_config.number_of_encode_threads = 2; | |
101 | |
102 // Quality options. | |
103 video_config.min_qp = 4; | |
104 video_config.max_qp = 40; | |
105 | |
106 // SSRCs and payload type. Don't change them. | |
107 video_config.ssrc = 11; | |
108 video_config.receiver_ssrc = 12; | |
109 video_config.rtp_payload_type = 96; | |
110 // TODO(miu): The default in cast_defines.h is 100. Should this be 100, and | |
111 // should receiver.cc's config also be 100? | |
112 video_config.max_playout_delay = base::TimeDelta::FromMilliseconds(300); | |
113 return video_config; | |
114 } | |
115 | 67 |
116 void UpdateCastTransportStatus( | 68 void UpdateCastTransportStatus( |
117 media::cast::CastTransportStatus status) { | 69 media::cast::CastTransportStatus status) { |
118 VLOG(1) << "Transport status: " << status; | 70 VLOG(1) << "Transport status: " << status; |
119 } | 71 } |
120 | 72 |
121 void LogRawEvents( | 73 void LogRawEvents( |
122 const scoped_refptr<media::cast::CastEnvironment>& cast_environment, | 74 const scoped_refptr<media::cast::CastEnvironment>& cast_environment, |
123 const std::vector<media::cast::PacketEvent>& packet_events, | 75 const std::vector<media::cast::PacketEvent>& packet_events, |
124 const std::vector<media::cast::FrameEvent>& frame_events) { | 76 const std::vector<media::cast::FrameEvent>& frame_events) { |
(...skipping 17 matching lines...) Expand all Loading... |
142 it != frame_events.end(); | 94 it != frame_events.end(); |
143 ++it) { | 95 ++it) { |
144 cast_environment->Logging()->InsertFrameEvent(it->timestamp, | 96 cast_environment->Logging()->InsertFrameEvent(it->timestamp, |
145 it->type, | 97 it->type, |
146 it->media_type, | 98 it->media_type, |
147 it->rtp_timestamp, | 99 it->rtp_timestamp, |
148 it->frame_id); | 100 it->frame_id); |
149 } | 101 } |
150 } | 102 } |
151 | 103 |
152 void InitializationResult(media::cast::CastInitializationStatus result) { | 104 void QuitLoopOnInitializationResult( |
153 bool end_result = result == media::cast::STATUS_AUDIO_INITIALIZED || | 105 media::cast::CastInitializationStatus result) { |
154 result == media::cast::STATUS_VIDEO_INITIALIZED; | 106 CHECK(result == media::cast::STATUS_AUDIO_INITIALIZED || |
155 CHECK(end_result) << "Cast sender uninitialized"; | 107 result == media::cast::STATUS_VIDEO_INITIALIZED) |
| 108 << "Cast sender uninitialized"; |
| 109 base::MessageLoop::current()->Quit(); |
156 } | 110 } |
157 | 111 |
158 net::IPEndPoint CreateUDPAddress(std::string ip_str, uint16 port) { | 112 net::IPEndPoint CreateUDPAddress(std::string ip_str, uint16 port) { |
159 net::IPAddressNumber ip_number; | 113 net::IPAddressNumber ip_number; |
160 CHECK(net::ParseIPLiteralToNumber(ip_str, &ip_number)); | 114 CHECK(net::ParseIPLiteralToNumber(ip_str, &ip_number)); |
161 return net::IPEndPoint(ip_number, port); | 115 return net::IPEndPoint(ip_number, port); |
162 } | 116 } |
163 | 117 |
164 void DumpLoggingData(const media::cast::proto::LogMetadata& log_metadata, | 118 void DumpLoggingData(const media::cast::proto::LogMetadata& log_metadata, |
165 const media::cast::FrameEventList& frame_events, | 119 const media::cast::FrameEventList& frame_events, |
(...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
275 if (remote_ip_address.empty()) | 229 if (remote_ip_address.empty()) |
276 remote_ip_address = "127.0.0.1"; | 230 remote_ip_address = "127.0.0.1"; |
277 int remote_port = 0; | 231 int remote_port = 0; |
278 if (!base::StringToInt(cmd->GetSwitchValueASCII(kSwitchPort), &remote_port) || | 232 if (!base::StringToInt(cmd->GetSwitchValueASCII(kSwitchPort), &remote_port) || |
279 remote_port < 0 || remote_port > 65535) { | 233 remote_port < 0 || remote_port > 65535) { |
280 remote_port = 2344; | 234 remote_port = 2344; |
281 } | 235 } |
282 LOG(INFO) << "Sending to " << remote_ip_address << ":" << remote_port | 236 LOG(INFO) << "Sending to " << remote_ip_address << ":" << remote_port |
283 << "."; | 237 << "."; |
284 | 238 |
285 media::cast::AudioSenderConfig audio_config = GetAudioSenderConfig(); | 239 media::cast::AudioSenderConfig audio_config = |
286 media::cast::VideoSenderConfig video_config = GetVideoSenderConfig(); | 240 media::cast::GetDefaultAudioSenderConfig(); |
| 241 media::cast::VideoSenderConfig video_config = |
| 242 media::cast::GetDefaultVideoSenderConfig(); |
287 | 243 |
288 // Running transport on the main thread. | 244 // Running transport on the main thread. |
289 // Setting up transport config. | 245 // Setting up transport config. |
290 net::IPEndPoint remote_endpoint = | 246 net::IPEndPoint remote_endpoint = |
291 CreateUDPAddress(remote_ip_address, static_cast<uint16>(remote_port)); | 247 CreateUDPAddress(remote_ip_address, static_cast<uint16>(remote_port)); |
292 | 248 |
293 // Enable raw event and stats logging. | 249 // Enable raw event and stats logging. |
294 // Running transport on the main thread. | 250 // Running transport on the main thread. |
295 scoped_refptr<media::cast::CastEnvironment> cast_environment( | 251 scoped_refptr<media::cast::CastEnvironment> cast_environment( |
296 new media::cast::CastEnvironment( | 252 new media::cast::CastEnvironment( |
(...skipping 11 matching lines...) Expand all Loading... |
308 int override_fps = 0; | 264 int override_fps = 0; |
309 if (!base::StringToInt(cmd->GetSwitchValueASCII(kSwitchFps), | 265 if (!base::StringToInt(cmd->GetSwitchValueASCII(kSwitchFps), |
310 &override_fps)){ | 266 &override_fps)){ |
311 override_fps = 0; | 267 override_fps = 0; |
312 } | 268 } |
313 base::FilePath source_path = cmd->GetSwitchValuePath(kSwitchSourceFile); | 269 base::FilePath source_path = cmd->GetSwitchValuePath(kSwitchSourceFile); |
314 if (!source_path.empty()) { | 270 if (!source_path.empty()) { |
315 LOG(INFO) << "Source: " << source_path.value(); | 271 LOG(INFO) << "Source: " << source_path.value(); |
316 fake_media_source->SetSourceFile(source_path, override_fps); | 272 fake_media_source->SetSourceFile(source_path, override_fps); |
317 } | 273 } |
| 274 if (cmd->HasSwitch(kSwitchVaryFrameSizes)) |
| 275 fake_media_source->SetVariableFrameSizeMode(true); |
318 | 276 |
319 // CastTransportSender initialization. | 277 // CastTransportSender initialization. |
320 scoped_ptr<media::cast::CastTransportSender> transport_sender = | 278 scoped_ptr<media::cast::CastTransportSender> transport_sender = |
321 media::cast::CastTransportSender::Create( | 279 media::cast::CastTransportSender::Create( |
322 NULL, // net log. | 280 NULL, // net log. |
323 cast_environment->Clock(), | 281 cast_environment->Clock(), |
324 net::IPEndPoint(), | 282 net::IPEndPoint(), |
325 remote_endpoint, | 283 remote_endpoint, |
326 make_scoped_ptr(new base::DictionaryValue), // options | 284 make_scoped_ptr(new base::DictionaryValue), // options |
327 base::Bind(&UpdateCastTransportStatus), | 285 base::Bind(&UpdateCastTransportStatus), |
328 base::Bind(&LogRawEvents, cast_environment), | 286 base::Bind(&LogRawEvents, cast_environment), |
329 base::TimeDelta::FromSeconds(1), | 287 base::TimeDelta::FromSeconds(1), |
330 media::cast::PacketReceiverCallback(), | 288 media::cast::PacketReceiverCallback(), |
331 io_message_loop.message_loop_proxy()); | 289 io_message_loop.message_loop_proxy()); |
332 | 290 |
333 // CastSender initialization. | |
334 scoped_ptr<media::cast::CastSender> cast_sender = | |
335 media::cast::CastSender::Create(cast_environment, transport_sender.get()); | |
336 cast_sender->InitializeVideo( | |
337 fake_media_source->get_video_config(), | |
338 base::Bind(&InitializationResult), | |
339 media::cast::CreateDefaultVideoEncodeAcceleratorCallback(), | |
340 media::cast::CreateDefaultVideoEncodeMemoryCallback()); | |
341 cast_sender->InitializeAudio(audio_config, base::Bind(&InitializationResult)); | |
342 | |
343 // Set up event subscribers. | 291 // Set up event subscribers. |
344 scoped_ptr<media::cast::EncodingEventSubscriber> video_event_subscriber; | 292 scoped_ptr<media::cast::EncodingEventSubscriber> video_event_subscriber; |
345 scoped_ptr<media::cast::EncodingEventSubscriber> audio_event_subscriber; | 293 scoped_ptr<media::cast::EncodingEventSubscriber> audio_event_subscriber; |
346 std::string video_log_file_name("/tmp/video_events.log.gz"); | 294 std::string video_log_file_name("/tmp/video_events.log.gz"); |
347 std::string audio_log_file_name("/tmp/audio_events.log.gz"); | 295 std::string audio_log_file_name("/tmp/audio_events.log.gz"); |
348 LOG(INFO) << "Logging audio events to: " << audio_log_file_name; | 296 LOG(INFO) << "Logging audio events to: " << audio_log_file_name; |
349 LOG(INFO) << "Logging video events to: " << video_log_file_name; | 297 LOG(INFO) << "Logging video events to: " << video_log_file_name; |
350 video_event_subscriber.reset(new media::cast::EncodingEventSubscriber( | 298 video_event_subscriber.reset(new media::cast::EncodingEventSubscriber( |
351 media::cast::VIDEO_EVENT, 10000)); | 299 media::cast::VIDEO_EVENT, 10000)); |
352 audio_event_subscriber.reset(new media::cast::EncodingEventSubscriber( | 300 audio_event_subscriber.reset(new media::cast::EncodingEventSubscriber( |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
398 | 346 |
399 io_message_loop.message_loop_proxy()->PostDelayedTask( | 347 io_message_loop.message_loop_proxy()->PostDelayedTask( |
400 FROM_HERE, | 348 FROM_HERE, |
401 base::Bind(&WriteStatsAndDestroySubscribers, | 349 base::Bind(&WriteStatsAndDestroySubscribers, |
402 cast_environment, | 350 cast_environment, |
403 base::Passed(&video_stats_subscriber), | 351 base::Passed(&video_stats_subscriber), |
404 base::Passed(&audio_stats_subscriber), | 352 base::Passed(&audio_stats_subscriber), |
405 base::Passed(&offset_estimator)), | 353 base::Passed(&offset_estimator)), |
406 base::TimeDelta::FromSeconds(logging_duration_seconds)); | 354 base::TimeDelta::FromSeconds(logging_duration_seconds)); |
407 | 355 |
| 356 // CastSender initialization. |
| 357 scoped_ptr<media::cast::CastSender> cast_sender = |
| 358 media::cast::CastSender::Create(cast_environment, transport_sender.get()); |
| 359 io_message_loop.PostTask( |
| 360 FROM_HERE, |
| 361 base::Bind(&media::cast::CastSender::InitializeVideo, |
| 362 base::Unretained(cast_sender.get()), |
| 363 fake_media_source->get_video_config(), |
| 364 base::Bind(&QuitLoopOnInitializationResult), |
| 365 media::cast::CreateDefaultVideoEncodeAcceleratorCallback(), |
| 366 media::cast::CreateDefaultVideoEncodeMemoryCallback())); |
| 367 io_message_loop.Run(); // Wait for video initialization. |
| 368 io_message_loop.PostTask( |
| 369 FROM_HERE, |
| 370 base::Bind(&media::cast::CastSender::InitializeAudio, |
| 371 base::Unretained(cast_sender.get()), |
| 372 audio_config, |
| 373 base::Bind(&QuitLoopOnInitializationResult))); |
| 374 io_message_loop.Run(); // Wait for audio initialization. |
| 375 |
408 fake_media_source->Start(cast_sender->audio_frame_input(), | 376 fake_media_source->Start(cast_sender->audio_frame_input(), |
409 cast_sender->video_frame_input()); | 377 cast_sender->video_frame_input()); |
410 | |
411 io_message_loop.Run(); | 378 io_message_loop.Run(); |
412 return 0; | 379 return 0; |
413 } | 380 } |
OLD | NEW |