New ACM test to trigger audio glitch when switching output sample rate
This CL implements a new unit test. The test is designed to trigger a problem in ACM where switching the desired output frequency creates a short discontinuity in the output audio. The problem itself is not solved in this CL, but the failing test is disabled for now. BUG=3919 R=kwiberg@webrtc.org Review URL: https://webrtc-codereview.appspot.com/23019004 git-svn-id: http://webrtc.googlecode.com/svn/trunk@7443 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
parent
c216b9aeaf
commit
81a78930ee
@ -164,6 +164,7 @@ void AcmReceiveTestOldApi::Run() {
|
|||||||
}
|
}
|
||||||
ASSERT_TRUE(audio_sink_->WriteAudioFrame(output_frame));
|
ASSERT_TRUE(audio_sink_->WriteAudioFrame(output_frame));
|
||||||
clock_.AdvanceTimeMilliseconds(10);
|
clock_.AdvanceTimeMilliseconds(10);
|
||||||
|
AfterGetAudio();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Insert packet after converting from RTPHeader to WebRtcRTPHeader.
|
// Insert packet after converting from RTPHeader to WebRtcRTPHeader.
|
||||||
@ -183,5 +184,31 @@ void AcmReceiveTestOldApi::Run() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AcmReceiveTestToggleOutputFreqOldApi::AcmReceiveTestToggleOutputFreqOldApi(
|
||||||
|
PacketSource* packet_source,
|
||||||
|
AudioSink* audio_sink,
|
||||||
|
int output_freq_hz_1,
|
||||||
|
int output_freq_hz_2,
|
||||||
|
int toggle_period_ms,
|
||||||
|
NumOutputChannels exptected_output_channels)
|
||||||
|
: AcmReceiveTestOldApi(packet_source,
|
||||||
|
audio_sink,
|
||||||
|
output_freq_hz_1,
|
||||||
|
exptected_output_channels),
|
||||||
|
output_freq_hz_1_(output_freq_hz_1),
|
||||||
|
output_freq_hz_2_(output_freq_hz_2),
|
||||||
|
toggle_period_ms_(toggle_period_ms),
|
||||||
|
last_toggle_time_ms_(clock_.TimeInMilliseconds()) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void AcmReceiveTestToggleOutputFreqOldApi::AfterGetAudio() {
|
||||||
|
if (clock_.TimeInMilliseconds() >= last_toggle_time_ms_ + toggle_period_ms_) {
|
||||||
|
output_freq_hz_ = (output_freq_hz_ == output_freq_hz_1_)
|
||||||
|
? output_freq_hz_2_
|
||||||
|
: output_freq_hz_1_;
|
||||||
|
last_toggle_time_ms_ = clock_.TimeInMilliseconds();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace test
|
} // namespace test
|
||||||
} // namespace webrtc
|
} // namespace webrtc
|
||||||
|
@ -47,17 +47,42 @@ class AcmReceiveTestOldApi {
|
|||||||
// Runs the test and returns true if successful.
|
// Runs the test and returns true if successful.
|
||||||
void Run();
|
void Run();
|
||||||
|
|
||||||
private:
|
protected:
|
||||||
|
// Method is called after each block of output audio is received from ACM.
|
||||||
|
virtual void AfterGetAudio() {}
|
||||||
|
|
||||||
SimulatedClock clock_;
|
SimulatedClock clock_;
|
||||||
scoped_ptr<AudioCodingModule> acm_;
|
scoped_ptr<AudioCodingModule> acm_;
|
||||||
PacketSource* packet_source_;
|
PacketSource* packet_source_;
|
||||||
AudioSink* audio_sink_;
|
AudioSink* audio_sink_;
|
||||||
const int output_freq_hz_;
|
int output_freq_hz_;
|
||||||
NumOutputChannels exptected_output_channels_;
|
NumOutputChannels exptected_output_channels_;
|
||||||
|
|
||||||
DISALLOW_COPY_AND_ASSIGN(AcmReceiveTestOldApi);
|
DISALLOW_COPY_AND_ASSIGN(AcmReceiveTestOldApi);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// This test toggles the output frequency every |toggle_period_ms|. The test
|
||||||
|
// starts with |output_freq_hz_1|. Except for the toggling, it does the same
|
||||||
|
// thing as AcmReceiveTestOldApi.
|
||||||
|
class AcmReceiveTestToggleOutputFreqOldApi : public AcmReceiveTestOldApi {
|
||||||
|
public:
|
||||||
|
AcmReceiveTestToggleOutputFreqOldApi(
|
||||||
|
PacketSource* packet_source,
|
||||||
|
AudioSink* audio_sink,
|
||||||
|
int output_freq_hz_1,
|
||||||
|
int output_freq_hz_2,
|
||||||
|
int toggle_period_ms,
|
||||||
|
NumOutputChannels exptected_output_channels);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void AfterGetAudio() OVERRIDE;
|
||||||
|
|
||||||
|
const int output_freq_hz_1_;
|
||||||
|
const int output_freq_hz_2_;
|
||||||
|
const int toggle_period_ms_;
|
||||||
|
int64_t last_toggle_time_ms_;
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace test
|
} // namespace test
|
||||||
} // namespace webrtc
|
} // namespace webrtc
|
||||||
#endif // WEBRTC_MODULES_AUDIO_CODING_MAIN_ACM2_ACM_RECEIVE_TEST_H_
|
#endif // WEBRTC_MODULES_AUDIO_CODING_MAIN_ACM2_ACM_RECEIVE_TEST_H_
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
#include "webrtc/modules/audio_coding/main/interface/audio_coding_module_typedefs.h"
|
#include "webrtc/modules/audio_coding/main/interface/audio_coding_module_typedefs.h"
|
||||||
#include "webrtc/modules/audio_coding/neteq/tools/audio_checksum.h"
|
#include "webrtc/modules/audio_coding/neteq/tools/audio_checksum.h"
|
||||||
#include "webrtc/modules/audio_coding/neteq/tools/audio_loop.h"
|
#include "webrtc/modules/audio_coding/neteq/tools/audio_loop.h"
|
||||||
|
#include "webrtc/modules/audio_coding/neteq/tools/constant_pcm_packet_source.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/output_audio_file.h"
|
#include "webrtc/modules/audio_coding/neteq/tools/output_audio_file.h"
|
||||||
#include "webrtc/modules/audio_coding/neteq/tools/packet.h"
|
#include "webrtc/modules/audio_coding/neteq/tools/packet.h"
|
||||||
@ -935,4 +936,105 @@ TEST_F(AcmSenderBitExactnessOldApi, Opus_stereo_20ms) {
|
|||||||
test::AcmReceiveTestOldApi::kStereoOutput);
|
test::AcmReceiveTestOldApi::kStereoOutput);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This test fixture is implemented to run ACM and change the desired output
|
||||||
|
// frequency during the call. The input packets are simply PCM16b-wb encoded
|
||||||
|
// payloads with a constant value of |kSampleValue|. The test fixture itself
|
||||||
|
// acts as PacketSource in between the receive test class and the constant-
|
||||||
|
// payload packet source class. The output is both written to file, and analyzed
|
||||||
|
// in this test fixture.
|
||||||
|
class AcmSwitchingOutputFrequencyOldApi : public ::testing::Test,
|
||||||
|
public test::PacketSource,
|
||||||
|
public test::AudioSink {
|
||||||
|
protected:
|
||||||
|
static const size_t kTestNumPackets = 100;
|
||||||
|
static const int kEncodedSampleRateHz = 16000;
|
||||||
|
static const size_t kPayloadLenSamples = 30 * kEncodedSampleRateHz / 1000;
|
||||||
|
static const int kPayloadType = 108; // Default payload type for PCM16b-wb.
|
||||||
|
|
||||||
|
AcmSwitchingOutputFrequencyOldApi()
|
||||||
|
: first_output_(true),
|
||||||
|
num_packets_(0),
|
||||||
|
packet_source_(kPayloadLenSamples,
|
||||||
|
kSampleValue,
|
||||||
|
kEncodedSampleRateHz,
|
||||||
|
kPayloadType),
|
||||||
|
high_output_freq_(0),
|
||||||
|
has_toggled_(false) {}
|
||||||
|
|
||||||
|
void Run(int low_output_freq, int high_output_freq, int toggle_period_ms) {
|
||||||
|
// Set up the receiver used to decode the packets and verify the decoded
|
||||||
|
// output.
|
||||||
|
const std::string output_file_name =
|
||||||
|
webrtc::test::OutputPath() +
|
||||||
|
::testing::UnitTest::GetInstance()
|
||||||
|
->current_test_info()
|
||||||
|
->test_case_name() +
|
||||||
|
"_" + ::testing::UnitTest::GetInstance()->current_test_info()->name() +
|
||||||
|
"_output.pcm";
|
||||||
|
test::OutputAudioFile output_file(output_file_name);
|
||||||
|
// Have the output audio sent both to file and to the WriteArray method in
|
||||||
|
// this class.
|
||||||
|
test::AudioSinkFork output(this, &output_file);
|
||||||
|
test::AcmReceiveTestToggleOutputFreqOldApi receive_test(
|
||||||
|
this,
|
||||||
|
&output,
|
||||||
|
low_output_freq,
|
||||||
|
high_output_freq,
|
||||||
|
toggle_period_ms,
|
||||||
|
test::AcmReceiveTestOldApi::kMonoOutput);
|
||||||
|
ASSERT_NO_FATAL_FAILURE(receive_test.RegisterDefaultCodecs());
|
||||||
|
high_output_freq_ = high_output_freq;
|
||||||
|
|
||||||
|
// This is where the actual test is executed.
|
||||||
|
receive_test.Run();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Inherited from test::PacketSource.
|
||||||
|
test::Packet* NextPacket() OVERRIDE {
|
||||||
|
// Check if it is time to terminate the test. The packet source is of type
|
||||||
|
// ConstantPcmPacketSource, which is infinite, so we must end the test
|
||||||
|
// "manually".
|
||||||
|
if (num_packets_++ > kTestNumPackets) {
|
||||||
|
EXPECT_TRUE(has_toggled_);
|
||||||
|
return NULL; // Test ended.
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the next packet from the source.
|
||||||
|
return packet_source_.NextPacket();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Inherited from test::AudioSink.
|
||||||
|
bool WriteArray(const int16_t* audio, size_t num_samples) {
|
||||||
|
// Skip checking the first output frame, since it has a number of zeros
|
||||||
|
// due to how NetEq is initialized.
|
||||||
|
if (first_output_) {
|
||||||
|
first_output_ = false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
for (size_t i = 0; i < num_samples; ++i) {
|
||||||
|
EXPECT_EQ(kSampleValue, audio[i]);
|
||||||
|
}
|
||||||
|
if (num_samples ==
|
||||||
|
static_cast<size_t>(high_output_freq_ / 100)) // Size of 10 ms frame.
|
||||||
|
has_toggled_ = true;
|
||||||
|
// The return value does not say if the values match the expectation, just
|
||||||
|
// that the method could process the samples.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const int16_t kSampleValue = 1000;
|
||||||
|
bool first_output_;
|
||||||
|
size_t num_packets_;
|
||||||
|
test::ConstantPcmPacketSource packet_source_;
|
||||||
|
int high_output_freq_;
|
||||||
|
bool has_toggled_;
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST_F(AcmSwitchingOutputFrequencyOldApi, TestWithoutToggling) {
|
||||||
|
Run(16000, 16000, 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(AcmSwitchingOutputFrequencyOldApi, DISABLED_TestWithToggling) {
|
||||||
|
Run(16000, 32000, 1000);
|
||||||
|
}
|
||||||
} // namespace webrtc
|
} // namespace webrtc
|
||||||
|
@ -185,6 +185,8 @@
|
|||||||
'tools/audio_loop.cc',
|
'tools/audio_loop.cc',
|
||||||
'tools/audio_loop.h',
|
'tools/audio_loop.h',
|
||||||
'tools/audio_sink.h',
|
'tools/audio_sink.h',
|
||||||
|
'tools/constant_pcm_packet_source.cc',
|
||||||
|
'tools/constant_pcm_packet_source.h',
|
||||||
'tools/input_audio_file.cc',
|
'tools/input_audio_file.cc',
|
||||||
'tools/input_audio_file.h',
|
'tools/input_audio_file.h',
|
||||||
'tools/output_audio_file.h',
|
'tools/output_audio_file.h',
|
||||||
|
@ -0,0 +1,71 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2014 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/constant_pcm_packet_source.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
#include "webrtc/base/checks.h"
|
||||||
|
#include "webrtc/modules/audio_coding/codecs/pcm16b/include/pcm16b.h"
|
||||||
|
#include "webrtc/modules/audio_coding/neteq/tools/packet.h"
|
||||||
|
|
||||||
|
namespace webrtc {
|
||||||
|
namespace test {
|
||||||
|
|
||||||
|
ConstantPcmPacketSource::ConstantPcmPacketSource(size_t payload_len_samples,
|
||||||
|
int16_t sample_value,
|
||||||
|
int sample_rate_hz,
|
||||||
|
int payload_type)
|
||||||
|
: payload_len_samples_(payload_len_samples),
|
||||||
|
packet_len_bytes_(2 * payload_len_samples_ + kHeaderLenBytes),
|
||||||
|
samples_per_ms_(sample_rate_hz / 1000),
|
||||||
|
next_arrival_time_ms_(0.0),
|
||||||
|
payload_type_(payload_type),
|
||||||
|
seq_number_(0),
|
||||||
|
timestamp_(0),
|
||||||
|
payload_ssrc_(0xABCD1234) {
|
||||||
|
int encoded_len = WebRtcPcm16b_EncodeW16(&sample_value, 1, &encoded_sample_);
|
||||||
|
CHECK_EQ(encoded_len, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
Packet* ConstantPcmPacketSource::NextPacket() {
|
||||||
|
CHECK_GT(packet_len_bytes_, kHeaderLenBytes);
|
||||||
|
uint8_t* packet_memory = new uint8_t[packet_len_bytes_];
|
||||||
|
// Fill the payload part of the packet memory with the pre-encoded value.
|
||||||
|
std::fill_n(reinterpret_cast<int16_t*>(packet_memory + kHeaderLenBytes),
|
||||||
|
payload_len_samples_,
|
||||||
|
encoded_sample_);
|
||||||
|
WriteHeader(packet_memory);
|
||||||
|
// |packet| assumes ownership of |packet_memory|.
|
||||||
|
Packet* packet =
|
||||||
|
new Packet(packet_memory, packet_len_bytes_, next_arrival_time_ms_);
|
||||||
|
next_arrival_time_ms_ += payload_len_samples_ / samples_per_ms_;
|
||||||
|
return packet;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConstantPcmPacketSource::WriteHeader(uint8_t* packet_memory) {
|
||||||
|
packet_memory[0] = 0x80;
|
||||||
|
packet_memory[1] = payload_type_ & 0xFF;
|
||||||
|
packet_memory[2] = (seq_number_ >> 8) & 0xFF;
|
||||||
|
packet_memory[3] = seq_number_ & 0xFF;
|
||||||
|
packet_memory[4] = (timestamp_ >> 24) & 0xFF;
|
||||||
|
packet_memory[5] = (timestamp_ >> 16) & 0xFF;
|
||||||
|
packet_memory[6] = (timestamp_ >> 8) & 0xFF;
|
||||||
|
packet_memory[7] = timestamp_ & 0xFF;
|
||||||
|
packet_memory[8] = (payload_ssrc_ >> 24) & 0xFF;
|
||||||
|
packet_memory[9] = (payload_ssrc_ >> 16) & 0xFF;
|
||||||
|
packet_memory[10] = (payload_ssrc_ >> 8) & 0xFF;
|
||||||
|
packet_memory[11] = payload_ssrc_ & 0xFF;
|
||||||
|
++seq_number_;
|
||||||
|
timestamp_ += static_cast<uint32_t>(payload_len_samples_);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace test
|
||||||
|
} // namespace webrtc
|
@ -0,0 +1,57 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2014 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_CONSTANT_PCM_PACKET_SOURCE_H_
|
||||||
|
#define WEBRTC_MODULES_AUDIO_CODING_NETEQ_TOOLS_CONSTANT_PCM_PACKET_SOURCE_H_
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "webrtc/base/constructormagic.h"
|
||||||
|
#include "webrtc/common_types.h"
|
||||||
|
#include "webrtc/modules/audio_coding/neteq/tools/packet_source.h"
|
||||||
|
|
||||||
|
namespace webrtc {
|
||||||
|
namespace test {
|
||||||
|
|
||||||
|
// This class implements a packet source that delivers PCM16b encoded packets
|
||||||
|
// with a constant sample value. The payload length, constant sample value,
|
||||||
|
// sample rate, and payload type are all set in the constructor.
|
||||||
|
class ConstantPcmPacketSource : public PacketSource {
|
||||||
|
public:
|
||||||
|
ConstantPcmPacketSource(size_t payload_len_samples,
|
||||||
|
int16_t sample_value,
|
||||||
|
int sample_rate_hz,
|
||||||
|
int payload_type);
|
||||||
|
|
||||||
|
// Returns a pointer to the next packet. Will never return NULL. That is,
|
||||||
|
// the source is infinite.
|
||||||
|
Packet* NextPacket() OVERRIDE;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void WriteHeader(uint8_t* packet_memory);
|
||||||
|
|
||||||
|
const size_t kHeaderLenBytes = 12;
|
||||||
|
const size_t payload_len_samples_;
|
||||||
|
const size_t packet_len_bytes_;
|
||||||
|
int16_t encoded_sample_;
|
||||||
|
const int samples_per_ms_;
|
||||||
|
double next_arrival_time_ms_;
|
||||||
|
const int payload_type_;
|
||||||
|
uint16_t seq_number_;
|
||||||
|
uint32_t timestamp_;
|
||||||
|
const uint32_t payload_ssrc_;
|
||||||
|
|
||||||
|
DISALLOW_COPY_AND_ASSIGN(ConstantPcmPacketSource);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace test
|
||||||
|
} // namespace webrtc
|
||||||
|
#endif // WEBRTC_MODULES_AUDIO_CODING_NETEQ_TOOLS_CONSTANT_PCM_PACKET_SOURCE_H_
|
Loading…
x
Reference in New Issue
Block a user