audio_encoder_opus_unittest.cc 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. // Copyright (c) 2012 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "remoting/codec/audio_encoder_opus.h"
  5. #include <stddef.h>
  6. #include <stdint.h>
  7. #include <cmath>
  8. #include <memory>
  9. #include <utility>
  10. #include "base/logging.h"
  11. #include "base/numerics/math_constants.h"
  12. #include "remoting/codec/audio_decoder_opus.h"
  13. #include "testing/gtest/include/gtest/gtest.h"
  14. namespace remoting {
  15. namespace {
  16. // Maximum value that can be encoded in a 16-bit signed sample.
  17. const int kMaxSampleValue = 32767;
  18. const int kChannels = 2;
  19. // Phase shift between left and right channels.
  20. const double kChannelPhaseShift = 2 * base::kPiDouble / 3;
  21. // The sampling rate that OPUS uses internally and that we expect to get
  22. // from the decoder.
  23. const AudioPacket_SamplingRate kDefaultSamplingRate =
  24. AudioPacket::SAMPLING_RATE_48000;
  25. // Maximum latency expected from the encoder.
  26. const int kMaxLatencyMs = 40;
  27. // When verifying results ignore the first 1k samples. This is necessary because
  28. // it takes some time for the codec to adjust for the input signal.
  29. const int kSkippedFirstSamples = 1000;
  30. // Maximum standard deviation of the difference between original and decoded
  31. // signals as a proportion of kMaxSampleValue. For two unrelated signals this
  32. // difference will be close to 1.0, even for signals that differ only slightly.
  33. // The value is chosen such that all the tests pass normally, but fail with
  34. // small changes (e.g. one sample shift between signals).
  35. const double kMaxSignalDeviation = 0.1;
  36. } // namespace
  37. class OpusAudioEncoderTest : public testing::Test {
  38. public:
  39. // Return test signal value at the specified position |pos|. |frequency_hz|
  40. // defines frequency of the signal. |channel| is used to calculate phase shift
  41. // of the signal, so that different signals are generated for left and right
  42. // channels.
  43. static int16_t GetSampleValue(AudioPacket::SamplingRate rate,
  44. double frequency_hz,
  45. double pos,
  46. int channel) {
  47. double angle =
  48. pos * 2 * base::kPiDouble * frequency_hz / static_cast<double>(rate) +
  49. kChannelPhaseShift * channel;
  50. return static_cast<int>(std::sin(angle) * kMaxSampleValue + 0.5);
  51. }
  52. // Creates audio packet filled with a test signal with the specified
  53. // |frequency_hz|.
  54. std::unique_ptr<AudioPacket> CreatePacket(int samples,
  55. AudioPacket::SamplingRate rate,
  56. double frequency_hz,
  57. int pos) {
  58. std::vector<int16_t> data(samples * kChannels);
  59. for (int i = 0; i < samples; ++i) {
  60. data[i * kChannels] = GetSampleValue(rate, frequency_hz, i + pos, 0);
  61. data[i * kChannels + 1] = GetSampleValue(rate, frequency_hz, i + pos, 1);
  62. }
  63. std::unique_ptr<AudioPacket> packet(new AudioPacket());
  64. packet->add_data(reinterpret_cast<char*>(&(data[0])),
  65. samples * kChannels * sizeof(int16_t));
  66. packet->set_encoding(AudioPacket::ENCODING_RAW);
  67. packet->set_sampling_rate(rate);
  68. packet->set_bytes_per_sample(AudioPacket::BYTES_PER_SAMPLE_2);
  69. packet->set_channels(AudioPacket::CHANNELS_STEREO);
  70. return packet;
  71. }
  72. // Decoded data is normally shifted in phase relative to the original signal.
  73. // This function returns the approximate shift in samples by finding the first
  74. // point when signal goes from negative to positive.
  75. double EstimateSignalShift(const std::vector<int16_t>& received_data) {
  76. for (size_t i = kSkippedFirstSamples;
  77. i < received_data.size() / kChannels - 1; i++) {
  78. int16_t this_sample = received_data[i * kChannels];
  79. int16_t next_sample = received_data[(i + 1) * kChannels];
  80. if (this_sample < 0 && next_sample > 0) {
  81. return
  82. i + static_cast<double>(-this_sample) / (next_sample - this_sample);
  83. }
  84. }
  85. return 0;
  86. }
  87. // Compares decoded signal with the test signal that was encoded. It estimates
  88. // phase shift from the original signal, then calculates standard deviation of
  89. // the difference between original and decoded signals.
  90. void ValidateReceivedData(int samples,
  91. AudioPacket::SamplingRate rate,
  92. double frequency_hz,
  93. const std::vector<int16_t>& received_data) {
  94. double shift = EstimateSignalShift(received_data);
  95. double diff_sqare_sum = 0;
  96. for (size_t i = kSkippedFirstSamples;
  97. i < received_data.size() / kChannels; i++) {
  98. double d = received_data[i * kChannels] -
  99. GetSampleValue(rate, frequency_hz, i - shift, 0);
  100. diff_sqare_sum += d * d;
  101. d = received_data[i * kChannels + 1] -
  102. GetSampleValue(rate, frequency_hz, i - shift, 1);
  103. diff_sqare_sum += d * d;
  104. }
  105. double deviation =
  106. std::sqrt(diff_sqare_sum / received_data.size()) / kMaxSampleValue;
  107. LOG(ERROR) << "Decoded signal deviation: " << deviation;
  108. EXPECT_LE(deviation, kMaxSignalDeviation);
  109. }
  110. void TestEncodeDecode(int packet_size,
  111. double frequency_hz,
  112. AudioPacket::SamplingRate rate) {
  113. const int kTotalTestSamples = 24000;
  114. encoder_ = std::make_unique<AudioEncoderOpus>();
  115. decoder_ = std::make_unique<AudioDecoderOpus>();
  116. std::vector<int16_t> received_data;
  117. int pos = 0;
  118. for (; pos < kTotalTestSamples; pos += packet_size) {
  119. std::unique_ptr<AudioPacket> source_packet =
  120. CreatePacket(packet_size, rate, frequency_hz, pos);
  121. std::unique_ptr<AudioPacket> encoded =
  122. encoder_->Encode(std::move(source_packet));
  123. if (encoded.get()) {
  124. std::unique_ptr<AudioPacket> decoded =
  125. decoder_->Decode(std::move(encoded));
  126. EXPECT_EQ(kDefaultSamplingRate, decoded->sampling_rate());
  127. for (int i = 0; i < decoded->data_size(); ++i) {
  128. const int16_t* data =
  129. reinterpret_cast<const int16_t*>(decoded->data(i).data());
  130. received_data.insert(
  131. received_data.end(), data,
  132. data + decoded->data(i).size() / sizeof(int16_t));
  133. }
  134. }
  135. }
  136. // Verify that at most kMaxLatencyMs worth of samples is buffered inside
  137. // |encoder_| and |decoder_|.
  138. EXPECT_GE(static_cast<int>(received_data.size()) / kChannels,
  139. pos - rate * kMaxLatencyMs / 1000);
  140. ValidateReceivedData(packet_size, kDefaultSamplingRate,
  141. frequency_hz, received_data);
  142. }
  143. protected:
  144. std::unique_ptr<AudioEncoderOpus> encoder_;
  145. std::unique_ptr<AudioDecoderOpus> decoder_;
  146. };
  147. TEST_F(OpusAudioEncoderTest, CreateAndDestroy) {
  148. }
  149. TEST_F(OpusAudioEncoderTest, NoResampling) {
  150. TestEncodeDecode(2000, 50, AudioPacket::SAMPLING_RATE_48000);
  151. TestEncodeDecode(2000, 3000, AudioPacket::SAMPLING_RATE_48000);
  152. TestEncodeDecode(2000, 10000, AudioPacket::SAMPLING_RATE_48000);
  153. }
  154. TEST_F(OpusAudioEncoderTest, Resampling) {
  155. TestEncodeDecode(2000, 50, AudioPacket::SAMPLING_RATE_44100);
  156. TestEncodeDecode(2000, 3000, AudioPacket::SAMPLING_RATE_44100);
  157. TestEncodeDecode(2000, 10000, AudioPacket::SAMPLING_RATE_44100);
  158. }
  159. TEST_F(OpusAudioEncoderTest, BufferSizeAndResampling) {
  160. TestEncodeDecode(500, 3000, AudioPacket::SAMPLING_RATE_44100);
  161. TestEncodeDecode(1000, 3000, AudioPacket::SAMPLING_RATE_44100);
  162. TestEncodeDecode(5000, 3000, AudioPacket::SAMPLING_RATE_44100);
  163. }
  164. } // namespace remoting