From d57e119d70319c7a6ae80b9d0f18cdb74dd26833 Mon Sep 17 00:00:00 2001 From: Adrian Cochrane Date: Wed, 13 Jan 2021 20:57:35 +1300 Subject: [PATCH] Refactor to use GLib event-based input. So I can receive PocketSphinx's events via GStreamer! --- src/main.c | 277 ++++++++++++++++++++++++++++------------------------- 1 file changed, 148 insertions(+), 129 deletions(-) diff --git a/src/main.c b/src/main.c index b9c657d..26d4956 100644 --- a/src/main.c +++ b/src/main.c @@ -194,7 +194,8 @@ int levenshtein_distance(const char *a, const char* b) { } int MAX_DIST = 3; // Is this ideal? -char *select_link(char **links, char *command) { +char **links = NULL; +char *select_link(char *command) { // Pass 1, min distance int score = INT_MAX; for (int i = 0; strcmp(links[i], " ") != 0; i++) { @@ -210,7 +211,7 @@ char *select_link(char **links, char *command) { // Pass 3: Retrieve answer for (int i = 0; strcmp(links[i], " ") != 0; i += 3) { - if (command[0] != '\0') {// "" to read entire link table... + if (command[0] != '\0' || command[0] == '\n') {// "" to read entire link table... if (score < levenshtein_distance(command, links[i]) && score < levenshtein_distance(command, links[i+1]) && score < levenshtein_distance(command, links[i+2])) continue; @@ -229,103 +230,150 @@ char *select_link(char **links, char *command) { struct termios stored_settings, no_echo; int read_keyboard = 0; -int speak_finalize(char *ssml, char **links, char **out_link) { - while (read_keyboard) { - if (out_link != NULL && *out_link != NULL) return 0; - - if (getc(stdin) == '\033') { - char mark[200]; - char fallback[200]; - espeak_Cancel(); - char c = getc(stdin); - if (c == 0 || c == -1 || c == '\033' || c == 'q') goto close; // skip [ - switch (getc(stdin)) { - case 'A': - // 🠕 - if (in_table) { - tablerow--; - if (tablerow > 0) { - sprintf(mark, "-rhaps-tablecell%i:%ix%i", tableno, tablerow, tablecol); - speak(ssml, mark, NULL); - break; - } else in_table = 0; - } - section_no--; - sprintf(mark, "-rhaps-section%i", section_no); - speak(ssml, section_no > 0 ? mark : NULL, NULL); - break; - case 'B': - // 🠗 - if (in_table) { - tablerow++; + +void read_page(char *uri, int read_input); +gboolean read_stdin(GIOChannel *source, GIOCondition condition, gpointer data) { + char *ssml = data; + + if (getc(stdin) == '\033') { + char mark[200]; + char fallback[200]; + espeak_Cancel(); + char c = getc(stdin); + if (c == 0 || c == -1 || c == '\033' || c == 'q') return 1; // skip [ + switch (getc(stdin)) { + case 'A': + // 🠕 + if (in_table) { + tablerow--; + if (tablerow > 0) { sprintf(mark, "-rhaps-tablecell%i:%ix%i", tableno, tablerow, tablecol); - sprintf(fallback, "-rhaps-section%i", section_no+1); - speak(ssml, mark, fallback); - break; // FIXME What if that mark doesn't exist? - } - section_no++; - sprintf(mark, "-rhaps-section%i", section_no); - speak(ssml, section_no > 0 ? mark : NULL, NULL); - break; - case 'C': - // ➔ - if (in_table) { - tablecol++; + speak(ssml, mark, NULL); + break; + } else in_table = 0; + } + section_no--; + sprintf(mark, "-rhaps-section%i", section_no); + speak(ssml, section_no > 0 ? mark : NULL, NULL); + break; + case 'B': + // 🠗 + if (in_table) { + tablerow++; + sprintf(mark, "-rhaps-tablecell%i:%ix%i", tableno, tablerow, tablecol); + sprintf(fallback, "-rhaps-section%i", section_no+1); + speak(ssml, mark, fallback); + break; // FIXME What if that mark doesn't exist? + } + section_no++; + sprintf(mark, "-rhaps-section%i", section_no); + speak(ssml, section_no > 0 ? mark : NULL, NULL); + break; + case 'C': + // ➔ + if (in_table) { + tablecol++; + sprintf(mark, "-rhaps-tablecell%i:%ix%i", tableno, tablerow, tablecol); + sprintf(fallback, "-rhaps-paragraph%i", paragraph_no+1); + speak(ssml, mark, fallback); + break; // FIXME What if that mark doesn't exist? + } + paragraph_no++; + sprintf(mark, "-rhaps-paragraph%i", paragraph_no); + speak(ssml, paragraph_no > 0 ? mark : NULL, NULL); + break; + case 'D': + // 🠔 + if (in_table) { + tablecol--; + if (tablecol > 0) { sprintf(mark, "-rhaps-tablecell%i:%ix%i", tableno, tablerow, tablecol); - sprintf(fallback, "-rhaps-paragraph%i", paragraph_no+1); - speak(ssml, mark, fallback); - break; // FIXME What if that mark doesn't exist? - } - paragraph_no++; - sprintf(mark, "-rhaps-paragraph%i", paragraph_no); - speak(ssml, paragraph_no > 0 ? mark : NULL, NULL); - break; - case 'D': - // 🠔 - if (in_table) { - tablecol--; - if (tablecol > 0) { - sprintf(mark, "-rhaps-tablecell%i:%ix%i", tableno, tablerow, tablecol); - speak(ssml, mark, NULL); - break; - } else in_table = 0; - } - paragraph_no--; - sprintf(mark, "-rhaps-paragraph%i", paragraph_no); - speak(ssml, paragraph_no > 0 ? mark : NULL, NULL); - break; + speak(ssml, mark, NULL); + break; + } else in_table = 0; } - } else { - // Read in a line - tcsetattr(0, TCSANOW, &stored_settings); - char *line = NULL; - size_t len = 0; - if (getline(&line, &len, stdin) < 0) - fprintf(stderr, "Failed to read stdin line!\n"); - else if (*line == '\n') { - espeak_Cancel(); - return 0; - } else if (out_link != NULL) - *out_link = select_link(links, line); - tcsetattr(0, TCSANOW, &no_echo); + paragraph_no--; + sprintf(mark, "-rhaps-paragraph%i", paragraph_no); + speak(ssml, paragraph_no > 0 ? mark : NULL, NULL); + break; + } + } else { + // Read in a line, with full terminal emulator i18n. + tcsetattr(0, TCSANOW, &stored_settings); + char *line = NULL; + size_t len = 0; + if (getline(&line, &len, stdin) < 0) { + fprintf(stderr, "Failed to read stdin line!\n"); + return TRUE; } + tcsetattr(0, TCSANOW, &no_echo); + read_page(select_link(line), 1); + return FALSE; } - espeak_ng_STATUS result = espeak_ng_Synchronize(); - if (result != ENS_OK) { - espeak_ng_PrintStatusCodeMessage(result, stderr, context); - return 4; + return TRUE; +} + +int speak_finalize(char *ssml) { + while (read_keyboard) { + if (!read_stdin(NULL, 0, ssml)) return 0; } close: - if (path_wav != NULL) sf_close(fd_wav); - espeak_ng_Terminate(); return 0; } /* Main driver */ -void write_links(FILE *dest, char **links) { +int speak_err = 0; +struct session *session = NULL; +struct page *referer = NULL; + +int use_espeak = 0; +char *logpath = NULL; +char *mimes = "text/html text/xml application/xml application/xhtml+xml text/plain"; +FILE *fd_ssml = NULL; +FILE *fd_links = NULL; + +void write_links() { for (int i = 0; strcmp(links[i], " ") != 0; i++) { - fprintf(dest, "%s%c", links[i], (i % 3) == 2 ? '\n' : '\t'); + fprintf(fd_links, "%s%c", links[i], (i % 3) == 2 ? '\n' : '\t'); + } +} + +void read_page(char *uri, int read_input) { + for (int i = 0; strcmp(links[i], " ") != 0; i++) free(links[i]); + free(links); + + if (use_espeak && speak_err == 0) speak_text(uri, espeakRATE, 10); + #ifdef WITH_SPEECHD + else if (spd_conn != NULL) spd_say(spd_conn, SPD_MESSAGE, uri); + #endif + else printf("%s\n", uri); + + struct page *page = c_fetchURL(session, mimes, referer, uri); + referer = page; + char *ssml = c_renderDoc(session, page, use_espeak); + links = c_extractLinks(page); + + if (logpath != NULL) c_writeLog(logpath, session); + + if (fd_ssml != NULL) fprintf(fd_ssml, "%s\n", ssml); + if (read_keyboard && strcmp(uri, "about:welcome")) select_link(""); + if (fd_links != NULL) write_links(fd_links, links); + if (use_espeak & speak_err == 0) speak(ssml, "main", NULL); + #ifdef WITH_SPEECHD + if (spd_conn != NULL) spd_say(spd_conn, SPD_MESSAGE, ssml); + #endif + + c_freePage(page); + free(uri); + + if (read_input) { + g_io_add_watch(g_io_channel_unix_new(0), G_IO_IN|G_IO_HUP, read_stdin, ssml); + // if (use_espeak & speak_err == 0) speak_err = speak_finalize(ssml); + } else { + free(ssml); + for (int i = 0; strcmp(links[i], " ") != 0; i++) free(links[i]); + free(links); } } @@ -340,16 +388,10 @@ FILE *parse_opt_file() { } int main(int argc, char **argv) { - int speak_err = 0; hs_init(&argc, &argv); gst_init(&argc, &argv); GMainLoop *loop = g_main_loop_new(NULL, FALSE); - char *mimes = "text/html text/xml application/xml application/xhtml+xml text/plain"; - char *logpath = NULL; - FILE *fd_ssml = NULL; - FILE *fd_links = NULL; - int use_espeak = 0; tcgetattr(0, &stored_settings); #ifdef WITH_SPEECHD SPDConnection *spd_conn = NULL; @@ -462,53 +504,30 @@ int main(int argc, char **argv) { if (dist != 3) return 11; #endif - struct session *session = c_newSession(); - struct page *referer = c_initialReferer(); + session = c_newSession(); + if (logpath != NULL) session = c_enableLogging(session); + referer = c_initialReferer(); if (use_espeak) speak_err = speak_initialize(); - char *ssml, **links, *uri; if (optind >= argc) { // No URLs specified, restore previous session or goto about:welcome - uri = c_lastVisited("about:welcome"); - goto read_uri; - } - for (int i = optind; i < argc; i++) { - uri = argv[i]; - -read_uri: - if (use_espeak && speak_err == 0) speak_text(uri, espeakRATE, 10); - #ifdef WITH_SPEECHD - else if (spd_conn != NULL) spd_say(spd_conn, SPD_MESSAGE, uri); - #endif - else printf("%s\n", argv[i]); - - if (logpath != NULL) session = c_enableLogging(session); + read_page(c_lastVisited("about:welcome"), 1); + } else for (int i = optind; i < argc; i++) read_page(argv[i], i+1 == argc); - struct page *page = c_fetchURL(session, mimes, referer, uri); - ssml = c_renderDoc(session, page, use_espeak); - links = c_extractLinks(page); - - if (logpath != NULL) c_writeLog(logpath, session); - - if (fd_ssml != NULL) fprintf(fd_ssml, "%s\n", ssml); - if (read_keyboard && strcmp(uri, "about:welcome")) select_link(links, ""); - if (fd_links != NULL) write_links(fd_links, links); - if (use_espeak & speak_err == 0) speak(ssml, "main", NULL); - #ifdef WITH_SPEECHD - if (spd_conn != NULL) spd_say(spd_conn, SPD_MESSAGE, ssml); - #endif - - c_freePage(page); - } - - uri = NULL; - if (use_espeak & speak_err == 0) speak_err = speak_finalize(ssml, links, &uri); - if (uri != NULL) goto read_uri; + g_main_loop_run(loop); #ifdef WITH_SPEECHD if (spd_conn != NULL) spd_close(spd_conn); #endif + espeak_ng_STATUS result = espeak_ng_Synchronize(); + if (result != ENS_OK) { + espeak_ng_PrintStatusCodeMessage(result, stderr, context); + return 4; + } + if (path_wav != NULL) sf_close(fd_wav); + espeak_ng_Terminate(); + c_freePage(referer); c_freeSession(session); hs_exit(); -- 2.30.2