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
|
||||
=======
|
||||
mini_al will request and deliver audio data through callbacks.
|
||||
Simple Playback Example
|
||||
=======================
|
||||
|
||||
```c
|
||||
mal_uint32 on_send_frames_to_device(mal_device* pDevice, mal_uint32 frameCount, void* pSamples)
|
||||
{
|
||||
drwav* pWav = (drwav*)pDevice->pUserData;
|
||||
if (pWav == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
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.
|
||||
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;
|
||||
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.");
|
||||
drwav_uninit(&wav);
|
||||
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);
|
||||
|
||||
printf("Press Enter to quit...");
|
||||
|
||||
@@ -53,14 +53,17 @@ int main()
|
||||
config.sampleRate = 48000;
|
||||
config.bufferSizeInFrames = 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");
|
||||
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");
|
||||
return -2;
|
||||
}
|
||||
mal_device_set_recv_callback(&captureDevice, on_recv_frames);
|
||||
mal_device_start(&captureDevice);
|
||||
|
||||
printf("Press Enter to stop recording...\n");
|
||||
@@ -71,11 +74,10 @@ int main()
|
||||
|
||||
printf("Playing...\n");
|
||||
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");
|
||||
return -3;
|
||||
}
|
||||
mal_device_set_send_callback(&playbackDevice, on_send_frames);
|
||||
mal_device_start(&playbackDevice);
|
||||
|
||||
printf("Press Enter to quit...\n");
|
||||
|
||||
@@ -37,21 +37,17 @@ int main(int argc, char** argv)
|
||||
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;
|
||||
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.");
|
||||
drwav_uninit(&wav);
|
||||
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);
|
||||
|
||||
printf("Press Enter to quit...");
|
||||
|
||||
@@ -75,14 +75,17 @@
|
||||
// config.sampleRate = wav.sampleRate;
|
||||
// config.bufferSizeInFrames = 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_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) {
|
||||
// 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.
|
||||
//
|
||||
// ...
|
||||
@@ -325,6 +328,10 @@ typedef struct
|
||||
mal_uint32 sampleRate;
|
||||
mal_uint32 bufferSizeInFrames;
|
||||
mal_uint32 periods;
|
||||
mal_recv_proc onRecvCallback;
|
||||
mal_send_proc onSendCallback;
|
||||
mal_stop_proc onStopCallback;
|
||||
mal_log_proc onLogCallback;
|
||||
} mal_device_config;
|
||||
|
||||
struct mal_device
|
||||
@@ -337,7 +344,6 @@ struct mal_device
|
||||
mal_uint32 bufferSizeInFrames;
|
||||
mal_uint32 periods;
|
||||
mal_uint32 state;
|
||||
mal_uint32 flags; // MAL_DEVICE_FLAG_*
|
||||
mal_recv_proc onRecv;
|
||||
mal_send_proc onSend;
|
||||
mal_stop_proc onStop;
|
||||
@@ -349,6 +355,7 @@ struct mal_device
|
||||
mal_event stopEvent;
|
||||
mal_thread thread;
|
||||
mal_result workResult; // This is set by the worker thread after it's finished doing a job.
|
||||
mal_uint32 flags; // MAL_DEVICE_FLAG_*
|
||||
|
||||
union
|
||||
{
|
||||
@@ -467,7 +474,7 @@ mal_result mal_enumerate_devices(mal_device_type type, mal_uint32* pCount, mal_d
|
||||
// Efficiency: LOW
|
||||
// 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.
|
||||
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.
|
||||
//
|
||||
@@ -3468,14 +3475,17 @@ mal_result mal_enumerate_devices(mal_device_type type, mal_uint32* pCount, mal_d
|
||||
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);
|
||||
mal_zero_object(pDevice);
|
||||
|
||||
// Set the user data and log callback ASAP to ensure it is available for the entire initialization process.
|
||||
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 (pDevice->onLog) {
|
||||
|
||||
Reference in New Issue
Block a user