From fe6e532c876bf3ec6776f76f9542038ac9c94d68 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 5 Mar 2012 07:11:09 -0800 Subject: [PATCH] Use a separate backend callback to start playback of the device This allows us to properly update the ALCdevice and its resources with the new parameters before starting playback, instead of expecting the mixer to block and wait after it has begun. This also lets us avoid holding the device lock while resetting and starting the device, which helps prevent lock inversion on some backends (ie, one thread locking A then B, and another thread locking B then A), ultimately allowing certain backends to asynchronously update the ALCdevice without risk of lockup. Capture still has issues here, however. --- Alc/ALc.c | 20 +++++------ Alc/backends/alsa.c | 49 +++++++++++++++++++++------ Alc/backends/dsound.c | 53 ++++++++++++++++++++---------- Alc/backends/loopback.c | 7 ++++ Alc/backends/mmdevapi.c | 84 ++++++++++++++++++++++++++++++----------------- Alc/backends/null.c | 9 +++-- Alc/backends/opensl.c | 40 ++++++++++++++++------ Alc/backends/oss.c | 14 ++++++-- Alc/backends/portaudio.c | 10 +++++- Alc/backends/pulseaudio.c | 41 ++++++++++++----------- Alc/backends/sndio.c | 10 +++++- Alc/backends/solaris.c | 14 ++++++-- Alc/backends/wave.c | 15 ++++++--- Alc/backends/winmm.c | 22 +++++++++---- OpenAL32/Include/alMain.h | 2 ++ 15 files changed, 273 insertions(+), 117 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index 024350ae..9ac841b3 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -40,7 +40,7 @@ #include "alu.h" -#define EmptyFuncs { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL } +#define EmptyFuncs { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL } static struct BackendInfo BackendList[] = { #ifdef HAVE_PULSEAUDIO { "pulse", alc_pulse_init, alc_pulse_deinit, alc_pulse_probe, EmptyFuncs }, @@ -1197,8 +1197,6 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) if((device->Flags&DEVICE_RUNNING)) return ALC_NO_ERROR; - LockDevice(device); - oldFreq = device->Frequency; oldChans = device->FmtChans; oldType = device->FmtType; @@ -1211,12 +1209,9 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) device->Frequency, (device->Flags&DEVICE_FREQUENCY_REQUEST)?" (requested)":"", device->UpdateSize, device->NumUpdates); + if(ALCdevice_ResetPlayback(device) == ALC_FALSE) - { - UnlockDevice(device); return ALC_INVALID_DEVICE; - } - device->Flags |= DEVICE_RUNNING; if(device->FmtChans != oldChans && (device->Flags&DEVICE_CHANNELS_REQUEST)) { @@ -1290,6 +1285,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) TRACE("Stereo duplication %s\n", (device->Flags&DEVICE_DUPLICATE_STEREO)?"enabled":"disabled"); oldMode = SetMixerFPUMode(); + LockDevice(device); context = device->ContextList; while(context) { @@ -1304,10 +1300,8 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) if(ALeffectState_DeviceUpdate(slot->EffectState, device) == AL_FALSE) { UnlockUIntMapRead(&context->EffectSlotMap); - RestoreFPUMode(oldMode); UnlockDevice(device); - ALCdevice_StopPlayback(device); - device->Flags &= ~DEVICE_RUNNING; + RestoreFPUMode(oldMode); return ALC_INVALID_DEVICE; } slot->NeedsUpdate = AL_FALSE; @@ -1336,8 +1330,12 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) context = context->next; } - RestoreFPUMode(oldMode); UnlockDevice(device); + RestoreFPUMode(oldMode); + + if(ALCdevice_StartPlayback(device) == ALC_FALSE) + return ALC_INVALID_DEVICE; + device->Flags |= DEVICE_RUNNING; return ALC_NO_ERROR; } diff --git a/Alc/backends/alsa.c b/Alc/backends/alsa.c index a9f34491..fa5ef1a6 100644 --- a/Alc/backends/alsa.c +++ b/Alc/backends/alsa.c @@ -44,6 +44,7 @@ MAKE_FUNC(snd_pcm_bytes_to_frames); MAKE_FUNC(snd_pcm_hw_params_malloc); MAKE_FUNC(snd_pcm_hw_params_free); MAKE_FUNC(snd_pcm_hw_params_any); +MAKE_FUNC(snd_pcm_hw_params_current); MAKE_FUNC(snd_pcm_hw_params_set_access); MAKE_FUNC(snd_pcm_hw_params_set_format); MAKE_FUNC(snd_pcm_hw_params_set_channels); @@ -111,6 +112,7 @@ MAKE_FUNC(snd_card_next); #define snd_pcm_hw_params_malloc psnd_pcm_hw_params_malloc #define snd_pcm_hw_params_free psnd_pcm_hw_params_free #define snd_pcm_hw_params_any psnd_pcm_hw_params_any +#define snd_pcm_hw_params_current psnd_pcm_hw_params_current #define snd_pcm_hw_params_set_access psnd_pcm_hw_params_set_access #define snd_pcm_hw_params_set_format psnd_pcm_hw_params_set_format #define snd_pcm_hw_params_set_channels psnd_pcm_hw_params_set_channels @@ -196,6 +198,7 @@ static ALCboolean alsa_load(void) LOAD_FUNC(snd_pcm_hw_params_malloc); LOAD_FUNC(snd_pcm_hw_params_free); LOAD_FUNC(snd_pcm_hw_params_any); + LOAD_FUNC(snd_pcm_hw_params_current); LOAD_FUNC(snd_pcm_hw_params_set_access); LOAD_FUNC(snd_pcm_hw_params_set_format); LOAD_FUNC(snd_pcm_hw_params_set_channels); @@ -647,7 +650,6 @@ static ALCboolean alsa_reset_playback(ALCdevice *device) int allowmmap; int err; - format = -1; switch(device->FmtType) { @@ -770,23 +772,52 @@ static ALCboolean alsa_reset_playback(ALCdevice *device) snd_pcm_sw_params_free(sp); sp = NULL; + /* Increase periods by one, since the temp buffer counts as an extra + * period */ + if(access == SND_PCM_ACCESS_RW_INTERLEAVED) + device->NumUpdates = periods+1; + else + device->NumUpdates = periods; + device->UpdateSize = periodSizeInFrames; device->Frequency = rate; + SetDefaultChannelOrder(device); - data->size = snd_pcm_frames_to_bytes(data->pcmHandle, periodSizeInFrames); + return ALC_TRUE; + +error: + ERR("%s failed: %s\n", funcerr, snd_strerror(err)); + if(hp) snd_pcm_hw_params_free(hp); + if(sp) snd_pcm_sw_params_free(sp); + return ALC_FALSE; +} + +static ALCboolean alsa_start_playback(ALCdevice *device) +{ + alsa_data *data = (alsa_data*)device->ExtraData; + snd_pcm_hw_params_t *hp = NULL; + snd_pcm_access_t access; + const char *funcerr; + int err; + + snd_pcm_hw_params_malloc(&hp); +#define CHECK(x) if((funcerr=#x),(err=(x)) < 0) goto error + CHECK(snd_pcm_hw_params_current(data->pcmHandle, hp)); + /* retrieve configuration info */ + CHECK(snd_pcm_hw_params_get_access(hp, &access)); +#undef CHECK + snd_pcm_hw_params_free(hp); + hp = NULL; + + data->size = snd_pcm_frames_to_bytes(data->pcmHandle, device->UpdateSize); if(access == SND_PCM_ACCESS_RW_INTERLEAVED) { - /* Increase periods by one, since the temp buffer counts as an extra - * period */ - periods++; data->buffer = malloc(data->size); if(!data->buffer) { ERR("buffer malloc failed\n"); return ALC_FALSE; } - device->UpdateSize = periodSizeInFrames; - device->NumUpdates = periods; data->thread = StartThread(ALSANoMMapProc, device); } else @@ -797,8 +828,6 @@ static ALCboolean alsa_reset_playback(ALCdevice *device) ERR("snd_pcm_prepare(data->pcmHandle) failed: %s\n", snd_strerror(err)); return ALC_FALSE; } - device->UpdateSize = periodSizeInFrames; - device->NumUpdates = periods; data->thread = StartThread(ALSAProc, device); } if(data->thread == NULL) @@ -814,7 +843,6 @@ static ALCboolean alsa_reset_playback(ALCdevice *device) error: ERR("%s failed: %s\n", funcerr, snd_strerror(err)); if(hp) snd_pcm_hw_params_free(hp); - if(sp) snd_pcm_sw_params_free(sp); return ALC_FALSE; } @@ -1186,6 +1214,7 @@ static const BackendFuncs alsa_funcs = { alsa_open_playback, alsa_close_playback, alsa_reset_playback, + alsa_start_playback, alsa_stop_playback, alsa_open_capture, alsa_close_capture, diff --git a/Alc/backends/dsound.c b/Alc/backends/dsound.c index feca3cfa..0eab62a4 100644 --- a/Alc/backends/dsound.c +++ b/Alc/backends/dsound.c @@ -392,6 +392,16 @@ static void DSoundClosePlayback(ALCdevice *device) { DSoundPlaybackData *pData = device->ExtraData; + if(pData->DSnotify) + IDirectSoundNotify_Release(pData->DSnotify); + pData->DSnotify = NULL; + if(pData->DSsbuffer) + IDirectSoundBuffer_Release(pData->DSsbuffer); + pData->DSsbuffer = NULL; + if(pData->DSpbuffer != NULL) + IDirectSoundBuffer_Release(pData->DSpbuffer); + pData->DSpbuffer = NULL; + IDirectSound_Release(pData->lpDS); CloseHandle(pData->hNotifyEvent); free(pData); @@ -408,6 +418,16 @@ static ALCboolean DSoundResetPlayback(ALCdevice *device) memset(&OutputType, 0, sizeof(OutputType)); + if(pData->DSnotify) + IDirectSoundNotify_Release(pData->DSnotify); + pData->DSnotify = NULL; + if(pData->DSsbuffer) + IDirectSoundBuffer_Release(pData->DSsbuffer); + pData->DSsbuffer = NULL; + if(pData->DSpbuffer != NULL) + IDirectSoundBuffer_Release(pData->DSpbuffer); + pData->DSpbuffer = NULL; + switch(device->FmtType) { case DevFmtByte: @@ -578,15 +598,6 @@ retry_open: } } - if(SUCCEEDED(hr)) - { - ResetEvent(pData->hNotifyEvent); - SetDefaultWFXChannelOrder(device); - pData->thread = StartThread(DSoundPlaybackProc, device); - if(pData->thread == NULL) - hr = E_FAIL; - } - if(FAILED(hr)) { if(pData->DSnotify != NULL) @@ -601,6 +612,20 @@ retry_open: return ALC_FALSE; } + ResetEvent(pData->hNotifyEvent); + SetDefaultWFXChannelOrder(device); + + return ALC_TRUE; +} + +static ALCboolean DSoundStartPlayback(ALCdevice *device) +{ + DSoundPlaybackData *pData = (DSoundPlaybackData*)device->ExtraData; + + pData->thread = StartThread(DSoundPlaybackProc, device); + if(pData->thread == NULL) + return ALC_FALSE; + return ALC_TRUE; } @@ -616,14 +641,7 @@ static void DSoundStopPlayback(ALCdevice *device) pData->thread = NULL; pData->killNow = 0; - - IDirectSoundNotify_Release(pData->DSnotify); - pData->DSnotify = NULL; - IDirectSoundBuffer_Release(pData->DSsbuffer); - pData->DSsbuffer = NULL; - if(pData->DSpbuffer != NULL) - IDirectSoundBuffer_Release(pData->DSpbuffer); - pData->DSpbuffer = NULL; + IDirectSoundBuffer_Stop(pData->DSsbuffer); } @@ -918,6 +936,7 @@ static const BackendFuncs DSoundFuncs = { DSoundOpenPlayback, DSoundClosePlayback, DSoundResetPlayback, + DSoundStartPlayback, DSoundStopPlayback, DSoundOpenCapture, DSoundCloseCapture, diff --git a/Alc/backends/loopback.c b/Alc/backends/loopback.c index 8a576361..3726974c 100644 --- a/Alc/backends/loopback.c +++ b/Alc/backends/loopback.c @@ -43,6 +43,12 @@ static ALCboolean loopback_reset_playback(ALCdevice *device) return ALC_TRUE; } +static ALCboolean loopback_start_playback(ALCdevice *device) +{ + return ALC_TRUE; + (void)device; +} + static void loopback_stop_playback(ALCdevice *device) { (void)device; @@ -52,6 +58,7 @@ static const BackendFuncs loopback_funcs = { loopback_open_playback, loopback_close_playback, loopback_reset_playback, + loopback_start_playback, loopback_stop_playback, NULL, NULL, diff --git a/Alc/backends/mmdevapi.c b/Alc/backends/mmdevapi.c index 52b54eb4..ccfb1a44 100644 --- a/Alc/backends/mmdevapi.c +++ b/Alc/backends/mmdevapi.c @@ -90,9 +90,10 @@ typedef struct { #define WM_USER_OpenDevice (WM_USER+0) #define WM_USER_ResetDevice (WM_USER+1) -#define WM_USER_StopDevice (WM_USER+2) -#define WM_USER_CloseDevice (WM_USER+3) -#define WM_USER_Enumerate (WM_USER+4) +#define WM_USER_StartDevice (WM_USER+2) +#define WM_USER_StopDevice (WM_USER+3) +#define WM_USER_CloseDevice (WM_USER+4) +#define WM_USER_Enumerate (WM_USER+5) static HRESULT WaitForResponse(ThreadRequest *req) { @@ -315,7 +316,6 @@ static HRESULT DoReset(ALCdevice *device) REFERENCE_TIME min_per, buf_time; UINT32 buffer_len, min_len; HRESULT hr; - void *ptr; hr = IAudioClient_GetMixFormat(data->client, &wfx); if(FAILED(hr)) @@ -532,32 +532,6 @@ static HRESULT DoReset(ALCdevice *device) ERR("Audio client returned buffer_len < period*2; expect break up\n"); } - ResetEvent(data->hNotifyEvent); - hr = IAudioClient_SetEventHandle(data->client, data->hNotifyEvent); - if(SUCCEEDED(hr)) - hr = IAudioClient_Start(data->client); - if(FAILED(hr)) - { - ERR("Failed to start audio client: 0x%08lx\n", hr); - return hr; - } - - hr = IAudioClient_GetService(data->client, &IID_IAudioRenderClient, &ptr); - if(SUCCEEDED(hr)) - { - data->render = ptr; - data->thread = StartThread(MMDevApiProc, device); - } - if(!data->thread) - { - if(data->render) - IAudioRenderClient_Release(data->render); - data->render = NULL; - IAudioClient_Stop(data->client); - ERR("Failed to start thread\n"); - return E_FAIL; - } - return hr; } @@ -656,6 +630,43 @@ static DWORD CALLBACK MMDevApiMsgProc(void *ptr) SetEvent(req->FinishedEvt); continue; + case WM_USER_StartDevice: + req = (ThreadRequest*)msg.wParam; + device = (ALCdevice*)msg.lParam; + data = device->ExtraData; + + ResetEvent(data->hNotifyEvent); + hr = IAudioClient_SetEventHandle(data->client, data->hNotifyEvent); + if(FAILED(hr)) + ERR("Failed to set event handle: 0x%08lx\n", hr); + else + { + hr = IAudioClient_Start(data->client); + if(FAILED(hr)) + ERR("Failed to start audio client: 0x%08lx\n", hr); + } + + if(SUCCEEDED(hr)) + hr = IAudioClient_GetService(data->client, &IID_IAudioRenderClient, &ptr); + if(SUCCEEDED(hr)) + { + data->render = ptr; + data->thread = StartThread(MMDevApiProc, device); + if(!data->thread) + { + if(data->render) + IAudioRenderClient_Release(data->render); + data->render = NULL; + IAudioClient_Stop(data->client); + ERR("Failed to start thread\n"); + hr = E_FAIL; + } + } + + req->result = hr; + SetEvent(req->FinishedEvt); + continue; + case WM_USER_StopDevice: req = (ThreadRequest*)msg.wParam; device = (ALCdevice*)msg.lParam; @@ -885,6 +896,18 @@ static ALCboolean MMDevApiResetPlayback(ALCdevice *device) return SUCCEEDED(hr) ? ALC_TRUE : ALC_FALSE; } +static ALCboolean MMDevApiStartPlayback(ALCdevice *device) +{ + MMDevApiData *data = device->ExtraData; + ThreadRequest req = { data->MsgEvent, 0 }; + HRESULT hr = E_FAIL; + + if(PostThreadMessage(ThreadID, WM_USER_StartDevice, (WPARAM)&req, (LPARAM)device)) + hr = WaitForResponse(&req); + + return SUCCEEDED(hr) ? ALC_TRUE : ALC_FALSE; +} + static void MMDevApiStopPlayback(ALCdevice *device) { MMDevApiData *data = device->ExtraData; @@ -899,6 +922,7 @@ static const BackendFuncs MMDevApiFuncs = { MMDevApiOpenPlayback, MMDevApiClosePlayback, MMDevApiResetPlayback, + MMDevApiStartPlayback, MMDevApiStopPlayback, NULL, NULL, diff --git a/Alc/backends/null.c b/Alc/backends/null.c index 10068630..8fc60b66 100644 --- a/Alc/backends/null.c +++ b/Alc/backends/null.c @@ -99,9 +99,13 @@ static void null_close_playback(ALCdevice *device) static ALCboolean null_reset_playback(ALCdevice *device) { - null_data *data = (null_data*)device->ExtraData; - SetDefaultWFXChannelOrder(device); + return ALC_TRUE; +} + +static ALCboolean null_start_playback(ALCdevice *device) +{ + null_data *data = (null_data*)device->ExtraData; data->thread = StartThread(NullProc, device); if(data->thread == NULL) @@ -129,6 +133,7 @@ static const BackendFuncs null_funcs = { null_open_playback, null_close_playback, null_reset_playback, + null_start_playback, null_stop_playback, NULL, NULL, diff --git a/Alc/backends/opensl.c b/Alc/backends/opensl.c index 58acc828..5ff60276 100644 --- a/Alc/backends/opensl.c +++ b/Alc/backends/opensl.c @@ -242,6 +242,10 @@ static void opensl_close_playback(ALCdevice *Device) { osl_data *data = Device->ExtraData; + if(data->bufferQueueObject != NULL) + SLObjectItf_Destroy(data->bufferQueueObject); + data->bufferQueueObject = NULL; + SLObjectItf_Destroy(data->outputMix); data->outputMix = NULL; @@ -257,16 +261,13 @@ static ALCboolean opensl_reset_playback(ALCdevice *Device) { osl_data *data = Device->ExtraData; SLDataLocator_AndroidSimpleBufferQueue loc_bufq; - SLAndroidSimpleBufferQueueItf bufferQueue; SLDataLocator_OutputMix loc_outmix; SLDataFormat_PCM format_pcm; SLDataSource audioSrc; SLDataSink audioSnk; - SLPlayItf player; SLInterfaceID id; SLboolean req; SLresult result; - ALuint i; Device->UpdateSize = (ALuint64)Device->UpdateSize * 44100 / Device->Frequency; @@ -303,6 +304,10 @@ static ALCboolean opensl_reset_playback(ALCdevice *Device) audioSnk.pFormat = NULL; + if(data->bufferQueueObject != NULL) + SLObjectItf_Destroy(data->bufferQueueObject); + data->bufferQueueObject = NULL; + result = SLEngineItf_CreateAudioPlayer(data->engine, &data->bufferQueueObject, &audioSrc, &audioSnk, 1, &id, &req); PRINTERR(result, "engine->CreateAudioPlayer"); if(SL_RESULT_SUCCESS == result) @@ -310,11 +315,29 @@ static ALCboolean opensl_reset_playback(ALCdevice *Device) result = SLObjectItf_Realize(data->bufferQueueObject, SL_BOOLEAN_FALSE); PRINTERR(result, "bufferQueue->Realize"); } - if(SL_RESULT_SUCCESS == result) + + if(SL_RESULT_SUCCESS != result) { - result = SLObjectItf_GetInterface(data->bufferQueueObject, SL_IID_BUFFERQUEUE, &bufferQueue); - PRINTERR(result, "bufferQueue->GetInterface"); + if(data->bufferQueueObject != NULL) + SLObjectItf_Destroy(data->bufferQueueObject); + data->bufferQueueObject = NULL; + + return ALC_FALSE; } + + return ALC_TRUE; +} + +static ALCboolean opensl_start_playback(ALCdevice *Device) +{ + osl_data *data = Device->ExtraData; + SLAndroidSimpleBufferQueueItf bufferQueue; + SLPlayItf player; + SLresult result; + ALuint i; + + result = SLObjectItf_GetInterface(data->bufferQueueObject, SL_IID_BUFFERQUEUE, &bufferQueue); + PRINTERR(result, "bufferQueue->GetInterface"); if(SL_RESULT_SUCCESS == result) { result = (*bufferQueue)->RegisterCallback(bufferQueue, opensl_callback, Device); @@ -372,10 +395,6 @@ static void opensl_stop_playback(ALCdevice *Device) { osl_data *data = Device->ExtraData; - if(data->bufferQueueObject != NULL) - SLObjectItf_Destroy(data->bufferQueueObject); - data->bufferQueueObject = NULL; - free(data->buffer); data->buffer = NULL; data->bufferSize = 0; @@ -386,6 +405,7 @@ static const BackendFuncs opensl_funcs = { opensl_open_playback, opensl_close_playback, opensl_reset_playback, + opensl_start_playback, opensl_stop_playback, NULL, NULL, diff --git a/Alc/backends/oss.c b/Alc/backends/oss.c index bd489e3e..a577d8be 100644 --- a/Alc/backends/oss.c +++ b/Alc/backends/oss.c @@ -268,11 +268,18 @@ static ALCboolean oss_reset_playback(ALCdevice *device) device->UpdateSize = info.fragsize / frameSize; device->NumUpdates = info.fragments + 1; - data->data_size = device->UpdateSize * frameSize; - data->mix_data = calloc(1, data->data_size); - SetDefaultChannelOrder(device); + return ALC_TRUE; +} + +static ALCboolean oss_start_playback(ALCdevice *device) +{ + oss_data *data = (oss_data*)device->ExtraData; + + data->data_size = device->UpdateSize * FrameSizeFromDevFmt(device->FmtChans, device->FmtType); + data->mix_data = calloc(1, data->data_size); + data->thread = StartThread(OSSProc, device); if(data->thread == NULL) { @@ -473,6 +480,7 @@ static const BackendFuncs oss_funcs = { oss_open_playback, oss_close_playback, oss_reset_playback, + oss_start_playback, oss_stop_playback, oss_open_capture, oss_close_capture, diff --git a/Alc/backends/portaudio.c b/Alc/backends/portaudio.c index 154b6349..03e54d14 100644 --- a/Alc/backends/portaudio.c +++ b/Alc/backends/portaudio.c @@ -261,12 +261,19 @@ static ALCboolean pa_reset_playback(ALCdevice *device) { pa_data *data = (pa_data*)device->ExtraData; const PaStreamInfo *streamInfo; - PaError err; streamInfo = Pa_GetStreamInfo(data->stream); device->Frequency = streamInfo->sampleRate; device->UpdateSize = data->update_size; + return ALC_TRUE; +} + +static ALCboolean pa_start_playback(ALCdevice *device) +{ + pa_data *data = (pa_data*)device->ExtraData; + PaError err; + err = Pa_StartStream(data->stream); if(err != paNoError) { @@ -409,6 +416,7 @@ static const BackendFuncs pa_funcs = { pa_open_playback, pa_close_playback, pa_reset_playback, + pa_start_playback, pa_stop_playback, pa_open_capture, pa_close_capture, diff --git a/Alc/backends/pulseaudio.c b/Alc/backends/pulseaudio.c index 8fe1118b..78854da7 100644 --- a/Alc/backends/pulseaudio.c +++ b/Alc/backends/pulseaudio.c @@ -873,6 +873,10 @@ static void pulse_close(ALCdevice *device) if(data->stream) { +#if PA_CHECK_VERSION(0,9,15) + if(pa_stream_set_buffer_attr_callback) + pa_stream_set_buffer_attr_callback(data->stream, NULL, NULL); +#endif pa_stream_disconnect(data->stream); pa_stream_unref(data->stream); } @@ -968,6 +972,10 @@ static ALCboolean pulse_reset_playback(ALCdevice *device) if(data->stream) { +#if PA_CHECK_VERSION(0,9,15) + if(pa_stream_set_buffer_attr_callback) + pa_stream_set_buffer_attr_callback(data->stream, NULL, NULL); +#endif pa_stream_disconnect(data->stream); pa_stream_unref(data->stream); data->stream = NULL; @@ -1079,28 +1087,25 @@ static ALCboolean pulse_reset_playback(ALCdevice *device) device->NumUpdates = maxu(device->NumUpdates, 2); device->UpdateSize = data->attr.minreq / pa_frame_size(&data->spec); + pa_threaded_mainloop_unlock(data->loop); + return ALC_TRUE; +} + +static ALCboolean pulse_start_playback(ALCdevice *device) +{ + pulse_data *data = device->ExtraData; + data->thread = StartThread(PulseProc, device); if(!data->thread) - { -#if PA_CHECK_VERSION(0,9,15) - if(pa_stream_set_buffer_attr_callback) - pa_stream_set_buffer_attr_callback(data->stream, NULL, NULL); -#endif - pa_stream_disconnect(data->stream); - pa_stream_unref(data->stream); - data->stream = NULL; - - pa_threaded_mainloop_unlock(data->loop); return ALC_FALSE; - } - pa_threaded_mainloop_unlock(data->loop); return ALC_TRUE; } static void pulse_stop_playback(ALCdevice *device) { pulse_data *data = device->ExtraData; + pa_operation *o; if(!data->stream) return; @@ -1115,13 +1120,10 @@ static void pulse_stop_playback(ALCdevice *device) pa_threaded_mainloop_lock(data->loop); -#if PA_CHECK_VERSION(0,9,15) - if(pa_stream_set_buffer_attr_callback) - pa_stream_set_buffer_attr_callback(data->stream, NULL, NULL); -#endif - pa_stream_disconnect(data->stream); - pa_stream_unref(data->stream); - data->stream = NULL; + o = pa_stream_cork(data->stream, 1, stream_success_callback, device); + while(pa_operation_get_state(o) == PA_OPERATION_RUNNING) + pa_threaded_mainloop_wait(data->loop); + pa_operation_unref(o); pa_threaded_mainloop_unlock(data->loop); } @@ -1352,6 +1354,7 @@ static const BackendFuncs pulse_funcs = { pulse_open_playback, pulse_close_playback, pulse_reset_playback, + pulse_start_playback, pulse_stop_playback, pulse_open_capture, pulse_close_capture, diff --git a/Alc/backends/sndio.c b/Alc/backends/sndio.c index 6be98c2f..fc368951 100644 --- a/Alc/backends/sndio.c +++ b/Alc/backends/sndio.c @@ -280,13 +280,20 @@ static ALCboolean sndio_reset_playback(ALCdevice *device) SetDefaultChannelOrder(device); + return ALC_TRUE; +} + +static ALCboolean sndio_start_playback(ALCdevice *device) +{ + sndio_data *data = device->ExtraData; + if(!sio_start(data->sndHandle)) { ERR("Error starting playback\n"); return ALC_FALSE; } - data->data_size = device->UpdateSize * par.bps * par.pchan; + data->data_size = device->UpdateSize * FrameSizeFromDevFmt(device->FmtChans, device->FmtType); data->mix_data = calloc(1, data->data_size); data->thread = StartThread(sndio_proc, device); @@ -325,6 +332,7 @@ static const BackendFuncs sndio_funcs = { sndio_open_playback, sndio_close_playback, sndio_reset_playback, + sndio_start_playback, sndio_stop_playback, NULL, NULL, diff --git a/Alc/backends/solaris.c b/Alc/backends/solaris.c index bf0f57f5..26d923c7 100644 --- a/Alc/backends/solaris.c +++ b/Alc/backends/solaris.c @@ -193,11 +193,18 @@ static ALCboolean solaris_reset_playback(ALCdevice *device) device->Frequency = info.play.sample_rate; device->UpdateSize = (info.play.buffer_size/device->NumUpdates) + 1; - data->data_size = device->UpdateSize * frameSize; - data->mix_data = calloc(1, data->data_size); - SetDefaultChannelOrder(device); + return ALC_TRUE; +} + +static ALCboolean solaris_start_playback(ALCdevice *device) +{ + solaris_data *data = (solaris_data*)device->ExtraData; + + data->data_size = device->UpdateSize * FrameSizeFromDevFmt(device->FmtChans, device->FmtType); + data->mix_data = calloc(1, data->data_size); + data->thread = StartThread(SolarisProc, device); if(data->thread == NULL) { @@ -233,6 +240,7 @@ static const BackendFuncs solaris_funcs = { solaris_open_playback, solaris_close_playback, solaris_reset_playback, + solaris_start_playback, solaris_stop_playback, NULL, NULL, diff --git a/Alc/backends/wave.c b/Alc/backends/wave.c index ad187896..d9f1fdc7 100644 --- a/Alc/backends/wave.c +++ b/Alc/backends/wave.c @@ -258,10 +258,18 @@ static ALCboolean wave_reset_playback(ALCdevice *device) ERR("Error writing header: %s\n", strerror(errno)); return ALC_FALSE; } - data->DataStart = ftell(data->f); - data->size = device->UpdateSize * channels * bits / 8; + SetDefaultWFXChannelOrder(device); + + return ALC_TRUE; +} + +static ALCboolean wave_start_playback(ALCdevice *device) +{ + wave_data *data = (wave_data*)device->ExtraData; + + data->size = device->UpdateSize * FrameSizeFromDevFmt(device->FmtChans, device->FmtType); data->buffer = malloc(data->size); if(!data->buffer) { @@ -269,8 +277,6 @@ static ALCboolean wave_reset_playback(ALCdevice *device) return ALC_FALSE; } - SetDefaultWFXChannelOrder(device); - data->thread = StartThread(WaveProc, device); if(data->thread == NULL) { @@ -316,6 +322,7 @@ static const BackendFuncs wave_funcs = { wave_open_playback, wave_close_playback, wave_reset_playback, + wave_start_playback, wave_stop_playback, NULL, NULL, diff --git a/Alc/backends/winmm.c b/Alc/backends/winmm.c index 9f2c6316..57d27974 100644 --- a/Alc/backends/winmm.c +++ b/Alc/backends/winmm.c @@ -397,6 +397,21 @@ static void WinMMClosePlayback(ALCdevice *device) static ALCboolean WinMMResetPlayback(ALCdevice *device) { WinMMData *pData = (WinMMData*)device->ExtraData; + + device->UpdateSize = (ALuint)((ALuint64)device->UpdateSize * + pData->Frequency / device->Frequency); + device->UpdateSize = device->UpdateSize*device->NumUpdates / 4; + device->NumUpdates = 4; + device->Frequency = pData->Frequency; + + SetDefaultWFXChannelOrder(device); + + return ALC_TRUE; +} + +static ALCboolean WinMMStartPlayback(ALCdevice *device) +{ + WinMMData *pData = (WinMMData*)device->ExtraData; ALbyte *BufferData; ALint lBufferSize; ALuint i; @@ -405,12 +420,6 @@ static ALCboolean WinMMResetPlayback(ALCdevice *device) if(pData->hWaveThread == NULL) return ALC_FALSE; - device->UpdateSize = (ALuint)((ALuint64)device->UpdateSize * - pData->Frequency / device->Frequency); - device->Frequency = pData->Frequency; - - SetDefaultWFXChannelOrder(device); - pData->lWaveBuffersCommitted = 0; // Create 4 Buffers @@ -689,6 +698,7 @@ static const BackendFuncs WinMMFuncs = { WinMMOpenPlayback, WinMMClosePlayback, WinMMResetPlayback, + WinMMStartPlayback, WinMMStopPlayback, WinMMOpenCapture, WinMMCloseCapture, diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 2fbea8c3..20f6d656 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -449,6 +449,7 @@ typedef struct { ALCenum (*OpenPlayback)(ALCdevice*, const ALCchar*); void (*ClosePlayback)(ALCdevice*); ALCboolean (*ResetPlayback)(ALCdevice*); + ALCboolean (*StartPlayback)(ALCdevice*); void (*StopPlayback)(ALCdevice*); ALCenum (*OpenCapture)(ALCdevice*, const ALCchar*); @@ -630,6 +631,7 @@ struct ALCdevice_struct #define ALCdevice_OpenPlayback(a,b) ((a)->Funcs->OpenPlayback((a), (b))) #define ALCdevice_ClosePlayback(a) ((a)->Funcs->ClosePlayback((a))) #define ALCdevice_ResetPlayback(a) ((a)->Funcs->ResetPlayback((a))) +#define ALCdevice_StartPlayback(a) ((a)->Funcs->StartPlayback((a))) #define ALCdevice_StopPlayback(a) ((a)->Funcs->StopPlayback((a))) #define ALCdevice_OpenCapture(a,b) ((a)->Funcs->OpenCapture((a), (b))) #define ALCdevice_CloseCapture(a) ((a)->Funcs->CloseCapture((a))) -- 2.11.4.GIT