Use test::Packet test::PacketSource classes in neteq_rtpplay

This change replaces the old NETEQTEST_RTPpacket and
NETEQTEST_DummyRTPpacket with the new test::Packet class. Note that the
Packet class automatically handles "dummy" packets (i.e., packets for
which only the header and a length field was stored to file)
automatically. There is no need to explicitly signal this to the
application any longer. The RTP input file is now handled as a
test::PacketSource object.

Also adding a new ConvertHeader method to the Packet class. This is
needed to extract the header information as an alternative data type.

Finally, some dead code was deleted from rtp_analyze.cc (unrelated to
the reset of this change).

BUG=2692
R=minyue@webrtc.org

Review URL: https://webrtc-codereview.appspot.com/21139004

git-svn-id: http://webrtc.googlecode.com/svn/trunk@6862 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
henrik.lundin@webrtc.org
2014-08-11 12:29:38 +00:00
parent 96d8b0e69f
commit 1c8391205e
5 changed files with 96 additions and 96 deletions

View File

@ -13,7 +13,6 @@
'type': 'executable', 'type': 'executable',
'dependencies': [ 'dependencies': [
'neteq', 'neteq',
'neteq_test_tools',
'neteq_unittest_tools', 'neteq_unittest_tools',
'PCM16B', 'PCM16B',
'<(webrtc_root)/test/test.gyp:test_support_main', '<(webrtc_root)/test/test.gyp:test_support_main',

View File

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

View File

@ -9,6 +9,10 @@
*/ */
#include "webrtc/modules/audio_coding/neteq/tools/packet.h" #include "webrtc/modules/audio_coding/neteq/tools/packet.h"
#include <string.h>
#include "webrtc/modules/interface/module_common_types.h"
#include "webrtc/modules/rtp_rtcp/interface/rtp_header_parser.h" #include "webrtc/modules/rtp_rtcp/interface/rtp_header_parser.h"
namespace webrtc { namespace webrtc {
@ -117,6 +121,14 @@ void Packet::DeleteRedHeaders(std::list<RTPHeader*>* headers) {
} }
} }
void Packet::ConvertHeader(WebRtcRTPHeader* copy_to) const {
memcpy(&copy_to->header, &header_, sizeof(header_));
copy_to->frameType = kAudioFrameSpeech;
copy_to->type.Audio.numEnergy = 0;
copy_to->type.Audio.channel = 1;
copy_to->type.Audio.isCNG = false;
}
bool Packet::ParseHeader(const RtpHeaderParser& parser) { bool Packet::ParseHeader(const RtpHeaderParser& parser) {
bool valid_header = parser.Parse( bool valid_header = parser.Parse(
payload_memory_.get(), static_cast<int>(packet_length_bytes_), &header_); payload_memory_.get(), static_cast<int>(packet_length_bytes_), &header_);

View File

@ -21,6 +21,7 @@
namespace webrtc { namespace webrtc {
class RtpHeaderParser; class RtpHeaderParser;
struct WebRtcRTPHeader;
namespace test { namespace test {
@ -89,6 +90,10 @@ class Packet {
const RTPHeader& header() const { return header_; } const RTPHeader& header() const { return header_; }
// Copies the packet header information, converting from the native RTPHeader
// type to WebRtcRTPHeader.
void ConvertHeader(WebRtcRTPHeader* copy_to) const;
void set_time_ms(double time) { time_ms_ = time; } void set_time_ms(double time) { time_ms_ = time; }
double time_ms() const { return time_ms_; } double time_ms() const { return time_ms_; }
bool valid_header() const { return valid_header_; } bool valid_header() const { return valid_header_; }

View File

@ -59,11 +59,6 @@ int main(int argc, char* argv[]) {
return 0; return 0;
} }
FILE* in_file = fopen(argv[1], "rb");
if (!in_file) {
printf("Cannot open input file %s\n", argv[1]);
return -1;
}
printf("Input file: %s\n", argv[1]); printf("Input file: %s\n", argv[1]);
webrtc::scoped_ptr<webrtc::test::RtpFileSource> file_source( webrtc::scoped_ptr<webrtc::test::RtpFileSource> file_source(
webrtc::test::RtpFileSource::Create(argv[1])); webrtc::test::RtpFileSource::Create(argv[1]));
@ -140,7 +135,6 @@ int main(int argc, char* argv[]) {
} }
} }
fclose(in_file);
fclose(out_file); fclose(out_file);
return 0; return 0;