From 0e1cabbd82ba43304150037131b2613299a1a647 Mon Sep 17 00:00:00 2001 From: Iwan Timmer Date: Sat, 27 May 2017 16:41:52 +0200 Subject: [PATCH] Check display mode before streaming --- libgamestream/client.c | 15 ++++++++++++ libgamestream/client.h | 1 + libgamestream/errors.h | 1 + libgamestream/xml.c | 52 ++++++++++++++++++++++++++++++++++++++++++ libgamestream/xml.h | 8 +++++++ src/main.c | 2 ++ 6 files changed, 79 insertions(+) diff --git a/libgamestream/client.c b/libgamestream/client.c index 24ce1d4..79c12f3 100644 --- a/libgamestream/client.c +++ b/libgamestream/client.c @@ -232,6 +232,9 @@ static int load_server_status(PSERVER_DATA server) { if (xml_search(data->memory, data->size, "GfeVersion", (char**) &server->serverInfo.serverInfoGfeVersion) != GS_OK) goto cleanup; + if (xml_modelist(data->memory, data->size, &server->modes) != GS_OK) + goto cleanup; + // These fields are present on all version of GFE that this client supports if (!strlen(currentGameText) || !strlen(pairedText) || !strlen(server->serverInfo.serverInfoAppVersion) || !strlen(stateText)) goto cleanup; @@ -641,6 +644,18 @@ int gs_start_app(PSERVER_DATA server, STREAM_CONFIGURATION *config, int appId, b char* result = NULL; char uuid_str[37]; + PDISPLAY_MODE mode = server->modes; + bool correct_mode = false; + while (mode != NULL) { + if (mode->width == config->width && mode->height == config->height && mode->refresh == config->fps) + correct_mode = true; + + mode = mode->next; + } + + if (!correct_mode) + return GS_NOT_SUPPORTED_MODE; + if (config->height >= 2160 && !server->supports4K) return GS_NOT_SUPPORTED_4K; diff --git a/libgamestream/client.h b/libgamestream/client.h index d1b8f69..5591d70 100644 --- a/libgamestream/client.h +++ b/libgamestream/client.h @@ -36,6 +36,7 @@ typedef struct _SERVER_DATA { int currentGame; int serverMajorVersion; char* gsVersion; + PDISPLAY_MODE modes; SERVER_INFORMATION serverInfo; } SERVER_DATA, *PSERVER_DATA; diff --git a/libgamestream/errors.h b/libgamestream/errors.h index 99e3187..f657ae7 100644 --- a/libgamestream/errors.h +++ b/libgamestream/errors.h @@ -27,5 +27,6 @@ #define GS_IO_ERROR -5 #define GS_NOT_SUPPORTED_4K -6 #define GS_UNSUPPORTED_VERSION -7 +#define GS_NOT_SUPPORTED_MODE -8 const char* gs_error; diff --git a/libgamestream/xml.c b/libgamestream/xml.c index 9efa963..4e5e86e 100644 --- a/libgamestream/xml.c +++ b/libgamestream/xml.c @@ -79,6 +79,37 @@ static void XMLCALL _xml_end_applist_element(void *userData, const char *name) { } } +static void XMLCALL _xml_start_mode_element(void *userData, const char *name, const char **atts) { + struct xml_query *search = (struct xml_query*) userData; + if (strcmp("DisplayMode", name) == 0) { + PDISPLAY_MODE mode = calloc(1, sizeof(DISPLAY_MODE)); + if (mode != NULL) { + mode->next = (PDISPLAY_MODE) search->data; + search->data = mode; + } + } else if (search->data != NULL && (strcmp("Height", name) == 0 || strcmp("Width", name) == 0 || strcmp("RefreshRate", name) == 0)) { + search->memory = malloc(1); + search->size = 0; + search->start = 1; + } +} + +static void XMLCALL _xml_end_mode_element(void *userData, const char *name) { + struct xml_query *search = (struct xml_query*) userData; + if (search->data != NULL && search->start) { + PDISPLAY_MODE mode = (PDISPLAY_MODE) search->data; + if (strcmp("Width", name) == 0) + mode->width = atoi(search->memory); + else if (strcmp("Height", name) == 0) + mode->height = atoi(search->memory); + else if (strcmp("RefreshRate", name) == 0) + mode->refresh = atoi(search->memory); + + free(search->memory); + search->start = 0; + } +} + static void XMLCALL _xml_write_data(void *userData, const XML_Char *s, int len) { struct xml_query *search = (struct xml_query*) userData; if (search->start > 0) { @@ -141,3 +172,24 @@ int xml_applist(char* data, size_t len, PAPP_LIST *app_list) { return GS_OK; } + +int xml_modelist(char* data, size_t len, PDISPLAY_MODE *mode_list) { + struct xml_query query = {0}; + query.memory = calloc(1, 1); + XML_Parser parser = XML_ParserCreate("UTF-8"); + XML_SetUserData(parser, &query); + XML_SetElementHandler(parser, _xml_start_mode_element, _xml_end_mode_element); + XML_SetCharacterDataHandler(parser, _xml_write_data); + if (! XML_Parse(parser, data, len, 1)) { + int code = XML_GetErrorCode(parser); + gs_error = XML_ErrorString(code); + XML_ParserFree(parser); + return GS_INVALID; + } + + XML_ParserFree(parser); + *mode_list = (PDISPLAY_MODE) query.data; + + return GS_OK; + +} diff --git a/libgamestream/xml.h b/libgamestream/xml.h index 99f488c..aee4214 100644 --- a/libgamestream/xml.h +++ b/libgamestream/xml.h @@ -26,5 +26,13 @@ typedef struct _APP_LIST { struct _APP_LIST *next; } APP_LIST, *PAPP_LIST; +typedef struct _DISPLAY_MODE { + unsigned int height; + unsigned int width; + unsigned int refresh; + struct _DISPLAY_MODE *next; +} DISPLAY_MODE, *PDISPLAY_MODE; + int xml_search(char* data, size_t len, char* node, char** result); int xml_applist(char* data, size_t len, PAPP_LIST *app_list); +int xml_modelist(char* data, size_t len, PDISPLAY_MODE *mode_list); diff --git a/src/main.c b/src/main.c index 9c45aee..d07d678 100644 --- a/src/main.c +++ b/src/main.c @@ -88,6 +88,8 @@ static void stream(PSERVER_DATA server, PCONFIGURATION config, enum platform sys if (ret < 0) { if (ret == GS_NOT_SUPPORTED_4K) fprintf(stderr, "Server doesn't support 4K\n"); + else if (ret == GS_NOT_SUPPORTED_MODE) + fprintf(stderr, "Server doesn't support %dx%d (%d fps)\n", config->stream.width, config->stream.height, config->stream.fps); else fprintf(stderr, "Errorcode starting app: %d\n", ret); exit(-1);