summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--api/franca/hmi/speechservice/SpeechOutput.fidl12
-rw-r--r--api/franca/navigation/navigationcore/NavigationCoreTypes.fidl4
-rw-r--r--src/speech/CMakeLists.txt116
-rw-r--r--src/speech/main.cpp254
-rwxr-xr-xsrc/speech/test-speech-capi.py88
5 files changed, 467 insertions, 7 deletions
diff --git a/api/franca/hmi/speechservice/SpeechOutput.fidl b/api/franca/hmi/speechservice/SpeechOutput.fidl
index 1cac5ef..b41f27f 100644
--- a/api/franca/hmi/speechservice/SpeechOutput.fidl
+++ b/api/franca/hmi/speechservice/SpeechOutput.fidl
@@ -141,7 +141,8 @@ interface SpeechOutput {
*/
<** @description : Notifies the connection status **>
- broadcast notifyConnectionStatus selective {
+// broadcast notifyConnectionStatus selective {
+ broadcast notifyConnectionStatus {
out {
<** @description : Client connection status. **>
ConnectionStatus connectionStatus
@@ -149,7 +150,8 @@ interface SpeechOutput {
}
<** @description : Notifies the last reached marker. **>
- broadcast notifyMarkerReached selective {
+// broadcast notifyMarkerReached selective {
+ broadcast notifyMarkerReached {
out {
<** @description : ID of the processed chunk. **>
ChunkID chunkID
@@ -159,7 +161,8 @@ interface SpeechOutput {
}
<** @description : Notifies the queue status. **>
- broadcast notifyQueueStatus selective {
+// broadcast notifyQueueStatus selective {
+ broadcast notifyQueueStatus {
out {
<** @description : Fill status of the text buffer. **>
QueueStatus queueStatus
@@ -167,7 +170,8 @@ interface SpeechOutput {
}
<** @description : Notifies the TTS engine status. **>
- broadcast notifyTTSStatus selective {
+// broadcast notifyTTSStatus selective {
+ broadcast notifyTTSStatus {
out {
<** @description : Current status of the TTS. **>
TtsStatus ttsStatus
diff --git a/api/franca/navigation/navigationcore/NavigationCoreTypes.fidl b/api/franca/navigation/navigationcore/NavigationCoreTypes.fidl
index 98ae3f4..e04be6e 100644
--- a/api/franca/navigation/navigationcore/NavigationCoreTypes.fidl
+++ b/api/franca/navigation/navigationcore/NavigationCoreTypes.fidl
@@ -24,7 +24,7 @@ typeCollection NavigationCoreTypes {
ALTITUDE = 162
}
- enumeration Notification {
+ enumeration Notification extends NotificationNavigation{
GUIDANCE_ERROR_NOMANEUVER = 0
GUIDANCE_ERROR_VOICENOTALLOWED
LOCATIONINPUT_ERROR_NOMORELOCATIONINPUTHANDLES
@@ -38,8 +38,6 @@ typeCollection NavigationCoreTypes {
ROUTING_ERROR_ROUTEPREFERENCENOTSUPPORTED
ROUTING_ERROR_WAYPOINTCANNOTBECHANGED
ROUTING_ERROR_TOOMANYWAYPOINTS
- SESSION_ERROR_NOMORESESSIONHANDLES
- SESSION_ERROR_SESSIONNOTAVAILABLE
}
}
diff --git a/src/speech/CMakeLists.txt b/src/speech/CMakeLists.txt
new file mode 100644
index 0000000..5e092ba
--- /dev/null
+++ b/src/speech/CMakeLists.txt
@@ -0,0 +1,116 @@
+###########################################################################
+# @licence app begin@
+# SPDX-License-Identifier: MPL-2.0
+#
+# Component Name: poi-server-capi
+#
+# Author: Philippe Colliot
+#
+# Copyright (C) 2015, PCA Peugeot Citroën
+#
+# 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-output-server)
+cmake_minimum_required(VERSION 2.8)
+
+message(STATUS ${PROJECT_NAME})
+
+set(CMAKE_VERBOSE_MAKEFILE on)
+set(CMAKE_CXX_FLAGS "-Wall -std=c++0x")
+
+set(API_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../../api")
+set(FRANCA_DIR "${API_DIR}/franca")
+set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/lib)
+set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/bin)
+
+# DBus Path
+if(DBUS_LIB_PATH)
+ message(STATUS "DBUS_LIB_PATH = " ${DBUS_LIB_PATH})
+ set(DBUS_INCLUDE_DIRS ${DBUS_LIB_PATH}/include/dbus-1.0 ${DBUS_LIB_PATH}/lib/dbus-1.0/include)
+ set(DBUS_LIBDIR ${DBUS_LIB_PATH}/lib)
+ set(DBUS_LIBRARIES ${DBUS_LIB_PATH}/lib/libdbus-1.so)
+else()
+ message(FATAL_ERROR "Please specify the path to your patched DBus library using -DDBUS_LIB_PATH=yourPath")
+endif()
+
+# Packages
+find_package(PkgConfig REQUIRED)
+find_package(CommonAPI 3.1.5 REQUIRED)
+find_package(CommonAPI-DBus 3.1.5 REQUIRED)
+
+#pkg_check_modules(DBUS "dbus-1 >= 1.8.4") // #to be fixed, it doesn't work so the paths are set manually (see above)
+pkg_check_modules(COMMONAPI "CommonAPI >= 3.1.5")
+pkg_check_modules(COMMONAPI_DBUS "CommonAPI-DBus >= 3.1.5")
+pkg_check_modules(GOBJECT gobject-2.0)
+pkg_check_modules(GLIB REQUIRED glib-2.0)
+
+# Add the Franca files (that will generate the CommonAPI stuff)
+set(COMMONAPI_GEN_DIR "${CMAKE_CURRENT_BINARY_DIR}/src-gen")
+add_subdirectory(${FRANCA_DIR}/hmi/speechservice "${CMAKE_CURRENT_BINARY_DIR}/franca")
+
+# Path to the generated files
+set(API_VERSION_MAJOR 4)
+set(API_VERSION "v${API_VERSION_MAJOR}")
+set(PRJ_SRC_GEN_ROOT_PATH ${COMMONAPI_GEN_DIR}/${API_VERSION}/org/genivi) #files shared by all the APIs
+set(PRJ_SRC_GEN_HMI_PATH ${PRJ_SRC_GEN_ROOT_PATH}/hmi) #files shared by the hmi APIs
+set(PRJ_SRC_GEN_SPEECHOUTPUTSERVICE_PATH ${PRJ_SRC_GEN_HMI_PATH}/speechoutputservice) #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_HMI_PATH}/*DBusStub*.cpp ${PRJ_SRC_GEN_HMI_PATH}/*Types.cpp ${PRJ_SRC_GEN_HMI_PATH}/*DBusDeployment.cpp ${PRJ_SRC_GEN_HMI_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
+ )
+FILE(GLOB PRJ_STUB_IMPL_SRCS
+ ${PRJ_SRC_GEN_ROOT_PATH}/*Stub*.cpp
+ ${PRJ_SRC_GEN_HMI_PATH}/*Stub*.cpp
+ ${PRJ_SRC_GEN_SPEECHOUTPUTSERVICE_PATH}/*Stub*.cpp
+ )
+
+set(PRJ_SRCS ${PRJ_LOCAL_SRCS} ${PRJ_STUB_GEN_SRCS} ${PRJ_STUB_IMPL_SRCS})
+
+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(
+ ${COMMONAPI_GEN_DIR}
+ ${PRJ_SRC_GEN_ROOT_PATH}
+ ${PRJ_SRC_GEN_HMI_PATH}
+ ${PRJ_SRC_GEN_SPEECHOUTPUTSERVICE_PATH}
+ ${DBUS_INCLUDE_DIRS}
+ ${COMMONAPI_INCLUDE_DIRS}
+ ${COMMONAPI_DBUS_INCLUDE_DIRS}
+ ${GOBJECT_INCLUDE_DIRS}
+ ${GLIB_INCLUDE_DIRS}
+ ${FLITE_INCLUDE_DIRS}
+)
+
+link_directories(
+ ${DBUS_LIBDIR}
+ ${COMMONAPI_LIBDIR}
+ ${COMMONAPI_DBUS_LIBDIR}
+ ${GOBJECT_LIBRARY_DIRS}
+ ${GLIB_LIBRARY_DIRS}
+ ${FLITE_LIBDIR}
+)
+
+set(LIBRARIES
+ ${DBUS_LIBRARIES}
+ ${COMMONAPI_LIBRARIES}
+ ${COMMONAPI_DBUS_LIBRARIES}
+ ${GOBJECT_LIBRARIES}
+ ${GLIB_LIBRARIES}
+ ${FLITE_LIBRARIES}
+)
+
+# Build service
+add_executable(${PROJECT_NAME} ${PRJ_SRCS})
+target_link_libraries(${PROJECT_NAME} ${LIBRARIES})
+install(TARGETS ${PROJECT_NAME} DESTINATION ${CMAKE_RUNTIME_OUTPUT_DIRECTORY})
diff --git a/src/speech/main.cpp b/src/speech/main.cpp
new file mode 100644
index 0000000..3cf0856
--- /dev/null
+++ b/src/speech/main.cpp
@@ -0,0 +1,254 @@
+/**
+* @licence app begin@
+* SPDX-License-Identifier: MPL-2.0
+*
+* \copyright Copyright (C) 2013-2014, PCA Peugeot Citroen
+*
+* \file main.cpp
+*
+* \brief This file is part of the speech proof of concept.
+*
+* \author Philippe Colliot <philippe.colliot@mpsa.com>
+*
+* \version 1.1
+*
+* 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:
+* <date>, <name>, <description of change>
+*
+* @licence end@
+*/
+
+#include <stdbool.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <iostream>
+#include <cmath>
+#include <typeinfo>
+#include <dbus-c++-1/dbus-c++/glib-integration.h>
+#include <semaphore.h>
+#include <flite.h>
+
+extern "C" {
+ cst_voice* register_cmu_us_kal(const char *voxdir);
+ void unregister_cmu_us_kal(cst_voice *vox);
+}
+
+
+#include <CommonAPI/CommonAPI.hpp>
+#include <CommonTypes.hpp>
+#include <SpeechOutputStubDefault.hpp>
+
+using namespace v4::org::genivi::hmi::speechoutputservice;
+using namespace v4::org::genivi;
+
+static std::shared_ptr < CommonAPI::Runtime > runtime;
+static const std::string domain = "local";
+
+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 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)
+ {
+ printf("\n>>> [server] processChunks()\n");
+ 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);
+}
+
+class SpeechOutputServerStub
+: public SpeechOutputStubDefault
+{
+
+public:
+
+ SpeechOutputServerStub() {
+ m_version.setVersionMajor(1);
+ m_version.setVersionMinor(0);
+ m_version.setVersionMicro(0);
+ m_version.setDate("12-10-2016");
+
+ m_lenLastChunk = 0;
+ m_slotCount = 0;
+
+ flite_init();
+
+ mp_voice = register_cmu_us_kal(NULL);
+
+ }
+
+ ~SpeechOutputServerStub() {
+ unregister_cmu_us_kal(mp_voice);
+ }
+
+ /**
+ * description: This method returns the API version implemented by the SpeechOutput.
+ */
+ void getVersion(const std::shared_ptr<CommonAPI::ClientId> _client, getVersionReply_t _reply) {
+ _reply(m_version);
+ }
+
+ /**
+ * description: Must be called to open a SpeechOutputService session and to get the audio
+ * connection.
+ */
+ void openPrompter(const std::shared_ptr<CommonAPI::ClientId> _client, SpeechOutput::ConnectionType _connectionType, SpeechOutput::PreProcessingType _preProcessingType, openPrompterReply_t _reply) {
+ printf("\n>>> [server] openPrompter()\n");
+
+ _reply();
+ }
+
+ /**
+ * 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.
+ */
+ void addTextChunk(const std::shared_ptr<CommonAPI::ClientId> _client, SpeechOutput::Chunk _chunk, addTextChunkReply_t _reply) {
+ printf("\n>>> [server] addTextChunk()\n \"%s\"\n", _chunk.c_str());
+
+ SpeechOutput::ChunkID _chunkID;
+
+ // todo: manage _chunkID
+
+ SpeechOutput::QueueStatus qStatus = SpeechOutput::QueueStatus::QS_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 = SpeechOutput::QueueStatus::QS_LOW_FILL;
+ }
+ else
+ {
+ qStatus = SpeechOutput::QueueStatus::QS_HIGH_FILL;
+ }
+ m_chunkBuffer.append(_chunk);
+ m_lenLastChunk = _chunk.size();
+ ++m_slotCount;
+ }
+ else
+ {
+ qStatus = SpeechOutput::QueueStatus::QS_FULL;
+ }
+ }
+
+ fireNotifyQueueStatusEvent(qStatus);
+
+ _reply(_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(const std::shared_ptr<CommonAPI::ClientId> _client, abortPrompterReply_t _reply) {
+ printf("\n>>> [server] abortPrompter()\n");
+
+ _reply();
+ }
+
+ /**
+ * description: The prompter is closed after the last text chunk submitted has finished playing.
+ */
+ void closePrompter(const std::shared_ptr<CommonAPI::ClientId> _client, closePrompterReply_t _reply) {
+ printf("\n>>> [server] closePrompter()\n");
+
+ _reply();
+ }
+
+
+// Specific methods
+
+
+private:
+ CommonTypes::Version m_version;
+
+};
+
+
+int main(int argc , char** argv )
+{
+ 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(""));
+
+ // Common API data init
+ runtime = CommonAPI::Runtime::get();
+ bool successfullyRegistered;
+
+ const std::string instanceSpeechOutput = "SpeechOutput";
+ std::shared_ptr<SpeechOutputServerStub> myServiceSpeechOutput = std::make_shared<SpeechOutputServerStub>();
+ successfullyRegistered = runtime->registerService(domain, instanceSpeechOutput, myServiceSpeechOutput);
+ while (!successfullyRegistered) {
+ std::this_thread::sleep_for(std::chrono::milliseconds(100));
+ successfullyRegistered = runtime->registerService(domain, instanceSpeechOutput, myServiceSpeechOutput);
+ }
+
+ 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
+ std::cout << "speech server started" << std::endl;
+
+ // loop listening
+
+ g_main_loop_run ( mainloop );
+
+
+ return EXIT_SUCCESS;
+}
diff --git a/src/speech/test-speech-capi.py b/src/speech/test-speech-capi.py
new file mode 100755
index 0000000..3ed92e1
--- /dev/null
+++ b/src/speech/test-speech-capi.py
@@ -0,0 +1,88 @@
+#!/usr/bin/python
+
+"""
+**************************************************************************
+* @licence app begin@
+* SPDX-License-Identifier: MPL-2.0
+*
+* \copyright Copyright (C) 2016, PSA GROUP
+*
+* \file test-speech-capi.py
+*
+* \brief This simple test shows how the speech
+* could be easily tested using a python script
+*
+* \author Philippe Colliot <philippe.colliot@mpsa.com>
+*
+* \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_Configuration_Settings_LOCALE = 37
+GENIVI_SearchStatusState_FINISHED = 1298
+GENIVI_SearchStatusState_NOT_STARTED = 1296
+
+#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)))
+
+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.speechoutputservice.SpeechOutput", \
+ signal_name = "notifyConnectionStatus")
+bus.add_signal_receiver(catch_speech_notifyMarkerReached_signal_handler, \
+ dbus_interface = "org.genivi.hmi.speechoutputservice.SpeechOutput", \
+ signal_name = "notifyMarkerReached")
+bus.add_signal_receiver(catch_speech_notifyQueueStatus_signal_handler, \
+ dbus_interface = "org.genivi.hmi.speechoutputservice.SpeechOutput", \
+ signal_name = "notifyQueueStatus")
+bus.add_signal_receiver(catch_speech_notifyTTSStatus_signal_handler, \
+ dbus_interface = "org.genivi.hmi.speechoutputservice.SpeechOutput", \
+ signal_name = "notifyTTSStatus")
+
+speech = bus.get_object('org.genivi.hmi.speechoutputservice.SpeechOutput_SpeechOutput','/SpeechOutput')
+g_speech_interface = dbus.Interface(speech, dbus_interface='org.genivi.hmi.speechoutputservice.SpeechOutput')
+
+g_speech_interface.addTextChunk(dbus.String("Hello"))
+
+#main loop
+gobject.timeout_add(TIME_OUT, timeout)
+loop = gobject.MainLoop()
+loop.run()