|
|
|
@ -21,9 +21,9 @@
|
|
|
|
|
#include "google/gflags.h"
|
|
|
|
|
#include "webrtc/modules/audio_coding/codecs/pcm16b/include/pcm16b.h"
|
|
|
|
|
#include "webrtc/modules/audio_coding/neteq/interface/neteq.h"
|
|
|
|
|
#include "webrtc/modules/audio_coding/neteq/test/NETEQTEST_RTPpacket.h"
|
|
|
|
|
#include "webrtc/modules/audio_coding/neteq/test/NETEQTEST_DummyRTPpacket.h"
|
|
|
|
|
#include "webrtc/modules/audio_coding/neteq/tools/input_audio_file.h"
|
|
|
|
|
#include "webrtc/modules/audio_coding/neteq/tools/packet.h"
|
|
|
|
|
#include "webrtc/modules/audio_coding/neteq/tools/rtp_file_source.h"
|
|
|
|
|
#include "webrtc/modules/interface/module_common_types.h"
|
|
|
|
|
#include "webrtc/system_wrappers/interface/scoped_ptr.h"
|
|
|
|
|
#include "webrtc/system_wrappers/interface/trace.h"
|
|
|
|
@ -92,8 +92,6 @@ static const bool cn_swb48_dummy =
|
|
|
|
|
google::RegisterFlagValidator(&FLAGS_cn_swb48, &ValidatePayloadType);
|
|
|
|
|
DEFINE_bool(codec_map, false, "Prints the mapping between RTP payload type and "
|
|
|
|
|
"codec");
|
|
|
|
|
DEFINE_bool(dummy_rtp, false, "The input file contains ""dummy"" RTP data, "
|
|
|
|
|
"i.e., only headers");
|
|
|
|
|
DEFINE_string(replacement_audio_file, "",
|
|
|
|
|
"A PCM file that will be used to populate ""dummy"" RTP packets");
|
|
|
|
|
|
|
|
|
@ -107,7 +105,7 @@ size_t ReplacePayload(webrtc::test::InputAudioFile* replacement_audio_file,
|
|
|
|
|
size_t* payload_mem_size_bytes,
|
|
|
|
|
size_t* frame_size_samples,
|
|
|
|
|
WebRtcRTPHeader* rtp_header,
|
|
|
|
|
NETEQTEST_RTPpacket* next_rtp);
|
|
|
|
|
const webrtc::test::Packet* next_packet);
|
|
|
|
|
int CodecSampleRate(uint8_t payload_type);
|
|
|
|
|
int CodecTimestampRate(uint8_t payload_type);
|
|
|
|
|
bool IsComfortNosie(uint8_t payload_type);
|
|
|
|
@ -139,15 +137,13 @@ int main(int argc, char* argv[]) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FILE* in_file = fopen(argv[1], "rb");
|
|
|
|
|
if (!in_file) {
|
|
|
|
|
std::cerr << "Cannot open input file " << argv[1] << std::endl;
|
|
|
|
|
exit(1);
|
|
|
|
|
}
|
|
|
|
|
std::cout << "Input file: " << argv[1] << std::endl;
|
|
|
|
|
printf("Input file: %s\n", argv[1]);
|
|
|
|
|
webrtc::scoped_ptr<webrtc::test::RtpFileSource> file_source(
|
|
|
|
|
webrtc::test::RtpFileSource::Create(argv[1]));
|
|
|
|
|
assert(file_source.get());
|
|
|
|
|
|
|
|
|
|
FILE* out_file = fopen(argv[2], "wb");
|
|
|
|
|
if (!in_file) {
|
|
|
|
|
if (!out_file) {
|
|
|
|
|
std::cerr << "Cannot open output file " << argv[2] << std::endl;
|
|
|
|
|
exit(1);
|
|
|
|
|
}
|
|
|
|
@ -162,12 +158,6 @@ int main(int argc, char* argv[]) {
|
|
|
|
|
replace_payload = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Read RTP file header.
|
|
|
|
|
if (NETEQTEST_RTPpacket::skipFileHeader(in_file) != 0) {
|
|
|
|
|
std::cerr << "Wrong format in RTP file" << std::endl;
|
|
|
|
|
exit(1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Enable tracing.
|
|
|
|
|
webrtc::Trace::CreateTrace();
|
|
|
|
|
webrtc::Trace::SetTraceFile((webrtc::test::OutputPath() +
|
|
|
|
@ -182,25 +172,17 @@ int main(int argc, char* argv[]) {
|
|
|
|
|
RegisterPayloadTypes(neteq);
|
|
|
|
|
|
|
|
|
|
// Read first packet.
|
|
|
|
|
NETEQTEST_RTPpacket* rtp;
|
|
|
|
|
NETEQTEST_RTPpacket* next_rtp = NULL;
|
|
|
|
|
if (!FLAGS_dummy_rtp) {
|
|
|
|
|
rtp = new NETEQTEST_RTPpacket();
|
|
|
|
|
if (replace_payload) {
|
|
|
|
|
next_rtp = new NETEQTEST_RTPpacket();
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
rtp = new NETEQTEST_DummyRTPpacket();
|
|
|
|
|
if (replace_payload) {
|
|
|
|
|
next_rtp = new NETEQTEST_DummyRTPpacket();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
rtp->readFromFile(in_file);
|
|
|
|
|
if (rtp->dataLen() < 0) {
|
|
|
|
|
std::cout << "Warning: RTP file is empty" << std::endl;
|
|
|
|
|
if (file_source->EndOfFile()) {
|
|
|
|
|
printf("Warning: RTP file is empty");
|
|
|
|
|
webrtc::Trace::ReturnTrace();
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
webrtc::scoped_ptr<webrtc::test::Packet> packet(file_source->NextPacket());
|
|
|
|
|
bool packet_available = true;
|
|
|
|
|
|
|
|
|
|
// Set up variables for audio replacement if needed.
|
|
|
|
|
webrtc::scoped_ptr<webrtc::test::Packet> next_packet;
|
|
|
|
|
bool next_packet_available = false;
|
|
|
|
|
size_t input_frame_size_timestamps = 0;
|
|
|
|
|
webrtc::scoped_ptr<int16_t[]> replacement_audio;
|
|
|
|
|
webrtc::scoped_ptr<uint8_t[]> payload;
|
|
|
|
@ -213,13 +195,15 @@ int main(int argc, char* argv[]) {
|
|
|
|
|
replacement_audio.reset(new int16_t[input_frame_size_timestamps]);
|
|
|
|
|
payload_mem_size_bytes = 2 * input_frame_size_timestamps;
|
|
|
|
|
payload.reset(new uint8_t[payload_mem_size_bytes]);
|
|
|
|
|
assert(next_rtp);
|
|
|
|
|
next_rtp->readFromFile(in_file);
|
|
|
|
|
assert(!file_source->EndOfFile());
|
|
|
|
|
next_packet.reset(file_source->NextPacket());
|
|
|
|
|
next_packet_available = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// This is the main simulation loop.
|
|
|
|
|
int time_now_ms = rtp->time(); // Start immediately with the first packet.
|
|
|
|
|
int next_input_time_ms = rtp->time();
|
|
|
|
|
// Set the simulation clock to start immediately with the first packet.
|
|
|
|
|
int time_now_ms = packet->time_ms();
|
|
|
|
|
int next_input_time_ms = time_now_ms;
|
|
|
|
|
int next_output_time_ms = time_now_ms;
|
|
|
|
|
if (time_now_ms % kOutputBlockSizeMs != 0) {
|
|
|
|
|
// Make sure that next_output_time_ms is rounded up to the next multiple
|
|
|
|
@ -227,15 +211,15 @@ int main(int argc, char* argv[]) {
|
|
|
|
|
next_output_time_ms +=
|
|
|
|
|
kOutputBlockSizeMs - time_now_ms % kOutputBlockSizeMs;
|
|
|
|
|
}
|
|
|
|
|
while (rtp->dataLen() >= 0) {
|
|
|
|
|
while (packet_available) {
|
|
|
|
|
// Check if it is time to insert packet.
|
|
|
|
|
while (time_now_ms >= next_input_time_ms && rtp->dataLen() >= 0) {
|
|
|
|
|
if (rtp->dataLen() > 0) {
|
|
|
|
|
while (time_now_ms >= next_input_time_ms && packet_available) {
|
|
|
|
|
assert(packet->virtual_payload_length_bytes() > 0);
|
|
|
|
|
// Parse RTP header.
|
|
|
|
|
WebRtcRTPHeader rtp_header;
|
|
|
|
|
rtp->parseHeader(&rtp_header);
|
|
|
|
|
uint8_t* payload_ptr = rtp->payload();
|
|
|
|
|
size_t payload_len = rtp->payloadLen();
|
|
|
|
|
packet->ConvertHeader(&rtp_header);
|
|
|
|
|
const uint8_t* payload_ptr = packet->payload();
|
|
|
|
|
size_t payload_len = packet->payload_length_bytes();
|
|
|
|
|
if (replace_payload) {
|
|
|
|
|
payload_len = ReplacePayload(replacement_audio_file.get(),
|
|
|
|
|
&replacement_audio,
|
|
|
|
@ -243,27 +227,36 @@ int main(int argc, char* argv[]) {
|
|
|
|
|
&payload_mem_size_bytes,
|
|
|
|
|
&input_frame_size_timestamps,
|
|
|
|
|
&rtp_header,
|
|
|
|
|
next_rtp);
|
|
|
|
|
next_packet.get());
|
|
|
|
|
payload_ptr = payload.get();
|
|
|
|
|
}
|
|
|
|
|
int error = neteq->InsertPacket(rtp_header, payload_ptr,
|
|
|
|
|
int error =
|
|
|
|
|
neteq->InsertPacket(rtp_header,
|
|
|
|
|
payload_ptr,
|
|
|
|
|
static_cast<int>(payload_len),
|
|
|
|
|
rtp->time() * sample_rate_hz / 1000);
|
|
|
|
|
packet->time_ms() * sample_rate_hz / 1000);
|
|
|
|
|
if (error != NetEq::kOK) {
|
|
|
|
|
std::cerr << "InsertPacket returned error code " <<
|
|
|
|
|
neteq->LastError() << std::endl;
|
|
|
|
|
}
|
|
|
|
|
std::cerr << "InsertPacket returned error code " << neteq->LastError()
|
|
|
|
|
<< std::endl;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Get next packet from file.
|
|
|
|
|
rtp->readFromFile(in_file);
|
|
|
|
|
if (replace_payload) {
|
|
|
|
|
// At this point |rtp| contains the packet *after* |next_rtp|.
|
|
|
|
|
// Swap RTP packet objects between |rtp| and |next_rtp|.
|
|
|
|
|
NETEQTEST_RTPpacket* temp_rtp = rtp;
|
|
|
|
|
rtp = next_rtp;
|
|
|
|
|
next_rtp = temp_rtp;
|
|
|
|
|
if (!file_source->EndOfFile()) {
|
|
|
|
|
packet.reset(file_source->NextPacket());
|
|
|
|
|
} else {
|
|
|
|
|
packet_available = false;
|
|
|
|
|
}
|
|
|
|
|
next_input_time_ms = rtp->time();
|
|
|
|
|
if (replace_payload) {
|
|
|
|
|
// At this point |packet| contains the packet *after* |next_packet|.
|
|
|
|
|
// Swap Packet objects between |packet| and |next_packet|.
|
|
|
|
|
packet.swap(next_packet);
|
|
|
|
|
// Swap the status indicators unless they're already the same.
|
|
|
|
|
if (packet_available != next_packet_available) {
|
|
|
|
|
packet_available = !packet_available;
|
|
|
|
|
next_packet_available = !next_packet_available;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
next_input_time_ms = packet->time_ms();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Check if it is time to get output audio.
|
|
|
|
@ -300,10 +293,7 @@ int main(int argc, char* argv[]) {
|
|
|
|
|
|
|
|
|
|
std::cout << "Simulation done" << std::endl;
|
|
|
|
|
|
|
|
|
|
fclose(in_file);
|
|
|
|
|
fclose(out_file);
|
|
|
|
|
delete rtp;
|
|
|
|
|
delete next_rtp;
|
|
|
|
|
delete neteq;
|
|
|
|
|
webrtc::Trace::ReturnTrace();
|
|
|
|
|
return 0;
|
|
|
|
@ -503,7 +493,7 @@ size_t ReplacePayload(webrtc::test::InputAudioFile* replacement_audio_file,
|
|
|
|
|
size_t* payload_mem_size_bytes,
|
|
|
|
|
size_t* frame_size_samples,
|
|
|
|
|
WebRtcRTPHeader* rtp_header,
|
|
|
|
|
NETEQTEST_RTPpacket* next_rtp) {
|
|
|
|
|
const webrtc::test::Packet* next_packet) {
|
|
|
|
|
size_t payload_len = 0;
|
|
|
|
|
// Check for CNG.
|
|
|
|
|
if (IsComfortNosie(rtp_header->header.payloadType)) {
|
|
|
|
@ -515,20 +505,20 @@ size_t ReplacePayload(webrtc::test::InputAudioFile* replacement_audio_file,
|
|
|
|
|
(*payload)[0] = 127; // Max attenuation of CNG.
|
|
|
|
|
payload_len = 1;
|
|
|
|
|
} else {
|
|
|
|
|
if (next_rtp->payloadLen() > 0) {
|
|
|
|
|
assert(next_packet->virtual_payload_length_bytes() > 0);
|
|
|
|
|
// Check if payload length has changed.
|
|
|
|
|
if (next_rtp->sequenceNumber() == rtp_header->header.sequenceNumber + 1) {
|
|
|
|
|
if (next_packet->header().sequenceNumber ==
|
|
|
|
|
rtp_header->header.sequenceNumber + 1) {
|
|
|
|
|
if (*frame_size_samples !=
|
|
|
|
|
next_rtp->timeStamp() - rtp_header->header.timestamp) {
|
|
|
|
|
next_packet->header().timestamp - rtp_header->header.timestamp) {
|
|
|
|
|
*frame_size_samples =
|
|
|
|
|
next_rtp->timeStamp() - rtp_header->header.timestamp;
|
|
|
|
|
next_packet->header().timestamp - rtp_header->header.timestamp;
|
|
|
|
|
(*replacement_audio).reset(
|
|
|
|
|
new int16_t[*frame_size_samples]);
|
|
|
|
|
*payload_mem_size_bytes = 2 * *frame_size_samples;
|
|
|
|
|
(*payload).reset(new uint8_t[*payload_mem_size_bytes]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// Get new speech.
|
|
|
|
|
assert((*replacement_audio).get());
|
|
|
|
|
if (CodecTimestampRate(rtp_header->header.payloadType) !=
|
|
|
|
@ -545,7 +535,7 @@ size_t ReplacePayload(webrtc::test::InputAudioFile* replacement_audio_file,
|
|
|
|
|
assert(*frame_size_samples > 0);
|
|
|
|
|
if (!replacement_audio_file->Read(*frame_size_samples,
|
|
|
|
|
(*replacement_audio).get())) {
|
|
|
|
|
std::cerr << "Could no read replacement audio file." << std::endl;
|
|
|
|
|
std::cerr << "Could not read replacement audio file." << std::endl;
|
|
|
|
|
webrtc::Trace::ReturnTrace();
|
|
|
|
|
exit(1);
|
|
|
|
|
}
|
|
|
|
|