Chromium Code Reviews| 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 "base/at_exit.h" | 8 #include "base/at_exit.h" |
| 9 #include "base/file_util.h" | 9 #include "base/file_util.h" |
| 10 #include "base/logging.h" | 10 #include "base/logging.h" |
| (...skipping 187 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 198 video_config.max_number_of_video_buffers_used = 1; | 198 video_config.max_number_of_video_buffers_used = 1; |
| 199 video_config.number_of_cores = 1; | 199 video_config.number_of_cores = 1; |
| 200 return video_config; | 200 return video_config; |
| 201 } | 201 } |
| 202 | 202 |
| 203 class SendProcess { | 203 class SendProcess { |
| 204 public: | 204 public: |
| 205 SendProcess(scoped_refptr<base::SingleThreadTaskRunner> thread_proxy, | 205 SendProcess(scoped_refptr<base::SingleThreadTaskRunner> thread_proxy, |
| 206 base::TickClock* clock, | 206 base::TickClock* clock, |
| 207 const VideoSenderConfig& video_config, | 207 const VideoSenderConfig& video_config, |
| 208 FrameInput* frame_input) | 208 scoped_refptr<AudioFrameInput> audio_frame_input, |
| 209 scoped_refptr<VideoFrameInput> video_frame_input) | |
| 209 : test_app_thread_proxy_(thread_proxy), | 210 : test_app_thread_proxy_(thread_proxy), |
| 210 video_config_(video_config), | 211 video_config_(video_config), |
| 211 audio_diff_(kFrameTimerMs), | 212 audio_diff_(kFrameTimerMs), |
| 212 frame_input_(frame_input), | 213 audio_frame_input_(audio_frame_input), |
| 214 video_frame_input_(video_frame_input), | |
| 213 synthetic_count_(0), | 215 synthetic_count_(0), |
| 214 clock_(clock), | 216 clock_(clock), |
| 215 start_time_(), | 217 start_time_(), |
| 216 send_time_(), | 218 send_time_(), |
| 217 weak_factory_(this) { | 219 weak_factory_(this) { |
| 218 audio_bus_factory_.reset(new TestAudioBusFactory(kAudioChannels, | 220 audio_bus_factory_.reset(new TestAudioBusFactory(kAudioChannels, |
| 219 kAudioSamplingFrequency, | 221 kAudioSamplingFrequency, |
| 220 kSoundFrequency, | 222 kSoundFrequency, |
| 221 kSoundVolume)); | 223 kSoundVolume)); |
| 222 if (ReadFromFile()) { | 224 if (ReadFromFile()) { |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 238 | 240 |
| 239 void SendFrame() { | 241 void SendFrame() { |
| 240 // Make sure that we don't drift. | 242 // Make sure that we don't drift. |
| 241 int num_10ms_blocks = audio_diff_ / 10; | 243 int num_10ms_blocks = audio_diff_ / 10; |
| 242 // Avoid drift. | 244 // Avoid drift. |
| 243 audio_diff_ += kFrameTimerMs - num_10ms_blocks * 10; | 245 audio_diff_ += kFrameTimerMs - num_10ms_blocks * 10; |
| 244 | 246 |
| 245 scoped_ptr<AudioBus> audio_bus(audio_bus_factory_->NextAudioBus( | 247 scoped_ptr<AudioBus> audio_bus(audio_bus_factory_->NextAudioBus( |
| 246 base::TimeDelta::FromMilliseconds(10) * num_10ms_blocks)); | 248 base::TimeDelta::FromMilliseconds(10) * num_10ms_blocks)); |
| 247 AudioBus* const audio_bus_ptr = audio_bus.get(); | 249 AudioBus* const audio_bus_ptr = audio_bus.get(); |
| 248 frame_input_->InsertAudio( | 250 audio_frame_input_->InsertAudio( |
| 249 audio_bus_ptr, | 251 audio_bus_ptr, |
| 250 clock_->NowTicks(), | 252 clock_->NowTicks(), |
| 251 base::Bind(&OwnThatAudioBus, base::Passed(&audio_bus))); | 253 base::Bind(&OwnThatAudioBus, base::Passed(&audio_bus))); |
| 252 | 254 |
| 253 gfx::Size size(video_config_.width, video_config_.height); | 255 gfx::Size size(video_config_.width, video_config_.height); |
| 254 // TODO(mikhal): Use the provided timestamp. | 256 // TODO(mikhal): Use the provided timestamp. |
| 255 if (start_time_.is_null()) | 257 if (start_time_.is_null()) |
| 256 start_time_ = clock_->NowTicks(); | 258 start_time_ = clock_->NowTicks(); |
| 257 base::TimeDelta time_diff = clock_->NowTicks() - start_time_; | 259 base::TimeDelta time_diff = clock_->NowTicks() - start_time_; |
| 258 scoped_refptr<media::VideoFrame> video_frame = | 260 scoped_refptr<media::VideoFrame> video_frame = |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 270 // Sleep if that time has yet to elapse. | 272 // Sleep if that time has yet to elapse. |
| 271 base::TimeTicks now = clock_->NowTicks(); | 273 base::TimeTicks now = clock_->NowTicks(); |
| 272 base::TimeDelta video_frame_time = | 274 base::TimeDelta video_frame_time = |
| 273 base::TimeDelta::FromMilliseconds(kFrameTimerMs); | 275 base::TimeDelta::FromMilliseconds(kFrameTimerMs); |
| 274 base::TimeDelta elapsed_time = now - send_time_; | 276 base::TimeDelta elapsed_time = now - send_time_; |
| 275 if (elapsed_time < video_frame_time) { | 277 if (elapsed_time < video_frame_time) { |
| 276 VLOG(1) << "Wait" << (video_frame_time - elapsed_time).InMilliseconds(); | 278 VLOG(1) << "Wait" << (video_frame_time - elapsed_time).InMilliseconds(); |
| 277 test_app_thread_proxy_->PostDelayedTask( | 279 test_app_thread_proxy_->PostDelayedTask( |
| 278 FROM_HERE, | 280 FROM_HERE, |
| 279 base::Bind(&SendProcess::SendVideoFrameOnTime, | 281 base::Bind(&SendProcess::SendVideoFrameOnTime, |
| 280 base::Unretained(this), | 282 weak_factory_.GetWeakPtr(), |
| 281 video_frame), | 283 video_frame), |
| 282 video_frame_time - elapsed_time); | 284 video_frame_time - elapsed_time); |
| 283 } else { | 285 } else { |
| 284 test_app_thread_proxy_->PostTask( | 286 test_app_thread_proxy_->PostTask( |
| 285 FROM_HERE, | 287 FROM_HERE, |
| 286 base::Bind(&SendProcess::SendVideoFrameOnTime, | 288 base::Bind(&SendProcess::SendVideoFrameOnTime, |
| 287 base::Unretained(this), | 289 weak_factory_.GetWeakPtr(), |
| 288 video_frame)); | 290 video_frame)); |
| 289 } | 291 } |
| 290 } | 292 } |
| 291 | 293 |
| 292 void SendVideoFrameOnTime(scoped_refptr<media::VideoFrame> video_frame) { | 294 void SendVideoFrameOnTime(scoped_refptr<media::VideoFrame> video_frame) { |
| 293 send_time_ = clock_->NowTicks(); | 295 send_time_ = clock_->NowTicks(); |
| 294 frame_input_->InsertRawVideoFrame(video_frame, send_time_); | 296 video_frame_input_->InsertRawVideoFrame(video_frame, send_time_); |
| 295 test_app_thread_proxy_->PostTask( | 297 test_app_thread_proxy_->PostTask( |
| 296 FROM_HERE, base::Bind(&SendProcess::SendFrame, base::Unretained(this))); | 298 FROM_HERE, base::Bind(&SendProcess::SendFrame, base::Unretained(this))); |
| 297 } | 299 } |
| 298 | 300 |
| 299 private: | 301 private: |
| 300 scoped_refptr<base::SingleThreadTaskRunner> test_app_thread_proxy_; | 302 scoped_refptr<base::SingleThreadTaskRunner> test_app_thread_proxy_; |
| 301 const VideoSenderConfig video_config_; | 303 const VideoSenderConfig video_config_; |
| 302 int audio_diff_; | 304 int audio_diff_; |
| 303 const scoped_refptr<FrameInput> frame_input_; | 305 const scoped_refptr<AudioFrameInput> audio_frame_input_; |
| 306 const scoped_refptr<VideoFrameInput> video_frame_input_; | |
| 304 FILE* video_file_; | 307 FILE* video_file_; |
| 305 uint8 synthetic_count_; | 308 uint8 synthetic_count_; |
| 306 base::TickClock* const clock_; // Not owned by this class. | 309 base::TickClock* const clock_; // Not owned by this class. |
| 307 base::TimeTicks start_time_; | 310 base::TimeTicks start_time_; |
| 308 base::TimeTicks send_time_; | 311 base::TimeTicks send_time_; |
| 309 scoped_ptr<TestAudioBusFactory> audio_bus_factory_; | 312 scoped_ptr<TestAudioBusFactory> audio_bus_factory_; |
| 310 base::WeakPtrFactory<SendProcess> weak_factory_; | 313 base::WeakPtrFactory<SendProcess> weak_factory_; |
| 311 }; | 314 }; |
| 312 | 315 |
| 313 } // namespace cast | 316 } // namespace cast |
| 314 } // namespace media | 317 } // namespace media |
| 315 | 318 |
| 316 namespace { | 319 namespace { |
| 317 void UpdateCastTransportStatus( | 320 void UpdateCastTransportStatus( |
| 318 media::cast::transport::CastTransportStatus status) {} | 321 media::cast::transport::CastTransportStatus status) {} |
| 319 | 322 |
| 320 void InitializationResult(media::cast::CastInitializationStatus result) { | 323 void InitializationResult(media::cast::CastInitializationStatus result) { |
| 321 CHECK_EQ(result, media::cast::STATUS_INITIALIZED); | 324 bool end_result = result == media::cast::STATUS_AUDIO_INITIALIZED || |
| 322 VLOG(1) << "Cast Sender initialized"; | 325 result == media::cast::STATUS_VIDEO_INITIALIZED; |
| 326 CHECK(end_result); | |
|
Alpha Left Google
2014/03/06 23:10:04
This should give a log message if !end_result is t
mikhal1
2014/03/06 23:38:53
Done.
| |
| 323 } | 327 } |
| 324 | 328 |
| 325 net::IPEndPoint CreateUDPAddress(std::string ip_str, int port) { | 329 net::IPEndPoint CreateUDPAddress(std::string ip_str, int port) { |
| 326 net::IPAddressNumber ip_number; | 330 net::IPAddressNumber ip_number; |
| 327 CHECK(net::ParseIPLiteralToNumber(ip_str, &ip_number)); | 331 CHECK(net::ParseIPLiteralToNumber(ip_str, &ip_number)); |
| 328 return net::IPEndPoint(ip_number, port); | 332 return net::IPEndPoint(ip_number, port); |
| 329 } | 333 } |
| 330 | 334 |
| 331 void WriteLogsToFileAndStopSubscribing( | 335 void WriteLogsToFileAndStopSubscribing( |
| 332 const scoped_refptr<media::cast::CastEnvironment>& cast_environment, | 336 const scoped_refptr<media::cast::CastEnvironment>& cast_environment, |
| 333 scoped_ptr<media::cast::EncodingEventSubscriber> video_event_subscriber, | 337 scoped_ptr<media::cast::EncodingEventSubscriber> video_event_subscriber, |
| 334 scoped_ptr<media::cast::EncodingEventSubscriber> audio_event_subscriber, | 338 scoped_ptr<media::cast::EncodingEventSubscriber> audio_event_subscriber, |
| 335 file_util::ScopedFILE log_file) { | 339 file_util::ScopedFILE log_file) { |
| 336 media::cast::LogSerializer serializer(media::cast::kMaxSerializedLogBytes); | 340 media::cast::LogSerializer serializer(media::cast::kMaxSerializedLogBytes); |
| 337 | 341 |
| 338 // Serialize video events. | 342 // Serialize video events. |
| 339 cast_environment->Logging()->RemoveRawEventSubscriber( | 343 cast_environment->Logging()->RemoveRawEventSubscriber( |
| 340 video_event_subscriber.get()); | 344 video_event_subscriber.get()); |
| 341 media::cast::FrameEventMap frame_events; | 345 media::cast::FrameEventMap frame_events; |
| 342 media::cast::PacketEventMap packet_events; | 346 media::cast::PacketEventMap packet_events; |
| 343 media::cast::RtpTimestamp first_rtp_timestamp; | 347 media::cast::RtpTimestamp first_rtp_timestamp; |
| 344 video_event_subscriber->GetEventsAndReset(&frame_events, &packet_events, | 348 video_event_subscriber->GetEventsAndReset( |
| 345 &first_rtp_timestamp); | 349 &frame_events, &packet_events, &first_rtp_timestamp); |
| 346 | 350 |
| 347 VLOG(0) << "Video frame map size: " << frame_events.size(); | 351 VLOG(0) << "Video frame map size: " << frame_events.size(); |
| 348 VLOG(0) << "Video packet map size: " << packet_events.size(); | 352 VLOG(0) << "Video packet map size: " << packet_events.size(); |
| 349 | 353 |
| 350 if (!serializer.SerializeEventsForStream(false, frame_events, packet_events, | 354 if (!serializer.SerializeEventsForStream( |
| 351 first_rtp_timestamp)) { | 355 false, frame_events, packet_events, first_rtp_timestamp)) { |
| 352 VLOG(1) << "Failed to serialize video events."; | 356 VLOG(1) << "Failed to serialize video events."; |
| 353 return; | 357 return; |
| 354 } | 358 } |
| 355 | 359 |
| 356 int length_so_far = serializer.GetSerializedLength(); | 360 int length_so_far = serializer.GetSerializedLength(); |
| 357 VLOG(0) << "Video events serialized length: " << length_so_far; | 361 VLOG(0) << "Video events serialized length: " << length_so_far; |
| 358 | 362 |
| 359 // Serialize audio events. | 363 // Serialize audio events. |
| 360 cast_environment->Logging()->RemoveRawEventSubscriber( | 364 cast_environment->Logging()->RemoveRawEventSubscriber( |
| 361 audio_event_subscriber.get()); | 365 audio_event_subscriber.get()); |
| 362 audio_event_subscriber->GetEventsAndReset(&frame_events, &packet_events, | 366 audio_event_subscriber->GetEventsAndReset( |
| 363 &first_rtp_timestamp); | 367 &frame_events, &packet_events, &first_rtp_timestamp); |
| 364 | 368 |
| 365 VLOG(0) << "Audio frame map size: " << frame_events.size(); | 369 VLOG(0) << "Audio frame map size: " << frame_events.size(); |
| 366 VLOG(0) << "Audio packet map size: " << packet_events.size(); | 370 VLOG(0) << "Audio packet map size: " << packet_events.size(); |
| 367 | 371 |
| 368 if (!serializer.SerializeEventsForStream(true, frame_events, packet_events, | 372 if (!serializer.SerializeEventsForStream( |
| 369 first_rtp_timestamp)) { | 373 true, frame_events, packet_events, first_rtp_timestamp)) { |
| 370 VLOG(1) << "Failed to serialize audio events."; | 374 VLOG(1) << "Failed to serialize audio events."; |
| 371 return; | 375 return; |
| 372 } | 376 } |
| 373 | 377 |
| 374 VLOG(0) << "Audio events serialized length: " | 378 VLOG(0) << "Audio events serialized length: " |
| 375 << serializer.GetSerializedLength() - length_so_far; | 379 << serializer.GetSerializedLength() - length_so_far; |
| 376 | 380 |
| 377 scoped_ptr<std::string> serialized_string = | 381 scoped_ptr<std::string> serialized_string = |
| 378 serializer.GetSerializedLogAndReset(); | 382 serializer.GetSerializedLogAndReset(); |
| 379 VLOG(0) << "Serialized string size: " << serialized_string->size(); | 383 VLOG(0) << "Serialized string size: " << serialized_string->size(); |
| 380 | 384 |
| 381 size_t ret = fwrite( | 385 size_t ret = fwrite( |
| 382 &(*serialized_string)[0], 1, serialized_string->size(), log_file.get()); | 386 &(*serialized_string)[0], 1, serialized_string->size(), log_file.get()); |
| 383 if (ret != serialized_string->size()) | 387 if (ret != serialized_string->size()) |
| 384 VLOG(1) << "Failed to write logs to file."; | 388 VLOG(1) << "Failed to write logs to file."; |
| 385 } | 389 } |
| 386 | 390 |
| 387 } // namespace | 391 } // namespace |
| 388 | 392 |
| 389 int main(int argc, char** argv) { | 393 int main(int argc, char** argv) { |
| 390 base::AtExitManager at_exit; | 394 base::AtExitManager at_exit; |
| 391 VLOG(1) << "Cast Sender"; | |
| 392 base::Thread test_thread("Cast sender test app thread"); | 395 base::Thread test_thread("Cast sender test app thread"); |
| 393 base::Thread audio_thread("Cast audio encoder thread"); | 396 base::Thread audio_thread("Cast audio encoder thread"); |
| 394 base::Thread video_thread("Cast video encoder thread"); | 397 base::Thread video_thread("Cast video encoder thread"); |
| 395 test_thread.Start(); | 398 test_thread.Start(); |
| 396 audio_thread.Start(); | 399 audio_thread.Start(); |
| 397 video_thread.Start(); | 400 video_thread.Start(); |
| 398 | 401 |
| 399 scoped_ptr<base::TickClock> clock(new base::DefaultTickClock()); | 402 scoped_ptr<base::TickClock> clock(new base::DefaultTickClock()); |
| 400 base::MessageLoopForIO io_message_loop; | 403 base::MessageLoopForIO io_message_loop; |
| 401 | 404 |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 439 new media::cast::CastEnvironment( | 442 new media::cast::CastEnvironment( |
| 440 clock.Pass(), | 443 clock.Pass(), |
| 441 io_message_loop.message_loop_proxy(), | 444 io_message_loop.message_loop_proxy(), |
| 442 audio_thread.message_loop_proxy(), | 445 audio_thread.message_loop_proxy(), |
| 443 NULL, | 446 NULL, |
| 444 video_thread.message_loop_proxy(), | 447 video_thread.message_loop_proxy(), |
| 445 NULL, | 448 NULL, |
| 446 io_message_loop.message_loop_proxy(), | 449 io_message_loop.message_loop_proxy(), |
| 447 media::cast::GetLoggingConfigWithRawEventsAndStatsEnabled())); | 450 media::cast::GetLoggingConfigWithRawEventsAndStatsEnabled())); |
| 448 | 451 |
| 449 scoped_ptr<media::cast::CastSender> cast_sender( | 452 scoped_ptr<media::cast::CastSender> cast_sender = |
| 450 media::cast::CastSender::CreateCastSender( | 453 media::cast::CastSender::Create(cast_environment, transport_sender.get()); |
| 451 cast_environment, | 454 |
| 452 &audio_config, | 455 cast_sender->InitializeVideo( |
| 453 &video_config, | 456 video_config, base::Bind(&InitializationResult), NULL); |
| 454 NULL, // gpu_factories. | 457 cast_sender->InitializeAudio(audio_config, base::Bind(&InitializationResult)); |
| 455 base::Bind(&InitializationResult), | |
| 456 transport_sender.get())); | |
| 457 | 458 |
| 458 transport_sender->SetPacketReceiver(cast_sender->packet_receiver()); | 459 transport_sender->SetPacketReceiver(cast_sender->packet_receiver()); |
| 459 | 460 |
| 460 media::cast::FrameInput* frame_input = cast_sender->frame_input(); | 461 scoped_refptr<media::cast::AudioFrameInput> audio_frame_input = |
| 462 cast_sender->audio_frame_input(); | |
| 463 scoped_refptr<media::cast::VideoFrameInput> video_frame_input = | |
| 464 cast_sender->video_frame_input(); | |
| 461 scoped_ptr<media::cast::SendProcess> send_process( | 465 scoped_ptr<media::cast::SendProcess> send_process( |
| 462 new media::cast::SendProcess(test_thread.message_loop_proxy(), | 466 new media::cast::SendProcess(test_thread.message_loop_proxy(), |
| 463 cast_environment->Clock(), | 467 cast_environment->Clock(), |
| 464 video_config, | 468 video_config, |
| 465 frame_input)); | 469 audio_frame_input, |
| 470 video_frame_input)); | |
| 466 | 471 |
| 467 // Set up event subscribers. | 472 // Set up event subscribers. |
| 468 // TODO(imcheng): Set up separate subscribers for audio / video / other. | 473 // TODO(imcheng): Set up separate subscribers for audio / video / other. |
| 469 int logging_duration = media::cast::GetLoggingDuration(); | 474 int logging_duration = media::cast::GetLoggingDuration(); |
| 470 scoped_ptr<media::cast::EncodingEventSubscriber> video_event_subscriber; | 475 scoped_ptr<media::cast::EncodingEventSubscriber> video_event_subscriber; |
| 471 scoped_ptr<media::cast::EncodingEventSubscriber> audio_event_subscriber; | 476 scoped_ptr<media::cast::EncodingEventSubscriber> audio_event_subscriber; |
| 472 if (logging_duration > 0) { | 477 if (logging_duration > 0) { |
| 473 std::string log_file_name(media::cast::GetLogFileDestination()); | 478 std::string log_file_name(media::cast::GetLogFileDestination()); |
| 474 video_event_subscriber.reset(new media::cast::EncodingEventSubscriber( | 479 video_event_subscriber.reset(new media::cast::EncodingEventSubscriber( |
| 475 media::cast::VIDEO_EVENT, 10000)); | 480 media::cast::VIDEO_EVENT, 10000)); |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 497 | 502 |
| 498 test_thread.message_loop_proxy()->PostTask( | 503 test_thread.message_loop_proxy()->PostTask( |
| 499 FROM_HERE, | 504 FROM_HERE, |
| 500 base::Bind(&media::cast::SendProcess::SendFrame, | 505 base::Bind(&media::cast::SendProcess::SendFrame, |
| 501 base::Unretained(send_process.get()))); | 506 base::Unretained(send_process.get()))); |
| 502 | 507 |
| 503 io_message_loop.Run(); | 508 io_message_loop.Run(); |
| 504 | 509 |
| 505 return 0; | 510 return 0; |
| 506 } | 511 } |
| OLD | NEW |