OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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 // Simulate end to end streaming. | 5 // Simulate end to end streaming. |
6 // | 6 // |
7 // Input: | 7 // Input: |
8 // --source= | 8 // --source= |
9 // WebM used as the source of video and audio frames. | 9 // WebM used as the source of video and audio frames. |
10 // --output= | 10 // --output= |
(...skipping 28 matching lines...) Expand all Loading... |
39 #include "media/cast/cast_sender.h" | 39 #include "media/cast/cast_sender.h" |
40 #include "media/cast/logging/encoding_event_subscriber.h" | 40 #include "media/cast/logging/encoding_event_subscriber.h" |
41 #include "media/cast/logging/log_serializer.h" | 41 #include "media/cast/logging/log_serializer.h" |
42 #include "media/cast/logging/logging_defines.h" | 42 #include "media/cast/logging/logging_defines.h" |
43 #include "media/cast/logging/proto/raw_events.pb.h" | 43 #include "media/cast/logging/proto/raw_events.pb.h" |
44 #include "media/cast/logging/raw_event_subscriber_bundle.h" | 44 #include "media/cast/logging/raw_event_subscriber_bundle.h" |
45 #include "media/cast/logging/simple_event_subscriber.h" | 45 #include "media/cast/logging/simple_event_subscriber.h" |
46 #include "media/cast/test/fake_media_source.h" | 46 #include "media/cast/test/fake_media_source.h" |
47 #include "media/cast/test/fake_single_thread_task_runner.h" | 47 #include "media/cast/test/fake_single_thread_task_runner.h" |
48 #include "media/cast/test/loopback_transport.h" | 48 #include "media/cast/test/loopback_transport.h" |
| 49 #include "media/cast/test/proto/network_simulation_model.pb.h" |
49 #include "media/cast/test/skewed_tick_clock.h" | 50 #include "media/cast/test/skewed_tick_clock.h" |
50 #include "media/cast/test/utility/audio_utility.h" | 51 #include "media/cast/test/utility/audio_utility.h" |
51 #include "media/cast/test/utility/default_config.h" | 52 #include "media/cast/test/utility/default_config.h" |
52 #include "media/cast/test/utility/test_util.h" | 53 #include "media/cast/test/utility/test_util.h" |
53 #include "media/cast/test/utility/udp_proxy.h" | 54 #include "media/cast/test/utility/udp_proxy.h" |
54 #include "media/cast/test/utility/video_utility.h" | 55 #include "media/cast/test/utility/video_utility.h" |
55 #include "media/cast/transport/cast_transport_config.h" | 56 #include "media/cast/transport/cast_transport_config.h" |
56 #include "media/cast/transport/cast_transport_defines.h" | 57 #include "media/cast/transport/cast_transport_defines.h" |
57 #include "media/cast/transport/cast_transport_sender.h" | 58 #include "media/cast/transport/cast_transport_sender.h" |
58 #include "media/cast/transport/cast_transport_sender_impl.h" | 59 #include "media/cast/transport/cast_transport_sender_impl.h" |
59 | 60 |
| 61 using media::cast::proto::IPPModel; |
| 62 using media::cast::proto::NetworkSimulationModel; |
| 63 using media::cast::proto::NetworkSimulationModelType; |
| 64 |
60 namespace media { | 65 namespace media { |
61 namespace cast { | 66 namespace cast { |
62 namespace { | 67 namespace { |
63 | |
64 const int kTargetDelay = 300; | 68 const int kTargetDelay = 300; |
65 const char kSourcePath[] = "source"; | 69 const char kSourcePath[] = "source"; |
| 70 const char kModelPath[] = "model"; |
66 const char kOutputPath[] = "output"; | 71 const char kOutputPath[] = "output"; |
67 const char kSimulationId[] = "sim-id"; | 72 const char kSimulationId[] = "sim-id"; |
| 73 const char kLibDir[] = "lib-dir"; |
68 | 74 |
69 void UpdateCastTransportStatus(transport::CastTransportStatus status) { | 75 void UpdateCastTransportStatus(transport::CastTransportStatus status) { |
70 LOG(INFO) << "Cast transport status: " << status; | 76 LOG(INFO) << "Cast transport status: " << status; |
71 } | 77 } |
72 | 78 |
73 void AudioInitializationStatus(CastInitializationStatus status) { | 79 void AudioInitializationStatus(CastInitializationStatus status) { |
74 LOG(INFO) << "Audio status: " << status; | 80 LOG(INFO) << "Audio status: " << status; |
75 } | 81 } |
76 | 82 |
77 void VideoInitializationStatus(CastInitializationStatus status) { | 83 void VideoInitializationStatus(CastInitializationStatus status) { |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
151 LOG(ERROR) << "Failed to append to log."; | 157 LOG(ERROR) << "Failed to append to log."; |
152 } | 158 } |
153 } | 159 } |
154 | 160 |
155 // Run simulation once. | 161 // Run simulation once. |
156 // | 162 // |
157 // |output_path| is the path to write serialized log. | 163 // |output_path| is the path to write serialized log. |
158 // |extra_data| is extra tagging information to write to log. | 164 // |extra_data| is extra tagging information to write to log. |
159 void RunSimulation(const base::FilePath& source_path, | 165 void RunSimulation(const base::FilePath& source_path, |
160 const base::FilePath& output_path, | 166 const base::FilePath& output_path, |
161 const std::string& extra_data) { | 167 const std::string& extra_data, |
| 168 const NetworkSimulationModel& model) { |
162 // Fake clock. Make sure start time is non zero. | 169 // Fake clock. Make sure start time is non zero. |
163 base::SimpleTestTickClock testing_clock; | 170 base::SimpleTestTickClock testing_clock; |
164 testing_clock.Advance(base::TimeDelta::FromSeconds(1)); | 171 testing_clock.Advance(base::TimeDelta::FromSeconds(1)); |
165 | 172 |
166 // Task runner. | 173 // Task runner. |
167 scoped_refptr<test::FakeSingleThreadTaskRunner> task_runner = | 174 scoped_refptr<test::FakeSingleThreadTaskRunner> task_runner = |
168 new test::FakeSingleThreadTaskRunner(&testing_clock); | 175 new test::FakeSingleThreadTaskRunner(&testing_clock); |
169 base::ThreadTaskRunnerHandle task_runner_handle(task_runner); | 176 base::ThreadTaskRunnerHandle task_runner_handle(task_runner); |
170 | 177 |
171 // CastEnvironments. | 178 // CastEnvironments. |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
236 net::IPEndPoint(), | 243 net::IPEndPoint(), |
237 base::Bind(&UpdateCastTransportStatus), | 244 base::Bind(&UpdateCastTransportStatus), |
238 base::Bind(&LogTransportEvents, sender_env), | 245 base::Bind(&LogTransportEvents, sender_env), |
239 base::TimeDelta::FromSeconds(1), | 246 base::TimeDelta::FromSeconds(1), |
240 task_runner, | 247 task_runner, |
241 &sender_to_receiver)); | 248 &sender_to_receiver)); |
242 scoped_ptr<CastSender> cast_sender( | 249 scoped_ptr<CastSender> cast_sender( |
243 CastSender::Create(sender_env, transport_sender.get())); | 250 CastSender::Create(sender_env, transport_sender.get())); |
244 | 251 |
245 // Build packet pipe. | 252 // Build packet pipe. |
246 // TODO(hclam): Allow user to input these parameters. Following | 253 if (model.type() != media::cast::proto::INTERRUPTED_POISSON_PROCESS) { |
247 // parameters are taken from a session from real-world data. It is | 254 LOG(ERROR) << "Unknown model type " << model.type() << "."; |
248 // chosen here because it gives a difficult environment. | 255 return; |
249 std::vector<double> average_rates; | 256 } |
250 average_rates.push_back(0.609); | 257 |
251 average_rates.push_back(0.495); | 258 const IPPModel& ipp_model = model.ipp(); |
252 average_rates.push_back(0.561); | 259 |
253 average_rates.push_back(0.458); | 260 std::vector<double> average_rates(ipp_model.average_rate_size()); |
254 average_rates.push_back(0.538); | 261 std::copy(ipp_model.average_rate().begin(), ipp_model.average_rate().end(), |
255 average_rates.push_back(0.513); | 262 average_rates.begin()); |
256 average_rates.push_back(0.585); | 263 test::InterruptedPoissonProcess ipp(average_rates, |
257 average_rates.push_back(0.592); | 264 ipp_model.coef_burstiness(), ipp_model.coef_variance(), 0); |
258 average_rates.push_back(0.658); | |
259 average_rates.push_back(0.556); | |
260 average_rates.push_back(0.371); | |
261 average_rates.push_back(0.595); | |
262 average_rates.push_back(0.490); | |
263 average_rates.push_back(0.980); | |
264 average_rates.push_back(0.781); | |
265 average_rates.push_back(0.463); | |
266 test::InterruptedPoissonProcess ipp(average_rates, 0.3, 4.1, 0); | |
267 | 265 |
268 // Connect sender to receiver. This initializes the pipe. | 266 // Connect sender to receiver. This initializes the pipe. |
269 receiver_to_sender.Initialize( | 267 receiver_to_sender.Initialize( |
270 ipp.NewBuffer(128 * 1024), cast_sender->packet_receiver(), task_runner, | 268 ipp.NewBuffer(128 * 1024), cast_sender->packet_receiver(), task_runner, |
271 &testing_clock); | 269 &testing_clock); |
272 sender_to_receiver.Initialize( | 270 sender_to_receiver.Initialize( |
273 ipp.NewBuffer(128 * 1024), cast_receiver->packet_receiver(), task_runner, | 271 ipp.NewBuffer(128 * 1024), cast_receiver->packet_receiver(), task_runner, |
274 &testing_clock); | 272 &testing_clock); |
275 | 273 |
276 // Start receiver. | 274 // Start receiver. |
(...skipping 17 matching lines...) Expand all Loading... |
294 CreateDefaultVideoEncodeMemoryCallback()); | 292 CreateDefaultVideoEncodeMemoryCallback()); |
295 | 293 |
296 // Start sending. | 294 // Start sending. |
297 if (!source_path.empty()) { | 295 if (!source_path.empty()) { |
298 // 0 means using the FPS from the file. | 296 // 0 means using the FPS from the file. |
299 media_source.SetSourceFile(source_path, 0); | 297 media_source.SetSourceFile(source_path, 0); |
300 } | 298 } |
301 media_source.Start(cast_sender->audio_frame_input(), | 299 media_source.Start(cast_sender->audio_frame_input(), |
302 cast_sender->video_frame_input()); | 300 cast_sender->video_frame_input()); |
303 | 301 |
304 // Run for 5 minutes. | 302 // Run for 3 minutes. |
305 base::TimeDelta elapsed_time; | 303 base::TimeDelta elapsed_time; |
306 while (elapsed_time.InMinutes() < 5) { | 304 while (elapsed_time.InMinutes() < 3) { |
307 // Each step is 100us. | 305 // Each step is 100us. |
308 base::TimeDelta step = base::TimeDelta::FromMicroseconds(100); | 306 base::TimeDelta step = base::TimeDelta::FromMicroseconds(100); |
309 task_runner->Sleep(step); | 307 task_runner->Sleep(step); |
310 elapsed_time += step; | 308 elapsed_time += step; |
311 } | 309 } |
312 | 310 |
313 LOG(INFO) << "Audio frame count: " << audio_frame_count; | 311 LOG(INFO) << "Audio frame count: " << audio_frame_count; |
314 LOG(INFO) << "Video frame count: " << video_frame_count; | 312 LOG(INFO) << "Video frame count: " << video_frame_count; |
315 LOG(INFO) << "Writing log: " << output_path.value(); | 313 LOG(INFO) << "Writing log: " << output_path.value(); |
316 | 314 |
317 // Truncate file and then write serialized log. | 315 // Truncate file and then write serialized log. |
318 { | 316 { |
319 base::ScopedFILE file(base::OpenFile(output_path, "wb")); | 317 base::ScopedFILE file(base::OpenFile(output_path, "wb")); |
320 if (!file.get()) { | 318 if (!file.get()) { |
321 LOG(INFO) << "Cannot write to log."; | 319 LOG(INFO) << "Cannot write to log."; |
322 return; | 320 return; |
323 } | 321 } |
324 } | 322 } |
325 AppendLog(&video_event_subscriber, extra_data, output_path); | 323 AppendLog(&video_event_subscriber, extra_data, output_path); |
326 AppendLog(&audio_event_subscriber, extra_data, output_path); | 324 AppendLog(&audio_event_subscriber, extra_data, output_path); |
327 } | 325 } |
328 | 326 |
| 327 NetworkSimulationModel DefaultModel() { |
| 328 NetworkSimulationModel model; |
| 329 model.set_type(cast::proto::INTERRUPTED_POISSON_PROCESS); |
| 330 IPPModel* ipp = model.mutable_ipp(); |
| 331 ipp->set_coef_burstiness(0.609); |
| 332 ipp->set_coef_variance(4.1); |
| 333 |
| 334 ipp->add_average_rate(0.609); |
| 335 ipp->add_average_rate(0.495); |
| 336 ipp->add_average_rate(0.561); |
| 337 ipp->add_average_rate(0.458); |
| 338 ipp->add_average_rate(0.538); |
| 339 ipp->add_average_rate(0.513); |
| 340 ipp->add_average_rate(0.585); |
| 341 ipp->add_average_rate(0.592); |
| 342 ipp->add_average_rate(0.658); |
| 343 ipp->add_average_rate(0.556); |
| 344 ipp->add_average_rate(0.371); |
| 345 ipp->add_average_rate(0.595); |
| 346 ipp->add_average_rate(0.490); |
| 347 ipp->add_average_rate(0.980); |
| 348 ipp->add_average_rate(0.781); |
| 349 ipp->add_average_rate(0.463); |
| 350 |
| 351 return model; |
| 352 } |
| 353 |
| 354 bool IsModelValid(const NetworkSimulationModel& model) { |
| 355 if (!model.has_type()) |
| 356 return false; |
| 357 NetworkSimulationModelType type = model.type(); |
| 358 if (type == media::cast::proto::INTERRUPTED_POISSON_PROCESS) { |
| 359 if (!model.has_ipp()) |
| 360 return false; |
| 361 const IPPModel& ipp = model.ipp(); |
| 362 if (ipp.coef_burstiness() <= 0.0 || ipp.coef_variance() <= 0.0) |
| 363 return false; |
| 364 if (ipp.average_rate_size() == 0) |
| 365 return false; |
| 366 for (int i = 0; i < ipp.average_rate_size(); i++) { |
| 367 if (ipp.average_rate(i) <= 0.0) |
| 368 return false; |
| 369 } |
| 370 } |
| 371 |
| 372 return true; |
| 373 } |
| 374 |
| 375 NetworkSimulationModel LoadModel(const base::FilePath& model_path) { |
| 376 if (model_path.empty()) { |
| 377 LOG(ERROR) << "Model path not set."; |
| 378 return DefaultModel(); |
| 379 } |
| 380 std::string model_str; |
| 381 if (!base::ReadFileToString(model_path, &model_str)) { |
| 382 LOG(ERROR) << "Failed to read model file."; |
| 383 return DefaultModel(); |
| 384 } |
| 385 |
| 386 NetworkSimulationModel model; |
| 387 if (!model.ParseFromString(model_str)) { |
| 388 LOG(ERROR) << "Failed to parse model."; |
| 389 return DefaultModel(); |
| 390 } |
| 391 if (!IsModelValid(model)) { |
| 392 LOG(ERROR) << "Invalid model."; |
| 393 return DefaultModel(); |
| 394 } |
| 395 |
| 396 return model; |
| 397 } |
| 398 |
329 } // namespace | 399 } // namespace |
330 } // namespace cast | 400 } // namespace cast |
331 } // namespace media | 401 } // namespace media |
332 | 402 |
333 int main(int argc, char** argv) { | 403 int main(int argc, char** argv) { |
334 base::AtExitManager at_exit; | 404 base::AtExitManager at_exit; |
335 CommandLine::Init(argc, argv); | 405 CommandLine::Init(argc, argv); |
336 InitLogging(logging::LoggingSettings()); | 406 InitLogging(logging::LoggingSettings()); |
337 | 407 |
338 base::FilePath media_path; | 408 const CommandLine* cmd = CommandLine::ForCurrentProcess(); |
339 if (!PathService::Get(base::DIR_MODULE, &media_path)) { | 409 base::FilePath media_path = cmd->GetSwitchValuePath(media::cast::kLibDir); |
340 LOG(ERROR) << "Failed to load FFmpeg."; | 410 if (media_path.empty()) { |
| 411 if (!PathService::Get(base::DIR_MODULE, &media_path)) { |
| 412 LOG(ERROR) << "Failed to load FFmpeg."; |
| 413 return 1; |
| 414 } |
| 415 } |
| 416 |
| 417 if (!media::InitializeMediaLibrary(media_path)) { |
| 418 LOG(ERROR) << "Failed to initialize FFmpeg."; |
341 return 1; | 419 return 1; |
342 } | 420 } |
343 media::InitializeMediaLibrary(media_path); | |
344 | 421 |
345 const CommandLine* cmd = CommandLine::ForCurrentProcess(); | |
346 base::FilePath source_path = cmd->GetSwitchValuePath( | 422 base::FilePath source_path = cmd->GetSwitchValuePath( |
347 media::cast::kSourcePath); | 423 media::cast::kSourcePath); |
348 base::FilePath output_path = cmd->GetSwitchValuePath( | 424 base::FilePath output_path = cmd->GetSwitchValuePath( |
349 media::cast::kOutputPath); | 425 media::cast::kOutputPath); |
350 if (output_path.empty()) { | 426 if (output_path.empty()) { |
351 base::GetTempDir(&output_path); | 427 base::GetTempDir(&output_path); |
352 output_path = output_path.AppendASCII("sim-events.gz"); | 428 output_path = output_path.AppendASCII("sim-events.gz"); |
353 } | 429 } |
354 std::string sim_id = cmd->GetSwitchValueASCII(media::cast::kSimulationId); | 430 std::string sim_id = cmd->GetSwitchValueASCII(media::cast::kSimulationId); |
355 | 431 |
| 432 NetworkSimulationModel model = media::cast::LoadModel( |
| 433 cmd->GetSwitchValuePath(media::cast::kModelPath)); |
| 434 |
356 base::DictionaryValue values; | 435 base::DictionaryValue values; |
357 values.SetBoolean("sim", true); | 436 values.SetBoolean("sim", true); |
358 values.SetString("sim-id", sim_id); | 437 values.SetString("sim-id", sim_id); |
359 | 438 |
360 std::string extra_data; | 439 std::string extra_data; |
361 base::JSONWriter::Write(&values, &extra_data); | 440 base::JSONWriter::Write(&values, &extra_data); |
362 | 441 |
363 // Run. | 442 // Run. |
364 media::cast::RunSimulation(source_path, output_path, extra_data); | 443 media::cast::RunSimulation(source_path, output_path, extra_data, model); |
365 return 0; | 444 return 0; |
366 } | 445 } |
OLD | NEW |