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));
|
||||
clock_.AdvanceTimeMilliseconds(10);
|
||||
AfterGetAudio();
|
||||
}
|
||||
|
||||
// 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 webrtc
|
||||
|
@ -47,17 +47,42 @@ class AcmReceiveTestOldApi {
|
||||
// Runs the test and returns true if successful.
|
||||
void Run();
|
||||
|
||||
private:
|
||||
protected:
|
||||
// Method is called after each block of output audio is received from ACM.
|
||||
virtual void AfterGetAudio() {}
|
||||
|
||||
SimulatedClock clock_;
|
||||
scoped_ptr<AudioCodingModule> acm_;
|
||||
PacketSource* packet_source_;
|
||||
AudioSink* audio_sink_;
|
||||
const int output_freq_hz_;
|
||||
int output_freq_hz_;
|
||||
NumOutputChannels exptected_output_channels_;
|
||||
|
||||
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 webrtc
|
||||
#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/neteq/tools/audio_checksum.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/output_audio_file.h"
|
||||
#include "webrtc/modules/audio_coding/neteq/tools/packet.h"
|
||||
@ -935,4 +936,105 @@ TEST_F(AcmSenderBitExactnessOldApi, Opus_stereo_20ms) {
|
||||
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
|
||||
|
@ -185,6 +185,8 @@
|
||||
'tools/audio_loop.cc',
|
||||
'tools/audio_loop.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.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…
Reference in New Issue
Block a user