From b6e5ec503981e4dad97bc8ccce6e8d079cfb9487 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Wed, 17 May 2017 10:27:25 +0200 Subject: [PATCH] Added client RDPGFX_QOE_FRAME_ACKNOWLEDGE_PDU --- channels/rdpgfx/client/rdpgfx_main.c | 76 +++++++++++++++++++++++++--- channels/rdpgfx/client/rdpgfx_main.h | 2 + 2 files changed, 70 insertions(+), 8 deletions(-) diff --git a/channels/rdpgfx/client/rdpgfx_main.c b/channels/rdpgfx/client/rdpgfx_main.c index 8d59a3720..328ea2efe 100644 --- a/channels/rdpgfx/client/rdpgfx_main.c +++ b/channels/rdpgfx/client/rdpgfx_main.c @@ -120,10 +120,7 @@ static UINT rdpgfx_send_caps_advertise_pdu(RDPGFX_CHANNEL_CALLBACK* callback) } if ((error = rdpgfx_write_header(s, &header))) - { - WLog_Print(gfx->log, WLOG_ERROR, "rdpgfx_write_header failed with error %"PRIu32"!", error); - return error; - } + goto fail; /* RDPGFX_CAPS_ADVERTISE_PDU */ Stream_Write_UINT16(s, pdu.capsSetCount); /* capsSetCount (2 bytes) */ @@ -139,6 +136,7 @@ static UINT rdpgfx_send_caps_advertise_pdu(RDPGFX_CHANNEL_CALLBACK* callback) Stream_SealLength(s); error = callback->channel->Write(callback->channel, (UINT32) Stream_Length(s), Stream_Buffer(s), NULL); +fail: Stream_Free(s, TRUE); return error; } @@ -167,6 +165,9 @@ static UINT rdpgfx_recv_caps_confirm_pdu(RDPGFX_CHANNEL_CALLBACK* callback, Stream_Read_UINT32(s, capsSet.version); /* version (4 bytes) */ Stream_Read_UINT32(s, capsDataLength); /* capsDataLength (4 bytes) */ Stream_Read_UINT32(s, capsSet.flags); /* capsData (4 bytes) */ + + gfx->ConnectionCaps = capsSet; + WLog_Print(gfx->log, WLOG_DEBUG, "RecvCapsConfirmPdu: version: 0x%08"PRIX32" flags: 0x%08"PRIX32"", capsSet.version, capsSet.flags); return CHANNEL_RC_OK; @@ -198,10 +199,7 @@ static UINT rdpgfx_send_frame_acknowledge_pdu(RDPGFX_CHANNEL_CALLBACK* callback, } if ((error = rdpgfx_write_header(s, &header))) - { - WLog_ERR(TAG, "rdpgfx_write_header failed with error %"PRIu32"!", error); - return error; - } + goto fail; /* RDPGFX_FRAME_ACKNOWLEDGE_PDU */ Stream_Write_UINT32(s, pdu->queueDepth); /* queueDepth (4 bytes) */ @@ -210,6 +208,43 @@ static UINT rdpgfx_send_frame_acknowledge_pdu(RDPGFX_CHANNEL_CALLBACK* callback, pdu->totalFramesDecoded); /* totalFramesDecoded (4 bytes) */ error = callback->channel->Write(callback->channel, (UINT32) Stream_Length(s), Stream_Buffer(s), NULL); +fail: + Stream_Free(s, TRUE); + return error; +} + +static UINT rdpgfx_send_qoe_frame_acknowledge_pdu(RDPGFX_CHANNEL_CALLBACK* callback, + const RDPGFX_QOE_FRAME_ACKNOWLEDGE_PDU* pdu) +{ + UINT error; + wStream* s; + RDPGFX_HEADER header; + RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) callback->plugin; + + header.flags = 0; + header.cmdId = RDPGFX_CMDID_QOEFRAMEACKNOWLEDGE; + header.pduLength = RDPGFX_HEADER_SIZE + 12; + WLog_Print(gfx->log, WLOG_DEBUG, "SendQoeFrameAcknowledgePdu: %"PRIu32"", pdu->frameId); + s = Stream_New(NULL, header.pduLength); + + if (!s) + { + WLog_ERR(TAG, "Stream_New failed!"); + return CHANNEL_RC_NO_MEMORY; + } + + if ((error = rdpgfx_write_header(s, &header))) + goto fail; + + /* RDPGFX_FRAME_ACKNOWLEDGE_PDU */ + Stream_Write_UINT32(s, pdu->frameId); + Stream_Write_UINT32(s, pdu->timestamp); + Stream_Write_UINT16(s, pdu->timeDiffSE); + Stream_Write_UINT16(s, pdu->timeDiffEDR); + + error = callback->channel->Write(callback->channel, (UINT32) Stream_Length(s), + Stream_Buffer(s), NULL); +fail: Stream_Free(s, TRUE); return error; } @@ -482,6 +517,7 @@ static UINT rdpgfx_recv_start_frame_pdu(RDPGFX_CHANNEL_CALLBACK* callback, WLog_Print(gfx->log, WLOG_DEBUG, "RecvStartFramePdu: frameId: %"PRIu32" timestamp: 0x%08"PRIX32"", pdu.frameId, pdu.timestamp); + gfx->StartDecodingTime = GetTickCountPrecise(); if (context) { IFCALLRET(context->StartFrame, error, context, &pdu); @@ -549,6 +585,30 @@ static UINT rdpgfx_recv_end_frame_pdu(RDPGFX_CHANNEL_CALLBACK* callback, WLog_Print(gfx->log, WLOG_DEBUG, "rdpgfx_send_frame_acknowledge_pdu failed with error %"PRIu32"", error); } + switch(gfx->ConnectionCaps.version) + { + case RDPGFX_CAPVERSION_10: + case RDPGFX_CAPVERSION_102: + case RDPGFX_CAPVERSION_103: + { + RDPGFX_QOE_FRAME_ACKNOWLEDGE_PDU qoe; + UINT32 diff = (GetTickCountPrecise() - gfx->StartDecodingTime); + + if (diff > 65000) + diff = 0; + + qoe.frameId = pdu.frameId; + qoe.timestamp = gfx->StartDecodingTime; + qoe.timeDiffSE = diff; + qoe.timeDiffEDR = 1; + if ((error = rdpgfx_send_qoe_frame_acknowledge_pdu(callback, &qoe))) + WLog_Print(gfx->log, WLOG_DEBUG, "rdpgfx_send_frame_acknowledge_pdu failed with error %"PRIu32"", error); + } + break; + default: + break; + } + return error; } diff --git a/channels/rdpgfx/client/rdpgfx_main.h b/channels/rdpgfx/client/rdpgfx_main.h index 08d9e93fc..c11a0af9e 100644 --- a/channels/rdpgfx/client/rdpgfx_main.h +++ b/channels/rdpgfx/client/rdpgfx_main.h @@ -71,6 +71,7 @@ struct _RDPGFX_PLUGIN ZGFX_CONTEXT* zgfx; UINT32 UnacknowledgedFrames; UINT32 TotalDecodedFrames; + UINT32 StartDecodingTime; BOOL suspendFrameAcks; wHashTable* SurfaceTable; @@ -80,6 +81,7 @@ struct _RDPGFX_PLUGIN rdpContext* rdpcontext; wLog* log; + RDPGFX_CAPSET ConnectionCaps; }; typedef struct _RDPGFX_PLUGIN RDPGFX_PLUGIN;