From 98ff89d0a69efd73c95ca4178edbe8dbd54e9fa0 Mon Sep 17 00:00:00 2001 From: skbeh <60107333+skbeh@users.noreply.github.com> Date: Wed, 5 Oct 2022 23:01:52 +0800 Subject: [PATCH] fix gtk warning and battery level not shown 1. Not reset gtk widgets when gtk main loop has stopped. 2. Wait until battery level info is received (currently always 1s), because level info is actually sent later so mostly `recv` returns before the client sends. --- src/av.c | 69 +++++++++++++++++++++++++++++++++--------------- src/connection.c | 16 +++++------ src/connection.h | 15 ++++++----- src/droidcam.c | 13 ++++----- 4 files changed, 71 insertions(+), 42 deletions(-) diff --git a/src/av.c b/src/av.c index 991e594..103d954 100644 --- a/src/av.c +++ b/src/av.c @@ -12,6 +12,8 @@ #include "decoder.h" #include #include +#include +#include extern int a_active; extern int v_active; @@ -39,56 +41,81 @@ SOCKET GetConnection(void) { // Battry Check thread void *BatteryThreadProc(__attribute__((__unused__)) void *args) { SOCKET socket = INVALID_SOCKET; - char buf[128] = {0}; - char battery_value[32] = {0}; - int i, j; + char buf[96]; + char battery_value[5]; + struct timeval tv = {0}; + tv.tv_sec = 1; dbgprint("Battery Thread Start\n"); while (v_running || a_running) { - if (!v_active && !a_active) { + if (!v_active && !a_active) { usleep(50000); continue; } + uint8_t battery_value_pos = 0; + size_t percent_len = 0; + socket = GetConnection(); if (socket == INVALID_SOCKET) { goto LOOP; } - if (Send(BATTERY_REQ, CSTR_LEN(BATTERY_REQ), socket) <= 0) { - errprint("error sending battery status request: (%d) '%s'\n", - errno, strerror(errno)); + if (setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, (const char *)&tv, + sizeof(tv)) == -1) { + goto LOOP; + }; + + if (!Send(BATTERY_REQ, CSTR_LEN(BATTERY_REQ), socket)) { + errprint("error sending battery status request: (%d) '%s'\n", errno, + strerror(errno)); goto LOOP; } memset(buf, 0, sizeof(buf)); + memset(battery_value, 0, sizeof(battery_value)); if (RecvAll(buf, sizeof(buf), socket) <= 0) { goto LOOP; } - for (i = 0; i < (sizeof(buf)-4); i++) { - if (buf[i] == '\r' && buf[i+1] == '\n' && buf[i+2] == '\r' && buf[i+3] == '\n') { - i += 4; + for (uint8_t i = 0; i < (sizeof(buf) - 4); i += 4) { + char *tmp = memchr(&buf[i], '\r', sizeof(buf)); + if (!tmp) { + goto LOOP; + } + if (memcmp(tmp + 1, "\n\r\n", 3) == 0) { + battery_value_pos = (tmp - buf) + 4; break; } } + if (!battery_value_pos || battery_value_pos > (sizeof(buf) - (4 + 1)) || + buf[battery_value_pos] == '0') { + goto LOOP; + } - j = 0; - while (i < sizeof(buf) && j < (sizeof(battery_value)-2) && buf[i] >= '0' && buf[i] <= '9') - battery_value[j++] = buf[i++]; + for (uint8_t j = 0; j < 3; j++) { + if (buf[battery_value_pos + j] >= '0' && + buf[battery_value_pos + j] <= '9') { + battery_value[j] = buf[battery_value_pos + j]; + percent_len++; + } else { + break; + } + } - if (j == 0) - battery_value[j++] = '-'; + if (percent_len == 0) { + battery_value[0] = '-'; + percent_len = 1; + } - battery_value[j++] = '%'; - battery_value[j++] = 0; + battery_value[percent_len] = '%'; dbgprint("battery_value: %s\n", battery_value); UpdateBatteryLabel(battery_value); LOOP: disconnect(socket); - for (j = 0; j < 30000 && (v_running || a_running); j++) + for (uint16_t i = 0; i < 30000 && (v_running || a_running); i++) usleep(1000); } @@ -126,8 +153,7 @@ void *VideoThreadProc(void *args) { } len = snprintf(buf, sizeof(buf), VIDEO_REQ, decoder_get_video_width(), decoder_get_video_height()); - if (Send(buf, len, videoSocket) <= 0){ - errprint("send error (%d) '%s'\n", errno, strerror(errno)); + if (!Send(buf, len, videoSocket)){ MSG_ERROR("Error sending request, DroidCam might be busy with another client."); goto early_out; } @@ -246,9 +272,8 @@ void *AudioThreadProc(void *arg) { return 0; } - if (Send(AUDIO_REQ, CSTR_LEN(AUDIO_REQ), socket) <= 0) { + if (!Send(AUDIO_REQ, CSTR_LEN(AUDIO_REQ), socket)) { errprint("send error (audio) (%d) '%s'\n", errno, strerror(errno)); - MSG_ERROR("Error sending audio request"); goto early_out; } diff --git a/src/connection.c b/src/connection.c index a320c34..2d898e4 100644 --- a/src/connection.c +++ b/src/connection.c @@ -86,41 +86,41 @@ SOCKET Connect(const char* ip, int port, const char **errormsg) { return sock; } -int Send(const char * buffer, int bytes, SOCKET s) { +bool Send(const char * buffer, int bytes, SOCKET s) { ssize_t w = 0; char *ptr = (char*) buffer; while (bytes > 0) { w = send(s, ptr, bytes, 0); if (w <= 0) { - return -1; + return false; } bytes -= w; ptr += w; } - return 1; + return true; } -int Recv(const char* buffer, int bytes, SOCKET s) { +ssize_t Recv(const char* buffer, int bytes, SOCKET s) { return recv(s, (char*)buffer, bytes, 0); } -int RecvAll(const char* buffer, int bytes, SOCKET s) { +ssize_t RecvAll(const char* buffer, int bytes, SOCKET s) { return recv(s, (char*)buffer, bytes, MSG_WAITALL); } -int RecvNonBlock(char * buffer, int bytes, SOCKET s) { +ssize_t RecvNonBlock(char * buffer, int bytes, SOCKET s) { int res = recv(s, buffer, bytes, MSG_DONTWAIT); return (res < 0 && (errno == EAGAIN || errno == EWOULDBLOCK)) ? 0 : res; } -int RecvNonBlockUDP(char * buffer, int bytes, SOCKET s) { +ssize_t RecvNonBlockUDP(char * buffer, int bytes, SOCKET s) { struct sockaddr_in from; socklen_t fromLen = sizeof(from); int res = recvfrom(s, buffer, bytes, MSG_DONTWAIT, (struct sockaddr *)&from, &fromLen); return (res < 0 && (errno == EAGAIN || errno == EWOULDBLOCK)) ? 0 : res; } -int SendUDPMessage(SOCKET s, const char *message, int length, char *ip, int port) { +ssize_t SendUDPMessage(SOCKET s, const char *message, int length, char *ip, int port) { struct sockaddr_in sin; sin.sin_port = htons((uint16_t)port); sin.sin_family = AF_INET; diff --git a/src/connection.h b/src/connection.h index 37a2668..f00afb8 100644 --- a/src/connection.h +++ b/src/connection.h @@ -9,6 +9,9 @@ #ifndef __CONN_H__ #define __CONN_H__ +#include +#include + #define INVALID_SOCKET -1 typedef int SOCKET; typedef long int SOCKET_PTR; @@ -19,11 +22,11 @@ void disconnect(SOCKET s); SOCKET accept_connection(int port); SOCKET CreateUdpSocket(void); -int Send(const char * buffer, int bytes, SOCKET s); -int Recv(const char * buffer, int bytes, SOCKET s); -int RecvAll(const char * buffer, int bytes, SOCKET s); -int RecvNonBlock(char * buffer, int bytes, SOCKET s); -int RecvNonBlockUDP(char * buffer, int bytes, SOCKET s); -int SendUDPMessage(SOCKET s, const char *message, int length, char *ip, int port); +bool Send(const char * buffer, int bytes, SOCKET s); +ssize_t Recv(const char * buffer, int bytes, SOCKET s); +ssize_t RecvAll(const char * buffer, int bytes, SOCKET s); +ssize_t RecvNonBlock(char * buffer, int bytes, SOCKET s); +ssize_t RecvNonBlockUDP(char * buffer, int bytes, SOCKET s); +ssize_t SendUDPMessage(SOCKET s, const char *message, int length, char *ip, int port); #endif diff --git a/src/droidcam.c b/src/droidcam.c index 086234b..6dba68a 100644 --- a/src/droidcam.c +++ b/src/droidcam.c @@ -106,7 +106,7 @@ void UpdateBatteryLabel(char *battery_value) { gtk_label_set_text(GTK_LABEL(batteryText), battery_value); } -static void Stop(void) { +static void stop_av(void) { a_running = false; v_running = false; dbgprint("join\n"); @@ -126,9 +126,9 @@ static void Stop(void) { g_thread_join(hBatteryThread); hBatteryThread = NULL; } +} - a_active = false; - v_active = false; +static void reset_ui(void) { gtk_widget_set_sensitive(GTK_WIDGET(elButton), FALSE); gtk_widget_set_sensitive(GTK_WIDGET(wbButton), FALSE); gtk_widget_set_sensitive(GTK_WIDGET(menuButton), FALSE); @@ -260,7 +260,8 @@ static void the_callback(GtkWidget* widget, gpointer extra) switch (cb) { case CB_BUTTON: if (v_running || a_running) { - Stop(); + reset_ui(); + stop_av(); cb = (int)g_settings.connection; goto _up; } @@ -669,7 +670,7 @@ int main(int argc, char *argv[]) g_signal_connect(window, "delete-event", G_CALLBACK(delete_window_callback), window); gtk_widget_show_all(window); - Stop(); // reset the UI + reset_ui(); LoadSettings(&g_settings); if (argc >= 1) { parse_args(argc, argv); @@ -716,7 +717,7 @@ int main(int argc, char *argv[]) // main loop gtk_main(); - Stop(); + stop_av(); decoder_fini(); connection_cleanup(); SaveSettings(&g_settings);