Merge pull request #4957 from akallabeth/wave_2_pdu_fix

Wave 2 pdu fix
This commit is contained in:
Norbert Federa 2018-10-23 09:28:00 +02:00 committed by GitHub
commit a7022e9a57
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 200 additions and 128 deletions

View File

@ -223,6 +223,15 @@ static BOOL rdpsnd_alsa_set_format(rdpsndDevicePlugin* device, const AUDIO_FORMA
return (rdpsnd_alsa_set_params(alsa) == 0);
}
static void rdpsnd_alsa_close_mixer(rdpsndAlsaPlugin* alsa)
{
if (alsa && alsa->mixer_handle)
{
snd_mixer_close(alsa->mixer_handle);
alsa->mixer_handle = NULL;
}
}
static BOOL rdpsnd_alsa_open_mixer(rdpsndAlsaPlugin* alsa)
{
int status;
@ -235,7 +244,7 @@ static BOOL rdpsnd_alsa_open_mixer(rdpsndAlsaPlugin* alsa)
if (status < 0)
{
WLog_ERR(TAG, "snd_mixer_open failed");
return FALSE;
goto fail;
}
status = snd_mixer_attach(alsa->mixer_handle, alsa->device_name);
@ -243,8 +252,7 @@ static BOOL rdpsnd_alsa_open_mixer(rdpsndAlsaPlugin* alsa)
if (status < 0)
{
WLog_ERR(TAG, "snd_mixer_attach failed");
snd_mixer_close(alsa->mixer_handle);
return FALSE;
goto fail;
}
status = snd_mixer_selem_register(alsa->mixer_handle, NULL, NULL);
@ -252,8 +260,7 @@ static BOOL rdpsnd_alsa_open_mixer(rdpsndAlsaPlugin* alsa)
if (status < 0)
{
WLog_ERR(TAG, "snd_mixer_selem_register failed");
snd_mixer_close(alsa->mixer_handle);
return FALSE;
goto fail;
}
status = snd_mixer_load(alsa->mixer_handle);
@ -261,11 +268,23 @@ static BOOL rdpsnd_alsa_open_mixer(rdpsndAlsaPlugin* alsa)
if (status < 0)
{
WLog_ERR(TAG, "snd_mixer_load failed");
snd_mixer_close(alsa->mixer_handle);
return FALSE;
goto fail;
}
return TRUE;
fail:
rdpsnd_alsa_close_mixer(alsa);
return FALSE;
}
static void rdpsnd_alsa_pcm_close(rdpsndAlsaPlugin* alsa)
{
if (alsa && alsa->pcm_handle)
{
snd_pcm_drain(alsa->pcm_handle);
snd_pcm_close(alsa->pcm_handle);
alsa->pcm_handle = 0;
}
}
static BOOL rdpsnd_alsa_open(rdpsndDevicePlugin* device, const AUDIO_FORMAT* format, UINT32 latency)
@ -293,37 +312,19 @@ static BOOL rdpsnd_alsa_open(rdpsndDevicePlugin* device, const AUDIO_FORMAT* for
static void rdpsnd_alsa_close(rdpsndDevicePlugin* device)
{
int status;
snd_htimestamp_t tstamp;
snd_pcm_uframes_t frames;
rdpsndAlsaPlugin* alsa = (rdpsndAlsaPlugin*) device;
if (!alsa->pcm_handle)
if (!alsa)
return;
status = snd_pcm_htimestamp(alsa->pcm_handle, &frames, &tstamp);
if (status != 0)
frames = 0;
rdpsnd_alsa_close_mixer(alsa);
}
static void rdpsnd_alsa_free(rdpsndDevicePlugin* device)
{
rdpsndAlsaPlugin* alsa = (rdpsndAlsaPlugin*) device;
if (alsa->pcm_handle)
{
snd_pcm_drain(alsa->pcm_handle);
snd_pcm_close(alsa->pcm_handle);
alsa->pcm_handle = 0;
}
if (alsa->mixer_handle)
{
snd_mixer_close(alsa->mixer_handle);
alsa->mixer_handle = NULL;
}
rdpsnd_alsa_pcm_close(alsa);
rdpsnd_alsa_close_mixer(alsa);
free(alsa->device_name);
free(alsa);
}
@ -361,8 +362,8 @@ static UINT32 rdpsnd_alsa_get_volume(rdpsndDevicePlugin* device)
dwVolumeLeft = ((50 * 0xFFFF) / 100); /* 50% */
dwVolumeRight = ((50 * 0xFFFF) / 100); /* 50% */
if (!alsa->mixer_handle)
rdpsnd_alsa_open_mixer(alsa);
if (!rdpsnd_alsa_open_mixer(alsa))
return 0;
for (elem = snd_mixer_first_elem(alsa->mixer_handle); elem; elem = snd_mixer_elem_next(elem))
{
@ -392,7 +393,7 @@ static BOOL rdpsnd_alsa_set_volume(rdpsndDevicePlugin* device, UINT32 value)
snd_mixer_elem_t* elem;
rdpsndAlsaPlugin* alsa = (rdpsndAlsaPlugin*) device;
if (!alsa->mixer_handle && !rdpsnd_alsa_open_mixer(alsa))
if (!rdpsnd_alsa_open_mixer(alsa))
return FALSE;
left = (value & 0xFFFF);
@ -438,8 +439,7 @@ static UINT rdpsnd_alsa_play(rdpsndDevicePlugin* device, const BYTE* data, size_
if (status < 0)
{
WLog_ERR(TAG, "status: %d\n", status);
snd_pcm_close(alsa->pcm_handle);
alsa->pcm_handle = NULL;
rdpsnd_alsa_close(alsa);
rdpsnd_alsa_open((rdpsndDevicePlugin*) alsa, NULL, alsa->latency);
break;
}

View File

@ -50,10 +50,47 @@ struct rdpsnd_pulse_plugin
pa_sample_spec sample_spec;
pa_stream* stream;
UINT32 latency;
UINT32 volume;
};
static BOOL rdpsnd_pulse_format_supported(rdpsndDevicePlugin* device, const AUDIO_FORMAT* format);
static void rdpsnd_pulse_get_sink_info(pa_context* c, const pa_sink_info* i, int eol,
void* userdata)
{
uint8_t x;
UINT16 dwVolumeLeft = ((50 * 0xFFFF) / 100); /* 50% */;
UINT16 dwVolumeRight = ((50 * 0xFFFF) / 100); /* 50% */;
rdpsndPulsePlugin* pulse = (rdpsndPulsePlugin*) userdata;
if (!pulse || !c || !i)
return;
for (x = 0; x < i->volume.channels; x++)
{
pa_volume_t volume = i->volume.values[x];
if (volume >= PA_VOLUME_NORM)
volume = PA_VOLUME_NORM - 1;
switch (x)
{
case 0:
dwVolumeLeft = (UINT16)volume;
break;
case 1:
dwVolumeRight = (UINT16)volume;
break;
default:
break;
}
}
pulse->volume = ((UINT32)dwVolumeLeft << 16U) | dwVolumeRight;
}
static void rdpsnd_pulse_context_state_callback(pa_context* context, void* userdata)
{
pa_context_state_t state;
@ -78,6 +115,7 @@ static void rdpsnd_pulse_context_state_callback(pa_context* context, void* userd
static BOOL rdpsnd_pulse_connect(rdpsndDevicePlugin* device)
{
pa_operation* o;
pa_context_state_t state;
rdpsndPulsePlugin* pulse = (rdpsndPulsePlugin*) device;
@ -112,6 +150,11 @@ static BOOL rdpsnd_pulse_connect(rdpsndDevicePlugin* device)
pa_threaded_mainloop_wait(pulse->mainloop);
}
o = pa_context_get_sink_info_by_index(pulse->context, 0, rdpsnd_pulse_get_sink_info, pulse);
if (o)
pa_operation_unref(o);
pa_threaded_mainloop_unlock(pulse->mainloop);
if (state == PA_CONTEXT_READY)
@ -347,11 +390,6 @@ static void rdpsnd_pulse_free(rdpsndDevicePlugin* device)
BOOL rdpsnd_pulse_format_supported(rdpsndDevicePlugin* device, const AUDIO_FORMAT* format)
{
rdpsndPulsePlugin* pulse = (rdpsndPulsePlugin*)device;
if (!pulse->context)
return FALSE;
switch (format->wFormatTag)
{
case WAVE_FORMAT_PCM:
@ -381,6 +419,24 @@ BOOL rdpsnd_pulse_format_supported(rdpsndDevicePlugin* device, const AUDIO_FORMA
return FALSE;
}
static UINT32 rdpsnd_pulse_get_volume(rdpsndDevicePlugin* device)
{
pa_operation* o;
rdpsndPulsePlugin* pulse = (rdpsndPulsePlugin*) device;
if (!pulse)
return 0;
if (!pulse->context || !pulse->mainloop)
return 0;
pa_threaded_mainloop_lock(pulse->mainloop);
o = pa_context_get_sink_info_by_index(pulse->context, 0, rdpsnd_pulse_get_sink_info, pulse);
pa_operation_unref(o);
pa_threaded_mainloop_unlock(pulse->mainloop);
return pulse->volume;
}
static BOOL rdpsnd_pulse_set_volume(rdpsndDevicePlugin* device, UINT32 value)
{
pa_cvolume cv;
@ -532,6 +588,7 @@ UINT freerdp_rdpsnd_client_subsystem_entry(PFREERDP_RDPSND_DEVICE_ENTRY_POINTS p
pulse->device.Open = rdpsnd_pulse_open;
pulse->device.FormatSupported = rdpsnd_pulse_format_supported;
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;

View File

@ -332,6 +332,48 @@ static UINT rdpsnd_recv_training_pdu(rdpsndPlugin* rdpsnd, wStream* s)
return rdpsnd_send_training_confirm_pdu(rdpsnd, wTimeStamp, wPackSize);
}
static BOOL rdpsnd_ensure_device_is_open(rdpsndPlugin* rdpsnd, UINT32 wFormatNo,
const AUDIO_FORMAT* format)
{
if (!rdpsnd)
return FALSE;
if (!rdpsnd->isOpen || (wFormatNo != rdpsnd->wCurrentFormatNo))
{
BOOL rc;
BOOL supported;
AUDIO_FORMAT deviceFormat = *format;
rdpsnd_recv_close_pdu(rdpsnd);
supported = IFCALLRESULT(FALSE, rdpsnd->device->FormatSupported, rdpsnd->device, format);
if (!supported)
{
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),
audio_format_get_tag_string(deviceFormat.wFormatTag));
rc = IFCALLRESULT(FALSE, rdpsnd->device->Open, rdpsnd->device, &deviceFormat, rdpsnd->latency);
if (!rc)
return FALSE;
if (!supported)
{
if (!freerdp_dsp_context_reset(rdpsnd->dsp_context, format))
return FALSE;
}
rdpsnd->isOpen = TRUE;
rdpsnd->wCurrentFormatNo = wFormatNo;
}
return TRUE;
}
/**
* Function description
*
@ -361,36 +403,8 @@ static UINT rdpsnd_recv_wave_info_pdu(rdpsndPlugin* rdpsnd, wStream* s,
WLog_Print(rdpsnd->log, WLOG_DEBUG, "WaveInfo: cBlockNo: %"PRIu8" wFormatNo: %"PRIu16" [%s]",
rdpsnd->cBlockNo, wFormatNo, audio_format_get_tag_string(format->wFormatTag));
if (!rdpsnd->isOpen || (wFormatNo != rdpsnd->wCurrentFormatNo))
{
BOOL rc;
AUDIO_FORMAT deviceFormat = *format;
rdpsnd_recv_close_pdu(rdpsnd);
rc = IFCALLRESULT(FALSE, rdpsnd->device->FormatSupported, rdpsnd->device, format);
if (!rc)
{
deviceFormat.wFormatTag = WAVE_FORMAT_PCM;
deviceFormat.wBitsPerSample = 16;
deviceFormat.cbSize = 0;
}
rc = IFCALLRESULT(FALSE, rdpsnd->device->Open, rdpsnd->device, &deviceFormat, rdpsnd->latency);
if (!rc)
return CHANNEL_RC_INITIALIZATION_ERROR;
rc = IFCALLRESULT(FALSE, rdpsnd->device->FormatSupported, rdpsnd->device, format);
if (!rc)
{
if (!freerdp_dsp_context_reset(rdpsnd->dsp_context, format))
return CHANNEL_RC_INITIALIZATION_ERROR;
}
rdpsnd->isOpen = TRUE;
rdpsnd->wCurrentFormatNo = wFormatNo;
}
if (!rdpsnd_ensure_device_is_open(rdpsnd, wFormatNo, format))
return ERROR_INTERNAL_ERROR;
rdpsnd->expectingWave = TRUE;
return CHANNEL_RC_OK;
@ -435,8 +449,8 @@ static UINT rdpsnd_treat_wave(rdpsndPlugin* rdpsnd, wStream* s, size_t size)
data = Stream_Pointer(s);
format = &rdpsnd->ClientFormats[rdpsnd->wCurrentFormatNo];
WLog_Print(rdpsnd->log, WLOG_DEBUG, "Wave: cBlockNo: %"PRIu8" wTimeStamp: %"PRIu16"",
rdpsnd->cBlockNo, rdpsnd->wTimeStamp);
WLog_Print(rdpsnd->log, WLOG_DEBUG, "Wave: cBlockNo: %"PRIu8" wTimeStamp: %"PRIu16", size: %"PRIdz,
rdpsnd->cBlockNo, rdpsnd->wTimeStamp, size);
if (rdpsnd->device && rdpsnd->attached)
{
@ -474,12 +488,16 @@ static UINT rdpsnd_treat_wave(rdpsndPlugin* rdpsnd, wStream* s, size_t size)
static UINT rdpsnd_recv_wave_pdu(rdpsndPlugin* rdpsnd, wStream* s)
{
rdpsnd->expectingWave = FALSE;
/**
* The Wave PDU is a special case: it is always sent after a Wave Info PDU,
* and we do not process its header. Instead, the header is pad that needs
* to be filled with the first four bytes of the audio sample data sent as
* part of the preceding Wave Info PDU.
*/
if (Stream_GetRemainingLength(s) < 4)
return ERROR_INVALID_DATA;
CopyMemory(Stream_Buffer(s), rdpsnd->waveData, 4);
return rdpsnd_treat_wave(rdpsnd, s, rdpsnd->waveDataSize);
}
@ -501,51 +519,25 @@ static UINT rdpsnd_recv_wave2_pdu(rdpsndPlugin* rdpsnd, wStream* s, UINT16 BodyS
rdpsnd->waveDataSize = BodySize - 12;
format = &rdpsnd->ClientFormats[wFormatNo];
rdpsnd->wArrivalTime = GetTickCount();
WLog_Print(rdpsnd->log, WLOG_DEBUG, "Wave2PDU: cBlockNo: %"PRIu8" wFormatNo: %"PRIu16"",
rdpsnd->cBlockNo, wFormatNo);
WLog_Print(rdpsnd->log, WLOG_DEBUG, "Wave2PDU: cBlockNo: %"PRIu8" wFormatNo: %"PRIu16", align=%hu",
rdpsnd->cBlockNo, wFormatNo, format->nBlockAlign);
if (!rdpsnd->isOpen || (wFormatNo != rdpsnd->wCurrentFormatNo))
{
BOOL rc;
AUDIO_FORMAT deviceFormat = *format;
rdpsnd_recv_close_pdu(rdpsnd);
rc = IFCALLRESULT(FALSE, rdpsnd->device->FormatSupported, rdpsnd->device, format);
if (!rc)
{
deviceFormat.wFormatTag = WAVE_FORMAT_PCM;
deviceFormat.wBitsPerSample = 16;
deviceFormat.cbSize = 0;
}
rc = IFCALLRESULT(FALSE, rdpsnd->device->Open, rdpsnd->device, &deviceFormat, rdpsnd->latency);
if (!rc)
return CHANNEL_RC_INITIALIZATION_ERROR;
rc = IFCALLRESULT(FALSE, rdpsnd->device->FormatSupported, rdpsnd->device, format);
if (!rc)
{
if (!freerdp_dsp_context_reset(rdpsnd->dsp_context, format))
return CHANNEL_RC_INITIALIZATION_ERROR;
}
rdpsnd->isOpen = TRUE;
rdpsnd->wCurrentFormatNo = wFormatNo;
}
if (!rdpsnd_ensure_device_is_open(rdpsnd, wFormatNo, format))
return ERROR_INTERNAL_ERROR;
return rdpsnd_treat_wave(rdpsnd, s, rdpsnd->waveDataSize);
}
static void rdpsnd_recv_close_pdu(rdpsndPlugin* rdpsnd)
{
WLog_Print(rdpsnd->log, WLOG_DEBUG, "Close");
if (rdpsnd->isOpen)
{
WLog_Print(rdpsnd->log, WLOG_DEBUG, "Closing device");
IFCALL(rdpsnd->device->Close, rdpsnd->device);
rdpsnd->isOpen = FALSE;
rdpsnd->isOpen = FALSE;
}
else
WLog_Print(rdpsnd->log, WLOG_DEBUG, "Device already closed");
}
/**
@ -555,7 +547,7 @@ static void rdpsnd_recv_close_pdu(rdpsndPlugin* rdpsnd)
*/
static UINT rdpsnd_recv_volume_pdu(rdpsndPlugin* rdpsnd, wStream* s)
{
BOOL error;
BOOL rc;
UINT32 dwVolume;
if (Stream_GetRemainingLength(s) < 4)
@ -563,9 +555,9 @@ static UINT rdpsnd_recv_volume_pdu(rdpsndPlugin* rdpsnd, wStream* s)
Stream_Read_UINT32(s, dwVolume);
WLog_Print(rdpsnd->log, WLOG_DEBUG, "Volume: 0x%08"PRIX32"", dwVolume);
error = IFCALLRESULT(FALSE, rdpsnd->device->SetVolume, rdpsnd->device, dwVolume);
rc = IFCALLRESULT(FALSE, rdpsnd->device->SetVolume, rdpsnd->device, dwVolume);
if (error)
if (!rc)
{
WLog_ERR(TAG, "error setting volume");
return CHANNEL_RC_INITIALIZATION_ERROR;

View File

@ -379,6 +379,26 @@ out:
return error;
}
static BOOL rdpsnd_server_align_wave_pdu(wStream* s, UINT32 alignment)
{
size_t size;
Stream_SealLength(s);
size = Stream_Length(s);
if ((size % alignment) != 0)
{
size_t offset = alignment - size % alignment;
if (!Stream_EnsureRemainingCapacity(s, offset))
return FALSE;
Stream_Zero(s, offset);
}
Stream_SealLength(s);
return TRUE;
}
/**
* Function description
* context->priv->lock should be obtained before calling this function
@ -410,10 +430,13 @@ static UINT rdpsnd_server_send_wave_pdu(RdpsndServerContext* context,
length = context->priv->out_pending_frames * context->priv->src_bytes_per_frame;
if (!freerdp_dsp_encode(context->priv->dsp_context, format, src, length, s))
error = ERROR_INTERNAL_ERROR;
return ERROR_INTERNAL_ERROR;
else
{
/* Set stream size */
if (!rdpsnd_server_align_wave_pdu(s, format->nBlockAlign))
return ERROR_INTERNAL_ERROR;
end = Stream_GetPosition(s);
Stream_SetPosition(s, 2);
Stream_Write_UINT16(s, end - start + 8);
@ -486,18 +509,23 @@ static UINT rdpsnd_server_send_wave2_pdu(RdpsndServerContext* context,
error = ERROR_INTERNAL_ERROR;
else
{
BOOL rc;
/* Set stream size */
if (!rdpsnd_server_align_wave_pdu(s, format->nBlockAlign))
return ERROR_INTERNAL_ERROR;
end = Stream_GetPosition(s);
Stream_SetPosition(s, 2);
Stream_Write_UINT16(s, end - 4);
Stream_SetPosition(s, end);
Stream_SealLength(s);
context->block_no = (context->block_no + 1) % 256;
rc = WTSVirtualChannelWrite(context->priv->ChannelHandle,
(PCHAR) Stream_Buffer(s), end, &written);
if (!WTSVirtualChannelWrite(context->priv->ChannelHandle,
(PCHAR) Stream_Buffer(s), Stream_Length(s), &written))
if (!rc || (end != written))
{
WLog_ERR(TAG, "WTSVirtualChannelWrite failed!");
WLog_ERR(TAG, "WTSVirtualChannelWrite failed! [stream length=%"PRIdz" - written=%"PRIu32, end,
written);
error = ERROR_INTERNAL_ERROR;
}
}
@ -715,7 +743,6 @@ static UINT rdpsnd_server_start(RdpsndServerContext* context)
}
return CHANNEL_RC_OK;
out_stopEvent:
CloseHandle(context->priv->StopEvent);
context->priv->StopEvent = NULL;

View File

@ -87,20 +87,17 @@ static BOOL update_recv_surfcmd_bitmap_ex(wStream* s, TS_BITMAP_DATA_EX* bmp)
static BOOL update_recv_surfcmd_surface_bits(rdpUpdate* update, wStream* s)
{
SURFACE_BITS_COMMAND* cmd = calloc(1, sizeof(SURFACE_BITS_COMMAND));
if (!cmd)
return FALSE;
SURFACE_BITS_COMMAND cmd = {0};
if (Stream_GetRemainingLength(s) < 8)
goto fail;
Stream_Read_UINT16(s, cmd->destLeft);
Stream_Read_UINT16(s, cmd->destTop);
Stream_Read_UINT16(s, cmd->destRight);
Stream_Read_UINT16(s, cmd->destBottom);
Stream_Read_UINT16(s, cmd.destLeft);
Stream_Read_UINT16(s, cmd.destTop);
Stream_Read_UINT16(s, cmd.destRight);
Stream_Read_UINT16(s, cmd.destBottom);
if (!update_recv_surfcmd_bitmap_ex(s, &cmd->bmp))
if (!update_recv_surfcmd_bitmap_ex(s, &cmd.bmp))
goto fail;
if (!update->SurfaceBits)
@ -109,9 +106,8 @@ static BOOL update_recv_surfcmd_surface_bits(rdpUpdate* update, wStream* s)
goto fail;
}
return update->SurfaceBits(update->context, cmd);
return update->SurfaceBits(update->context, &cmd);
fail:
free_surface_bits_command(update->context, cmd);
return FALSE;
}