Commit 922b5846 authored by David Reid's avatar David Reid

Introduce a new device notification system.

This replaces the stop callback. The new callback supports different
event types, not all of which are supported on all backends.

This commit also fixes a bug where the stop callback is not fired.

Public issue https://github.com/mackron/miniaudio/issues/351
parent 2bd5011b
...@@ -5750,6 +5750,69 @@ typedef enum ...@@ -5750,6 +5750,69 @@ typedef enum
#define MA_BACKEND_COUNT (ma_backend_null+1) #define MA_BACKEND_COUNT (ma_backend_null+1)
/* Device notification types. */
typedef enum
{
ma_device_notification_type_started,
ma_device_notification_type_stopped,
ma_device_notification_type_rerouted,
ma_device_notification_type_interruption_began,
ma_device_notification_type_interruption_ended
} ma_device_notification_type;
typedef struct
{
ma_device* pDevice;
ma_device_notification_type type;
union
{
struct
{
int __unused;
} started;
struct
{
int __unused;
} stopped;
struct
{
int __unused;
} rerouted;
struct
{
int __unused;
} interruption;
} data;
} ma_device_notification;
/*
The notification callback for when the application should be notified of a change to the device.
This callback is used for notifying the application of changes such as when the device has started,
stopped, rerouted or an interruption has occurred. Note that not all backends will post all
notification types. For example, some backends will perform automatic stream routing without any
kind of notification to the host program which means miniaudio will never know about it and will
never be able to fire the rerouted notification. You should keep this in mind when designing your
program.
The stopped notification will *not* get fired when a device is rerouted.
Parameters
----------
pNotification (in)
A pointer to a structure containing information about the event. Use the `pDevice` member of
this object to retrieve the relevant device. The `type` member can be used to discriminate
against each of the notification types.
Remarks
-------
Do not restart or uninitialize the device from the callback.
*/
typedef void (* ma_device_notification_proc)(const ma_device_notification* pNotification);
/* /*
The callback for processing audio data from the device. The callback for processing audio data from the device.
...@@ -5792,7 +5855,12 @@ The proper way to stop the device is to call `ma_device_stop()` from a different ...@@ -5792,7 +5855,12 @@ The proper way to stop the device is to call `ma_device_stop()` from a different
*/ */
typedef void (* ma_device_data_proc)(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount); typedef void (* ma_device_data_proc)(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount);
/* /*
DEPRECATED. Use ma_device_notification_proc instead.
The callback for when the device has been stopped. The callback for when the device has been stopped.
This will be called when the device is stopped explicitly with `ma_device_stop()` and also called implicitly when the device is stopped through external forces This will be called when the device is stopped explicitly with `ma_device_stop()` and also called implicitly when the device is stopped through external forces
...@@ -5809,7 +5877,7 @@ Remarks ...@@ -5809,7 +5877,7 @@ Remarks
------- -------
Do not restart or uninitialize the device from the callback. Do not restart or uninitialize the device from the callback.
*/ */
typedef void (* ma_stop_proc)(ma_device* pDevice); typedef void (* ma_stop_proc)(ma_device* pDevice); /* DEPRECATED. Use ma_device_notification_proc instead. */
typedef enum typedef enum
{ {
...@@ -5988,6 +6056,7 @@ struct ma_device_config ...@@ -5988,6 +6056,7 @@ struct ma_device_config
ma_bool8 noClip; /* When set to true, the contents of the output buffer passed into the data callback will be clipped after returning. Only applies when the playback sample format is f32. */ ma_bool8 noClip; /* When set to true, the contents of the output buffer passed into the data callback will be clipped after returning. Only applies when the playback sample format is f32. */
ma_bool8 noDisableDenormals; /* Do not disable denormals when firing the data callback. */ ma_bool8 noDisableDenormals; /* Do not disable denormals when firing the data callback. */
ma_device_data_proc dataCallback; ma_device_data_proc dataCallback;
ma_device_notification_proc notificationCallback;
ma_stop_proc stopCallback; ma_stop_proc stopCallback;
void* pUserData; void* pUserData;
ma_resampler_config resampling; ma_resampler_config resampling;
...@@ -6644,21 +6713,22 @@ struct ma_device ...@@ -6644,21 +6713,22 @@ struct ma_device
ma_device_type type; ma_device_type type;
ma_uint32 sampleRate; ma_uint32 sampleRate;
MA_ATOMIC(4, ma_device_state) state; /* The state of the device is variable and can change at any time on any thread. Must be used atomically. */ MA_ATOMIC(4, ma_device_state) state; /* The state of the device is variable and can change at any time on any thread. Must be used atomically. */
ma_device_data_proc onData; /* Set once at initialization time and should not be changed after. */ ma_device_data_proc onData; /* Set once at initialization time and should not be changed after. */
ma_stop_proc onStop; /* Set once at initialization time and should not be changed after. */ ma_device_notification_proc onNotification; /* Set once at initialization time and should not be changed after. */
void* pUserData; /* Application defined data. */ ma_stop_proc onStop; /* DEPRECATED. Use the notification callback instead. Set once at initialization time and should not be changed after. */
void* pUserData; /* Application defined data. */
ma_mutex startStopLock; ma_mutex startStopLock;
ma_event wakeupEvent; ma_event wakeupEvent;
ma_event startEvent; ma_event startEvent;
ma_event stopEvent; ma_event stopEvent;
ma_thread thread; ma_thread thread;
ma_result workResult; /* This is set by the worker thread after it's finished doing a job. */ ma_result workResult; /* This is set by the worker thread after it's finished doing a job. */
ma_bool8 isOwnerOfContext; /* When set to true, uninitializing the device will also uninitialize the context. Set to true when NULL is passed into ma_device_init(). */ ma_bool8 isOwnerOfContext; /* When set to true, uninitializing the device will also uninitialize the context. Set to true when NULL is passed into ma_device_init(). */
ma_bool8 noPreSilencedOutputBuffer; ma_bool8 noPreSilencedOutputBuffer;
ma_bool8 noClip; ma_bool8 noClip;
ma_bool8 noDisableDenormals; ma_bool8 noDisableDenormals;
MA_ATOMIC(4, float) masterVolumeFactor; /* Linear 0..1. Can be read and written simultaneously by different threads. Must be used atomically. */ MA_ATOMIC(4, float) masterVolumeFactor; /* Linear 0..1. Can be read and written simultaneously by different threads. Must be used atomically. */
ma_duplex_rb duplexRB; /* Intermediary buffer for duplex device on asynchronous backends. */ ma_duplex_rb duplexRB; /* Intermediary buffer for duplex device on asynchronous backends. */
struct struct
{ {
ma_resample_algorithm algorithm; ma_resample_algorithm algorithm;
...@@ -7535,9 +7605,8 @@ then be set directly on the structure. Below are the members of the `ma_device_c ...@@ -7535,9 +7605,8 @@ then be set directly on the structure. Below are the members of the `ma_device_c
dataCallback dataCallback
The callback to fire whenever data is ready to be delivered to or from the device. The callback to fire whenever data is ready to be delivered to or from the device.
stopCallback notificationCallback
The callback to fire whenever the device has stopped, either explicitly via `ma_device_stop()`, or implicitly due to things like the device being The callback to fire when something has changed with the device, such as whether or not it has been started or stopped.
disconnected.
pUserData pUserData
The user data pointer to use with the device. You can access this directly from the device object like `device.pUserData`. The user data pointer to use with the device. You can access this directly from the device object like `device.pUserData`.
...@@ -16618,6 +16687,57 @@ static MA_INLINE void ma_device_restore_denormals(ma_device* pDevice, unsigned i ...@@ -16618,6 +16687,57 @@ static MA_INLINE void ma_device_restore_denormals(ma_device* pDevice, unsigned i
} }
} }
static ma_device_notification ma_device_notification_init(ma_device* pDevice, ma_device_notification_type type)
{
ma_device_notification notification;
MA_ZERO_OBJECT(&notification);
notification.pDevice = pDevice;
notification.type = type;
return notification;
}
static void ma_device__on_notification(ma_device_notification notification)
{
MA_ASSERT(notification.pDevice != NULL);
if (notification.pDevice->onNotification != NULL) {
notification.pDevice->onNotification(&notification);
}
/* TEMP FOR COMPATIBILITY: If it's a stopped notification, fire the onStop callback as well. This is only for backwards compatibility and will be removed. */
if (notification.pDevice->onStop != NULL && notification.type == ma_device_notification_type_stopped) {
notification.pDevice->onStop(notification.pDevice);
}
}
void ma_device__on_notification_started(ma_device* pDevice)
{
ma_device__on_notification(ma_device_notification_init(pDevice, ma_device_notification_type_started));
}
void ma_device__on_notification_stopped(ma_device* pDevice)
{
ma_device__on_notification(ma_device_notification_init(pDevice, ma_device_notification_type_stopped));
}
void ma_device__on_notification_rerouted(ma_device* pDevice)
{
ma_device__on_notification(ma_device_notification_init(pDevice, ma_device_notification_type_rerouted));
}
void ma_device__on_notification_interruption_began(ma_device* pDevice)
{
ma_device__on_notification(ma_device_notification_init(pDevice, ma_device_notification_type_interruption_began));
}
void ma_device__on_notification_interruption_ended(ma_device* pDevice)
{
ma_device__on_notification(ma_device_notification_init(pDevice, ma_device_notification_type_interruption_ended));
}
static void ma_device__on_data(ma_device* pDevice, void* pFramesOut, const void* pFramesIn, ma_uint32 frameCount) static void ma_device__on_data(ma_device* pDevice, void* pFramesOut, const void* pFramesIn, ma_uint32 frameCount)
{ {
float masterVolumeFactor; float masterVolumeFactor;
...@@ -27729,12 +27849,10 @@ static void ma_device_on_suspended__pulse(ma_pa_stream* pStream, void* pUserData ...@@ -27729,12 +27849,10 @@ static void ma_device_on_suspended__pulse(ma_pa_stream* pStream, void* pUserData
if (suspended == 1) { if (suspended == 1) {
ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[Pulse] Device suspended state changed. Suspended.\n"); ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[Pulse] Device suspended state changed. Suspended.\n");
ma_device__on_notification_stopped(pDevice);
if (pDevice->onStop) {
pDevice->onStop(pDevice);
}
} else { } else {
ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[Pulse] Device suspended state changed. Resumed.\n"); ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[Pulse] Device suspended state changed. Resumed.\n");
ma_device__on_notification_started(pDevice);
} }
} }
...@@ -29007,17 +29125,13 @@ static ma_result ma_device_start__jack(ma_device* pDevice) ...@@ -29007,17 +29125,13 @@ static ma_result ma_device_start__jack(ma_device* pDevice)
static ma_result ma_device_stop__jack(ma_device* pDevice) static ma_result ma_device_stop__jack(ma_device* pDevice)
{ {
ma_context* pContext = pDevice->pContext; ma_context* pContext = pDevice->pContext;
ma_stop_proc onStop;
if (((ma_jack_deactivate_proc)pContext->jack.jack_deactivate)((ma_jack_client_t*)pDevice->jack.pClient) != 0) { if (((ma_jack_deactivate_proc)pContext->jack.jack_deactivate)((ma_jack_client_t*)pDevice->jack.pClient) != 0) {
ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[JACK] An error occurred when deactivating the JACK client."); ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[JACK] An error occurred when deactivating the JACK client.");
return MA_ERROR; return MA_ERROR;
} }
onStop = pDevice->onStop; ma_device__on_notification_stopped(pDevice);
if (onStop) {
onStop(pDevice);
}
return MA_SUCCESS; return MA_SUCCESS;
} }
...@@ -30981,11 +31095,7 @@ static void on_start_stop__coreaudio(void* pUserData, AudioUnit audioUnit, Audio ...@@ -30981,11 +31095,7 @@ static void on_start_stop__coreaudio(void* pUserData, AudioUnit audioUnit, Audio
Audio APIs in the callback when the device has been stopped or uninitialized. Audio APIs in the callback when the device has been stopped or uninitialized.
*/ */
if (ma_device_get_state(pDevice) == ma_device_state_uninitialized || ma_device_get_state(pDevice) == ma_device_state_stopping || ma_device_get_state(pDevice) == ma_device_state_stopped) { if (ma_device_get_state(pDevice) == ma_device_state_uninitialized || ma_device_get_state(pDevice) == ma_device_state_stopping || ma_device_get_state(pDevice) == ma_device_state_stopped) {
ma_stop_proc onStop = pDevice->onStop; ma_device__on_notification_stopped(pDevice);
if (onStop) {
onStop(pDevice);
}
ma_event_signal(&pDevice->coreaudio.stopEvent); ma_event_signal(&pDevice->coreaudio.stopEvent);
} else { } else {
UInt32 isRunning; UInt32 isRunning;
...@@ -30996,8 +31106,6 @@ static void on_start_stop__coreaudio(void* pUserData, AudioUnit audioUnit, Audio ...@@ -30996,8 +31106,6 @@ static void on_start_stop__coreaudio(void* pUserData, AudioUnit audioUnit, Audio
} }
if (!isRunning) { if (!isRunning) {
ma_stop_proc onStop;
/* /*
The stop event is a bit annoying in Core Audio because it will be called when we automatically switch the default device. Some scenarios to consider: The stop event is a bit annoying in Core Audio because it will be called when we automatically switch the default device. Some scenarios to consider:
...@@ -31011,7 +31119,7 @@ static void on_start_stop__coreaudio(void* pUserData, AudioUnit audioUnit, Audio ...@@ -31011,7 +31119,7 @@ static void on_start_stop__coreaudio(void* pUserData, AudioUnit audioUnit, Audio
/* /*
It looks like the device is switching through an external event, such as the user unplugging the device or changing the default device It looks like the device is switching through an external event, such as the user unplugging the device or changing the default device
via the operating system's sound settings. If we're re-initializing the device, we just terminate because we want the stopping of the via the operating system's sound settings. If we're re-initializing the device, we just terminate because we want the stopping of the
device to be seamless to the client (we don't want them receiving the onStop event and thinking that the device has stopped when it device to be seamless to the client (we don't want them receiving the stopped event and thinking that the device has stopped when it
hasn't!). hasn't!).
*/ */
if (((audioUnit == pDevice->coreaudio.audioUnitPlayback) && pDevice->coreaudio.isSwitchingPlaybackDevice) || if (((audioUnit == pDevice->coreaudio.audioUnitPlayback) && pDevice->coreaudio.isSwitchingPlaybackDevice) ||
...@@ -31024,16 +31132,13 @@ static void on_start_stop__coreaudio(void* pUserData, AudioUnit audioUnit, Audio ...@@ -31024,16 +31132,13 @@ static void on_start_stop__coreaudio(void* pUserData, AudioUnit audioUnit, Audio
will try switching to the new default device seamlessly. We need to somehow find a way to determine whether or not Core Audio will most will try switching to the new default device seamlessly. We need to somehow find a way to determine whether or not Core Audio will most
likely be successful in switching to the new device. likely be successful in switching to the new device.
TODO: Try to predict if Core Audio will switch devices. If not, the onStop callback needs to be posted. TODO: Try to predict if Core Audio will switch devices. If not, the stopped callback needs to be posted.
*/ */
return; return;
} }
/* Getting here means we need to stop the device. */ /* Getting here means we need to stop the device. */
onStop = pDevice->onStop; ma_device__on_notification_stopped(pDevice);
if (onStop) {
onStop(pDevice);
}
} }
} }
...@@ -35360,8 +35465,6 @@ static ma_result ma_device_start__aaudio(ma_device* pDevice) ...@@ -35360,8 +35465,6 @@ static ma_result ma_device_start__aaudio(ma_device* pDevice)
static ma_result ma_device_stop__aaudio(ma_device* pDevice) static ma_result ma_device_stop__aaudio(ma_device* pDevice)
{ {
ma_stop_proc onStop;
MA_ASSERT(pDevice != NULL); MA_ASSERT(pDevice != NULL);
if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) { if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
...@@ -35378,10 +35481,7 @@ static ma_result ma_device_stop__aaudio(ma_device* pDevice) ...@@ -35378,10 +35481,7 @@ static ma_result ma_device_stop__aaudio(ma_device* pDevice)
} }
} }
onStop = pDevice->onStop; ma_device__on_notification_stopped(pDevice);
if (onStop) {
onStop(pDevice);
}
return MA_SUCCESS; return MA_SUCCESS;
} }
...@@ -36537,7 +36637,6 @@ static ma_result ma_device_drain__opensl(ma_device* pDevice, ma_device_type devi ...@@ -36537,7 +36637,6 @@ static ma_result ma_device_drain__opensl(ma_device* pDevice, ma_device_type devi
static ma_result ma_device_stop__opensl(ma_device* pDevice) static ma_result ma_device_stop__opensl(ma_device* pDevice)
{ {
SLresult resultSL; SLresult resultSL;
ma_stop_proc onStop;
MA_ASSERT(pDevice != NULL); MA_ASSERT(pDevice != NULL);
...@@ -36571,10 +36670,7 @@ static ma_result ma_device_stop__opensl(ma_device* pDevice) ...@@ -36571,10 +36670,7 @@ static ma_result ma_device_stop__opensl(ma_device* pDevice)
} }
/* Make sure the client is aware that the device has stopped. There may be an OpenSL|ES callback for this, but I haven't found it. */ /* Make sure the client is aware that the device has stopped. There may be an OpenSL|ES callback for this, but I haven't found it. */
onStop = pDevice->onStop; ma_device__on_notification_stopped(pDevice);
if (onStop) {
onStop(pDevice);
}
return MA_SUCCESS; return MA_SUCCESS;
} }
...@@ -37255,10 +37351,7 @@ static ma_result ma_device_stop__webaudio(ma_device* pDevice) ...@@ -37255,10 +37351,7 @@ static ma_result ma_device_stop__webaudio(ma_device* pDevice)
}, pDevice->webaudio.indexPlayback); }, pDevice->webaudio.indexPlayback);
} }
ma_stop_proc onStop = pDevice->onStop; ma_device__on_notification_stopped(pDevice);
if (onStop) {
onStop(pDevice);
}
return MA_SUCCESS; return MA_SUCCESS;
} }
...@@ -37587,7 +37680,7 @@ static ma_thread_result MA_THREADCALL ma_worker_thread(void* pData) ...@@ -37587,7 +37680,7 @@ static ma_thread_result MA_THREADCALL ma_worker_thread(void* pData)
for (;;) { /* <-- This loop just keeps the thread alive. The main audio loop is inside. */ for (;;) { /* <-- This loop just keeps the thread alive. The main audio loop is inside. */
ma_result startResult; ma_result startResult;
ma_result stopResult; /* <-- This will store the result from onDeviceStop(). If it returns an error, we don't fire the onStop callback. */ ma_result stopResult; /* <-- This will store the result from onDeviceStop(). If it returns an error, we don't fire the stopped notification callback. */
/* We wait on an event to know when something has requested that the device be started and the main loop entered. */ /* We wait on an event to know when something has requested that the device be started and the main loop entered. */
ma_event_wait(&pDevice->wakeupEvent); ma_event_wait(&pDevice->wakeupEvent);
...@@ -37623,6 +37716,8 @@ static ma_thread_result MA_THREADCALL ma_worker_thread(void* pData) ...@@ -37623,6 +37716,8 @@ static ma_thread_result MA_THREADCALL ma_worker_thread(void* pData)
ma_device__set_state(pDevice, ma_device_state_started); ma_device__set_state(pDevice, ma_device_state_started);
ma_event_signal(&pDevice->startEvent); ma_event_signal(&pDevice->startEvent);
ma_device__on_notification_started(pDevice);
if (pDevice->pContext->callbacks.onDeviceDataLoop != NULL) { if (pDevice->pContext->callbacks.onDeviceDataLoop != NULL) {
pDevice->pContext->callbacks.onDeviceDataLoop(pDevice); pDevice->pContext->callbacks.onDeviceDataLoop(pDevice);
} else { } else {
...@@ -37638,12 +37733,12 @@ static ma_thread_result MA_THREADCALL ma_worker_thread(void* pData) ...@@ -37638,12 +37733,12 @@ static ma_thread_result MA_THREADCALL ma_worker_thread(void* pData)
} }
/* /*
After the device has stopped, make sure an event is posted. Don't post an onStop event if After the device has stopped, make sure an event is posted. Don't post a stopped event if
stopping failed. This can happen on some backends when the underlying stream has been stopping failed. This can happen on some backends when the underlying stream has been
stopped due to the device being physically unplugged or disabled via an OS setting. stopped due to the device being physically unplugged or disabled via an OS setting.
*/ */
if (pDevice->onStop && stopResult != MA_SUCCESS) { if (stopResult == MA_SUCCESS) {
pDevice->onStop(pDevice); ma_device__on_notification_stopped(pDevice);
} }
/* A function somewhere is waiting for the device to have stopped for real so we need to signal an event to allow it to continue. */ /* A function somewhere is waiting for the device to have stopped for real so we need to signal an event to allow it to continue. */
...@@ -38315,9 +38410,10 @@ MA_API ma_result ma_device_init(ma_context* pContext, const ma_device_config* pC ...@@ -38315,9 +38410,10 @@ MA_API ma_result ma_device_init(ma_context* pContext, const ma_device_config* pC
pDevice->pContext = pContext; pDevice->pContext = pContext;
/* Set the user data and log callback ASAP to ensure it is available for the entire initialization process. */ /* Set the user data and log callback ASAP to ensure it is available for the entire initialization process. */
pDevice->pUserData = pConfig->pUserData; pDevice->pUserData = pConfig->pUserData;
pDevice->onData = pConfig->dataCallback; pDevice->onData = pConfig->dataCallback;
pDevice->onStop = pConfig->stopCallback; pDevice->onNotification = pConfig->notificationCallback;
pDevice->onStop = pConfig->stopCallback;
if (pConfig->playback.pDeviceID != NULL) { if (pConfig->playback.pDeviceID != NULL) {
MA_COPY_MEMORY(&pDevice->playback.id, pConfig->playback.pDeviceID, sizeof(pDevice->playback.id)); MA_COPY_MEMORY(&pDevice->playback.id, pConfig->playback.pDeviceID, sizeof(pDevice->playback.id));
...@@ -38811,6 +38907,7 @@ MA_API ma_result ma_device_start(ma_device* pDevice) ...@@ -38811,6 +38907,7 @@ MA_API ma_result ma_device_start(ma_device* pDevice)
if (result == MA_SUCCESS) { if (result == MA_SUCCESS) {
ma_device__set_state(pDevice, ma_device_state_started); ma_device__set_state(pDevice, ma_device_state_started);
ma_device__on_notification_started(pDevice);
} }
} else { } else {
/* /*
...@@ -89129,6 +89226,10 @@ There have also been some other smaller changes added to this release. ...@@ -89129,6 +89226,10 @@ There have also been some other smaller changes added to this release.
REVISION HISTORY REVISION HISTORY
================ ================
v0.11.2 - TBD v0.11.2 - TBD
- Add a new device notification system to replace the stop callback. The stop callback is still
in place, but will be removed in the next version. New code should use the notificationCallback
member in the device config instead of stopCallback.
- Fix a bug where the stopped notification doesn't get fired.
- iOS: The IO buffer size is now configured based on the device's configured period size. - iOS: The IO buffer size is now configured based on the device's configured period size.
- WebAudio: Optimizations to some JavaScript code. - WebAudio: Optimizations to some JavaScript code.
...@@ -13,13 +13,13 @@ will receive the captured audio. ...@@ -13,13 +13,13 @@ will receive the captured audio.
"backend" is one of the miniaudio backends: "backend" is one of the miniaudio backends:
wasapi wasapi
dsound dsound or directsound
winmm winmm
coreaudio coreaudio
sndio sndio
audio4 audio4
oss oss
pulseaudio pulseaudio or pulse
alsa alsa
jack jack
aaudio aaudio
...@@ -124,7 +124,7 @@ ma_bool32 try_parse_backend(const char* arg, ma_backend* pBackends, ma_uint32 ba ...@@ -124,7 +124,7 @@ ma_bool32 try_parse_backend(const char* arg, ma_backend* pBackends, ma_uint32 ba
pBackends[backendCount++] = ma_backend_wasapi; pBackends[backendCount++] = ma_backend_wasapi;
goto done; goto done;
} }
if (strcmp(arg, "dsound") == 0) { if (strcmp(arg, "dsound") == 0 || strcmp(arg, "directsound") == 0) {
pBackends[backendCount++] = ma_backend_dsound; pBackends[backendCount++] = ma_backend_dsound;
goto done; goto done;
} }
...@@ -148,7 +148,7 @@ ma_bool32 try_parse_backend(const char* arg, ma_backend* pBackends, ma_uint32 ba ...@@ -148,7 +148,7 @@ ma_bool32 try_parse_backend(const char* arg, ma_backend* pBackends, ma_uint32 ba
pBackends[backendCount++] = ma_backend_oss; pBackends[backendCount++] = ma_backend_oss;
goto done; goto done;
} }
if (strcmp(arg, "pulseaudio") == 0) { if (strcmp(arg, "pulseaudio") == 0 || strcmp(arg, "pulse") == 0) {
pBackends[backendCount++] = ma_backend_pulseaudio; pBackends[backendCount++] = ma_backend_pulseaudio;
goto done; goto done;
} }
...@@ -304,10 +304,39 @@ void on_log(void* pUserData, ma_uint32 logLevel, const char* message) ...@@ -304,10 +304,39 @@ void on_log(void* pUserData, ma_uint32 logLevel, const char* message)
printf("%s: %s", ma_log_level_to_string(logLevel), message); printf("%s: %s", ma_log_level_to_string(logLevel), message);
} }
void on_stop(ma_device* pDevice) void on_notification(const ma_device_notification* pNotification)
{ {
(void)pDevice; MA_ASSERT(pNotification != NULL);
printf("Stopped\n");
switch (pNotification->type)
{
case ma_device_notification_type_started:
{
printf("Started\n");
} break;
case ma_device_notification_type_stopped:
{
printf("Stopped\n");
} break;
case ma_device_notification_type_rerouted:
{
printf("Rerouted\n");
} break;
case ma_device_notification_type_interruption_began:
{
printf("Interruption Began\n");
} break;
case ma_device_notification_type_interruption_ended:
{
printf("Interruption Ended\n");
} break;
default: break;
}
} }
void on_data(ma_device* pDevice, void* pFramesOut, const void* pFramesIn, ma_uint32 frameCount) void on_data(ma_device* pDevice, void* pFramesOut, const void* pFramesIn, ma_uint32 frameCount)
...@@ -458,13 +487,13 @@ int main(int argc, char** argv) ...@@ -458,13 +487,13 @@ int main(int argc, char** argv)
} }
deviceConfig = ma_device_config_init(deviceType); deviceConfig = ma_device_config_init(deviceType);
deviceConfig.playback.format = deviceFormat; deviceConfig.playback.format = deviceFormat;
deviceConfig.playback.channels = deviceChannels; deviceConfig.playback.channels = deviceChannels;
deviceConfig.capture.format = deviceFormat; deviceConfig.capture.format = deviceFormat;
deviceConfig.capture.channels = deviceChannels; deviceConfig.capture.channels = deviceChannels;
deviceConfig.sampleRate = deviceSampleRate; deviceConfig.sampleRate = deviceSampleRate;
deviceConfig.dataCallback = on_data; deviceConfig.dataCallback = on_data;
deviceConfig.stopCallback = on_stop; deviceConfig.notificationCallback = on_notification;
result = ma_device_init(&g_State.context, &deviceConfig, &g_State.device); result = ma_device_init(&g_State.context, &deviceConfig, &g_State.device);
if (result != MA_SUCCESS) { if (result != MA_SUCCESS) {
printf("Failed to initialize device.\n"); printf("Failed to initialize device.\n");
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment