ma_backend_callbacks class final
These are the callbacks required to be implemented for a backend. These callbacks are grouped into two parts: context and device. There is one context to many devices. A device is created from a context.
The general flow goes like this:
- A context is created with
onContextInit()1a) Available devices can be enumerated withonContextEnumerateDevices()if required. 1b) Detailed information about a device can be queried withonContextGetDeviceInfo()if required. - A device is created from the context that was created in the first step using
onDeviceInit(), and optionally a device ID that was selected from device enumeration viaonContextEnumerateDevices(). - A device is started or stopped with
onDeviceStart()/onDeviceStop() - Data is delivered to and from the device by the backend. This is always done based on the native format returned by the prior call
to
onDeviceInit(). Conversion between the device's native format and the format requested by the application will be handled by miniaudio internally.
Initialization of the context is quite simple. You need to do any necessary initialization of internal objects and then output the callbacks defined in this structure.
Once the context has been initialized you can initialize a device. Before doing so, however, the application may want to know which
physical devices are available. This is where onContextEnumerateDevices() comes in. This is fairly simple. For each device, fire the
given callback with, at a minimum, the basic information filled out in ma_device_info. When the callback returns MA_FALSE, enumeration
needs to stop and the onContextEnumerateDevices() function returns with a success code.
Detailed device information can be retrieved from a device ID using onContextGetDeviceInfo(). This takes as input the device type and ID,
and on output returns detailed information about the device in ma_device_info. The onContextGetDeviceInfo() callback must handle the
case when the device ID is NULL, in which case information about the default device needs to be retrieved.
Once the context has been created and the device ID retrieved (if using anything other than the default device), the device can be created. This is a little bit more complicated than initialization of the context due to it's more complicated configuration. When initializing a device, a duplex device may be requested. This means a separate data format needs to be specified for both playback and capture. On input, the data format is set to what the application wants. On output it's set to the native format which should match as closely as possible to the requested format. The conversion between the format requested by the application and the device's native format will be handled internally by miniaudio.
On input, if the sample format is set to ma_format_unknown, the backend is free to use whatever sample format it desires, so long as it's
supported by miniaudio. When the channel count is set to 0, the backend should use the device's native channel count. The same applies for
sample rate. For the channel map, the default should be used when ma_channel_map_is_blank() returns true (all channels set to
MA_CHANNEL_NONE). On input, the periodSizeInFrames or periodSizeInMilliseconds option should always be set. The backend should
inspect both of these variables. If periodSizeInFrames is set, it should take priority, otherwise it needs to be derived from the period
size in milliseconds (periodSizeInMilliseconds) and the sample rate, keeping in mind that the sample rate may be 0, in which case the
sample rate will need to be determined before calculating the period size in frames. On output, all members of the ma_device_descriptor
object should be set to a valid value, except for periodSizeInMilliseconds which is optional (periodSizeInFrames must be set).
Starting and stopping of the device is done with onDeviceStart() and onDeviceStop() and should be self-explanatory. If the backend uses
asynchronous reading and writing, onDeviceStart() and onDeviceStop() should always be implemented.
The handling of data delivery between the application and the device is the most complicated part of the process. To make this a bit
easier, some helper callbacks are available. If the backend uses a blocking read/write style of API, the onDeviceRead() and
onDeviceWrite() callbacks can optionally be implemented. These are blocking and work just like reading and writing from a file. If the
backend uses a callback for data delivery, that callback must call ma_device_handle_backend_data_callback() from within it's callback.
This allows miniaudio to then process any necessary data conversion and then pass it to the miniaudio data callback.
If the backend requires absolute flexibility with it's data delivery, it can optionally implement the onDeviceDataLoop() callback
which will allow it to implement the logic that will run on the audio thread. This is much more advanced and is completely optional.
The audio thread should run data delivery logic in a loop while ma_device_get_state() == ma_device_state_started and no errors have been
encountered. Do not start or stop the device here. That will be handled from outside the onDeviceDataLoop() callback.
The invocation of the onDeviceDataLoop() callback will be handled by miniaudio. When you start the device, miniaudio will fire this
callback. When the device is stopped, the ma_device_get_state() == ma_device_state_started condition will fail and the loop will be terminated
which will then fall through to the part that stops the device. For an example on how to implement the onDeviceDataLoop() callback,
look at ma_device_audio_thread__default_read_write(). Implement the onDeviceDataLoopWakeup() callback if you need a mechanism to
wake up the audio thread.
If the backend supports an optimized retrieval of device information from an initialized ma_device object, it should implement the
onDeviceGetInfo() callback. This is optional, in which case it will fall back to onContextGetDeviceInfo() which is less efficient.
- Inheritance
- Implemented types
- Available extensions
Constructors
Properties
-
address
→ Pointer<
T> -
Available on T, provided by the StructAddress extension
The memory address of the underlying data.no setter - hashCode → int
-
The hash code for this object.
no setterinherited
-
onContextEnumerateDevices
↔ Pointer<
NativeFunction< Int Function(Pointer< >ma_context> pContext, ma_enum_devices_callback_proc callback, Pointer<Void> pUserData)> -
getter/setter pair
-
onContextGetDeviceInfo
↔ Pointer<
NativeFunction< Int Function(Pointer< >ma_context> pContext, UnsignedInt deviceType, Pointer<ma_device_id> pDeviceID, Pointer<ma_device_info> pDeviceInfo)> -
getter/setter pair
-
onContextInit
↔ Pointer<
NativeFunction< Int Function(Pointer< >ma_context> pContext, Pointer<ma_context_config> pConfig, Pointer<ma_backend_callbacks> pCallbacks)> -
getter/setter pair
-
onContextUninit
↔ Pointer<
NativeFunction< Int Function(Pointer< >ma_context> pContext)> -
getter/setter pair
-
onDeviceDataLoop
↔ Pointer<
NativeFunction< Int Function(Pointer< >ma_device> pDevice)> -
getter/setter pair
-
onDeviceDataLoopWakeup
↔ Pointer<
NativeFunction< Int Function(Pointer< >ma_device> pDevice)> -
getter/setter pair
-
onDeviceGetInfo
↔ Pointer<
NativeFunction< Int Function(Pointer< >ma_device> pDevice, UnsignedInt type, Pointer<ma_device_info> pDeviceInfo)> -
getter/setter pair
-
onDeviceInit
↔ Pointer<
NativeFunction< Int Function(Pointer< >ma_device> pDevice, Pointer<ma_device_config> pConfig, Pointer<ma_device_descriptor> pDescriptorPlayback, Pointer<ma_device_descriptor> pDescriptorCapture)> -
getter/setter pair
-
onDeviceRead
↔ Pointer<
NativeFunction< Int Function(Pointer< >ma_device> pDevice, Pointer<Void> pFrames, ma_uint32 frameCount, Pointer<ma_uint32> pFramesRead)> -
getter/setter pair
-
onDeviceStart
↔ Pointer<
NativeFunction< Int Function(Pointer< >ma_device> pDevice)> -
getter/setter pair
-
onDeviceStop
↔ Pointer<
NativeFunction< Int Function(Pointer< >ma_device> pDevice)> -
getter/setter pair
-
onDeviceUninit
↔ Pointer<
NativeFunction< Int Function(Pointer< >ma_device> pDevice)> -
getter/setter pair
-
onDeviceWrite
↔ Pointer<
NativeFunction< Int Function(Pointer< >ma_device> pDevice, Pointer<Void> pFrames, ma_uint32 frameCount, Pointer<ma_uint32> pFramesWritten)> -
getter/setter pair
- runtimeType → Type
-
A representation of the runtime type of the object.
no setterinherited
Methods
-
noSuchMethod(
Invocation invocation) → dynamic -
Invoked when a nonexistent method or property is accessed.
inherited
-
toString(
) → String -
A string representation of this object.
inherited
Operators
-
operator ==(
Object other) → bool -
The equality operator.
inherited