[host] shutdown capture if there are no subscribers

Fixes #33
This commit is contained in:
Geoffrey McRae 2020-08-11 18:30:47 +10:00
parent ca02e1aba9
commit c7330167cf
2 changed files with 84 additions and 48 deletions

View File

@ -62,6 +62,14 @@ static const struct LGMPQueueConfig POINTER_QUEUE_CONFIG =
#define MAX_POINTER_SIZE (sizeof(KVMFRCursor) + (128 * 128 * 4)) #define MAX_POINTER_SIZE (sizeof(KVMFRCursor) + (128 * 128 * 4))
enum AppState
{
APP_STATE_RUNNING,
APP_STATE_IDLE,
APP_STATE_RESTART,
APP_STATE_SHUTDOWN
};
struct app struct app
{ {
PLGMPHost lgmp; PLGMPHost lgmp;
@ -81,8 +89,7 @@ struct app
CaptureInterface * iface; CaptureInterface * iface;
bool running; enum AppState state;
bool reinit;
LGTimer * lgmpTimer; LGTimer * lgmpTimer;
LGThread * frameThread; LGThread * frameThread;
}; };
@ -95,7 +102,7 @@ static bool lgmpTimer(void * opaque)
if ((status = lgmpHostProcess(app.lgmp)) != LGMP_OK) if ((status = lgmpHostProcess(app.lgmp)) != LGMP_OK)
{ {
DEBUG_ERROR("lgmpHostProcess Failed: %s", lgmpStatusString(status)); DEBUG_ERROR("lgmpHostProcess Failed: %s", lgmpStatusString(status));
app.running = false; app.state = APP_STATE_SHUTDOWN;
return false; return false;
} }
@ -111,7 +118,7 @@ static int frameThread(void * opaque)
CaptureFrame frame = { 0 }; CaptureFrame frame = { 0 };
const long pageSize = sysinfo_getPageSize(); const long pageSize = sysinfo_getPageSize();
while(app.running) while(app.state == APP_STATE_RUNNING)
{ {
//wait until there is room in the queue //wait until there is room in the queue
if(lgmpHostQueuePending(app.frameQueue) == LGMP_Q_FRAME_LEN) if(lgmpHostQueuePending(app.frameQueue) == LGMP_Q_FRAME_LEN)
@ -128,7 +135,7 @@ static int frameThread(void * opaque)
case CAPTURE_RESULT_REINIT: case CAPTURE_RESULT_REINIT:
{ {
app.reinit = true; app.state = APP_STATE_RESTART;
DEBUG_INFO("Frame thread reinit"); DEBUG_INFO("Frame thread reinit");
return 0; return 0;
} }
@ -205,7 +212,7 @@ static int frameThread(void * opaque)
bool startThreads() bool startThreads()
{ {
app.running = true; app.state = APP_STATE_RUNNING;
if (!lgCreateThread("FrameThread", frameThread, NULL, &app.frameThread)) if (!lgCreateThread("FrameThread", frameThread, NULL, &app.frameThread))
{ {
DEBUG_ERROR("Failed to create the frame thread"); DEBUG_ERROR("Failed to create the frame thread");
@ -219,8 +226,9 @@ bool stopThreads()
{ {
bool ok = true; bool ok = true;
app.running = false;
app.iface->stop(); app.iface->stop();
if (app.state != APP_STATE_SHUTDOWN)
app.state = APP_STATE_IDLE;
if (app.frameThread && !lgJoinThread(app.frameThread, NULL)) if (app.frameThread && !lgJoinThread(app.frameThread, NULL))
{ {
@ -234,7 +242,14 @@ bool stopThreads()
static bool captureStart() static bool captureStart()
{ {
DEBUG_INFO("Using : %s", app.iface->getName()); if (app.state == APP_STATE_IDLE)
{
if (!app.iface->init())
{
DEBUG_ERROR("Initialize the capture device");
return false;
}
}
const unsigned int maxFrameSize = app.iface->getMaxFrameSize(); const unsigned int maxFrameSize = app.iface->getMaxFrameSize();
if (maxFrameSize > app.maxFrameSize) if (maxFrameSize > app.maxFrameSize)
@ -248,31 +263,33 @@ static bool captureStart()
return startThreads(); return startThreads();
} }
static bool captureRestart() static bool captureStop()
{ {
DEBUG_INFO("==== [ Capture Restart ] ===="); DEBUG_INFO("==== [ Capture Stop ] ====");
if (!stopThreads()) if (!stopThreads())
return false; return false;
if (!app.iface->deinit() || !app.iface->init()) if (!app.iface->deinit())
{ {
DEBUG_ERROR("Failed to reinitialize the capture device"); DEBUG_ERROR("Failed to deinitialize the capture device");
return false; return false;
} }
if (!captureStart())
return false;
return true; return true;
} }
static bool captureRestart()
{
return captureStop() && captureStart();
}
bool captureGetPointerBuffer(void ** data, uint32_t * size) bool captureGetPointerBuffer(void ** data, uint32_t * size)
{ {
// spin until there is room // spin until there is room
while(lgmpHostQueuePending(app.pointerQueue) == LGMP_Q_POINTER_LEN) while(lgmpHostQueuePending(app.pointerQueue) == LGMP_Q_POINTER_LEN)
{ {
usleep(1); usleep(1);
if (!app.running) if (app.state == APP_STATE_RUNNING)
return false; return false;
} }
@ -522,6 +539,9 @@ int app_main(int argc, char * argv[])
goto fail; goto fail;
} }
DEBUG_INFO("Using : %s", iface->getName());
app.state = APP_STATE_RUNNING;
app.iface = iface; app.iface = iface;
LG_LOCK_INIT(app.pointerLock); LG_LOCK_INIT(app.pointerLock);
@ -532,50 +552,66 @@ int app_main(int argc, char * argv[])
goto fail; goto fail;
} }
if (!captureStart()) while(app.state != APP_STATE_SHUTDOWN)
{ {
exitcode = -1; if(lgmpHostQueueHasSubs(app.pointerQueue) ||
goto exit; lgmpHostQueueHasSubs(app.frameQueue))
}
while(app.running)
{
if (app.reinit && !captureRestart())
{ {
exitcode = -1; if (!captureStart())
goto exit; {
exitcode = -1;
goto exit;
}
} }
app.reinit = false; else
if (lgmpHostQueueNewSubs(app.pointerQueue) > 0)
{ {
LG_LOCK(app.pointerLock); usleep(100);
sendPointer(true); continue;
LG_UNLOCK(app.pointerLock);
} }
switch(iface->capture()) while(app.state != APP_STATE_SHUTDOWN && (
lgmpHostQueueHasSubs(app.pointerQueue) ||
lgmpHostQueueHasSubs(app.frameQueue)))
{ {
case CAPTURE_RESULT_OK: if (app.state == APP_STATE_RESTART)
break; {
case CAPTURE_RESULT_TIMEOUT:
continue;
case CAPTURE_RESULT_REINIT:
if (!captureRestart()) if (!captureRestart())
{ {
exitcode = -1; exitcode = -1;
goto exit; goto exit;
} }
app.reinit = false; app.state = APP_STATE_RUNNING;
continue; }
case CAPTURE_RESULT_ERROR: if (lgmpHostQueueNewSubs(app.pointerQueue) > 0)
DEBUG_ERROR("Capture interface reported a fatal error"); {
exitcode = -1; LG_LOCK(app.pointerLock);
goto finish; sendPointer(true);
LG_UNLOCK(app.pointerLock);
}
switch(iface->capture())
{
case CAPTURE_RESULT_OK:
break;
case CAPTURE_RESULT_TIMEOUT:
continue;
case CAPTURE_RESULT_REINIT:
app.state = APP_STATE_RESTART;
continue;
case CAPTURE_RESULT_ERROR:
DEBUG_ERROR("Capture interface reported a fatal error");
exitcode = -1;
goto finish;
}
} }
if (app.state != APP_STATE_SHUTDOWN)
DEBUG_INFO("No subscribers, going to sleep...");
captureStop();
} }
finish: finish:
@ -602,5 +638,5 @@ fail:
void app_quit() void app_quit()
{ {
app.running = false; app.state = APP_STATE_SHUTDOWN;
} }

@ -1 +1 @@
Subproject commit 7d3b8a1d8b8a24f3812fb250b6e853f2c37ec483 Subproject commit 2a1477550cc122dcac8af7016ac5f15dec2e139a