OLD | NEW |
---|---|
1 /* | 1 /* |
2 * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. | 2 * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license | 4 * Use of this source code is governed by a BSD-style license |
5 * that can be found in the LICENSE file in the root of the source | 5 * that can be found in the LICENSE file in the root of the source |
6 * tree. An additional intellectual property rights grant can be found | 6 * tree. An additional intellectual property rights grant can be found |
7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
9 */ | 9 */ |
10 | 10 |
11 // TODO(hlundin): The functionality in this file should be moved into one or | 11 // TODO(hlundin): The functionality in this file should be moved into one or |
12 // several classes. | 12 // several classes. |
13 | 13 |
14 #include <assert.h> | 14 #include <assert.h> |
15 #include <errno.h> | 15 #include <errno.h> |
16 #include <limits.h> // For ULONG_MAX returned by strtoul. | 16 #include <limits.h> // For ULONG_MAX returned by strtoul. |
17 #include <stdio.h> | 17 #include <stdio.h> |
18 #include <stdlib.h> // For strtoul. | 18 #include <stdlib.h> // For strtoul. |
19 | 19 |
20 #include <algorithm> | 20 #include <algorithm> |
21 #include <iostream> | 21 #include <iostream> |
22 #include <limits> | |
22 #include <string> | 23 #include <string> |
23 | 24 |
24 #include "google/gflags.h" | 25 #include "google/gflags.h" |
25 #include "webrtc/base/checks.h" | 26 #include "webrtc/base/checks.h" |
27 #include "webrtc/base/safe_conversions.h" | |
26 #include "webrtc/base/scoped_ptr.h" | 28 #include "webrtc/base/scoped_ptr.h" |
27 #include "webrtc/modules/audio_coding/codecs/pcm16b/include/pcm16b.h" | 29 #include "webrtc/modules/audio_coding/codecs/pcm16b/include/pcm16b.h" |
28 #include "webrtc/modules/audio_coding/neteq/interface/neteq.h" | 30 #include "webrtc/modules/audio_coding/neteq/interface/neteq.h" |
29 #include "webrtc/modules/audio_coding/neteq/tools/input_audio_file.h" | 31 #include "webrtc/modules/audio_coding/neteq/tools/input_audio_file.h" |
30 #include "webrtc/modules/audio_coding/neteq/tools/output_audio_file.h" | 32 #include "webrtc/modules/audio_coding/neteq/tools/output_audio_file.h" |
31 #include "webrtc/modules/audio_coding/neteq/tools/output_wav_file.h" | 33 #include "webrtc/modules/audio_coding/neteq/tools/output_wav_file.h" |
32 #include "webrtc/modules/audio_coding/neteq/tools/packet.h" | 34 #include "webrtc/modules/audio_coding/neteq/tools/packet.h" |
35 #include "webrtc/modules/audio_coding/neteq/tools/rtc_event_log_source.h" | |
33 #include "webrtc/modules/audio_coding/neteq/tools/rtp_file_source.h" | 36 #include "webrtc/modules/audio_coding/neteq/tools/rtp_file_source.h" |
34 #include "webrtc/modules/interface/module_common_types.h" | 37 #include "webrtc/modules/interface/module_common_types.h" |
35 #include "webrtc/system_wrappers/interface/trace.h" | 38 #include "webrtc/system_wrappers/interface/trace.h" |
39 #include "webrtc/test/rtp_file_reader.h" | |
36 #include "webrtc/test/testsupport/fileutils.h" | 40 #include "webrtc/test/testsupport/fileutils.h" |
37 #include "webrtc/typedefs.h" | 41 #include "webrtc/typedefs.h" |
38 | 42 |
39 using webrtc::NetEq; | 43 using webrtc::NetEq; |
40 using webrtc::WebRtcRTPHeader; | 44 using webrtc::WebRtcRTPHeader; |
41 | 45 |
42 namespace { | 46 namespace { |
43 | 47 |
44 // Parses the input string for a valid SSRC (at the start of the string). If a | 48 // Parses the input string for a valid SSRC (at the start of the string). If a |
45 // valid SSRC is found, it is written to the output variable |ssrc|, and true is | 49 // valid SSRC is found, it is written to the output variable |ssrc|, and true is |
(...skipping 331 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
377 if (FLAGS_codec_map) { | 381 if (FLAGS_codec_map) { |
378 // We have already printed the codec map. Just end the program. | 382 // We have already printed the codec map. Just end the program. |
379 return 0; | 383 return 0; |
380 } | 384 } |
381 // Print usage information. | 385 // Print usage information. |
382 std::cout << google::ProgramUsage(); | 386 std::cout << google::ProgramUsage(); |
383 return 0; | 387 return 0; |
384 } | 388 } |
385 | 389 |
386 printf("Input file: %s\n", argv[1]); | 390 printf("Input file: %s\n", argv[1]); |
387 rtc::scoped_ptr<webrtc::test::RtpFileSource> file_source( | 391 |
388 webrtc::test::RtpFileSource::Create(argv[1])); | 392 // TODO(ivoc): Modify the RtpFileSource::Create and RtcEventLogSource::Create |
393 // functions to return a nullptr on failure instead of crashing | |
394 // the program. | |
395 | |
396 // This temporary solution uses a RtpFileReader directly to check if the file | |
397 // is a valid RtpDump file. | |
398 bool is_rtp_dump = false; | |
399 { | |
400 rtc::scoped_ptr<webrtc::test::RtpFileReader> rtp_reader( | |
401 webrtc::test::RtpFileReader::Create( | |
402 webrtc::test::RtpFileReader::kRtpDump, argv[1])); | |
403 if (rtp_reader) | |
404 is_rtp_dump = true; | |
405 } | |
406 rtc::scoped_ptr<webrtc::test::PacketSource> file_source; | |
407 webrtc::test::RtcEventLogSource* event_log_source = nullptr; | |
408 if (is_rtp_dump) { | |
409 file_source.reset(webrtc::test::RtpFileSource::Create(argv[1])); | |
410 } else { | |
411 event_log_source = webrtc::test::RtcEventLogSource::Create(argv[1]); | |
412 file_source.reset(event_log_source); | |
413 } | |
414 | |
389 assert(file_source.get()); | 415 assert(file_source.get()); |
390 | 416 |
391 // Check if an SSRC value was provided. | 417 // Check if an SSRC value was provided. |
392 if (!FLAGS_ssrc.empty()) { | 418 if (!FLAGS_ssrc.empty()) { |
393 uint32_t ssrc; | 419 uint32_t ssrc; |
394 CHECK(ParseSsrc(FLAGS_ssrc, &ssrc)) << "Flag verification has failed."; | 420 CHECK(ParseSsrc(FLAGS_ssrc, &ssrc)) << "Flag verification has failed."; |
395 file_source->SelectSsrc(ssrc); | 421 file_source->SelectSsrc(ssrc); |
396 } | 422 } |
397 | 423 |
398 // Check if a replacement audio file was provided, and if so, open it. | 424 // Check if a replacement audio file was provided, and if so, open it. |
399 bool replace_payload = false; | 425 bool replace_payload = false; |
400 rtc::scoped_ptr<webrtc::test::InputAudioFile> replacement_audio_file; | 426 rtc::scoped_ptr<webrtc::test::InputAudioFile> replacement_audio_file; |
401 if (!FLAGS_replacement_audio_file.empty()) { | 427 if (!FLAGS_replacement_audio_file.empty()) { |
402 replacement_audio_file.reset( | 428 replacement_audio_file.reset( |
403 new webrtc::test::InputAudioFile(FLAGS_replacement_audio_file)); | 429 new webrtc::test::InputAudioFile(FLAGS_replacement_audio_file)); |
404 replace_payload = true; | 430 replace_payload = true; |
405 } | 431 } |
406 | 432 |
407 // Read first packet. | 433 // Read first packet. |
408 rtc::scoped_ptr<webrtc::test::Packet> packet(file_source->NextPacket()); | 434 rtc::scoped_ptr<webrtc::test::Packet> packet(file_source->NextPacket()); |
409 if (!packet) { | 435 if (!packet) { |
410 printf( | 436 printf( |
411 "Warning: input file is empty, or the filters did not match any " | 437 "Warning: input file is empty, or the filters did not match any " |
412 "packets\n"); | 438 "packets\n"); |
413 webrtc::Trace::ReturnTrace(); | 439 webrtc::Trace::ReturnTrace(); |
414 return 0; | 440 return 0; |
415 } | 441 } |
416 bool packet_available = true; | 442 if (packet->payload_length_bytes() == 0 && !replace_payload) { |
443 std::cerr << "Warning: input file contains header-only packets, but no " | |
444 << "replacement file is specified." << std::endl; | |
445 webrtc::Trace::ReturnTrace(); | |
446 return -1; | |
447 } | |
417 | 448 |
418 // Check the sample rate. | 449 // Check the sample rate. |
419 int sample_rate_hz = CodecSampleRate(packet->header().payloadType); | 450 int sample_rate_hz = CodecSampleRate(packet->header().payloadType); |
420 if (sample_rate_hz <= 0) { | 451 if (sample_rate_hz <= 0) { |
421 printf("Warning: Invalid sample rate from RTP packet.\n"); | 452 printf("Warning: Invalid sample rate from RTP packet.\n"); |
422 webrtc::Trace::ReturnTrace(); | 453 webrtc::Trace::ReturnTrace(); |
423 return 0; | 454 return 0; |
424 } | 455 } |
425 | 456 |
426 // Open the output file now that we know the sample rate. (Rate is only needed | 457 // Open the output file now that we know the sample rate. (Rate is only needed |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
468 replacement_audio.reset(new int16_t[input_frame_size_timestamps]); | 499 replacement_audio.reset(new int16_t[input_frame_size_timestamps]); |
469 payload_mem_size_bytes = 2 * input_frame_size_timestamps; | 500 payload_mem_size_bytes = 2 * input_frame_size_timestamps; |
470 payload.reset(new uint8_t[payload_mem_size_bytes]); | 501 payload.reset(new uint8_t[payload_mem_size_bytes]); |
471 next_packet.reset(file_source->NextPacket()); | 502 next_packet.reset(file_source->NextPacket()); |
472 assert(next_packet); | 503 assert(next_packet); |
473 next_packet_available = true; | 504 next_packet_available = true; |
474 } | 505 } |
475 | 506 |
476 // This is the main simulation loop. | 507 // This is the main simulation loop. |
477 // Set the simulation clock to start immediately with the first packet. | 508 // Set the simulation clock to start immediately with the first packet. |
478 int start_time_ms = packet->time_ms(); | 509 int64_t start_time_ms = rtc::checked_cast<int64_t>(packet->time_ms()); |
479 int time_now_ms = packet->time_ms(); | 510 int64_t time_now_ms = start_time_ms; |
480 int next_input_time_ms = time_now_ms; | 511 int64_t next_input_time_ms = time_now_ms; |
481 int next_output_time_ms = time_now_ms; | 512 int64_t next_output_time_ms = time_now_ms; |
482 if (time_now_ms % kOutputBlockSizeMs != 0) { | 513 if (time_now_ms % kOutputBlockSizeMs != 0) { |
483 // Make sure that next_output_time_ms is rounded up to the next multiple | 514 // Make sure that next_output_time_ms is rounded up to the next multiple |
484 // of kOutputBlockSizeMs. (Legacy bit-exactness.) | 515 // of kOutputBlockSizeMs. (Legacy bit-exactness.) |
485 next_output_time_ms += | 516 next_output_time_ms += |
486 kOutputBlockSizeMs - time_now_ms % kOutputBlockSizeMs; | 517 kOutputBlockSizeMs - time_now_ms % kOutputBlockSizeMs; |
487 } | 518 } |
488 while (packet_available) { | 519 |
520 bool packet_available = true; | |
521 bool output_event_available = true; | |
522 if (!is_rtp_dump) { | |
523 next_output_time_ms = event_log_source->NextAudioOutputEventMs(); | |
524 if (next_output_time_ms == std::numeric_limits<int64_t>::max()) | |
525 output_event_available = false; | |
526 start_time_ms = time_now_ms = | |
527 std::min(next_input_time_ms, next_output_time_ms); | |
528 } | |
529 while (packet_available || output_event_available) { | |
530 // Advance time to next event. | |
531 time_now_ms = std::min(next_input_time_ms, next_output_time_ms); | |
489 // Check if it is time to insert packet. | 532 // Check if it is time to insert packet. |
490 while (time_now_ms >= next_input_time_ms && packet_available) { | 533 while (time_now_ms >= next_input_time_ms && packet_available) { |
491 assert(packet->virtual_payload_length_bytes() > 0); | 534 assert(packet->virtual_payload_length_bytes() > 0); |
492 // Parse RTP header. | 535 // Parse RTP header. |
493 WebRtcRTPHeader rtp_header; | 536 WebRtcRTPHeader rtp_header; |
494 packet->ConvertHeader(&rtp_header); | 537 packet->ConvertHeader(&rtp_header); |
495 const uint8_t* payload_ptr = packet->payload(); | 538 const uint8_t* payload_ptr = packet->payload(); |
496 size_t payload_len = packet->payload_length_bytes(); | 539 size_t payload_len = packet->payload_length_bytes(); |
497 if (replace_payload) { | 540 if (replace_payload) { |
498 payload_len = ReplacePayload(replacement_audio_file.get(), | 541 payload_len = ReplacePayload(replacement_audio_file.get(), |
499 &replacement_audio, | 542 &replacement_audio, |
500 &payload, | 543 &payload, |
501 &payload_mem_size_bytes, | 544 &payload_mem_size_bytes, |
502 &input_frame_size_timestamps, | 545 &input_frame_size_timestamps, |
503 &rtp_header, | 546 &rtp_header, |
504 next_packet.get()); | 547 next_packet.get()); |
505 payload_ptr = payload.get(); | 548 payload_ptr = payload.get(); |
506 } | 549 } |
507 int error = | 550 int error = |
508 neteq->InsertPacket(rtp_header, | 551 neteq->InsertPacket(rtp_header, |
509 payload_ptr, | 552 payload_ptr, |
510 payload_len, | 553 payload_len, |
511 packet->time_ms() * sample_rate_hz / 1000); | 554 rtc::checked_cast<uint32_t>( |
hlundin-webrtc
2015/09/07 11:46:57
I don't think you want the checked_cast here, just
| |
555 packet->time_ms() * sample_rate_hz / 1000)); | |
512 if (error != NetEq::kOK) { | 556 if (error != NetEq::kOK) { |
513 if (neteq->LastError() == NetEq::kUnknownRtpPayloadType) { | 557 if (neteq->LastError() == NetEq::kUnknownRtpPayloadType) { |
514 std::cerr << "RTP Payload type " | 558 std::cerr << "RTP Payload type " |
515 << static_cast<int>(rtp_header.header.payloadType) | 559 << static_cast<int>(rtp_header.header.payloadType) |
516 << " is unknown." << std::endl; | 560 << " is unknown." << std::endl; |
517 std::cerr << "Use --codec_map to view default mapping." << std::endl; | 561 std::cerr << "Use --codec_map to view default mapping." << std::endl; |
518 std::cerr << "Use --helpshort for information on how to make custom " | 562 std::cerr << "Use --helpshort for information on how to make custom " |
519 "mappings." << std::endl; | 563 "mappings." << std::endl; |
520 } else { | 564 } else { |
521 std::cerr << "InsertPacket returned error code " << neteq->LastError() | 565 std::cerr << "InsertPacket returned error code " << neteq->LastError() |
522 << std::endl; | 566 << std::endl; |
523 std::cerr << "Header data:" << std::endl; | 567 std::cerr << "Header data:" << std::endl; |
524 std::cerr << " PT = " | 568 std::cerr << " PT = " |
525 << static_cast<int>(rtp_header.header.payloadType) | 569 << static_cast<int>(rtp_header.header.payloadType) |
526 << std::endl; | 570 << std::endl; |
527 std::cerr << " SN = " << rtp_header.header.sequenceNumber | 571 std::cerr << " SN = " << rtp_header.header.sequenceNumber |
528 << std::endl; | 572 << std::endl; |
529 std::cerr << " TS = " << rtp_header.header.timestamp << std::endl; | 573 std::cerr << " TS = " << rtp_header.header.timestamp << std::endl; |
530 } | 574 } |
531 } | 575 } |
532 | 576 |
533 // Get next packet from file. | 577 // Get next packet from file. |
534 webrtc::test::Packet* temp_packet = file_source->NextPacket(); | 578 webrtc::test::Packet* temp_packet = file_source->NextPacket(); |
535 if (temp_packet) { | 579 if (temp_packet) { |
536 packet.reset(temp_packet); | 580 packet.reset(temp_packet); |
581 if (replace_payload) { | |
582 // At this point |packet| contains the packet *after* |next_packet|. | |
583 // Swap Packet objects between |packet| and |next_packet|. | |
584 packet.swap(next_packet); | |
585 // Swap the status indicators unless they're already the same. | |
586 if (packet_available != next_packet_available) { | |
587 packet_available = !packet_available; | |
588 next_packet_available = !next_packet_available; | |
589 } | |
590 } | |
591 next_input_time_ms = rtc::checked_cast<int64_t>(packet->time_ms()); | |
537 } else { | 592 } else { |
593 // Set next input time to the maximum value of int64_t to prevent the | |
594 // time_now_ms from becoming stuck at the final value. | |
595 next_input_time_ms = std::numeric_limits<int64_t>::max(); | |
538 packet_available = false; | 596 packet_available = false; |
539 } | 597 } |
540 if (replace_payload) { | |
541 // At this point |packet| contains the packet *after* |next_packet|. | |
542 // Swap Packet objects between |packet| and |next_packet|. | |
543 packet.swap(next_packet); | |
544 // Swap the status indicators unless they're already the same. | |
545 if (packet_available != next_packet_available) { | |
546 packet_available = !packet_available; | |
547 next_packet_available = !next_packet_available; | |
548 } | |
549 } | |
550 next_input_time_ms = packet->time_ms(); | |
551 } | 598 } |
552 | 599 |
553 // Check if it is time to get output audio. | 600 // Check if it is time to get output audio. |
554 if (time_now_ms >= next_output_time_ms) { | 601 while (time_now_ms >= next_output_time_ms && output_event_available) { |
555 static const int kOutDataLen = | 602 static const int kOutDataLen = |
556 kOutputBlockSizeMs * kMaxSamplesPerMs * kMaxChannels; | 603 kOutputBlockSizeMs * kMaxSamplesPerMs * kMaxChannels; |
557 int16_t out_data[kOutDataLen]; | 604 int16_t out_data[kOutDataLen]; |
558 int num_channels; | 605 int num_channels; |
559 int samples_per_channel; | 606 int samples_per_channel; |
560 int error = neteq->GetAudio(kOutDataLen, out_data, &samples_per_channel, | 607 int error = neteq->GetAudio(kOutDataLen, out_data, &samples_per_channel, |
561 &num_channels, NULL); | 608 &num_channels, NULL); |
562 if (error != NetEq::kOK) { | 609 if (error != NetEq::kOK) { |
563 std::cerr << "GetAudio returned error code " << | 610 std::cerr << "GetAudio returned error code " << |
564 neteq->LastError() << std::endl; | 611 neteq->LastError() << std::endl; |
565 } else { | 612 } else { |
566 // Calculate sample rate from output size. | 613 // Calculate sample rate from output size. |
567 sample_rate_hz = 1000 * samples_per_channel / kOutputBlockSizeMs; | 614 sample_rate_hz = 1000 * samples_per_channel / kOutputBlockSizeMs; |
568 } | 615 } |
569 | 616 |
570 // Write to file. | 617 // Write to file. |
571 // TODO(hlundin): Make writing to file optional. | 618 // TODO(hlundin): Make writing to file optional. |
572 size_t write_len = samples_per_channel * num_channels; | 619 size_t write_len = samples_per_channel * num_channels; |
573 if (!output->WriteArray(out_data, write_len)) { | 620 if (!output->WriteArray(out_data, write_len)) { |
574 std::cerr << "Error while writing to file" << std::endl; | 621 std::cerr << "Error while writing to file" << std::endl; |
575 webrtc::Trace::ReturnTrace(); | 622 webrtc::Trace::ReturnTrace(); |
576 exit(1); | 623 exit(1); |
577 } | 624 } |
578 next_output_time_ms += kOutputBlockSizeMs; | 625 if (is_rtp_dump) { |
626 next_output_time_ms += kOutputBlockSizeMs; | |
627 if (!packet_available) | |
628 output_event_available = false; | |
629 } else { | |
630 next_output_time_ms = event_log_source->NextAudioOutputEventMs(); | |
631 if (next_output_time_ms == std::numeric_limits<int64_t>::max()) | |
632 output_event_available = false; | |
633 } | |
579 } | 634 } |
580 // Advance time to next event. | |
581 time_now_ms = std::min(next_input_time_ms, next_output_time_ms); | |
582 } | 635 } |
583 | |
584 printf("Simulation done\n"); | 636 printf("Simulation done\n"); |
585 printf("Produced %i ms of audio\n", time_now_ms - start_time_ms); | 637 printf("Produced %i ms of audio\n", |
638 static_cast<int>(time_now_ms - start_time_ms)); | |
586 | 639 |
587 delete neteq; | 640 delete neteq; |
588 webrtc::Trace::ReturnTrace(); | 641 webrtc::Trace::ReturnTrace(); |
589 return 0; | 642 return 0; |
590 } | 643 } |
OLD | NEW |