Commit 2c656d5e authored by David Reid's avatar David Reid

Dynamically link to libpthread.so at runtime.

This should remove the need to link to libpthread.
parent a69279bc
......@@ -720,6 +720,22 @@ struct mal_context
mal_proc CoTaskMemFree;
mal_proc PropVariantClear;
} win32;
#endif
#ifdef MAL_POSIX
struct
{
mal_handle pthreadSO;
mal_proc pthread_create;
mal_proc pthread_join;
mal_proc pthread_mutex_init;
mal_proc pthread_mutex_destroy;
mal_proc pthread_mutex_lock;
mal_proc pthread_mutex_unlock;
mal_proc pthread_cond_init;
mal_proc pthread_cond_destroy;
mal_proc pthread_cond_wait;
mal_proc pthread_cond_signal;
} posix;
#endif
int _unused;
};
......@@ -1636,8 +1652,10 @@ mal_proc mal_dlsym(mal_handle handle, const char* symbol)
//
///////////////////////////////////////////////////////////////////////////////
#ifdef MAL_WIN32
mal_bool32 mal_thread_create__win32(mal_thread* pThread, mal_thread_entry_proc entryProc, void* pData)
mal_bool32 mal_thread_create__win32(mal_context* pContext, mal_thread* pThread, mal_thread_entry_proc entryProc, void* pData)
{
(void)pContext;
*pThread = CreateThread(NULL, 0, entryProc, pData, 0, NULL);
if (*pThread == NULL) {
return MAL_FALSE;
......@@ -1646,8 +1664,10 @@ mal_bool32 mal_thread_create__win32(mal_thread* pThread, mal_thread_entry_proc e
return MAL_TRUE;
}
void mal_thread_wait__win32(mal_thread* pThread)
void mal_thread_wait__win32(mal_context* pContext, mal_thread* pThread)
{
(void)pContext;
WaitForSingleObject(*pThread, INFINITE);
}
......@@ -1657,8 +1677,10 @@ void mal_sleep__win32(mal_uint32 milliseconds)
}
mal_bool32 mal_mutex_create__win32(mal_mutex* pMutex)
mal_bool32 mal_mutex_create__win32(mal_context* pContext, mal_mutex* pMutex)
{
(void)pContext;
*pMutex = CreateEventA(NULL, FALSE, TRUE, NULL);
if (*pMutex == NULL) {
return MAL_FALSE;
......@@ -1667,24 +1689,32 @@ mal_bool32 mal_mutex_create__win32(mal_mutex* pMutex)
return MAL_TRUE;
}
void mal_mutex_delete__win32(mal_mutex* pMutex)
void mal_mutex_delete__win32(mal_context* pContext, mal_mutex* pMutex)
{
(void)pContext;
CloseHandle(*pMutex);
}
void mal_mutex_lock__win32(mal_mutex* pMutex)
void mal_mutex_lock__win32(mal_context* pContext, mal_mutex* pMutex)
{
(void)pContext;
WaitForSingleObject(*pMutex, INFINITE);
}
void mal_mutex_unlock__win32(mal_mutex* pMutex)
void mal_mutex_unlock__win32(mal_context* pContext, mal_mutex* pMutex)
{
(void)pContext;
SetEvent(*pMutex);
}
mal_bool32 mal_event_create__win32(mal_event* pEvent)
mal_bool32 mal_event_create__win32(mal_context* pContext, mal_event* pEvent)
{
(void)pContext;
*pEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
if (*pEvent == NULL) {
return MAL_FALSE;
......@@ -1693,32 +1723,49 @@ mal_bool32 mal_event_create__win32(mal_event* pEvent)
return MAL_TRUE;
}
void mal_event_delete__win32(mal_event* pEvent)
void mal_event_delete__win32(mal_context* pContext, mal_event* pEvent)
{
(void)pContext;
CloseHandle(*pEvent);
}
mal_bool32 mal_event_wait__win32(mal_event* pEvent)
mal_bool32 mal_event_wait__win32(mal_context* pContext, mal_event* pEvent)
{
(void)pContext;
return WaitForSingleObject(*pEvent, INFINITE) == WAIT_OBJECT_0;
}
mal_bool32 mal_event_signal__win32(mal_event* pEvent)
mal_bool32 mal_event_signal__win32(mal_context* pContext, mal_event* pEvent)
{
(void)pContext;
return SetEvent(*pEvent);
}
#endif
#ifdef MAL_POSIX
mal_bool32 mal_thread_create__posix(mal_thread* pThread, mal_thread_entry_proc entryProc, void* pData)
typedef int (* mal_pthread_create_proc)(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg);
typedef int (* mal_pthread_join_proc)(pthread_t thread, void **retval);
typedef int (* mal_pthread_mutex_init_proc)(pthread_mutex_t *__mutex, const pthread_mutexattr_t *__mutexattr);
typedef int (* mal_pthread_mutex_destroy_proc)(pthread_mutex_t *__mutex);
typedef int (* mal_pthread_mutex_lock_proc)(pthread_mutex_t *__mutex);
typedef int (* mal_pthread_mutex_unlock_proc)(pthread_mutex_t *__mutex);
typedef int (* mal_pthread_cond_init_proc)(pthread_cond_t *__restrict __cond, const pthread_condattr_t *__restrict __cond_attr);
typedef int (* mal_pthread_cond_destroy_proc)(pthread_cond_t *__cond);
typedef int (* mal_pthread_cond_signal_proc)(pthread_cond_t *__cond);
typedef int (* mal_pthread_cond_wait_proc)(pthread_cond_t *__restrict __cond, pthread_mutex_t *__restrict __mutex);
mal_bool32 mal_thread_create__posix(mal_context* pContext, mal_thread* pThread, mal_thread_entry_proc entryProc, void* pData)
{
return pthread_create(pThread, NULL, entryProc, pData) == 0;
return ((mal_pthread_create_proc)pContext->posix.pthread_create)(pThread, NULL, entryProc, pData) == 0;
}
void mal_thread_wait__posix(mal_thread* pThread)
void mal_thread_wait__posix(mal_context* pContext, mal_thread* pThread)
{
pthread_join(*pThread, NULL);
((mal_pthread_join_proc)pContext->posix.pthread_join)(*pThread, NULL);
}
void mal_sleep__posix(mal_uint32 milliseconds)
......@@ -1727,34 +1774,34 @@ void mal_sleep__posix(mal_uint32 milliseconds)
}
mal_bool32 mal_mutex_create__posix(mal_mutex* pMutex)
mal_bool32 mal_mutex_create__posix(mal_context* pContext, mal_mutex* pMutex)
{
return pthread_mutex_init(pMutex, NULL) == 0;
return ((mal_pthread_mutex_init_proc)pContext->posix.pthread_mutex_init)(pMutex, NULL) == 0;
}
void mal_mutex_delete__posix(mal_mutex* pMutex)
void mal_mutex_delete__posix(mal_context* pContext, mal_mutex* pMutex)
{
pthread_mutex_destroy(pMutex);
((mal_pthread_mutex_destroy_proc)pContext->posix.pthread_mutex_destroy)(pMutex);
}
void mal_mutex_lock__posix(mal_mutex* pMutex)
void mal_mutex_lock__posix(mal_context* pContext, mal_mutex* pMutex)
{
pthread_mutex_lock(pMutex);
((mal_pthread_mutex_lock_proc)pContext->posix.pthread_mutex_lock)(pMutex);
}
void mal_mutex_unlock__posix(mal_mutex* pMutex)
void mal_mutex_unlock__posix(mal_context* pContext, mal_mutex* pMutex)
{
pthread_mutex_unlock(pMutex);
((mal_pthread_mutex_unlock_proc)pContext->posix.pthread_mutex_unlock)(pMutex);
}
mal_bool32 mal_event_create__posix(mal_event* pEvent)
mal_bool32 mal_event_create__posix(mal_context* pContext, mal_event* pEvent)
{
if (pthread_mutex_init(&pEvent->mutex, NULL) != 0) {
if (((mal_pthread_mutex_init_proc)pContext->posix.pthread_mutex_init)(&pEvent->mutex, NULL) != 0) {
return MAL_FALSE;
}
if (pthread_cond_init(&pEvent->condition, NULL) != 0) {
if (((mal_pthread_cond_init_proc)pContext->posix.pthread_cond_init)(&pEvent->condition, NULL) != 0) {
return MAL_FALSE;
}
......@@ -1762,61 +1809,61 @@ mal_bool32 mal_event_create__posix(mal_event* pEvent)
return MAL_TRUE;
}
void mal_event_delete__posix(mal_event* pEvent)
void mal_event_delete__posix(mal_context* pContext, mal_event* pEvent)
{
pthread_cond_destroy(&pEvent->condition);
pthread_mutex_destroy(&pEvent->mutex);
((mal_pthread_cond_destroy_proc)pContext->posix.pthread_cond_destroy)(&pEvent->condition);
((mal_pthread_mutex_destroy_proc)pContext->posix.pthread_mutex_destroy)(&pEvent->mutex);
}
mal_bool32 mal_event_wait__posix(mal_event* pEvent)
mal_bool32 mal_event_wait__posix(mal_context* pContext, mal_event* pEvent)
{
pthread_mutex_lock(&pEvent->mutex);
((mal_pthread_mutex_lock_proc)pContext->posix.pthread_mutex_lock)(&pEvent->mutex);
{
while (pEvent->value == 0) {
pthread_cond_wait(&pEvent->condition, &pEvent->mutex);
((mal_pthread_cond_wait_proc)pContext->posix.pthread_cond_wait)(&pEvent->condition, &pEvent->mutex);
}
pEvent->value = 0; // Auto-reset.
}
pthread_mutex_unlock(&pEvent->mutex);
((mal_pthread_mutex_unlock_proc)pContext->posix.pthread_mutex_unlock)(&pEvent->mutex);
return MAL_TRUE;
}
mal_bool32 mal_event_signal__posix(mal_event* pEvent)
mal_bool32 mal_event_signal__posix(mal_context* pContext, mal_event* pEvent)
{
pthread_mutex_lock(&pEvent->mutex);
((mal_pthread_mutex_lock_proc)pContext->posix.pthread_mutex_lock)(&pEvent->mutex);
{
pEvent->value = 1;
pthread_cond_signal(&pEvent->condition);
((mal_pthread_cond_signal_proc)pContext->posix.pthread_cond_signal)(&pEvent->condition);
}
pthread_mutex_unlock(&pEvent->mutex);
((mal_pthread_mutex_unlock_proc)pContext->posix.pthread_mutex_unlock)(&pEvent->mutex);
return MAL_TRUE;
}
#endif
mal_bool32 mal_thread_create(mal_thread* pThread, mal_thread_entry_proc entryProc, void* pData)
mal_bool32 mal_thread_create(mal_context* pContext, mal_thread* pThread, mal_thread_entry_proc entryProc, void* pData)
{
if (pThread == NULL || entryProc == NULL) return MAL_FALSE;
#ifdef MAL_WIN32
return mal_thread_create__win32(pThread, entryProc, pData);
return mal_thread_create__win32(pContext, pThread, entryProc, pData);
#endif
#ifdef MAL_POSIX
return mal_thread_create__posix(pThread, entryProc, pData);
return mal_thread_create__posix(pContext, pThread, entryProc, pData);
#endif
}
void mal_thread_wait(mal_thread* pThread)
void mal_thread_wait(mal_context* pContext, mal_thread* pThread)
{
if (pThread == NULL) return;
#ifdef MAL_WIN32
mal_thread_wait__win32(pThread);
mal_thread_wait__win32(pContext, pThread);
#endif
#ifdef MAL_POSIX
mal_thread_wait__posix(pThread);
mal_thread_wait__posix(pContext, pThread);
#endif
}
......@@ -1831,100 +1878,100 @@ void mal_sleep(mal_uint32 milliseconds)
}
mal_bool32 mal_mutex_create(mal_mutex* pMutex)
mal_bool32 mal_mutex_create(mal_context* pContext, mal_mutex* pMutex)
{
if (pMutex == NULL) return MAL_FALSE;
#ifdef MAL_WIN32
return mal_mutex_create__win32(pMutex);
return mal_mutex_create__win32(pContext, pMutex);
#endif
#ifdef MAL_POSIX
return mal_mutex_create__posix(pMutex);
return mal_mutex_create__posix(pContext, pMutex);
#endif
}
void mal_mutex_delete(mal_mutex* pMutex)
void mal_mutex_delete(mal_context* pContext, mal_mutex* pMutex)
{
if (pMutex == NULL) return;
#ifdef MAL_WIN32
mal_mutex_delete__win32(pMutex);
mal_mutex_delete__win32(pContext, pMutex);
#endif
#ifdef MAL_POSIX
mal_mutex_delete__posix(pMutex);
mal_mutex_delete__posix(pContext, pMutex);
#endif
}
void mal_mutex_lock(mal_mutex* pMutex)
void mal_mutex_lock(mal_context* pContext, mal_mutex* pMutex)
{
if (pMutex == NULL) return;
#ifdef MAL_WIN32
mal_mutex_lock__win32(pMutex);
mal_mutex_lock__win32(pContext, pMutex);
#endif
#ifdef MAL_POSIX
mal_mutex_lock__posix(pMutex);
mal_mutex_lock__posix(pContext, pMutex);
#endif
}
void mal_mutex_unlock(mal_mutex* pMutex)
void mal_mutex_unlock(mal_context* pContext, mal_mutex* pMutex)
{
if (pMutex == NULL) return;
#ifdef MAL_WIN32
mal_mutex_unlock__win32(pMutex);
mal_mutex_unlock__win32(pContext, pMutex);
#endif
#ifdef MAL_POSIX
mal_mutex_unlock__posix(pMutex);
mal_mutex_unlock__posix(pContext, pMutex);
#endif
}
mal_bool32 mal_event_create(mal_event* pEvent)
mal_bool32 mal_event_create(mal_context* pContext, mal_event* pEvent)
{
if (pEvent == NULL) return MAL_FALSE;
#ifdef MAL_WIN32
return mal_event_create__win32(pEvent);
return mal_event_create__win32(pContext, pEvent);
#endif
#ifdef MAL_POSIX
return mal_event_create__posix(pEvent);
return mal_event_create__posix(pContext, pEvent);
#endif
}
void mal_event_delete(mal_event* pEvent)
void mal_event_delete(mal_context* pContext, mal_event* pEvent)
{
if (pEvent == NULL) return;
#ifdef MAL_WIN32
mal_event_delete__win32(pEvent);
mal_event_delete__win32(pContext, pEvent);
#endif
#ifdef MAL_POSIX
mal_event_delete__posix(pEvent);
mal_event_delete__posix(pContext, pEvent);
#endif
}
mal_bool32 mal_event_wait(mal_event* pEvent)
mal_bool32 mal_event_wait(mal_context* pContext, mal_event* pEvent)
{
if (pEvent == NULL) return MAL_FALSE;
#ifdef MAL_WIN32
return mal_event_wait__win32(pEvent);
return mal_event_wait__win32(pContext, pEvent);
#endif
#ifdef MAL_POSIX
return mal_event_wait__posix(pEvent);
return mal_event_wait__posix(pContext, pEvent);
#endif
}
mal_bool32 mal_event_signal(mal_event* pEvent)
mal_bool32 mal_event_signal(mal_context* pContext, mal_event* pEvent)
{
if (pEvent == NULL) return MAL_FALSE;
#ifdef MAL_WIN32
return mal_event_signal__win32(pEvent);
return mal_event_signal__win32(pContext, pEvent);
#endif
#ifdef MAL_POSIX
return mal_event_signal__posix(pEvent);
return mal_event_signal__posix(pContext, pEvent);
#endif
}
......@@ -4718,6 +4765,7 @@ static mal_bool32 mal_device_write__alsa(mal_device* pDevice)
break; // Success.
} else {
mal_post_error(pDevice, "[ALSA] snd_pcm_writei() failed when writing initial data.", MAL_FAILED_TO_SEND_DATA_TO_DEVICE);
return MAL_FALSE;
}
} else {
......@@ -7199,10 +7247,10 @@ mal_thread_result MAL_THREADCALL mal_worker_thread(void* pData)
// Let the other threads know that the device has stopped.
mal_device__set_state(pDevice, MAL_STATE_STOPPED);
mal_event_signal(&pDevice->stopEvent);
mal_event_signal(pDevice->pContext, &pDevice->stopEvent);
// We use an event to wait for a request to wake up.
mal_event_wait(&pDevice->wakeupEvent);
mal_event_wait(pDevice->pContext, &pDevice->wakeupEvent);
// Default result code.
pDevice->workResult = MAL_SUCCESS;
......@@ -7219,21 +7267,21 @@ mal_thread_result MAL_THREADCALL mal_worker_thread(void* pData)
pDevice->workResult = mal_device__start_backend(pDevice);
if (pDevice->workResult != MAL_SUCCESS) {
mal_event_signal(&pDevice->startEvent);
mal_event_signal(pDevice->pContext, &pDevice->startEvent);
continue;
}
// The thread that requested the device to start playing is waiting for this thread to start the
// device for real, which is now.
mal_device__set_state(pDevice, MAL_STATE_STARTED);
mal_event_signal(&pDevice->startEvent);
mal_event_signal(pDevice->pContext, &pDevice->startEvent);
// Now we just enter the main loop. The main loop can be broken with mal_device__break_main_loop().
mal_device__main_loop(pDevice);
}
// Make sure we aren't continuously waiting on a stop event.
mal_event_signal(&pDevice->stopEvent); // <-- Is this still needed?
mal_event_signal(pDevice->pContext, &pDevice->stopEvent); // <-- Is this still needed?
#ifdef MAL_WIN32
mal_CoUninitialize(pDevice->pContext);
......@@ -7282,13 +7330,41 @@ mal_result mal_context_init_backend_apis__win32(mal_context* pContext)
#else
mal_result mal_context_uninit_backend_apis__nix(mal_context* pContext)
{
(void)pContext;
mal_dlclose(pContext->posix.pthreadSO);
return MAL_SUCCESS;
}
mal_result mal_context_init_backend_apis__nix(mal_context* pContext)
{
(void)pContext;
// pthread
const char* libpthreadFileNames[] = {
"libpthread.so",
"libpthread.so.0"
};
for (size_t i = 0; i < sizeof(libpthreadFileNames) / sizeof(libpthreadFileNames[0]); ++i) {
pContext->posix.pthreadSO = mal_dlopen(libpthreadFileNames[i]);
if (pContext->posix.pthreadSO != NULL) {
break;
}
}
if (pContext->posix.pthreadSO == NULL) {
return MAL_FAILED_TO_INIT_BACKEND;
}
pContext->posix.pthread_create = (mal_proc)mal_dlsym(pContext->posix.pthreadSO, "pthread_create");
pContext->posix.pthread_join = (mal_proc)mal_dlsym(pContext->posix.pthreadSO, "pthread_join");
pContext->posix.pthread_mutex_init = (mal_proc)mal_dlsym(pContext->posix.pthreadSO, "pthread_mutex_init");
pContext->posix.pthread_mutex_destroy = (mal_proc)mal_dlsym(pContext->posix.pthreadSO, "pthread_mutex_destroy");
pContext->posix.pthread_mutex_lock = (mal_proc)mal_dlsym(pContext->posix.pthreadSO, "pthread_mutex_lock");
pContext->posix.pthread_mutex_unlock = (mal_proc)mal_dlsym(pContext->posix.pthreadSO, "pthread_mutex_unlock");
pContext->posix.pthread_cond_init = (mal_proc)mal_dlsym(pContext->posix.pthreadSO, "pthread_cond_init");
pContext->posix.pthread_cond_destroy = (mal_proc)mal_dlsym(pContext->posix.pthreadSO, "pthread_cond_destroy");
pContext->posix.pthread_cond_wait = (mal_proc)mal_dlsym(pContext->posix.pthreadSO, "pthread_cond_wait");
pContext->posix.pthread_cond_signal = (mal_proc)mal_dlsym(pContext->posix.pthreadSO, "pthread_cond_signal");
return MAL_SUCCESS;
}
#endif
......@@ -7302,7 +7378,6 @@ mal_result mal_context_init_backend_apis(mal_context* pContext)
result = mal_context_init_backend_apis__nix(pContext);
#endif
return result;
}
......@@ -7637,7 +7712,7 @@ mal_result mal_device_init(mal_context* pContext, mal_device_type type, mal_devi
pDevice->internalSampleRate = pDevice->sampleRate;
mal_copy_memory(pDevice->internalChannelMap, pDevice->channelMap, sizeof(pDevice->channelMap));
if (!mal_mutex_create(&pDevice->lock)) {
if (!mal_mutex_create(pContext, &pDevice->lock)) {
return mal_post_error(pDevice, "Failed to create mutex.", MAL_FAILED_TO_CREATE_MUTEX);
}
......@@ -7646,19 +7721,19 @@ mal_result mal_device_init(mal_context* pContext, mal_device_type type, mal_devi
//
// Each of these semaphores is released internally by the worker thread when the work is completed. The start
// semaphore is also used to wake up the worker thread.
if (!mal_event_create(&pDevice->wakeupEvent)) {
mal_mutex_delete(&pDevice->lock);
if (!mal_event_create(pContext, &pDevice->wakeupEvent)) {
mal_mutex_delete(pContext, &pDevice->lock);
return mal_post_error(pDevice, "Failed to create worker thread wakeup event.", MAL_FAILED_TO_CREATE_EVENT);
}
if (!mal_event_create(&pDevice->startEvent)) {
mal_event_delete(&pDevice->wakeupEvent);
mal_mutex_delete(&pDevice->lock);
if (!mal_event_create(pContext, &pDevice->startEvent)) {
mal_event_delete(pContext, &pDevice->wakeupEvent);
mal_mutex_delete(pContext, &pDevice->lock);
return mal_post_error(pDevice, "Failed to create worker thread start event.", MAL_FAILED_TO_CREATE_EVENT);
}
if (!mal_event_create(&pDevice->stopEvent)) {
mal_event_delete(&pDevice->startEvent);
mal_event_delete(&pDevice->wakeupEvent);
mal_mutex_delete(&pDevice->lock);
if (!mal_event_create(pContext, &pDevice->stopEvent)) {
mal_event_delete(pContext, &pDevice->startEvent);
mal_event_delete(pContext, &pDevice->wakeupEvent);
mal_mutex_delete(pContext, &pDevice->lock);
return mal_post_error(pDevice, "Failed to create worker thread stop event.", MAL_FAILED_TO_CREATE_EVENT);
}
......@@ -7755,13 +7830,13 @@ mal_result mal_device_init(mal_context* pContext, mal_device_type type, mal_devi
// Some backends don't require the worker thread.
if (pContext->backend != mal_backend_opensl) {
// The worker thread.
if (!mal_thread_create(&pDevice->thread, mal_worker_thread, pDevice)) {
if (!mal_thread_create(pContext, &pDevice->thread, mal_worker_thread, pDevice)) {
mal_device_uninit(pDevice);
return mal_post_error(pDevice, "Failed to create worker thread.", MAL_FAILED_TO_CREATE_THREAD);
}
// Wait for the worker thread to put the device into it's stopped state for real.
mal_event_wait(&pDevice->stopEvent);
mal_event_wait(pContext, &pDevice->stopEvent);
} else {
mal_device__set_state(pDevice, MAL_STATE_STOPPED);
}
......@@ -7787,14 +7862,14 @@ void mal_device_uninit(mal_device* pDevice)
// Wake up the worker thread and wait for it to properly terminate.
if (pDevice->pContext->backend != mal_backend_opensl) {
mal_event_signal(&pDevice->wakeupEvent);
mal_thread_wait(&pDevice->thread);
mal_event_signal(pDevice->pContext, &pDevice->wakeupEvent);
mal_thread_wait(pDevice->pContext, &pDevice->thread);
}
mal_event_delete(&pDevice->stopEvent);
mal_event_delete(&pDevice->startEvent);
mal_event_delete(&pDevice->wakeupEvent);
mal_mutex_delete(&pDevice->lock);
mal_event_delete(pDevice->pContext, &pDevice->stopEvent);
mal_event_delete(pDevice->pContext, &pDevice->startEvent);
mal_event_delete(pDevice->pContext, &pDevice->wakeupEvent);
mal_mutex_delete(pDevice->pContext, &pDevice->lock);
#ifdef MAL_ENABLE_WASAPI
if (pDevice->pContext->backend == mal_backend_wasapi) {
......@@ -7864,22 +7939,22 @@ mal_result mal_device_start(mal_device* pDevice)
if (mal_device__get_state(pDevice) == MAL_STATE_UNINITIALIZED) return mal_post_error(pDevice, "mal_device_start() called for an uninitialized device.", MAL_DEVICE_NOT_INITIALIZED);
mal_result result = MAL_ERROR;
mal_mutex_lock(&pDevice->lock);
mal_mutex_lock(pDevice->pContext, &pDevice->lock);
{
// Be a bit more descriptive if the device is already started or is already in the process of starting. This is likely
// a bug with the application.
if (mal_device__get_state(pDevice) == MAL_STATE_STARTING) {
mal_mutex_unlock(&pDevice->lock);
mal_mutex_unlock(pDevice->pContext, &pDevice->lock);
return mal_post_error(pDevice, "mal_device_start() called while another thread is already starting it.", MAL_DEVICE_ALREADY_STARTING);
}
if (mal_device__get_state(pDevice) == MAL_STATE_STARTED) {
mal_mutex_unlock(&pDevice->lock);
mal_mutex_unlock(pDevice->pContext, &pDevice->lock);
return mal_post_error(pDevice, "mal_device_start() called for a device that's already started.", MAL_DEVICE_ALREADY_STARTED);
}
// The device needs to be in a stopped state. If it's not, we just let the caller know the device is busy.
if (mal_device__get_state(pDevice) != MAL_STATE_STOPPED) {
mal_mutex_unlock(&pDevice->lock);
mal_mutex_unlock(pDevice->pContext, &pDevice->lock);
return mal_post_error(pDevice, "mal_device_start() called while another thread is in the process of stopping it.", MAL_DEVICE_BUSY);
}
......@@ -7894,15 +7969,15 @@ mal_result mal_device_start(mal_device* pDevice)
#endif
// Synchronous backends.
{
mal_event_signal(&pDevice->wakeupEvent);
mal_event_signal(pDevice->pContext, &pDevice->wakeupEvent);
// Wait for the worker thread to finish starting the device. Note that the worker thread will be the one
// who puts the device into the started state. Don't call mal_device__set_state() here.
mal_event_wait(&pDevice->startEvent);
mal_event_wait(pDevice->pContext, &pDevice->startEvent);
result = pDevice->workResult;
}
}
mal_mutex_unlock(&pDevice->lock);
mal_mutex_unlock(pDevice->pContext, &pDevice->lock);
return result;
}
......@@ -7913,22 +7988,22 @@ mal_result mal_device_stop(mal_device* pDevice)
if (mal_device__get_state(pDevice) == MAL_STATE_UNINITIALIZED) return mal_post_error(pDevice, "mal_device_stop() called for an uninitialized device.", MAL_DEVICE_NOT_INITIALIZED);
mal_result result = MAL_ERROR;
mal_mutex_lock(&pDevice->lock);
mal_mutex_lock(pDevice->pContext, &pDevice->lock);
{
// Be a bit more descriptive if the device is already stopped or is already in the process of stopping. This is likely
// a bug with the application.
if (mal_device__get_state(pDevice) == MAL_STATE_STOPPING) {
mal_mutex_unlock(&pDevice->lock);
mal_mutex_unlock(pDevice->pContext, &pDevice->lock);
return mal_post_error(pDevice, "mal_device_stop() called while another thread is already stopping it.", MAL_DEVICE_ALREADY_STOPPING);
}
if (mal_device__get_state(pDevice) == MAL_STATE_STOPPED) {
mal_mutex_unlock(&pDevice->lock);
mal_mutex_unlock(pDevice->pContext, &pDevice->lock);
return mal_post_error(pDevice, "mal_device_stop() called for a device that's already stopped.", MAL_DEVICE_ALREADY_STOPPED);
}
// The device needs to be in a started state. If it's not, we just let the caller know the device is busy.
if (mal_device__get_state(pDevice) != MAL_STATE_STARTED) {
mal_mutex_unlock(&pDevice->lock);
mal_mutex_unlock(pDevice->pContext, &pDevice->lock);
return mal_post_error(pDevice, "mal_device_stop() called while another thread is in the process of starting it.", MAL_DEVICE_BUSY);
}
......@@ -7950,11 +8025,11 @@ mal_result mal_device_stop(mal_device* pDevice)
// We need to wait for the worker thread to become available for work before returning. Note that the worker thread will be
// the one who puts the device into the stopped state. Don't call mal_device__set_state() here.
mal_event_wait(&pDevice->stopEvent);
mal_event_wait(pDevice->pContext, &pDevice->stopEvent);
result = MAL_SUCCESS;
}
}
mal_mutex_unlock(&pDevice->lock);
mal_mutex_unlock(pDevice->pContext, &pDevice->lock);
return result;
}
......@@ -9182,6 +9257,7 @@ void mal_pcm_f32_to_s32(int* pOut, const float* pIn, unsigned int count)
// - Added support for WinMM (waveOut/waveIn).
// - Added support for UWP (Universal Windows Platform) applications. Currently C++ only.
// - WASAPI is now the highest priority backend on Windows platforms.
// - Improved error handling.
//
// v0.3 - 2017-06-19
// - API CHANGE: Introduced the notion of a context. The context is the highest level object and is required for
......
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