mirror of
https://github.com/mackron/miniaudio.git
synced 2026-04-21 15:56:58 +02:00
API CHANGE: Add device callbacks to mal_device_config.
Rationale: 1) It allows the callbacks to be set at initialization time which feels a bit more intuitive to me. 2) It avoids the need to call mal_device_set_send_callback(), etc. 3) It's a bit more consistent with the onLog callback. Previously, onLog would be passed to mal_device_init(), whereas onSend, etc were set with mal_device_set_send_callback(), etc. which feels needlessly inconsistent.
This commit is contained in:
@@ -17,14 +17,17 @@ Features
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
Example
|
Simple Playback Example
|
||||||
=======
|
=======================
|
||||||
mini_al will request and deliver audio data through callbacks.
|
|
||||||
|
|
||||||
```c
|
```c
|
||||||
mal_uint32 on_send_frames_to_device(mal_device* pDevice, mal_uint32 frameCount, void* pSamples)
|
mal_uint32 on_send_frames_to_device(mal_device* pDevice, mal_uint32 frameCount, void* pSamples)
|
||||||
{
|
{
|
||||||
drwav* pWav = (drwav*)pDevice->pUserData;
|
drwav* pWav = (drwav*)pDevice->pUserData;
|
||||||
|
if (pWav == NULL) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
return (mal_uint32)drwav_read_f32(pWav, frameCount * pDevice->channels, (float*)pSamples) / pDevice->channels;
|
return (mal_uint32)drwav_read_f32(pWav, frameCount * pDevice->channels, (float*)pSamples) / pDevice->channels;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -42,20 +45,23 @@ int main(int argc, char** argv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// In this example we use the default playback device with a default buffer size and period count.
|
// In this example we use the default playback device with a default buffer size and period count.
|
||||||
|
mal_device_config config;
|
||||||
|
config.format = mal_format_f32;
|
||||||
|
config.channels = wav.channels;
|
||||||
|
config.sampleRate = wav.sampleRate;
|
||||||
|
config.bufferSizeInFrames = 0; // Use default.
|
||||||
|
config.periods = 0; // Use default.
|
||||||
|
config.onRecvCallback = NULL; // Not used for playback.
|
||||||
|
config.onSendCallback = on_send_frames_to_device;
|
||||||
|
config.onStopCallback = NULL;
|
||||||
|
config.onLogCallback = NULL;
|
||||||
|
|
||||||
mal_device device;
|
mal_device device;
|
||||||
if (mal_device_init(&device, mal_device_type_playback, NULL, mal_format_f32, wav.channels, wav.sampleRate, 0, 0, NULL) != MAL_SUCCESS) {
|
if (mal_device_init(&device, mal_device_type_playback, NULL, &config, &wav) != MAL_SUCCESS) {
|
||||||
printf("Failed to open playback device.");
|
printf("Failed to open playback device.");
|
||||||
drwav_uninit(&wav);
|
drwav_uninit(&wav);
|
||||||
return -3;
|
return -3;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The pUserData member of mal_device is reserved for you.
|
|
||||||
device.pUserData = &wav;
|
|
||||||
|
|
||||||
// This is the callback for sending data to a playback device when it needs more. Make sure
|
|
||||||
// it's set before playing the device otherwise you'll end up with silence for the first
|
|
||||||
// bunch of frames.
|
|
||||||
mal_device_set_send_callback(&device, on_send_frames_to_device);
|
|
||||||
mal_device_start(&device);
|
mal_device_start(&device);
|
||||||
|
|
||||||
printf("Press Enter to quit...");
|
printf("Press Enter to quit...");
|
||||||
|
|||||||
@@ -53,14 +53,17 @@ int main()
|
|||||||
config.sampleRate = 48000;
|
config.sampleRate = 48000;
|
||||||
config.bufferSizeInFrames = 0; // Use default.
|
config.bufferSizeInFrames = 0; // Use default.
|
||||||
config.periods = 0; // Use default.
|
config.periods = 0; // Use default.
|
||||||
|
config.onRecvCallback = on_recv_frames;
|
||||||
|
config.onSendCallback = on_send_frames;
|
||||||
|
config.onStopCallback = NULL;
|
||||||
|
config.onLogCallback = NULL;
|
||||||
|
|
||||||
printf("Recording...\n");
|
printf("Recording...\n");
|
||||||
mal_device captureDevice;
|
mal_device captureDevice;
|
||||||
if (mal_device_init(&captureDevice, mal_device_type_capture, NULL, &config, NULL, NULL)) {
|
if (mal_device_init(&captureDevice, mal_device_type_capture, NULL, &config, NULL)) {
|
||||||
printf("Failed to initialize capture device.\n");
|
printf("Failed to initialize capture device.\n");
|
||||||
return -2;
|
return -2;
|
||||||
}
|
}
|
||||||
mal_device_set_recv_callback(&captureDevice, on_recv_frames);
|
|
||||||
mal_device_start(&captureDevice);
|
mal_device_start(&captureDevice);
|
||||||
|
|
||||||
printf("Press Enter to stop recording...\n");
|
printf("Press Enter to stop recording...\n");
|
||||||
@@ -71,11 +74,10 @@ int main()
|
|||||||
|
|
||||||
printf("Playing...\n");
|
printf("Playing...\n");
|
||||||
mal_device playbackDevice;
|
mal_device playbackDevice;
|
||||||
if (mal_device_init(&playbackDevice, mal_device_type_playback, NULL, &config, NULL, NULL)) {
|
if (mal_device_init(&playbackDevice, mal_device_type_playback, NULL, &config, NULL)) {
|
||||||
printf("Failed to initialize playback device.\n");
|
printf("Failed to initialize playback device.\n");
|
||||||
return -3;
|
return -3;
|
||||||
}
|
}
|
||||||
mal_device_set_send_callback(&playbackDevice, on_send_frames);
|
|
||||||
mal_device_start(&playbackDevice);
|
mal_device_start(&playbackDevice);
|
||||||
|
|
||||||
printf("Press Enter to quit...\n");
|
printf("Press Enter to quit...\n");
|
||||||
|
|||||||
@@ -37,21 +37,17 @@ int main(int argc, char** argv)
|
|||||||
config.sampleRate = wav.sampleRate;
|
config.sampleRate = wav.sampleRate;
|
||||||
config.bufferSizeInFrames = 0; // Use default.
|
config.bufferSizeInFrames = 0; // Use default.
|
||||||
config.periods = 0; // Use default.
|
config.periods = 0; // Use default.
|
||||||
|
config.onRecvCallback = NULL; // Not used for playback.
|
||||||
|
config.onSendCallback = on_send_frames_to_device;
|
||||||
|
config.onStopCallback = NULL;
|
||||||
|
config.onLogCallback = NULL;
|
||||||
|
|
||||||
mal_device device;
|
mal_device device;
|
||||||
if (mal_device_init(&device, mal_device_type_playback, NULL, &config, NULL, NULL) != MAL_SUCCESS) {
|
if (mal_device_init(&device, mal_device_type_playback, NULL, &config, &wav) != MAL_SUCCESS) {
|
||||||
printf("Failed to open playback device.");
|
printf("Failed to open playback device.");
|
||||||
drwav_uninit(&wav);
|
drwav_uninit(&wav);
|
||||||
return -3;
|
return -3;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The pUserData member of mal_device is reserved for you.
|
|
||||||
device.pUserData = &wav;
|
|
||||||
|
|
||||||
// This is the callback for sending data to a playback device when it needs more. Make sure
|
|
||||||
// it's set before playing the device otherwise you'll end up with silence for the first
|
|
||||||
// bunch of frames.
|
|
||||||
mal_device_set_send_callback(&device, on_send_frames_to_device);
|
|
||||||
mal_device_start(&device);
|
mal_device_start(&device);
|
||||||
|
|
||||||
printf("Press Enter to quit...");
|
printf("Press Enter to quit...");
|
||||||
|
|||||||
@@ -75,14 +75,17 @@
|
|||||||
// config.sampleRate = wav.sampleRate;
|
// config.sampleRate = wav.sampleRate;
|
||||||
// config.bufferSizeInFrames = 0; // Use default.
|
// config.bufferSizeInFrames = 0; // Use default.
|
||||||
// config.periods = 0; // Use default.
|
// config.periods = 0; // Use default.
|
||||||
|
// config.onSendCallback = on_send_samples;
|
||||||
|
// config.onRecvCallback = NULL; // Not used for playback devices.
|
||||||
|
// config.onStopCallback = NULL; // We don't care about knowing when the device has stopped...
|
||||||
|
// config.onLogCallback = NULL; // ... nor do we care about logging (but you really should in a real-world application).
|
||||||
//
|
//
|
||||||
// mal_device device;
|
// mal_device device;
|
||||||
// mal_result result = mal_device_init(&device, mal_device_type_playback, NULL, &config, NULL, pMyData);
|
// mal_result result = mal_device_init(&device, mal_device_type_playback, NULL, &config, pMyData);
|
||||||
// if (result != MAL_SUCCESS) {
|
// if (result != MAL_SUCCESS) {
|
||||||
// return -1;
|
// return -1;
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// mal_device_set_send_callback(&device, on_send_samples);
|
|
||||||
// mal_device_start(&device); // The device is sleeping by default so you'll need to start it manually.
|
// mal_device_start(&device); // The device is sleeping by default so you'll need to start it manually.
|
||||||
//
|
//
|
||||||
// ...
|
// ...
|
||||||
@@ -293,11 +296,11 @@ typedef enum
|
|||||||
{
|
{
|
||||||
// I like to keep these explicitly defined because they're used as a key into a lookup table. When items are
|
// I like to keep these explicitly defined because they're used as a key into a lookup table. When items are
|
||||||
// added to this, make sure there are no gaps and that they're added to the lookup table in mal_get_sample_size_in_bytes().
|
// added to this, make sure there are no gaps and that they're added to the lookup table in mal_get_sample_size_in_bytes().
|
||||||
mal_format_u8 = 0,
|
mal_format_u8 = 0,
|
||||||
mal_format_s16 = 1, // Seems to be the most widely supported format.
|
mal_format_s16 = 1, // Seems to be the most widely supported format.
|
||||||
mal_format_s24 = 2, // Tightly packed. 3 bytes per sample.
|
mal_format_s24 = 2, // Tightly packed. 3 bytes per sample.
|
||||||
mal_format_s32 = 3,
|
mal_format_s32 = 3,
|
||||||
mal_format_f32 = 4,
|
mal_format_f32 = 4,
|
||||||
} mal_format;
|
} mal_format;
|
||||||
|
|
||||||
typedef union
|
typedef union
|
||||||
@@ -325,6 +328,10 @@ typedef struct
|
|||||||
mal_uint32 sampleRate;
|
mal_uint32 sampleRate;
|
||||||
mal_uint32 bufferSizeInFrames;
|
mal_uint32 bufferSizeInFrames;
|
||||||
mal_uint32 periods;
|
mal_uint32 periods;
|
||||||
|
mal_recv_proc onRecvCallback;
|
||||||
|
mal_send_proc onSendCallback;
|
||||||
|
mal_stop_proc onStopCallback;
|
||||||
|
mal_log_proc onLogCallback;
|
||||||
} mal_device_config;
|
} mal_device_config;
|
||||||
|
|
||||||
struct mal_device
|
struct mal_device
|
||||||
@@ -337,7 +344,6 @@ struct mal_device
|
|||||||
mal_uint32 bufferSizeInFrames;
|
mal_uint32 bufferSizeInFrames;
|
||||||
mal_uint32 periods;
|
mal_uint32 periods;
|
||||||
mal_uint32 state;
|
mal_uint32 state;
|
||||||
mal_uint32 flags; // MAL_DEVICE_FLAG_*
|
|
||||||
mal_recv_proc onRecv;
|
mal_recv_proc onRecv;
|
||||||
mal_send_proc onSend;
|
mal_send_proc onSend;
|
||||||
mal_stop_proc onStop;
|
mal_stop_proc onStop;
|
||||||
@@ -349,6 +355,7 @@ struct mal_device
|
|||||||
mal_event stopEvent;
|
mal_event stopEvent;
|
||||||
mal_thread thread;
|
mal_thread thread;
|
||||||
mal_result workResult; // This is set by the worker thread after it's finished doing a job.
|
mal_result workResult; // This is set by the worker thread after it's finished doing a job.
|
||||||
|
mal_uint32 flags; // MAL_DEVICE_FLAG_*
|
||||||
|
|
||||||
union
|
union
|
||||||
{
|
{
|
||||||
@@ -467,7 +474,7 @@ mal_result mal_enumerate_devices(mal_device_type type, mal_uint32* pCount, mal_d
|
|||||||
// Efficiency: LOW
|
// Efficiency: LOW
|
||||||
// This API will dynamically link to backend DLLs/SOs like dsound.dll, and is otherwise just slow
|
// This API will dynamically link to backend DLLs/SOs like dsound.dll, and is otherwise just slow
|
||||||
// due to the nature of it being an initialization API.
|
// due to the nature of it being an initialization API.
|
||||||
mal_result mal_device_init(mal_device* pDevice, mal_device_type type, mal_device_id* pDeviceID, mal_device_config* pConfig, mal_log_proc onLog, void* pUserData);
|
mal_result mal_device_init(mal_device* pDevice, mal_device_type type, mal_device_id* pDeviceID, mal_device_config* pConfig, void* pUserData);
|
||||||
|
|
||||||
// Uninitializes a device.
|
// Uninitializes a device.
|
||||||
//
|
//
|
||||||
@@ -3468,14 +3475,17 @@ mal_result mal_enumerate_devices(mal_device_type type, mal_uint32* pCount, mal_d
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
mal_result mal_device_init(mal_device* pDevice, mal_device_type type, mal_device_id* pDeviceID, mal_device_config* pConfig, mal_log_proc onLog, void* pUserData)
|
mal_result mal_device_init(mal_device* pDevice, mal_device_type type, mal_device_id* pDeviceID, mal_device_config* pConfig, void* pUserData)
|
||||||
{
|
{
|
||||||
if (pDevice == NULL) return mal_post_error(pDevice, "mal_device_init() called with invalid arguments.", MAL_INVALID_ARGS);
|
if (pDevice == NULL) return mal_post_error(pDevice, "mal_device_init() called with invalid arguments.", MAL_INVALID_ARGS);
|
||||||
mal_zero_object(pDevice);
|
mal_zero_object(pDevice);
|
||||||
|
|
||||||
// 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 = pUserData;
|
pDevice->pUserData = pUserData;
|
||||||
pDevice->onLog = onLog;
|
pDevice->onLog = pConfig->onLogCallback;
|
||||||
|
pDevice->onStop = pConfig->onStopCallback;
|
||||||
|
pDevice->onSend = pConfig->onSendCallback;
|
||||||
|
pDevice->onRecv = pConfig->onRecvCallback;
|
||||||
|
|
||||||
if (((mal_uint64)pDevice % sizeof(pDevice)) != 0) {
|
if (((mal_uint64)pDevice % sizeof(pDevice)) != 0) {
|
||||||
if (pDevice->onLog) {
|
if (pDevice->onLog) {
|
||||||
|
|||||||
Reference in New Issue
Block a user