From 05e7bfeeea9f4fbddd6f96bb4b33234e44611095 Mon Sep 17 00:00:00 2001 From: "niklas.enbom@webrtc.org" Date: Thu, 24 Jan 2013 18:53:43 +0000 Subject: [PATCH] Mainly hlundin's patch. Review URL: https://webrtc-codereview.appspot.com/1052004 git-svn-id: http://webrtc.googlecode.com/svn/trunk@3405 4adac7df-926f-26a2-2b94-8c16560cd09d --- .../audio_coding/main/source/acm_neteq.cc | 2 +- .../main/source/audio_coding_module_impl.cc | 4 +- webrtc/modules/audio_coding/neteq/automode.c | 6 +-- webrtc/modules/audio_coding/neteq/automode.h | 4 +- .../audio_coding/neteq/bufstats_decision.c | 11 ++-- webrtc/modules/audio_coding/neteq/neteq.gypi | 26 +++++++++ .../neteq/tools/input_audio_file.cc | 45 ++++++++++++++++ .../neteq/tools/input_audio_file.h | 54 +++++++++++++++++++ .../audio_coding/neteq/tools/rtp_generator.cc | 41 ++++++++++++++ .../audio_coding/neteq/tools/rtp_generator.h | 53 ++++++++++++++++++ .../modules/audio_coding/neteq/webrtc_neteq.c | 4 +- .../neteq/webrtc_neteq_unittest.cc | 43 ++++++++++++++- 12 files changed, 277 insertions(+), 16 deletions(-) create mode 100644 webrtc/modules/audio_coding/neteq/tools/input_audio_file.cc create mode 100644 webrtc/modules/audio_coding/neteq/tools/input_audio_file.h create mode 100644 webrtc/modules/audio_coding/neteq/tools/rtp_generator.cc create mode 100644 webrtc/modules/audio_coding/neteq/tools/rtp_generator.h diff --git a/webrtc/modules/audio_coding/main/source/acm_neteq.cc b/webrtc/modules/audio_coding/main/source/acm_neteq.cc index 1f900c0805..624324e84a 100644 --- a/webrtc/modules/audio_coding/main/source/acm_neteq.cc +++ b/webrtc/modules/audio_coding/main/source/acm_neteq.cc @@ -223,7 +223,7 @@ WebRtc_Word16 ACMNetEQ::AllocatePacketBufferByIdxSafe( } if (WebRtcNetEQ_GetRecommendedBufferSize(inst_[idx], used_codecs, num_codecs, - kTCPLargeJitter, + kTCPXLargeJitter, &max_num_packets, &buffer_size_in_bytes) != 0) { LogError("GetRecommendedBufferSize", idx); diff --git a/webrtc/modules/audio_coding/main/source/audio_coding_module_impl.cc b/webrtc/modules/audio_coding/main/source/audio_coding_module_impl.cc index 2ce5abb68f..a27b73fd81 100644 --- a/webrtc/modules/audio_coding/main/source/audio_coding_module_impl.cc +++ b/webrtc/modules/audio_coding/main/source/audio_coding_module_impl.cc @@ -2084,9 +2084,9 @@ int AudioCodingModuleImpl::InitStereoSlave() { // Minimum playout delay (Used for lip-sync). WebRtc_Word32 AudioCodingModuleImpl::SetMinimumPlayoutDelay( const WebRtc_Word32 time_ms) { - if ((time_ms < 0) || (time_ms > 1000)) { + if ((time_ms < 0) || (time_ms > 10000)) { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, id_, - "Delay must be in the range of 0-1000 milliseconds."); + "Delay must be in the range of 0-10000 milliseconds."); return -1; } return neteq_.SetExtraDelay(time_ms); diff --git a/webrtc/modules/audio_coding/neteq/automode.c b/webrtc/modules/audio_coding/neteq/automode.c index d8d56c6921..10a5dbbf94 100644 --- a/webrtc/modules/audio_coding/neteq/automode.c +++ b/webrtc/modules/audio_coding/neteq/automode.c @@ -216,7 +216,7 @@ int WebRtcNetEQ_UpdateIatStatistics(AutomodeInst_t *inst, int maxBufLen, streamingMode); if (tempvar > 0) { - inst->optBufLevel = (WebRtc_UWord16) tempvar; + inst->optBufLevel = tempvar; if (streamingMode != 0) { @@ -575,7 +575,7 @@ int WebRtcNetEQ_BufferLevelFilter(WebRtc_Word32 curSizeMs8, AutomodeInst_t *inst * * levelFiltFact is in Q8 */ - inst->buffLevelFilt = (WebRtc_UWord16) (WEBRTC_SPL_RSHIFT_W32( + inst->buffLevelFilt = (WEBRTC_SPL_RSHIFT_W32( WEBRTC_SPL_MUL_16_U16(inst->levelFiltFact, inst->buffLevelFilt), 8) + WEBRTC_SPL_MUL_16_16(256 - inst->levelFiltFact, curSizeFrames)); } @@ -589,7 +589,7 @@ int WebRtcNetEQ_BufferLevelFilter(WebRtc_Word32 curSizeMs8, AutomodeInst_t *inst * from samples to packets in Q8. Make sure that the filtered value is * non-negative. */ - inst->buffLevelFilt = (WebRtc_UWord16) WEBRTC_SPL_MAX( inst->buffLevelFilt - + inst->buffLevelFilt = WEBRTC_SPL_MAX( inst->buffLevelFilt - WebRtcSpl_DivW32W16( WEBRTC_SPL_LSHIFT_W32(inst->sampleMemory, 8), /* sampleMemory in Q8 */ inst->packetSpeechLenSamp ), /* divide by packetSpeechLenSamp */ diff --git a/webrtc/modules/audio_coding/neteq/automode.h b/webrtc/modules/audio_coding/neteq/automode.h index dbd09cf9a7..2e6b514b47 100644 --- a/webrtc/modules/audio_coding/neteq/automode.h +++ b/webrtc/modules/audio_coding/neteq/automode.h @@ -65,14 +65,14 @@ typedef struct /* Filtered current buffer level */ WebRtc_UWord16 levelFiltFact; /* filter forgetting factor in Q8 */ - WebRtc_UWord16 buffLevelFilt; /* filtered buffer level in Q8 */ + int buffLevelFilt; /* filtered buffer level in Q8 */ /* Inter-arrival time (iat) statistics */ WebRtc_Word32 iatProb[MAX_IAT + 1]; /* iat probabilities in Q30 */ WebRtc_Word16 iatProbFact; /* iat forgetting factor in Q15 */ WebRtc_UWord32 packetIatCountSamp; /* time (in timestamps) elapsed since last packet arrival, based on RecOut calls */ - WebRtc_UWord16 optBufLevel; /* current optimal buffer level in Q8 */ + int optBufLevel; /* current optimal buffer level in Q8 */ /* Packet related information */ WebRtc_Word16 packetSpeechLenSamp; /* speech samples per incoming packet */ diff --git a/webrtc/modules/audio_coding/neteq/bufstats_decision.c b/webrtc/modules/audio_coding/neteq/bufstats_decision.c index 3d37e17324..08fd1fb451 100644 --- a/webrtc/modules/audio_coding/neteq/bufstats_decision.c +++ b/webrtc/modules/audio_coding/neteq/bufstats_decision.c @@ -38,11 +38,11 @@ WebRtc_UWord16 WebRtcNetEQ_BufstatsDecision(BufstatsInst_t *inst, WebRtc_Word16 int currentDelayMs; WebRtc_Word32 currSizeSamples = cur_size; - WebRtc_Word16 extraDelayPacketsQ8 = 0; + int extraDelayPacketsQ8 = 0; /* Avoid overflow if the buffer size should be really large (cur_size is limited 256ms) */ WebRtc_Word32 curr_sizeQ7 = WEBRTC_SPL_LSHIFT_W32(cur_size, 4); - WebRtc_UWord16 level_limit_hi, level_limit_lo; + int level_limit_hi, level_limit_lo; inst->Automode_inst.prevTimeScale &= (prevPlayMode == MODE_SUCCESS_ACCELERATE || prevPlayMode == MODE_LOWEN_ACCELERATE || prevPlayMode == MODE_SUCCESS_PREEMPTIVE @@ -167,10 +167,11 @@ WebRtc_UWord16 WebRtcNetEQ_BufstatsDecision(BufstatsInst_t *inst, WebRtc_Word16 if (inst->Automode_inst.extraDelayMs > 0 && inst->Automode_inst.packetSpeechLenSamp > 0) { - extraDelayPacketsQ8 = WebRtcSpl_DivW32W16ResW16( - (WEBRTC_SPL_MUL(inst->Automode_inst.extraDelayMs, 8 * fs_mult) << 8), - inst->Automode_inst.packetSpeechLenSamp); + /* (extra delay in samples in Q8) */ + extraDelayPacketsQ8 = + ((inst->Automode_inst.extraDelayMs * 8 * fs_mult) << 8) / + inst->Automode_inst.packetSpeechLenSamp; } /* Check if needed packet is available */ diff --git a/webrtc/modules/audio_coding/neteq/neteq.gypi b/webrtc/modules/audio_coding/neteq/neteq.gypi index 88c826063c..bf92a1452f 100644 --- a/webrtc/modules/audio_coding/neteq/neteq.gypi +++ b/webrtc/modules/audio_coding/neteq/neteq.gypi @@ -93,6 +93,7 @@ 'dependencies': [ 'NetEq', 'NetEqTestTools', + 'neteq_unittest_tools', '<(DEPTH)/testing/gtest.gyp:gtest', '<(webrtc_root)/test/test.gyp:test_support_main', ], @@ -100,6 +101,31 @@ 'webrtc_neteq_unittest.cc', ], }, # neteq_unittests + + { + 'target_name': 'neteq_unittest_tools', + 'type': 'static_library', + 'dependencies': [ + '<(DEPTH)/testing/gmock.gyp:gmock', + '<(DEPTH)/testing/gtest.gyp:gtest', + '<(webrtc_root)/test/test.gyp:test_support_main', + ], + 'direct_dependent_settings': { + 'include_dirs': [ + 'tools', + ], + }, + 'include_dirs': [ + 'tools', + ], + 'sources': [ + 'tools/input_audio_file.cc', + 'tools/input_audio_file.h', + 'tools/rtp_generator.cc', + 'tools/rtp_generator.h', + ], + }, # neteq_unittest_tools + { 'target_name': 'NetEqRTPplay', 'type': 'executable', diff --git a/webrtc/modules/audio_coding/neteq/tools/input_audio_file.cc b/webrtc/modules/audio_coding/neteq/tools/input_audio_file.cc new file mode 100644 index 0000000000..d555be6cb0 --- /dev/null +++ b/webrtc/modules/audio_coding/neteq/tools/input_audio_file.cc @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2012 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 "webrtc/modules/audio_coding/neteq/tools/input_audio_file.h" + +namespace webrtc { +namespace test { + +bool InputAudioFile::Read(size_t samples, int16_t* destination) { + if (!fp_) { + return false; + } + size_t bytes_read = fread(destination, sizeof(int16_t), samples, fp_); + if (bytes_read < samples) { + // Rewind and read the missing sampels. + rewind(fp_); + size_t missing_samples = samples - bytes_read; + if (fread(destination, sizeof(int16_t), missing_samples, fp_) < + missing_samples) { + // Could not read enough even after rewinding the file. + return false; + } + } + return true; +} + +void InputAudioFile::DuplicateInterleaved(const int16_t* source, size_t samples, + size_t channels, + int16_t* destination) { + for (size_t i = 0; i < samples; ++i) { + for (size_t j = 0; j < channels; ++j) { + destination[i * channels + j] = source[i]; + } + } +} + +} // namespace test +} // namespace webrtc diff --git a/webrtc/modules/audio_coding/neteq/tools/input_audio_file.h b/webrtc/modules/audio_coding/neteq/tools/input_audio_file.h new file mode 100644 index 0000000000..8727890c3f --- /dev/null +++ b/webrtc/modules/audio_coding/neteq/tools/input_audio_file.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2012 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. + */ + +#ifndef WEBRTC_MODULES_AUDIO_CODING_NETEQ_TOOLS_INPUT_AUDIO_FILE_H_ +#define WEBRTC_MODULES_AUDIO_CODING_NETEQ_TOOLS_INPUT_AUDIO_FILE_H_ + +#include +#include + +#include "webrtc/system_wrappers/interface/constructor_magic.h" +#include "webrtc/typedefs.h" + +namespace webrtc { +namespace test { + +// Class for handling a looping input audio file. +class InputAudioFile { + public: + explicit InputAudioFile(const std::string file_name) { + fp_ = fopen(file_name.c_str(), "rb"); + } + + virtual ~InputAudioFile() { + fclose(fp_); + } + + // Reads |samples| elements from source file to |destination|. Returns true + // if the read was successful, otherwise false. If the file end is reached, + // the file is rewound and reading continues from the beginning. + // The output |destination| must have the capacity to hold |samples| elements. + bool Read(size_t samples, int16_t* destination); + + // Creates a multi-channel signal from a mono signal. Each sample is repeated + // |channels| times to create an interleaved multi-channel signal where all + // channels are identical. The output |destination| must have the capacity to + // hold samples * channels elements. + static void DuplicateInterleaved(const int16_t* source, size_t samples, + size_t channels, int16_t* destination); + + private: + FILE* fp_; + DISALLOW_COPY_AND_ASSIGN(InputAudioFile); +}; + +} // namespace test +} // namespace webrtc +#endif // WEBRTC_MODULES_AUDIO_CODING_NETEQ_TOOLS_INPUT_AUDIO_FILE_H_ diff --git a/webrtc/modules/audio_coding/neteq/tools/rtp_generator.cc b/webrtc/modules/audio_coding/neteq/tools/rtp_generator.cc new file mode 100644 index 0000000000..f3976d9201 --- /dev/null +++ b/webrtc/modules/audio_coding/neteq/tools/rtp_generator.cc @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2012 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 + +#include "webrtc/modules/audio_coding/neteq/tools/rtp_generator.h" + +namespace webrtc { +namespace test { + +uint32_t RtpGenerator::GetRtpHeader(uint8_t payload_type, + size_t payload_length_samples, + WebRtcRTPHeader* rtp_header) { + assert(rtp_header); + if (!rtp_header) { + return 0; + } + rtp_header->header.sequenceNumber = seq_number_++; + rtp_header->header.timestamp = timestamp_; + timestamp_ += payload_length_samples; + rtp_header->header.payloadType = payload_type; + rtp_header->header.markerBit = false; + rtp_header->header.ssrc = ssrc_; + rtp_header->header.numCSRCs = 0; + rtp_header->frameType = kAudioFrameSpeech; + + uint32_t this_send_time = next_send_time_ms_; + assert(samples_per_ms_ > 0); + next_send_time_ms_ += payload_length_samples / samples_per_ms_; + return this_send_time; +} + +} // namespace test +} // namespace webrtc diff --git a/webrtc/modules/audio_coding/neteq/tools/rtp_generator.h b/webrtc/modules/audio_coding/neteq/tools/rtp_generator.h new file mode 100644 index 0000000000..004dc9ead7 --- /dev/null +++ b/webrtc/modules/audio_coding/neteq/tools/rtp_generator.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2012 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. + */ + +#ifndef WEBRTC_MODULES_AUDIO_CODING_NETEQ_TOOLS_RTP_GENERATOR_H_ +#define WEBRTC_MODULES_AUDIO_CODING_NETEQ_TOOLS_RTP_GENERATOR_H_ + +#include "webrtc/modules/interface/module_common_types.h" +#include "webrtc/system_wrappers/interface/constructor_magic.h" +#include "webrtc/typedefs.h" + +namespace webrtc { +namespace test { + +// Class for generating RTP headers. +class RtpGenerator { + public: + RtpGenerator(int samples_per_ms, + uint16_t start_seq_number = 0, + uint32_t start_timestamp = 0, + uint32_t start_send_time_ms = 0, + uint32_t ssrc = 0x12345678) + : seq_number_(start_seq_number), + timestamp_(start_timestamp), + next_send_time_ms_(start_send_time_ms), + ssrc_(ssrc), + samples_per_ms_(samples_per_ms) { + } + + // Writes the next RTP header to |rtp_header|, wich will be of type + // |payload_type|. Returns the send time for this packet (in ms). The value of + // |payload_length_samples| determines the send time for the next packet. + uint32_t GetRtpHeader(uint8_t payload_type, size_t payload_length_samples, + WebRtcRTPHeader* rtp_header); + + private: + uint16_t seq_number_; + uint32_t timestamp_; + uint32_t next_send_time_ms_; + const uint32_t ssrc_; + const int samples_per_ms_; + DISALLOW_COPY_AND_ASSIGN(RtpGenerator); +}; + +} // namespace test +} // namespace webrtc +#endif // WEBRTC_MODULES_AUDIO_CODING_NETEQ_TOOLS_RTP_GENERATOR_H_ diff --git a/webrtc/modules/audio_coding/neteq/webrtc_neteq.c b/webrtc/modules/audio_coding/neteq/webrtc_neteq.c index d13902d266..3dbefba4cb 100644 --- a/webrtc/modules/audio_coding/neteq/webrtc_neteq.c +++ b/webrtc/modules/audio_coding/neteq/webrtc_neteq.c @@ -339,7 +339,7 @@ int WebRtcNetEQ_GetRecommendedBufferSize(void *inst, const enum WebRtcNetEQDecod } else if (nwType == kTCPXLargeJitter) { - multiplier = 20; + multiplier = 12; } else { @@ -514,7 +514,7 @@ int WebRtcNetEQ_SetExtraDelay(void *inst, int DelayInMs) { MainInst_t *NetEqMainInst = (MainInst_t*) inst; if (NetEqMainInst == NULL) return (-1); - if ((DelayInMs < 0) || (DelayInMs > 1000)) + if ((DelayInMs < 0) || (DelayInMs > 10000)) { NetEqMainInst->ErrorCode = -FAULTY_DELAYVALUE; return (-1); diff --git a/webrtc/modules/audio_coding/neteq/webrtc_neteq_unittest.cc b/webrtc/modules/audio_coding/neteq/webrtc_neteq_unittest.cc index ebb96aab8b..c0adfd7141 100644 --- a/webrtc/modules/audio_coding/neteq/webrtc_neteq_unittest.cc +++ b/webrtc/modules/audio_coding/neteq/webrtc_neteq_unittest.cc @@ -27,6 +27,7 @@ #include "modules/audio_coding/neteq/test/NETEQTEST_CodecClass.h" #include "modules/audio_coding/neteq/test/NETEQTEST_NetEQClass.h" #include "modules/audio_coding/neteq/test/NETEQTEST_RTPpacket.h" +#include "webrtc/modules/audio_coding/neteq/tools/input_audio_file.h" #include "testsupport/fileutils.h" #include "typedefs.h" // NOLINT(build/include) @@ -212,7 +213,7 @@ void NetEqDecodingTest::SetUp() { SelectDecoders(usedCodec); neteq_inst_ = new NETEQTEST_NetEQClass(usedCodec, dec_.size(), 8000, - kTCPLargeJitter); + kTCPXLargeJitter); ASSERT_TRUE(neteq_inst_); LoadDecoders(); } @@ -651,4 +652,44 @@ TEST_F(NetEqDecodingTest, NoInputDataStereo) { free(ms_info); } +TEST_F(NetEqDecodingTest, TestExtraDelay) { + static const int kNumFrames = 120000; // Needed for convergence. + int frame_index = 0; + static const int kFrameSizeSamples = 30 * 16; + static const int kPayloadBytes = kFrameSizeSamples * 2; + test::InputAudioFile input_file( + webrtc::test::ResourcePath("audio_coding/testfile32kHz", "pcm")); + int16_t input[kFrameSizeSamples]; + static const int kExtraDelayMs = 5000; + ASSERT_EQ(0, WebRtcNetEQ_SetExtraDelay(neteq_inst_->instance(), + kExtraDelayMs)); + for (int i = 0; i < kNumFrames; ++i) { + ASSERT_TRUE(input_file.Read(kFrameSizeSamples, input)); + WebRtcNetEQ_RTPInfo rtp_info; + PopulateRtpInfo(frame_index, frame_index * kFrameSizeSamples, &rtp_info); + uint8_t* payload = reinterpret_cast(input); + ASSERT_EQ(0, + WebRtcNetEQ_RecInRTPStruct(neteq_inst_->instance(), + &rtp_info, + payload, + kPayloadBytes, 0)); + ++frame_index; + // Pull out data. + for (int j = 0; j < 3; ++j) { + ASSERT_TRUE(kBlockSize16kHz == neteq_inst_->recOut(out_data_)); + } + if (i % 100 == 0) { + WebRtcNetEQ_NetworkStatistics network_stats; + ASSERT_EQ(0, WebRtcNetEQ_GetNetworkStatistics(neteq_inst_->instance(), + &network_stats)); + const int expected_lower_limit = + std::min(i * 0.083 - 210, 0.9 * network_stats.preferredBufferSize); + EXPECT_GE(network_stats.currentBufferSize, expected_lower_limit); + const int expected_upper_limit = + std::min(i * 0.083 + 255, 1.2 * network_stats.preferredBufferSize); + EXPECT_LE(network_stats.currentBufferSize, expected_upper_limit); + } + } +} + } // namespace