mirror of
https://github.com/mollyim/webrtc.git
synced 2025-05-14 06:10:40 +01:00

This reverts commitc4b391a257
. Reason for revert: issue fixed Original change's description: > Revert "NetEQ RTP Play: Optionally write output audio file" > > This reverts commit6330818ec8
. > > Reason for revert: This breaks api/test/neteq_simulator_factory.cc, which unfortunately was not caught by our bots. > > Original change's description: > > NetEQ RTP Play: Optionally write output audio file > > > > This CL makes the output audio file optional to more > > quickly run neteq_rtpplay when no audio output is needed. > > The CL also includes necessary adaptations because of pre-existing > > dependencies (e.g., the output audio file name is used to create > > the plotting script file names). > > > > The command line arguments are retro-compatible - i.e., same behavior > > when specifying the output audio file and the new flag > > --output_files_base_name is not used. > > > > This CL also includes a test script with which the retro-compatibility > > has been verified. > > > > Bug: webrtc:10337 > > Change-Id: Ie3f301b3b2ed0682fb74426d9cf452396f2b112b > > Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/126224 > > Commit-Queue: Alessio Bazzica <alessiob@webrtc.org> > > Reviewed-by: Ivo Creusen <ivoc@webrtc.org> > > Cr-Commit-Position: refs/heads/master@{#27067} > > TBR=henrik.lundin@webrtc.org,alessiob@webrtc.org,ivoc@webrtc.org > > Change-Id: I0c63a8ba9566ef567ee398f571f2a511916fa742 > No-Presubmit: true > No-Tree-Checks: true > No-Try: true > Bug: webrtc:10337 > Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/127293 > Reviewed-by: Ivo Creusen <ivoc@webrtc.org> > Commit-Queue: Ivo Creusen <ivoc@webrtc.org> > Cr-Commit-Position: refs/heads/master@{#27078} TBR=henrik.lundin@webrtc.org,alessiob@webrtc.org,ivoc@webrtc.org Change-Id: Ia7061f7c2d69db61638ad612e82cd429eb49d539 Bug: webrtc:10337 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/127540 Reviewed-by: Ivo Creusen <ivoc@webrtc.org> Reviewed-by: Alessio Bazzica <alessiob@webrtc.org> Commit-Queue: Alessio Bazzica <alessiob@webrtc.org> Cr-Commit-Position: refs/heads/master@{#27106}
384 lines
15 KiB
C++
384 lines
15 KiB
C++
/*
|
|
* Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
|
|
*
|
|
* Use of this source code is governed by a BSD-style license
|
|
* that can be found in the LICENSE file in the root of the source
|
|
* tree. An additional intellectual property rights grant can be found
|
|
* in the file PATENTS. All contributing project authors may
|
|
* be found in the AUTHORS file in the root of the source tree.
|
|
*/
|
|
|
|
#include <iostream>
|
|
#include <string>
|
|
|
|
#include "absl/strings/string_view.h"
|
|
#include "absl/types/optional.h"
|
|
#include "modules/audio_coding/neteq/tools/neteq_test.h"
|
|
#include "modules/audio_coding/neteq/tools/neteq_test_factory.h"
|
|
#include "rtc_base/flags.h"
|
|
#include "rtc_base/strings/string_builder.h"
|
|
#include "system_wrappers/include/field_trial.h"
|
|
#include "test/field_trial.h"
|
|
|
|
namespace {
|
|
|
|
using TestConfig = webrtc::test::NetEqTestFactory::Config;
|
|
|
|
WEBRTC_DEFINE_bool(codec_map,
|
|
false,
|
|
"Prints the mapping between RTP payload type and "
|
|
"codec");
|
|
WEBRTC_DEFINE_string(
|
|
force_fieldtrials,
|
|
"",
|
|
"Field trials control experimental feature code which can be forced. "
|
|
"E.g. running with --force_fieldtrials=WebRTC-FooFeature/Enable/"
|
|
" will assign the group Enable to field trial WebRTC-FooFeature.");
|
|
WEBRTC_DEFINE_bool(help, false, "Prints this message");
|
|
// Define command line flags.
|
|
WEBRTC_DEFINE_int(pcmu,
|
|
TestConfig::default_pcmu(),
|
|
"RTP payload type for PCM-u");
|
|
WEBRTC_DEFINE_int(pcma,
|
|
TestConfig::default_pcma(),
|
|
"RTP payload type for PCM-a");
|
|
WEBRTC_DEFINE_int(ilbc,
|
|
TestConfig::default_ilbc(),
|
|
"RTP payload type for iLBC");
|
|
WEBRTC_DEFINE_int(isac,
|
|
TestConfig::default_isac(),
|
|
"RTP payload type for iSAC");
|
|
WEBRTC_DEFINE_int(isac_swb,
|
|
TestConfig::default_isac_swb(),
|
|
"RTP payload type for iSAC-swb (32 kHz)");
|
|
WEBRTC_DEFINE_int(opus,
|
|
TestConfig::default_opus(),
|
|
"RTP payload type for Opus");
|
|
WEBRTC_DEFINE_int(pcm16b,
|
|
TestConfig::default_pcm16b(),
|
|
"RTP payload type for PCM16b-nb (8 kHz)");
|
|
WEBRTC_DEFINE_int(pcm16b_wb,
|
|
TestConfig::default_pcm16b_wb(),
|
|
"RTP payload type for PCM16b-wb (16 kHz)");
|
|
WEBRTC_DEFINE_int(pcm16b_swb32,
|
|
TestConfig::default_pcm16b_swb32(),
|
|
"RTP payload type for PCM16b-swb32 (32 kHz)");
|
|
WEBRTC_DEFINE_int(pcm16b_swb48,
|
|
TestConfig::default_pcm16b_swb48(),
|
|
"RTP payload type for PCM16b-swb48 (48 kHz)");
|
|
WEBRTC_DEFINE_int(g722,
|
|
TestConfig::default_g722(),
|
|
"RTP payload type for G.722");
|
|
WEBRTC_DEFINE_int(avt,
|
|
TestConfig::default_avt(),
|
|
"RTP payload type for AVT/DTMF (8 kHz)");
|
|
WEBRTC_DEFINE_int(avt_16,
|
|
TestConfig::default_avt_16(),
|
|
"RTP payload type for AVT/DTMF (16 kHz)");
|
|
WEBRTC_DEFINE_int(avt_32,
|
|
TestConfig::default_avt_32(),
|
|
"RTP payload type for AVT/DTMF (32 kHz)");
|
|
WEBRTC_DEFINE_int(avt_48,
|
|
TestConfig::default_avt_48(),
|
|
"RTP payload type for AVT/DTMF (48 kHz)");
|
|
WEBRTC_DEFINE_int(red,
|
|
TestConfig::default_red(),
|
|
"RTP payload type for redundant audio (RED)");
|
|
WEBRTC_DEFINE_int(cn_nb,
|
|
TestConfig::default_cn_nb(),
|
|
"RTP payload type for comfort noise (8 kHz)");
|
|
WEBRTC_DEFINE_int(cn_wb,
|
|
TestConfig::default_cn_wb(),
|
|
"RTP payload type for comfort noise (16 kHz)");
|
|
WEBRTC_DEFINE_int(cn_swb32,
|
|
TestConfig::default_cn_swb32(),
|
|
"RTP payload type for comfort noise (32 kHz)");
|
|
WEBRTC_DEFINE_int(cn_swb48,
|
|
TestConfig::default_cn_swb48(),
|
|
"RTP payload type for comfort noise (48 kHz)");
|
|
WEBRTC_DEFINE_string(replacement_audio_file,
|
|
"",
|
|
"A PCM file that will be used to populate dummy"
|
|
" RTP packets");
|
|
WEBRTC_DEFINE_string(
|
|
ssrc,
|
|
"",
|
|
"Only use packets with this SSRC (decimal or hex, the latter "
|
|
"starting with 0x)");
|
|
WEBRTC_DEFINE_int(audio_level,
|
|
TestConfig::default_audio_level(),
|
|
"Extension ID for audio level (RFC 6464)");
|
|
WEBRTC_DEFINE_int(abs_send_time,
|
|
TestConfig::default_abs_send_time(),
|
|
"Extension ID for absolute sender time");
|
|
WEBRTC_DEFINE_int(transport_seq_no,
|
|
TestConfig::default_transport_seq_no(),
|
|
"Extension ID for transport sequence number");
|
|
WEBRTC_DEFINE_int(video_content_type,
|
|
TestConfig::default_video_content_type(),
|
|
"Extension ID for video content type");
|
|
WEBRTC_DEFINE_int(video_timing,
|
|
TestConfig::default_video_timing(),
|
|
"Extension ID for video timing");
|
|
WEBRTC_DEFINE_string(output_files_base_name,
|
|
"",
|
|
"Custom path used as prefix for the output files - i.e., "
|
|
"matlab plot, python plot, text log.");
|
|
WEBRTC_DEFINE_bool(matlabplot,
|
|
false,
|
|
"Generates a matlab script for plotting the delay profile");
|
|
WEBRTC_DEFINE_bool(pythonplot,
|
|
false,
|
|
"Generates a python script for plotting the delay profile");
|
|
WEBRTC_DEFINE_bool(textlog,
|
|
false,
|
|
"Generates a text log describing the simulation on a "
|
|
"step-by-step basis.");
|
|
WEBRTC_DEFINE_bool(concealment_events, false, "Prints concealment events");
|
|
WEBRTC_DEFINE_int(max_nr_packets_in_buffer,
|
|
TestConfig::default_max_nr_packets_in_buffer(),
|
|
"Maximum allowed number of packets in the buffer");
|
|
WEBRTC_DEFINE_bool(enable_fast_accelerate,
|
|
false,
|
|
"Enables jitter buffer fast accelerate");
|
|
|
|
// Parses the input string for a valid SSRC (at the start of the string). If a
|
|
// valid SSRC is found, it is written to the output variable |ssrc|, and true is
|
|
// returned. Otherwise, false is returned.
|
|
bool ParseSsrc(const std::string& str, uint32_t* ssrc) {
|
|
if (str.empty())
|
|
return true;
|
|
int base = 10;
|
|
// Look for "0x" or "0X" at the start and change base to 16 if found.
|
|
if ((str.compare(0, 2, "0x") == 0) || (str.compare(0, 2, "0X") == 0))
|
|
base = 16;
|
|
errno = 0;
|
|
char* end_ptr;
|
|
unsigned long value = strtoul(str.c_str(), &end_ptr, base); // NOLINT
|
|
if (value == ULONG_MAX && errno == ERANGE)
|
|
return false; // Value out of range for unsigned long.
|
|
if (sizeof(unsigned long) > sizeof(uint32_t) && value > 0xFFFFFFFF) // NOLINT
|
|
return false; // Value out of range for uint32_t.
|
|
if (end_ptr - str.c_str() < static_cast<ptrdiff_t>(str.length()))
|
|
return false; // Part of the string was not parsed.
|
|
*ssrc = static_cast<uint32_t>(value);
|
|
return true;
|
|
}
|
|
|
|
static bool ValidateExtensionId(int value) {
|
|
if (value > 0 && value <= 255) // Value is ok.
|
|
return true;
|
|
printf("Extension ID must be between 1 and 255, not %d\n",
|
|
static_cast<int>(value));
|
|
return false;
|
|
}
|
|
|
|
// Flag validators.
|
|
bool ValidatePayloadType(int value) {
|
|
if (value >= 0 && value <= 127) // Value is ok.
|
|
return true;
|
|
printf("Payload type must be between 0 and 127, not %d\n",
|
|
static_cast<int>(value));
|
|
return false;
|
|
}
|
|
|
|
bool ValidateSsrcValue(const std::string& str) {
|
|
uint32_t dummy_ssrc;
|
|
if (ParseSsrc(str, &dummy_ssrc)) // Value is ok.
|
|
return true;
|
|
printf("Invalid SSRC: %s\n", str.c_str());
|
|
return false;
|
|
}
|
|
|
|
void PrintCodecMappingEntry(const char* codec, int flag) {
|
|
std::cout << codec << ": " << flag << std::endl;
|
|
}
|
|
|
|
void PrintCodecMapping() {
|
|
PrintCodecMappingEntry("PCM-u", FLAG_pcmu);
|
|
PrintCodecMappingEntry("PCM-a", FLAG_pcma);
|
|
PrintCodecMappingEntry("iLBC", FLAG_ilbc);
|
|
PrintCodecMappingEntry("iSAC", FLAG_isac);
|
|
PrintCodecMappingEntry("iSAC-swb (32 kHz)", FLAG_isac_swb);
|
|
PrintCodecMappingEntry("Opus", FLAG_opus);
|
|
PrintCodecMappingEntry("PCM16b-nb (8 kHz)", FLAG_pcm16b);
|
|
PrintCodecMappingEntry("PCM16b-wb (16 kHz)", FLAG_pcm16b_wb);
|
|
PrintCodecMappingEntry("PCM16b-swb32 (32 kHz)", FLAG_pcm16b_swb32);
|
|
PrintCodecMappingEntry("PCM16b-swb48 (48 kHz)", FLAG_pcm16b_swb48);
|
|
PrintCodecMappingEntry("G.722", FLAG_g722);
|
|
PrintCodecMappingEntry("AVT/DTMF (8 kHz)", FLAG_avt);
|
|
PrintCodecMappingEntry("AVT/DTMF (16 kHz)", FLAG_avt_16);
|
|
PrintCodecMappingEntry("AVT/DTMF (32 kHz)", FLAG_avt_32);
|
|
PrintCodecMappingEntry("AVT/DTMF (48 kHz)", FLAG_avt_48);
|
|
PrintCodecMappingEntry("redundant audio (RED)", FLAG_red);
|
|
PrintCodecMappingEntry("comfort noise (8 kHz)", FLAG_cn_nb);
|
|
PrintCodecMappingEntry("comfort noise (16 kHz)", FLAG_cn_wb);
|
|
PrintCodecMappingEntry("comfort noise (32 kHz)", FLAG_cn_swb32);
|
|
PrintCodecMappingEntry("comfort noise (48 kHz)", FLAG_cn_swb48);
|
|
}
|
|
|
|
bool ValidateOutputFilesOptions(bool textlog,
|
|
bool plotting,
|
|
absl::string_view output_files_base_name,
|
|
absl::string_view output_audio_filename) {
|
|
bool output_files_base_name_specified = !output_files_base_name.empty();
|
|
if (!textlog && !plotting && output_files_base_name_specified) {
|
|
std::cout << "Error: --output_files_base_name cannot be used without at "
|
|
<< "least one of the following flags: --textlog, --matlabplot, "
|
|
<< "--pythonplot." << std::endl;
|
|
return false;
|
|
}
|
|
// Without |output_audio_filename|, |output_files_base_name| is required when
|
|
// one or more output files must be generated (in order to form a valid output
|
|
// file name).
|
|
if (output_audio_filename.empty() && (textlog || plotting) &&
|
|
!output_files_base_name_specified) {
|
|
std::cout << "Error: when no output audio file is specified and --textlog, "
|
|
<< "--matlabplot and/or --pythonplot are used, "
|
|
<< "--output_files_base_name must be also used." << std::endl;
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
absl::optional<std::string> CreateOptionalOutputFileName(
|
|
bool output_requested,
|
|
absl::string_view basename,
|
|
absl::string_view output_audio_filename,
|
|
absl::string_view suffix) {
|
|
if (!output_requested) {
|
|
return absl::nullopt;
|
|
}
|
|
if (!basename.empty()) {
|
|
// Override the automatic assignment.
|
|
rtc::StringBuilder sb(basename);
|
|
sb << suffix;
|
|
return sb.str();
|
|
}
|
|
if (!output_audio_filename.empty()) {
|
|
// Automatically assign name.
|
|
rtc::StringBuilder sb(output_audio_filename);
|
|
sb << suffix;
|
|
return sb.str();
|
|
}
|
|
std::cout << "Error: invalid text log file parameters.";
|
|
return absl::nullopt;
|
|
}
|
|
|
|
} // namespace
|
|
|
|
int main(int argc, char* argv[]) {
|
|
webrtc::test::NetEqTestFactory factory;
|
|
std::string program_name = argv[0];
|
|
std::string usage =
|
|
"Tool for decoding an RTP dump file using NetEq.\n"
|
|
"Run " +
|
|
program_name +
|
|
" --help for usage.\n"
|
|
"Example usage:\n" +
|
|
program_name + " input.rtp [output.{pcm, wav}]\n";
|
|
if (rtc::FlagList::SetFlagsFromCommandLine(&argc, argv, true)) {
|
|
exit(1);
|
|
}
|
|
if (FLAG_help) {
|
|
std::cout << usage;
|
|
rtc::FlagList::Print(nullptr, false);
|
|
exit(0);
|
|
}
|
|
if (FLAG_codec_map) {
|
|
PrintCodecMapping();
|
|
exit(0);
|
|
}
|
|
if (argc < 2 || argc > 3) { // The output audio file is optional.
|
|
// Print usage information.
|
|
std::cout << usage;
|
|
exit(0);
|
|
}
|
|
const std::string output_audio_filename((argc == 3) ? argv[2] : "");
|
|
const std::string output_files_base_name(FLAG_output_files_base_name);
|
|
RTC_CHECK(ValidateOutputFilesOptions(
|
|
FLAG_textlog, FLAG_matlabplot || FLAG_pythonplot, output_files_base_name,
|
|
output_audio_filename));
|
|
RTC_CHECK(ValidatePayloadType(FLAG_pcmu));
|
|
RTC_CHECK(ValidatePayloadType(FLAG_pcma));
|
|
RTC_CHECK(ValidatePayloadType(FLAG_ilbc));
|
|
RTC_CHECK(ValidatePayloadType(FLAG_isac));
|
|
RTC_CHECK(ValidatePayloadType(FLAG_isac_swb));
|
|
RTC_CHECK(ValidatePayloadType(FLAG_opus));
|
|
RTC_CHECK(ValidatePayloadType(FLAG_pcm16b));
|
|
RTC_CHECK(ValidatePayloadType(FLAG_pcm16b_wb));
|
|
RTC_CHECK(ValidatePayloadType(FLAG_pcm16b_swb32));
|
|
RTC_CHECK(ValidatePayloadType(FLAG_pcm16b_swb48));
|
|
RTC_CHECK(ValidatePayloadType(FLAG_g722));
|
|
RTC_CHECK(ValidatePayloadType(FLAG_avt));
|
|
RTC_CHECK(ValidatePayloadType(FLAG_avt_16));
|
|
RTC_CHECK(ValidatePayloadType(FLAG_avt_32));
|
|
RTC_CHECK(ValidatePayloadType(FLAG_avt_48));
|
|
RTC_CHECK(ValidatePayloadType(FLAG_red));
|
|
RTC_CHECK(ValidatePayloadType(FLAG_cn_nb));
|
|
RTC_CHECK(ValidatePayloadType(FLAG_cn_wb));
|
|
RTC_CHECK(ValidatePayloadType(FLAG_cn_swb32));
|
|
RTC_CHECK(ValidatePayloadType(FLAG_cn_swb48));
|
|
RTC_CHECK(ValidateSsrcValue(FLAG_ssrc));
|
|
RTC_CHECK(ValidateExtensionId(FLAG_audio_level));
|
|
RTC_CHECK(ValidateExtensionId(FLAG_abs_send_time));
|
|
RTC_CHECK(ValidateExtensionId(FLAG_transport_seq_no));
|
|
RTC_CHECK(ValidateExtensionId(FLAG_video_content_type));
|
|
RTC_CHECK(ValidateExtensionId(FLAG_video_timing));
|
|
|
|
webrtc::test::ValidateFieldTrialsStringOrDie(FLAG_force_fieldtrials);
|
|
webrtc::field_trial::InitFieldTrialsFromString(FLAG_force_fieldtrials);
|
|
webrtc::test::NetEqTestFactory::Config config;
|
|
config.pcmu = FLAG_pcmu;
|
|
config.pcma = FLAG_pcma;
|
|
config.ilbc = FLAG_ilbc;
|
|
config.isac = FLAG_isac;
|
|
config.isac_swb = FLAG_isac_swb;
|
|
config.opus = FLAG_opus;
|
|
config.pcm16b = FLAG_pcm16b;
|
|
config.pcm16b_wb = FLAG_pcm16b_wb;
|
|
config.pcm16b_swb32 = FLAG_pcm16b_swb32;
|
|
config.pcm16b_swb48 = FLAG_pcm16b_swb48;
|
|
config.g722 = FLAG_g722;
|
|
config.avt = FLAG_avt;
|
|
config.avt_16 = FLAG_avt_16;
|
|
config.avt_32 = FLAG_avt_32;
|
|
config.avt_48 = FLAG_avt_48;
|
|
config.red = FLAG_red;
|
|
config.cn_nb = FLAG_cn_nb;
|
|
config.cn_wb = FLAG_cn_wb;
|
|
config.cn_swb32 = FLAG_cn_swb32;
|
|
config.cn_swb48 = FLAG_cn_swb48;
|
|
config.replacement_audio_file = FLAG_replacement_audio_file;
|
|
config.audio_level = FLAG_audio_level;
|
|
config.abs_send_time = FLAG_abs_send_time;
|
|
config.transport_seq_no = FLAG_transport_seq_no;
|
|
config.video_content_type = FLAG_video_content_type;
|
|
config.video_timing = FLAG_video_timing;
|
|
config.matlabplot = FLAG_matlabplot;
|
|
config.pythonplot = FLAG_pythonplot;
|
|
config.concealment_events = FLAG_concealment_events;
|
|
config.max_nr_packets_in_buffer = FLAG_max_nr_packets_in_buffer;
|
|
config.enable_fast_accelerate = FLAG_enable_fast_accelerate;
|
|
if (!output_audio_filename.empty()) {
|
|
config.output_audio_filename = output_audio_filename;
|
|
}
|
|
config.textlog_filename =
|
|
CreateOptionalOutputFileName(FLAG_textlog, output_files_base_name,
|
|
output_audio_filename, ".text_log.txt");
|
|
config.plot_scripts_basename = CreateOptionalOutputFileName(
|
|
FLAG_matlabplot || FLAG_pythonplot, output_files_base_name,
|
|
output_audio_filename, "");
|
|
|
|
// Check if an SSRC value was provided.
|
|
if (strlen(FLAG_ssrc) > 0) {
|
|
uint32_t ssrc;
|
|
RTC_CHECK(ParseSsrc(FLAG_ssrc, &ssrc)) << "Flag verification has failed.";
|
|
config.ssrc_filter = absl::make_optional(ssrc);
|
|
}
|
|
|
|
std::unique_ptr<webrtc::test::NetEqTest> test = factory.InitializeTest(
|
|
/*input_filename=*/argv[1], config);
|
|
test->Run();
|
|
return 0;
|
|
}
|