From 2cba019cdfc24b49be57ee53e136d5fb7bf2af10 Mon Sep 17 00:00:00 2001 From: Scott Murray Date: Wed, 26 Jun 2019 17:34:48 -0400 Subject: navigation: Update patches for pipewire and running as non-root Changes include: * Replace the patch to add 4A support with a simpler one to just use ALSA via a gst-launch pipeline. gstreamer is used to provide the flexibility to easily switch to a pipewire output sink and likely add back setting a role via a property. * Add a patch to set the new audio and display permissions for running as non-root. Bug-AGL: SPEC-2557, SPEC-2571 Change-Id: Iae442b58c8d8feca51cc23c1378b264a4038bda7 Signed-off-by: Scott Murray --- .../navigation/0001-add-4A-playback-support.patch | 361 --------------------- .../navigation/0001-switch-to-alsa-output.patch | 35 ++ .../navigation/0003-update-permissions.patch | 22 ++ recipes-demo-hmi/navigation/navigation_git.bb | 5 +- 4 files changed, 60 insertions(+), 363 deletions(-) delete mode 100644 recipes-demo-hmi/navigation/navigation/0001-add-4A-playback-support.patch create mode 100644 recipes-demo-hmi/navigation/navigation/0001-switch-to-alsa-output.patch create mode 100644 recipes-demo-hmi/navigation/navigation/0003-update-permissions.patch mode change 100755 => 100644 recipes-demo-hmi/navigation/navigation_git.bb diff --git a/recipes-demo-hmi/navigation/navigation/0001-add-4A-playback-support.patch b/recipes-demo-hmi/navigation/navigation/0001-add-4A-playback-support.patch deleted file mode 100644 index b4192358..00000000 --- a/recipes-demo-hmi/navigation/navigation/0001-add-4A-playback-support.patch +++ /dev/null @@ -1,361 +0,0 @@ -gpsnavi: Add AGL 4A playback support - -To properly support 4A on AGL, pull in the binding, add some code -to open / close the "navigation" role, and use a simple gstreamer -pipeline to play the generated files. The existing script templates -have had their playback commands removed, but are retained for -driving the voice file generation. - -Signed-off-by: Scott Murray - -diff --git a/agl/config.xml b/agl/config.xml -index 9d4c0ca..960f652 100755 ---- a/agl/config.xml -+++ b/agl/config.xml -@@ -7,11 +7,13 @@ - AISIN AW - - -+ - - - - - -+ - - GPL - -diff --git a/configure.ac b/configure.ac -index 33348c3..6b7b391 100755 ---- a/configure.ac -+++ b/configure.ac -@@ -26,11 +26,13 @@ PKG_CHECK_MODULES([GLIB], [glib-2.0 gthread-2.0]) - PKG_CHECK_MODULES([FREETYPE2], [freetype2]) - PKG_CHECK_MODULES([WAYLAND], [wayland-client wayland-egl egl]) - PKG_CHECK_MODULES([GL], [glesv2]) -+PKG_CHECK_MODULES([GSTREAMER], [gstreamer-1.0]) - PKG_CHECK_MODULES([ZLIB], [zlib]) - PKG_CHECK_MODULES([SQLITE3], [sqlite3]) - PKG_CHECK_MODULES([EXPAT], [expat]) - PKG_CHECK_MODULES([OPENSSL], [openssl]) - PKG_CHECK_MODULES([DBUSCXX], [dbus-c++-1]) -+PKG_CHECK_MODULES([LIBAFBWSC], [libafbwsc]) - PKG_CHECK_MODULES([WINDOWMANAGER], [libwindowmanager]) - PKG_CHECK_MODULES([HOMESCREEN], [libhomescreen]) - -diff --git a/flite_agl.in b/flite_agl.in -index 28b512c..d11b043 100644 ---- a/flite_agl.in -+++ b/flite_agl.in -@@ -1,6 +1,3 @@ - #!/bin/sh - TMP=/tmp/navi.wav - echo "$1" | flite_hts_engine -m @datadir@/Voice/us/cmu_us_arctic_slt.htsvoice -o $TMP --paplay --property='media.role=Navi' $TMP --rm -f $TMP -- -diff --git a/jtalk_agl.in b/jtalk_agl.in -index 76900f4..857c824 100644 ---- a/jtalk_agl.in -+++ b/jtalk_agl.in -@@ -1,6 +1,3 @@ - #!/bin/sh - TMP=/tmp/navi.wav - echo "$1" | open_jtalk -ow $TMP -m @exec_prefix@/share/Voice/mei/mei_normal.htsvoice -x @exec_prefix@/share/dic/ --paplay --property='media.role=Navi' $TMP --rm -f $TMP -- -diff --git a/src/Makefile.am b/src/Makefile.am -index affb9a5..6d0fa55 100755 ---- a/src/Makefile.am -+++ b/src/Makefile.am -@@ -26,6 +26,7 @@ sms/sms-core/SMCoreDM/RG/RG_GuideNear.c \ - sms/sms-core/SMCoreDM/RG/RG_ShareData.c \ - sms/sms-core/SMCoreDM/RG/RG_GuideVoiceBuild_en.c \ - sms/sms-core/SMCoreDM/RG/RG_GuideVoice.c \ -+sms/sms-core/SMCoreDM/RG/RG_GuideVoice4A.cpp \ - sms/sms-core/SMCoreDM/RG/RG_GuideApi.c \ - sms/sms-core/SMCoreDM/SCRTThread.c \ - sms/sms-core/SMCoreDAL/SMDALAreaCls.c \ -@@ -537,6 +538,8 @@ libnavicore_la_CFLAGS = -fPIC \ - @FREETYPE2_CFLAGS@ \ - @WAYLAND_CFLAGS@ \ - @GL_CFLAGS@ \ -+ @GSTREAMER_CFLAGS@ \ -+ @LIBAFBWSC_CFLAGS@ \ - @ZLIB_CFLAGS@ \ - @SQLITE3_CFLAGS@ \ - @EXPAT_CFLAGS@ \ -@@ -547,6 +550,8 @@ libnavicore_la_CXXFLAGS = -fPIC \ - @FREETYPE2_CFLAGS@ \ - @WAYLAND_CFLAGS@ \ - @GL_CFLAGS@ \ -+ @GSTREAMER_CFLAGS@ \ -+ @LIBAFBWSC_CFLAGS@ \ - @ZLIB_CFLAGS@ \ - @SQLITE3_CFLAGS@ \ - @EXPAT_CFLAGS@ \ -@@ -555,6 +560,8 @@ libnavicore_la_CXXFLAGS = -fPIC \ - libnavicore_la_LIBADD = \ - @OPENSSL_LIBS@ \ - @GL_LIBS@ \ -+ @GSTREAMER_LIBS@ \ -+ @LIBAFBWSC_LIBS@ \ - @ZLIB_LIBS@ \ - @SQLITE3_LIBS@ \ - @EXPAT_LIBS@ -diff --git a/src/sms/sms-core/SMCoreDM/RG/RG_GuideVoice.c b/src/sms/sms-core/SMCoreDM/RG/RG_GuideVoice.c -index 3828d5c..36e6775 100755 ---- a/src/sms/sms-core/SMCoreDM/RG/RG_GuideVoice.c -+++ b/src/sms/sms-core/SMCoreDM/RG/RG_GuideVoice.c -@@ -16,6 +16,8 @@ - - #include "sms-core/SMCoreDM/SMCoreDMInternal.h" - -+extern int play_voice(const char* voice_gen_cmd); -+ - typedef struct _tts_text_tbl - { - INT32 code; -@@ -205,9 +207,9 @@ E_SC_RESULT RG_CTL_CreateVoiceText(RT_NAME_t *in, INT32 language) - } - else - { -- strncat(tts_voice, "\" & ", (TTSMAX - len - 1)); -+ strncat(tts_voice, "\"", (TTSMAX - len - 1)); - -- system(tts_voice); -+ play_voice(tts_voice); - } - - return (e_SC_RESULT_SUCCESS); -diff --git a/src/sms/sms-core/SMCoreDM/RG/RG_GuideVoice4A.cpp b/src/sms/sms-core/SMCoreDM/RG/RG_GuideVoice4A.cpp -new file mode 100644 -index 0000000..6b59c0e ---- /dev/null -+++ b/src/sms/sms-core/SMCoreDM/RG/RG_GuideVoice4A.cpp -@@ -0,0 +1,223 @@ -+/* -+ * Copyright (C) 2018 Konsulko Group -+ * Author: Scott Murray -+ * -+ * This program is licensed under GPL version 2 license. -+ * See the LICENSE file distributed with this source file. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+extern "C" -+{ -+#include -+#include -+#include -+} -+ -+#define NAVI_TMPFILE "/tmp/navi.wav" -+ -+static struct afb_wsj1* ws; -+static struct afb_wsj1_itf itf; -+sd_event* loop; -+ -+// port and token from src/glview/glview_wayland.cpp -+extern long g_port; -+extern std::string g_token; -+ -+static int set_role_state(bool state); -+ -+void play_voice_file(const char *output) -+{ -+ if(!output) -+ return; -+ -+ // Initialize GStreamer -+ gst_init(NULL, NULL); -+ -+ std::string pipeline_str = "filesrc location="; -+ pipeline_str += NAVI_TMPFILE; -+ pipeline_str += " ! wavparse ! audioconvert ! audioresample ! alsasink device="; -+ pipeline_str += output; -+ GstElement *pipeline = gst_parse_launch(pipeline_str.c_str(), NULL); -+ if(!pipeline) { -+ std::cerr << "gstreamer pipeline construction failed!" << std::endl; -+ return; -+ } -+ -+ // Start pipeline -+ gst_element_set_state(pipeline, GST_STATE_PLAYING); -+ std::cerr << "Playing guidance" << std::endl; -+ -+ // Wait until error or EOS -+ GstBus *bus = gst_element_get_bus(pipeline); -+ GstMessage *msg = gst_bus_timed_pop_filtered(bus, -+ GST_CLOCK_TIME_NONE, -+ (GstMessageType) (GST_MESSAGE_ERROR | GST_MESSAGE_EOS)); -+ -+ // Free resources -+ if(msg != NULL) -+ gst_message_unref(msg); -+ gst_object_unref(bus); -+ gst_element_set_state(pipeline, GST_STATE_NULL); -+ gst_object_unref(pipeline); -+ -+ // Remove temporary file -+ unlink(NAVI_TMPFILE); -+ -+ return; -+} -+ -+static void on_hangup(void *closure, struct afb_wsj1 *wsj) -+{ -+} -+ -+static void on_call(void *closure, const char *api, const char *verb, struct afb_wsj1_msg *msg) -+{ -+} -+ -+static void on_event(void* closure, const char* event, struct afb_wsj1_msg *msg) -+{ -+} -+ -+static void on_reply(void *closure, struct afb_wsj1_msg *msg) -+{ -+ bool state = (bool) closure; -+ -+ if(!state) { -+ // Role is closed, return -+ return; -+ } -+ -+ // We opened the role, play the file -+ struct json_object* reply = afb_wsj1_msg_object_j(msg); -+ if(reply) { -+ struct json_object* response; -+ int rc = json_object_object_get_ex(reply, "response", &response); -+ if(rc) { -+ struct json_object* val; -+ rc = json_object_object_get_ex(response, "device_uri", &val); -+ if (rc && json_object_get_string_len(val)) { -+ const char* jres_pcm = json_object_get_string(val); -+ play_voice_file(jres_pcm); -+ } -+ } -+ } -+ -+ // Give up role now that we're done -+ set_role_state(false); -+} -+ -+static void *event_loop_run(void *args) -+{ -+ struct sd_event* loop = (struct sd_event*)(args); -+ -+ for(;;) -+ sd_event_run(loop, 30000000); -+} -+ -+static int start_event_loop(void) -+{ -+ if(ws && loop) { -+ pthread_t thread_id; -+ if(pthread_create(&thread_id, NULL, event_loop_run, loop) != 0) { -+ return -1; -+ } else { -+ return thread_id; -+ } -+ } else { -+ return -1; -+ } -+} -+ -+static int init_ws(int port, std::string &token) -+{ -+ loop = NULL; -+ std::string uri; -+ -+ if(sd_event_default(&loop) < 0) { -+ std::cerr << __FUNCTION__ << ": Failed to create event loop" << std::endl; -+ goto error; -+ } -+ -+ // Initialize interface for websocket -+ itf.on_hangup = on_hangup; -+ itf.on_call = on_call; -+ itf.on_event = on_event; -+ -+ uri = "ws://localhost:" + std::to_string(port) + "/api?token=" + token; -+ std::cerr << "Using URI: " << uri << std::endl; -+ ws = afb_ws_client_connect_wsj1(loop, uri.c_str(), &itf, NULL); -+ if(ws == NULL) { -+ std::cerr << __FUNCTION__ << ": Failed to create websocket connection" << std::endl; -+ goto error; -+ } -+ start_event_loop(); -+ return 0; -+error: -+ if(loop) { -+ sd_event_unref(loop); -+ } -+ return -1; -+} -+ -+static int set_role_state(bool state) -+{ -+ int rc; -+ json_object *jsonData = json_object_new_object(); -+ -+ json_object_object_add(jsonData, "action", json_object_new_string(state ? "open" : "close")); -+ rc = afb_wsj1_call_j(ws, "ahl-4a", "navigation", jsonData, on_reply, (void*) state); -+ if (rc < 0) { -+ std::cerr << __FUNCTION__ << ": Failed to call ahl-4a/navigation!" << std::endl; -+ } -+ return rc; -+} -+ -+pthread_mutex_t ws_mutex = PTHREAD_MUTEX_INITIALIZER; -+ -+static void *play_voice_handler(void *data) -+{ -+ int rc; -+ char *voice_gen_cmd = (char*) data; -+ if(!voice_gen_cmd) -+ return NULL; -+ -+ pthread_mutex_lock(&ws_mutex); -+ if(!ws) { -+ rc = init_ws(g_port, g_token); -+ pthread_mutex_unlock(&ws_mutex); -+ if(rc < 0) -+ return NULL; -+ } -+ pthread_mutex_unlock(&ws_mutex); -+ -+ // Generate guidance voice file -+ rc = system(voice_gen_cmd); -+ free(voice_gen_cmd); -+ -+ // Try to get role and play file -+ set_role_state(true); -+ -+ return NULL; -+} -+ -+extern "C" int play_voice(const char* voice_gen_cmd) -+{ -+ pthread_t handler_thread; -+ char *tmp; -+ -+ if(!voice_gen_cmd) -+ return -1; -+ -+ tmp = strdup(voice_gen_cmd); -+ return pthread_create(&handler_thread, NULL, play_voice_handler, (void*) tmp); -+} diff --git a/recipes-demo-hmi/navigation/navigation/0001-switch-to-alsa-output.patch b/recipes-demo-hmi/navigation/navigation/0001-switch-to-alsa-output.patch new file mode 100644 index 00000000..4ce9a430 --- /dev/null +++ b/recipes-demo-hmi/navigation/navigation/0001-switch-to-alsa-output.patch @@ -0,0 +1,35 @@ +gpsnavi: Switch to ALSA output + +Update the talk scripts to use ALSA output via gst-launch-1.0 instead +of PulseAudio's paplay. gstreamer is used since it is likely that a +further revision will change to a pipewire output sink and add back +setting a role property. + +Upstream-Status: Inappropriate [no upstream] + +Signed-off-by: Scott Murray + +diff --git a/flite_agl.in b/flite_agl.in +index 28b512c..67a09e5 100644 +--- a/flite_agl.in ++++ b/flite_agl.in +@@ -1,6 +1,6 @@ + #!/bin/sh + TMP=/tmp/navi.wav + echo "$1" | flite_hts_engine -m @datadir@/Voice/us/cmu_us_arctic_slt.htsvoice -o $TMP +-paplay --property='media.role=Navi' $TMP ++gst-launch-1.0 filesrc location=$TMP ! decodebin ! audioconvert ! audioresample ! alsasink + rm -f $TMP + +diff --git a/jtalk_agl.in b/jtalk_agl.in +index 76900f4..73c87e5 100644 +--- a/jtalk_agl.in ++++ b/jtalk_agl.in +@@ -1,6 +1,6 @@ + #!/bin/sh + TMP=/tmp/navi.wav + echo "$1" | open_jtalk -ow $TMP -m @exec_prefix@/share/Voice/mei/mei_normal.htsvoice -x @exec_prefix@/share/dic/ +-paplay --property='media.role=Navi' $TMP ++gst-launch-1.0 filesrc location=$TMP ! decodebin ! audioconvert ! audioresample ! alsasink + rm -f $TMP + diff --git a/recipes-demo-hmi/navigation/navigation/0003-update-permissions.patch b/recipes-demo-hmi/navigation/navigation/0003-update-permissions.patch new file mode 100644 index 00000000..1f1ee491 --- /dev/null +++ b/recipes-demo-hmi/navigation/navigation/0003-update-permissions.patch @@ -0,0 +1,22 @@ +gpsnavi: Update permissions + +Add the new display and audio permissions required with the change to +running as non-root. + +Upstream-Status: Inappropriate [no upstream] + +Signed-off-by: Scott Murray + +diff --git a/agl/config.xml b/agl/config.xml +index 9d4c0ca..44de94a 100755 +--- a/agl/config.xml ++++ b/agl/config.xml +@@ -8,6 +8,8 @@ + + + ++ ++ + + + diff --git a/recipes-demo-hmi/navigation/navigation_git.bb b/recipes-demo-hmi/navigation/navigation_git.bb old mode 100755 new mode 100644 index 80ef24ea..0a5f7579 --- a/recipes-demo-hmi/navigation/navigation_git.bb +++ b/recipes-demo-hmi/navigation/navigation_git.bb @@ -13,14 +13,15 @@ DEPENDS = " \ " RDEPENDS_${PN} = " flite openjtalk glib-2.0 freetype sqlite3 wayland zlib expat openssl \ - wayland libdbus-c++ af-main " + wayland libdbus-c++ af-main gstreamer1.0" RDEPENDS_${PN} += " agl-service-navigation " SRCREV="89dc0052aced411ef09f8e0034fb5cf2c96ee637" SRC_URI="git://github.com/AGLExport/gpsnavi.git;branch=agl \ - file://0001-add-4A-playback-support.patch \ + file://0001-switch-to-alsa-output.patch \ file://0002-openssl-1.1-fixes.patch \ + file://0003-update-permissions.patch \ file://download_mapdata_jp.sh \ file://download_mapdata_uk.sh \ file://org.agl.naviapi.conf \ -- cgit 1.2.3-korg