navigation: Update patches for pipewire and running as non-root 53/21753/1
authorScott Murray <scott.murray@konsulko.com>
Wed, 26 Jun 2019 21:34:48 +0000 (17:34 -0400)
committerScott Murray <scott.murray@konsulko.com>
Wed, 26 Jun 2019 21:34:48 +0000 (17:34 -0400)
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 <scott.murray@konsulko.com>
recipes-demo-hmi/navigation/navigation/0001-add-4A-playback-support.patch [deleted file]
recipes-demo-hmi/navigation/navigation/0001-switch-to-alsa-output.patch [new file with mode: 0644]
recipes-demo-hmi/navigation/navigation/0003-update-permissions.patch [new file with mode: 0644]
recipes-demo-hmi/navigation/navigation_git.bb [changed mode: 0755->0644]

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 (file)
index b419235..0000000
+++ /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 <scott.murray@konsulko.com>
-
-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 @@
-   <author>AISIN AW</author>
-   <feature name="urn:AGL:widget:required-permission">
-     <param name="urn:AGL:permission::public:no-htdocs" value="required" />
-+    <param name="urn:AGL:permission:audio:public:audiostream" value="required" />
-     <param name="http://tizen.org/privilege/internal/dbus" value="required" />
-   </feature>
-   <feature name="urn:AGL:widget:required-api">
-     <param name="homescreen" value="ws" />
-     <param name="windowmanager" value="ws" />
-+    <param name="ahl-4a" value="ws" />
-   </feature>
-   <license>GPL</license>
-   <feature name="urn:AGL:widget:file-properties">
-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 @@
\r
- #include "sms-core/SMCoreDM/SMCoreDMInternal.h"\r
\r
-+extern int play_voice(const char* voice_gen_cmd);\r
-+\r
- typedef struct _tts_text_tbl \r
- {\r
-       INT32   code;\r
-@@ -205,9 +207,9 @@ E_SC_RESULT RG_CTL_CreateVoiceText(RT_NAME_t *in, INT32 language)
-       }\r
-       else\r
-       {\r
--              strncat(tts_voice, "\" & ", (TTSMAX - len - 1));\r
-+              strncat(tts_voice, "\"", (TTSMAX - len - 1));\r
-               \r
--              system(tts_voice);\r
-+              play_voice(tts_voice);\r
-       }\r
-       \r
-       return (e_SC_RESULT_SUCCESS);\r
-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 <scott.murray@konsulko.com>
-+ *
-+ * This program is licensed under GPL version 2 license.
-+ * See the LICENSE file distributed with this source file.
-+ */
-+
-+#include <string>
-+#include <iostream>
-+#include <cstring>
-+#include <unistd.h>
-+#include <sys/types.h>
-+#include <sys/stat.h>
-+#include <pthread.h>
-+#include <gst/gst.h>
-+#include <json-c/json.h>
-+
-+extern "C"
-+{
-+#include <afb/afb-wsj1.h>
-+#include <afb/afb-ws-client.h>
-+#include <systemd/sd-event.h>
-+}
-+
-+#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 (file)
index 0000000..4ce9a43
--- /dev/null
@@ -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 <scott.murray@konsulko.com>
+
+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 (file)
index 0000000..1f1ee49
--- /dev/null
@@ -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 <scott.murray@konsulko.com>
+
+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 @@
+   <feature name="urn:AGL:widget:required-permission">
+     <param name="urn:AGL:permission::public:no-htdocs" value="required" />
+     <param name="http://tizen.org/privilege/internal/dbus" value="required" />
++    <param name="urn:AGL:permission::public:display" value="required" />
++    <param name="urn:AGL:permission::public:audio" value="required" />
+   </feature>
+   <feature name="urn:AGL:widget:required-api">
+     <param name="homescreen" value="ws" />
old mode 100755 (executable)
new mode 100644 (file)
index 80ef24e..0a5f757
@@ -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 \