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 "CubebInputStream.h"
9 #include "gmock/gmock.h"
10 #include "gtest/gtest.h"
12 #include "MockCubeb.h"
15 using namespace mozilla
;
18 #define DispatchFunction(f) \
19 NS_DispatchToCurrentThread(NS_NewRunnableFunction(__func__, f))
22 class MockListener
: public CubebInputStream::Listener
{
24 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MockListener
, override
);
25 MOCK_METHOD2(DataCallback
, long(const void* aBuffer
, long aFrames
));
26 MOCK_METHOD1(StateCallback
, void(cubeb_state aState
));
27 MOCK_METHOD0(DeviceChangedCallback
, void());
30 ~MockListener() = default;
33 TEST(TestCubebInputStream
, DataCallback
)
36 using ::testing::NotNull
;
38 MockCubeb
* cubeb
= new MockCubeb();
39 CubebUtils::ForceSetCubebContext(cubeb
->AsCubebContext());
41 const CubebUtils::AudioDeviceID deviceId
= nullptr;
42 const uint32_t channels
= 2;
45 ASSERT_EQ(cubeb_get_preferred_sample_rate(cubeb
->AsCubebContext(), &rate
),
48 nsTArray
<AudioDataValue
> data
;
49 auto listener
= MakeRefPtr
<MockListener
>();
50 EXPECT_CALL(*listener
, DataCallback(NotNull(), Ne(0)))
51 .WillRepeatedly([&](const void* aBuffer
, long aFrames
) {
52 const AudioDataValue
* source
=
53 reinterpret_cast<const AudioDataValue
*>(aBuffer
);
55 static_cast<size_t>(aFrames
) * static_cast<size_t>(channels
);
56 data
.AppendElements(source
, sampleCount
);
60 EXPECT_CALL(*listener
, StateCallback(CUBEB_STATE_STARTED
));
61 EXPECT_CALL(*listener
, StateCallback(CUBEB_STATE_STOPPED
));
63 EXPECT_CALL(*listener
, DeviceChangedCallback
).Times(0);
65 UniquePtr
<CubebInputStream
> cis
;
66 DispatchFunction([&] {
67 cis
= CubebInputStream::Create(deviceId
, channels
, rate
, true,
71 RefPtr
<SmartMockCubebStream
> stream
= WaitFor(cubeb
->StreamInitEvent());
72 EXPECT_TRUE(stream
->mHasInput
);
74 stream
->SetInputRecordingEnabled(true);
76 DispatchFunction([&] { ASSERT_EQ(cis
->Start(), CUBEB_OK
); });
77 WaitFor(stream
->FramesProcessedEvent());
79 DispatchFunction([&] { ASSERT_EQ(cis
->Stop(), CUBEB_OK
); });
80 WaitFor(stream
->OutputVerificationEvent());
82 nsTArray
<AudioDataValue
> record
= stream
->TakeRecordedInput();
84 DispatchFunction([&] { cis
= nullptr; });
85 WaitFor(cubeb
->StreamDestroyEvent());
87 ASSERT_EQ(data
, record
);
90 TEST(TestCubebInputStream
, ErrorCallback
)
93 using ::testing::NotNull
;
94 using ::testing::ReturnArg
;
96 MockCubeb
* cubeb
= new MockCubeb();
97 CubebUtils::ForceSetCubebContext(cubeb
->AsCubebContext());
99 const CubebUtils::AudioDeviceID deviceId
= nullptr;
100 const uint32_t channels
= 2;
103 ASSERT_EQ(cubeb_get_preferred_sample_rate(cubeb
->AsCubebContext(), &rate
),
106 auto listener
= MakeRefPtr
<MockListener
>();
107 EXPECT_CALL(*listener
, DataCallback(NotNull(), Ne(0)))
108 .WillRepeatedly(ReturnArg
<1>());
110 EXPECT_CALL(*listener
, StateCallback(CUBEB_STATE_STARTED
));
111 EXPECT_CALL(*listener
, StateCallback(CUBEB_STATE_ERROR
));
113 EXPECT_CALL(*listener
, DeviceChangedCallback
).Times(0);
115 UniquePtr
<CubebInputStream
> cis
;
116 DispatchFunction([&] {
117 cis
= CubebInputStream::Create(deviceId
, channels
, rate
, true,
121 RefPtr
<SmartMockCubebStream
> stream
= WaitFor(cubeb
->StreamInitEvent());
122 EXPECT_TRUE(stream
->mHasInput
);
124 DispatchFunction([&] { ASSERT_EQ(cis
->Start(), CUBEB_OK
); });
125 WaitFor(stream
->FramesProcessedEvent());
127 DispatchFunction([&] { stream
->ForceError(); });
128 WaitFor(stream
->ErrorForcedEvent());
130 // If stream ran into an error state, then it should be stopped.
132 DispatchFunction([&] { cis
= nullptr; });
133 WaitFor(cubeb
->StreamDestroyEvent());
136 TEST(TestCubebInputStream
, DeviceChangedCallback
)
139 using ::testing::NotNull
;
140 using ::testing::ReturnArg
;
142 MockCubeb
* cubeb
= new MockCubeb();
143 CubebUtils::ForceSetCubebContext(cubeb
->AsCubebContext());
145 const CubebUtils::AudioDeviceID deviceId
= nullptr;
146 const uint32_t channels
= 2;
149 ASSERT_EQ(cubeb_get_preferred_sample_rate(cubeb
->AsCubebContext(), &rate
),
152 auto listener
= MakeRefPtr
<MockListener
>();
153 EXPECT_CALL(*listener
, DataCallback(NotNull(), Ne(0)))
154 .WillRepeatedly(ReturnArg
<1>());
156 // In real world, the stream might run into an error state when the
157 // device-changed event is fired (e.g., the last default output device is
158 // unplugged). But it's fine to not check here since we can control how
159 // MockCubeb behaves.
160 EXPECT_CALL(*listener
, StateCallback(CUBEB_STATE_STARTED
));
161 EXPECT_CALL(*listener
, StateCallback(CUBEB_STATE_STOPPED
));
163 EXPECT_CALL(*listener
, DeviceChangedCallback
);
165 UniquePtr
<CubebInputStream
> cis
;
166 DispatchFunction([&] {
167 cis
= CubebInputStream::Create(deviceId
, channels
, rate
, true,
171 RefPtr
<SmartMockCubebStream
> stream
= WaitFor(cubeb
->StreamInitEvent());
172 EXPECT_TRUE(stream
->mHasInput
);
174 DispatchFunction([&] { ASSERT_EQ(cis
->Start(), CUBEB_OK
); });
175 WaitFor(stream
->FramesProcessedEvent());
177 DispatchFunction([&] { stream
->ForceDeviceChanged(); });
178 WaitFor(stream
->DeviceChangeForcedEvent());
180 // The stream can keep running when its device is changed.
181 DispatchFunction([&] { ASSERT_EQ(cis
->Stop(), CUBEB_OK
); });
182 cubeb_state state
= WaitFor(stream
->StateEvent());
183 EXPECT_EQ(state
, CUBEB_STATE_STOPPED
);
185 DispatchFunction([&] { cis
= nullptr; });
186 WaitFor(cubeb
->StreamDestroyEvent());