/src/mozilla-central/dom/media/gtest/TestAudioTrackEncoder.cpp
Line | Count | Source (jump to first uncovered line) |
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 | | #include "SineWaveGenerator.h" |
9 | | |
10 | | using namespace mozilla; |
11 | | |
12 | | class AudioGenerator |
13 | | { |
14 | | public: |
15 | | AudioGenerator(int32_t aChannels, int32_t aSampleRate) |
16 | | : mGenerator(aSampleRate, 1000) |
17 | | , mChannels(aChannels) |
18 | 0 | {} |
19 | | |
20 | | void Generate(AudioSegment& aSegment, const int32_t& aSamples) |
21 | 0 | { |
22 | 0 | RefPtr<SharedBuffer> buffer = SharedBuffer::Create(aSamples * sizeof(int16_t)); |
23 | 0 | int16_t* dest = static_cast<int16_t*>(buffer->Data()); |
24 | 0 | mGenerator.generate(dest, aSamples); |
25 | 0 | AutoTArray<const int16_t*, 1> channels; |
26 | 0 | for (int32_t i = 0; i < mChannels; i++) { |
27 | 0 | channels.AppendElement(dest); |
28 | 0 | } |
29 | 0 | aSegment.AppendFrames(buffer.forget(), channels, aSamples, PRINCIPAL_HANDLE_NONE); |
30 | 0 | } |
31 | | |
32 | | private: |
33 | | SineWaveGenerator mGenerator; |
34 | | const int32_t mChannels; |
35 | | }; |
36 | | |
37 | | class TestOpusTrackEncoder : public OpusTrackEncoder |
38 | | { |
39 | | public: |
40 | 0 | TestOpusTrackEncoder() : OpusTrackEncoder(90000) {} |
41 | | |
42 | | // Return true if it has successfully initialized the Opus encoder. |
43 | | bool TestOpusRawCreation(int aChannels, int aSamplingRate) |
44 | 0 | { |
45 | 0 | if (Init(aChannels, aSamplingRate) == NS_OK) { |
46 | 0 | if (IsInitialized()) { |
47 | 0 | return true; |
48 | 0 | } |
49 | 0 | } |
50 | 0 | return false; |
51 | 0 | } |
52 | | |
53 | | // Return the sample rate of data to be fed to the Opus encoder, could be |
54 | | // re-sampled if it was not one of the Opus supported sampling rates. |
55 | | // Init() is expected to be called first. |
56 | | int TestGetOutputSampleRate() |
57 | 0 | { |
58 | 0 | return mInitialized ? GetOutputSampleRate() : 0; |
59 | 0 | } |
60 | | }; |
61 | | |
62 | | static bool |
63 | | TestOpusInit(int aChannels, int aSamplingRate) |
64 | 0 | { |
65 | 0 | TestOpusTrackEncoder encoder; |
66 | 0 | return encoder.TestOpusRawCreation(aChannels, aSamplingRate); |
67 | 0 | } |
68 | | |
69 | | TEST(OpusAudioTrackEncoder, InitRaw) |
70 | 0 | { |
71 | 0 | // Expect false with 0 or negative channels of input signal. |
72 | 0 | EXPECT_FALSE(TestOpusInit(0, 16000)); |
73 | 0 | EXPECT_FALSE(TestOpusInit(-1, 16000)); |
74 | 0 |
|
75 | 0 | // The Opus format supports up to 8 channels, and supports multitrack audio up |
76 | 0 | // to 255 channels, but the current implementation supports only mono and |
77 | 0 | // stereo, and downmixes any more than that. |
78 | 0 | // Expect false with channels of input signal exceed the max supported number. |
79 | 0 | EXPECT_FALSE(TestOpusInit(8 + 1, 16000)); |
80 | 0 |
|
81 | 0 | // Should accept channels within valid range. |
82 | 0 | for (int i = 1; i <= 8; i++) { |
83 | 0 | EXPECT_TRUE(TestOpusInit(i, 16000)); |
84 | 0 | } |
85 | 0 |
|
86 | 0 | // Expect false with 0 or negative sampling rate of input signal. |
87 | 0 | EXPECT_FALSE(TestOpusInit(1, 0)); |
88 | 0 | EXPECT_FALSE(TestOpusInit(1, -1)); |
89 | 0 |
|
90 | 0 | // Verify sample rate bounds checking. |
91 | 0 | EXPECT_FALSE(TestOpusInit(2, 2000)); |
92 | 0 | EXPECT_FALSE(TestOpusInit(2, 4000)); |
93 | 0 | EXPECT_FALSE(TestOpusInit(2, 7999)); |
94 | 0 | EXPECT_TRUE(TestOpusInit(2, 8000)); |
95 | 0 | EXPECT_TRUE(TestOpusInit(2, 192000)); |
96 | 0 | EXPECT_FALSE(TestOpusInit(2, 192001)); |
97 | 0 | EXPECT_FALSE(TestOpusInit(2, 200000)); |
98 | 0 | } |
99 | | |
100 | | TEST(OpusAudioTrackEncoder, Init) |
101 | 0 | { |
102 | 0 | { |
103 | 0 | // The encoder does not normally recieve enough info from null data to |
104 | 0 | // init. However, multiple attempts to do so, with sufficiently long |
105 | 0 | // duration segments, should result in a best effort attempt. The first |
106 | 0 | // attempt should never do this though, even if the duration is long: |
107 | 0 | OpusTrackEncoder encoder(48000); |
108 | 0 | AudioSegment segment; |
109 | 0 | segment.AppendNullData(48000 * 100); |
110 | 0 | encoder.TryInit(segment, segment.GetDuration()); |
111 | 0 | EXPECT_FALSE(encoder.IsInitialized()); |
112 | 0 |
|
113 | 0 | // Multiple init attempts should result in best effort init: |
114 | 0 | encoder.TryInit(segment, segment.GetDuration()); |
115 | 0 | EXPECT_TRUE(encoder.IsInitialized()); |
116 | 0 | } |
117 | 0 |
|
118 | 0 | { |
119 | 0 | // If the duration of the segments given to the encoder is not long then |
120 | 0 | // we shouldn't try a best effort init: |
121 | 0 | OpusTrackEncoder encoder(48000); |
122 | 0 | AudioSegment segment; |
123 | 0 | segment.AppendNullData(1); |
124 | 0 | encoder.TryInit(segment, segment.GetDuration()); |
125 | 0 | EXPECT_FALSE(encoder.IsInitialized()); |
126 | 0 | encoder.TryInit(segment, segment.GetDuration()); |
127 | 0 | EXPECT_FALSE(encoder.IsInitialized()); |
128 | 0 | } |
129 | 0 |
|
130 | 0 | { |
131 | 0 | // For non-null segments we should init immediately |
132 | 0 | OpusTrackEncoder encoder(48000); |
133 | 0 | AudioSegment segment; |
134 | 0 | AudioGenerator generator(2, 48000); |
135 | 0 | generator.Generate(segment, 1); |
136 | 0 | encoder.TryInit(segment, segment.GetDuration()); |
137 | 0 | EXPECT_TRUE(encoder.IsInitialized()); |
138 | 0 | } |
139 | 0 |
|
140 | 0 | { |
141 | 0 | // Test low sample rate bound |
142 | 0 | OpusTrackEncoder encoder(7999); |
143 | 0 | AudioSegment segment; |
144 | 0 | AudioGenerator generator(2, 7999); |
145 | 0 | generator.Generate(segment, 1); |
146 | 0 | encoder.TryInit(segment, segment.GetDuration()); |
147 | 0 | EXPECT_FALSE(encoder.IsInitialized()); |
148 | 0 | } |
149 | 0 |
|
150 | 0 | { |
151 | 0 | // Test low sample rate bound |
152 | 0 | OpusTrackEncoder encoder(8000); |
153 | 0 | AudioSegment segment; |
154 | 0 | AudioGenerator generator(2, 8000); |
155 | 0 | generator.Generate(segment, 1); |
156 | 0 | encoder.TryInit(segment, segment.GetDuration()); |
157 | 0 | EXPECT_TRUE(encoder.IsInitialized()); |
158 | 0 | } |
159 | 0 |
|
160 | 0 | { |
161 | 0 | // Test high sample rate bound |
162 | 0 | OpusTrackEncoder encoder(192001); |
163 | 0 | AudioSegment segment; |
164 | 0 | AudioGenerator generator(2, 192001); |
165 | 0 | generator.Generate(segment, 1); |
166 | 0 | encoder.TryInit(segment, segment.GetDuration()); |
167 | 0 | EXPECT_FALSE(encoder.IsInitialized()); |
168 | 0 | } |
169 | 0 |
|
170 | 0 | { |
171 | 0 | // Test high sample rate bound |
172 | 0 | OpusTrackEncoder encoder(192000); |
173 | 0 | AudioSegment segment; |
174 | 0 | AudioGenerator generator(2, 192000); |
175 | 0 | generator.Generate(segment, 1); |
176 | 0 | encoder.TryInit(segment, segment.GetDuration()); |
177 | 0 | EXPECT_TRUE(encoder.IsInitialized()); |
178 | 0 | } |
179 | 0 | } |
180 | | |
181 | | static int |
182 | | TestOpusResampler(int aChannels, int aSamplingRate) |
183 | 0 | { |
184 | 0 | TestOpusTrackEncoder encoder; |
185 | 0 | EXPECT_TRUE(encoder.TestOpusRawCreation(aChannels, aSamplingRate)); |
186 | 0 | return encoder.TestGetOutputSampleRate(); |
187 | 0 | } |
188 | | |
189 | | TEST(OpusAudioTrackEncoder, Resample) |
190 | 0 | { |
191 | 0 | // Sampling rates of data to be fed to Opus encoder, should remain unchanged |
192 | 0 | // if it is one of Opus supported rates (8000, 12000, 16000, 24000 and 48000 |
193 | 0 | // (kHz)) at initialization. |
194 | 0 | EXPECT_TRUE(TestOpusResampler(1, 8000) == 8000); |
195 | 0 | EXPECT_TRUE(TestOpusResampler(1, 12000) == 12000); |
196 | 0 | EXPECT_TRUE(TestOpusResampler(1, 16000) == 16000); |
197 | 0 | EXPECT_TRUE(TestOpusResampler(1, 24000) == 24000); |
198 | 0 | EXPECT_TRUE(TestOpusResampler(1, 48000) == 48000); |
199 | 0 |
|
200 | 0 | // Otherwise, it should be resampled to 48kHz by resampler. |
201 | 0 | EXPECT_TRUE(TestOpusResampler(1, 9600) == 48000); |
202 | 0 | EXPECT_TRUE(TestOpusResampler(1, 44100) == 48000); |
203 | 0 | } |
204 | | |
205 | | TEST(OpusAudioTrackEncoder, FetchMetadata) |
206 | 0 | { |
207 | 0 | const int32_t channels = 1; |
208 | 0 | const int32_t sampleRate = 44100; |
209 | 0 | TestOpusTrackEncoder encoder; |
210 | 0 | EXPECT_TRUE(encoder.TestOpusRawCreation(channels, sampleRate)); |
211 | 0 |
|
212 | 0 | RefPtr<TrackMetadataBase> metadata = encoder.GetMetadata(); |
213 | 0 | ASSERT_EQ(TrackMetadataBase::METADATA_OPUS, metadata->GetKind()); |
214 | 0 |
|
215 | 0 | RefPtr<OpusMetadata> opusMeta = |
216 | 0 | static_cast<OpusMetadata*>(metadata.get()); |
217 | 0 | EXPECT_EQ(channels, opusMeta->mChannels); |
218 | 0 | EXPECT_EQ(sampleRate, opusMeta->mSamplingFrequency); |
219 | 0 | } |
220 | | |
221 | | TEST(OpusAudioTrackEncoder, FrameEncode) |
222 | 0 | { |
223 | 0 | const int32_t channels = 1; |
224 | 0 | const int32_t sampleRate = 44100; |
225 | 0 | TestOpusTrackEncoder encoder; |
226 | 0 | EXPECT_TRUE(encoder.TestOpusRawCreation(channels, sampleRate)); |
227 | 0 |
|
228 | 0 | // Generate five seconds of raw audio data. |
229 | 0 | AudioGenerator generator(channels, sampleRate); |
230 | 0 | AudioSegment segment; |
231 | 0 | const int32_t samples = sampleRate * 5; |
232 | 0 | generator.Generate(segment, samples); |
233 | 0 |
|
234 | 0 | encoder.SetStartOffset(0); |
235 | 0 | encoder.AppendAudioSegment(std::move(segment)); |
236 | 0 | encoder.AdvanceCurrentTime(samples); |
237 | 0 |
|
238 | 0 | EncodedFrameContainer container; |
239 | 0 | EXPECT_TRUE(NS_SUCCEEDED(encoder.GetEncodedTrack(container))); |
240 | 0 |
|
241 | 0 | // Verify that encoded data is 5 seconds long. |
242 | 0 | uint64_t totalDuration = 0; |
243 | 0 | for (auto& frame : container.GetEncodedFrames()) { |
244 | 0 | totalDuration += frame->GetDuration(); |
245 | 0 | } |
246 | 0 | // 44100 as used above gets resampled to 48000 for opus. |
247 | 0 | const uint64_t five = 48000 * 5; |
248 | 0 | EXPECT_EQ(five, totalDuration); |
249 | 0 | } |