diff --git a/channels/rdpgfx/client/rdpgfx_main.c b/channels/rdpgfx/client/rdpgfx_main.c index 930ef6276..aeb4b3614 100644 --- a/channels/rdpgfx/client/rdpgfx_main.c +++ b/channels/rdpgfx/client/rdpgfx_main.c @@ -363,21 +363,40 @@ static UINT rdpgfx_send_frame_acknowledge_pdu(RdpgfxClientContext* context, pdu->totalFramesDecoded); /* totalFramesDecoded (4 bytes) */ error = callback->channel->Write(callback->channel, (UINT32) Stream_Length(s), Stream_Buffer(s), NULL); + + if (error == CHANNEL_RC_OK) /* frame successfully acked */ + gfx->UnacknowledgedFrames--; + fail: Stream_Free(s, TRUE); return error; } -static UINT rdpgfx_send_qoe_frame_acknowledge_pdu(RDPGFX_CHANNEL_CALLBACK* callback, +static UINT rdpgfx_send_qoe_frame_acknowledge_pdu(RdpgfxClientContext* context, const RDPGFX_QOE_FRAME_ACKNOWLEDGE_PDU* pdu) { UINT error; wStream* s; RDPGFX_HEADER header; - RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) callback->plugin; + RDPGFX_CHANNEL_CALLBACK* callback; + RDPGFX_PLUGIN* gfx; header.flags = 0; header.cmdId = RDPGFX_CMDID_QOEFRAMEACKNOWLEDGE; header.pduLength = RDPGFX_HEADER_SIZE + 12; + + if (!context || !pdu) + return ERROR_BAD_ARGUMENTS; + + gfx = (RDPGFX_PLUGIN*) context->handle; + + if (!gfx) + return ERROR_BAD_CONFIGURATION; + + callback = gfx->listener_callback->channel_callback; + + if (!callback) + return ERROR_BAD_CONFIGURATION; + DEBUG_RDPGFX(gfx->log, "SendQoeFrameAcknowledgePdu: %"PRIu32"", pdu->frameId); s = Stream_New(NULL, header.pduLength); @@ -402,6 +421,75 @@ fail: return error; } +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT rdpgfx_send_cache_import_offer_pdu(RdpgfxClientContext* context, + const RDPGFX_CACHE_IMPORT_OFFER_PDU* pdu) +{ + UINT16 index; + UINT error = CHANNEL_RC_OK; + wStream* s; + RDPGFX_PLUGIN* gfx; + RDPGFX_CHANNEL_CALLBACK* callback; + RDPGFX_HEADER header; + RDPGFX_CACHE_ENTRY_METADATA* cacheEntries; + + if (!context || !pdu) + return ERROR_BAD_ARGUMENTS; + + gfx = (RDPGFX_PLUGIN*) context->handle; + + if (!gfx) + return ERROR_BAD_CONFIGURATION; + + callback = gfx->listener_callback->channel_callback; + + if (!callback) + return ERROR_BAD_CONFIGURATION; + + header.flags = 0; + header.cmdId = RDPGFX_CMDID_CACHEIMPORTOFFER; + header.pduLength = RDPGFX_HEADER_SIZE + 2 + pdu->cacheEntriesCount * 12; + DEBUG_RDPGFX(gfx->log, "SendCacheImportOfferPdu: cacheEntriesCount: %"PRIu16"", pdu->cacheEntriesCount); + 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; + + if (pdu->cacheEntriesCount <= 0) + { + WLog_ERR(TAG, "Invalid cacheEntriesCount: %"PRIu16"", pdu->cacheEntriesCount); + error = ERROR_INVALID_DATA; + goto fail; + } + + /* cacheEntriesCount (2 bytes) */ + Stream_Write_UINT16(s, pdu->cacheEntriesCount); + + for (index = 0; index < pdu->cacheEntriesCount; index++) + { + cacheEntries = &(pdu->cacheEntries[index]); + Stream_Write_UINT64(s, cacheEntries->cacheKey); /* cacheKey (8 bytes) */ + Stream_Write_UINT32(s, cacheEntries->bitmapLength); /* bitmapLength (4 bytes) */ + } + + error = callback->channel->Write(callback->channel, (UINT32) Stream_Length(s), + Stream_Buffer(s), NULL); + +fail: + Stream_Free(s, TRUE); + return error; +} + /** * Function description * @@ -720,30 +808,30 @@ static UINT rdpgfx_recv_end_frame_pdu(RDPGFX_CHANNEL_CALLBACK* callback, } } - gfx->UnacknowledgedFrames--; gfx->TotalDecodedFrames++; + + if (!gfx->sendFrameAcks) + return error; + ack.frameId = pdu.frameId; ack.totalFramesDecoded = gfx->TotalDecodedFrames; - if (gfx->sendFrameAcks) + if (gfx->suspendFrameAcks) { - if (gfx->suspendFrameAcks) - { - ack.queueDepth = SUSPEND_FRAME_ACKNOWLEDGEMENT; - - if (gfx->TotalDecodedFrames == 1) - 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); - } - else - { - ack.queueDepth = QUEUE_DEPTH_UNAVAILABLE; + ack.queueDepth = SUSPEND_FRAME_ACKNOWLEDGEMENT; + if (gfx->TotalDecodedFrames == 1) 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); - } + error); + } + else + { + ack.queueDepth = QUEUE_DEPTH_UNAVAILABLE; + + 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); } switch (gfx->ConnectionCaps.version) @@ -767,7 +855,7 @@ static UINT rdpgfx_recv_end_frame_pdu(RDPGFX_CHANNEL_CALLBACK* callback, qoe.timeDiffSE = diff; qoe.timeDiffEDR = 1; - if ((error = rdpgfx_send_qoe_frame_acknowledge_pdu(callback, &qoe))) + if ((error = rdpgfx_send_qoe_frame_acknowledge_pdu(context, &qoe))) WLog_Print(gfx->log, WLOG_ERROR, "rdpgfx_send_qoe_frame_acknowledge_pdu failed with error %"PRIu32"", error); @@ -2035,6 +2123,9 @@ UINT DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints) context->GetCacheSlotData = rdpgfx_get_cache_slot_data; context->CapsAdvertise = rdpgfx_send_caps_advertise_pdu; context->FrameAcknowledge = rdpgfx_send_frame_acknowledge_pdu; + context->CacheImportOffer = rdpgfx_send_cache_import_offer_pdu; + context->QoeFrameAcknowledge = rdpgfx_send_qoe_frame_acknowledge_pdu; + gfx->iface.pInterface = (void*) context; gfx->zgfx = zgfx_context_new(FALSE); diff --git a/channels/rdpgfx/server/rdpgfx_main.c b/channels/rdpgfx/server/rdpgfx_main.c index 989f421b3..793dcd1c3 100644 --- a/channels/rdpgfx/server/rdpgfx_main.c +++ b/channels/rdpgfx/server/rdpgfx_main.c @@ -1165,8 +1165,7 @@ static UINT rdpgfx_recv_cache_import_offer_pdu(RdpgfxServerContext* context, { cacheEntries = &(pdu.cacheEntries[index]); Stream_Read_UINT64(s, cacheEntries->cacheKey); /* cacheKey (8 bytes) */ - /* bitmapLength (4 bytes) */ - Stream_Read_UINT32(s, cacheEntries->bitmapLength); + Stream_Read_UINT32(s, cacheEntries->bitmapLength); /* bitmapLength (4 bytes) */ } if (context) diff --git a/include/freerdp/client/rdpgfx.h b/include/freerdp/client/rdpgfx.h index 793f0e07c..b33786a29 100644 --- a/include/freerdp/client/rdpgfx.h +++ b/include/freerdp/client/rdpgfx.h @@ -92,6 +92,8 @@ typedef UINT(*pcRdpgfxCapsConfirm)(RdpgfxClientContext* context, const RDPGFX_CAPS_CONFIRM_PDU* capsConfirm); typedef UINT(*pcRdpgfxFrameAcknowledge)(RdpgfxClientContext* context, const RDPGFX_FRAME_ACKNOWLEDGE_PDU* frameAcknowledge); +typedef UINT(*pcRdpgfxQoeFrameAcknowledge)(RdpgfxClientContext* context, + const RDPGFX_QOE_FRAME_ACKNOWLEDGE_PDU* qoeFrameAcknowledge); typedef UINT(*pcRdpgfxMapWindowForSurface)(RdpgfxClientContext* context, UINT16 surfaceID, UINT64 windowID); @@ -134,6 +136,7 @@ struct _rdpgfx_client_context pcRdpgfxCapsAdvertise CapsAdvertise; pcRdpgfxCapsConfirm CapsConfirm; pcRdpgfxFrameAcknowledge FrameAcknowledge; + pcRdpgfxQoeFrameAcknowledge QoeFrameAcknowledge; /* No locking required */ pcRdpgfxUpdateSurfaces UpdateSurfaces; diff --git a/server/proxy/pf_rdpgfx.c b/server/proxy/pf_rdpgfx.c index d049e2748..a729dc871 100644 --- a/server/proxy/pf_rdpgfx.c +++ b/server/proxy/pf_rdpgfx.c @@ -286,6 +286,24 @@ static UINT pf_rdpgfx_frame_acknowledge(RdpgfxServerContext* context, return client->FrameAcknowledge(client, frameAcknowledge); } +static UINT pf_rdpgfx_qoe_frame_acknowledge(RdpgfxServerContext* context, + const RDPGFX_QOE_FRAME_ACKNOWLEDGE_PDU* qoeFrameAcknowledge) +{ + proxyData* pdata = (proxyData*) context->custom; + RdpgfxClientContext* client = (RdpgfxClientContext*) pdata->pc->gfx; + WLog_DBG(TAG, __FUNCTION__); + return client->QoeFrameAcknowledge(client, qoeFrameAcknowledge); +} + +static UINT pf_rdpgfx_cache_import_offer(RdpgfxServerContext* context, + const RDPGFX_CACHE_IMPORT_OFFER_PDU* cacheImportOffer) +{ + proxyData* pdata = (proxyData*) context->custom; + RdpgfxClientContext* client = (RdpgfxClientContext*) pdata->pc->gfx; + WLog_DBG(TAG, __FUNCTION__); + return client->CacheImportOffer(client, cacheImportOffer); +} + void pf_rdpgfx_pipeline_init(RdpgfxClientContext* gfx, RdpgfxServerContext* server, proxyData* pdata) { @@ -310,10 +328,13 @@ void pf_rdpgfx_pipeline_init(RdpgfxClientContext* gfx, RdpgfxServerContext* serv gfx->MapSurfaceToWindow = pf_rdpgfx_map_surface_to_window; gfx->MapSurfaceToScaledOutput = pf_rdpgfx_map_surface_to_scaled_output; gfx->MapSurfaceToScaledWindow = pf_rdpgfx_map_surface_to_scaled_window; + gfx->OnOpen = pf_rdpgfx_on_open; gfx->OnClose = pf_rdpgfx_on_close; gfx->CapsConfirm = pf_rdpgfx_caps_confirm; /* Set server callbacks */ server->CapsAdvertise = pf_rdpgfx_caps_advertise; server->FrameAcknowledge = pf_rdpgfx_frame_acknowledge; + server->CacheImportOffer = pf_rdpgfx_cache_import_offer; + server->QoeFrameAcknowledge = pf_rdpgfx_qoe_frame_acknowledge; }