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;
|
return CHANNEL_RC_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rdpsnd_fake_start(rdpsndDevicePlugin* device)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function description
|
* 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.FormatSupported = rdpsnd_fake_format_supported;
|
||||||
fake->device.SetVolume = rdpsnd_fake_set_volume;
|
fake->device.SetVolume = rdpsnd_fake_set_volume;
|
||||||
fake->device.Play = rdpsnd_fake_play;
|
fake->device.Play = rdpsnd_fake_play;
|
||||||
fake->device.Start = rdpsnd_fake_start;
|
|
||||||
fake->device.Close = rdpsnd_fake_close;
|
fake->device.Close = rdpsnd_fake_close;
|
||||||
fake->device.Free = rdpsnd_fake_free;
|
fake->device.Free = rdpsnd_fake_free;
|
||||||
args = pEntryPoints->args;
|
args = pEntryPoints->args;
|
||||||
|
@ -95,10 +95,6 @@ static UINT rdpsnd_proxy_play(rdpsndDevicePlugin* device, const BYTE* data, size
|
|||||||
return GetTickCount() - start;
|
return GetTickCount() - start;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rdpsnd_proxy_start(rdpsndDevicePlugin* device)
|
|
||||||
{
|
|
||||||
/* do nothing */
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function description
|
* 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.FormatSupported = rdpsnd_proxy_format_supported;
|
||||||
proxy->device.SetVolume = rdpsnd_proxy_set_volume;
|
proxy->device.SetVolume = rdpsnd_proxy_set_volume;
|
||||||
proxy->device.Play = rdpsnd_proxy_play;
|
proxy->device.Play = rdpsnd_proxy_play;
|
||||||
proxy->device.Start = rdpsnd_proxy_start;
|
|
||||||
proxy->device.Close = rdpsnd_proxy_close;
|
proxy->device.Close = rdpsnd_proxy_close;
|
||||||
proxy->device.Free = rdpsnd_proxy_free;
|
proxy->device.Free = rdpsnd_proxy_free;
|
||||||
args = pEntryPoints->args;
|
args = pEntryPoints->args;
|
||||||
|
@ -390,6 +390,29 @@ static void rdpsnd_pulse_free(rdpsndDevicePlugin* device)
|
|||||||
free(pulse);
|
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)
|
BOOL rdpsnd_pulse_format_supported(rdpsndDevicePlugin* device, const AUDIO_FORMAT* format)
|
||||||
{
|
{
|
||||||
switch (format->wFormatTag)
|
switch (format->wFormatTag)
|
||||||
@ -507,18 +530,6 @@ static UINT rdpsnd_pulse_play(rdpsndDevicePlugin* device, const BYTE* data, size
|
|||||||
return latency / 1000;
|
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
|
* 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.GetVolume = rdpsnd_pulse_get_volume;
|
||||||
pulse->device.SetVolume = rdpsnd_pulse_set_volume;
|
pulse->device.SetVolume = rdpsnd_pulse_set_volume;
|
||||||
pulse->device.Play = rdpsnd_pulse_play;
|
pulse->device.Play = rdpsnd_pulse_play;
|
||||||
pulse->device.Start = rdpsnd_pulse_start;
|
|
||||||
pulse->device.Close = rdpsnd_pulse_close;
|
pulse->device.Close = rdpsnd_pulse_close;
|
||||||
pulse->device.Free = rdpsnd_pulse_free;
|
pulse->device.Free = rdpsnd_pulse_free;
|
||||||
|
pulse->device.DefaultFormat = rdpsnd_pulse_default_format;
|
||||||
args = pEntryPoints->args;
|
args = pEntryPoints->args;
|
||||||
|
|
||||||
if (args->argc > 1)
|
if (args->argc > 1)
|
||||||
|
@ -343,11 +343,15 @@ static BOOL rdpsnd_ensure_device_is_open(rdpsndPlugin* rdpsnd, UINT32 wFormatNo,
|
|||||||
supported = IFCALLRESULT(FALSE, rdpsnd->device->FormatSupported, rdpsnd->device, format);
|
supported = IFCALLRESULT(FALSE, rdpsnd->device->FormatSupported, rdpsnd->device, format);
|
||||||
|
|
||||||
if (!supported)
|
if (!supported)
|
||||||
|
{
|
||||||
|
if (!IFCALLRESULT(FALSE, rdpsnd->device->DefaultFormat, rdpsnd->device, format,
|
||||||
|
&deviceFormat))
|
||||||
{
|
{
|
||||||
deviceFormat.wFormatTag = WAVE_FORMAT_PCM;
|
deviceFormat.wFormatTag = WAVE_FORMAT_PCM;
|
||||||
deviceFormat.wBitsPerSample = 16;
|
deviceFormat.wBitsPerSample = 16;
|
||||||
deviceFormat.cbSize = 0;
|
deviceFormat.cbSize = 0;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
WLog_Print(rdpsnd->log, WLOG_DEBUG, "Opening device with format %s [backend %s]",
|
WLog_Print(rdpsnd->log, WLOG_DEBUG, "Opening device with format %s [backend %s]",
|
||||||
audio_format_get_tag_string(format->wFormatTag),
|
audio_format_get_tag_string(format->wFormatTag),
|
||||||
|
@ -41,7 +41,9 @@
|
|||||||
|
|
||||||
#include "rdpsnd_main.h"
|
#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;
|
typedef struct rdpsnd_winmm_plugin rdpsndWinmmPlugin;
|
||||||
|
|
||||||
@ -54,7 +56,9 @@ struct rdpsnd_winmm_plugin
|
|||||||
UINT32 volume;
|
UINT32 volume;
|
||||||
wLog* log;
|
wLog* log;
|
||||||
UINT32 latency;
|
UINT32 latency;
|
||||||
|
#if defined(WITH_WINMM_SEMAPHORE)
|
||||||
HANDLE semaphore;
|
HANDLE semaphore;
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
static BOOL rdpsnd_winmm_convert_format(const AUDIO_FORMAT* in, WAVEFORMATEX* out)
|
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;
|
break;
|
||||||
case WOM_DONE:
|
case WOM_DONE:
|
||||||
waveOutUnprepareHeader(hwo, lpWaveHdr, sizeof(WAVEHDR));
|
waveOutUnprepareHeader(hwo, lpWaveHdr, sizeof(WAVEHDR));
|
||||||
|
free(lpWaveHdr->lpData);
|
||||||
free(lpWaveHdr);
|
free(lpWaveHdr);
|
||||||
|
#if defined(WITH_WINMM_SEMAPHORE)
|
||||||
ReleaseSemaphore(winmm->semaphore, 1, NULL);
|
ReleaseSemaphore(winmm->semaphore, 1, NULL);
|
||||||
|
#endif
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@ -136,7 +143,9 @@ static BOOL rdpsnd_winmm_open(rdpsndDevicePlugin* device, const AUDIO_FORMAT* fo
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(WITH_WINMM_SEMAPHORE)
|
||||||
ReleaseSemaphore(winmm->semaphore, SEM_COUNT_MAX, NULL);
|
ReleaseSemaphore(winmm->semaphore, SEM_COUNT_MAX, NULL);
|
||||||
|
#endif
|
||||||
|
|
||||||
mmResult = waveOutSetVolume(winmm->hWaveOut, winmm->volume);
|
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)
|
static void rdpsnd_winmm_close(rdpsndDevicePlugin* device)
|
||||||
{
|
{
|
||||||
size_t x;
|
|
||||||
MMRESULT mmResult;
|
MMRESULT mmResult;
|
||||||
rdpsndWinmmPlugin* winmm = (rdpsndWinmmPlugin*)device;
|
rdpsndWinmmPlugin* winmm = (rdpsndWinmmPlugin*)device;
|
||||||
|
|
||||||
if (winmm->hWaveOut)
|
if (winmm->hWaveOut)
|
||||||
{
|
{
|
||||||
|
#if defined(WITH_WINMM_SEMAPHORE)
|
||||||
|
size_t x;
|
||||||
for (x = 0; x < SEM_COUNT_MAX; x++)
|
for (x = 0; x < SEM_COUNT_MAX; x++)
|
||||||
WaitForSingleObject(winmm->semaphore, INFINITE);
|
WaitForSingleObject(winmm->semaphore, INFINITE);
|
||||||
|
#endif
|
||||||
mmResult = waveOutClose(winmm->hWaveOut);
|
mmResult = waveOutClose(winmm->hWaveOut);
|
||||||
if (mmResult != MMSYSERR_NOERROR)
|
if (mmResult != MMSYSERR_NOERROR)
|
||||||
WLog_Print(winmm->log, WLOG_ERROR, "waveOutClose failure: %" PRIu32 "", mmResult);
|
WLog_Print(winmm->log, WLOG_ERROR, "waveOutClose failure: %" PRIu32 "", mmResult);
|
||||||
@ -174,7 +185,9 @@ static void rdpsnd_winmm_free(rdpsndDevicePlugin* device)
|
|||||||
if (winmm)
|
if (winmm)
|
||||||
{
|
{
|
||||||
rdpsnd_winmm_close(device);
|
rdpsnd_winmm_close(device);
|
||||||
|
#if defined(WITH_WINMM_SEMAPHORE)
|
||||||
CloseHandle(winmm->semaphore);
|
CloseHandle(winmm->semaphore);
|
||||||
|
#endif
|
||||||
free(winmm);
|
free(winmm);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -232,12 +245,6 @@ static BOOL rdpsnd_winmm_set_volume(rdpsndDevicePlugin* device, UINT32 value)
|
|||||||
return TRUE;
|
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)
|
static UINT rdpsnd_winmm_play(rdpsndDevicePlugin* device, const BYTE* data, size_t size)
|
||||||
{
|
{
|
||||||
MMRESULT mmResult;
|
MMRESULT mmResult;
|
||||||
@ -256,7 +263,10 @@ static UINT rdpsnd_winmm_play(rdpsndDevicePlugin* device, const BYTE* data, size
|
|||||||
|
|
||||||
lpWaveHdr->dwFlags = 0;
|
lpWaveHdr->dwFlags = 0;
|
||||||
lpWaveHdr->dwLoops = 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;
|
lpWaveHdr->dwBufferLength = (DWORD)size;
|
||||||
|
|
||||||
mmResult = waveOutPrepareHeader(winmm->hWaveOut, lpWaveHdr, sizeof(WAVEHDR));
|
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)
|
if (mmResult != MMSYSERR_NOERROR)
|
||||||
{
|
{
|
||||||
WLog_Print(winmm->log, WLOG_ERROR, "waveOutPrepareHeader failure: %" PRIu32 "", mmResult);
|
WLog_Print(winmm->log, WLOG_ERROR, "waveOutPrepareHeader failure: %" PRIu32 "", mmResult);
|
||||||
free(lpWaveHdr);
|
goto fail;
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(WITH_WINMM_SEMAPHORE)
|
||||||
WaitForSingleObject(winmm->semaphore, INFINITE);
|
WaitForSingleObject(winmm->semaphore, INFINITE);
|
||||||
|
#endif
|
||||||
mmResult = waveOutWrite(winmm->hWaveOut, lpWaveHdr, sizeof(WAVEHDR));
|
mmResult = waveOutWrite(winmm->hWaveOut, lpWaveHdr, sizeof(WAVEHDR));
|
||||||
|
|
||||||
if (mmResult != MMSYSERR_NOERROR)
|
if (mmResult != MMSYSERR_NOERROR)
|
||||||
{
|
{
|
||||||
WLog_Print(winmm->log, WLOG_ERROR, "waveOutWrite failure: %" PRIu32 "", mmResult);
|
WLog_Print(winmm->log, WLOG_ERROR, "waveOutWrite failure: %" PRIu32 "", mmResult);
|
||||||
waveOutUnprepareHeader(winmm->hWaveOut, lpWaveHdr, sizeof(WAVEHDR));
|
waveOutUnprepareHeader(winmm->hWaveOut, lpWaveHdr, sizeof(WAVEHDR));
|
||||||
free(lpWaveHdr);
|
goto fail;
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return winmm->latency;
|
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)
|
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));
|
winmm = (rdpsndWinmmPlugin*)calloc(1, sizeof(rdpsndWinmmPlugin));
|
||||||
|
|
||||||
if (!winmm)
|
if (!winmm)
|
||||||
return CHANNEL_RC_NO_MEMORY;
|
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.FormatSupported = rdpsnd_winmm_format_supported;
|
||||||
winmm->device.GetVolume = rdpsnd_winmm_get_volume;
|
winmm->device.GetVolume = rdpsnd_winmm_get_volume;
|
||||||
winmm->device.SetVolume = rdpsnd_winmm_set_volume;
|
winmm->device.SetVolume = rdpsnd_winmm_set_volume;
|
||||||
winmm->device.Start = rdpsnd_winmm_start;
|
|
||||||
winmm->device.Play = rdpsnd_winmm_play;
|
winmm->device.Play = rdpsnd_winmm_play;
|
||||||
winmm->device.Close = rdpsnd_winmm_close;
|
winmm->device.Close = rdpsnd_winmm_close;
|
||||||
winmm->device.Free = rdpsnd_winmm_free;
|
winmm->device.Free = rdpsnd_winmm_free;
|
||||||
winmm->log = WLog_Get(TAG);
|
winmm->log = WLog_Get(TAG);
|
||||||
|
#if defined(WITH_WINMM_SEMAPHORE)
|
||||||
winmm->semaphore = CreateSemaphore(NULL, 0, SEM_COUNT_MAX, NULL);
|
winmm->semaphore = CreateSemaphore(NULL, 0, SEM_COUNT_MAX, NULL);
|
||||||
if (!winmm->semaphore)
|
if (!winmm->semaphore)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
#endif
|
||||||
args = pEntryPoints->args;
|
args = pEntryPoints->args;
|
||||||
rdpsnd_winmm_parse_addin_args((rdpsndDevicePlugin*)winmm, args);
|
rdpsnd_winmm_parse_addin_args((rdpsndDevicePlugin*)winmm, args);
|
||||||
winmm->volume = 0xFFFFFFFF;
|
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 (*pcStart)(rdpsndDevicePlugin* device);
|
||||||
typedef void (*pcClose)(rdpsndDevicePlugin* device);
|
typedef void (*pcClose)(rdpsndDevicePlugin* device);
|
||||||
typedef void (*pcFree)(rdpsndDevicePlugin* device);
|
typedef void (*pcFree)(rdpsndDevicePlugin* device);
|
||||||
|
typedef BOOL (*pcDefaultFormat)(rdpsndDevicePlugin* device, const AUDIO_FORMAT* desired,
|
||||||
|
AUDIO_FORMAT* defaultFormat);
|
||||||
|
|
||||||
struct rdpsnd_device_plugin
|
struct rdpsnd_device_plugin
|
||||||
{
|
{
|
||||||
@ -48,9 +50,10 @@ struct rdpsnd_device_plugin
|
|||||||
pcGetVolume GetVolume;
|
pcGetVolume GetVolume;
|
||||||
pcSetVolume SetVolume;
|
pcSetVolume SetVolume;
|
||||||
pcPlay Play;
|
pcPlay Play;
|
||||||
pcStart Start;
|
pcStart Start; /* Deprecated, unused. */
|
||||||
pcClose Close;
|
pcClose Close;
|
||||||
pcFree Free;
|
pcFree Free;
|
||||||
|
pcDefaultFormat DefaultFormat;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define RDPSND_DEVICE_EXPORT_FUNC_NAME "freerdp_rdpsnd_client_subsystem_entry"
|
#define RDPSND_DEVICE_EXPORT_FUNC_NAME "freerdp_rdpsnd_client_subsystem_entry"
|
||||||
|
Loading…
Reference in New Issue
Block a user