1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5
6 #include "gtest/gtest.h"
7 #include "OpusTrackEncoder.h"
8
9 #include "AudioGenerator.h"
10 #include "AudioSampleFormat.h"
11
12 using namespace mozilla;
13
14 class TestOpusTrackEncoder : public OpusTrackEncoder {
15 public:
TestOpusTrackEncoder(TrackRate aTrackRate,MediaQueue<EncodedFrame> & aEncodedDataQueue)16 TestOpusTrackEncoder(TrackRate aTrackRate,
17 MediaQueue<EncodedFrame>& aEncodedDataQueue)
18 : OpusTrackEncoder(aTrackRate, aEncodedDataQueue) {}
19
20 // Return true if it has successfully initialized the Opus encoder.
TestOpusRawCreation(int aChannels)21 bool TestOpusRawCreation(int aChannels) {
22 if (Init(aChannels) == NS_OK) {
23 if (IsInitialized()) {
24 return true;
25 }
26 }
27 return false;
28 }
29 };
30
TestOpusInit(int aChannels,TrackRate aSamplingRate)31 static bool TestOpusInit(int aChannels, TrackRate aSamplingRate) {
32 MediaQueue<EncodedFrame> frames;
33 TestOpusTrackEncoder encoder(aSamplingRate, frames);
34 return encoder.TestOpusRawCreation(aChannels);
35 }
36
TEST(OpusAudioTrackEncoder,InitRaw)37 TEST(OpusAudioTrackEncoder, InitRaw)
38 {
39 // Expect false with 0 or negative channels of input signal.
40 EXPECT_FALSE(TestOpusInit(0, 16000));
41 EXPECT_FALSE(TestOpusInit(-1, 16000));
42
43 // The Opus format supports up to 8 channels, and supports multitrack audio up
44 // to 255 channels, but the current implementation supports only mono and
45 // stereo, and downmixes any more than that.
46 // Expect false with channels of input signal exceed the max supported number.
47 EXPECT_FALSE(TestOpusInit(8 + 1, 16000));
48
49 // Should accept channels within valid range.
50 for (int i = 1; i <= 8; i++) {
51 EXPECT_TRUE(TestOpusInit(i, 16000));
52 }
53
54 // Expect false with 0 or negative sampling rate of input signal.
55 EXPECT_FALSE(TestOpusInit(1, 0));
56 EXPECT_FALSE(TestOpusInit(1, -1));
57
58 // Verify sample rate bounds checking.
59 EXPECT_FALSE(TestOpusInit(2, 2000));
60 EXPECT_FALSE(TestOpusInit(2, 4000));
61 EXPECT_FALSE(TestOpusInit(2, 7999));
62 EXPECT_TRUE(TestOpusInit(2, 8000));
63 EXPECT_TRUE(TestOpusInit(2, 192000));
64 EXPECT_FALSE(TestOpusInit(2, 192001));
65 EXPECT_FALSE(TestOpusInit(2, 200000));
66 }
67
TEST(OpusAudioTrackEncoder,Init)68 TEST(OpusAudioTrackEncoder, Init)
69 {
70 {
71 // The encoder does not normally recieve enough info from null data to
72 // init. However, multiple attempts to do so, with sufficiently long
73 // duration segments, should result in a default-init. The first attempt
74 // should never do this though, even if the duration is long:
75 MediaQueue<EncodedFrame> frames;
76 OpusTrackEncoder encoder(48000, frames);
77 AudioSegment segment;
78 segment.AppendNullData(48000 * 100);
79 encoder.TryInit(segment, segment.GetDuration());
80 EXPECT_FALSE(encoder.IsInitialized());
81
82 // Multiple init attempts should result in best effort init:
83 encoder.TryInit(segment, segment.GetDuration());
84 EXPECT_TRUE(encoder.IsInitialized());
85 }
86
87 {
88 // For non-null segments we should init immediately
89 MediaQueue<EncodedFrame> frames;
90 OpusTrackEncoder encoder(48000, frames);
91 AudioSegment segment;
92 AudioGenerator<AudioDataValue> generator(2, 48000);
93 generator.Generate(segment, 1);
94 encoder.TryInit(segment, segment.GetDuration());
95 EXPECT_TRUE(encoder.IsInitialized());
96 }
97
98 {
99 // Test low sample rate bound
100 MediaQueue<EncodedFrame> frames;
101 OpusTrackEncoder encoder(7999, frames);
102 AudioSegment segment;
103 AudioGenerator<AudioDataValue> generator(2, 7999);
104 generator.Generate(segment, 1);
105 encoder.TryInit(segment, segment.GetDuration());
106 EXPECT_FALSE(encoder.IsInitialized());
107 }
108
109 {
110 // Test low sample rate bound
111 MediaQueue<EncodedFrame> frames;
112 OpusTrackEncoder encoder(8000, frames);
113 AudioSegment segment;
114 AudioGenerator<AudioDataValue> generator(2, 8000);
115 generator.Generate(segment, 1);
116 encoder.TryInit(segment, segment.GetDuration());
117 EXPECT_TRUE(encoder.IsInitialized());
118 }
119
120 {
121 // Test high sample rate bound
122 MediaQueue<EncodedFrame> frames;
123 OpusTrackEncoder encoder(192001, frames);
124 AudioSegment segment;
125 AudioGenerator<AudioDataValue> generator(2, 192001);
126 generator.Generate(segment, 1);
127 encoder.TryInit(segment, segment.GetDuration());
128 EXPECT_FALSE(encoder.IsInitialized());
129 }
130
131 {
132 // Test high sample rate bound
133 MediaQueue<EncodedFrame> frames;
134 OpusTrackEncoder encoder(192000, frames);
135 AudioSegment segment;
136 AudioGenerator<AudioDataValue> generator(2, 192000);
137 generator.Generate(segment, 1);
138 encoder.TryInit(segment, segment.GetDuration());
139 EXPECT_TRUE(encoder.IsInitialized());
140 }
141
142 {
143 // Test that it takes 10s to trigger default-init.
144 MediaQueue<EncodedFrame> frames;
145 OpusTrackEncoder encoder(48000, frames);
146 AudioSegment longSegment;
147 longSegment.AppendNullData(48000 * 10 - 1);
148 AudioSegment shortSegment;
149 shortSegment.AppendNullData(1);
150 encoder.TryInit(longSegment, longSegment.GetDuration());
151 EXPECT_FALSE(encoder.IsInitialized());
152 encoder.TryInit(shortSegment, shortSegment.GetDuration());
153 EXPECT_FALSE(encoder.IsInitialized());
154 encoder.TryInit(shortSegment, shortSegment.GetDuration());
155 EXPECT_TRUE(encoder.IsInitialized());
156 }
157 }
158
TestOpusResampler(TrackRate aSamplingRate)159 static int TestOpusResampler(TrackRate aSamplingRate) {
160 MediaQueue<EncodedFrame> frames;
161 OpusTrackEncoder encoder(aSamplingRate, frames);
162 return encoder.mOutputSampleRate;
163 }
164
TEST(OpusAudioTrackEncoder,Resample)165 TEST(OpusAudioTrackEncoder, Resample)
166 {
167 // Sampling rates of data to be fed to Opus encoder, should remain unchanged
168 // if it is one of Opus supported rates (8000, 12000, 16000, 24000 and 48000
169 // (kHz)) at initialization.
170 EXPECT_TRUE(TestOpusResampler(8000) == 8000);
171 EXPECT_TRUE(TestOpusResampler(12000) == 12000);
172 EXPECT_TRUE(TestOpusResampler(16000) == 16000);
173 EXPECT_TRUE(TestOpusResampler(24000) == 24000);
174 EXPECT_TRUE(TestOpusResampler(48000) == 48000);
175
176 // Otherwise, it should be resampled to 48kHz by resampler.
177 EXPECT_TRUE(TestOpusResampler(9600) == 48000);
178 EXPECT_TRUE(TestOpusResampler(44100) == 48000);
179 }
180
TEST(OpusAudioTrackEncoder,FetchMetadata)181 TEST(OpusAudioTrackEncoder, FetchMetadata)
182 {
183 const int32_t channels = 1;
184 const TrackRate sampleRate = 44100;
185 MediaQueue<EncodedFrame> frames;
186 TestOpusTrackEncoder encoder(sampleRate, frames);
187 EXPECT_TRUE(encoder.TestOpusRawCreation(channels));
188
189 RefPtr<TrackMetadataBase> metadata = encoder.GetMetadata();
190 ASSERT_EQ(TrackMetadataBase::METADATA_OPUS, metadata->GetKind());
191
192 RefPtr<OpusMetadata> opusMeta = static_cast<OpusMetadata*>(metadata.get());
193 EXPECT_EQ(channels, opusMeta->mChannels);
194 EXPECT_EQ(sampleRate, opusMeta->mSamplingFrequency);
195 }
196
TEST(OpusAudioTrackEncoder,FrameEncode)197 TEST(OpusAudioTrackEncoder, FrameEncode)
198 {
199 const int32_t channels = 1;
200 const TrackRate sampleRate = 44100;
201 MediaQueue<EncodedFrame> frames;
202 TestOpusTrackEncoder encoder(sampleRate, frames);
203 EXPECT_TRUE(encoder.TestOpusRawCreation(channels));
204
205 // Generate five seconds of raw audio data.
206 AudioGenerator<AudioDataValue> generator(channels, sampleRate);
207 AudioSegment segment;
208 const int32_t samples = sampleRate * 5;
209 generator.Generate(segment, samples);
210
211 encoder.AppendAudioSegment(std::move(segment));
212 encoder.NotifyEndOfStream();
213
214 EXPECT_TRUE(encoder.IsEncodingComplete());
215 EXPECT_TRUE(frames.IsFinished());
216
217 // Verify that encoded data is 5 seconds long.
218 uint64_t totalDuration = 0;
219 while (RefPtr<EncodedFrame> frame = frames.PopFront()) {
220 totalDuration += frame->mDuration;
221 }
222 // 44100 as used above gets resampled to 48000 for opus.
223 const uint64_t five = 48000 * 5;
224 EXPECT_EQ(five + encoder.GetLookahead(), totalDuration);
225 }
226
TEST(OpusAudioTrackEncoder,DefaultInitDuration)227 TEST(OpusAudioTrackEncoder, DefaultInitDuration)
228 {
229 const TrackRate rate = 44100;
230 MediaQueue<EncodedFrame> frames;
231 OpusTrackEncoder encoder(rate, frames);
232 AudioGenerator<AudioDataValue> generator(2, rate);
233 AudioSegment segment;
234 // 15 seconds should trigger the default-init rate.
235 // The default-init timeout is evaluated once per chunk, so keep chunks
236 // reasonably short.
237 for (int i = 0; i < 150; ++i) {
238 generator.Generate(segment, rate / 10);
239 }
240 encoder.AppendAudioSegment(std::move(segment));
241 encoder.NotifyEndOfStream();
242
243 EXPECT_TRUE(encoder.IsEncodingComplete());
244 EXPECT_TRUE(frames.IsFinished());
245
246 // Verify that encoded data is 15 seconds long.
247 uint64_t totalDuration = 0;
248 while (RefPtr<EncodedFrame> frame = frames.PopFront()) {
249 totalDuration += frame->mDuration;
250 }
251 // 44100 as used above gets resampled to 48000 for opus.
252 const uint64_t fifteen = 48000 * 15;
253 EXPECT_EQ(totalDuration, fifteen + encoder.GetLookahead());
254 }
255
TestSampleRate(TrackRate aSampleRate,uint64_t aInputFrames)256 uint64_t TestSampleRate(TrackRate aSampleRate, uint64_t aInputFrames) {
257 MediaQueue<EncodedFrame> frames;
258 OpusTrackEncoder encoder(aSampleRate, frames);
259 AudioGenerator<AudioDataValue> generator(2, aSampleRate);
260 AudioSegment segment;
261 const uint64_t chunkSize = aSampleRate / 10;
262 const uint64_t chunks = aInputFrames / chunkSize;
263 // 15 seconds should trigger the default-init rate.
264 // The default-init timeout is evaluated once per chunk, so keep chunks
265 // reasonably short.
266 for (size_t i = 0; i < chunks; ++i) {
267 generator.Generate(segment, chunkSize);
268 }
269 generator.Generate(segment, aInputFrames % chunks);
270 encoder.AppendAudioSegment(std::move(segment));
271 encoder.NotifyEndOfStream();
272
273 EXPECT_TRUE(encoder.IsEncodingComplete());
274 EXPECT_TRUE(frames.IsFinished());
275
276 // Verify that encoded data is 15 seconds long.
277 uint64_t totalDuration = 0;
278 while (RefPtr<EncodedFrame> frame = frames.PopFront()) {
279 totalDuration += frame->mDuration;
280 }
281 return totalDuration - encoder.GetLookahead();
282 }
283
TEST(OpusAudioTrackEncoder,DurationSampleRates)284 TEST(OpusAudioTrackEncoder, DurationSampleRates)
285 {
286 // Factors of 48k
287 EXPECT_EQ(TestSampleRate(48000, 48000 * 3 / 2), 48000U * 3 / 2);
288 EXPECT_EQ(TestSampleRate(24000, 24000 * 3 / 2), 48000U * 3 / 2);
289 EXPECT_EQ(TestSampleRate(16000, 16000 * 3 / 2), 48000U * 3 / 2);
290 EXPECT_EQ(TestSampleRate(12000, 12000 * 3 / 2), 48000U * 3 / 2);
291 EXPECT_EQ(TestSampleRate(8000, 8000 * 3 / 2), 48000U * 3 / 2);
292
293 // Non-factors of 48k, resampled
294 EXPECT_EQ(TestSampleRate(44100, 44100 * 3 / 2), 48000U * 3 / 2);
295 EXPECT_EQ(TestSampleRate(32000, 32000 * 3 / 2), 48000U * 3 / 2);
296 EXPECT_EQ(TestSampleRate(96000, 96000 * 3 / 2), 48000U * 3 / 2);
297 EXPECT_EQ(TestSampleRate(33330, 33330 * 3 / 2), 48000U * 3 / 2);
298 }
299