From b9bda20d81ea44ed8265de8819eb95e2e31dabf9 Mon Sep 17 00:00:00 2001 From: asanoaozora Date: Tue, 26 Sep 2017 13:55:44 +0200 Subject: update speech POC and connect it to navigation (some improvements needed) --- src/navigation/build.sh | 28 ++- .../genivi_mapviewer_mapviewercontrol.cxx | 11 +- .../genivi_navigationcore_guidance.cxx | 24 +- src/navigation/run | 18 +- src/speech-service/CMakeLists.txt | 101 ++++++++ src/speech-service/build.sh | 78 ++++++ src/speech-service/kill-all | 4 + src/speech-service/log.h | 154 ++++++++++++ src/speech-service/main.cpp | 276 +++++++++++++++++++++ src/speech-service/run | 41 +++ src/speech-service/test-speech.py | 89 +++++++ src/speech/CMakeLists.txt | 12 +- src/speech/main.cpp | 2 +- src/speech/test-speech-capi.py | 12 +- 14 files changed, 821 insertions(+), 29 deletions(-) create mode 100644 src/speech-service/CMakeLists.txt create mode 100755 src/speech-service/build.sh create mode 100755 src/speech-service/kill-all create mode 100644 src/speech-service/log.h create mode 100644 src/speech-service/main.cpp create mode 100755 src/speech-service/run create mode 100755 src/speech-service/test-speech.py (limited to 'src') diff --git a/src/navigation/build.sh b/src/navigation/build.sh index 4a7217e..f8daf55 100755 --- a/src/navigation/build.sh +++ b/src/navigation/build.sh @@ -34,6 +34,8 @@ navit=0 #no build of navit -> -n option poi=0 #no build of poi -> -p option dlt_option="OFF" #no DLT -> -l option debug="OFF" #no debug -> -d option +speech=0 #no build of speech -> -s option +speech_option="OFF" function check_path_for_capi { @@ -61,7 +63,7 @@ function check_path_for_capi commonapi_tools_option="-DWITH_PLUGIN_MIGRATION=ON -DWITH_DBUS_INTERFACE=OFF -DDBUS_LIB_PATH="$DBUS_LIB_PATH" -DCOMMONAPI_DBUS_TOOL_DIR="$COMMONAPI_DBUS_TOOL_DIR" -DCOMMONAPI_TOOL_DIR="$COMMONAPI_TOOL_DIR } -while getopts cdlmhnp opt +while getopts cdlmhnps opt do case $opt in c) @@ -84,9 +86,13 @@ do p) poi=1 ;; + s) + speech=1 + speech_option="ON" + ;; h) echo "Usage:" - echo "$0 [-cdhlmnp]" + echo "$0 [-cdhlmnps]" echo "-c: Rebuild with clean" echo "-d: Enable the debug messages" echo "-h: Help" @@ -94,6 +100,7 @@ do echo "-m: Build with commonAPI plugins (only with -c)" echo "-n: Build navit" echo "-p: Build poi" + echo "-s: Build with speech" exit 1 esac done @@ -143,7 +150,7 @@ cd .. echo 'build navigation' if [ "$clean" = 1 ] then - cmake -DWITH_DLT=$dlt_option $commonapi_tools_option -DWITH_DEBUG=$debug ../ + cmake -DWITH_DLT=$dlt_option $commonapi_tools_option -DWITH_SPEECH=$speech_option -DWITH_DEBUG=$debug ../ echo 'Allow to display Korean and Japanese by replacing a font in the configuration file of navit instances' sed -i -e 's/Liberation Sans/NanumGothic/' ./navit/navit/navit_genivi_mapviewer.xml sed -i -e 's/Liberation Sans/NanumGothic/' ./navit/navit/navit_genivi_navigationcore.xml @@ -166,3 +173,18 @@ then fi cd ../../navigation +#speech +cd ../speech-service +mkdir -p build +cd build +if [ "$speech" = 1 ] +then + echo 'build speech' + if [ "$clean" = 1 ] + then + cmake -DWITH_DLT=$dlt_option -DWITH_DEBUG=$debug ../ + fi + make +fi +cd ../../navigation + diff --git a/src/navigation/map-viewer/mapviewercontrol-plugin/genivi_mapviewer_mapviewercontrol.cxx b/src/navigation/map-viewer/mapviewercontrol-plugin/genivi_mapviewer_mapviewercontrol.cxx index 6082063..702c596 100644 --- a/src/navigation/map-viewer/mapviewercontrol-plugin/genivi_mapviewer_mapviewercontrol.cxx +++ b/src/navigation/map-viewer/mapviewercontrol-plugin/genivi_mapviewer_mapviewercontrol.cxx @@ -1622,12 +1622,19 @@ static void callbackFunction(ilmObjectType object, t_ilm_uint surfaceId, t_ilm_b struct ilmSurfaceProperties pSurfaceProperties; t_ilm_layer renderOrder[2]; + if(object == ILM_LAYER) { + if(created){ + //FIXIT: Need to add tempo + sleep(1); + } + } + if (object == ILM_SURFACE) { if (created) { if (surfaceId == FSA_SURFACE) { //FIXIT: Need to add tempo - sleep(1); + sleep(2); //Grab all the layers - HMI will be pLength-2 and FSA pLength-1 if (ilm_getLayerIDs(&pLength, &ppArray) != ILM_SUCCESS) { @@ -1635,7 +1642,7 @@ static void callbackFunction(ilmObjectType object, t_ilm_uint surfaceId, t_ilm_b } //FIXIT: Since we don't know thep id of hmi_launcher and order of start. - //Guess it is teh last one or the one before navit mapviewer PID. + //Guess it is the last one or the one before navit mapviewer PID. renderOrder[0] = FSA_SURFACE; if (ppArray[pLength - 2] != FSA_SURFACE) renderOrder[1] = SURFACE_OFFSET + ppArray[pLength - 2]; diff --git a/src/navigation/navigation-core/guidance-plugin/genivi_navigationcore_guidance.cxx b/src/navigation/navigation-core/guidance-plugin/genivi_navigationcore_guidance.cxx index a7b8419..782150e 100644 --- a/src/navigation/navigation-core/guidance-plugin/genivi_navigationcore_guidance.cxx +++ b/src/navigation/navigation-core/guidance-plugin/genivi_navigationcore_guidance.cxx @@ -49,7 +49,7 @@ #include #include #include - +#include #include "navigation-common-dbus.h" #include "log.h" @@ -73,11 +73,11 @@ class SpeechOutput SpeechOutput(DBus::Connection &connection) : DBus::ObjectProxy(connection, "/org/genivi/hmi/speechservice/SpeechOutput", - "org.genivi.navigation.hmi.speechservice.SpeechOutput") + "org.genivi.hmi.speechservice.SpeechOutput") { } - void notifyConnectionStatus(const uint32_t& connectionStatus) + void notifyConnectionStatus(const int32_t& connectionStatus) { } @@ -87,12 +87,12 @@ class SpeechOutput } - void notifyQueueStatus(const uint32_t& queueStatus) + void notifyQueueStatus(const int32_t& queueStatus) { } - void notifyTTSStatus(const uint32_t& ttsStatus) + void notifyTTSStatus(const int32_t& ttsStatus) { } @@ -690,12 +690,17 @@ void GuidanceObj::SetVoiceGuidance(const bool& activate, const std::string& voic void GuidanceObj::PlayVoiceManeuver() { +#if (SPEECH_ENABLED) message *messages; messages = navit_get_messages(get_navit()); -#if (SPEECH_ENABLED) - m_speechoutput->openPrompter(GENIVI_SPEECHSERVICE_CT_NAVIGATION,GENIVI_SPEECHSERVICE_PPT_NAVIGATION); - m_speechoutput->addTextChunk(messages); - m_speechoutput->closePrompter(); + if(messages){ + m_speechoutput->openPrompter(GENIVI_SPEECHSERVICE_CT_NAVIGATION,GENIVI_SPEECHSERVICE_PPT_NAVIGATION); + while(messages){ + m_speechoutput->addTextChunk(std::string(messages->text)); + messages=messages->next; + } + m_speechoutput->closePrompter(); + } #endif } @@ -754,6 +759,7 @@ GuidanceObj_Callback(GuidanceObj *obj) } obj->m_guidance->ManeuverChanged(maneuver); LOG_INFO(gCtx,"Maneuver: %d",maneuver); + obj->PlayVoiceManeuver(); } else { LOG_ERROR(gCtx,"Maneuver item not found: %p",item); } diff --git a/src/navigation/run b/src/navigation/run index 24efa16..1430da5 100755 --- a/src/navigation/run +++ b/src/navigation/run @@ -90,6 +90,7 @@ replayer=1 verbose=0 #no debug or log messages displayed center="4612 N 0608 E" poi=0 +speech=0 CUR_DIR=$PWD BIN_DIR=$CUR_DIR/bin @@ -104,7 +105,10 @@ POI_SERVER_RESOURCE_DIR=$CUR_DIR/../../src/poi-service/resource poidatabase=$POI_SERVER_RESOURCE_DIR/empty.db # empty poi database by default -while getopts c:ghnoprvx opt +SPEECH_SERVER=speech-server +SPEECH_OUTPUT_BIN_DIR=$CUR_DIR/../../src/speech-service/bin/ + +while getopts c:ghnoprsvx opt do case $opt in c) @@ -142,6 +146,9 @@ do r) replayer=0 ;; + s) + speech=1 + ;; v) #enable log messages verbose=1 ;; @@ -150,7 +157,7 @@ do ;; h) echo "Usage:" - echo "$0 [-c center][-gnoprvx]" + echo "$0 [-c center][-gnoprsvxh]" echo "-c: Set center (supported values: paris,tokyo,seoul,longitude,latitude). Default is geneve" echo "-g: Run subprocesses within gdb (only with -x)" echo "-h: This help" @@ -158,6 +165,7 @@ do echo "-r: Don't start replayer" echo "-o: Create log file of subprocess output" echo "-p: Launch the poi server" + echo "-s: Launch the speech server" echo "-v: Enable the output debug messages" echo "-x: Run subprocesses in own xterm to get separated log messages" exit 1 @@ -192,6 +200,12 @@ then run "POI service" $POI_SERVER_BIN_DIR/$POI_SERVER -f $poidatabase fi +if [ "$speech" = 1 ] +then + # start the speech server + run "Speech service" $SPEECH_OUTPUT_BIN_DIR/$SPEECH_SERVER +fi + cd $NAVIT_BIN_DIR >bookmark.txt diff --git a/src/speech-service/CMakeLists.txt b/src/speech-service/CMakeLists.txt new file mode 100644 index 0000000..96725e7 --- /dev/null +++ b/src/speech-service/CMakeLists.txt @@ -0,0 +1,101 @@ +########################################################################### +# @licence app begin@ +# SPDX-License-Identifier: MPL-2.0 +# +# Component Name: speech-server +# +# Author: Philippe Colliot +# +# Copyright (C) 2017, PSA GROUP +# +# License: +# This Source Code Form is subject to the terms of the +# Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with +# this file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# @licence end@ +########################################################################### +project(speech-server) +cmake_minimum_required(VERSION 2.8) +find_package(PkgConfig REQUIRED) + +message(STATUS ${PROJECT_NAME}) + +add_definitions("-std=gnu++11") + +option(WITH_DEBUG + "Enable the debug messages" OFF) +option(WITH_DLT + "Enable DLT logging" OFF) + +message(STATUS "WITH_DEBUG = ${WITH_DEBUG}") +message(STATUS "WITH_DLT = ${WITH_DLT}") + +set(API_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../../api") +set(DBUS_GENERATED_INCLUDE_DIR "${CMAKE_CURRENT_BINARY_DIR}/dbus-include") + +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/lib) +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/bin) + +if(${WITH_DLT}) + add_definitions("-DDLT_ENABLED=1") + pkg_check_modules(DLT REQUIRED automotive-dlt) + include_directories( ${DLT_INCLUDE_DIRS} ) + set(LIBRARIES ${LIBRARIES} ${DLT_LIBRARIES}) +endif() + +if(WITH_DEBUG) + add_definitions("-DDEBUG_ENABLED=1") +endif() + +pkg_check_modules(DBUS_CPP dbus-c++-1) +pkg_check_modules(GLIB REQUIRED glib-2.0) +pkg_check_modules(GOBJECT gobject-2.0) +pkg_check_modules(DBUS dbus-1) +pkg_check_modules(DBUS_CPP_GLIB dbus-c++-glib-1) + +#generates the GLib DBus proxies and adaptors +add_subdirectory(${API_DIR}/speech-service "${DBUS_GENERATED_INCLUDE_DIR}/speech-service") + +#add flite dependencies +set(FLITE_INCLUDE_DIRS /usr/include/flite) +set(FLITE_LIBDIR /usr/lib/x86_64-linux-gnu/) +set(FLITE_LIBRARIES /usr/lib/x86_64-linux-gnu/libflite.so /usr/lib/x86_64-linux-gnu/libflite_cmu_us_kal.so) + +include_directories( + ${CMAKE_CURRENT_SOURCE_DIR} + ${COMMON_DIR} + ${DBUS_GENERATED_INCLUDE_DIR}/speech-service + ${DBUS_CPP_INCLUDE_DIRS} + ${GLIB_INCLUDE_DIRS} + ${GOBJECT_INCLUDE_DIRS} + ${DBUS_INCLUDE_DIRS} + ${DBUS_CPP_GLIB_INCLUDE_DIRS} + ${FLITE_INCLUDE_DIRS} +) + +link_directories( + ${DBUS_CPP_LIBRARY_DIRS} + ${GLIB_LIBRARY_DIRS} + ${GOBJECT_LIBRARY_DIRS} + ${DBUS_LIBRARY_DIRS} + ${DBUS_CPP_GLIB_DIRS} + ${FLITE_LIBDIR} +) + +set(LIBRARIES + ${LIBRARIES} + ${DBUS_CPP_LIBRARIES} + ${GLIB_LIBRARIES} + ${GOBJECT_LIBRARIES} + ${DBUS_LIBRARIES} + ${DBUS_CPP_GLIB_LIBRARIES} + ${FLITE_LIBRARIES} +) + +add_executable(${PROJECT_NAME} + main.cpp +) + +target_link_libraries(${PROJECT_NAME} ${LIBRARIES}) + diff --git a/src/speech-service/build.sh b/src/speech-service/build.sh new file mode 100755 index 0000000..2dbb819 --- /dev/null +++ b/src/speech-service/build.sh @@ -0,0 +1,78 @@ +#!/bin/bash + +########################################################################### +# @licence app begin@ +# SPDX-License-Identifier: MPL-2.0 +# +# \copyright Copyright (C) 2013-2017, PSA Group +# +# \file build.sh +# +# \brief This file is part of the Build System for speech. +# +# \author Philippe Colliot +# +# \version 1.0 +# +# This Source Code Form is subject to the terms of the +# Mozilla Public License (MPL), v. 2.0. +# If a copy of the MPL was not distributed with this file, +# You can obtain one at http://mozilla.org/MPL/2.0/. +# +# For further information see http://www.genivi.org/. +# +# List of changes: +# +# +# @licence end@ +########################################################################### + +clean=0 #no clean (means no cmake) -> -c option +dlt_option="OFF" #no DLT -> -l option +debug="OFF" #no debug -> -d option + +while getopts cdhl opt +do + case $opt in + c) + clean=1 + ;; + d) + debug="ON" + ;; + l) + dlt_option="ON" + ;; + h) + echo "Usage:" + echo "$0 [-cdhl]" + echo "-c: Rebuild with clean" + echo "-d: Enable the debug messages" + echo "-h: Help" + echo "-l: Build with dlt (only with -c)" + exit 1 + esac +done + +set -e + +if [ "$clean" = 1 ] +then + echo 'clean up the build folder' + if [ -d "./build" ] + then + find ./build ! -name '*.cbp' -type f -exec rm -f {} + + fi +fi + +mkdir -p build +cd build + +echo 'build speech output' +if [ "$clean" = 1 ] +then + cmake -DWITH_DLT=$dlt_option -DWITH_DEBUG=$debug ../ +fi +make + + diff --git a/src/speech-service/kill-all b/src/speech-service/kill-all new file mode 100755 index 0000000..9889cf6 --- /dev/null +++ b/src/speech-service/kill-all @@ -0,0 +1,4 @@ +#!/bin/sh +echo 'kill all remaining process' +kill -9 `ps -ef | grep speech-server | grep -v grep | awk '{print $2}'` + diff --git a/src/speech-service/log.h b/src/speech-service/log.h new file mode 100644 index 0000000..4d946fb --- /dev/null +++ b/src/speech-service/log.h @@ -0,0 +1,154 @@ +/************************************************************************** +* @licence app begin@ +* +* SPDX-License-Identifier: MPL-2.0 +* +* \ingroup GNSSService +* +* \copyright Copyright (C) BMW Car IT GmbH 2011 +* Copyright (C) 2013, XS Embedded GmbH +* +* \license +* This Source Code Form is subject to the terms of the +* Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with +* this file, You can obtain one at http://mozilla.org/MPL/2.0/. +* +* @licence end@ +**************************************************************************/ + +#ifndef INCLUDE_LOG +#define INCLUDE_LOG + +// turn-on via cmake define: +// $ cmake -DWITH_DLT=1 -DDEBUG_ENABLED=1 .. + +#if (!DLT_ENABLED) +/*****************************************************************************/ +// use printf +#include + +// some type-name used instead of DLT context +typedef const char* NoDltContext; + +#define DLT_DECLARE_CONTEXT(CONTEXT) \ + NoDltContext CONTEXT; + +#define DLT_IMPORT_CONTEXT(CONTEXT) \ + extern NoDltContext CONTEXT; + +#define DLT_REGISTER_CONTEXT(CONTEXT, CONTEXT_ID, DESC) \ + CONTEXT = CONTEXT_ID; + +#define DLT_REGISTER_APP(CONTEXT, DESC) ; + +#define DLT_UNREGISTER_CONTEXT(CONTEXT) ; +#define DLT_UNREGISTER_APP() ; +#define dlt_free() ; + +// log calls +#if (!DEBUG_ENABLED) + +#define LOG_VERBOSE_MSG(context, msg) ; +#define LOG_VERBOSE(context, fmt, ...) ; + +#define LOG_DEBUG_MSG(context, msg) ; +#define LOG_DEBUG(context, fmt, ...) ; + +#define LOG_INFO_MSG(context, msg) ; +#define LOG_INFO(context, fmt, ...) ; + +#define LOG_WARNING_MSG(context, msg) ; +#define LOG_WARNING(context, fmt, ...) ; + +#else + +#define LOG_VERBOSE_MSG(context, msg) \ + fprintf(stderr, "[VERBO][%4s] " msg "\n", context) +#define LOG_VERBOSE(context, fmt, ...) \ + fprintf(stderr, "[VERBO][%4s] " fmt "\n", context, __VA_ARGS__) + +#define LOG_DEBUG_MSG(context, msg) \ + fprintf(stderr, "[DEBUG][%4s] " msg "\n", context) +#define LOG_DEBUG(context, fmt, ...) \ + fprintf(stderr, "[DEBUG][%4s] " fmt "\n", context, __VA_ARGS__) + +#define LOG_INFO_MSG(context, msg) \ + fprintf(stderr, "[INFO ][%4s] " msg "\n", context) +#define LOG_INFO(context, fmt, ...) \ + fprintf(stderr, "[INFO ][%4s] " fmt "\n", context, __VA_ARGS__) + +#define LOG_WARNING_MSG(context, msg) \ + fprintf(stderr, "[WARN ][%4s] " msg "\n", context) +#define LOG_WARNING(context, fmt, ...) \ + fprintf(stderr, "[WARN ][%4s] " fmt "\n", context, __VA_ARGS__) +#endif + +#define LOG_ERROR_MSG(context, msg) \ + fprintf(stderr, "[ERROR][%4s] " msg "\n", context) +#define LOG_ERROR(context, fmt, ...) \ + fprintf(stderr, "[ERROR][%4s] " fmt "\n", context, __VA_ARGS__) + +#define LOG_FATAL_MSG(context, msg) \ + fprintf(stderr, "[FATAL][%4s] " msg "\n", context) +#define LOG_FATAL(context, fmt, ...) \ + fprintf(stderr, "[FATAL][%4s] " fmt "\n", context, __VA_ARGS__) + +#else /* DLT_ENABLED */ +/*****************************************************************************/ +// use DLT +#include "dlt.h" + +typedef const char* Context; + +#define LOG_VERBOSE_MSG(context, msg) \ + DLT_LOG(context, DLT_LOG_VERBOSE, DLT_STRING(msg)); +#define LOG_VERBOSE(context, fmt, ...) \ + { \ + char logBuffer[256]; \ + sprintf(logBuffer, fmt, __VA_ARGS__); \ + DLT_LOG(context, DLT_LOG_VERBOSE, DLT_STRING(logBuffer)); \ + } +#define LOG_DEBUG_MSG(context, msg) \ + DLT_LOG(context, DLT_LOG_DEBUG, DLT_STRING(msg)); +#define LOG_DEBUG(context, fmt, ...) \ + { \ + char logBuffer[256]; \ + sprintf(logBuffer, fmt, __VA_ARGS__); \ + DLT_LOG(context, DLT_LOG_DEBUG, DLT_STRING(logBuffer)); \ + } +#define LOG_INFO_MSG(context, msg) \ + DLT_LOG(context, DLT_LOG_INFO, DLT_STRING(msg)); +#define LOG_INFO(context, fmt, ...) \ + { \ + char logBuffer[256]; \ + sprintf(logBuffer, fmt, __VA_ARGS__); \ + DLT_LOG(context, DLT_LOG_INFO, DLT_STRING(logBuffer)); \ + } +#define LOG_WARNING_MSG(context, msg) \ + DLT_LOG(context, DLT_LOG_WARN, DLT_STRING(msg)); +#define LOG_WARNING(context, fmt, ...) \ + { \ + char logBuffer[256]; \ + sprintf(logBuffer, fmt, __VA_ARGS__); \ + DLT_LOG(context, DLT_LOG_WARN, DLT_STRING(logBuffer)); \ + } +#define LOG_ERROR_MSG(context, msg) \ + DLT_LOG(context, DLT_LOG_ERROR, DLT_STRING(msg)); +#define LOG_ERROR(context, fmt, ...) \ + { \ + char logBuffer[256]; \ + sprintf(logBuffer, fmt, __VA_ARGS__); \ + DLT_LOG(context, DLT_LOG_ERROR, DLT_STRING(logBuffer)); \ + } +#define LOG_FATAL_MSG(context, msg) \ + DLT_LOG(context, DLT_LOG_FATAL, DLT_STRING(msg)); +#define LOG_FATAL(context, fmt, ...) \ + { \ + char logBuffer[256]; \ + sprintf(logBuffer, fmt, __VA_ARGS__); \ + DLT_LOG(context, DLT_LOG_FATAL, DLT_STRING(logBuffer)); \ + } + +#endif /* DLT_ENABLED */ + +#endif /* INCLUDE_LOG */ diff --git a/src/speech-service/main.cpp b/src/speech-service/main.cpp new file mode 100644 index 0000000..df45857 --- /dev/null +++ b/src/speech-service/main.cpp @@ -0,0 +1,276 @@ +/** +* @licence app begin@ +* SPDX-License-Identifier: MPL-2.0 +* +* \copyright Copyright (C) 2013-2017, PSA GROUP +* +* \file main.cpp +* +* \brief This file is part of the speech service proof of concept. +* +* \author Philippe Colliot +* \brief Some parts of the code has been inspired by the following people: +* \brief Mario Thielert, David Kämpf, Dominique Massonie +* +* \version 1.0 +* +* This Source Code Form is subject to the terms of the +* Mozilla Public License (MPL), v. 2.0. +* If a copy of the MPL was not distributed with this file, +* You can obtain one at http://mozilla.org/MPL/2.0/. +* +* For further information see http://www.genivi.org/. +* +* List of changes: +* , , +* +* @licence end@ +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "genivi-speechservice-constants.h" +#include "genivi-speechservice-speechoutput_adaptor.h" +#include "log.h" +#include +#include + +extern "C" { + cst_voice* register_cmu_us_kal(const char *voxdir); + void unregister_cmu_us_kal(cst_voice *vox); +} + +DLT_DECLARE_CONTEXT(gCtx) + +static const char* speech_SERVICE_NAME = "org.genivi.hmi.speechservice.SpeechOutput"; +static const char* speech_OBJECT_PATH = "/org/genivi/hmi/speechservice/SpeechOutput"; + +static DBus::Glib::BusDispatcher *dispatcher; +static DBus::Connection *dbusConnection; + +static int m_lenLastChunk; +static int m_slotCount; +static const uint32_t MAX_CHUNK_SIZE = 1024 + 1; /**< Maximum size of any chunk which can be stored within the queue. */ +static const uint32_t MAX_SLOT_COUNT = 16; /**< Maximum number of chunks which can be present in the queue at the same time. */ +static const uint32_t MAX_SLOT_COUNT_NO_WARN = (3 * MAX_SLOT_COUNT) / 4; /**< When pushing a chunk, TAQS_WARNING shall be reported if the new occupied slot count exceeds MAX_SLOT_COUNT_NO_WARN. */ +static const uint32_t MAX_CHUNK_LENGTH = 1024; /**< max length of a single prompt part */ +static const uint32_t MAX_MARKER_LENGTH = 32; /**< marker tag inside the prompt chunk */ +static const uint32_t PROCESS_CHUNKS_LOOP = 100; +static cst_voice* mp_voice; +static cst_audio_streaming_info* mp_asi; +static pthread_mutex_t mutex; + +static std::string m_chunkBuffer; /** max size = MAX_CHUNK_SIZE*MAX_SLOT_COUNT */ + +gboolean processChunks(gpointer data) { + //worker thread to process chunks in buffer + + pthread_mutex_lock(&mutex); + + if (m_chunkBuffer.length() > 0) + { + LOG_DEBUG_MSG(gCtx,"processChunks"); + std::string tempBuffer; + tempBuffer.assign(m_chunkBuffer); + m_chunkBuffer.clear(); //buffer empty + m_slotCount=0; //reset counter of slots + + pthread_mutex_unlock(&mutex); + + // pass string to TTS engine + flite_text_to_speech(tempBuffer.c_str(),mp_voice,"play"); + } + else + { + pthread_mutex_unlock(&mutex); + } + return(true); +} + +static int fliteCallback(const cst_wave *w, int start, int size, + int last, cst_audio_streaming_info_struct *asi) +{ + static cst_audiodev *ad = 0; + + if (start == 0) + ad = audio_open(w->sample_rate,w->num_channels,CST_AUDIO_LINEAR16); + + audio_write(ad,&w->samples[start],size*sizeof(short)); + + if (last == 1) + { + audio_drain(ad); + audio_close(ad); + ad = NULL; + LOG_DEBUG_MSG(gCtx,"end of processing chunks"); + } + + /* if you want to stop return CST_AUDIO_STREAM_STOP */ + return CST_AUDIO_STREAM_CONT; +} + +class SpeechOutput +: public org::genivi::hmi::speechservice::SpeechOutput_adaptor, + public DBus::IntrospectableAdaptor, + public DBus::ObjectAdaptor +{ +public: + + SpeechOutput(DBus::Connection &connection) : DBus::ObjectAdaptor(connection, speech_OBJECT_PATH){ + m_version._1=1; + m_version._2=0; + m_version._3=0; + m_version._4="12-10-2016"; + + m_lenLastChunk = 0; + m_slotCount = 0; + + flite_init(); + + mp_voice = register_cmu_us_kal(NULL); + mp_asi = new_audio_streaming_info(); + mp_asi->asc = fliteCallback; + + feat_set(mp_voice->features,"streaming_info",audio_streaming_info_val(mp_asi)); + } + + ~SpeechOutput(){ + unregister_cmu_us_kal(mp_voice); + } + + ::DBus::Struct< uint16_t, uint16_t, uint16_t, std::string > getVersion(){ + return m_version; + } + + void openPrompter(const int32_t& connectionType, const int32_t& preProcessingType){ + LOG_DEBUG(gCtx,"openPrompter: connection %d preprocessing %d",connectionType,preProcessingType); + } + + /** + * description: The prompter must be opened to trigger the playback of the provided prompt. + * + The prompt length must not exceed the length of a PromptChunk + * buffer. + Synthesizes the provided text or if using the escape sequence of the + * engine supplier a wave file in a supported sampling rate is provided, the + * system will back back also wave files. + The text will be normalized using the + * context identifier provided to openprompter. This applies to matching + * prerecorded files as well as the synthesis of number and words that are + * matched to a lexical dictionary. + The synthesize will start if the prompter is + * idle, if the prompter is already playing the playback will be delayed until + * all previously added text chunks are played back. For every text chunk + * provided a notification will be send. + */ + uint32_t addTextChunk(const std::string& chunk){ + LOG_DEBUG(gCtx,"addTextChunk: %s", chunk.c_str()); + + uint32_t _chunkID; + + // todo: manage _chunkID + + int32_t qStatus = GENIVI_SPEECHSERVICE_CS_UNKNOWN; + + if (chunk.size() > 0 && chunk.size() < MAX_CHUNK_LENGTH) + { + if (m_slotCount < (int) MAX_SLOT_COUNT) + { + if (m_slotCount <= (int) MAX_SLOT_COUNT_NO_WARN) + { + qStatus = GENIVI_SPEECHSERVICE_QS_LOW_FILL; + } + else + { + qStatus = GENIVI_SPEECHSERVICE_QS_HIGH_FILL; + } + m_chunkBuffer.append(chunk); + m_lenLastChunk = chunk.size(); + ++m_slotCount; + } + else + { + qStatus = GENIVI_SPEECHSERVICE_QS_FULL; + } + } + + notifyQueueStatus(qStatus); + + return(_chunkID); + } + + /** + * description: A prompt must be playing to perform an abort action. If no prompting operation + * in progress there will be no reaction of the system. + */ + void abortPrompter(){ + LOG_DEBUG_MSG(gCtx,"abortPrompter"); + } + + /** + * description: The prompter is closed after the last text chunk submitted has finished playing. + */ + void closePrompter(){ + LOG_DEBUG_MSG(gCtx,"closePrompter"); + } + +private: + ::DBus::Struct< uint16_t, uint16_t, uint16_t, std::string > m_version; +}; + +static SpeechOutput* serverSpeechOutput; + +int main(int argc , char** argv ) +{ + DLT_REGISTER_APP("SPCS","SPEECH SERVER"); + DLT_REGISTER_CONTEXT(gCtx,"SPCS","Global Context"); + + GMainLoop * mainloop ; + guint processChunksID; + + // Set the global C and C++ locale to the user-configured locale, + // so we can use std::cout with UTF-8, via Glib::ustring, without exceptions. + std::locale::global(std::locale("")); + + // creating the dispatcher + dispatcher = new DBus::Glib::BusDispatcher(); + DBus::default_dispatcher = dispatcher; + dispatcher->attach(NULL); + + // create a connection on the session bus + dbusConnection = new DBus::Connection(DBus::Connection::SessionBus()); + dbusConnection->setup(dispatcher); + + // create the server for SpeechOutput + dbusConnection->request_name(speech_SERVICE_NAME); + serverSpeechOutput=new SpeechOutput(*dbusConnection); + + processChunksID = g_timeout_add(PROCESS_CHUNKS_LOOP,processChunks,NULL); + + // Create a new GMainLoop with default context and initial state of "not running " + mainloop = g_main_loop_new (g_main_context_default() , FALSE ); + + // Send a feedback to the user + LOG_INFO_MSG(gCtx,"Speech output server started"); + + // loop listening + g_main_loop_run ( mainloop ); + + // clean memory + delete serverSpeechOutput; + delete dbusConnection; + delete dispatcher; + + LOG_INFO_MSG(gCtx,"Speech output server stopped"); + + return EXIT_SUCCESS; +} + diff --git a/src/speech-service/run b/src/speech-service/run new file mode 100755 index 0000000..f60767e --- /dev/null +++ b/src/speech-service/run @@ -0,0 +1,41 @@ +#!/bin/sh + +# @licence app begin@ +# SPDX-License-Identifier: MPL-2.0 +# +# \copyright Copyright (C) 2013-2014, PCA Peugeot Citroen +# +# \file run +# +# \brief This file is part of the Build System. +# +# \author Philippe Colliot +# +# \version 1.0 +# +# This Source Code Form is subject to the terms of the +# Mozilla Public License (MPL), v. 2.0. +# If a copy of the MPL was not distributed with this file, +# You can obtain one at http://mozilla.org/MPL/2.0/. +# +# For further information see http://www.genivi.org/. +# +# List of changes: +# +# , , +# +# @licence end@ + +CURDIR=$PWD + +BIN_DIR=$CURDIR/bin +SPEECH_OUPUT_SERVER_BIN_DIR=$BIN_DIR + +echo 'kill reminding orphan process if necessary' +./kill-all + +echo '------------------------start the server------------------------' +$SPEECH_OUPUT_SERVER_BIN_DIR/speech-server + + + diff --git a/src/speech-service/test-speech.py b/src/speech-service/test-speech.py new file mode 100755 index 0000000..0f99e13 --- /dev/null +++ b/src/speech-service/test-speech.py @@ -0,0 +1,89 @@ +#!/usr/bin/python + +""" +************************************************************************** +* @licence app begin@ +* SPDX-License-Identifier: MPL-2.0 +* +* \copyright Copyright (C) 2016, PSA GROUP +* +* \file test-speech.py +* +* \brief This simple test shows how the speech +* could be easily tested using a python script +* +* \author Philippe Colliot +* +* \version 1.0 +* +* This Source Code Form is subject to the terms of the +* Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with +# this file, You can obtain one at http://mozilla.org/MPL/2.0/. +* List of changes: +* +* @licence end@ +************************************************************************** +""" + +import dbus +import gobject +import dbus.mainloop.glib +import time + +import pdb; +#pdb.set_trace() +#constants as defined in the Navigation API +GENIVI_SPEECHSERVICE_QS_LOW_FILL=51 + +#constants used into the script +TIME_OUT = 10000 + +def catch_speech_notifyConnectionStatus_signal_handler(connectionStatus): + print("Connection status: " + str(int(connectionStatus))) + +def catch_speech_notifyMarkerReached_signal_handler(chunkID,marker): + print("Chunk ID: " + chunkID) + +def catch_speech_notifyQueueStatus_signal_handler(queueStatus): + print("Queue status: " + str(int(queueStatus))) + if queueStatus==GENIVI_SPEECHSERVICE_QS_LOW_FILL: + print ('\nTest OK') + loop.quit() + +def catch_speech_notifyTTSStatus_signal_handler(ttsStatus): + print("TTS status: " + str(int(ttsStatus))) + +#timeout +def timeout(): + print ('Timeout Expired') + print ('\nTest FAILED') + loop.quit() + +if __name__ == '__main__': + dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) + +#connect to session bus +bus = dbus.SessionBus() + +bus.add_signal_receiver(catch_speech_notifyConnectionStatus_signal_handler, \ + dbus_interface = "org.genivi.hmi.speechservice.SpeechOutput", \ + signal_name = "notifyConnectionStatus") +bus.add_signal_receiver(catch_speech_notifyMarkerReached_signal_handler, \ + dbus_interface = "org.genivi.hmi.speechservice.SpeechOutput", \ + signal_name = "notifyMarkerReached") +bus.add_signal_receiver(catch_speech_notifyQueueStatus_signal_handler, \ + dbus_interface = "org.genivi.hmi.speechservice.SpeechOutput", \ + signal_name = "notifyQueueStatus") +bus.add_signal_receiver(catch_speech_notifyTTSStatus_signal_handler, \ + dbus_interface = "org.genivi.hmi.speechservice.SpeechOutput", \ + signal_name = "notifyTTSStatus") + +speech = bus.get_object('org.genivi.hmi.speechservice.SpeechOutput','/org/genivi/speechservice/SpeechOutput') +g_speech_interface = dbus.Interface(speech, dbus_interface='org.genivi.hmi.speechservice.SpeechOutput') + +g_speech_interface.addTextChunk(dbus.String("Hello")) + +#main loop +gobject.timeout_add(TIME_OUT, timeout) +loop = gobject.MainLoop() +loop.run() diff --git a/src/speech/CMakeLists.txt b/src/speech/CMakeLists.txt index ee62ba2..27f578b 100644 --- a/src/speech/CMakeLists.txt +++ b/src/speech/CMakeLists.txt @@ -56,20 +56,20 @@ add_subdirectory(${FRANCA_DIR}/hmi/speechservice "${CMAKE_CURRENT_BINARY_DIR}/fr # Path to the generated files set(API_VERSION_NAVIGATION_MAJOR 4) set(API_VERSION_NAVIGATION "v${API_VERSION_NAVIGATION_MAJOR}") -set(API_VERSION_SPEECHOUTPUTSERVICE_MAJOR 1) -set(API_VERSION_SPEECHOUTPUTSERVICE "v${API_VERSION_SPEECHOUTPUTSERVICE_MAJOR}") +set(API_VERSION_SPEECHSERVICE_MAJOR 1) +set(API_VERSION_SPEECHSERVICE "v${API_VERSION_SPEECHSERVICE_MAJOR}") set(PRJ_SRC_GEN_COMMON_PATH ${COMMONAPI_GEN_DIR}/${API_VERSION_NAVIGATION}/org/genivi) #files shared by all the APIs -set(PRJ_SRC_GEN_SPEECHOUTPUTSERVICE_PATH ${COMMONAPI_GEN_DIR}/${API_VERSION_SPEECHOUTPUTSERVICE}/org/genivi/hmi/speechoutputservice) #files shared by the speechservice APIs +set(PRJ_SRC_GEN_SPEECHSERVICE_PATH ${COMMONAPI_GEN_DIR}/${API_VERSION_SPEECHSERVICE}/org/genivi/hmi/speechservice) #files shared by the speechservice APIs # Source Files FILE(GLOB PRJ_LOCAL_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) FILE(GLOB PRJ_STUB_GEN_SRCS ${PRJ_SRC_GEN_ROOT_PATH}/*DBusStub*.cpp ${PRJ_SRC_GEN_ROOT_PATH}/*Types.cpp ${PRJ_SRC_GEN_ROOT_PATH}/*DBusDeployment.cpp ${PRJ_SRC_GEN_ROOT_PATH}/*StubDefault.cpp - ${PRJ_SRC_GEN_SPEECHOUTPUTSERVICE_PATH}/*DBusStub*.cpp ${PRJ_SRC_GEN_SPEECHOUTPUTSERVICE_PATH}/*Types.cpp ${PRJ_SRC_GEN_SPEECHOUTPUTSERVICE_PATH}/*DBusDeployment.cpp ${PRJ_SRC_GEN_SPEECHOUTPUTSERVICE_PATH}/*StubDefault.cpp + ${PRJ_SRC_GEN_SPEECHSERVICE_PATH}/*DBusStub*.cpp ${PRJ_SRC_GEN_SPEECHSERVICE_PATH}/*Types.cpp ${PRJ_SRC_GEN_SPEECHSERVICE_PATH}/*DBusDeployment.cpp ${PRJ_SRC_GEN_SPEECHSERVICE_PATH}/*StubDefault.cpp ) FILE(GLOB PRJ_STUB_IMPL_SRCS ${PRJ_SRC_GEN_ROOT_PATH}/*Stub*.cpp - ${PRJ_SRC_GEN_SPEECHOUTPUTSERVICE_PATH}/*Stub*.cpp + ${PRJ_SRC_GEN_SPEECHSERVICE_PATH}/*Stub*.cpp ) set(PRJ_SRCS ${PRJ_LOCAL_SRCS} ${PRJ_STUB_GEN_SRCS} ${PRJ_STUB_IMPL_SRCS}) @@ -82,7 +82,7 @@ include_directories( ${COMMONAPI_GEN_DIR} ${PRJ_SRC_GEN_ROOT_PATH} ${PRJ_SRC_GEN_COMMON_PATH} - ${PRJ_SRC_GEN_SPEECHOUTPUTSERVICE_PATH} + ${PRJ_SRC_GEN_SPEECHSERVICE_PATH} ${DBUS_INCLUDE_DIRS} ${COMMONAPI_INCLUDE_DIRS} ${COMMONAPI_DBUS_INCLUDE_DIRS} diff --git a/src/speech/main.cpp b/src/speech/main.cpp index 4d3b1bc..f6b3ca4 100644 --- a/src/speech/main.cpp +++ b/src/speech/main.cpp @@ -50,7 +50,7 @@ extern "C" { #include #include -using namespace v1::org::genivi::hmi::speechoutputservice; +using namespace v1::org::genivi::hmi::speechservice; using namespace v4::org::genivi; static std::shared_ptr < CommonAPI::Runtime > runtime; diff --git a/src/speech/test-speech-capi.py b/src/speech/test-speech-capi.py index 1fc6eb3..f89c60b 100755 --- a/src/speech/test-speech-capi.py +++ b/src/speech/test-speech-capi.py @@ -62,20 +62,20 @@ if __name__ == '__main__': bus = dbus.SessionBus() bus.add_signal_receiver(catch_speech_notifyConnectionStatus_signal_handler, \ - dbus_interface = "org.genivi.hmi.speechoutputservice.SpeechOutput.v1_0", \ + dbus_interface = "org.genivi.hmi.speechservice.SpeechOutput.v1_0", \ signal_name = "notifyConnectionStatus") bus.add_signal_receiver(catch_speech_notifyMarkerReached_signal_handler, \ - dbus_interface = "org.genivi.hmi.speechoutputservice.SpeechOutput.v1_0", \ + dbus_interface = "org.genivi.hmi.speechservice.SpeechOutput.v1_0", \ signal_name = "notifyMarkerReached") bus.add_signal_receiver(catch_speech_notifyQueueStatus_signal_handler, \ - dbus_interface = "org.genivi.hmi.speechoutputservice.SpeechOutput.v1_0", \ + dbus_interface = "org.genivi.hmi.speechservice.SpeechOutput.v1_0", \ signal_name = "notifyQueueStatus") bus.add_signal_receiver(catch_speech_notifyTTSStatus_signal_handler, \ - dbus_interface = "org.genivi.hmi.speechoutputservice.SpeechOutput.v1_0", \ + dbus_interface = "org.genivi.hmi.speechservice.SpeechOutput.v1_0", \ signal_name = "notifyTTSStatus") -speech = bus.get_object('org.genivi.hmi.speechoutputservice.SpeechOutput.v1_0_SpeechOutput','/SpeechOutput') -g_speech_interface = dbus.Interface(speech, dbus_interface='org.genivi.hmi.speechoutputservice.SpeechOutput.v1_0') +speech = bus.get_object('org.genivi.hmi.speechservice.SpeechOutput.v1_0_SpeechOutput','/SpeechOutput') +g_speech_interface = dbus.Interface(speech, dbus_interface='org.genivi.hmi.speechservice.SpeechOutput.v1_0') g_speech_interface.addTextChunk(dbus.String("Hello")) -- cgit v1.2.1