Refactored winmm backend
Using CALLBACK_FUNCTION again, but protect with semaphore to avoid closing the device while there are still buffers to be played.
This commit is contained in:
parent
208fbabfde
commit
1b9e01509d
@ -41,6 +41,8 @@
|
||||
|
||||
#include "rdpsnd_main.h"
|
||||
|
||||
#define SEM_COUNT_MAX 4
|
||||
|
||||
typedef struct rdpsnd_winmm_plugin rdpsndWinmmPlugin;
|
||||
|
||||
struct rdpsnd_winmm_plugin
|
||||
@ -51,7 +53,8 @@ struct rdpsnd_winmm_plugin
|
||||
WAVEFORMATEX format;
|
||||
UINT32 volume;
|
||||
wLog* log;
|
||||
HANDLE playedEvent;
|
||||
UINT32 latency;
|
||||
HANDLE semaphore;
|
||||
};
|
||||
|
||||
static BOOL rdpsnd_winmm_convert_format(const AUDIO_FORMAT* in, WAVEFORMATEX* out)
|
||||
@ -84,14 +87,39 @@ static BOOL rdpsnd_winmm_set_format(rdpsndDevicePlugin* device, const AUDIO_FORM
|
||||
{
|
||||
rdpsndWinmmPlugin* winmm = (rdpsndWinmmPlugin*) device;
|
||||
|
||||
WINPR_UNUSED(latency);
|
||||
|
||||
winmm->latency = latency;
|
||||
if (!rdpsnd_winmm_convert_format(format, &winmm->format))
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void CALLBACK waveOutProc(
|
||||
HWAVEOUT hwo,
|
||||
UINT uMsg,
|
||||
DWORD_PTR dwInstance,
|
||||
DWORD_PTR dwParam1,
|
||||
DWORD_PTR dwParam2
|
||||
)
|
||||
{
|
||||
rdpsndWinmmPlugin* winmm = (rdpsndWinmmPlugin*) dwInstance;
|
||||
LPWAVEHDR lpWaveHdr = (LPWAVEHDR)dwParam1;
|
||||
|
||||
switch(uMsg)
|
||||
{
|
||||
case WOM_OPEN:
|
||||
case WOM_CLOSE:
|
||||
break;
|
||||
case WOM_DONE:
|
||||
waveOutUnprepareHeader(hwo, lpWaveHdr, sizeof(WAVEHDR));
|
||||
free(lpWaveHdr);
|
||||
ReleaseSemaphore(winmm->semaphore, 1, NULL);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static BOOL rdpsnd_winmm_open(rdpsndDevicePlugin* device, const AUDIO_FORMAT* format,
|
||||
UINT32 latency)
|
||||
{
|
||||
@ -105,8 +133,8 @@ static BOOL rdpsnd_winmm_open(rdpsndDevicePlugin* device, const AUDIO_FORMAT* fo
|
||||
return FALSE;
|
||||
|
||||
mmResult = waveOutOpen(&winmm->hWaveOut, WAVE_MAPPER, &winmm->format,
|
||||
(DWORD_PTR) winmm->playedEvent, (DWORD_PTR)NULL,
|
||||
CALLBACK_EVENT);
|
||||
(DWORD_PTR) waveOutProc, (DWORD_PTR)winmm,
|
||||
CALLBACK_FUNCTION);
|
||||
|
||||
if (mmResult != MMSYSERR_NOERROR)
|
||||
{
|
||||
@ -114,6 +142,8 @@ static BOOL rdpsnd_winmm_open(rdpsndDevicePlugin* device, const AUDIO_FORMAT* fo
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
ReleaseSemaphore(winmm->semaphore, SEM_COUNT_MAX, NULL);
|
||||
|
||||
mmResult = waveOutSetVolume(winmm->hWaveOut, winmm->volume);
|
||||
|
||||
if (mmResult != MMSYSERR_NOERROR)
|
||||
@ -127,22 +157,17 @@ static BOOL rdpsnd_winmm_open(rdpsndDevicePlugin* device, const AUDIO_FORMAT* fo
|
||||
|
||||
static void rdpsnd_winmm_close(rdpsndDevicePlugin* device)
|
||||
{
|
||||
size_t x;
|
||||
MMRESULT mmResult;
|
||||
rdpsndWinmmPlugin* winmm = (rdpsndWinmmPlugin*) device;
|
||||
|
||||
if (winmm->hWaveOut)
|
||||
{
|
||||
mmResult = waveOutReset(winmm->hWaveOut);
|
||||
if (mmResult != MMSYSERR_NOERROR)
|
||||
{
|
||||
WLog_Print(winmm->log, WLOG_ERROR, "waveOutReset failure: %"PRIu32"", mmResult);
|
||||
}
|
||||
for (x=0; x<SEM_COUNT_MAX; x++)
|
||||
WaitForSingleObject(winmm->semaphore, INFINITE);
|
||||
mmResult = waveOutClose(winmm->hWaveOut);
|
||||
|
||||
if (mmResult != MMSYSERR_NOERROR)
|
||||
{
|
||||
WLog_Print(winmm->log, WLOG_ERROR, "waveOutClose failure: %"PRIu32"", mmResult);
|
||||
}
|
||||
|
||||
winmm->hWaveOut = NULL;
|
||||
}
|
||||
@ -155,7 +180,7 @@ static void rdpsnd_winmm_free(rdpsndDevicePlugin* device)
|
||||
if (winmm)
|
||||
{
|
||||
rdpsnd_winmm_close(device);
|
||||
CloseHandle(winmm->playedEvent);
|
||||
CloseHandle(winmm->semaphore);
|
||||
free(winmm);
|
||||
}
|
||||
}
|
||||
@ -222,7 +247,7 @@ static void rdpsnd_winmm_start(rdpsndDevicePlugin* device)
|
||||
static UINT rdpsnd_winmm_play(rdpsndDevicePlugin* device, const BYTE* data, size_t size)
|
||||
{
|
||||
MMRESULT mmResult;
|
||||
WAVEHDR lpWaveHdr[1];
|
||||
LPWAVEHDR lpWaveHdr;
|
||||
rdpsndWinmmPlugin* winmm = (rdpsndWinmmPlugin*) device;
|
||||
|
||||
if (!winmm->hWaveOut)
|
||||
@ -231,39 +256,36 @@ static UINT rdpsnd_winmm_play(rdpsndDevicePlugin* device, const BYTE* data, size
|
||||
if (size > UINT32_MAX)
|
||||
return 0;
|
||||
|
||||
lpWaveHdr = malloc(sizeof(WAVEHDR));
|
||||
if (!lpWaveHdr)
|
||||
return 0;
|
||||
|
||||
lpWaveHdr->dwFlags = 0;
|
||||
lpWaveHdr->dwLoops = 0;
|
||||
lpWaveHdr->lpData = (LPSTR) data;
|
||||
lpWaveHdr->dwBufferLength = (DWORD)size;
|
||||
|
||||
lpWaveHdr->lpNext = NULL;
|
||||
|
||||
mmResult = waveOutPrepareHeader(winmm->hWaveOut, lpWaveHdr, sizeof(WAVEHDR));
|
||||
|
||||
if (mmResult != MMSYSERR_NOERROR)
|
||||
{
|
||||
WLog_Print(winmm->log, WLOG_ERROR, "waveOutPrepareHeader failure: %"PRIu32"", mmResult);
|
||||
free(lpWaveHdr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
WaitForSingleObject(winmm->semaphore, INFINITE);
|
||||
mmResult = waveOutWrite(winmm->hWaveOut, lpWaveHdr, sizeof(WAVEHDR));
|
||||
|
||||
if (mmResult != MMSYSERR_NOERROR)
|
||||
{
|
||||
WLog_Print(winmm->log, WLOG_ERROR, "waveOutWrite failure: %"PRIu32"", mmResult);
|
||||
waveOutUnprepareHeader(winmm->hWaveOut, lpWaveHdr, sizeof(WAVEHDR));
|
||||
free(lpWaveHdr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
WaitForSingleObject(winmm->playedEvent, INFINITE);
|
||||
}
|
||||
while((lpWaveHdr->dwFlags & WHDR_DONE) == 0);
|
||||
|
||||
waveOutUnprepareHeader(winmm->hWaveOut, lpWaveHdr, sizeof(WAVEHDR));
|
||||
|
||||
return 0;
|
||||
return winmm->latency;
|
||||
}
|
||||
|
||||
static void rdpsnd_winmm_parse_addin_args(rdpsndDevicePlugin* device, ADDIN_ARGV* args)
|
||||
@ -301,11 +323,16 @@ UINT freerdp_rdpsnd_client_subsystem_entry(PFREERDP_RDPSND_DEVICE_ENTRY_POINTS p
|
||||
winmm->device.Close = rdpsnd_winmm_close;
|
||||
winmm->device.Free = rdpsnd_winmm_free;
|
||||
winmm->log = WLog_Get(TAG);
|
||||
winmm->playedEvent = CreateEventA(NULL, FALSE, FALSE, NULL);
|
||||
|
||||
winmm->semaphore = CreateSemaphore(NULL, 0, SEM_COUNT_MAX, NULL);
|
||||
if (!winmm->semaphore)
|
||||
goto fail;
|
||||
args = pEntryPoints->args;
|
||||
rdpsnd_winmm_parse_addin_args((rdpsndDevicePlugin*) winmm, args);
|
||||
winmm->volume = 0xFFFFFFFF;
|
||||
pEntryPoints->pRegisterRdpsndDevice(pEntryPoints->rdpsnd, (rdpsndDevicePlugin*) winmm);
|
||||
return CHANNEL_RC_OK;
|
||||
|
||||
fail:
|
||||
rdpsnd_winmm_free((rdpsndDevicePlugin*)winmm);
|
||||
return ERROR_INTERNAL_ERROR;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user