diff --git a/bom/pom.xml b/bom/pom.xml
index c0a5d2e5f..607d88f31 100644
--- a/bom/pom.xml
+++ b/bom/pom.xml
@@ -468,7 +468,7 @@
org.daisy.pipeline.modules
tts-adapter-sapinative
- 3.1.0
+ 3.1.1-SNAPSHOT
org.daisy.pipeline.modules
diff --git a/tts/tts-adapters/tts-adapter-sapinative/src/main/java/org/daisy/pipeline/tts/onecore/Onecore.java b/tts/tts-adapters/tts-adapter-sapinative/src/main/java/org/daisy/pipeline/tts/onecore/Onecore.java
index 12ef130cc..90a6702da 100644
--- a/tts/tts-adapters/tts-adapter-sapinative/src/main/java/org/daisy/pipeline/tts/onecore/Onecore.java
+++ b/tts/tts-adapters/tts-adapter-sapinative/src/main/java/org/daisy/pipeline/tts/onecore/Onecore.java
@@ -1,12 +1,14 @@
package org.daisy.pipeline.tts.onecore;
+import java.io.IOException;
+
public class Onecore {
public static native long openConnection();
public static native int closeConnection(long connection);
- public static native int speak(long connection, String voiceVendor, String voiceName, String text);
+ public static native int speak(long connection, String voiceVendor, String voiceName, String text) throws IOException;
/* in bytes*/
public static native int getStreamSize(long connection);
diff --git a/tts/tts-adapters/tts-adapter-sapinative/src/main/java/org/daisy/pipeline/tts/onecore/SAPI.java b/tts/tts-adapters/tts-adapter-sapinative/src/main/java/org/daisy/pipeline/tts/onecore/SAPI.java
index 35c6be3c1..7260e7cb9 100644
--- a/tts/tts-adapters/tts-adapter-sapinative/src/main/java/org/daisy/pipeline/tts/onecore/SAPI.java
+++ b/tts/tts-adapters/tts-adapter-sapinative/src/main/java/org/daisy/pipeline/tts/onecore/SAPI.java
@@ -1,12 +1,14 @@
package org.daisy.pipeline.tts.onecore;
+import java.io.IOException;
+
public class SAPI {
- public static native long openConnection();
+ public static native long openConnection() throws IOException;
public static native int closeConnection(long connection);
- public static native int speak(long connection, String voiceVendor, String voiceName, String text);
+ public static native int speak(long connection, String voiceVendor, String voiceName, String text) throws IOException;
/* in bytes*/
public static native int getStreamSize(long connection);
diff --git a/tts/tts-adapters/tts-adapter-sapinative/src/main/java/org/daisy/pipeline/tts/sapi/impl/SAPIEngine.java b/tts/tts-adapters/tts-adapter-sapinative/src/main/java/org/daisy/pipeline/tts/sapi/impl/SAPIEngine.java
index 82f43b596..7930b63ef 100644
--- a/tts/tts-adapters/tts-adapter-sapinative/src/main/java/org/daisy/pipeline/tts/sapi/impl/SAPIEngine.java
+++ b/tts/tts-adapters/tts-adapter-sapinative/src/main/java/org/daisy/pipeline/tts/sapi/impl/SAPIEngine.java
@@ -79,8 +79,8 @@ public SynthesisResult synthesize(XdmNode ssml, Voice voice, TTSResource resourc
}
try {
List marks = new ArrayList<>();
- AudioInputStream audio = speak(transformSsmlNodeToString(ssml, ssmlTransformer, xsltParams),
- voice, resource, marks);
+ String ssmlForEngine = transformSsmlNodeToString(ssml, ssmlTransformer, xsltParams);
+ AudioInputStream audio = speak(ssmlForEngine, voice, resource, marks);
return new SynthesisResult(audio, marks);
} catch (IOException|SaxonApiException e) {
throw new SynthesisException(e);
@@ -93,33 +93,54 @@ public AudioInputStream speak(String ssml, Voice voice, TTSResource resource, Li
voice = mVoiceFormatConverter.get(voice.name.toLowerCase());
ThreadResource tr = (ThreadResource)resource;
if (voice.engine.equals("sapi") ){
- int res = SAPI.speak(tr.SAPIConnection, voice.engine, voice.name, ssml);
- if (res != SAPIResult.SAPINATIVE_OK.value()) {
- throw new SynthesisException("SAPI-legacy speak error " + res + " raised with voice "
- + voice + ": " + SAPIResult.valueOfCode(res)+"\nFor text :"
- + ssml);
+ try {
+ int res = SAPI.speak(tr.SAPIConnection, voice.engine, voice.name, ssml);
+ if (res != SAPIResult.SAPINATIVE_OK.value()) {
+ throw new SynthesisException("SAPI-legacy speak error " + res + " raised with voice "
+ + voice + ": " + SAPIResult.valueOfCode(res)+"\nFor text :"
+ + ssml);
+ }
+ } catch (RuntimeException e){
+ Logger.error("SAPI-legacy raised a RUNTIME exception while speaking " + ssml + " with " + voice + " : " + e.getMessage());
+ throw new SynthesisException("SAPI-legacy raised a RUNTIME exception while speaking " + ssml + " with " + voice, e);
+ } catch (Exception e){
+ Logger.error("SAPI-legacy raised an exception while speaking " + ssml + " with " + voice + " : " + e.getMessage());
+ throw new SynthesisException("SAPI-legacy raised an exception while speaking " + ssml + " with " + voice, e);
}
+
int size = SAPI.getStreamSize(tr.SAPIConnection);
byte[] data = new byte[size];
SAPI.readStream(tr.SAPIConnection, data, 0);
- long[] bookmarksPositions = SAPI.getBookmarkPositions(tr.SAPIConnection);
+
+ String[] names = SAPI.getBookmarkNames(tr.SAPIConnection);
+ long[] positions = SAPI.getBookmarkPositions(tr.SAPIConnection);
float sampleRate = sapiAudioFormat.getSampleRate();
int bytesPerSample = sapiAudioFormat.getSampleSizeInBits() / 8;
- for (long position : bookmarksPositions) {
- int offset = (int) ((position * sampleRate * bytesPerSample) / 1000);
- marks.add(offset);
+ for (int i = 0; i < names.length; ++i) {
+ int offset = (int) ((positions[i] * sampleRate * bytesPerSample) / 1000);
+ // it happens that SAPI / OneCore sometimes make empty bookmarks (for unknown reason)
+ if (names[i].length() > 0){
+ marks.add(offset);
+ }
}
return createAudioStream(sapiAudioFormat, data);
} else { // use onecore engine
- int res = Onecore.speak(tr.onecoreConnection, voice.engine, voice.name, ssml);
- if (res != OnecoreResult.SAPINATIVE_OK.value()) {
- throw new SynthesisException("SAPI-Onecore speak error " + res + " raised with voice "
- + voice + ": " + OnecoreResult.valueOfCode(res)+"\nFor text :"
- + ssml);
+ try {
+ int res = Onecore.speak(tr.onecoreConnection, voice.engine, voice.name, ssml);
+ if (res != OnecoreResult.SAPINATIVE_OK.value()) {
+ throw new SynthesisException("SAPI-Onecore speak error " + res + " raised with voice "
+ + voice + ": " + OnecoreResult.valueOfCode(res)+"\nFor text :"
+ + ssml);
+ }
+ } catch (IOException e) {
+ Logger.error("SAPI-onecore raised an exception while speaking " + ssml + " with " + voice + " : " + e.getMessage());
+ throw new SynthesisException("SAPI-Onecore raised an exception while speaking " + ssml + " with " + voice, e);
}
+
int size = Onecore.getStreamSize(tr.onecoreConnection);
byte[] data = new byte[size];
Onecore.readStream(tr.onecoreConnection, data, 0);
+ String[] names = Onecore.getBookmarkNames(tr.onecoreConnection);
long[] pos = Onecore.getBookmarkPositions(tr.onecoreConnection);
AudioInputStream result;
try {
@@ -130,9 +151,12 @@ public AudioInputStream speak(String ssml, Voice voice, TTSResource resource, Li
AudioFormat resultFormat = result.getFormat();
float sampleRate = resultFormat.getSampleRate();
int bytesPerSample = resultFormat.getSampleSizeInBits() / 8;
- for (long po : pos) {
- int offset = (int) ((po * sampleRate * bytesPerSample) / 1000);
- marks.add(offset);
+ for (int i = 0; i < names.length; ++i) {
+ int offset = (int) ((pos[i] * sampleRate * bytesPerSample) / 1000);
+ // it happens that SAPI / OneCore sometimes make empty bookmarks (for unknown reason)
+ if (names[i].length() > 0){
+ marks.add(offset);
+ }
}
return result;
}
@@ -149,11 +173,17 @@ public TTSResource allocateThreadResources() throws SynthesisException {
tr.onecoreConnection = connection;
}
if (this.sapiAudioFormat != null){
- long connection = SAPI.openConnection();
- if (connection == 0) {
- throw new SynthesisException("could not open SAPI-Onecore context.");
+ try {
+ long connection = SAPI.openConnection();
+ if (connection == 0) {
+ throw new IOException("could not connect to SAPI-Legacy context.");
+ }
+ tr.SAPIConnection = connection;
+ } catch (IOException e) {
+ throw new SynthesisException("could not open SAPI-Legacy context.", e);
}
- tr.SAPIConnection = connection;
+
+
}
return tr;
}
@@ -224,8 +254,14 @@ public Collection getAvailableVoices() {
// Note that since onecore voice are added after sapi,
// they are overwriting matching sapi voices to avoid duplicates
try {
+ // remove the "desktop" extension of SAPI legacy microsoft voices
+ // So that onecore voices are used instead if available
+ String key = names.get(i).toLowerCase();
+ if (key.endsWith(" desktop")) {
+ key = key.substring(0,key.length() - " desktop".length());
+ }
mVoiceFormatConverter.put(
- names.get(i).toLowerCase(),
+ key,
new Voice(
vendors.get(i),
names.get(i),
diff --git a/tts/tts-adapters/tts-adapter-sapinative/src/main/jni/jni_helper.h b/tts/tts-adapters/tts-adapter-sapinative/src/main/jni/jni_helper.h
index 449ea8a82..d789f505a 100644
--- a/tts/tts-adapters/tts-adapter-sapinative/src/main/jni/jni_helper.h
+++ b/tts/tts-adapters/tts-adapter-sapinative/src/main/jni/jni_helper.h
@@ -47,4 +47,6 @@ jobjectArray newJavaArray(JNIEnv* env, Iterator items, size_t size, const char*
return jArray;
}
+void raiseIOException(JNIEnv* env, const jchar* message, size_t len);
+
#endif
\ No newline at end of file
diff --git a/tts/tts-adapters/tts-adapter-sapinative/src/main/jni/onecorenative/jni_helper.cpp b/tts/tts-adapters/tts-adapter-sapinative/src/main/jni/onecorenative/jni_helper.cpp
index 0840c25a3..cfd5739c1 100644
--- a/tts/tts-adapters/tts-adapter-sapinative/src/main/jni/onecorenative/jni_helper.cpp
+++ b/tts/tts-adapters/tts-adapter-sapinative/src/main/jni/onecorenative/jni_helper.cpp
@@ -20,4 +20,12 @@ jobjectArray emptyJavaArray(JNIEnv* env, const char* javaClass, int size) {
jclass objClass = env->FindClass(javaClass);
jobjectArray jArray = env->NewObjectArray(size, objClass, 0);
return jArray;
-}
\ No newline at end of file
+}
+
+void raiseIOException(JNIEnv* env, const jchar* message, size_t len ) {
+ jclass exceptionClass = env->FindClass("java/io/IOException");
+ jmethodID construtor = env->GetMethodID(exceptionClass, "", "(Ljava/lang/String;)V");
+ jstring messageJava = env->NewString(message, len);
+ jobject except = env->NewObject(exceptionClass, construtor, messageJava);
+ env->Throw((jthrowable)except);
+}
diff --git a/tts/tts-adapters/tts-adapter-sapinative/src/main/jni/onecorenative/org_daisy_pipeline_tts_onecore_Onecore.cpp b/tts/tts-adapters/tts-adapter-sapinative/src/main/jni/onecorenative/org_daisy_pipeline_tts_onecore_Onecore.cpp
index ab57ea76a..11c4c8b49 100644
--- a/tts/tts-adapters/tts-adapter-sapinative/src/main/jni/onecorenative/org_daisy_pipeline_tts_onecore_Onecore.cpp
+++ b/tts/tts-adapters/tts-adapter-sapinative/src/main/jni/onecorenative/org_daisy_pipeline_tts_onecore_Onecore.cpp
@@ -36,9 +36,6 @@ ConnectionsRegistry* openedConnection = NULL;
///////////////////////////////////////
JNIEXPORT jint JNICALL Java_org_daisy_pipeline_tts_onecore_Onecore_initialize(JNIEnv* env, jclass) {
-#if _DEBUG
- std::wcout << "Initializing Onecore" << std::endl;
-#endif
gAllVoices = new OneCoreVoice::Map();
winrtConnection temp = winrtConnection();
for each (auto rawVoice in temp.voices())
@@ -59,7 +56,7 @@ JNIEXPORT jint JNICALL Java_org_daisy_pipeline_tts_onecore_Onecore_initialize(JN
voice
));
}
- openedConnection = new ConnectionsRegistry();
+ openedConnection = new ConnectionsRegistry(1024);
return SAPI_OK;
}
@@ -72,9 +69,6 @@ JNIEXPORT jlong JNICALL Java_org_daisy_pipeline_tts_onecore_Onecore_openConnecti
}
JNIEXPORT jint JNICALL Java_org_daisy_pipeline_tts_onecore_Onecore_closeConnection(JNIEnv*, jclass, jlong connection) {
-#if _DEBUG
- std::wcout << "Closing onecore connection " << connection << std::endl;
-#endif
Connection* conn = reinterpret_cast(connection);
if (conn != NULL) {
delete conn;
@@ -91,16 +85,10 @@ JNIEXPORT jint JNICALL Java_org_daisy_pipeline_tts_onecore_Onecore_closeConnecti
JNIEXPORT jint JNICALL Java_org_daisy_pipeline_tts_onecore_Onecore_dispose(JNIEnv*, jclass) {
-#if _DEBUG
- std::wcout << "Disposing of Onecore" << std::endl;
-#endif
// Close remaining connections
if (openedConnection != NULL) {
for (ConnectionsRegistry::iterator it = openedConnection->begin(); it != openedConnection->end(); ++it) {
-#if _DEBUG
- std::wcout << "- Cleaning onecore connection " << *it << std::endl;
-#endif
Connection* conn = reinterpret_cast(*it);
delete conn;
}
@@ -135,25 +123,29 @@ JNIEXPORT jint JNICALL Java_org_daisy_pipeline_tts_onecore_Onecore_speak(JNIEnv*
if (!(convertToUTF16(env, text, conn->sentence, MAX_SENTENCE_SIZE)))
return TOO_LONG_TEXT;
-#if _DEBUG
- std::wcout << it->second.name << " speaking " << conn->sentence << std::endl;
-#endif
- // VoiceInformation seems to create an exception, so we use the voice display name for now
- winrt::hstring ssmltext = winrt::hstring(conn->sentence);
- winrt::hstring foundVoiceName = it->second.rawVoice;
+ // VoiceInformation seems to create an exception, so we use the voice display name for now
+ winrt::hstring ssmltext = winrt::hstring(conn->sentence);
+ winrt::hstring foundVoiceName = it->second.rawVoice;
- try {
- conn->streamData = conn->onecore.speak(ssmltext, foundVoiceName);
- conn->marksNames = conn->onecore.marksNames();
- conn->marksPositions = conn->onecore.marksPositions();
- }
- catch (winrt::hresult_error const& ex)
- {
- winrt::hresult hr = ex.code();
- winrt::hstring message = ex.message();
- std::wcout << "Exception raised while speaking " << conn->sentence << std::endl << "With voice " << it->second.name << " : " << std::endl;
- std::cout << message.c_str() << std::endl;
- }
+ try {
+ conn->streamData = conn->onecore.speak(ssmltext, foundVoiceName);
+ conn->marksNames = conn->onecore.marksNames();
+ conn->marksPositions = conn->onecore.marksPositions();
+ }
+ catch (winrt::hresult_error const& ex)
+ {
+
+ winrt::hresult hr = ex.code();
+ std::wstring message = std::wstring(ex.message().c_str());
+ std::wstring sentence = std::wstring(conn->sentence);
+ std::wostringstream excep;
+ excep << L"Error code (0x" << std::hex << hr.value << L") raised when trying to speak with OneCore SAPI" << std::endl;
+ excep << message << std::endl;
+ // Use exception instead of return result to get error code in java
+ raiseIOException(env, (const jchar*)excep.str().c_str(), excep.str().size());
+ return COULD_NOT_SPEAK;
+
+ }
return SAPI_OK;
}
@@ -191,9 +183,6 @@ struct VoiceVendorToJString {
}
};
JNIEXPORT jobjectArray JNICALL Java_org_daisy_pipeline_tts_onecore_Onecore_getVoiceVendors(JNIEnv* env, jclass) {
-#if _DEBUG
- std::wcout << "Getting voice vendors" << std::endl;
-#endif
if (gAllVoices != NULL) {
return newJavaArray(
env,
@@ -213,9 +202,6 @@ struct VoiceNameToJString {
}
};
JNIEXPORT jobjectArray JNICALL Java_org_daisy_pipeline_tts_onecore_Onecore_getVoiceNames(JNIEnv* env, jclass) {
-#if _DEBUG
- std::wcout << "Getting voice names" << std::endl;
-#endif
if (gAllVoices != NULL) {
return newJavaArray(
env,
@@ -235,9 +221,6 @@ struct VoiceLocaleToJString {
}
};
JNIEXPORT jobjectArray JNICALL Java_org_daisy_pipeline_tts_onecore_Onecore_getVoiceLocales(JNIEnv* env, jclass) {
-#if _DEBUG
- std::wcout << "Getting voice locales" << std::endl;
-#endif
if (gAllVoices != NULL) {
return newJavaArray(
env,
@@ -258,9 +241,6 @@ struct VoiceGenderToJString {
};
JNIEXPORT jobjectArray JNICALL Java_org_daisy_pipeline_tts_onecore_Onecore_getVoiceGenders(JNIEnv* env, jclass)
{
-#if _DEBUG
- std::wcout << "Getting voice genders" << std::endl;
-#endif
if (gAllVoices != NULL) {
return newJavaArray(
env,
@@ -280,9 +260,6 @@ struct VoiceAgeToJString {
};
JNIEXPORT jobjectArray JNICALL Java_org_daisy_pipeline_tts_onecore_Onecore_getVoiceAges(JNIEnv* env, jclass)
{
-#if _DEBUG
- std::wcout << "Getting voice ages" << std::endl;
-#endif
if (gAllVoices != NULL) {
return newJavaArray(
env,
diff --git a/tts/tts-adapters/tts-adapter-sapinative/src/main/jni/onecorenative/pch.h b/tts/tts-adapters/tts-adapter-sapinative/src/main/jni/onecorenative/pch.h
index 7def6ed5f..089ba27ea 100644
--- a/tts/tts-adapters/tts-adapter-sapinative/src/main/jni/onecorenative/pch.h
+++ b/tts/tts-adapters/tts-adapter-sapinative/src/main/jni/onecorenative/pch.h
@@ -1,5 +1,6 @@
#pragma once
#include
+#include
#include
#include
#include
diff --git a/tts/tts-adapters/tts-adapter-sapinative/src/main/jni/sapinative/jni_helper.cpp b/tts/tts-adapters/tts-adapter-sapinative/src/main/jni/sapinative/jni_helper.cpp
index 0840c25a3..8ec0d8a08 100644
--- a/tts/tts-adapters/tts-adapter-sapinative/src/main/jni/sapinative/jni_helper.cpp
+++ b/tts/tts-adapters/tts-adapter-sapinative/src/main/jni/sapinative/jni_helper.cpp
@@ -20,4 +20,12 @@ jobjectArray emptyJavaArray(JNIEnv* env, const char* javaClass, int size) {
jclass objClass = env->FindClass(javaClass);
jobjectArray jArray = env->NewObjectArray(size, objClass, 0);
return jArray;
-}
\ No newline at end of file
+}
+
+void raiseIOException(JNIEnv* env, const jchar* message, size_t len) {
+ jclass exceptionClass = env->FindClass("java/lang/Exception");
+ jmethodID construtor = env->GetMethodID(exceptionClass, "", "(Ljava/lang/String;)V");
+ jstring messageJava = env->NewString(message, len);
+ jobject except = env->NewObject(exceptionClass, construtor, messageJava);
+ env->Throw((jthrowable)except);
+}
diff --git a/tts/tts-adapters/tts-adapter-sapinative/src/main/jni/sapinative/org_daisy_pipeline_tts_onecore_SAPI.cpp b/tts/tts-adapters/tts-adapter-sapinative/src/main/jni/sapinative/org_daisy_pipeline_tts_onecore_SAPI.cpp
index 464546d94..0d2919f9a 100644
--- a/tts/tts-adapters/tts-adapter-sapinative/src/main/jni/sapinative/org_daisy_pipeline_tts_onecore_SAPI.cpp
+++ b/tts/tts-adapters/tts-adapter-sapinative/src/main/jni/sapinative/org_daisy_pipeline_tts_onecore_SAPI.cpp
@@ -85,9 +85,6 @@ ConnectionsRegistry* openedConnection = NULL;
JNIEXPORT jint JNICALL Java_org_daisy_pipeline_tts_onecore_SAPI_initialize(JNIEnv* env, jclass, jint sampleRate, jshort bitsPerSample) {
-#if _DEBUG
- std::wcout << "Initializing SAPI" << std::endl;
-#endif
if (bitsPerSample != 8 && bitsPerSample != 16)
return UNSUPPORTED_AUDIO_FORMAT;
@@ -110,7 +107,7 @@ JNIEXPORT jint JNICALL Java_org_daisy_pipeline_tts_onecore_SAPI_initialize(JNIEn
gWaveFormat->nAvgBytesPerSec = gWaveFormat->nBlockAlign * gWaveFormat->nSamplesPerSec;
gWaveFormat->cbSize = 0;
- openedConnection = new ConnectionsRegistry();
+ openedConnection = new ConnectionsRegistry(1024);
HRESULT hr;
hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
@@ -183,9 +180,6 @@ JNIEXPORT jint JNICALL Java_org_daisy_pipeline_tts_onecore_SAPI_initialize(JNIEn
// but the use of "sapi" as vendor could lead to errors in voice
// identification if some vendors decided to provided voices with the same
// name
-#if _DEBUG
- std::wcout << L"Registering voice " << L"sapi" << " : " << name << std::endl;
-#endif
gAllVoices->insert(std::make_pair(
std::pair(L"sapi", name),
Voice(cpToken,
@@ -203,9 +197,6 @@ JNIEXPORT jint JNICALL Java_org_daisy_pipeline_tts_onecore_SAPI_initialize(JNIEn
else cpToken->Release();
}
}
-#if _DEBUG
- std::wcout << "Done" << std::endl;
-#endif
cpEnum->Release();
category->Release();
@@ -213,14 +204,16 @@ JNIEXPORT jint JNICALL Java_org_daisy_pipeline_tts_onecore_SAPI_initialize(JNIEn
}
-JNIEXPORT jlong JNICALL Java_org_daisy_pipeline_tts_onecore_SAPI_openConnection(JNIEnv*, jclass) {
-
+JNIEXPORT jlong JNICALL Java_org_daisy_pipeline_tts_onecore_SAPI_openConnection(JNIEnv* env, jclass) {
Connection* conn = new Connection();
HRESULT hr;
hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
//hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
if (hr != S_OK && hr != S_FALSE) {
- std::wcout << "SAPI - COM server not initialized for the connection attempt" << std::endl;
+ std::wostringstream excep;
+ excep << L"SAPI - COM server not initialized for the connection attempt" << std::endl;
+ // Use exception instead of return result to get error code in java
+ raiseIOException(env, (const jchar*)excep.str().c_str(), excep.str().size());
return 0;
}
hr = CoCreateInstance(CLSID_SpVoice, NULL, CLSCTX_ALL, IID_ISpVoice, (void**)(&conn->spVoice));
@@ -236,27 +229,24 @@ JNIEXPORT jlong JNICALL Java_org_daisy_pipeline_tts_onecore_SAPI_openConnection(
(LPTSTR)&errorText,
0,
NULL);
- std::wcout << "Could not create a Voice instance: " << std::endl;
- std::wcout << errorText << std::endl;
+ std::wostringstream excep;
+ excep << L"Could not create a Voice instance: " << std::endl;
+ excep << errorText << std::endl;
LocalFree(errorText);
+ raiseIOException(env, (const jchar*)excep.str().c_str(), excep.str().size());
errorText = NULL;
delete conn;
return 0;
}
conn->spVoice->AddRef();
jlong connectionPtr = reinterpret_cast(conn);
-#if _DEBUG
- std::wcout << "New connection opened with the pipeline : " << connectionPtr << std::endl;
-#endif
// Add connection ptr on registry
openedConnection->push_back(connectionPtr);
return connectionPtr;
}
-JNIEXPORT jint JNICALL Java_org_daisy_pipeline_tts_onecore_SAPI_closeConnection(JNIEnv*, jclass, jlong connection) {
-#if _DEBUG
- std::wcout << "Closing SAPI connection " << connection << std::endl;
-#endif
+JNIEXPORT jint JNICALL Java_org_daisy_pipeline_tts_onecore_SAPI_closeConnection(JNIEnv*, jclass, jlong connection)
+{
{
Connection* conn = reinterpret_cast(connection);
if (conn != NULL) {
@@ -275,8 +265,8 @@ JNIEXPORT jint JNICALL Java_org_daisy_pipeline_tts_onecore_SAPI_closeConnection(
return SAPI_OK;
}
-JNIEXPORT jint JNICALL Java_org_daisy_pipeline_tts_onecore_SAPI_speak(JNIEnv* env, jclass, jlong connection, jstring voiceVendor, jstring voiceName, jstring text) {
-
+JNIEXPORT jint JNICALL Java_org_daisy_pipeline_tts_onecore_SAPI_speak(JNIEnv* env, jclass, jlong connection, jstring voiceVendor, jstring voiceName, jstring text)
+{
wchar_t c_vendor[MAX_VOICE_NAME_SIZE / sizeof(wchar_t)];
if (!(convertToUTF16(env, voiceVendor, c_vendor, MAX_VOICE_NAME_SIZE)))
return TOO_LONG_VOICE_VENDOR;
@@ -287,9 +277,6 @@ JNIEXPORT jint JNICALL Java_org_daisy_pipeline_tts_onecore_SAPI_speak(JNIEnv* en
SapiVoice::Map::iterator it;
if (gAllVoices != NULL) {
-#if _DEBUG
- std::wcout << L"Looking for voice " << c_vendor << " : " << c_name << std::endl;
-#endif
it = gAllVoices->find(std::make_pair(c_vendor, c_name));
if (it == gAllVoices->end()) return VOICE_NOT_FOUND;
} else {
@@ -392,7 +379,7 @@ JNIEXPORT jint JNICALL Java_org_daisy_pipeline_tts_onecore_SAPI_speak(JNIEnv* en
return COULD_NOT_BIND_OUTPUT;
}
// Start recording
- // Fixing ssml speak tag to add xml:lang
+ // Fixing ssml speak tag to add xml:lang
std::wstring sentence = std::wstring(conn->sentence);
std::basic_regex tagSearch(
L"xml:lang=",
@@ -408,83 +395,78 @@ JNIEXPORT jint JNICALL Java_org_daisy_pipeline_tts_onecore_SAPI_speak(JNIEnv* en
sentence = std::regex_replace(sentence, speakTagSearch, newTagStream.str());
}
-#if _DEBUG
- else {
- std::wcout << L"Text contains an 'xml:lang' attribute" << std::endl;
- }
- std::wcout << L"SAPI " << c_name << L" Speaking " << sentence << std::endl;
-#endif
conn->qStream.startWritingPhase();
-
- hr = conn->spVoice->Speak(sentence.c_str(), CLIENT_SPEAK_FLAGS, 0);
- if (hr == E_INVALIDARG)
- return COULD_NOT_SPEAK_INVALIDARG;
+ try {
+ hr = conn->spVoice->Speak(sentence.c_str(), CLIENT_SPEAK_FLAGS, 0);
+ if (hr == E_INVALIDARG)
+ return COULD_NOT_SPEAK_INVALIDARG;
- if (hr == E_POINTER)
- return COULD_NOT_SPEAK_E_POINTER;
+ if (hr == E_POINTER)
+ return COULD_NOT_SPEAK_E_POINTER;
- if (hr == E_OUTOFMEMORY)
- return COULD_NOT_SPEAK_OUTOFMEMORY;
+ if (hr == E_OUTOFMEMORY)
+ return COULD_NOT_SPEAK_OUTOFMEMORY;
- if (hr == SPERR_INVALID_FLAGS)
- return COULD_NOT_SPEAK_INVALIDFLAGS;
+ if (hr == SPERR_INVALID_FLAGS)
+ return COULD_NOT_SPEAK_INVALIDFLAGS;
- if (hr == SPERR_DEVICE_BUSY)
- return COULD_NOT_SPEAK_BUSY;
+ if (hr == SPERR_DEVICE_BUSY)
+ return COULD_NOT_SPEAK_BUSY;
- if (hr == SPERR_UNSUPPORTED_FORMAT)
- return COULD_NOT_SPEAK_THIS_FORMAT;
+ if (hr == SPERR_UNSUPPORTED_FORMAT)
+ return COULD_NOT_SPEAK_THIS_FORMAT;
- if (hr != S_OK) {
- return COULD_NOT_SPEAK;
- }
+ if (hr != S_OK) {
+ std::wostringstream excep;
+ excep << L"Unknown error code (0x" << std::hex << hr <sentence) << std::endl << L"With voice " << it->second.name << std::endl;
+ // Raise exception to also get the error code from SAPI
+ raiseIOException(env, (const jchar*)excep.str().c_str(), excep.str().size());
+ return COULD_NOT_SPEAK;
+ }
- conn->currentBookmarkIndex = 0;
- jlong duration = 0; //in milliseconds
- bool end = false;
- HRESULT eventFound = S_FALSE;
- do {
-#if _DEBUG
- std::wcout << "Waiting for an event with " << (end ? "5000 ms" : "no") << " time out" << std::endl;
-#endif
- // wait for a possible last event after end
- conn->spVoice->WaitForNotifyEvent(INFINITE);
- SPEVENT event;
- eventFound = S_FALSE;
+ conn->currentBookmarkIndex = 0;
+ jlong duration = 0; //in milliseconds
+ bool end = false;
+ HRESULT eventFound = S_FALSE;
do {
- memset(&event, 0, sizeof(SPEVENT));
- eventFound = conn->spVoice->GetEvents(1, &event, NULL);
- if (eventFound == S_OK) {
-#if _DEBUG
- std::wcout << "event found : " << event.eEventId << std::endl;
-#endif
- switch (event.eEventId) {
- case SPEI_VISEME:
- duration += HIWORD(event.wParam);
- break;
- case SPEI_END_INPUT_STREAM:
- end = true;
- break;
- case SPEI_TTS_BOOKMARK:
- if (conn->currentBookmarkIndex == conn->bookmarkNames.size()) {
- int newsize = 1 + (3 * static_cast(conn->bookmarkNames.size())) / 2;
- conn->bookmarkNames.resize(newsize);
- conn->bookmarkPositions.resize(newsize);
+ // wait for a possible last event after end
+ conn->spVoice->WaitForNotifyEvent(INFINITE);
+ SPEVENT event;
+ eventFound = S_FALSE;
+ do {
+ memset(&event, 0, sizeof(SPEVENT));
+ eventFound = conn->spVoice->GetEvents(1, &event, NULL);
+ if (eventFound == S_OK) {
+ switch (event.eEventId) {
+ case SPEI_VISEME:
+ duration += HIWORD(event.wParam);
+ break;
+ case SPEI_END_INPUT_STREAM:
+ end = true;
+ break;
+ case SPEI_TTS_BOOKMARK:
+ if (conn->currentBookmarkIndex == conn->bookmarkNames.size()) {
+ int newsize = 1 + (3 * static_cast(conn->bookmarkNames.size())) / 2;
+ conn->bookmarkNames.resize(newsize);
+ conn->bookmarkPositions.resize(newsize);
+ }
+ //bookmarks are not pushed_back to prevent allocating/releasing all over the place
+ conn->bookmarkNames[conn->currentBookmarkIndex] = (const wchar_t*)(event.lParam);
+ conn->bookmarkPositions[conn->currentBookmarkIndex] = duration;
+ ++(conn->currentBookmarkIndex);
+ break;
}
- //bookmarks are not pushed_back to prevent allocating/releasing all over the place
- conn->bookmarkNames[conn->currentBookmarkIndex] = (const wchar_t*)(event.lParam);
- conn->bookmarkPositions[conn->currentBookmarkIndex] = duration;
- ++(conn->currentBookmarkIndex);
-#if _DEBUG
- std::wcout << "found mark " << (const wchar_t*)(event.lParam) << std::endl;
-#endif
- break;
}
- }
- } while (eventFound == S_OK);
- } while (!end);
-
+ } while (eventFound == S_OK);
+ } while (!end);
+ }
+ catch (const std::exception& e) {
+ std::wostringstream excep;
+ excep << L"Exception raised while speaking " << std::wstring(conn->sentence) << std::endl << L"With voice " << it->second.name << L" : " << std::endl;
+ excep << e.what() << std::endl;
+ raiseIOException(env, (const jchar*)excep.str().c_str(), excep.str().size());
+ }
conn->qStream.endWritingPhase();
// end recording
return SAPI_OK;
@@ -492,12 +474,14 @@ JNIEXPORT jint JNICALL Java_org_daisy_pipeline_tts_onecore_SAPI_speak(JNIEnv* en
-JNIEXPORT jint JNICALL Java_org_daisy_pipeline_tts_onecore_SAPI_getStreamSize(JNIEnv*, jclass, jlong connection) {
+JNIEXPORT jint JNICALL Java_org_daisy_pipeline_tts_onecore_SAPI_getStreamSize(JNIEnv*, jclass, jlong connection)
+{
Connection* conn = reinterpret_cast(connection);
return conn->qStream.in_avail();
}
-JNIEXPORT jint JNICALL Java_org_daisy_pipeline_tts_onecore_SAPI_readStream(JNIEnv* env, jclass, jlong connection, jbyteArray dest, jint offset) {
+JNIEXPORT jint JNICALL Java_org_daisy_pipeline_tts_onecore_SAPI_readStream(JNIEnv* env, jclass, jlong connection, jbyteArray dest, jint offset)
+{
Connection* conn = reinterpret_cast(connection);
//the array 'dest' is assumed to be big enough thanks to
@@ -519,10 +503,8 @@ struct VoiceVendorToJString {
return env->NewString((const jchar*)str, static_cast(std::wcslen(str)));
}
};
-JNIEXPORT jobjectArray JNICALL Java_org_daisy_pipeline_tts_onecore_SAPI_getVoiceVendors(JNIEnv* env, jclass) {
-#if _DEBUG
- std::wcout << "Getting voice vendors" << std::endl;
-#endif
+JNIEXPORT jobjectArray JNICALL Java_org_daisy_pipeline_tts_onecore_SAPI_getVoiceVendors(JNIEnv* env, jclass)
+{
if (gAllVoices != NULL) {
return newJavaArray(
env,
@@ -543,10 +525,8 @@ struct VoiceNameToJString {
}
};
-JNIEXPORT jobjectArray JNICALL Java_org_daisy_pipeline_tts_onecore_SAPI_getVoiceNames(JNIEnv* env, jclass) {
-#if _DEBUG
- std::wcout << "Getting voice names" << std::endl;
-#endif
+JNIEXPORT jobjectArray JNICALL Java_org_daisy_pipeline_tts_onecore_SAPI_getVoiceNames(JNIEnv* env, jclass)
+{
if (gAllVoices != NULL) {
return newJavaArray(
env,
@@ -565,10 +545,8 @@ struct VoiceLocaleToJString {
return env->NewString((const jchar*)str, static_cast(std::wcslen(str)));
}
};
-JNIEXPORT jobjectArray JNICALL Java_org_daisy_pipeline_tts_onecore_SAPI_getVoiceLocales(JNIEnv* env, jclass) {
-#if _DEBUG
- std::wcout << "Getting voice locales" << std::endl;
-#endif
+JNIEXPORT jobjectArray JNICALL Java_org_daisy_pipeline_tts_onecore_SAPI_getVoiceLocales(JNIEnv* env, jclass)
+{
if (gAllVoices != NULL) {
return newJavaArray(
env,
@@ -589,9 +567,6 @@ struct VoiceGenderToJString {
};
JNIEXPORT jobjectArray JNICALL Java_org_daisy_pipeline_tts_onecore_SAPI_getVoiceGenders(JNIEnv* env, jclass)
{
-#if _DEBUG
- std::wcout << "Getting voice genders" << std::endl;
-#endif
if (gAllVoices != NULL) {
return newJavaArray(
env,
@@ -611,9 +586,6 @@ struct VoiceAgeToJString {
};
JNIEXPORT jobjectArray JNICALL Java_org_daisy_pipeline_tts_onecore_SAPI_getVoiceAges(JNIEnv* env, jclass)
{
-#if _DEBUG
- std::wcout << "Getting voice ages" << std::endl;
-#endif
if (gAllVoices != NULL) {
return newJavaArray(
env,
@@ -638,13 +610,14 @@ JNIEXPORT jobjectArray JNICALL Java_org_daisy_pipeline_tts_onecore_SAPI_getBookm
return newJavaArray::iterator, BookMarkNamesToJString>(
env,
conn->bookmarkNames.begin(),
- conn->currentBookmarkIndex,
+ (size_t) conn->currentBookmarkIndex,
"java/lang/String"
);
}
-JNIEXPORT jlongArray JNICALL Java_org_daisy_pipeline_tts_onecore_SAPI_getBookmarkPositions(JNIEnv* env, jclass, jlong connection) {
+JNIEXPORT jlongArray JNICALL Java_org_daisy_pipeline_tts_onecore_SAPI_getBookmarkPositions(JNIEnv* env, jclass, jlong connection)
+{
Connection* conn = reinterpret_cast(connection);
jlongArray result = env->NewLongArray(conn->currentBookmarkIndex);
@@ -654,19 +627,13 @@ JNIEXPORT jlongArray JNICALL Java_org_daisy_pipeline_tts_onecore_SAPI_getBookmar
return result;
}
-JNIEXPORT jint JNICALL Java_org_daisy_pipeline_tts_onecore_SAPI_dispose(JNIEnv*, jclass) {
-#if _DEBUG
- std::wcout << "Disposing of sapi" << std::endl;
-#endif
-
+JNIEXPORT jint JNICALL Java_org_daisy_pipeline_tts_onecore_SAPI_dispose(JNIEnv*, jclass)
+{
{
// Close remaining connections
if (openedConnection != NULL) {
for (ConnectionsRegistry::iterator it = openedConnection->begin(); it != openedConnection->end(); ++it) {
-#if _DEBUG
- std::wcout << "- Cleaning sapi connection " << *it << std::endl;
-#endif
Connection* conn = reinterpret_cast(*it);
delete conn;
}
@@ -689,9 +656,6 @@ JNIEXPORT jint JNICALL Java_org_daisy_pipeline_tts_onecore_SAPI_dispose(JNIEnv*,
}
CoUninitialize();
-#if _DEBUG
- std::wcout << "sapi disposed" << std::endl;
-#endif
return SAPI_OK;
}
diff --git a/tts/tts-adapters/tts-adapter-sapinative/src/main/resources/transform-ssml.xsl b/tts/tts-adapters/tts-adapter-sapinative/src/main/resources/transform-ssml.xsl
index 3030f15f3..39bc6ce48 100644
--- a/tts/tts-adapters/tts-adapter-sapinative/src/main/resources/transform-ssml.xsl
+++ b/tts/tts-adapters/tts-adapter-sapinative/src/main/resources/transform-ssml.xsl
@@ -1,36 +1,49 @@
-
+
-
+
-
+
-
+
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
-
+
+
+
+
diff --git a/tts/tts-adapters/tts-adapter-sapinative/src/main/resources/x64/onecorenative.dll b/tts/tts-adapters/tts-adapter-sapinative/src/main/resources/x64/onecorenative.dll
index 3a0d8171d..cab7816ff 100644
Binary files a/tts/tts-adapters/tts-adapter-sapinative/src/main/resources/x64/onecorenative.dll and b/tts/tts-adapters/tts-adapter-sapinative/src/main/resources/x64/onecorenative.dll differ
diff --git a/tts/tts-adapters/tts-adapter-sapinative/src/main/resources/x64/sapinative.dll b/tts/tts-adapters/tts-adapter-sapinative/src/main/resources/x64/sapinative.dll
index 395d045e5..001805f49 100644
Binary files a/tts/tts-adapters/tts-adapter-sapinative/src/main/resources/x64/sapinative.dll and b/tts/tts-adapters/tts-adapter-sapinative/src/main/resources/x64/sapinative.dll differ
diff --git a/tts/tts-adapters/tts-adapter-sapinative/src/main/resources/x86/onecorenative.dll b/tts/tts-adapters/tts-adapter-sapinative/src/main/resources/x86/onecorenative.dll
index 76531d81c..4390b395d 100644
Binary files a/tts/tts-adapters/tts-adapter-sapinative/src/main/resources/x86/onecorenative.dll and b/tts/tts-adapters/tts-adapter-sapinative/src/main/resources/x86/onecorenative.dll differ
diff --git a/tts/tts-adapters/tts-adapter-sapinative/src/main/resources/x86/sapinative.dll b/tts/tts-adapters/tts-adapter-sapinative/src/main/resources/x86/sapinative.dll
index f1ef7c0e8..9ec06dfc2 100644
Binary files a/tts/tts-adapters/tts-adapter-sapinative/src/main/resources/x86/sapinative.dll and b/tts/tts-adapters/tts-adapter-sapinative/src/main/resources/x86/sapinative.dll differ
diff --git a/tts/tts-adapters/tts-adapter-sapinative/src/test/java/org/daisy/pipeline/tts/sapi/impl/OnecoreTest.java b/tts/tts-adapters/tts-adapter-sapinative/src/test/java/org/daisy/pipeline/tts/sapi/impl/OnecoreTest.java
index 4f5de1499..fba851118 100644
--- a/tts/tts-adapters/tts-adapter-sapinative/src/test/java/org/daisy/pipeline/tts/sapi/impl/OnecoreTest.java
+++ b/tts/tts-adapters/tts-adapter-sapinative/src/test/java/org/daisy/pipeline/tts/sapi/impl/OnecoreTest.java
@@ -1,5 +1,6 @@
package org.daisy.pipeline.tts.sapi.impl;
+import java.io.IOException;
import java.util.Collection;
import java.util.HashMap;
@@ -87,6 +88,8 @@ static String SSML(String x) {
return "" + x + "";
}
+
+
/**
* Send a text to the TTS API and assert that
* - Voices are correctly retrieved
@@ -95,7 +98,7 @@ static String SSML(String x) {
* @param text the text to speak
* @return the pointer of the connection opened with the TTS API
*/
- static long speakCycle(String text) {
+ static long speakCycle(String text) throws IOException {
String[] names = Onecore.getVoiceNames();
String[] vendors = Onecore.getVoiceVendors();
String[] locales = Onecore.getVoiceLocales();
@@ -123,7 +126,7 @@ static long speakCycle(String text) {
}
@Test
- public void speakEasy() {
+ public void speakEasy() throws IOException {
long connection = speakCycle(SSML("this is a test"));
Onecore.closeConnection(connection);
}
@@ -142,7 +145,7 @@ private static SAPIEngine allocateEngine() throws Throwable {
* Test continuous speaking on a connection with 2 sentences
*/
@Test
- public void speakTwice() {
+ public void speakTwice() throws IOException {
String[] names = Onecore.getVoiceNames();
String[] vendors = Onecore.getVoiceVendors();
Assert.assertTrue(names.length > 0);
@@ -170,7 +173,7 @@ public void speakTwice() {
* Test to retrieve the name and position of a mark
*/
@Test
- public void oneBookmark() {
+ public void oneBookmark() throws IOException {
String bookmark = "bmark";
long connection = speakCycle(SSML("this is a bookmark"));
String[] names = Onecore.getBookmarkNames(connection);
@@ -185,7 +188,7 @@ public void oneBookmark() {
* Test to retrieve ending marks names and position.
*/
@Test
- public void endingBookmark() {
+ public void endingBookmark() throws IOException {
String bookmark = "endingmark";
long connection = speakCycle(SSML("this is an ending mark "));
@@ -201,7 +204,7 @@ public void endingBookmark() {
* Test to retrieve the name and position of 2 marks in the text
*/
@Test
- public void twoBookmarks() {
+ public void twoBookmarks() throws IOException {
String b1 = "bmark1";
String b2 = "bmark2";
long connection = speakCycle(SSML("one two three four ";
}
- static long speakCycle(String text) {
+ static long speakCycle(String text) throws IOException {
String[] names = SAPI.getVoiceNames();
String[] vendors = SAPI.getVoiceVendors();
String[] locales = SAPI.getVoiceLocales();
@@ -91,14 +93,13 @@ public void getVoiceAges() {
}
@Test
- public void manageConnection() {
+ public void manageConnection() throws IOException {
long connection = SAPI.openConnection();
Assert.assertNotSame(0, connection);
SAPI.closeConnection(connection);
}
-
@Test
- public void speakEasy() {
+ public void speakEasy() throws IOException{
long connection = speakCycle(SSML("this is a test"));
SAPI.closeConnection(connection);
}
@@ -115,7 +116,7 @@ public void getVoiceInfo() throws Throwable {
}
@Test
- public void speakTwice() {
+ public void speakTwice() throws IOException {
String[] names = SAPI.getVoiceNames();
String[] vendors = SAPI.getVoiceVendors();
Assert.assertTrue(names.length > 0);
@@ -139,7 +140,7 @@ public void speakTwice() {
}
@Test
- public void bookmarkReply() {
+ public void bookmarkReply() throws IOException {
long connection = speakCycle(SSML("this is a bookmark"));
String[] names = SAPI.getBookmarkNames(connection);
long[] pos = SAPI.getBookmarkPositions(connection);
@@ -149,7 +150,7 @@ public void bookmarkReply() {
}
@Test
- public void oneBookmark() {
+ public void oneBookmark() throws IOException {
String bookmark = "bmark";
long connection = speakCycle(SSML("this is a bookmark"));
String[] names = SAPI.getBookmarkNames(connection);
@@ -161,7 +162,7 @@ public void oneBookmark() {
}
@Test
- public void endingBookmark() {
+ public void endingBookmark() throws IOException {
String bookmark = "endingmark";
long connection = speakCycle(SSML("this is an ending mark "));
String[] names = SAPI.getBookmarkNames(connection);
@@ -173,7 +174,7 @@ public void endingBookmark() {
}
@Test
- public void twoBookmarks() {
+ public void twoBookmarks() throws IOException {
String b1 = "bmark1";
String b2 = "bmark2";
long connection = speakCycle(SSML("one two three four diff);
}
- static private int[] findSize(final String[] sentences, int startShift) throws InterruptedException {
+ static private int[] findSize(final String[] sentences, int startShift) throws InterruptedException, IOException {
final String[] names = SAPI.getVoiceNames();
final String[] vendors = SAPI.getVoiceVendors();
final int[] foundSize = new int[sentences.length];
@@ -199,10 +200,15 @@ static private int[] findSize(final String[] sentences, int startShift) throws I
final int j = i;
threads[i] = new Thread() {
public void run() {
- long connection = SAPI.openConnection();
- SAPI.speak(connection, vendors[0], names[0], sentences[j]);
- foundSize[j] = SAPI.getStreamSize(connection);
- SAPI.closeConnection(connection);
+ try{
+ long connection = SAPI.openConnection();
+ SAPI.speak(connection, vendors[0], names[0], sentences[j]);
+ foundSize[j] = SAPI.getStreamSize(connection);
+ SAPI.closeConnection(connection);
+ } catch (IOException e){
+
+ }
+
}
};
}
@@ -216,7 +222,7 @@ public void run() {
}
@Test
- public void multithreadedSpeak() throws InterruptedException {
+ public void multithreadedSpeak() throws InterruptedException, IOException {
final String[] sentences = new String[]{
SSML("short"), SSML("regular size"), SSML("a bit longer size"),
SSML("very much longer sentence")
diff --git a/tts/tts-adapters/tts-adapter-sapinative/src/test/java/org/daisy/pipeline/tts/sapi/impl/SapiSSMLTest.java b/tts/tts-adapters/tts-adapter-sapinative/src/test/java/org/daisy/pipeline/tts/sapi/impl/SapiSSMLTest.java
index 96ef54e5d..492856073 100644
--- a/tts/tts-adapters/tts-adapter-sapinative/src/test/java/org/daisy/pipeline/tts/sapi/impl/SapiSSMLTest.java
+++ b/tts/tts-adapters/tts-adapter-sapinative/src/test/java/org/daisy/pipeline/tts/sapi/impl/SapiSSMLTest.java
@@ -2,6 +2,7 @@
import java.io.IOException;
import java.io.InputStream;
+import java.io.StringReader;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Map;
@@ -24,9 +25,13 @@
import org.junit.Before;
import org.junit.Test;
+import org.slf4j.LoggerFactory;
import org.xml.sax.SAXException;
+import javax.xml.transform.stream.StreamSource;
+
public class SapiSSMLTest {
+ private static final org.slf4j.Logger Logger = LoggerFactory.getLogger(SapiSSMLTest.class);
private ThreadUnsafeXslTransformer Transformer;
private static Processor Proc = new Processor(false);
@@ -60,9 +65,38 @@ public void completeSSML() throws URISyntaxException, SaxonApiException, SAXExce
params.put("ending-mark", endingmark);
params.put("voice", voice);
String result = Transformer.transformToString(tw.getResult(), params);
- String expected = ""
- + "this is text";
+ Logger.info(result);
+ String expected = ""
+ + "this is text";
+ Diff d = new Diff(result, expected);
+ Assert.assertTrue(d.similar());
+ }
+
+ @Test
+ public void exampleSSML() throws SaxonApiException, IOException, SAXException {
+ String endingmark = "emark";
+ String voice = "john";
+ Map params = new TreeMap();
+ params.put("ending-mark", endingmark);
+ params.put("voice", voice);
+ XdmNode toTest = Proc.newDocumentBuilder().build(new StreamSource(new StringReader(
+ "" +
+ "" +
+ "this" +
+ "is" +
+ "a" +
+ "sentence" +
+ "" +
+ ""
+ )));
+ String result = Transformer.transformToString(toTest, params);
+ Logger.info("result = " + result);
+ String expected = "" +
+ "this is a sentence" +
+ "" +
+ "" +
+ "";
Diff d = new Diff(result, expected);
Assert.assertTrue(d.similar());
}
@@ -85,7 +119,7 @@ public void incompleteSSML() throws URISyntaxException, SaxonApiException, SAXEx
params.put("voice", voice);
String result = Transformer.transformToString(tw.getResult(), params);
String expected = ""
- + "this is textthis is text";
Diff d = new Diff(result, expected);
Assert.assertTrue(d.similar());
@@ -111,7 +145,7 @@ public void noDocumentRoot() throws URISyntaxException, SaxonApiException, SAXEx
XdmNode firstChild = (XdmNode) tw.getResult().axisIterator(Axis.CHILD).next();
String result = Transformer.transformToString(firstChild, params);
String expected = ""
- + "this is textthis is text";
Diff d = new Diff(result, expected);
Assert.assertTrue(d.similar());