Bug 1869043 rename MockCubebStream::InputSampleRate() SampleRate() r=pehrsons
[gecko.git] / dom / media / gtest / MockCubeb.h
blobc744a20051f5ae327471889b5b26b62d0e2ac56a
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/. */
5 #ifndef MOCKCUBEB_H_
6 #define MOCKCUBEB_H_
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"
15 #include "nsTArray.h"
17 #include <thread>
18 #include <atomic>
19 #include <chrono>
21 namespace mozilla {
22 const uint32_t MAX_OUTPUT_CHANNELS = 2;
23 const uint32_t MAX_INPUT_CHANNELS = 2;
25 struct cubeb_ops {
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)(
56 cubeb_stream* stream,
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
64 // cubeb-internal.h
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,
88 uint64_t* position);
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 = {
114 /*.init =*/NULL,
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.
149 cubeb* context;
150 void* mUserPtr;
152 public:
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,
164 bool aFrozenStart);
166 ~MockCubebStream();
168 int Start();
169 int Stop();
170 uint64_t Position();
171 void Destroy();
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);
189 void ForceError();
190 void ForceDeviceChanged();
191 void Thaw();
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
203 // only works once.
204 nsTArray<AudioDataValue>&& TakeRecordedOutput();
205 // Get the recorded input from this stream. This doesn't copy, and therefore
206 // only works once.
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();
218 private:
219 KeepProcessing Process(long aNrFrames);
220 KeepProcessing Process10Ms();
222 public:
223 const RunningMode mRunningMode;
224 const bool mHasInput;
225 const bool mHasOutput;
226 SmartMockCubebStream* const mSelf;
228 private:
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.
236 bool mFrozenStart;
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
258 nsCString mName;
259 // The stream params
260 cubeb_stream_params mOutputParams = {};
261 cubeb_stream_params mInputParams = {};
262 /* Device IDs */
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.
284 // Interleaved.
285 nsTArray<AudioDataValue> mRecordedOutput;
286 // The recorded data, copied from the input buffer of the callback.
287 // Interleaved.
288 nsTArray<AudioDataValue> mRecordedInput;
291 class SmartMockCubebStream
292 : public MockCubebStream,
293 public SupportsThreadSafeWeakPtr<SmartMockCubebStream> {
294 public:
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,
307 aFrozenStart) {}
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.
314 class MockCubeb {
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);
323 public:
324 using RunningMode = MockCubebStream::RunningMode;
326 MockCubeb();
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);
334 void Destroy();
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);
348 // Control API
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)
377 public:
378 explicit AudioThreadAutoUnforcer(MockCubeb* aContext)
379 : mContext(aContext) {}
381 protected:
382 virtual ~AudioThreadAutoUnforcer() { mContext->UnforceAudioThread(); }
383 MockCubeb* mContext;
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
390 // results.
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);
408 void GoFaster();
409 void DontGoFaster();
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();
426 private:
427 ~MockCubeb();
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,
497 user_ptr);
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();
510 return CUBEB_OK;
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)
519 return "audiounit";
520 #elif defined(XP_WIN)
521 return "wasapi";
522 #elif defined(ANDROID)
523 return "opensl";
524 #elif defined(__OpenBSD__)
525 return "sndio";
526 #else
527 return "pulse";
528 #endif
531 static int cubeb_mock_stream_set_volume(cubeb_stream* stream, float volume) {
532 return CUBEB_OK;
535 static int cubeb_mock_stream_set_name(cubeb_stream* stream,
536 char const* stream_name) {
537 return MockCubebStream::AsMock(stream)->SetName(stream_name);
538 return CUBEB_OK;
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) {
550 *latency_ms = 10;
551 return CUBEB_OK;
554 int cubeb_mock_get_preferred_sample_rate(cubeb* context, uint32_t* rate) {
555 *rate = 44100;
556 return CUBEB_OK;
559 int cubeb_mock_get_max_channel_count(cubeb* context, uint32_t* max_channels) {
560 *max_channels = MAX_OUTPUT_CHANNELS;
561 return CUBEB_OK;
564 void PrintDevice(cubeb_device_info aInfo);
566 void PrintDevice(AudioDeviceInfo* aInfo);
568 cubeb_device_info DeviceTemplate(cubeb_devid aId, cubeb_device_type aType,
569 const char* name);
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_