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