diff --git a/client/include/interface/transport.h b/client/include/interface/transport.h index 445b4706..bcf0c6a2 100644 --- a/client/include/interface/transport.h +++ b/client/include/interface/transport.h @@ -201,11 +201,17 @@ typedef struct LG_TransportOps LG_TransportStatus (*nextFrame)(LG_Transport * transport, bool useDMA, LG_TransportFrame * frame); void (*releaseFrame)(LG_Transport * transport, LG_TransportFrame * frame); + /* Called by the frame consumer as it exits. A backend may release transient + * stream resources; nextFrame must reacquire them when the consumer restarts. */ + void (*stopFrame)(LG_Transport * transport); LG_TransportStatus (*nextPointer)(LG_Transport * transport, LG_TransportPointer * pointer); void (*releasePointer)(LG_Transport * transport, LG_TransportPointer * pointer); + /* Called by the pointer consumer as it exits. A backend may release transient + * stream resources; nextPointer must reacquire them when the consumer restarts. */ + void (*stopPointer)(LG_Transport * transport); LG_TransportStatus (*sendControl)(LG_Transport * transport, const LG_TransportControl * control, LG_TransportControlToken * token); diff --git a/client/src/main.c b/client/src/main.c index a7f0e86b..c8602f8c 100644 --- a/client/src/main.c +++ b/client/src/main.c @@ -569,6 +569,9 @@ int main_cursorThread(void * unused) g_state.transportOps->releasePointer(g_state.transport, &pointer); } + if (g_state.transportOps->stopPointer) + g_state.transportOps->stopPointer(g_state.transport); + return 0; } @@ -583,7 +586,11 @@ int main_frameThread(void * unused) lgWaitEvent(e_startup, TIMEOUT_INFINITE); if (app_getState() != APP_STATE_RUNNING) + { + if (g_state.transportOps->stopFrame) + g_state.transportOps->stopFrame(g_state.transport); return 0; + } while(app_getState() == APP_STATE_RUNNING && !g_state.stopVideo) { @@ -813,6 +820,9 @@ int main_frameThread(void * unused) app_useSpiceDisplay(false); } + if (g_state.transportOps->stopFrame) + g_state.transportOps->stopFrame(g_state.transport); + RENDERER(onRestart); if (app_getState() != APP_STATE_SHUTDOWN) diff --git a/client/transports/LGMP/lgmp.c b/client/transports/LGMP/lgmp.c index d6f68a61..1a6dc303 100644 --- a/client/transports/LGMP/lgmp.c +++ b/client/transports/LGMP/lgmp.c @@ -204,20 +204,47 @@ static bool lgmp_create(LG_Transport ** result) return true; } -static void lgmp_closeQueues(struct LG_Transport * this) +static void lgmp_stopFrame(struct LG_Transport * this) { if (this->framePending && this->frameQueue) { - lgmpClientMessageDone(this->frameQueue); - this->framePending = false; + const LGMP_STATUS status = lgmpClientMessageDone(this->frameQueue); + if (status != LGMP_OK) + DEBUG_WARN("Failed to release pending LGMP frame: %s", + lgmpStatusString(status)); + } + this->framePending = false; + LGMP_STATUS status = lgmpClientUnsubscribe(&this->frameQueue); + if (status != LGMP_OK) + { + DEBUG_WARN("Failed to unsubscribe from the LGMP frame queue: %s", + lgmpStatusString(status)); + this->frameQueue = NULL; } - lgmpClientUnsubscribe(&this->frameQueue); + this->frameSerial = 0; + this->formatValid = false; +} + +static void lgmp_stopPointer(struct LG_Transport * this) +{ LG_LOCK(this->pointerLock); - lgmpClientUnsubscribe(&this->pointerQueue); + const LGMP_STATUS status = lgmpClientUnsubscribe(&this->pointerQueue); + if (status != LGMP_OK) + { + DEBUG_WARN("Failed to unsubscribe from the LGMP pointer queue: %s", + lgmpStatusString(status)); + this->pointerQueue = NULL; + } LG_UNLOCK(this->pointerLock); } +static void lgmp_closeQueues(struct LG_Transport * this) +{ + lgmp_stopFrame(this); + lgmp_stopPointer(this); +} + static void lgmp_closeDMA(struct LG_Transport * this) { for (unsigned i = 0; i < LGMP_Q_FRAME_LEN; ++i) @@ -358,9 +385,7 @@ static void lgmp_disconnect(LG_Transport * this) { lgmp_closeQueues(this); lgmp_closeDMA(this); - this->connected = false; - this->frameSerial = 0; - this->formatValid = false; + this->connected = false; } static bool lgmp_sessionValid(LG_Transport * this) @@ -389,10 +414,13 @@ static LG_TransportStatus lgmp_subscribe(PLGMPClient client, uint32_t id, if (*queue) return LG_TRANSPORT_OK; - LGMP_STATUS status = lgmpClientSubscribe(client, id, queue); + PLGMPClientQueue subscribed = NULL; + LGMP_STATUS status = lgmpClientSubscribe(client, id, &subscribed); switch (status) { - case LGMP_OK: return LG_TRANSPORT_OK; + case LGMP_OK: + *queue = subscribed; + return LG_TRANSPORT_OK; case LGMP_ERR_NO_SUCH_QUEUE: return LG_TRANSPORT_TIMEOUT; case LGMP_ERR_INVALID_SESSION: return LG_TRANSPORT_DISCONNECTED; default: @@ -594,10 +622,16 @@ static LG_TransportStatus lgmp_nextPointer(LG_Transport * this, uint32_t pointerFlags = 0; size_t shapeSize = 0; size_t transformSize = 0; - LG_LOCK(this->pointerLock); - LG_TransportStatus status = lgmp_subscribe(this->client, LGMP_Q_POINTER, - &this->pointerQueue); - LG_UNLOCK(this->pointerLock); + LG_TransportStatus status = LG_TRANSPORT_OK; + if (!this->pointerQueue) + { + LG_LOCK(this->pointerLock); + status = lgmp_subscribe(this->client, LGMP_Q_POINTER, + &this->pointerQueue); + LG_UNLOCK(this->pointerLock); + if (status == LG_TRANSPORT_TIMEOUT) + usleep(1000); + } if (status == LG_TRANSPORT_OK) { LGMPMessage message; @@ -649,11 +683,7 @@ static LG_TransportStatus lgmp_nextPointer(LG_Transport * this, } } if (status != LG_TRANSPORT_OK) - { - if (status == LG_TRANSPORT_TIMEOUT) - usleep(1000); return status; - } const KVMFRCursor * cursor = (const KVMFRCursor *)this->pointerData; memset(result, 0, sizeof(*result)); @@ -771,8 +801,10 @@ const LG_TransportOps LGT_LGMP = .detachRenderer = lgmp_detachRenderer, .nextFrame = lgmp_nextFrame, .releaseFrame = lgmp_releaseFrame, + .stopFrame = lgmp_stopFrame, .nextPointer = lgmp_nextPointer, .releasePointer = lgmp_releasePointer, + .stopPointer = lgmp_stopPointer, .sendControl = lgmp_sendControl, .controlStatus = lgmp_controlStatus, };