"include/svn:/svn.code.sf.net/p/irrlicht/code/trunk@2990" did not exist on "f040a326d87f7d5ae7153d5cf477a22145985db3"
Commit 516ff2e5 authored by David Reid's avatar David Reid

Get basic playback working on the OpenAL backend.

parent 518f628f
...@@ -525,6 +525,8 @@ struct mal_device ...@@ -525,6 +525,8 @@ struct mal_device
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_* mal_uint32 flags; // MAL_DEVICE_FLAG_*
mal_uint32 internalChannels;
union union
{ {
#ifdef MAL_ENABLE_WASAPI #ifdef MAL_ENABLE_WASAPI
...@@ -590,6 +592,11 @@ struct mal_device ...@@ -590,6 +592,11 @@ struct mal_device
/*ALCdevice**/ mal_ptr pDeviceALC; /*ALCdevice**/ mal_ptr pDeviceALC;
/*ALuint*/ mal_uint32 sourceAL; /*ALuint*/ mal_uint32 sourceAL;
/*ALuint*/ mal_uint32 buffersAL[MAL_MAX_PERIODS_OPENAL]; /*ALuint*/ mal_uint32 buffersAL[MAL_MAX_PERIODS_OPENAL];
/*ALenum*/ mal_uint32 formatAL;
mal_uint32 subBufferSizeInFrames; // This is the size of each of the OpenAL buffers (buffersAL).
mal_uint8* pIntermediaryBuffer; // This is malloc()'d and is used as the destination for reading from the client. Typed as mal_uint8 for easy offsetting.
mal_uint32 iNextBuffer; // The next buffer to unenqueue and then re-enqueue as new data is read.
mal_bool32 breakFromMainLoop;
} openal; } openal;
#endif #endif
...@@ -4090,7 +4097,7 @@ static mal_result mal_device__stop_backend__sles(mal_device* pDevice) ...@@ -4090,7 +4097,7 @@ static mal_result mal_device__stop_backend__sles(mal_device* pDevice)
// TODO: Remove unused APIs. // TODO: Remove unused APIs.
typedef ALCcontext* (MAL_AL_APIENTRY * MAL_LPALCCREATECONTEXT) (ALCdevice *device, const ALCint *attrlist); typedef ALCcontext* (MAL_AL_APIENTRY * MAL_LPALCCREATECONTEXT) (ALCdevice *device, const ALCint *attrlist);
typedef ALCboolean (MAL_AL_APIENTRY * MAL_LPALCMAKECONTEXTCURRENT)(ALCcontext *context); typedef ALCboolean (MAL_AL_APIENTRY * MAL_LPALCMAKECONTEXTCURRENT) (ALCcontext *context);
typedef void (MAL_AL_APIENTRY * MAL_LPALCPROCESSCONTEXT) (ALCcontext *context); typedef void (MAL_AL_APIENTRY * MAL_LPALCPROCESSCONTEXT) (ALCcontext *context);
typedef void (MAL_AL_APIENTRY * MAL_LPALCSUSPENDCONTEXT) (ALCcontext *context); typedef void (MAL_AL_APIENTRY * MAL_LPALCSUSPENDCONTEXT) (ALCcontext *context);
typedef void (MAL_AL_APIENTRY * MAL_LPALCDESTROYCONTEXT) (ALCcontext *context); typedef void (MAL_AL_APIENTRY * MAL_LPALCDESTROYCONTEXT) (ALCcontext *context);
...@@ -4099,13 +4106,13 @@ typedef ALCdevice* (MAL_AL_APIENTRY * MAL_LPALCGETCONTEXTSDEVICE) (ALCcontex ...@@ -4099,13 +4106,13 @@ typedef ALCdevice* (MAL_AL_APIENTRY * MAL_LPALCGETCONTEXTSDEVICE) (ALCcontex
typedef ALCdevice* (MAL_AL_APIENTRY * MAL_LPALCOPENDEVICE) (const ALCchar *devicename); typedef ALCdevice* (MAL_AL_APIENTRY * MAL_LPALCOPENDEVICE) (const ALCchar *devicename);
typedef ALCboolean (MAL_AL_APIENTRY * MAL_LPALCCLOSEDEVICE) (ALCdevice *device); typedef ALCboolean (MAL_AL_APIENTRY * MAL_LPALCCLOSEDEVICE) (ALCdevice *device);
typedef ALCenum (MAL_AL_APIENTRY * MAL_LPALCGETERROR) (ALCdevice *device); typedef ALCenum (MAL_AL_APIENTRY * MAL_LPALCGETERROR) (ALCdevice *device);
typedef ALCboolean (MAL_AL_APIENTRY * MAL_LPALCISEXTENSIONPRESENT)(ALCdevice *device, const ALCchar *extname); typedef ALCboolean (MAL_AL_APIENTRY * MAL_LPALCISEXTENSIONPRESENT) (ALCdevice *device, const ALCchar *extname);
typedef void* (MAL_AL_APIENTRY * MAL_LPALCGETPROCADDRESS) (ALCdevice *device, const ALCchar *funcname); typedef void* (MAL_AL_APIENTRY * MAL_LPALCGETPROCADDRESS) (ALCdevice *device, const ALCchar *funcname);
typedef ALCenum (MAL_AL_APIENTRY * MAL_LPALCGETENUMVALUE) (ALCdevice *device, const ALCchar *enumname); typedef ALCenum (MAL_AL_APIENTRY * MAL_LPALCGETENUMVALUE) (ALCdevice *device, const ALCchar *enumname);
typedef const ALCchar* (MAL_AL_APIENTRY * MAL_LPALCGETSTRING) (ALCdevice *device, ALCenum param); typedef const ALCchar* (MAL_AL_APIENTRY * MAL_LPALCGETSTRING) (ALCdevice *device, ALCenum param);
typedef void (MAL_AL_APIENTRY * MAL_LPALCGETINTEGERV) (ALCdevice *device, ALCenum param, ALCsizei size, ALCint *values); typedef void (MAL_AL_APIENTRY * MAL_LPALCGETINTEGERV) (ALCdevice *device, ALCenum param, ALCsizei size, ALCint *values);
typedef ALCdevice* (MAL_AL_APIENTRY * MAL_LPALCCAPTUREOPENDEVICE) (const ALCchar *devicename, ALCuint frequency, ALCenum format, ALCsizei buffersize); typedef ALCdevice* (MAL_AL_APIENTRY * MAL_LPALCCAPTUREOPENDEVICE) (const ALCchar *devicename, ALCuint frequency, ALCenum format, ALCsizei buffersize);
typedef ALCboolean (MAL_AL_APIENTRY * MAL_LPALCCAPTURECLOSEDEVICE)(ALCdevice *device); typedef ALCboolean (MAL_AL_APIENTRY * MAL_LPALCCAPTURECLOSEDEVICE) (ALCdevice *device);
typedef void (MAL_AL_APIENTRY * MAL_LPALCCAPTURESTART) (ALCdevice *device); typedef void (MAL_AL_APIENTRY * MAL_LPALCCAPTURESTART) (ALCdevice *device);
typedef void (MAL_AL_APIENTRY * MAL_LPALCCAPTURESTOP) (ALCdevice *device); typedef void (MAL_AL_APIENTRY * MAL_LPALCCAPTURESTOP) (ALCdevice *device);
typedef void (MAL_AL_APIENTRY * MAL_LPALCCAPTURESAMPLES) (ALCdevice *device, ALCvoid *buffer, ALCsizei samples); typedef void (MAL_AL_APIENTRY * MAL_LPALCCAPTURESAMPLES) (ALCdevice *device, ALCvoid *buffer, ALCsizei samples);
...@@ -4372,6 +4379,8 @@ static void mal_device_uninit__openal(mal_device* pDevice) ...@@ -4372,6 +4379,8 @@ static void mal_device_uninit__openal(mal_device* pDevice)
} else { } else {
((MAL_LPALCCAPTURECLOSEDEVICE)pDevice->pContext->openal.alcCaptureCloseDevice)(pDevice->openal.pDeviceALC); ((MAL_LPALCCAPTURECLOSEDEVICE)pDevice->pContext->openal.alcCaptureCloseDevice)(pDevice->openal.pDeviceALC);
} }
mal_free(pDevice->openal.pIntermediaryBuffer);
} }
static mal_result mal_device_init__openal(mal_context* pContext, mal_device_type type, mal_device_id* pDeviceID, mal_device_config* pConfig, mal_device* pDevice) static mal_result mal_device_init__openal(mal_context* pContext, mal_device_type type, mal_device_id* pDeviceID, mal_device_config* pConfig, mal_device* pDevice)
...@@ -4383,10 +4392,13 @@ static mal_result mal_device_init__openal(mal_context* pContext, mal_device_type ...@@ -4383,10 +4392,13 @@ static mal_result mal_device_init__openal(mal_context* pContext, mal_device_type
ALCsizei bufferSizeInSamplesAL = pConfig->bufferSizeInFrames; ALCsizei bufferSizeInSamplesAL = pConfig->bufferSizeInFrames;
ALCuint frequencyAL = pConfig->sampleRate; ALCuint frequencyAL = pConfig->sampleRate;
mal_uint32 channelsAL = 0;
// OpenAL supports only mono and stereo. // OpenAL supports only mono and stereo.
ALCenum formatAL = 0; ALCenum formatAL = 0;
if (pConfig->channels == 1) { if (pConfig->channels == 1) {
// Mono. // Mono.
channelsAL = 1;
if (pConfig->format == mal_format_f32) { if (pConfig->format == mal_format_f32) {
if (pContext->openal.isFloat32Supported) { if (pContext->openal.isFloat32Supported) {
formatAL = MAL_AL_FORMAT_MONO_FLOAT32; formatAL = MAL_AL_FORMAT_MONO_FLOAT32;
...@@ -4404,7 +4416,7 @@ static mal_result mal_device_init__openal(mal_context* pContext, mal_device_type ...@@ -4404,7 +4416,7 @@ static mal_result mal_device_init__openal(mal_context* pContext, mal_device_type
} }
} else { } else {
// Stereo. // Stereo.
bufferSizeInSamplesAL *= 2; channelsAL = 2;
if (pConfig->format == mal_format_f32) { if (pConfig->format == mal_format_f32) {
if (pContext->openal.isFloat32Supported) { if (pContext->openal.isFloat32Supported) {
formatAL = MAL_AL_FORMAT_STEREO_FLOAT32; formatAL = MAL_AL_FORMAT_STEREO_FLOAT32;
...@@ -4426,6 +4438,8 @@ static mal_result mal_device_init__openal(mal_context* pContext, mal_device_type ...@@ -4426,6 +4438,8 @@ static mal_result mal_device_init__openal(mal_context* pContext, mal_device_type
return MAL_FORMAT_NOT_SUPPORTED; return MAL_FORMAT_NOT_SUPPORTED;
} }
bufferSizeInSamplesAL *= channelsAL;
// OpenAL feels a bit unintuitive to me... The global object is a device, and it would appear that each device can have // OpenAL feels a bit unintuitive to me... The global object is a device, and it would appear that each device can have
// many context's... // many context's...
...@@ -4465,22 +4479,150 @@ static mal_result mal_device_init__openal(mal_context* pContext, mal_device_type ...@@ -4465,22 +4479,150 @@ static mal_result mal_device_init__openal(mal_context* pContext, mal_device_type
pDevice->openal.buffersAL[i] = buffersAL[i]; pDevice->openal.buffersAL[i] = buffersAL[i];
} }
pDevice->internalChannels = channelsAL;
pDevice->openal.formatAL = formatAL;
pDevice->openal.subBufferSizeInFrames = pDevice->bufferSizeInFrames / pDevice->periods;
pDevice->openal.pIntermediaryBuffer = (mal_uint8*)mal_malloc(pDevice->openal.subBufferSizeInFrames * channelsAL * mal_get_sample_size_in_bytes(pDevice->format));
if (pDevice->openal.pIntermediaryBuffer == NULL) {
mal_device_uninit__openal(pDevice);
return MAL_OUT_OF_MEMORY;
}
return MAL_SUCCESS; return MAL_SUCCESS;
} }
#if 0
static mal_result mal_device__start_backend__openal(mal_device* pDevice) static mal_result mal_device__start_backend__openal(mal_device* pDevice)
{ {
mal_assert(pDevice != NULL); mal_assert(pDevice != NULL);
if (pDevice->type == mal_device_type_playback) {
// Playback.
//
// When starting playback we want to ensure each buffer is filled and queued before playing the source.
pDevice->openal.iNextBuffer = 0;
for (mal_uint32 i = 0; i < pDevice->periods; ++i) {
mal_device__read_frames_from_client(pDevice, pDevice->openal.subBufferSizeInFrames, pDevice->openal.pIntermediaryBuffer);
ALuint bufferAL = pDevice->openal.buffersAL[i];
((MAL_LPALBUFFERDATA)pDevice->pContext->openal.alBufferData)(bufferAL, pDevice->openal.formatAL, pDevice->openal.pIntermediaryBuffer, pDevice->openal.subBufferSizeInFrames * pDevice->internalChannels * mal_get_sample_size_in_bytes(pDevice->format), pDevice->sampleRate);
((MAL_LPALSOURCEQUEUEBUFFERS)pDevice->pContext->openal.alSourceQueueBuffers)(pDevice->openal.sourceAL, 1, &bufferAL);
}
// Start the source only after filling and queueing each buffer.
((MAL_LPALSOURCEPLAY)pDevice->pContext->openal.alSourcePlay)(pDevice->openal.sourceAL);
} else {
// Capture.
((MAL_LPALCCAPTURESTART)pDevice->pContext->openal.alcCaptureStart)(pDevice->openal.pDeviceALC);
}
return MAL_SUCCESS; return MAL_SUCCESS;
} }
static mal_result mal_device__stop_backend__openal(mal_device* pDevice) static mal_result mal_device__stop_backend__openal(mal_device* pDevice)
{ {
mal_assert(pDevice != NULL); mal_assert(pDevice != NULL);
if (pDevice->type == mal_device_type_playback) {
((MAL_LPALSOURCESTOP)pDevice->pContext->openal.alSourceStop)(pDevice->openal.sourceAL);
} else {
((MAL_LPALCCAPTURESTOP)pDevice->pContext->openal.alcCaptureStop)(pDevice->openal.pDeviceALC);
}
return MAL_SUCCESS;
}
static mal_result mal_device__break_main_loop__openal(mal_device* pDevice)
{
mal_assert(pDevice != NULL);
pDevice->openal.breakFromMainLoop = MAL_TRUE;
return MAL_SUCCESS;
}
static mal_uint32 mal_device__get_available_frames__openal(mal_device* pDevice)
{
mal_assert(pDevice != NULL);
if (pDevice->type == mal_device_type_playback) {
ALint processedBufferCount = 0;
((MAL_LPALGETSOURCEI)pDevice->pContext->openal.alGetSourcei)(pDevice->openal.sourceAL, AL_BUFFERS_PROCESSED, &processedBufferCount);
return processedBufferCount * pDevice->openal.subBufferSizeInFrames;
} else {
ALint samplesAvailable = 0;
((MAL_LPALCGETINTEGERV)pDevice->pContext->openal.alcGetIntegerv)(pDevice->openal.pDeviceALC, ALC_CAPTURE_SAMPLES, (ALCsizei)sizeof(ALint), &samplesAvailable);
return samplesAvailable / pDevice->channels;
}
}
static mal_uint32 mal_device__wait_for_frames__openal(mal_device* pDevice)
{
mal_assert(pDevice != NULL);
while (!pDevice->openal.breakFromMainLoop) {
mal_uint32 framesAvailable = mal_device__get_available_frames__openal(pDevice);
if (framesAvailable > 0) {
return framesAvailable;
}
mal_sleep(1);
}
// We'll get here if the loop was terminated. When capturing we want to return whatever is available. For playback we just drop it.
if (pDevice->type == mal_device_type_playback) {
return 0;
} else {
return mal_device__get_available_frames__openal(pDevice);
}
}
static mal_result mal_device__main_loop__openal(mal_device* pDevice)
{
mal_assert(pDevice != NULL);
pDevice->openal.breakFromMainLoop = MAL_FALSE;
while (!pDevice->openal.breakFromMainLoop) {
mal_uint32 framesAvailable = mal_device__wait_for_frames__openal(pDevice);
if (framesAvailable == 0) {
continue;
}
// If it's a playback device, don't bother grabbing more data if the device is being stopped.
if (pDevice->openal.breakFromMainLoop && pDevice->type == mal_device_type_playback) {
return MAL_FALSE;
}
if (pDevice->type == mal_device_type_playback) {
while (framesAvailable > 0) {
mal_uint32 framesToRead = (framesAvailable > pDevice->openal.subBufferSizeInFrames) ? pDevice->openal.subBufferSizeInFrames : framesAvailable;
ALuint bufferAL = pDevice->openal.buffersAL[pDevice->openal.iNextBuffer];
pDevice->openal.iNextBuffer = (pDevice->openal.iNextBuffer + 1) % pDevice->periods;
mal_device__read_frames_from_client(pDevice, framesToRead, pDevice->openal.pIntermediaryBuffer);
((MAL_LPALSOURCEUNQUEUEBUFFERS)pDevice->pContext->openal.alSourceUnqueueBuffers)(pDevice->openal.sourceAL, 1, &bufferAL);
((MAL_LPALBUFFERDATA)pDevice->pContext->openal.alBufferData)(bufferAL, pDevice->openal.formatAL, pDevice->openal.pIntermediaryBuffer, pDevice->openal.subBufferSizeInFrames * pDevice->internalChannels * mal_get_sample_size_in_bytes(pDevice->format), pDevice->sampleRate);
((MAL_LPALSOURCEQUEUEBUFFERS)pDevice->pContext->openal.alSourceQueueBuffers)(pDevice->openal.sourceAL, 1, &bufferAL);
framesAvailable -= framesToRead;
}
} else {
while (framesAvailable > 0) {
mal_uint32 framesToSend = (framesAvailable > pDevice->openal.subBufferSizeInFrames) ? pDevice->openal.subBufferSizeInFrames : framesAvailable;
((MAL_LPALCCAPTURESAMPLES)pDevice->pContext->openal.alcCaptureSamples)(pDevice->openal.pDeviceALC, pDevice->openal.pIntermediaryBuffer, framesToSend);
mal_device__send_frames_to_client(pDevice, framesToSend, pDevice->openal.pIntermediaryBuffer);
framesAvailable -= framesToSend;
}
}
}
return MAL_SUCCESS; return MAL_SUCCESS;
} }
#endif
#endif // OpenAL #endif // OpenAL
...@@ -4504,6 +4646,11 @@ static mal_result mal_device__start_backend(mal_device* pDevice) ...@@ -4504,6 +4646,11 @@ static mal_result mal_device__start_backend(mal_device* pDevice)
result = mal_device__start_backend__alsa(pDevice); result = mal_device__start_backend__alsa(pDevice);
} }
#endif #endif
#ifdef MAL_ENABLE_OPENAL
if (pDevice->pContext->backend == mal_backend_openal) {
result = mal_device__start_backend__openal(pDevice);
}
#endif
#ifdef MAL_ENABLE_NULL #ifdef MAL_ENABLE_NULL
if (pDevice->pContext->backend == mal_backend_null) { if (pDevice->pContext->backend == mal_backend_null) {
result = mal_device__start_backend__null(pDevice); result = mal_device__start_backend__null(pDevice);
...@@ -4533,6 +4680,11 @@ static mal_result mal_device__stop_backend(mal_device* pDevice) ...@@ -4533,6 +4680,11 @@ static mal_result mal_device__stop_backend(mal_device* pDevice)
result = mal_device__stop_backend__alsa(pDevice); result = mal_device__stop_backend__alsa(pDevice);
} }
#endif #endif
#ifdef MAL_ENABLE_OPENAL
if (pDevice->pContext->backend == mal_backend_openal) {
result = mal_device__stop_backend__openal(pDevice);
}
#endif
#ifdef MAL_ENABLE_NULL #ifdef MAL_ENABLE_NULL
if (pDevice->pContext->backend == mal_backend_null) { if (pDevice->pContext->backend == mal_backend_null) {
result = mal_device__stop_backend__null(pDevice); result = mal_device__stop_backend__null(pDevice);
...@@ -4562,6 +4714,11 @@ static mal_result mal_device__break_main_loop(mal_device* pDevice) ...@@ -4562,6 +4714,11 @@ static mal_result mal_device__break_main_loop(mal_device* pDevice)
result = mal_device__break_main_loop__alsa(pDevice); result = mal_device__break_main_loop__alsa(pDevice);
} }
#endif #endif
#ifdef MAL_ENABLE_OPENAL
if (pDevice->pContext->backend == mal_backend_openal) {
result = mal_device__break_main_loop__openal(pDevice);
}
#endif
#ifdef MAL_ENABLE_NULL #ifdef MAL_ENABLE_NULL
if (pDevice->pContext->backend == mal_backend_null) { if (pDevice->pContext->backend == mal_backend_null) {
result = mal_device__break_main_loop__null(pDevice); result = mal_device__break_main_loop__null(pDevice);
...@@ -4591,6 +4748,11 @@ static mal_result mal_device__main_loop(mal_device* pDevice) ...@@ -4591,6 +4748,11 @@ static mal_result mal_device__main_loop(mal_device* pDevice)
result = mal_device__main_loop__alsa(pDevice); result = mal_device__main_loop__alsa(pDevice);
} }
#endif #endif
#ifdef MAL_ENABLE_OPENAL
if (pDevice->pContext->backend == mal_backend_openal) {
result = mal_device__main_loop__openal(pDevice);
}
#endif
#ifdef MAL_ENABLE_NULL #ifdef MAL_ENABLE_NULL
if (pDevice->pContext->backend == mal_backend_null) { if (pDevice->pContext->backend == mal_backend_null) {
result = mal_device__main_loop__null(pDevice); result = mal_device__main_loop__null(pDevice);
......
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