Bug 1869043 rename MockCubebStream::InputSampleRate() SampleRate() r=pehrsons
[gecko.git] / dom / media / gtest / TestAudioInputSource.cpp
blobf3f18b26a983f6a88a6896a6420979dad87dc4c0
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
7 #include "AudioInputSource.h"
9 #include "gmock/gmock.h"
10 #include "gtest/gtest.h"
12 #include "MockCubeb.h"
13 #include "mozilla/gtest/WaitFor.h"
14 #include "nsContentUtils.h"
16 using namespace mozilla;
17 using testing::ContainerEq;
19 namespace {
20 #define DispatchFunction(f) \
21 NS_DispatchToCurrentThread(NS_NewRunnableFunction(__func__, f))
22 } // namespace
24 class MockEventListener : public AudioInputSource::EventListener {
25 public:
26 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MockEventListener, override);
27 MOCK_METHOD1(AudioDeviceChanged, void(AudioInputSource::Id));
28 MOCK_METHOD2(AudioStateCallback,
29 void(AudioInputSource::Id,
30 AudioInputSource::EventListener::State));
32 private:
33 ~MockEventListener() = default;
36 TEST(TestAudioInputSource, StartAndStop)
38 MockCubeb* cubeb = new MockCubeb();
39 CubebUtils::ForceSetCubebContext(cubeb->AsCubebContext());
41 const AudioInputSource::Id sourceId = 1;
42 const CubebUtils::AudioDeviceID deviceId = (CubebUtils::AudioDeviceID)1;
43 const uint32_t channels = 2;
44 const PrincipalHandle testPrincipal =
45 MakePrincipalHandle(nsContentUtils::GetSystemPrincipal());
46 const TrackRate sourceRate = 44100;
47 const TrackRate targetRate = 48000;
49 auto listener = MakeRefPtr<MockEventListener>();
50 EXPECT_CALL(*listener,
51 AudioStateCallback(
52 sourceId, AudioInputSource::EventListener::State::Started))
53 .Times(2);
54 EXPECT_CALL(*listener,
55 AudioStateCallback(
56 sourceId, AudioInputSource::EventListener::State::Stopped))
57 .Times(4);
59 RefPtr<AudioInputSource> ais = MakeRefPtr<AudioInputSource>(
60 std::move(listener), sourceId, deviceId, channels, true, testPrincipal,
61 sourceRate, targetRate);
62 ASSERT_TRUE(ais);
64 // Make sure start and stop works.
66 DispatchFunction([&] { ais->Start(); });
67 RefPtr<SmartMockCubebStream> stream = WaitFor(cubeb->StreamInitEvent());
68 EXPECT_TRUE(stream->mHasInput);
69 EXPECT_FALSE(stream->mHasOutput);
70 EXPECT_EQ(stream->GetInputDeviceID(), deviceId);
71 EXPECT_EQ(stream->InputChannels(), channels);
72 EXPECT_EQ(stream->SampleRate(), static_cast<uint32_t>(sourceRate));
74 Unused << WaitFor(stream->FramesProcessedEvent());
76 DispatchFunction([&] { ais->Stop(); });
77 Unused << WaitFor(cubeb->StreamDestroyEvent());
80 // Make sure restart is ok.
82 DispatchFunction([&] { ais->Start(); });
83 RefPtr<SmartMockCubebStream> stream = WaitFor(cubeb->StreamInitEvent());
84 EXPECT_TRUE(stream->mHasInput);
85 EXPECT_FALSE(stream->mHasOutput);
86 EXPECT_EQ(stream->GetInputDeviceID(), deviceId);
87 EXPECT_EQ(stream->InputChannels(), channels);
88 EXPECT_EQ(stream->SampleRate(), static_cast<uint32_t>(sourceRate));
90 Unused << WaitFor(stream->FramesProcessedEvent());
92 DispatchFunction([&] { ais->Stop(); });
93 Unused << WaitFor(cubeb->StreamDestroyEvent());
96 ais = nullptr; // Drop the SharedThreadPool here.
99 TEST(TestAudioInputSource, DataOutputBeforeStartAndAfterStop)
101 MockCubeb* cubeb = new MockCubeb();
102 CubebUtils::ForceSetCubebContext(cubeb->AsCubebContext());
104 const AudioInputSource::Id sourceId = 1;
105 const CubebUtils::AudioDeviceID deviceId = (CubebUtils::AudioDeviceID)1;
106 const uint32_t channels = 2;
107 const PrincipalHandle testPrincipal =
108 MakePrincipalHandle(nsContentUtils::GetSystemPrincipal());
109 const TrackRate sourceRate = 44100;
110 const TrackRate targetRate = 48000;
112 const TrackTime requestFrames = 2 * WEBAUDIO_BLOCK_SIZE;
114 auto listener = MakeRefPtr<MockEventListener>();
115 EXPECT_CALL(*listener,
116 AudioStateCallback(
117 sourceId, AudioInputSource::EventListener::State::Started));
118 EXPECT_CALL(*listener,
119 AudioStateCallback(
120 sourceId, AudioInputSource::EventListener::State::Stopped))
121 .Times(2);
123 RefPtr<AudioInputSource> ais = MakeRefPtr<AudioInputSource>(
124 std::move(listener), sourceId, deviceId, channels, true, testPrincipal,
125 sourceRate, targetRate);
126 ASSERT_TRUE(ais);
128 // It's ok to call GetAudioSegment before starting
130 AudioSegment data =
131 ais->GetAudioSegment(requestFrames, AudioInputSource::Consumer::Same);
132 EXPECT_EQ(data.GetDuration(), requestFrames);
133 EXPECT_TRUE(data.IsNull());
136 DispatchFunction([&] { ais->Start(); });
137 RefPtr<SmartMockCubebStream> stream = WaitFor(cubeb->StreamInitEvent());
138 EXPECT_TRUE(stream->mHasInput);
139 EXPECT_FALSE(stream->mHasOutput);
140 EXPECT_EQ(stream->InputChannels(), channels);
142 stream->SetInputRecordingEnabled(true);
144 Unused << WaitFor(stream->FramesProcessedEvent());
146 DispatchFunction([&] { ais->Stop(); });
147 Unused << WaitFor(cubeb->StreamDestroyEvent());
149 // Check the data output
151 nsTArray<AudioDataValue> record = stream->TakeRecordedInput();
152 size_t frames = record.Length() / channels;
153 AudioSegment deinterleaved;
154 deinterleaved.AppendFromInterleavedBuffer(record.Elements(), frames,
155 channels, testPrincipal);
156 AudioDriftCorrection driftCorrector(sourceRate, targetRate, testPrincipal);
157 AudioSegment expectedSegment = driftCorrector.RequestFrames(
158 deinterleaved, static_cast<uint32_t>(requestFrames));
160 CopyableTArray<AudioDataValue> expected;
161 size_t expectedSamples =
162 expectedSegment.WriteToInterleavedBuffer(expected, channels);
164 AudioSegment actualSegment =
165 ais->GetAudioSegment(requestFrames, AudioInputSource::Consumer::Same);
166 EXPECT_EQ(actualSegment.GetDuration(), requestFrames);
167 CopyableTArray<AudioDataValue> actual;
168 size_t actualSamples =
169 actualSegment.WriteToInterleavedBuffer(actual, channels);
171 EXPECT_EQ(actualSamples, expectedSamples);
172 EXPECT_EQ(actualSamples / channels, static_cast<size_t>(requestFrames));
173 EXPECT_THAT(actual, ContainerEq(expected));
176 ais = nullptr; // Drop the SharedThreadPool here.
179 TEST(TestAudioInputSource, ErrorCallback)
181 MockCubeb* cubeb = new MockCubeb();
182 CubebUtils::ForceSetCubebContext(cubeb->AsCubebContext());
184 const AudioInputSource::Id sourceId = 1;
185 const CubebUtils::AudioDeviceID deviceId = (CubebUtils::AudioDeviceID)1;
186 const uint32_t channels = 2;
187 const PrincipalHandle testPrincipal =
188 MakePrincipalHandle(nsContentUtils::GetSystemPrincipal());
189 const TrackRate sourceRate = 44100;
190 const TrackRate targetRate = 48000;
192 auto listener = MakeRefPtr<MockEventListener>();
193 EXPECT_CALL(*listener,
194 AudioStateCallback(
195 sourceId, AudioInputSource::EventListener::State::Started));
196 EXPECT_CALL(*listener,
197 AudioStateCallback(
198 sourceId, AudioInputSource::EventListener::State::Error));
199 EXPECT_CALL(*listener,
200 AudioStateCallback(
201 sourceId, AudioInputSource::EventListener::State::Stopped))
202 .Times(2);
204 RefPtr<AudioInputSource> ais = MakeRefPtr<AudioInputSource>(
205 std::move(listener), sourceId, deviceId, channels, true, testPrincipal,
206 sourceRate, targetRate);
207 ASSERT_TRUE(ais);
209 DispatchFunction([&] { ais->Start(); });
210 RefPtr<SmartMockCubebStream> stream = WaitFor(cubeb->StreamInitEvent());
211 EXPECT_TRUE(stream->mHasInput);
212 EXPECT_FALSE(stream->mHasOutput);
213 EXPECT_EQ(stream->InputChannels(), channels);
215 Unused << WaitFor(stream->FramesProcessedEvent());
217 DispatchFunction([&] { stream->ForceError(); });
218 WaitFor(stream->ErrorForcedEvent());
220 DispatchFunction([&] { ais->Stop(); });
221 Unused << WaitFor(cubeb->StreamDestroyEvent());
223 ais = nullptr; // Drop the SharedThreadPool here.
226 TEST(TestAudioInputSource, DeviceChangedCallback)
228 MockCubeb* cubeb = new MockCubeb();
229 CubebUtils::ForceSetCubebContext(cubeb->AsCubebContext());
231 const AudioInputSource::Id sourceId = 1;
232 const CubebUtils::AudioDeviceID deviceId = (CubebUtils::AudioDeviceID)1;
233 const uint32_t channels = 2;
234 const PrincipalHandle testPrincipal =
235 MakePrincipalHandle(nsContentUtils::GetSystemPrincipal());
236 const TrackRate sourceRate = 44100;
237 const TrackRate targetRate = 48000;
239 auto listener = MakeRefPtr<MockEventListener>();
240 EXPECT_CALL(*listener, AudioDeviceChanged(sourceId));
241 EXPECT_CALL(*listener,
242 AudioStateCallback(
243 sourceId, AudioInputSource::EventListener::State::Started));
244 EXPECT_CALL(*listener,
245 AudioStateCallback(
246 sourceId, AudioInputSource::EventListener::State::Stopped))
247 .Times(2);
249 RefPtr<AudioInputSource> ais = MakeRefPtr<AudioInputSource>(
250 std::move(listener), sourceId, deviceId, channels, true, testPrincipal,
251 sourceRate, targetRate);
252 ASSERT_TRUE(ais);
254 DispatchFunction([&] { ais->Start(); });
255 RefPtr<SmartMockCubebStream> stream = WaitFor(cubeb->StreamInitEvent());
256 EXPECT_TRUE(stream->mHasInput);
257 EXPECT_FALSE(stream->mHasOutput);
258 EXPECT_EQ(stream->InputChannels(), channels);
260 Unused << WaitFor(stream->FramesProcessedEvent());
262 DispatchFunction([&] { stream->ForceDeviceChanged(); });
263 WaitFor(stream->DeviceChangeForcedEvent());
265 DispatchFunction([&] { ais->Stop(); });
266 Unused << WaitFor(cubeb->StreamDestroyEvent());
268 ais = nullptr; // Drop the SharedThreadPool here.