Skip to content

Commit

Permalink
Added proper latency estimation for winmm sound backend.
Browse files Browse the repository at this point in the history
  • Loading branch information
akallabeth committed Aug 12, 2019
1 parent 60636a7 commit 9d26a47
Showing 1 changed file with 37 additions and 16 deletions.
53 changes: 37 additions & 16 deletions channels/rdpsnd/client/winmm/rdpsnd_winmm.c
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,8 @@ struct rdpsnd_winmm_plugin
HWAVEOUT hWaveOut;
WAVEFORMATEX format;
UINT32 volume;
HANDLE next;
wLog* log;
DWORD diff;
};

static BOOL rdpsnd_winmm_convert_format(const AUDIO_FORMAT* in, WAVEFORMATEX* out)
Expand Down Expand Up @@ -82,6 +83,8 @@ static BOOL rdpsnd_winmm_set_format(rdpsndDevicePlugin* device, const AUDIO_FORM
{
rdpsndWinmmPlugin* winmm = (rdpsndWinmmPlugin*) device;

WINPR_UNUSED(latency);

if (!rdpsnd_winmm_convert_format(format, &winmm->format))
return FALSE;

Expand All @@ -91,27 +94,38 @@ static BOOL rdpsnd_winmm_set_format(rdpsndDevicePlugin* device, const AUDIO_FORM
static void CALLBACK rdpsnd_winmm_callback_function(HWAVEOUT hwo, UINT uMsg, DWORD_PTR dwInstance,
DWORD_PTR dwParam1, DWORD_PTR dwParam2)
{
UINT64 diff;
LPWAVEHDR lpWaveHdr;
rdpsndWinmmPlugin* winmm = (rdpsndWinmmPlugin*) dwInstance;
UINT64 stop = GetTickCount();

WINPR_UNUSED(hwo);
WINPR_UNUSED(uMsg);
WINPR_UNUSED(dwParam2);

switch (uMsg)
{
case MM_WOM_OPEN:
WLog_DBG(TAG, "MM_WOM_OPEN");
WLog_Print(winmm->log, WLOG_DEBUG, "MM_WOM_OPEN");
break;

case MM_WOM_CLOSE:
WLog_DBG(TAG, "MM_WOM_CLOSE");
WLog_Print(winmm->log, WLOG_DEBUG, "MM_WOM_CLOSE");
break;

case MM_WOM_DONE:
WLog_DBG(TAG, "MM_WOM_DONE");
WLog_Print(winmm->log, WLOG_DEBUG, "MM_WOM_DONE");
lpWaveHdr = (LPWAVEHDR) dwParam1;
if (stop < lpWaveHdr->dwUser)
stop += UINT32_MAX;

diff = stop - lpWaveHdr->dwUser;
free(lpWaveHdr);
winmm->diff = (diff > UINT_MAX) ? UINT_MAX : (UINT32)diff;
break;

default:
WLog_DBG(TAG, "UNKNOWN [0x%08"PRIx32"]", uMsg);
WLog_Print(winmm->log, WLOG_DEBUG, "UNKNOWN [0x%08"PRIx32"]", uMsg);
break;
}
}
Expand All @@ -133,15 +147,15 @@ static BOOL rdpsnd_winmm_open(rdpsndDevicePlugin* device, const AUDIO_FORMAT* fo

if (mmResult != MMSYSERR_NOERROR)
{
WLog_ERR(TAG, "waveOutOpen failed: %"PRIu32"", mmResult);
WLog_Print(winmm->log, WLOG_ERROR, "waveOutOpen failed: %"PRIu32"", mmResult);
return FALSE;
}

mmResult = waveOutSetVolume(winmm->hWaveOut, winmm->volume);

if (mmResult != MMSYSERR_NOERROR)
{
WLog_ERR(TAG, "waveOutSetVolume failed: %"PRIu32"", mmResult);
WLog_Print(winmm->log, WLOG_ERROR, "waveOutSetVolume failed: %"PRIu32"", mmResult);
return FALSE;
}

Expand All @@ -160,7 +174,7 @@ static void rdpsnd_winmm_close(rdpsndDevicePlugin* device)

if (mmResult != MMSYSERR_NOERROR)
{
WLog_ERR(TAG, "waveOutClose failure: %"PRIu32"", mmResult);
WLog_Print(winmm->log, WLOG_ERROR, "waveOutClose failure: %"PRIu32"", mmResult);
}

winmm->hWaveOut = NULL;
Expand All @@ -183,6 +197,7 @@ static BOOL rdpsnd_winmm_format_supported(rdpsndDevicePlugin* device, const AUDI
MMRESULT result;
WAVEFORMATEX out;

WINPR_UNUSED(device);
if (rdpsnd_winmm_convert_format(format, &out))
{
result = waveOutOpen(NULL, WAVE_MAPPER, &out, 0, 0, WAVE_FORMAT_QUERY);
Expand All @@ -202,7 +217,7 @@ static UINT32 rdpsnd_winmm_get_volume(rdpsndDevicePlugin* device)
rdpsndWinmmPlugin* winmm = (rdpsndWinmmPlugin*) device;
dwVolumeLeft = ((50 * 0xFFFF) / 100); /* 50% */
dwVolumeRight = ((50 * 0xFFFF) / 100); /* 50% */
dwVolume = (dwVolumeLeft << 16) | dwVolumeRight;
dwVolume = ((UINT32)dwVolumeLeft << 16) | dwVolumeRight;

if (!winmm->hWaveOut)
return dwVolume;
Expand All @@ -225,6 +240,7 @@ static BOOL rdpsnd_winmm_set_volume(rdpsndDevicePlugin* device, UINT32 value)
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)
Expand All @@ -236,41 +252,45 @@ static UINT rdpsnd_winmm_play(rdpsndDevicePlugin* device, const BYTE* data, size
if (!winmm->hWaveOut)
return 0;

lpWaveHdr = (LPWAVEHDR) malloc(sizeof(WAVEHDR));
if (size > UINT32_MAX)
return ERROR_INVALID_DATA;

lpWaveHdr = (LPWAVEHDR) calloc(1, sizeof(WAVEHDR));

if (!lpWaveHdr)
return 0;

ZeroMemory(lpWaveHdr, sizeof(WAVEHDR));
lpWaveHdr->dwFlags = 0;
lpWaveHdr->dwLoops = 0;
lpWaveHdr->lpData = (LPSTR) data;
lpWaveHdr->dwBufferLength = size;
lpWaveHdr->dwUser = NULL;
lpWaveHdr->dwBufferLength = (DWORD)size;
lpWaveHdr->dwUser = GetTickCount();
lpWaveHdr->lpNext = NULL;
mmResult = waveOutPrepareHeader(winmm->hWaveOut, lpWaveHdr, sizeof(WAVEHDR));

if (mmResult != MMSYSERR_NOERROR)
{
WLog_ERR(TAG, "waveOutPrepareHeader failure: %"PRIu32"", mmResult);
WLog_Print(winmm->log, WLOG_ERROR, "waveOutPrepareHeader failure: %"PRIu32"", mmResult);
return 0;
}

mmResult = waveOutWrite(winmm->hWaveOut, lpWaveHdr, sizeof(WAVEHDR));

if (mmResult != MMSYSERR_NOERROR)
{
WLog_ERR(TAG, "waveOutWrite failure: %"PRIu32"", mmResult);
WLog_Print(winmm->log, WLOG_ERROR, "waveOutWrite failure: %"PRIu32"", mmResult);
waveOutUnprepareHeader(winmm->hWaveOut, lpWaveHdr, sizeof(WAVEHDR));
free(lpWaveHdr);
return 0;
}

return 10; /* TODO: Get real latencry in [ms] */
return (UINT)winmm->diff;
}

static void rdpsnd_winmm_parse_addin_args(rdpsndDevicePlugin* device, ADDIN_ARGV* args)
{
WINPR_UNUSED(device);
WINPR_UNUSED(args);
}

#ifdef BUILTIN_CHANNELS
Expand Down Expand Up @@ -301,6 +321,7 @@ UINT freerdp_rdpsnd_client_subsystem_entry(PFREERDP_RDPSND_DEVICE_ENTRY_POINTS p
winmm->device.Play = rdpsnd_winmm_play;
winmm->device.Close = rdpsnd_winmm_close;
winmm->device.Free = rdpsnd_winmm_free;
winmm->log = WLog_Get(TAG);

args = pEntryPoints->args;
rdpsnd_winmm_parse_addin_args((rdpsndDevicePlugin*) winmm, args);
Expand Down

0 comments on commit 9d26a47

Please sign in to comment.