1116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// Copyright 2014 The Chromium Authors. All rights reserved.
2116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// Use of this source code is governed by a BSD-style license that can be
3116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// found in the LICENSE file.
4116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
5116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// Simulate end to end streaming.
6116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch//
7116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// Input:
8116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// --source=
9116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch//   WebM used as the source of video and audio frames.
10116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// --output=
11116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch//   File path to writing out the raw event log of the simulation session.
12116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// --sim-id=
13116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch//   Unique simulation ID.
141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// --target-delay-ms=
151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci//   Target playout delay to configure (integer number of milliseconds).
161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci//   Optional; default is 400.
17116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch//
18116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// Output:
19116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// - Raw event log of the simulation session tagged with the unique test ID,
20116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch//   written out to the specified file path.
21116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
22116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "base/at_exit.h"
23116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "base/base_paths.h"
24116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "base/command_line.h"
25116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "base/files/file_path.h"
261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "base/files/file_util.h"
27116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "base/files/memory_mapped_file.h"
28116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "base/files/scoped_file.h"
29116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "base/json/json_writer.h"
30116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "base/logging.h"
31116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "base/path_service.h"
321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "base/strings/string_number_conversions.h"
33116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "base/test/simple_test_tick_clock.h"
34116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "base/thread_task_runner_handle.h"
35116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "base/time/tick_clock.h"
36116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "base/values.h"
37116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "media/base/audio_bus.h"
38116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "media/base/media.h"
39116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "media/base/video_frame.h"
40116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "media/cast/cast_config.h"
41116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "media/cast/cast_environment.h"
42116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "media/cast/cast_receiver.h"
43116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "media/cast/cast_sender.h"
44116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "media/cast/logging/encoding_event_subscriber.h"
45116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "media/cast/logging/log_serializer.h"
46116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "media/cast/logging/logging_defines.h"
47116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "media/cast/logging/proto/raw_events.pb.h"
48116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "media/cast/logging/raw_event_subscriber_bundle.h"
49116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "media/cast/logging/simple_event_subscriber.h"
50116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "media/cast/net/cast_transport_config.h"
51116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "media/cast/net/cast_transport_defines.h"
52116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "media/cast/net/cast_transport_sender.h"
53116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "media/cast/net/cast_transport_sender_impl.h"
54116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "media/cast/test/fake_media_source.h"
55116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "media/cast/test/fake_single_thread_task_runner.h"
56116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "media/cast/test/loopback_transport.h"
57116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "media/cast/test/proto/network_simulation_model.pb.h"
58116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "media/cast/test/skewed_tick_clock.h"
59116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "media/cast/test/utility/audio_utility.h"
60116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "media/cast/test/utility/default_config.h"
61116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "media/cast/test/utility/test_util.h"
62116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "media/cast/test/utility/udp_proxy.h"
63116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "media/cast/test/utility/video_utility.h"
64116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
65116680a4aac90f2aa7413d9095a592090648e557Ben Murdochusing media::cast::proto::IPPModel;
66116680a4aac90f2aa7413d9095a592090648e557Ben Murdochusing media::cast::proto::NetworkSimulationModel;
67116680a4aac90f2aa7413d9095a592090648e557Ben Murdochusing media::cast::proto::NetworkSimulationModelType;
68116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
69116680a4aac90f2aa7413d9095a592090648e557Ben Murdochnamespace media {
70116680a4aac90f2aa7413d9095a592090648e557Ben Murdochnamespace cast {
71116680a4aac90f2aa7413d9095a592090648e557Ben Murdochnamespace {
72116680a4aac90f2aa7413d9095a592090648e557Ben Murdochconst char kSourcePath[] = "source";
73116680a4aac90f2aa7413d9095a592090648e557Ben Murdochconst char kModelPath[] = "model";
74116680a4aac90f2aa7413d9095a592090648e557Ben Murdochconst char kOutputPath[] = "output";
75116680a4aac90f2aa7413d9095a592090648e557Ben Murdochconst char kSimulationId[] = "sim-id";
76116680a4aac90f2aa7413d9095a592090648e557Ben Murdochconst char kLibDir[] = "lib-dir";
771320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciconst char kTargetDelay[] = "target-delay-ms";
781320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
791320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccibase::TimeDelta GetTargetPlayoutDelay() {
801320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  const std::string delay_str =
811320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      CommandLine::ForCurrentProcess()->GetSwitchValueASCII(kTargetDelay);
821320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (delay_str.empty())
831320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    return base::TimeDelta::FromMilliseconds(400);
841320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  int delay_ms;
851320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  CHECK(base::StringToInt(delay_str, &delay_ms));
861320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  CHECK_GT(delay_ms, 0);
871320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  return base::TimeDelta::FromMilliseconds(delay_ms);
881320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
89116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
90116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid UpdateCastTransportStatus(CastTransportStatus status) {
91116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  LOG(INFO) << "Cast transport status: " << status;
92116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
93116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
94116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid AudioInitializationStatus(CastInitializationStatus status) {
95116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  LOG(INFO) << "Audio status: " << status;
96116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
97116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
98116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid VideoInitializationStatus(CastInitializationStatus status) {
99116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  LOG(INFO) << "Video status: " << status;
100116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
101116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
102116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid LogTransportEvents(const scoped_refptr<CastEnvironment>& env,
1035f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                        const std::vector<PacketEvent>& packet_events,
1045f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                        const std::vector<FrameEvent>& frame_events) {
105116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  for (std::vector<media::cast::PacketEvent>::const_iterator it =
106116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch           packet_events.begin();
107116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch       it != packet_events.end();
108116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch       ++it) {
109116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    env->Logging()->InsertPacketEvent(it->timestamp,
110116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                      it->type,
111116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                      it->media_type,
112116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                      it->rtp_timestamp,
113116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                      it->frame_id,
114116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                      it->packet_id,
115116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                      it->max_packet_id,
116116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                      it->size);
117116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
1185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  for (std::vector<media::cast::FrameEvent>::const_iterator it =
1195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)           frame_events.begin();
1205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)       it != frame_events.end();
1215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)       ++it) {
1225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if (it->type == FRAME_PLAYOUT) {
1235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      env->Logging()->InsertFrameEventWithDelay(
1245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          it->timestamp,
1255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          it->type,
1265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          it->media_type,
1275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          it->rtp_timestamp,
1285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          it->frame_id,
1295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          it->delay_delta);
1305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    } else {
1315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      env->Logging()->InsertFrameEvent(
1325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          it->timestamp,
1335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          it->type,
1345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          it->media_type,
1355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          it->rtp_timestamp,
1365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          it->frame_id);
1375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    }
1385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
139116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
140116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
141116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid GotVideoFrame(
142116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    int* counter,
143116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    CastReceiver* cast_receiver,
144116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    const scoped_refptr<media::VideoFrame>& video_frame,
145116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    const base::TimeTicks& render_time,
146116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    bool continuous) {
147116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  ++*counter;
148116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  cast_receiver->RequestDecodedVideoFrame(
149116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      base::Bind(&GotVideoFrame, counter, cast_receiver));
150116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
151116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
152116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid GotAudioFrame(
153116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    int* counter,
154116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    CastReceiver* cast_receiver,
155116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    scoped_ptr<AudioBus> audio_bus,
156116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    const base::TimeTicks& playout_time,
157116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    bool is_continuous) {
158116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  ++*counter;
159116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  cast_receiver->RequestDecodedAudioFrame(
160116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      base::Bind(&GotAudioFrame, counter, cast_receiver));
161116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
162116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
1635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// Serialize |frame_events| and |packet_events| and append to the file
1645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// located at |output_path|.
1655f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void AppendLogToFile(media::cast::proto::LogMetadata* metadata,
1665f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                     const media::cast::FrameEventList& frame_events,
1675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                     const media::cast::PacketEventList& packet_events,
1685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                     const base::FilePath& output_path) {
169116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  media::cast::proto::GeneralDescription* gen_desc =
1705f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      metadata->mutable_general_description();
171116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  gen_desc->set_product("Cast Simulator");
172116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  gen_desc->set_product_version("0.1");
173116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
174116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  scoped_ptr<char[]> serialized_log(new char[media::cast::kMaxSerializedBytes]);
175116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  int output_bytes;
1765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  bool success = media::cast::SerializeEvents(*metadata,
177116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                              frame_events,
178116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                              packet_events,
179116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                              true,
180116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                              media::cast::kMaxSerializedBytes,
181116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                              serialized_log.get(),
182116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                              &output_bytes);
183116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
184116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (!success) {
185116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    LOG(ERROR) << "Failed to serialize log.";
186116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    return;
187116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
188116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
189116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (AppendToFile(output_path, serialized_log.get(), output_bytes) == -1) {
190116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    LOG(ERROR) << "Failed to append to log.";
191116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
192116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
193116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
194116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// Run simulation once.
195116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch//
196116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// |output_path| is the path to write serialized log.
197116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// |extra_data| is extra tagging information to write to log.
198116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid RunSimulation(const base::FilePath& source_path,
199116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                   const base::FilePath& output_path,
200116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                   const std::string& extra_data,
201116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                   const NetworkSimulationModel& model) {
202116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // Fake clock. Make sure start time is non zero.
203116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  base::SimpleTestTickClock testing_clock;
204116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  testing_clock.Advance(base::TimeDelta::FromSeconds(1));
205116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
206116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // Task runner.
207116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  scoped_refptr<test::FakeSingleThreadTaskRunner> task_runner =
208116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      new test::FakeSingleThreadTaskRunner(&testing_clock);
209116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  base::ThreadTaskRunnerHandle task_runner_handle(task_runner);
210116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
211116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // CastEnvironments.
212116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  scoped_refptr<CastEnvironment> sender_env =
213116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      new CastEnvironment(
214116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch          scoped_ptr<base::TickClock>(
215116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch              new test::SkewedTickClock(&testing_clock)).Pass(),
216116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch          task_runner,
217116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch          task_runner,
218116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch          task_runner);
219116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  scoped_refptr<CastEnvironment> receiver_env =
220116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      new CastEnvironment(
221116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch          scoped_ptr<base::TickClock>(
222116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch              new test::SkewedTickClock(&testing_clock)).Pass(),
223116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch          task_runner,
224116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch          task_runner,
225116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch          task_runner);
226116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
227116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // Event subscriber. Store at most 1 hour of events.
228116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  EncodingEventSubscriber audio_event_subscriber(AUDIO_EVENT,
229116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                                 100 * 60 * 60);
230116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  EncodingEventSubscriber video_event_subscriber(VIDEO_EVENT,
231116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                                 30 * 60 * 60);
232116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  sender_env->Logging()->AddRawEventSubscriber(&audio_event_subscriber);
233116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  sender_env->Logging()->AddRawEventSubscriber(&video_event_subscriber);
234116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
235116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // Audio sender config.
236116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  AudioSenderConfig audio_sender_config = GetDefaultAudioSenderConfig();
2371320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  audio_sender_config.max_playout_delay = GetTargetPlayoutDelay();
238116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
239116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // Audio receiver config.
240116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  FrameReceiverConfig audio_receiver_config =
241116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      GetDefaultAudioReceiverConfig();
242116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  audio_receiver_config.rtp_max_delay_ms =
2431320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      audio_sender_config.max_playout_delay.InMilliseconds();
244116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
245116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // Video sender config.
246116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  VideoSenderConfig video_sender_config = GetDefaultVideoSenderConfig();
24703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  video_sender_config.max_bitrate = 2500000;
248116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  video_sender_config.min_bitrate = 2000000;
24903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  video_sender_config.start_bitrate = 2000000;
2501320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  video_sender_config.max_playout_delay = GetTargetPlayoutDelay();
251116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
252116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // Video receiver config.
253116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  FrameReceiverConfig video_receiver_config =
254116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      GetDefaultVideoReceiverConfig();
255116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  video_receiver_config.rtp_max_delay_ms =
2561320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      video_sender_config.max_playout_delay.InMilliseconds();
257116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
258116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // Loopback transport.
259116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  LoopBackTransport receiver_to_sender(receiver_env);
260116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  LoopBackTransport sender_to_receiver(sender_env);
261116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
262116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // Cast receiver.
263116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  scoped_ptr<CastReceiver> cast_receiver(
264116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      CastReceiver::Create(receiver_env,
265116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                           audio_receiver_config,
266116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                           video_receiver_config,
267116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                           &receiver_to_sender));
268116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
269116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // Cast sender and transport sender.
270116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  scoped_ptr<CastTransportSender> transport_sender(
271116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      new CastTransportSenderImpl(
272116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch          NULL,
273116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch          &testing_clock,
274116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch          net::IPEndPoint(),
2751320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          make_scoped_ptr(new base::DictionaryValue),
276116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch          base::Bind(&UpdateCastTransportStatus),
277116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch          base::Bind(&LogTransportEvents, sender_env),
278116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch          base::TimeDelta::FromSeconds(1),
279116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch          task_runner,
280116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch          &sender_to_receiver));
281116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  scoped_ptr<CastSender> cast_sender(
282116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      CastSender::Create(sender_env, transport_sender.get()));
283116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
284116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // Build packet pipe.
285116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (model.type() != media::cast::proto::INTERRUPTED_POISSON_PROCESS) {
286116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    LOG(ERROR) << "Unknown model type " << model.type() << ".";
287116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    return;
288116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
289116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
290116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  const IPPModel& ipp_model = model.ipp();
291116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
292116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  std::vector<double> average_rates(ipp_model.average_rate_size());
293116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  std::copy(ipp_model.average_rate().begin(), ipp_model.average_rate().end(),
294116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      average_rates.begin());
295116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  test::InterruptedPoissonProcess ipp(average_rates,
296116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      ipp_model.coef_burstiness(), ipp_model.coef_variance(), 0);
297116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
298116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // Connect sender to receiver. This initializes the pipe.
299116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  receiver_to_sender.Initialize(
3006e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      ipp.NewBuffer(128 * 1024).Pass(),
3016e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      transport_sender->PacketReceiverForTesting(),
3025f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      task_runner, &testing_clock);
303116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  sender_to_receiver.Initialize(
3046e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      ipp.NewBuffer(128 * 1024).Pass(),
3056e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      cast_receiver->packet_receiver(), task_runner,
306116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      &testing_clock);
307116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
308116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // Start receiver.
309116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  int audio_frame_count = 0;
310116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  int video_frame_count = 0;
311116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  cast_receiver->RequestDecodedVideoFrame(
312116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      base::Bind(&GotVideoFrame, &video_frame_count, cast_receiver.get()));
313116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  cast_receiver->RequestDecodedAudioFrame(
314116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      base::Bind(&GotAudioFrame, &audio_frame_count, cast_receiver.get()));
315116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
316116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  FakeMediaSource media_source(task_runner,
317116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                               &testing_clock,
318116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                               video_sender_config);
319116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
320116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // Initializing audio and video senders.
321116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  cast_sender->InitializeAudio(audio_sender_config,
322116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                               base::Bind(&AudioInitializationStatus));
323116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  cast_sender->InitializeVideo(media_source.get_video_config(),
324116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                               base::Bind(&VideoInitializationStatus),
325116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                               CreateDefaultVideoEncodeAcceleratorCallback(),
326116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                               CreateDefaultVideoEncodeMemoryCallback());
3271320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  task_runner->RunTasks();
328116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
329116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // Start sending.
330116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (!source_path.empty()) {
331116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    // 0 means using the FPS from the file.
332116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    media_source.SetSourceFile(source_path, 0);
333116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
334116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  media_source.Start(cast_sender->audio_frame_input(),
335116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                     cast_sender->video_frame_input());
336116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
337116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // Run for 3 minutes.
338116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  base::TimeDelta elapsed_time;
339116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  while (elapsed_time.InMinutes() < 3) {
340116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    // Each step is 100us.
341116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    base::TimeDelta step = base::TimeDelta::FromMicroseconds(100);
342116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    task_runner->Sleep(step);
343116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    elapsed_time += step;
344116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
345116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
3465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // Get event logs for audio and video.
3475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  media::cast::proto::LogMetadata audio_metadata, video_metadata;
3485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  media::cast::FrameEventList audio_frame_events, video_frame_events;
3495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  media::cast::PacketEventList audio_packet_events, video_packet_events;
3505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  audio_metadata.set_extra_data(extra_data);
3515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  video_metadata.set_extra_data(extra_data);
3525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  audio_event_subscriber.GetEventsAndReset(
3535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      &audio_metadata, &audio_frame_events, &audio_packet_events);
3545f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  video_event_subscriber.GetEventsAndReset(
3555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      &video_metadata, &video_frame_events, &video_packet_events);
3565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
3575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // Print simulation results.
3585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
3595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // Compute and print statistics for video:
3605f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  //
3615f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // * Total video frames captured.
3625f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // * Total video frames encoded.
3635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // * Total video frames dropped.
3645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // * Total video frames received late.
3655f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // * Average target bitrate.
3665f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // * Average encoded bitrate.
3675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  int total_video_frames = 0;
3685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  int encoded_video_frames = 0;
3695f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  int dropped_video_frames = 0;
3705f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  int late_video_frames = 0;
3711320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  int64 total_delay_of_late_frames_ms = 0;
3725f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  int64 encoded_size = 0;
3735f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  int64 target_bitrate = 0;
3745f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  for (size_t i = 0; i < video_frame_events.size(); ++i) {
3755f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    const media::cast::proto::AggregatedFrameEvent& event =
3765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        *video_frame_events[i];
3775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    ++total_video_frames;
3785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if (event.has_encoded_frame_size()) {
3795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      ++encoded_video_frames;
3805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      encoded_size += event.encoded_frame_size();
3815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      target_bitrate += event.target_bitrate();
3825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    } else {
3835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      ++dropped_video_frames;
3845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    }
3851320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    if (event.has_delay_millis() && event.delay_millis() < 0) {
3865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      ++late_video_frames;
3871320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      total_delay_of_late_frames_ms += -event.delay_millis();
3881320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    }
3895f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
3905f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
3915f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  double avg_encoded_bitrate =
3925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      !encoded_video_frames ? 0 :
3935f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      8.0 * encoded_size * video_sender_config.max_frame_rate /
3945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      encoded_video_frames / 1000;
3955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  double avg_target_bitrate =
3965f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      !encoded_video_frames ? 0 : target_bitrate / encoded_video_frames / 1000;
3975f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
3981320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  LOG(INFO) << "Configured target playout delay (ms): "
3991320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci            << video_receiver_config.rtp_max_delay_ms;
400116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  LOG(INFO) << "Audio frame count: " << audio_frame_count;
4015f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  LOG(INFO) << "Total video frames: " << total_video_frames;
4025f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  LOG(INFO) << "Dropped video frames " << dropped_video_frames;
4031320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  LOG(INFO) << "Late video frames: " << late_video_frames
4041320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci            << " (average lateness: "
4051320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci            << (late_video_frames > 0 ?
4061320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                    static_cast<double>(total_delay_of_late_frames_ms) /
4071320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                        late_video_frames :
4081320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                    0)
4091320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci            << " ms)";
4105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  LOG(INFO) << "Average encoded bitrate (kbps): " << avg_encoded_bitrate;
4115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  LOG(INFO) << "Average target bitrate (kbps): " << avg_target_bitrate;
412116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  LOG(INFO) << "Writing log: " << output_path.value();
413116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
414116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // Truncate file and then write serialized log.
415116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  {
416116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    base::ScopedFILE file(base::OpenFile(output_path, "wb"));
417116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    if (!file.get()) {
418116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      LOG(INFO) << "Cannot write to log.";
419116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      return;
420116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    }
421116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
4225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  AppendLogToFile(&video_metadata, video_frame_events, video_packet_events,
4235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                  output_path);
4245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  AppendLogToFile(&audio_metadata, audio_frame_events, audio_packet_events,
4255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                  output_path);
426116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
427116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
428116680a4aac90f2aa7413d9095a592090648e557Ben MurdochNetworkSimulationModel DefaultModel() {
429116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  NetworkSimulationModel model;
430116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  model.set_type(cast::proto::INTERRUPTED_POISSON_PROCESS);
431116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  IPPModel* ipp = model.mutable_ipp();
432116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  ipp->set_coef_burstiness(0.609);
433116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  ipp->set_coef_variance(4.1);
434116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
435116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  ipp->add_average_rate(0.609);
436116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  ipp->add_average_rate(0.495);
437116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  ipp->add_average_rate(0.561);
438116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  ipp->add_average_rate(0.458);
439116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  ipp->add_average_rate(0.538);
440116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  ipp->add_average_rate(0.513);
441116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  ipp->add_average_rate(0.585);
442116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  ipp->add_average_rate(0.592);
443116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  ipp->add_average_rate(0.658);
444116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  ipp->add_average_rate(0.556);
445116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  ipp->add_average_rate(0.371);
446116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  ipp->add_average_rate(0.595);
447116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  ipp->add_average_rate(0.490);
448116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  ipp->add_average_rate(0.980);
449116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  ipp->add_average_rate(0.781);
450116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  ipp->add_average_rate(0.463);
451116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
452116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  return model;
453116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
454116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
455116680a4aac90f2aa7413d9095a592090648e557Ben Murdochbool IsModelValid(const NetworkSimulationModel& model) {
456116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (!model.has_type())
457116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    return false;
458116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  NetworkSimulationModelType type = model.type();
459116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (type == media::cast::proto::INTERRUPTED_POISSON_PROCESS) {
460116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    if (!model.has_ipp())
461116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      return false;
462116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    const IPPModel& ipp = model.ipp();
463116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    if (ipp.coef_burstiness() <= 0.0 || ipp.coef_variance() <= 0.0)
464116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      return false;
465116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    if (ipp.average_rate_size() == 0)
466116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      return false;
467116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    for (int i = 0; i < ipp.average_rate_size(); i++) {
468116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      if (ipp.average_rate(i) <= 0.0)
469116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        return false;
470116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    }
471116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
472116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
473116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  return true;
474116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
475116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
476116680a4aac90f2aa7413d9095a592090648e557Ben MurdochNetworkSimulationModel LoadModel(const base::FilePath& model_path) {
477116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (model_path.empty()) {
478116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    LOG(ERROR) << "Model path not set.";
479116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    return DefaultModel();
480116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
481116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  std::string model_str;
482116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (!base::ReadFileToString(model_path, &model_str)) {
483116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    LOG(ERROR) << "Failed to read model file.";
484116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    return DefaultModel();
485116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
486116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
487116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  NetworkSimulationModel model;
488116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (!model.ParseFromString(model_str)) {
489116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    LOG(ERROR) << "Failed to parse model.";
490116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    return DefaultModel();
491116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
492116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (!IsModelValid(model)) {
493116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    LOG(ERROR) << "Invalid model.";
494116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    return DefaultModel();
495116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
496116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
497116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  return model;
498116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
499116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
500116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}  // namespace
501116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}  // namespace cast
502116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}  // namespace media
503116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
504116680a4aac90f2aa7413d9095a592090648e557Ben Murdochint main(int argc, char** argv) {
505116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  base::AtExitManager at_exit;
506116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  CommandLine::Init(argc, argv);
507116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  InitLogging(logging::LoggingSettings());
508116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
509116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  const CommandLine* cmd = CommandLine::ForCurrentProcess();
510116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  base::FilePath media_path = cmd->GetSwitchValuePath(media::cast::kLibDir);
511116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (media_path.empty()) {
512116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    if (!PathService::Get(base::DIR_MODULE, &media_path)) {
513116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      LOG(ERROR) << "Failed to load FFmpeg.";
514116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      return 1;
515116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    }
516116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
517116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
518116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (!media::InitializeMediaLibrary(media_path)) {
519116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    LOG(ERROR) << "Failed to initialize FFmpeg.";
520116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    return 1;
521116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
522116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
523116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  base::FilePath source_path = cmd->GetSwitchValuePath(
524116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      media::cast::kSourcePath);
525116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  base::FilePath output_path = cmd->GetSwitchValuePath(
526116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      media::cast::kOutputPath);
527116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (output_path.empty()) {
528116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    base::GetTempDir(&output_path);
529116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    output_path = output_path.AppendASCII("sim-events.gz");
530116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
531116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  std::string sim_id = cmd->GetSwitchValueASCII(media::cast::kSimulationId);
532116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
533116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  NetworkSimulationModel model = media::cast::LoadModel(
534116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      cmd->GetSwitchValuePath(media::cast::kModelPath));
535116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
536116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  base::DictionaryValue values;
537116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  values.SetBoolean("sim", true);
538116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  values.SetString("sim-id", sim_id);
539116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
540116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  std::string extra_data;
541116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  base::JSONWriter::Write(&values, &extra_data);
542116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
543116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // Run.
544116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  media::cast::RunSimulation(source_path, output_path, extra_data, model);
545116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  return 0;
546116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
547