diff --git a/channels/rdpgfx/client/rdpgfx_main.c b/channels/rdpgfx/client/rdpgfx_main.c index 987c78726..c7b17e2e0 100644 --- a/channels/rdpgfx/client/rdpgfx_main.c +++ b/channels/rdpgfx/client/rdpgfx_main.c @@ -52,20 +52,75 @@ * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpgfx_send_caps_advertise_pdu(RDPGFX_CHANNEL_CALLBACK* callback) +static UINT rdpgfx_send_caps_advertise_pdu(RdpgfxClientContext* context, + const RDPGFX_CAPS_ADVERTISE_PDU* pdu) { - UINT error; - UINT32 x; - wStream* s; + UINT error = CHANNEL_RC_OK; UINT16 index; - RDPGFX_PLUGIN* gfx; RDPGFX_HEADER header; RDPGFX_CAPSET* capsSet; + RDPGFX_PLUGIN* gfx; + RDPGFX_CHANNEL_CALLBACK* callback; + wStream* s; + gfx = (RDPGFX_PLUGIN*) context->handle; + callback = gfx->listener_callback->channel_callback; + header.flags = 0; + header.cmdId = RDPGFX_CMDID_CAPSADVERTISE; + header.pduLength = RDPGFX_HEADER_SIZE + 2; + + for (index = 0; index < pdu->capsSetCount; index++) + { + capsSet = &(pdu->capsSets[index]); + header.pduLength += RDPGFX_CAPSET_BASE_SIZE + capsSet->length; + } + + WLog_Print(gfx->log, WLOG_DEBUG, "SendCapsAdvertisePdu %"PRIu16"", pdu->capsSetCount); + 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_CAPS_ADVERTISE_PDU */ + Stream_Write_UINT16(s, pdu->capsSetCount); /* capsSetCount (2 bytes) */ + + for (index = 0; index < pdu->capsSetCount; index++) + { + capsSet = &(pdu->capsSets[index]); + Stream_Write_UINT32(s, capsSet->version); /* version (4 bytes) */ + Stream_Write_UINT32(s, capsSet->length); /* capsDataLength (4 bytes) */ + Stream_Write_UINT32(s, capsSet->flags); /* capsData (4 bytes) */ + Stream_Zero(s, capsSet->length - 4); + } + + Stream_SealLength(s); + error = callback->channel->Write(callback->channel, (UINT32) Stream_Length(s), + Stream_Buffer(s), NULL); +fail: + Stream_Free(s, TRUE); + return error; +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT rdpgfx_send_supported_caps(RDPGFX_CHANNEL_CALLBACK* callback) +{ + UINT error = CHANNEL_RC_OK; + RDPGFX_PLUGIN* gfx; + RdpgfxClientContext* context; + RDPGFX_CAPSET* capsSet; RDPGFX_CAPSET capsSets[RDPGFX_NUMBER_CAPSETS] = { 0 }; RDPGFX_CAPS_ADVERTISE_PDU pdu; gfx = (RDPGFX_PLUGIN*) callback->plugin; - header.flags = 0; - header.cmdId = RDPGFX_CMDID_CAPSADVERTISE; + context = (RdpgfxClientContext*) gfx->iface.pInterface; pdu.capsSetCount = 0; pdu.capsSets = (RDPGFX_CAPSET*) capsSets; capsSet = &capsSets[pdu.capsSetCount++]; @@ -160,40 +215,11 @@ static UINT rdpgfx_send_caps_advertise_pdu(RDPGFX_CHANNEL_CALLBACK* callback) #endif } - header.pduLength = RDPGFX_HEADER_SIZE + 2; - - for (x = 0; x < pdu.capsSetCount; x++) - header.pduLength += RDPGFX_CAPSET_BASE_SIZE + capsSets[x].length; - - WLog_Print(gfx->log, WLOG_DEBUG, "SendCapsAdvertisePdu %"PRIu16"", pdu.capsSetCount); - s = Stream_New(NULL, header.pduLength); - - if (!s) + if (context) { - WLog_ERR(TAG, "Stream_New failed!"); - return CHANNEL_RC_NO_MEMORY; + IFCALLRET(context->CapsAdvertise, error, context, &pdu); } - if ((error = rdpgfx_write_header(s, &header))) - goto fail; - - /* RDPGFX_CAPS_ADVERTISE_PDU */ - Stream_Write_UINT16(s, pdu.capsSetCount); /* capsSetCount (2 bytes) */ - - for (index = 0; index < pdu.capsSetCount; index++) - { - capsSet = &(pdu.capsSets[index]); - Stream_Write_UINT32(s, capsSet->version); /* version (4 bytes) */ - Stream_Write_UINT32(s, capsSet->length); /* capsDataLength (4 bytes) */ - Stream_Write_UINT32(s, capsSet->flags); /* capsData (4 bytes) */ - Stream_Zero(s, capsSet->length - 4); - } - - Stream_SealLength(s); - error = callback->channel->Write(callback->channel, (UINT32) Stream_Length(s), - Stream_Buffer(s), NULL); -fail: - Stream_Free(s, TRUE); return error; } @@ -209,6 +235,7 @@ static UINT rdpgfx_recv_caps_confirm_pdu(RDPGFX_CHANNEL_CALLBACK* callback, UINT32 capsDataLength; RDPGFX_CAPS_CONFIRM_PDU pdu; RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) callback->plugin; + RdpgfxClientContext* context = (RdpgfxClientContext*) gfx->iface.pInterface; pdu.capsSet = &capsSet; if (Stream_GetRemainingLength(s) < 12) @@ -223,6 +250,12 @@ static UINT rdpgfx_recv_caps_confirm_pdu(RDPGFX_CHANNEL_CALLBACK* callback, gfx->ConnectionCaps = capsSet; WLog_Print(gfx->log, WLOG_DEBUG, "RecvCapsConfirmPdu: version: 0x%08"PRIX32" flags: 0x%08"PRIX32"", capsSet.version, capsSet.flags); + + if (context) + { + IFCALL(context->CapsConfirm, context, &pdu); + } + return CHANNEL_RC_OK; } @@ -231,13 +264,14 @@ static UINT rdpgfx_recv_caps_confirm_pdu(RDPGFX_CHANNEL_CALLBACK* callback, * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpgfx_send_frame_acknowledge_pdu(RDPGFX_CHANNEL_CALLBACK* callback, +static UINT rdpgfx_send_frame_acknowledge_pdu(RdpgfxClientContext* context, RDPGFX_FRAME_ACKNOWLEDGE_PDU* pdu) { UINT error; wStream* s; RDPGFX_HEADER header; - RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) callback->plugin; + RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) context->handle; + RDPGFX_CHANNEL_CALLBACK* callback = gfx->listener_callback->channel_callback; header.flags = 0; header.cmdId = RDPGFX_CMDID_FRAMEACKNOWLEDGE; header.pduLength = RDPGFX_HEADER_SIZE + 12; @@ -599,7 +633,6 @@ static UINT rdpgfx_recv_end_frame_pdu(RDPGFX_CHANNEL_CALLBACK* callback, RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) callback->plugin; RdpgfxClientContext* context = (RdpgfxClientContext*) gfx->iface.pInterface; UINT error = CHANNEL_RC_OK; - BOOL sendAck = TRUE; if (Stream_GetRemainingLength(s) < RDPGFX_END_FRAME_PDU_SIZE) { @@ -625,16 +658,15 @@ static UINT rdpgfx_recv_end_frame_pdu(RDPGFX_CHANNEL_CALLBACK* callback, gfx->TotalDecodedFrames++; ack.frameId = pdu.frameId; ack.totalFramesDecoded = gfx->TotalDecodedFrames; - IFCALLRET(context->PreFrameAck, sendAck, context, &ack); - if (sendAck) + if (gfx->sendFrameAcks) { if (gfx->suspendFrameAcks) { ack.queueDepth = SUSPEND_FRAME_ACKNOWLEDGEMENT; if (gfx->TotalDecodedFrames == 1) - if ((error = rdpgfx_send_frame_acknowledge_pdu(callback, &ack))) + if ((error = rdpgfx_send_frame_acknowledge_pdu(context, &ack))) WLog_Print(gfx->log, WLOG_ERROR, "rdpgfx_send_frame_acknowledge_pdu failed with error %"PRIu32"", error); } @@ -642,7 +674,7 @@ static UINT rdpgfx_recv_end_frame_pdu(RDPGFX_CHANNEL_CALLBACK* callback, { ack.queueDepth = QUEUE_DEPTH_UNAVAILABLE; - if ((error = rdpgfx_send_frame_acknowledge_pdu(callback, &ack))) + if ((error = rdpgfx_send_frame_acknowledge_pdu(context, &ack))) WLog_Print(gfx->log, WLOG_ERROR, "rdpgfx_send_frame_acknowledge_pdu failed with error %"PRIu32"", error); } @@ -667,7 +699,8 @@ static UINT rdpgfx_recv_end_frame_pdu(RDPGFX_CHANNEL_CALLBACK* callback, qoe.timeDiffEDR = 1; if ((error = rdpgfx_send_qoe_frame_acknowledge_pdu(callback, &qoe))) - WLog_Print(gfx->log, WLOG_ERROR, "rdpgfx_send_frame_acknowledge_pdu failed with error %"PRIu32"", + WLog_Print(gfx->log, WLOG_ERROR, + "rdpgfx_send_qoe_frame_acknowledge_pdu failed with error %"PRIu32"", error); } @@ -1518,8 +1551,24 @@ static UINT rdpgfx_on_data_received(IWTSVirtualChannelCallback* static UINT rdpgfx_on_open(IWTSVirtualChannelCallback* pChannelCallback) { RDPGFX_CHANNEL_CALLBACK* callback = (RDPGFX_CHANNEL_CALLBACK*) pChannelCallback; - WLog_DBG(TAG, "OnOpen"); - return rdpgfx_send_caps_advertise_pdu(callback); + RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) callback->plugin; + RdpgfxClientContext* context = (RdpgfxClientContext*) gfx->iface.pInterface; + UINT error = CHANNEL_RC_OK; + BOOL do_caps_advertise = TRUE; + gfx->sendFrameAcks = TRUE; + + if (context) + { + IFCALLRET(context->OnOpen, error, context, &do_caps_advertise, &gfx->sendFrameAcks); + + if (error) + WLog_Print(gfx->log, WLOG_ERROR, "context->OnOpen failed with error %"PRIu32"", error); + } + + if (do_caps_advertise) + error = rdpgfx_send_supported_caps(callback); + + return error; } /** @@ -1580,6 +1629,11 @@ static UINT rdpgfx_on_close(IWTSVirtualChannelCallback* pChannelCallback) } } + if (context) + { + IFCALL(context->OnClose, context); + } + return CHANNEL_RC_OK; } @@ -1911,6 +1965,8 @@ UINT DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints) context->GetSurfaceData = rdpgfx_get_surface_data; context->SetCacheSlotData = rdpgfx_set_cache_slot_data; context->GetCacheSlotData = rdpgfx_get_cache_slot_data; + context->CapsAdvertise = rdpgfx_send_caps_advertise_pdu; + context->FrameAcknowledge = rdpgfx_send_frame_acknowledge_pdu; gfx->iface.pInterface = (void*) context; gfx->zgfx = zgfx_context_new(FALSE); diff --git a/channels/rdpgfx/client/rdpgfx_main.h b/channels/rdpgfx/client/rdpgfx_main.h index 7efe29863..0b098398d 100644 --- a/channels/rdpgfx/client/rdpgfx_main.h +++ b/channels/rdpgfx/client/rdpgfx_main.h @@ -73,6 +73,7 @@ struct _RDPGFX_PLUGIN UINT32 TotalDecodedFrames; UINT32 StartDecodingTime; BOOL suspendFrameAcks; + BOOL sendFrameAcks; wHashTable* SurfaceTable; diff --git a/include/freerdp/client/rdpgfx.h b/include/freerdp/client/rdpgfx.h index 7de72ed9f..ea2120eb1 100644 --- a/include/freerdp/client/rdpgfx.h +++ b/include/freerdp/client/rdpgfx.h @@ -83,8 +83,15 @@ typedef UINT(*pcRdpgfxUpdateSurfaces)(RdpgfxClientContext* context); typedef UINT(*pcRdpgfxUpdateSurfaceArea)(RdpgfxClientContext* context, UINT16 surfaceId, UINT32 nrRects, const RECTANGLE_16* rects); -typedef BOOL(*pcRdpgfxPreFrameAck)(RdpgfxClientContext* context, - RDPGFX_FRAME_ACKNOWLEDGE_PDU* frameAcknowledge); +typedef UINT(*pcRdpgfxOnOpen)(RdpgfxClientContext* context, BOOL* do_caps_advertise, + BOOL* do_frame_acks); +typedef UINT(*pcRdpgfxOnClose)(RdpgfxClientContext* context); +typedef UINT(*pcRdpgfxCapsAdvertise)(RdpgfxClientContext* context, + const RDPGFX_CAPS_ADVERTISE_PDU* capsAdvertise); +typedef UINT(*pcRdpgfxCapsConfirm)(RdpgfxClientContext* context, + const RDPGFX_CAPS_CONFIRM_PDU* capsConfirm); +typedef UINT(*pcRdpgfxFrameAcknowledge)(RdpgfxClientContext* context, + const RDPGFX_FRAME_ACKNOWLEDGE_PDU* frameAcknowledge); struct _rdpgfx_client_context { @@ -117,12 +124,17 @@ struct _rdpgfx_client_context pcRdpgfxSetCacheSlotData SetCacheSlotData; pcRdpgfxGetCacheSlotData GetCacheSlotData; + /* Proxy callbacks */ + pcRdpgfxOnOpen OnOpen; + pcRdpgfxOnClose OnClose; + pcRdpgfxCapsAdvertise CapsAdvertise; + pcRdpgfxCapsConfirm CapsConfirm; + pcRdpgfxFrameAcknowledge FrameAcknowledge; + /* No locking required */ pcRdpgfxUpdateSurfaces UpdateSurfaces; pcRdpgfxUpdateSurfaceArea UpdateSurfaceArea; - pcRdpgfxPreFrameAck PreFrameAck; - CRITICAL_SECTION mux; PROFILER_DEFINE(SurfaceProfiler) };