#include "remoting/codec/audio_encoder_opus.h"
#include <stddef.h>
#include <stdint.h>
#include <cmath>
#include <memory>
#include <numbers>
#include <utility>
#include "base/compiler_specific.h"
#include "base/logging.h"
#include "remoting/codec/audio_decoder_opus.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace remoting {
namespace {
const int kMaxSampleValue = 32767;
const int kChannels = 2;
const double kChannelPhaseShift = 2 * std::numbers::pi / 3;
const AudioPacket_SamplingRate kDefaultSamplingRate =
AudioPacket::SAMPLING_RATE_48000;
const int kMaxLatencyMs = 40;
const int kSkippedFirstSamples = 1000;
const double kMaxSignalDeviation = 0.1;
}
class OpusAudioEncoderTest : public testing::Test {
public:
static int16_t GetSampleValue(AudioPacket::SamplingRate rate,
double frequency_hz,
double pos,
int channel) {
double angle =
pos * 2 * std::numbers::pi * frequency_hz / static_cast<double>(rate) +
kChannelPhaseShift * channel;
return static_cast<int>(std::sin(angle) * kMaxSampleValue + 0.5);
}
std::unique_ptr<AudioPacket> CreatePacket(int samples,
AudioPacket::SamplingRate rate,
double frequency_hz,
int pos) {
std::vector<int16_t> data(samples * kChannels);
for (int i = 0; i < samples; ++i) {
data[i * kChannels] = GetSampleValue(rate, frequency_hz, i + pos, 0);
data[i * kChannels + 1] = GetSampleValue(rate, frequency_hz, i + pos, 1);
}
std::unique_ptr<AudioPacket> packet(new AudioPacket());
packet->add_data(reinterpret_cast<char*>(&(data[0])),
samples * kChannels * sizeof(int16_t));
packet->set_encoding(AudioPacket::ENCODING_RAW);
packet->set_sampling_rate(rate);
packet->set_bytes_per_sample(AudioPacket::BYTES_PER_SAMPLE_2);
packet->set_channels(AudioPacket::CHANNELS_STEREO);
return packet;
}
double EstimateSignalShift(const std::vector<int16_t>& received_data) {
for (size_t i = kSkippedFirstSamples;
i < received_data.size() / kChannels - 1; i++) {
int16_t this_sample = received_data[i * kChannels];
int16_t next_sample = received_data[(i + 1) * kChannels];
if (this_sample < 0 && next_sample > 0) {
return i +
static_cast<double>(-this_sample) / (next_sample - this_sample);
}
}
return 0;
}
void ValidateReceivedData(int samples,
AudioPacket::SamplingRate rate,
double frequency_hz,
const std::vector<int16_t>& received_data) {
double shift = EstimateSignalShift(received_data);
double diff_sqare_sum = 0;
for (size_t i = kSkippedFirstSamples; i < received_data.size() / kChannels;
i++) {
double d = received_data[i * kChannels] -
GetSampleValue(rate, frequency_hz, i - shift, 0);
diff_sqare_sum += d * d;
d = received_data[i * kChannels + 1] -
GetSampleValue(rate, frequency_hz, i - shift, 1);
diff_sqare_sum += d * d;
}
double deviation =
std::sqrt(diff_sqare_sum / received_data.size()) / kMaxSampleValue;
LOG(ERROR) << "Decoded signal deviation: " << deviation;
EXPECT_LE(deviation, kMaxSignalDeviation);
}
void TestEncodeDecode(int packet_size,
double frequency_hz,
AudioPacket::SamplingRate rate) {
const int kTotalTestSamples = 24000;
encoder_ = std::make_unique<AudioEncoderOpus>();
decoder_ = std::make_unique<AudioDecoderOpus>();
std::vector<int16_t> received_data;
int pos = 0;
for (; pos < kTotalTestSamples; pos += packet_size) {
std::unique_ptr<AudioPacket> source_packet =
CreatePacket(packet_size, rate, frequency_hz, pos);
std::unique_ptr<AudioPacket> encoded =
encoder_->Encode(std::move(source_packet));
if (encoded.get()) {
std::unique_ptr<AudioPacket> decoded =
decoder_->Decode(std::move(encoded));
EXPECT_EQ(kDefaultSamplingRate, decoded->sampling_rate());
for (int i = 0; i < decoded->data_size(); ++i) {
const int16_t* data = UNSAFE_TODO(
reinterpret_cast<const int16_t*>(decoded->data(i).data()));
received_data.insert(
received_data.end(), data,
UNSAFE_TODO(data + decoded->data(i).size() / sizeof(int16_t)));
}
}
}
EXPECT_GE(static_cast<int>(received_data.size()) / kChannels,
pos - rate * kMaxLatencyMs / 1000);
ValidateReceivedData(packet_size, kDefaultSamplingRate, frequency_hz,
received_data);
}
protected:
std::unique_ptr<AudioEncoderOpus> encoder_;
std::unique_ptr<AudioDecoderOpus> decoder_;
};
TEST_F(OpusAudioEncoderTest, CreateAndDestroy) {}
TEST_F(OpusAudioEncoderTest, NoResampling) {
TestEncodeDecode(2000, 50, AudioPacket::SAMPLING_RATE_48000);
TestEncodeDecode(2000, 3000, AudioPacket::SAMPLING_RATE_48000);
TestEncodeDecode(2000, 10000, AudioPacket::SAMPLING_RATE_48000);
}
TEST_F(OpusAudioEncoderTest, Resampling) {
TestEncodeDecode(2000, 50, AudioPacket::SAMPLING_RATE_44100);
TestEncodeDecode(2000, 3000, AudioPacket::SAMPLING_RATE_44100);
TestEncodeDecode(2000, 10000, AudioPacket::SAMPLING_RATE_44100);
}
TEST_F(OpusAudioEncoderTest, BufferSizeAndResampling) {
TestEncodeDecode(500, 3000, AudioPacket::SAMPLING_RATE_44100);
TestEncodeDecode(1000, 3000, AudioPacket::SAMPLING_RATE_44100);
TestEncodeDecode(5000, 3000, AudioPacket::SAMPLING_RATE_44100);
}
}