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 <armin.novak@thincast.com>
This commit is contained in:
Armin Novak 2020-01-08 11:27:49 +01:00
parent 05a865281e
commit f720ec5383
6 changed files with 66 additions and 41 deletions

View File

@ -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;

View File

@ -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;

View File

@ -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)

View File

@ -343,11 +343,15 @@ static BOOL rdpsnd_ensure_device_is_open(rdpsndPlugin* rdpsnd, UINT32 wFormatNo,
supported = IFCALLRESULT(FALSE, rdpsnd->device->FormatSupported, rdpsnd->device, format);
if (!supported)
{
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]",
audio_format_get_tag_string(format->wFormatTag),

View File

@ -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;

View File

@ -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"