Updating XTBs based on .GRDs from branch master
[chromium-blink-merge.git] / media / cast / test / sender.cc
blobc8168be5a50a011b133793fea6ab60ea821daa0a
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 <queue>
10 #include "base/at_exit.h"
11 #include "base/base_paths.h"
12 #include "base/command_line.h"
13 #include "base/files/file_path.h"
14 #include "base/json/json_writer.h"
15 #include "base/logging.h"
16 #include "base/memory/scoped_ptr.h"
17 #include "base/path_service.h"
18 #include "base/strings/string_number_conversions.h"
19 #include "base/threading/thread.h"
20 #include "base/time/default_tick_clock.h"
21 #include "base/values.h"
22 #include "media/base/media.h"
23 #include "media/base/video_frame.h"
24 #include "media/cast/cast_config.h"
25 #include "media/cast/cast_environment.h"
26 #include "media/cast/cast_sender.h"
27 #include "media/cast/logging/encoding_event_subscriber.h"
28 #include "media/cast/logging/log_serializer.h"
29 #include "media/cast/logging/logging_defines.h"
30 #include "media/cast/logging/proto/raw_events.pb.h"
31 #include "media/cast/logging/receiver_time_offset_estimator_impl.h"
32 #include "media/cast/logging/stats_event_subscriber.h"
33 #include "media/cast/net/cast_transport_defines.h"
34 #include "media/cast/net/cast_transport_sender.h"
35 #include "media/cast/net/udp_transport.h"
36 #include "media/cast/test/fake_media_source.h"
37 #include "media/cast/test/utility/default_config.h"
38 #include "media/cast/test/utility/input_builder.h"
40 namespace {
42 // The max allowed size of serialized log.
43 const int kMaxSerializedLogBytes = 10 * 1000 * 1000;
45 // Flags for this program:
47 // --address=xx.xx.xx.xx
48 // IP address of receiver.
50 // --port=xxxx
51 // Port number of receiver.
53 // --source-file=xxx.webm
54 // WebM file as source of video frames.
56 // --fps=xx
57 // Override framerate of the video stream.
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.
62 const char kSwitchAddress[] = "address";
63 const char kSwitchPort[] = "port";
64 const char kSwitchSourceFile[] = "source-file";
65 const char kSwitchFps[] = "fps";
66 const char kSwitchVaryFrameSizes[] = "vary-frame-sizes";
68 void UpdateCastTransportStatus(
69 media::cast::CastTransportStatus status) {
70 VLOG(1) << "Transport status: " << status;
73 void LogRawEvents(
74 const scoped_refptr<media::cast::CastEnvironment>& cast_environment,
75 const std::vector<media::cast::PacketEvent>& packet_events,
76 const std::vector<media::cast::FrameEvent>& frame_events) {
77 VLOG(1) << "Got packet events from transport, size: " << packet_events.size();
78 for (std::vector<media::cast::PacketEvent>::const_iterator it =
79 packet_events.begin();
80 it != packet_events.end();
81 ++it) {
82 cast_environment->Logging()->InsertPacketEvent(it->timestamp,
83 it->type,
84 it->media_type,
85 it->rtp_timestamp,
86 it->frame_id,
87 it->packet_id,
88 it->max_packet_id,
89 it->size);
91 VLOG(1) << "Got frame events from transport, size: " << frame_events.size();
92 for (std::vector<media::cast::FrameEvent>::const_iterator it =
93 frame_events.begin();
94 it != frame_events.end();
95 ++it) {
96 cast_environment->Logging()->InsertFrameEvent(it->timestamp,
97 it->type,
98 it->media_type,
99 it->rtp_timestamp,
100 it->frame_id);
104 void QuitLoopOnInitializationResult(media::cast::OperationalStatus result) {
105 CHECK(result == media::cast::STATUS_INITIALIZED)
106 << "Cast sender uninitialized";
107 base::MessageLoop::current()->Quit();
110 net::IPEndPoint CreateUDPAddress(std::string ip_str, uint16 port) {
111 net::IPAddressNumber ip_number;
112 CHECK(net::ParseIPLiteralToNumber(ip_str, &ip_number));
113 return net::IPEndPoint(ip_number, port);
116 void DumpLoggingData(const media::cast::proto::LogMetadata& log_metadata,
117 const media::cast::FrameEventList& frame_events,
118 const media::cast::PacketEventList& packet_events,
119 base::ScopedFILE log_file) {
120 VLOG(0) << "Frame map size: " << frame_events.size();
121 VLOG(0) << "Packet map size: " << packet_events.size();
123 scoped_ptr<char[]> event_log(new char[kMaxSerializedLogBytes]);
124 int event_log_bytes;
125 if (!media::cast::SerializeEvents(log_metadata,
126 frame_events,
127 packet_events,
128 true,
129 kMaxSerializedLogBytes,
130 event_log.get(),
131 &event_log_bytes)) {
132 VLOG(0) << "Failed to serialize events.";
133 return;
136 VLOG(0) << "Events serialized length: " << event_log_bytes;
138 int ret = fwrite(event_log.get(), 1, event_log_bytes, log_file.get());
139 if (ret != event_log_bytes)
140 VLOG(0) << "Failed to write logs to file.";
143 void WriteLogsToFileAndDestroySubscribers(
144 const scoped_refptr<media::cast::CastEnvironment>& cast_environment,
145 scoped_ptr<media::cast::EncodingEventSubscriber> video_event_subscriber,
146 scoped_ptr<media::cast::EncodingEventSubscriber> audio_event_subscriber,
147 base::ScopedFILE video_log_file,
148 base::ScopedFILE audio_log_file) {
149 cast_environment->Logging()->RemoveRawEventSubscriber(
150 video_event_subscriber.get());
151 cast_environment->Logging()->RemoveRawEventSubscriber(
152 audio_event_subscriber.get());
154 VLOG(0) << "Dumping logging data for video stream.";
155 media::cast::proto::LogMetadata log_metadata;
156 media::cast::FrameEventList frame_events;
157 media::cast::PacketEventList packet_events;
158 video_event_subscriber->GetEventsAndReset(
159 &log_metadata, &frame_events, &packet_events);
161 DumpLoggingData(log_metadata,
162 frame_events,
163 packet_events,
164 video_log_file.Pass());
166 VLOG(0) << "Dumping logging data for audio stream.";
167 audio_event_subscriber->GetEventsAndReset(
168 &log_metadata, &frame_events, &packet_events);
170 DumpLoggingData(log_metadata,
171 frame_events,
172 packet_events,
173 audio_log_file.Pass());
176 void WriteStatsAndDestroySubscribers(
177 const scoped_refptr<media::cast::CastEnvironment>& cast_environment,
178 scoped_ptr<media::cast::StatsEventSubscriber> video_event_subscriber,
179 scoped_ptr<media::cast::StatsEventSubscriber> audio_event_subscriber,
180 scoped_ptr<media::cast::ReceiverTimeOffsetEstimatorImpl> estimator) {
181 cast_environment->Logging()->RemoveRawEventSubscriber(
182 video_event_subscriber.get());
183 cast_environment->Logging()->RemoveRawEventSubscriber(
184 audio_event_subscriber.get());
185 cast_environment->Logging()->RemoveRawEventSubscriber(estimator.get());
187 scoped_ptr<base::DictionaryValue> stats = video_event_subscriber->GetStats();
188 std::string json;
189 base::JSONWriter::WriteWithOptions(
190 *stats, base::JSONWriter::OPTIONS_PRETTY_PRINT, &json);
191 VLOG(0) << "Video stats: " << json;
193 stats = audio_event_subscriber->GetStats();
194 json.clear();
195 base::JSONWriter::WriteWithOptions(
196 *stats, base::JSONWriter::OPTIONS_PRETTY_PRINT, &json);
197 VLOG(0) << "Audio stats: " << json;
200 } // namespace
202 int main(int argc, char** argv) {
203 base::AtExitManager at_exit;
204 base::CommandLine::Init(argc, argv);
205 InitLogging(logging::LoggingSettings());
207 // Prepare media module for FFmpeg decoding.
208 media::InitializeMediaLibrary();
210 base::Thread test_thread("Cast sender test app thread");
211 base::Thread audio_thread("Cast audio encoder thread");
212 base::Thread video_thread("Cast video encoder thread");
213 test_thread.Start();
214 audio_thread.Start();
215 video_thread.Start();
217 base::MessageLoopForIO io_message_loop;
219 // Default parameters.
220 base::CommandLine* cmd = base::CommandLine::ForCurrentProcess();
221 std::string remote_ip_address = cmd->GetSwitchValueASCII(kSwitchAddress);
222 if (remote_ip_address.empty())
223 remote_ip_address = "127.0.0.1";
224 int remote_port = 0;
225 if (!base::StringToInt(cmd->GetSwitchValueASCII(kSwitchPort), &remote_port) ||
226 remote_port < 0 || remote_port > 65535) {
227 remote_port = 2344;
229 LOG(INFO) << "Sending to " << remote_ip_address << ":" << remote_port
230 << ".";
232 media::cast::AudioSenderConfig audio_config =
233 media::cast::GetDefaultAudioSenderConfig();
234 media::cast::VideoSenderConfig video_config =
235 media::cast::GetDefaultVideoSenderConfig();
237 // Running transport on the main thread.
238 // Setting up transport config.
239 net::IPEndPoint remote_endpoint =
240 CreateUDPAddress(remote_ip_address, static_cast<uint16>(remote_port));
242 // Enable raw event and stats logging.
243 // Running transport on the main thread.
244 scoped_refptr<media::cast::CastEnvironment> cast_environment(
245 new media::cast::CastEnvironment(
246 make_scoped_ptr<base::TickClock>(new base::DefaultTickClock()),
247 io_message_loop.task_runner(),
248 audio_thread.task_runner(),
249 video_thread.task_runner()));
251 // SendProcess initialization.
252 scoped_ptr<media::cast::FakeMediaSource> fake_media_source(
253 new media::cast::FakeMediaSource(test_thread.task_runner(),
254 cast_environment->Clock(),
255 audio_config,
256 video_config,
257 false));
259 int final_fps = 0;
260 if (!base::StringToInt(cmd->GetSwitchValueASCII(kSwitchFps),
261 &final_fps)){
262 final_fps = 0;
264 base::FilePath source_path = cmd->GetSwitchValuePath(kSwitchSourceFile);
265 if (!source_path.empty()) {
266 LOG(INFO) << "Source: " << source_path.value();
267 fake_media_source->SetSourceFile(source_path, final_fps);
269 if (cmd->HasSwitch(kSwitchVaryFrameSizes))
270 fake_media_source->SetVariableFrameSizeMode(true);
272 // CastTransportSender initialization.
273 scoped_ptr<media::cast::CastTransportSender> transport_sender =
274 media::cast::CastTransportSender::Create(
275 NULL, // net log.
276 cast_environment->Clock(),
277 net::IPEndPoint(),
278 remote_endpoint,
279 make_scoped_ptr(new base::DictionaryValue), // options
280 base::Bind(&UpdateCastTransportStatus),
281 base::Bind(&LogRawEvents, cast_environment),
282 base::TimeDelta::FromSeconds(1),
283 media::cast::PacketReceiverCallback(),
284 io_message_loop.task_runner());
286 // Set up event subscribers.
287 scoped_ptr<media::cast::EncodingEventSubscriber> video_event_subscriber;
288 scoped_ptr<media::cast::EncodingEventSubscriber> audio_event_subscriber;
289 std::string video_log_file_name("/tmp/video_events.log.gz");
290 std::string audio_log_file_name("/tmp/audio_events.log.gz");
291 LOG(INFO) << "Logging audio events to: " << audio_log_file_name;
292 LOG(INFO) << "Logging video events to: " << video_log_file_name;
293 video_event_subscriber.reset(new media::cast::EncodingEventSubscriber(
294 media::cast::VIDEO_EVENT, 10000));
295 audio_event_subscriber.reset(new media::cast::EncodingEventSubscriber(
296 media::cast::AUDIO_EVENT, 10000));
297 cast_environment->Logging()->AddRawEventSubscriber(
298 video_event_subscriber.get());
299 cast_environment->Logging()->AddRawEventSubscriber(
300 audio_event_subscriber.get());
302 // Subscribers for stats.
303 scoped_ptr<media::cast::ReceiverTimeOffsetEstimatorImpl> offset_estimator(
304 new media::cast::ReceiverTimeOffsetEstimatorImpl());
305 cast_environment->Logging()->AddRawEventSubscriber(offset_estimator.get());
306 scoped_ptr<media::cast::StatsEventSubscriber> video_stats_subscriber(
307 new media::cast::StatsEventSubscriber(media::cast::VIDEO_EVENT,
308 cast_environment->Clock(),
309 offset_estimator.get()));
310 scoped_ptr<media::cast::StatsEventSubscriber> audio_stats_subscriber(
311 new media::cast::StatsEventSubscriber(media::cast::AUDIO_EVENT,
312 cast_environment->Clock(),
313 offset_estimator.get()));
314 cast_environment->Logging()->AddRawEventSubscriber(
315 video_stats_subscriber.get());
316 cast_environment->Logging()->AddRawEventSubscriber(
317 audio_stats_subscriber.get());
319 base::ScopedFILE video_log_file(fopen(video_log_file_name.c_str(), "w"));
320 if (!video_log_file) {
321 VLOG(1) << "Failed to open video log file for writing.";
322 exit(-1);
325 base::ScopedFILE audio_log_file(fopen(audio_log_file_name.c_str(), "w"));
326 if (!audio_log_file) {
327 VLOG(1) << "Failed to open audio log file for writing.";
328 exit(-1);
331 const int logging_duration_seconds = 10;
332 io_message_loop.task_runner()->PostDelayedTask(
333 FROM_HERE,
334 base::Bind(&WriteLogsToFileAndDestroySubscribers,
335 cast_environment,
336 base::Passed(&video_event_subscriber),
337 base::Passed(&audio_event_subscriber),
338 base::Passed(&video_log_file),
339 base::Passed(&audio_log_file)),
340 base::TimeDelta::FromSeconds(logging_duration_seconds));
342 io_message_loop.task_runner()->PostDelayedTask(
343 FROM_HERE,
344 base::Bind(&WriteStatsAndDestroySubscribers,
345 cast_environment,
346 base::Passed(&video_stats_subscriber),
347 base::Passed(&audio_stats_subscriber),
348 base::Passed(&offset_estimator)),
349 base::TimeDelta::FromSeconds(logging_duration_seconds));
351 // CastSender initialization.
352 scoped_ptr<media::cast::CastSender> cast_sender =
353 media::cast::CastSender::Create(cast_environment, transport_sender.get());
354 io_message_loop.PostTask(
355 FROM_HERE,
356 base::Bind(&media::cast::CastSender::InitializeVideo,
357 base::Unretained(cast_sender.get()),
358 fake_media_source->get_video_config(),
359 base::Bind(&QuitLoopOnInitializationResult),
360 media::cast::CreateDefaultVideoEncodeAcceleratorCallback(),
361 media::cast::CreateDefaultVideoEncodeMemoryCallback()));
362 io_message_loop.Run(); // Wait for video initialization.
363 io_message_loop.PostTask(
364 FROM_HERE,
365 base::Bind(&media::cast::CastSender::InitializeAudio,
366 base::Unretained(cast_sender.get()),
367 audio_config,
368 base::Bind(&QuitLoopOnInitializationResult)));
369 io_message_loop.Run(); // Wait for audio initialization.
371 fake_media_source->Start(cast_sender->audio_frame_input(),
372 cast_sender->video_frame_input());
373 io_message_loop.Run();
374 return 0;