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:
parent
05a865281e
commit
f720ec5383
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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]",
|
||||
|
@ -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;
|
||||
|
@ -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"
|
||||
|
Loading…
Reference in New Issue
Block a user