mirror of
https://github.com/gnif/LookingGlass.git
synced 2024-11-22 05:27:20 +00:00
[host] windows: handle graceful shutdown on user switch
This commit is contained in:
parent
6a72633674
commit
545e736389
@ -37,7 +37,7 @@
|
|||||||
int app_main(int argc, char * argv[]);
|
int app_main(int argc, char * argv[]);
|
||||||
bool app_init(void);
|
bool app_init(void);
|
||||||
void app_shutdown(void);
|
void app_shutdown(void);
|
||||||
void app_quit(void);
|
void app_quit(int exitcode);
|
||||||
|
|
||||||
// these must be implemented for each OS
|
// these must be implemented for each OS
|
||||||
const char * os_getExecutable(void);
|
const char * os_getExecutable(void);
|
||||||
|
@ -62,7 +62,7 @@ int main(int argc, char * argv[])
|
|||||||
void sigHandler(int signo)
|
void sigHandler(int signo)
|
||||||
{
|
{
|
||||||
DEBUG_INFO("SIGINT");
|
DEBUG_INFO("SIGINT");
|
||||||
app_quit();
|
app_quit(LG_HOST_EXIT_USER);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool app_init(void)
|
bool app_init(void)
|
||||||
|
@ -246,7 +246,7 @@ LRESULT CALLBACK DummyWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
|||||||
NULL
|
NULL
|
||||||
);
|
);
|
||||||
|
|
||||||
if (clicked == ID_MENU_EXIT ) app_quit();
|
if (clicked == ID_MENU_EXIT ) app_quit(LG_HOST_EXIT_USER);
|
||||||
else if (clicked == ID_MENU_SHOW_LOG)
|
else if (clicked == ID_MENU_SHOW_LOG)
|
||||||
{
|
{
|
||||||
const char * logFile = option_get_string("os", "logFile");
|
const char * logFile = option_get_string("os", "logFile");
|
||||||
@ -259,6 +259,14 @@ LRESULT CALLBACK DummyWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case WM_WTSSESSION_CHANGE:
|
||||||
|
if (wParam == WTS_CONSOLE_DISCONNECT)
|
||||||
|
{
|
||||||
|
DEBUG_INFO("Console disconnected, shutting down");
|
||||||
|
app_quit(LG_HOST_EXIT_CAPTURE);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
if (msg == app.trayRestartMsg)
|
if (msg == app.trayRestartMsg)
|
||||||
RegisterTrayIcon();
|
RegisterTrayIcon();
|
||||||
@ -440,6 +448,9 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
|
|||||||
AppendMenu(app.trayMenu, MF_SEPARATOR, 0 , NULL );
|
AppendMenu(app.trayMenu, MF_SEPARATOR, 0 , NULL );
|
||||||
AppendMenu(app.trayMenu, MF_STRING , ID_MENU_EXIT , "Exit" );
|
AppendMenu(app.trayMenu, MF_STRING , ID_MENU_EXIT , "Exit" );
|
||||||
|
|
||||||
|
if (!WTSRegisterSessionNotification(app.messageWnd, NOTIFY_FOR_THIS_SESSION))
|
||||||
|
DEBUG_WINERROR("WTSRegisterSessionNotification failed", GetLastError());
|
||||||
|
|
||||||
// create the application thread
|
// create the application thread
|
||||||
LGThread * thread;
|
LGThread * thread;
|
||||||
if (!lgCreateThread("appThread", appThread, NULL, &thread))
|
if (!lgCreateThread("appThread", appThread, NULL, &thread))
|
||||||
@ -470,6 +481,8 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
|
|||||||
}
|
}
|
||||||
|
|
||||||
shutdown:
|
shutdown:
|
||||||
|
WTSUnRegisterSessionNotification(app.messageWnd);
|
||||||
|
|
||||||
DestroyMenu(app.trayMenu);
|
DestroyMenu(app.trayMenu);
|
||||||
app_shutdown();
|
app_shutdown();
|
||||||
UnregisterWait(app.exitWait);
|
UnregisterWait(app.exitWait);
|
||||||
|
327
host/src/app.c
327
host/src/app.c
@ -68,8 +68,8 @@ enum AppState
|
|||||||
{
|
{
|
||||||
APP_STATE_RUNNING,
|
APP_STATE_RUNNING,
|
||||||
APP_STATE_IDLE,
|
APP_STATE_IDLE,
|
||||||
APP_STATE_RESTART,
|
APP_STATE_TRANSITION_TO_IDLE,
|
||||||
APP_STATE_REINIT,
|
APP_STATE_REINIT_LGMP,
|
||||||
APP_STATE_SHUTDOWN
|
APP_STATE_SHUTDOWN
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -103,10 +103,12 @@ struct app
|
|||||||
uint32_t frameSerial;
|
uint32_t frameSerial;
|
||||||
|
|
||||||
CaptureInterface * iface;
|
CaptureInterface * iface;
|
||||||
|
bool captureStarted;
|
||||||
|
|
||||||
enum AppState state;
|
enum AppState state, lastState;
|
||||||
LGTimer * lgmpTimer;
|
LGTimer * lgmpTimer;
|
||||||
LGThread * frameThread;
|
LGThread * frameThread;
|
||||||
|
bool threadsStarted;
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct app app;
|
static struct app app;
|
||||||
@ -156,6 +158,14 @@ static struct Option options[] =
|
|||||||
{0}
|
{0}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
inline static void setAppState(enum AppState state)
|
||||||
|
{
|
||||||
|
if (app.state == APP_STATE_SHUTDOWN)
|
||||||
|
return;
|
||||||
|
app.lastState = app.state;
|
||||||
|
app.state = state;
|
||||||
|
}
|
||||||
|
|
||||||
static bool lgmpTimer(void * opaque)
|
static bool lgmpTimer(void * opaque)
|
||||||
{
|
{
|
||||||
LGMP_STATUS status;
|
LGMP_STATUS status;
|
||||||
@ -166,12 +176,12 @@ static bool lgmpTimer(void * opaque)
|
|||||||
{
|
{
|
||||||
DEBUG_ERROR("LGMP reported the shared memory has been corrrupted, "
|
DEBUG_ERROR("LGMP reported the shared memory has been corrrupted, "
|
||||||
"attempting to recover");
|
"attempting to recover");
|
||||||
app.state = APP_STATE_REINIT;
|
setAppState(APP_STATE_REINIT_LGMP);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
DEBUG_ERROR("lgmpHostProcess Failed: %s", lgmpStatusString(status));
|
DEBUG_ERROR("lgmpHostProcess Failed: %s", lgmpStatusString(status));
|
||||||
app.state = APP_STATE_SHUTDOWN;
|
setAppState(APP_STATE_SHUTDOWN);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -196,7 +206,7 @@ static bool lgmpTimer(void * opaque)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool sendFrame(CaptureResult result)
|
static bool sendFrame(CaptureResult result, bool * restart)
|
||||||
{
|
{
|
||||||
CaptureFrame frame = { 0 };
|
CaptureFrame frame = { 0 };
|
||||||
bool repeatFrame = false;
|
bool repeatFrame = false;
|
||||||
@ -225,13 +235,14 @@ static bool sendFrame(CaptureResult result)
|
|||||||
|
|
||||||
case CAPTURE_RESULT_REINIT:
|
case CAPTURE_RESULT_REINIT:
|
||||||
{
|
{
|
||||||
app.state = APP_STATE_RESTART;
|
*restart = true;
|
||||||
DEBUG_INFO("Frame thread reinit");
|
DEBUG_INFO("Frame thread reinit");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
case CAPTURE_RESULT_ERROR:
|
case CAPTURE_RESULT_ERROR:
|
||||||
{
|
{
|
||||||
|
*restart = false;
|
||||||
DEBUG_ERROR("Failed to get the frame");
|
DEBUG_ERROR("Failed to get the frame");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -363,39 +374,43 @@ static int frameThread(void * opaque)
|
|||||||
|
|
||||||
while(app.state == APP_STATE_RUNNING)
|
while(app.state == APP_STATE_RUNNING)
|
||||||
{
|
{
|
||||||
if (!sendFrame(CAPTURE_RESULT_OK))
|
bool restart = false;
|
||||||
|
if (!sendFrame(CAPTURE_RESULT_OK, &restart))
|
||||||
|
{
|
||||||
|
if (restart)
|
||||||
|
setAppState(APP_STATE_TRANSITION_TO_IDLE);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
DEBUG_INFO("Frame thread stopped");
|
DEBUG_INFO("Frame thread stopped");
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool startThreads(void)
|
bool startThreads(void)
|
||||||
{
|
{
|
||||||
app.state = APP_STATE_RUNNING;
|
if (app.threadsStarted)
|
||||||
if (!app.iface->asyncCapture)
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (!lgCreateThread("FrameThread", frameThread, NULL, &app.frameThread))
|
if (app.iface->asyncCapture)
|
||||||
{
|
if (!lgCreateThread("FrameThread", frameThread, NULL, &app.frameThread))
|
||||||
DEBUG_ERROR("Failed to create the frame thread");
|
{
|
||||||
return false;
|
DEBUG_ERROR("Failed to create the frame thread");
|
||||||
}
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
app.threadsStarted = true;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool stopThreads(void)
|
bool stopThreads(void)
|
||||||
{
|
{
|
||||||
app.iface->stop();
|
if (!app.threadsStarted)
|
||||||
if (app.state != APP_STATE_SHUTDOWN &&
|
|
||||||
app.state != APP_STATE_REINIT)
|
|
||||||
app.state = APP_STATE_IDLE;
|
|
||||||
|
|
||||||
if (!app.iface->asyncCapture)
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (app.frameThread)
|
app.iface->stop();
|
||||||
|
|
||||||
|
if (app.iface->asyncCapture && app.frameThread)
|
||||||
{
|
{
|
||||||
if (!lgJoinThread(app.frameThread, NULL))
|
if (!lgJoinThread(app.frameThread, NULL))
|
||||||
{
|
{
|
||||||
@ -406,32 +421,37 @@ bool stopThreads(void)
|
|||||||
app.frameThread = NULL;
|
app.frameThread = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
app.threadsStarted = false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool captureStart(void)
|
static bool captureStart(void)
|
||||||
{
|
{
|
||||||
if (app.state == APP_STATE_IDLE)
|
if (app.captureStarted)
|
||||||
{
|
return true;
|
||||||
if (!app.iface->init(app.ivshmemBase, &app.alignSize))
|
|
||||||
{
|
|
||||||
DEBUG_ERROR("Failed to initialize the capture device");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (app.iface->start && !app.iface->start())
|
if (!app.iface->init(app.ivshmemBase, &app.alignSize))
|
||||||
{
|
{
|
||||||
DEBUG_ERROR("Failed to start the capture device");
|
DEBUG_ERROR("Failed to initialize the capture device");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (app.iface->start && !app.iface->start())
|
||||||
|
{
|
||||||
|
DEBUG_ERROR("Failed to start the capture device");
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
DEBUG_INFO("==== [ Capture Start ] ====");
|
DEBUG_INFO("==== [ Capture Start ] ====");
|
||||||
|
app.captureStarted = true;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool captureStop(void)
|
static bool captureStop(void)
|
||||||
{
|
{
|
||||||
|
if (!app.captureStarted)
|
||||||
|
return true;
|
||||||
|
|
||||||
DEBUG_INFO("==== [ Capture Stop ] ====");
|
DEBUG_INFO("==== [ Capture Stop ] ====");
|
||||||
|
|
||||||
if (!app.iface->deinit())
|
if (!app.iface->deinit())
|
||||||
@ -441,6 +461,7 @@ static bool captureStop(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
app.frameValid = false;
|
app.frameValid = false;
|
||||||
|
app.captureStarted = false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -790,7 +811,8 @@ int app_main(int argc, char * argv[])
|
|||||||
// make sure rng is actually seeded for LGMP
|
// make sure rng is actually seeded for LGMP
|
||||||
srand((unsigned)time(NULL));
|
srand((unsigned)time(NULL));
|
||||||
|
|
||||||
app.state = APP_STATE_RUNNING;
|
app.lastState = APP_STATE_RUNNING;
|
||||||
|
app.state = APP_STATE_RUNNING;
|
||||||
ivshmemOptionsInit();
|
ivshmemOptionsInit();
|
||||||
|
|
||||||
// register capture interface options
|
// register capture interface options
|
||||||
@ -887,7 +909,8 @@ int app_main(int argc, char * argv[])
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (iface->init(app.ivshmemBase, &app.alignSize))
|
app.iface = iface;
|
||||||
|
if (captureStart())
|
||||||
break;
|
break;
|
||||||
|
|
||||||
iface->free();
|
iface->free();
|
||||||
@ -896,6 +919,8 @@ int app_main(int argc, char * argv[])
|
|||||||
|
|
||||||
if (!iface)
|
if (!iface)
|
||||||
{
|
{
|
||||||
|
app.iface = NULL;
|
||||||
|
|
||||||
if (*ifaceName)
|
if (*ifaceName)
|
||||||
DEBUG_ERROR("Specified capture interface not supported");
|
DEBUG_ERROR("Specified capture interface not supported");
|
||||||
else
|
else
|
||||||
@ -907,8 +932,6 @@ int app_main(int argc, char * argv[])
|
|||||||
DEBUG_INFO("Using : %s", iface->getName());
|
DEBUG_INFO("Using : %s", iface->getName());
|
||||||
DEBUG_INFO("Capture Method : %s", iface->asyncCapture ?
|
DEBUG_INFO("Capture Method : %s", iface->asyncCapture ?
|
||||||
"Asynchronous" : "Synchronous");
|
"Asynchronous" : "Synchronous");
|
||||||
|
|
||||||
app.iface = iface;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!lgmpSetup(&shmDev))
|
if (!lgmpSetup(&shmDev))
|
||||||
@ -919,141 +942,129 @@ int app_main(int argc, char * argv[])
|
|||||||
|
|
||||||
LG_LOCK_INIT(app.pointerLock);
|
LG_LOCK_INIT(app.pointerLock);
|
||||||
|
|
||||||
if (app.iface->start && !app.iface->start())
|
do
|
||||||
{
|
{
|
||||||
DEBUG_ERROR("Failed to start the capture interface");
|
switch(app.state)
|
||||||
exitcode = LG_HOST_EXIT_FATAL;
|
|
||||||
goto fail_lgmp;
|
|
||||||
}
|
|
||||||
|
|
||||||
while(app.state != APP_STATE_SHUTDOWN)
|
|
||||||
{
|
|
||||||
if (app.state == APP_STATE_REINIT)
|
|
||||||
{
|
{
|
||||||
DEBUG_INFO("Performing LGMP reinitialization");
|
case APP_STATE_REINIT_LGMP:
|
||||||
lgmpShutdown();
|
DEBUG_INFO("Performing LGMP reinitialization");
|
||||||
app.state = APP_STATE_RUNNING;
|
lgmpShutdown();
|
||||||
if (!lgmpSetup(&shmDev))
|
setAppState(app.lastState);
|
||||||
goto fail_lgmp;
|
if (!lgmpSetup(&shmDev))
|
||||||
}
|
goto fail_lgmp;
|
||||||
|
|
||||||
if (app.state == APP_STATE_IDLE)
|
|
||||||
{
|
|
||||||
if(lgmpHostQueueHasSubs(app.pointerQueue) ||
|
|
||||||
lgmpHostQueueHasSubs(app.frameQueue))
|
|
||||||
{
|
|
||||||
if (!captureStart())
|
|
||||||
{
|
|
||||||
exitcode = LG_HOST_EXIT_FAILED;
|
|
||||||
goto fail_capture;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!startThreads())
|
|
||||||
{
|
|
||||||
exitcode = LG_HOST_EXIT_FAILED;
|
|
||||||
goto fail_threads;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
usleep(100000);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
while(likely(app.state != APP_STATE_SHUTDOWN && (
|
|
||||||
lgmpHostQueueHasSubs(app.pointerQueue) ||
|
|
||||||
lgmpHostQueueHasSubs(app.frameQueue))))
|
|
||||||
{
|
|
||||||
if (unlikely(
|
|
||||||
app.state == APP_STATE_RESTART ||
|
|
||||||
app.state == APP_STATE_REINIT))
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (unlikely(lgmpHostQueueNewSubs(app.pointerQueue) > 0))
|
case APP_STATE_IDLE:
|
||||||
{
|
// if there are no clients subscribed, just remain idle
|
||||||
LG_LOCK(app.pointerLock);
|
if (!lgmpHostQueueHasSubs(app.pointerQueue) &&
|
||||||
sendPointer(true);
|
!lgmpHostQueueHasSubs(app.frameQueue))
|
||||||
LG_UNLOCK(app.pointerLock);
|
|
||||||
}
|
|
||||||
|
|
||||||
const uint64_t delta = microtime() - previousFrameTime;
|
|
||||||
if (delta < throttleUs)
|
|
||||||
{
|
|
||||||
const uint64_t us = throttleUs - delta;
|
|
||||||
// only delay if the time is reasonable
|
|
||||||
if (us > 1000)
|
|
||||||
nsleep(us * 1000);
|
|
||||||
}
|
|
||||||
|
|
||||||
const uint64_t captureStart = microtime();
|
|
||||||
|
|
||||||
const CaptureResult result = app.iface->capture(
|
|
||||||
app.captureIndex, app.frameBuffer[app.captureIndex]);
|
|
||||||
|
|
||||||
if (likely(result == CAPTURE_RESULT_OK))
|
|
||||||
previousFrameTime = captureStart;
|
|
||||||
else if (likely(result == CAPTURE_RESULT_TIMEOUT))
|
|
||||||
{
|
|
||||||
if (!app.iface->asyncCapture)
|
|
||||||
if (unlikely(app.frameValid &&
|
|
||||||
lgmpHostQueueNewSubs(app.frameQueue) > 0))
|
|
||||||
{
|
|
||||||
LGMP_STATUS status;
|
|
||||||
if ((status = lgmpHostQueuePost(app.frameQueue, 0,
|
|
||||||
app.frameMemory[app.readIndex])) != LGMP_OK)
|
|
||||||
DEBUG_ERROR("%s", lgmpStatusString(status));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
switch(result)
|
|
||||||
{
|
{
|
||||||
case CAPTURE_RESULT_REINIT:
|
usleep(100000);
|
||||||
app.state = APP_STATE_RESTART;
|
continue;
|
||||||
continue;
|
|
||||||
|
|
||||||
case CAPTURE_RESULT_ERROR:
|
|
||||||
DEBUG_ERROR("Capture interface reported a fatal error");
|
|
||||||
exitcode = LG_HOST_EXIT_FAILED;
|
|
||||||
goto fail_capture;
|
|
||||||
|
|
||||||
default:
|
|
||||||
DEBUG_ASSERT("Invalid capture result");
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (!app.iface->asyncCapture)
|
// clients subscribed, start the capture
|
||||||
sendFrame(result);
|
if (!captureStart() || !startThreads())
|
||||||
}
|
{
|
||||||
|
exitcode = LG_HOST_EXIT_FAILED;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
setAppState(APP_STATE_RUNNING);
|
||||||
|
break;
|
||||||
|
|
||||||
if (app.state != APP_STATE_SHUTDOWN)
|
case APP_STATE_TRANSITION_TO_IDLE:
|
||||||
{
|
if (!stopThreads() || !captureStop())
|
||||||
if (!stopThreads())
|
{
|
||||||
|
exitcode = LG_HOST_EXIT_FAILED;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
setAppState(APP_STATE_IDLE);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case APP_STATE_RUNNING:
|
||||||
{
|
{
|
||||||
exitcode = LG_HOST_EXIT_FAILED;
|
// if there are no clients subscribed, go idle
|
||||||
goto fail_threads;
|
if (!lgmpHostQueueHasSubs(app.pointerQueue) &&
|
||||||
|
!lgmpHostQueueHasSubs(app.frameQueue))
|
||||||
|
{
|
||||||
|
setAppState(APP_STATE_TRANSITION_TO_IDLE);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if there is a brand new client, send them the pointer
|
||||||
|
if (unlikely(lgmpHostQueueNewSubs(app.pointerQueue) > 0))
|
||||||
|
{
|
||||||
|
LG_LOCK(app.pointerLock);
|
||||||
|
sendPointer(true);
|
||||||
|
LG_UNLOCK(app.pointerLock);
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint64_t delta = microtime() - previousFrameTime;
|
||||||
|
if (delta < throttleUs)
|
||||||
|
{
|
||||||
|
const uint64_t us = throttleUs - delta;
|
||||||
|
// only delay if the time is reasonable
|
||||||
|
if (us > 1000)
|
||||||
|
nsleep(us * 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint64_t captureStartTime = microtime();
|
||||||
|
|
||||||
|
const CaptureResult result = app.iface->capture(
|
||||||
|
app.captureIndex, app.frameBuffer[app.captureIndex]);
|
||||||
|
|
||||||
|
if (likely(result == CAPTURE_RESULT_OK))
|
||||||
|
previousFrameTime = captureStartTime;
|
||||||
|
else if (likely(result == CAPTURE_RESULT_TIMEOUT))
|
||||||
|
{
|
||||||
|
if (!app.iface->asyncCapture)
|
||||||
|
if (unlikely(app.frameValid &&
|
||||||
|
lgmpHostQueueNewSubs(app.frameQueue) > 0))
|
||||||
|
{
|
||||||
|
LGMP_STATUS status;
|
||||||
|
if ((status = lgmpHostQueuePost(app.frameQueue, 0,
|
||||||
|
app.frameMemory[app.readIndex])) != LGMP_OK)
|
||||||
|
DEBUG_ERROR("%s", lgmpStatusString(status));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
switch(result)
|
||||||
|
{
|
||||||
|
case CAPTURE_RESULT_REINIT:
|
||||||
|
setAppState(APP_STATE_TRANSITION_TO_IDLE);
|
||||||
|
continue;
|
||||||
|
|
||||||
|
case CAPTURE_RESULT_ERROR:
|
||||||
|
DEBUG_ERROR("Capture interface reported a fatal error");
|
||||||
|
exitcode = LG_HOST_EXIT_FAILED;
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
default:
|
||||||
|
DEBUG_ASSERT("Invalid capture result");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!app.iface->asyncCapture)
|
||||||
|
{
|
||||||
|
bool restart = false;
|
||||||
|
if (!sendFrame(result, &restart) && restart)
|
||||||
|
setAppState(APP_STATE_TRANSITION_TO_IDLE);
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!captureStop())
|
case APP_STATE_SHUTDOWN:
|
||||||
{
|
break;
|
||||||
exitcode = LG_HOST_EXIT_FAILED;
|
|
||||||
goto fail_capture;
|
|
||||||
}
|
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
while(app.state != APP_STATE_SHUTDOWN);
|
||||||
|
|
||||||
exitcode = app.exitcode;
|
exitcode = app.exitcode;
|
||||||
|
|
||||||
|
fail:
|
||||||
stopThreads();
|
stopThreads();
|
||||||
|
|
||||||
fail_threads:
|
|
||||||
captureStop();
|
captureStop();
|
||||||
|
|
||||||
fail_capture:
|
|
||||||
app.iface->free();
|
app.iface->free();
|
||||||
LG_LOCK_FREE(app.pointerLock);
|
LG_LOCK_FREE(app.pointerLock);
|
||||||
|
|
||||||
@ -1072,7 +1083,7 @@ void app_shutdown(void)
|
|||||||
app.state = APP_STATE_SHUTDOWN;
|
app.state = APP_STATE_SHUTDOWN;
|
||||||
}
|
}
|
||||||
|
|
||||||
void app_quit(void)
|
void app_quit(int exitcode)
|
||||||
{
|
{
|
||||||
if (app.state == APP_STATE_SHUTDOWN)
|
if (app.state == APP_STATE_SHUTDOWN)
|
||||||
{
|
{
|
||||||
@ -1080,6 +1091,6 @@ void app_quit(void)
|
|||||||
exit(LG_HOST_EXIT_USER);
|
exit(LG_HOST_EXIT_USER);
|
||||||
}
|
}
|
||||||
|
|
||||||
app.exitcode = LG_HOST_EXIT_USER;
|
app.exitcode = exitcode;
|
||||||
app_shutdown();
|
app_shutdown();
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user