From f720ec538335601752b3a112d27474bb073399a6 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Wed, 8 Jan 2020 11:27:49 +0100 Subject: [PATCH] RDPSND device API refinements * Added default format callback for rdpsnd backend to allow different default input formats (different samplerates, ...) * Made WINMM backend in flight packet limitation a compile time option * Fixed missing buffer copy in winmm backend Signed-off-by: Armin Novak --- channels/rdpsnd/client/fake/rdpsnd_fake.c | 5 ---- channels/rdpsnd/client/proxy/rdpsnd_proxy.c | 5 ---- channels/rdpsnd/client/pulse/rdpsnd_pulse.c | 37 +++++++++++++++--------- channels/rdpsnd/client/rdpsnd_main.c | 10 +++++-- channels/rdpsnd/client/winmm/rdpsnd_winmm.c | 45 ++++++++++++++++++++--------- include/freerdp/client/rdpsnd.h | 5 +++- 6 files changed, 66 insertions(+), 41 deletions(-) diff --git a/channels/rdpsnd/client/fake/rdpsnd_fake.c b/channels/rdpsnd/client/fake/rdpsnd_fake.c index 6ae7926..c5f78f9 100644 --- a/channels/rdpsnd/client/fake/rdpsnd_fake.c +++ b/channels/rdpsnd/client/fake/rdpsnd_fake.c @@ -81,10 +81,6 @@ static UINT rdpsnd_fake_play(rdpsndDevicePlugin* device, const BYTE* data, size_ return CHANNEL_RC_OK; } -static void rdpsnd_fake_start(rdpsndDevicePlugin* device) -{ -} - /** * Function description * @@ -142,7 +138,6 @@ UINT freerdp_rdpsnd_client_subsystem_entry(PFREERDP_RDPSND_DEVICE_ENTRY_POINTS p fake->device.FormatSupported = rdpsnd_fake_format_supported; fake->device.SetVolume = rdpsnd_fake_set_volume; fake->device.Play = rdpsnd_fake_play; - fake->device.Start = rdpsnd_fake_start; fake->device.Close = rdpsnd_fake_close; fake->device.Free = rdpsnd_fake_free; args = pEntryPoints->args; diff --git a/channels/rdpsnd/client/proxy/rdpsnd_proxy.c b/channels/rdpsnd/client/proxy/rdpsnd_proxy.c index 9de71c9..dd6af04 100644 --- a/channels/rdpsnd/client/proxy/rdpsnd_proxy.c +++ b/channels/rdpsnd/client/proxy/rdpsnd_proxy.c @@ -95,10 +95,6 @@ static UINT rdpsnd_proxy_play(rdpsndDevicePlugin* device, const BYTE* data, size return GetTickCount() - start; } -static void rdpsnd_proxy_start(rdpsndDevicePlugin* device) -{ - /* do nothing */ -} /** * Function description @@ -131,7 +127,6 @@ UINT freerdp_rdpsnd_client_subsystem_entry(PFREERDP_RDPSND_DEVICE_ENTRY_POINTS p proxy->device.FormatSupported = rdpsnd_proxy_format_supported; proxy->device.SetVolume = rdpsnd_proxy_set_volume; proxy->device.Play = rdpsnd_proxy_play; - proxy->device.Start = rdpsnd_proxy_start; proxy->device.Close = rdpsnd_proxy_close; proxy->device.Free = rdpsnd_proxy_free; args = pEntryPoints->args; diff --git a/channels/rdpsnd/client/pulse/rdpsnd_pulse.c b/channels/rdpsnd/client/pulse/rdpsnd_pulse.c index 0ea359f..7f3a6da 100644 --- a/channels/rdpsnd/client/pulse/rdpsnd_pulse.c +++ b/channels/rdpsnd/client/pulse/rdpsnd_pulse.c @@ -390,6 +390,29 @@ static void rdpsnd_pulse_free(rdpsndDevicePlugin* device) free(pulse); } +static BOOL rdpsnd_pulse_default_format(rdpsndDevicePlugin* device, const AUDIO_FORMAT* desired, + AUDIO_FORMAT* defaultFormat) +{ + rdpsndPulsePlugin* pulse = (rdpsndPulsePlugin*)device; + if (!pulse || !defaultFormat) + return FALSE; + + *defaultFormat = *desired; + defaultFormat->data = NULL; + defaultFormat->cbSize = 0; + defaultFormat->wFormatTag = WAVE_FORMAT_PCM; + if ((defaultFormat->nChannels < 1) || (defaultFormat->nChannels > PA_CHANNELS_MAX)) + defaultFormat->nChannels = 2; + if ((defaultFormat->nSamplesPerSec < 1) || (defaultFormat->nSamplesPerSec > PA_RATE_MAX)) + defaultFormat->nSamplesPerSec = 44100; + if ((defaultFormat->wBitsPerSample != 8) && (defaultFormat->wBitsPerSample != 16)) + defaultFormat->wBitsPerSample = 16; + + defaultFormat->nBlockAlign = defaultFormat->nChannels * defaultFormat->wBitsPerSample / 8; + defaultFormat->nAvgBytesPerSec = defaultFormat->nBlockAlign * defaultFormat->nSamplesPerSec; + return TRUE; +} + BOOL rdpsnd_pulse_format_supported(rdpsndDevicePlugin* device, const AUDIO_FORMAT* format) { switch (format->wFormatTag) @@ -507,18 +530,6 @@ static UINT rdpsnd_pulse_play(rdpsndDevicePlugin* device, const BYTE* data, size return latency / 1000; } -static void rdpsnd_pulse_start(rdpsndDevicePlugin* device) -{ - rdpsndPulsePlugin* pulse = (rdpsndPulsePlugin*)device; - - if (!pulse->stream) - return; - - pa_threaded_mainloop_lock(pulse->mainloop); - pa_stream_trigger(pulse->stream, NULL, NULL); - pa_threaded_mainloop_unlock(pulse->mainloop); -} - /** * Function description * @@ -587,9 +598,9 @@ UINT freerdp_rdpsnd_client_subsystem_entry(PFREERDP_RDPSND_DEVICE_ENTRY_POINTS p pulse->device.GetVolume = rdpsnd_pulse_get_volume; pulse->device.SetVolume = rdpsnd_pulse_set_volume; pulse->device.Play = rdpsnd_pulse_play; - pulse->device.Start = rdpsnd_pulse_start; pulse->device.Close = rdpsnd_pulse_close; pulse->device.Free = rdpsnd_pulse_free; + pulse->device.DefaultFormat = rdpsnd_pulse_default_format; args = pEntryPoints->args; if (args->argc > 1) diff --git a/channels/rdpsnd/client/rdpsnd_main.c b/channels/rdpsnd/client/rdpsnd_main.c index 384c5c6..bcc726f 100644 --- a/channels/rdpsnd/client/rdpsnd_main.c +++ b/channels/rdpsnd/client/rdpsnd_main.c @@ -344,9 +344,13 @@ static BOOL rdpsnd_ensure_device_is_open(rdpsndPlugin* rdpsnd, UINT32 wFormatNo, if (!supported) { - deviceFormat.wFormatTag = WAVE_FORMAT_PCM; - deviceFormat.wBitsPerSample = 16; - deviceFormat.cbSize = 0; + if (!IFCALLRESULT(FALSE, rdpsnd->device->DefaultFormat, rdpsnd->device, format, + &deviceFormat)) + { + deviceFormat.wFormatTag = WAVE_FORMAT_PCM; + deviceFormat.wBitsPerSample = 16; + deviceFormat.cbSize = 0; + } } WLog_Print(rdpsnd->log, WLOG_DEBUG, "Opening device with format %s [backend %s]", diff --git a/channels/rdpsnd/client/winmm/rdpsnd_winmm.c b/channels/rdpsnd/client/winmm/rdpsnd_winmm.c index 8fade6e..3f8c6f7 100644 --- a/channels/rdpsnd/client/winmm/rdpsnd_winmm.c +++ b/channels/rdpsnd/client/winmm/rdpsnd_winmm.c @@ -41,7 +41,9 @@ #include "rdpsnd_main.h" -#define SEM_COUNT_MAX 4 +#if defined(WITH_WINMM_SEMAPHORE) +#define SEM_COUNT_MAX 6 +#endif typedef struct rdpsnd_winmm_plugin rdpsndWinmmPlugin; @@ -54,7 +56,9 @@ struct rdpsnd_winmm_plugin UINT32 volume; wLog* log; UINT32 latency; +#if defined(WITH_WINMM_SEMAPHORE) HANDLE semaphore; +#endif }; static BOOL rdpsnd_winmm_convert_format(const AUDIO_FORMAT* in, WAVEFORMATEX* out) @@ -107,8 +111,11 @@ static void CALLBACK waveOutProc(HWAVEOUT hwo, UINT uMsg, DWORD_PTR dwInstance, break; case WOM_DONE: waveOutUnprepareHeader(hwo, lpWaveHdr, sizeof(WAVEHDR)); + free(lpWaveHdr->lpData); free(lpWaveHdr); +#if defined(WITH_WINMM_SEMAPHORE) ReleaseSemaphore(winmm->semaphore, 1, NULL); +#endif break; default: break; @@ -136,7 +143,9 @@ static BOOL rdpsnd_winmm_open(rdpsndDevicePlugin* device, const AUDIO_FORMAT* fo return FALSE; } +#if defined(WITH_WINMM_SEMAPHORE) ReleaseSemaphore(winmm->semaphore, SEM_COUNT_MAX, NULL); +#endif mmResult = waveOutSetVolume(winmm->hWaveOut, winmm->volume); @@ -151,14 +160,16 @@ 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) { +#if defined(WITH_WINMM_SEMAPHORE) + size_t x; for (x = 0; x < SEM_COUNT_MAX; x++) WaitForSingleObject(winmm->semaphore, INFINITE); +#endif mmResult = waveOutClose(winmm->hWaveOut); if (mmResult != MMSYSERR_NOERROR) WLog_Print(winmm->log, WLOG_ERROR, "waveOutClose failure: %" PRIu32 "", mmResult); @@ -174,7 +185,9 @@ static void rdpsnd_winmm_free(rdpsndDevicePlugin* device) if (winmm) { rdpsnd_winmm_close(device); +#if defined(WITH_WINMM_SEMAPHORE) CloseHandle(winmm->semaphore); +#endif free(winmm); } } @@ -232,12 +245,6 @@ static BOOL rdpsnd_winmm_set_volume(rdpsndDevicePlugin* device, UINT32 value) return TRUE; } -static void rdpsnd_winmm_start(rdpsndDevicePlugin* device) -{ - // rdpsndWinmmPlugin* winmm = (rdpsndWinmmPlugin*) device; - WINPR_UNUSED(device); -} - static UINT rdpsnd_winmm_play(rdpsndDevicePlugin* device, const BYTE* data, size_t size) { MMRESULT mmResult; @@ -256,7 +263,10 @@ static UINT rdpsnd_winmm_play(rdpsndDevicePlugin* device, const BYTE* data, size lpWaveHdr->dwFlags = 0; lpWaveHdr->dwLoops = 0; - lpWaveHdr->lpData = (LPSTR)data; + lpWaveHdr->lpData = malloc(size); + if (!lpWaveHdr->lpData) + goto fail; + memcpy(lpWaveHdr->lpData, data, size); lpWaveHdr->dwBufferLength = (DWORD)size; mmResult = waveOutPrepareHeader(winmm->hWaveOut, lpWaveHdr, sizeof(WAVEHDR)); @@ -264,22 +274,27 @@ static UINT rdpsnd_winmm_play(rdpsndDevicePlugin* device, const BYTE* data, size if (mmResult != MMSYSERR_NOERROR) { WLog_Print(winmm->log, WLOG_ERROR, "waveOutPrepareHeader failure: %" PRIu32 "", mmResult); - free(lpWaveHdr); - return 0; + goto fail; } +#if defined(WITH_WINMM_SEMAPHORE) WaitForSingleObject(winmm->semaphore, INFINITE); +#endif 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; + goto fail; } return winmm->latency; +fail: + if (lpWaveHdr) + free(lpWaveHdr->lpData); + free(lpWaveHdr); + return 0; } static void rdpsnd_winmm_parse_addin_args(rdpsndDevicePlugin* device, ADDIN_ARGV* args) @@ -311,6 +326,7 @@ UINT freerdp_rdpsnd_client_subsystem_entry(PFREERDP_RDPSND_DEVICE_ENTRY_POINTS p } winmm = (rdpsndWinmmPlugin*)calloc(1, sizeof(rdpsndWinmmPlugin)); + if (!winmm) return CHANNEL_RC_NO_MEMORY; @@ -318,14 +334,15 @@ UINT freerdp_rdpsnd_client_subsystem_entry(PFREERDP_RDPSND_DEVICE_ENTRY_POINTS p winmm->device.FormatSupported = rdpsnd_winmm_format_supported; winmm->device.GetVolume = rdpsnd_winmm_get_volume; winmm->device.SetVolume = rdpsnd_winmm_set_volume; - winmm->device.Start = rdpsnd_winmm_start; winmm->device.Play = rdpsnd_winmm_play; winmm->device.Close = rdpsnd_winmm_close; winmm->device.Free = rdpsnd_winmm_free; winmm->log = WLog_Get(TAG); +#if defined(WITH_WINMM_SEMAPHORE) winmm->semaphore = CreateSemaphore(NULL, 0, SEM_COUNT_MAX, NULL); if (!winmm->semaphore) goto fail; +#endif args = pEntryPoints->args; rdpsnd_winmm_parse_addin_args((rdpsndDevicePlugin*)winmm, args); winmm->volume = 0xFFFFFFFF; diff --git a/include/freerdp/client/rdpsnd.h b/include/freerdp/client/rdpsnd.h index 6b491e8..e78d934 100644 --- a/include/freerdp/client/rdpsnd.h +++ b/include/freerdp/client/rdpsnd.h @@ -38,6 +38,8 @@ typedef UINT (*pcPlay)(rdpsndDevicePlugin* device, const BYTE* data, size_t size typedef void (*pcStart)(rdpsndDevicePlugin* device); typedef void (*pcClose)(rdpsndDevicePlugin* device); typedef void (*pcFree)(rdpsndDevicePlugin* device); +typedef BOOL (*pcDefaultFormat)(rdpsndDevicePlugin* device, const AUDIO_FORMAT* desired, + AUDIO_FORMAT* defaultFormat); struct rdpsnd_device_plugin { @@ -48,9 +50,10 @@ struct rdpsnd_device_plugin pcGetVolume GetVolume; pcSetVolume SetVolume; pcPlay Play; - pcStart Start; + pcStart Start; /* Deprecated, unused. */ pcClose Close; pcFree Free; + pcDefaultFormat DefaultFormat; }; #define RDPSND_DEVICE_EXPORT_FUNC_NAME "freerdp_rdpsnd_client_subsystem_entry" -- 2.7.4