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 file,
4 * You can obtain one at http://mozilla.org/MPL/2.0/. */
8 #include "AudioDeviceInfo.h"
9 #include "AudioGenerator.h"
10 #include "AudioVerifier.h"
11 #include "MediaEventSource.h"
12 #include "mozilla/DataMutex.h"
13 #include "mozilla/MozPromise.h"
14 #include "mozilla/ThreadSafeWeakPtr.h"
22 const uint32_t MAX_OUTPUT_CHANNELS
= 2;
23 const uint32_t MAX_INPUT_CHANNELS
= 2;
26 int (*init
)(cubeb
** context
, char const* context_name
);
27 char const* (*get_backend_id
)(cubeb
* context
);
28 int (*get_max_channel_count
)(cubeb
* context
, uint32_t* max_channels
);
29 int (*get_min_latency
)(cubeb
* context
, cubeb_stream_params params
,
30 uint32_t* latency_ms
);
31 int (*get_preferred_sample_rate
)(cubeb
* context
, uint32_t* rate
);
32 int (*enumerate_devices
)(cubeb
* context
, cubeb_device_type type
,
33 cubeb_device_collection
* collection
);
34 int (*device_collection_destroy
)(cubeb
* context
,
35 cubeb_device_collection
* collection
);
36 void (*destroy
)(cubeb
* context
);
37 int (*stream_init
)(cubeb
* context
, cubeb_stream
** stream
,
38 char const* stream_name
, cubeb_devid input_device
,
39 cubeb_stream_params
* input_stream_params
,
40 cubeb_devid output_device
,
41 cubeb_stream_params
* output_stream_params
,
42 unsigned int latency
, cubeb_data_callback data_callback
,
43 cubeb_state_callback state_callback
, void* user_ptr
);
44 void (*stream_destroy
)(cubeb_stream
* stream
);
45 int (*stream_start
)(cubeb_stream
* stream
);
46 int (*stream_stop
)(cubeb_stream
* stream
);
47 int (*stream_get_position
)(cubeb_stream
* stream
, uint64_t* position
);
48 int (*stream_get_latency
)(cubeb_stream
* stream
, uint32_t* latency
);
49 int (*stream_get_input_latency
)(cubeb_stream
* stream
, uint32_t* latency
);
50 int (*stream_set_volume
)(cubeb_stream
* stream
, float volumes
);
51 int (*stream_set_name
)(cubeb_stream
* stream
, char const* stream_name
);
52 int (*stream_get_current_device
)(cubeb_stream
* stream
,
53 cubeb_device
** const device
);
54 int (*stream_device_destroy
)(cubeb_stream
* stream
, cubeb_device
* device
);
55 int (*stream_register_device_changed_callback
)(
57 cubeb_device_changed_callback device_changed_callback
);
58 int (*register_device_collection_changed
)(
59 cubeb
* context
, cubeb_device_type devtype
,
60 cubeb_device_collection_changed_callback callback
, void* user_ptr
);
63 // Keep those and the struct definition in sync with cubeb.h and
65 void cubeb_mock_destroy(cubeb
* context
);
66 static int cubeb_mock_enumerate_devices(cubeb
* context
, cubeb_device_type type
,
67 cubeb_device_collection
* out
);
69 static int cubeb_mock_device_collection_destroy(
70 cubeb
* context
, cubeb_device_collection
* collection
);
72 static int cubeb_mock_register_device_collection_changed(
73 cubeb
* context
, cubeb_device_type devtype
,
74 cubeb_device_collection_changed_callback callback
, void* user_ptr
);
76 static int cubeb_mock_stream_init(
77 cubeb
* context
, cubeb_stream
** stream
, char const* stream_name
,
78 cubeb_devid input_device
, cubeb_stream_params
* input_stream_params
,
79 cubeb_devid output_device
, cubeb_stream_params
* output_stream_params
,
80 unsigned int latency
, cubeb_data_callback data_callback
,
81 cubeb_state_callback state_callback
, void* user_ptr
);
83 static int cubeb_mock_stream_start(cubeb_stream
* stream
);
85 static int cubeb_mock_stream_stop(cubeb_stream
* stream
);
87 static int cubeb_mock_stream_get_position(cubeb_stream
* stream
,
90 static void cubeb_mock_stream_destroy(cubeb_stream
* stream
);
92 static char const* cubeb_mock_get_backend_id(cubeb
* context
);
94 static int cubeb_mock_stream_set_volume(cubeb_stream
* stream
, float volume
);
96 static int cubeb_mock_stream_set_name(cubeb_stream
* stream
,
97 char const* stream_name
);
99 static int cubeb_mock_stream_register_device_changed_callback(
100 cubeb_stream
* stream
,
101 cubeb_device_changed_callback device_changed_callback
);
103 static int cubeb_mock_get_min_latency(cubeb
* context
,
104 cubeb_stream_params params
,
105 uint32_t* latency_ms
);
107 static int cubeb_mock_get_preferred_sample_rate(cubeb
* context
, uint32_t* rate
);
109 static int cubeb_mock_get_max_channel_count(cubeb
* context
,
110 uint32_t* max_channels
);
112 // Mock cubeb impl, only supports device enumeration for now.
113 cubeb_ops
const mock_ops
= {
115 /*.get_backend_id =*/cubeb_mock_get_backend_id
,
116 /*.get_max_channel_count =*/cubeb_mock_get_max_channel_count
,
117 /*.get_min_latency =*/cubeb_mock_get_min_latency
,
118 /*.get_preferred_sample_rate =*/cubeb_mock_get_preferred_sample_rate
,
119 /*.enumerate_devices =*/cubeb_mock_enumerate_devices
,
120 /*.device_collection_destroy =*/cubeb_mock_device_collection_destroy
,
121 /*.destroy =*/cubeb_mock_destroy
,
122 /*.stream_init =*/cubeb_mock_stream_init
,
123 /*.stream_destroy =*/cubeb_mock_stream_destroy
,
124 /*.stream_start =*/cubeb_mock_stream_start
,
125 /*.stream_stop =*/cubeb_mock_stream_stop
,
126 /*.stream_get_position =*/cubeb_mock_stream_get_position
,
127 /*.stream_get_latency =*/NULL
,
128 /*.stream_get_input_latency =*/NULL
,
129 /*.stream_set_volume =*/cubeb_mock_stream_set_volume
,
130 /*.stream_set_name =*/cubeb_mock_stream_set_name
,
131 /*.stream_get_current_device =*/NULL
,
132 /*.stream_device_destroy =*/NULL
,
133 /*.stream_register_device_changed_callback =*/
134 cubeb_mock_stream_register_device_changed_callback
,
135 /*.register_device_collection_changed =*/
137 cubeb_mock_register_device_collection_changed
};
139 class SmartMockCubebStream
;
141 // Represents the fake cubeb_stream. The context instance is needed to
142 // provide access on cubeb_ops struct.
143 class MockCubebStream
{
144 friend class MockCubeb
;
146 // These members need to have the exact same memory layout as a real
147 // cubeb_stream, so that AsMock() returns a pointer to this that can be used
148 // as a cubeb_stream.
153 enum class KeepProcessing
{ No
, Yes
};
154 enum class RunningMode
{ Automatic
, Manual
};
156 MockCubebStream(cubeb
* aContext
, char const* aStreamName
,
157 cubeb_devid aInputDevice
,
158 cubeb_stream_params
* aInputStreamParams
,
159 cubeb_devid aOutputDevice
,
160 cubeb_stream_params
* aOutputStreamParams
,
161 cubeb_data_callback aDataCallback
,
162 cubeb_state_callback aStateCallback
, void* aUserPtr
,
163 SmartMockCubebStream
* aSelf
, RunningMode aRunningMode
,
172 int SetName(char const* aName
);
173 int RegisterDeviceChangedCallback(
174 cubeb_device_changed_callback aDeviceChangedCallback
);
176 cubeb_stream
* AsCubebStream();
177 static MockCubebStream
* AsMock(cubeb_stream
* aStream
);
179 char const* StreamName() const { return mName
.get(); }
180 cubeb_devid
GetInputDeviceID() const;
181 cubeb_devid
GetOutputDeviceID() const;
183 uint32_t InputChannels() const;
184 uint32_t OutputChannels() const;
185 uint32_t SampleRate() const;
186 uint32_t InputFrequency() const;
188 void SetDriftFactor(float aDriftFactor
);
190 void ForceDeviceChanged();
193 // For RunningMode::Manual, drive this MockCubebStream forward.
194 KeepProcessing
ManualDataCallback(long aNrFrames
);
196 // Enable input recording for this driver. This is best called before
197 // the thread is running, but is safe to call whenever.
198 void SetOutputRecordingEnabled(bool aEnabled
);
199 // Enable input recording for this driver. This is best called before
200 // the thread is running, but is safe to call whenever.
201 void SetInputRecordingEnabled(bool aEnabled
);
202 // Get the recorded output from this stream. This doesn't copy, and therefore
204 nsTArray
<AudioDataValue
>&& TakeRecordedOutput();
205 // Get the recorded input from this stream. This doesn't copy, and therefore
207 nsTArray
<AudioDataValue
>&& TakeRecordedInput();
209 MediaEventSource
<nsCString
>& NameSetEvent();
210 MediaEventSource
<cubeb_state
>& StateEvent();
211 MediaEventSource
<uint32_t>& FramesProcessedEvent();
212 MediaEventSource
<uint32_t>& FramesVerifiedEvent();
213 MediaEventSource
<std::tuple
<uint64_t, float, uint32_t>>&
214 OutputVerificationEvent();
215 MediaEventSource
<void>& ErrorForcedEvent();
216 MediaEventSource
<void>& DeviceChangeForcedEvent();
219 KeepProcessing
Process(long aNrFrames
);
220 KeepProcessing
Process10Ms();
223 const RunningMode mRunningMode
;
224 const bool mHasInput
;
225 const bool mHasOutput
;
226 SmartMockCubebStream
* const mSelf
;
229 void NotifyState(cubeb_state aState
);
231 static constexpr long kMaxNrFrames
= 1920;
232 // Monitor used to block start until mFrozenStart is false.
233 Monitor mFrozenStartMonitor MOZ_UNANNOTATED
;
234 // Whether this stream should wait for an explicit start request before
235 // starting. Protected by FrozenStartMonitor.
237 // Used to abort a frozen start if cubeb_stream_start() is called currently
238 // with a blocked cubeb_stream_start() call.
239 std::atomic_bool mStreamStop
{true};
240 // Whether or not the output-side of this stream (what is written from the
241 // callback output buffer) is recorded in an internal buffer. The data is then
242 // available via `GetRecordedOutput`.
243 std::atomic_bool mOutputRecordingEnabled
{false};
244 // Whether or not the input-side of this stream (what is written from the
245 // callback input buffer) is recorded in an internal buffer. The data is then
246 // available via `TakeRecordedInput`.
247 std::atomic_bool mInputRecordingEnabled
{false};
248 // The audio buffer used on data callback.
249 AudioDataValue mOutputBuffer
[MAX_OUTPUT_CHANNELS
* kMaxNrFrames
] = {};
250 AudioDataValue mInputBuffer
[MAX_INPUT_CHANNELS
* kMaxNrFrames
] = {};
251 // The audio callback
252 cubeb_data_callback mDataCallback
= nullptr;
253 // The stream state callback
254 cubeb_state_callback mStateCallback
= nullptr;
255 // The device changed callback
256 cubeb_device_changed_callback mDeviceChangedCallback
= nullptr;
257 // A name for this stream
260 cubeb_stream_params mOutputParams
= {};
261 cubeb_stream_params mInputParams
= {};
263 cubeb_devid mInputDeviceID
;
264 cubeb_devid mOutputDeviceID
;
266 std::atomic
<float> mDriftFactor
{1.0};
267 std::atomic_bool mFastMode
{false};
268 std::atomic_bool mForceErrorState
{false};
269 std::atomic_bool mForceDeviceChanged
{false};
270 std::atomic_bool mDestroyed
{false};
271 std::atomic
<uint64_t> mPosition
{0};
272 AudioGenerator
<AudioDataValue
> mAudioGenerator
;
273 AudioVerifier
<AudioDataValue
> mAudioVerifier
;
275 MediaEventProducer
<nsCString
> mNameSetEvent
;
276 MediaEventProducer
<cubeb_state
> mStateEvent
;
277 MediaEventProducer
<uint32_t> mFramesProcessedEvent
;
278 MediaEventProducer
<uint32_t> mFramesVerifiedEvent
;
279 MediaEventProducer
<std::tuple
<uint64_t, float, uint32_t>>
280 mOutputVerificationEvent
;
281 MediaEventProducer
<void> mErrorForcedEvent
;
282 MediaEventProducer
<void> mDeviceChangedForcedEvent
;
283 // The recorded data, copied from the output_buffer of the callback.
285 nsTArray
<AudioDataValue
> mRecordedOutput
;
286 // The recorded data, copied from the input buffer of the callback.
288 nsTArray
<AudioDataValue
> mRecordedInput
;
291 class SmartMockCubebStream
292 : public MockCubebStream
,
293 public SupportsThreadSafeWeakPtr
<SmartMockCubebStream
> {
295 MOZ_DECLARE_REFCOUNTED_TYPENAME(SmartMockCubebStream
)
296 SmartMockCubebStream(cubeb
* aContext
, char const* aStreamName
,
297 cubeb_devid aInputDevice
,
298 cubeb_stream_params
* aInputStreamParams
,
299 cubeb_devid aOutputDevice
,
300 cubeb_stream_params
* aOutputStreamParams
,
301 cubeb_data_callback aDataCallback
,
302 cubeb_state_callback aStateCallback
, void* aUserPtr
,
303 RunningMode aRunningMode
, bool aFrozenStart
)
304 : MockCubebStream(aContext
, aStreamName
, aInputDevice
, aInputStreamParams
,
305 aOutputDevice
, aOutputStreamParams
, aDataCallback
,
306 aStateCallback
, aUserPtr
, this, aRunningMode
,
310 // This class has two facets: it is both a fake cubeb backend that is intended
311 // to be used for testing, and passed to Gecko code that expects a normal
312 // backend, but is also controllable by the test code to decide what the backend
313 // should do, depending on what is being tested.
315 // This needs to have the exact same memory layout as a real cubeb backend.
316 // It's very important for the `ops` member to be the very first member of
317 // the class, and for MockCubeb to not have any virtual members (to avoid
318 // having a vtable), so that AsMock() returns a pointer to this that can be
319 // used as a cubeb backend.
320 const cubeb_ops
* ops
;
321 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MockCubeb
);
324 using RunningMode
= MockCubebStream::RunningMode
;
327 explicit MockCubeb(RunningMode aRunningMode
);
328 // Cubeb backend implementation
329 // This allows passing this class as a cubeb* instance.
330 // cubeb_destroy(context) should eventually be called on the return value
331 // iff this method is called.
332 cubeb
* AsCubebContext();
333 static MockCubeb
* AsMock(cubeb
* aContext
);
335 // Fill in the collection parameter with all devices of aType.
336 int EnumerateDevices(cubeb_device_type aType
,
337 cubeb_device_collection
* aCollection
);
338 // Clear the collection parameter and deallocate its related memory space.
339 int DestroyDeviceCollection(cubeb_device_collection
* aCollection
);
341 // For a given device type, add a callback, called with a user pointer, when
342 // the device collection for this backend changes (i.e. a device has been
343 // removed or added).
344 int RegisterDeviceCollectionChangeCallback(
345 cubeb_device_type aDevType
,
346 cubeb_device_collection_changed_callback aCallback
, void* aUserPtr
);
350 // Add an input or output device to this backend. This calls the device
351 // collection invalidation callback if needed.
352 void AddDevice(cubeb_device_info aDevice
);
353 // Remove a specific input or output device to this backend, returns true if
354 // a device was removed. This calls the device collection invalidation
355 // callback if needed.
356 bool RemoveDevice(cubeb_devid aId
);
357 // Remove all input or output devices from this backend, without calling the
358 // callback. This is meant to clean up in between tests.
359 void ClearDevices(cubeb_device_type aType
);
361 // This allows simulating a backend that does not support setting a device
362 // collection invalidation callback, to be able to test the fallback path.
363 void SetSupportDeviceChangeCallback(bool aSupports
);
365 // This causes the next stream init with this context to return failure;
366 void ForceStreamInitError();
368 // Makes MockCubebStreams starting after this point wait for AllowStart().
369 // Callers must ensure they get a hold of the stream through StreamInitEvent
370 // to be able to start them.
371 void SetStreamStartFreezeEnabled(bool aEnabled
);
373 // Helper class that automatically unforces a forced audio thread on release.
374 class AudioThreadAutoUnforcer
{
375 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(AudioThreadAutoUnforcer
)
378 explicit AudioThreadAutoUnforcer(MockCubeb
* aContext
)
379 : mContext(aContext
) {}
382 virtual ~AudioThreadAutoUnforcer() { mContext
->UnforceAudioThread(); }
386 // Creates the audio thread if one is not available. The audio thread remains
387 // forced until UnforceAudioThread is called. The returned promise is resolved
388 // when the audio thread is running. With this, a test can ensure starting
389 // audio streams is deterministically fast across platforms for more accurate
391 using ForcedAudioThreadPromise
=
392 MozPromise
<RefPtr
<AudioThreadAutoUnforcer
>, nsresult
, false>;
393 RefPtr
<ForcedAudioThreadPromise
> ForceAudioThread();
395 // Allows a forced audio thread to stop.
396 void UnforceAudioThread();
398 int StreamInit(cubeb
* aContext
, cubeb_stream
** aStream
,
399 char const* aStreamName
, cubeb_devid aInputDevice
,
400 cubeb_stream_params
* aInputStreamParams
,
401 cubeb_devid aOutputDevice
,
402 cubeb_stream_params
* aOutputStreamParams
,
403 cubeb_data_callback aDataCallback
,
404 cubeb_state_callback aStateCallback
, void* aUserPtr
);
406 void StreamDestroy(MockCubebStream
* aStream
);
411 MediaEventSource
<RefPtr
<SmartMockCubebStream
>>& StreamInitEvent();
412 MediaEventSource
<RefPtr
<SmartMockCubebStream
>>& StreamDestroyEvent();
414 // MockCubeb specific API
415 void StartStream(MockCubebStream
* aStream
);
416 void StopStream(MockCubebStream
* aStream
);
418 // Simulates the audio thread. The thread is created at Start and destroyed
419 // at Stop. At next StreamStart a new thread is created.
420 static void ThreadFunction_s(MockCubeb
* aContext
) {
421 aContext
->ThreadFunction();
424 void ThreadFunction();
428 // The callback to call when the device list has been changed.
429 cubeb_device_collection_changed_callback
430 mInputDeviceCollectionChangeCallback
= nullptr;
431 cubeb_device_collection_changed_callback
432 mOutputDeviceCollectionChangeCallback
= nullptr;
433 // The pointer to pass in the callback.
434 void* mInputDeviceCollectionChangeUserPtr
= nullptr;
435 void* mOutputDeviceCollectionChangeUserPtr
= nullptr;
436 void* mUserPtr
= nullptr;
437 // Whether or not this backend supports device collection change
438 // notification via a system callback. If not, Gecko is expected to re-query
439 // the list every time.
440 bool mSupportsDeviceCollectionChangedCallback
= true;
441 const RunningMode mRunningMode
;
442 Atomic
<bool> mStreamInitErrorState
;
443 // Whether new MockCubebStreams should be frozen on start.
444 Atomic
<bool> mStreamStartFreezeEnabled
{false};
445 // Whether the audio thread is forced, i.e., whether it remains active even
446 // with no live streams.
447 Atomic
<bool> mForcedAudioThread
{false};
448 Atomic
<bool> mHasCubebContext
{false};
449 Atomic
<bool> mDestroyed
{false};
450 MozPromiseHolder
<ForcedAudioThreadPromise
> mForcedAudioThreadPromise
;
451 // Our input and output devices.
452 nsTArray
<cubeb_device_info
> mInputDevices
;
453 nsTArray
<cubeb_device_info
> mOutputDevices
;
455 // The streams that are currently running.
456 DataMutex
<nsTArray
<RefPtr
<SmartMockCubebStream
>>> mLiveStreams
{
457 "MockCubeb::mLiveStreams"};
458 // Thread that simulates the audio thread, shared across MockCubebStreams to
459 // avoid unintended drift. This is set together with mLiveStreams, under the
460 // mLiveStreams DataMutex.
461 UniquePtr
<std::thread
> mFakeAudioThread
;
462 // Whether to run the fake audio thread in fast mode, not caring about wall
463 // clock time. false is default and means data is processed every 10ms. When
464 // true we sleep(0) between iterations instead of 10ms.
465 std::atomic
<bool> mFastMode
{false};
467 MediaEventProducer
<RefPtr
<SmartMockCubebStream
>> mStreamInitEvent
;
468 MediaEventProducer
<RefPtr
<SmartMockCubebStream
>> mStreamDestroyEvent
;
471 int cubeb_mock_enumerate_devices(cubeb
* context
, cubeb_device_type type
,
472 cubeb_device_collection
* out
) {
473 return MockCubeb::AsMock(context
)->EnumerateDevices(type
, out
);
476 int cubeb_mock_device_collection_destroy(cubeb
* context
,
477 cubeb_device_collection
* collection
) {
478 return MockCubeb::AsMock(context
)->DestroyDeviceCollection(collection
);
481 int cubeb_mock_register_device_collection_changed(
482 cubeb
* context
, cubeb_device_type devtype
,
483 cubeb_device_collection_changed_callback callback
, void* user_ptr
) {
484 return MockCubeb::AsMock(context
)->RegisterDeviceCollectionChangeCallback(
485 devtype
, callback
, user_ptr
);
488 int cubeb_mock_stream_init(
489 cubeb
* context
, cubeb_stream
** stream
, char const* stream_name
,
490 cubeb_devid input_device
, cubeb_stream_params
* input_stream_params
,
491 cubeb_devid output_device
, cubeb_stream_params
* output_stream_params
,
492 unsigned int latency
, cubeb_data_callback data_callback
,
493 cubeb_state_callback state_callback
, void* user_ptr
) {
494 return MockCubeb::AsMock(context
)->StreamInit(
495 context
, stream
, stream_name
, input_device
, input_stream_params
,
496 output_device
, output_stream_params
, data_callback
, state_callback
,
500 int cubeb_mock_stream_start(cubeb_stream
* stream
) {
501 return MockCubebStream::AsMock(stream
)->Start();
504 int cubeb_mock_stream_stop(cubeb_stream
* stream
) {
505 return MockCubebStream::AsMock(stream
)->Stop();
508 int cubeb_mock_stream_get_position(cubeb_stream
* stream
, uint64_t* position
) {
509 *position
= MockCubebStream::AsMock(stream
)->Position();
513 void cubeb_mock_stream_destroy(cubeb_stream
* stream
) {
514 MockCubebStream::AsMock(stream
)->Destroy();
517 static char const* cubeb_mock_get_backend_id(cubeb
* context
) {
518 #if defined(XP_MACOSX)
520 #elif defined(XP_WIN)
522 #elif defined(ANDROID)
524 #elif defined(__OpenBSD__)
531 static int cubeb_mock_stream_set_volume(cubeb_stream
* stream
, float volume
) {
535 static int cubeb_mock_stream_set_name(cubeb_stream
* stream
,
536 char const* stream_name
) {
537 return MockCubebStream::AsMock(stream
)->SetName(stream_name
);
541 int cubeb_mock_stream_register_device_changed_callback(
542 cubeb_stream
* stream
,
543 cubeb_device_changed_callback device_changed_callback
) {
544 return MockCubebStream::AsMock(stream
)->RegisterDeviceChangedCallback(
545 device_changed_callback
);
548 int cubeb_mock_get_min_latency(cubeb
* context
, cubeb_stream_params params
,
549 uint32_t* latency_ms
) {
554 int cubeb_mock_get_preferred_sample_rate(cubeb
* context
, uint32_t* rate
) {
559 int cubeb_mock_get_max_channel_count(cubeb
* context
, uint32_t* max_channels
) {
560 *max_channels
= MAX_OUTPUT_CHANNELS
;
564 void PrintDevice(cubeb_device_info aInfo
);
566 void PrintDevice(AudioDeviceInfo
* aInfo
);
568 cubeb_device_info
DeviceTemplate(cubeb_devid aId
, cubeb_device_type aType
,
571 cubeb_device_info
DeviceTemplate(cubeb_devid aId
, cubeb_device_type aType
);
573 void AddDevices(MockCubeb
* mock
, uint32_t device_count
,
574 cubeb_device_type deviceType
);
576 } // namespace mozilla
578 #endif // MOCKCUBEB_H_