Merge change 3374 into donut
* changes:
Fix tracking of backup participants across package remove/update
diff --git a/include/tts/TtsEngine.h b/include/tts/TtsEngine.h
index bf62995..d2aa30e 100644
--- a/include/tts/TtsEngine.h
+++ b/include/tts/TtsEngine.h
@@ -16,33 +16,45 @@
#include <media/AudioSystem.h>
// This header defines the interface used by the Android platform
-// to access Text-To-Speech functionality in shared libraries that implement speech
-// synthesis and the management of resources associated with the synthesis.
-// An example of the implementation of this interface can be found in
+// to access Text-To-Speech functionality in shared libraries that implement
+// speech synthesis and the management of resources associated with the
+// synthesis.
+// An example of the implementation of this interface can be found in
// FIXME: add path+name to implementation of default TTS engine
// Libraries implementing this interface are used in:
// frameworks/base/tts/jni/android_tts_SpeechSynthesis.cpp
namespace android {
+enum tts_synth_status {
+ TTS_SYNTH_DONE = 0,
+ TTS_SYNTH_PENDING = 1
+};
+
+enum tts_callback_status {
+ TTS_CALLBACK_HALT = 0,
+ TTS_CALLBACK_CONTINUE = 1
+};
+
// The callback is used by the implementation of this interface to notify its
// client, the Android TTS service, that the last requested synthesis has been
-// completed.
+// completed. // TODO reword
// The callback for synthesis completed takes:
-// void * - The userdata pointer set in the original synth call
-// uint32_t - Track sampling rate in Hz
-// audio_format - The AudioSystem::audio_format enum
-// int - The number of channels
-// int8_t * - A buffer of audio data only valid during the execution of the callback
-// size_t - The size of the buffer
-// Note about memory management:
-// The implementation of TtsEngine is responsible for the management of the memory
-// it allocates to store the synthesized speech. After the execution of the callback
-// to hand the synthesized data to the client of TtsEngine, the TTS engine is
-// free to reuse or free the previously allocated memory.
-// This implies that the implementation of the "synthDoneCB" callback cannot use
-// the pointer to the buffer of audio samples outside of the callback itself.
-typedef void (synthDoneCB_t)(void *, uint32_t, AudioSystem::audio_format, int, int8_t *, size_t);
+// @param [inout] void *& - The userdata pointer set in the original
+// synth call
+// @param [in] uint32_t - Track sampling rate in Hz
+// @param [in] audio_format - The AudioSystem::audio_format enum
+// @param [in] int - The number of channels
+// @param [inout] int8_t *& - A buffer of audio data only valid during the
+// execution of the callback
+// @param [inout] size_t & - The size of the buffer
+// @param [in] tts_synth_status - indicate whether the synthesis is done, or
+// if more data is to be synthesized.
+// @return TTS_CALLBACK_HALT to indicate the synthesis must stop,
+// TTS_CALLBACK_CONTINUE to indicate the synthesis must continue if
+// there is more data to produce.
+typedef tts_callback_status (synthDoneCB_t)(void *&, uint32_t,
+ AudioSystem::audio_format, int, int8_t *&, size_t&, tts_synth_status);
class TtsEngine;
extern "C" TtsEngine* getTtsEngine();
@@ -69,38 +81,41 @@
// @return TTS_SUCCESS, or TTS_FAILURE
virtual tts_result shutdown();
- // Interrupt synthesis and flushes any synthesized data that hasn't been output yet.
- // This will block until callbacks underway are completed.
+ // Interrupt synthesis and flushes any synthesized data that hasn't been
+ // output yet. This will block until callbacks underway are completed.
// @return TTS_SUCCESS, or TTS_FAILURE
virtual tts_result stop();
- // Load the resources associated with the specified language. The loaded language will
- // only be used once a call to setLanguage() with the same language value is issued.
- // Language values are based on the Android conventions for localization as described in
- // the Android platform documentation on internationalization. This implies that language
- // data is specified in the format xx-rYY, where xx is a two letter ISO 639-1 language code
- // in lowercase and rYY is a two letter ISO 3166-1-alpha-2 language code in uppercase
- // preceded by a lowercase "r".
+ // Load the resources associated with the specified language. The loaded
+ // language will only be used once a call to setLanguage() with the same
+ // language value is issued. Language values are based on the Android
+ // conventions for localization as described in the Android platform
+ // documentation on internationalization. This implies that language
+ // data is specified in the format xx-rYY, where xx is a two letter
+ // ISO 639-1 language code in lowercase and rYY is a two letter
+ // ISO 3166-1-alpha-2 language code in uppercase preceded by a
+ // lowercase "r".
// @param value pointer to the language value
// @param size length of the language value
// @return TTS_SUCCESS, or TTS_FAILURE
virtual tts_result loadLanguage(const char *value, const size_t size);
- // Signal the engine to use the specified language. This will force the language to be
- // loaded if it wasn't loaded previously with loadLanguage().
+ // Signal the engine to use the specified language. This will force the
+ // language to be loaded if it wasn't loaded previously with loadLanguage().
// See loadLanguage for the specification of the language.
// @param value pointer to the language value
// @param size length of the language value
// @return TTS_SUCCESS, or TTS_FAILURE
virtual tts_result setLanguage(const char *value, const size_t size);
- // Retrieve the currently set language, or an empty "value" if no language has
- // been set.
+ // Retrieve the currently set language, or an empty "value" if no language
+ // has been set.
// @param[out] value pointer to the retrieved language value
- // @param[inout] iosize in: stores the size available to store the language value in *value
- // out: stores the size required to hold the language value if
- // getLanguage() returned TTS_PROPERTY_SIZE_TOO_SMALL,
- // unchanged otherwise.
+ // @param[inout] iosize in: stores the size available to store the language
+ // value in *value
+ // out: stores the size required to hold the language
+ // value if getLanguage() returned
+ // TTS_PROPERTY_SIZE_TOO_SMALL, unchanged otherwise.
// @return TTS_SUCCESS, or TTS_PROPERTY_SIZE_TOO_SMALL, or TTS_FAILURE
virtual tts_result getLanguage(char *value, size_t *iosize);
@@ -109,23 +124,31 @@
// @param property pointer to the property name
// @param value pointer to the property value
// @param size maximum size required to store this type of property
- // @return TTS_PROPERTY_UNSUPPORTED, or TTS_SUCCESS, or TTS_FAILURE,
+ // @return TTS_PROPERTY_UNSUPPORTED, or TTS_SUCCESS, or TTS_FAILURE,
// or TTS_VALUE_INVALID
- virtual tts_result setProperty(const char *property, const char *value, const size_t size);
+ virtual tts_result setProperty(const char *property, const char *value,
+ const size_t size);
// Retrieve a property from the TTS engine
// @param property pointer to the property name
// @param[out] value pointer to the retrieved language value
- // @param[inout] iosize in: stores the size available to store the property value
- // out: stores the size required to hold the language value if
- // getLanguage() returned TTS_PROPERTY_SIZE_TOO_SMALL,
- // unchanged otherwise.
- // @return TTS_PROPERTY_UNSUPPORTED, or TTS_SUCCESS, or TTS_PROPERTY_SIZE_TOO_SMALL
- virtual tts_result getProperty(const char *property, char *value, size_t *iosize);
+ // @param[inout] iosize in: stores the size available to store the
+ // property value.
+ // out: stores the size required to hold the language
+ // value if getLanguage() returned
+ // TTS_PROPERTY_SIZE_TOO_SMALL, unchanged otherwise
+ // @return TTS_PROPERTY_UNSUPPORTED, or TTS_SUCCESS,
+ // or TTS_PROPERTY_SIZE_TOO_SMALL
+ virtual tts_result getProperty(const char *property, char *value,
+ size_t *iosize);
// Synthesize the text.
- // When synthesis completes, the engine invokes the callback to notify the TTS framework.
- // Note about the format of the input: the text parameter may use the following elements
+ // As the synthesis is performed, the engine invokes the callback to notify
+ // the TTS framework that it has filled the given buffer, and indicates how
+ // many bytes it wrote. The callback is called repeatedly until the engine
+ // has generated all the audio data corresponding to the text.
+ // Note about the format of the input: the text parameter may use the
+ // following elements
// and their respective attributes as defined in the SSML 1.0 specification:
// * lang
// * say-as:
@@ -154,14 +177,25 @@
// Text is coded in UTF-8.
// @param text the UTF-8 text to synthesize
// @param userdata pointer to be returned when the call is invoked
+ // @param buffer the location where the synthesized data must be written
+ // @param bufferSize the number of bytes that can be written in buffer
// @return TTS_SUCCESS or TTS_FAILURE
- virtual tts_result synthesizeText(const char *text, void *userdata);
+ virtual tts_result synthesizeText(const char *text, int8_t *buffer,
+ size_t bufferSize, void *userdata);
- // Synthesize IPA text. When synthesis completes, the engine must call the given callback to notify the TTS API.
+ // Synthesize IPA text.
+ // As the synthesis is performed, the engine invokes the callback to notify
+ // the TTS framework that it has filled the given buffer, and indicates how
+ // many bytes it wrote. The callback is called repeatedly until the engine
+ // has generated all the audio data corresponding to the IPA data.
// @param ipa the IPA data to synthesize
// @param userdata pointer to be returned when the call is invoked
- // @return TTS_FEATURE_UNSUPPORTED if IPA is not supported, otherwise TTS_SUCCESS or TTS_FAILURE
- virtual tts_result synthesizeIpa(const char *ipa, void *userdata);
+ // @param buffer the location where the synthesized data must be written
+ // @param bufferSize the number of bytes that can be written in buffer
+ // @return TTS_FEATURE_UNSUPPORTED if IPA is not supported,
+ // otherwise TTS_SUCCESS or TTS_FAILURE
+ virtual tts_result synthesizeIpa(const char *ipa, int8_t *buffer,
+ size_t bufferSize, void *userdata);
};
} // namespace android
diff --git a/tts/jni/android_tts_SynthProxy.cpp b/tts/jni/android_tts_SynthProxy.cpp
old mode 100755
new mode 100644
index d8f1bf3..582e621
--- a/tts/jni/android_tts_SynthProxy.cpp
+++ b/tts/jni/android_tts_SynthProxy.cpp
@@ -32,6 +32,7 @@
#define DEFAULT_TTS_RATE 16000
#define DEFAULT_TTS_FORMAT AudioSystem::PCM_16_BIT
#define DEFAULT_TTS_NB_CHANNELS 1
+#define DEFAULT_TTS_BUFFERSIZE 1024
#define USAGEMODE_PLAY_IMMEDIATELY 0
#define USAGEMODE_WRITE_TO_FILE 1
@@ -64,6 +65,8 @@
uint32_t mSampleRate;
AudioSystem::audio_format mAudFormat;
int mNbChannels;
+ int8_t * mBuffer;
+ size_t mBufferSize;
SynthProxyJniStorage() {
//tts_class = NULL;
@@ -73,6 +76,8 @@
mSampleRate = DEFAULT_TTS_RATE;
mAudFormat = DEFAULT_TTS_FORMAT;
mNbChannels = DEFAULT_TTS_NB_CHANNELS;
+ mBufferSize = DEFAULT_TTS_BUFFERSIZE;
+ mBuffer = new int8_t[mBufferSize];
}
~SynthProxyJniStorage() {
@@ -81,6 +86,7 @@
mNativeSynthInterface->shutdown();
mNativeSynthInterface = NULL;
}
+ delete mBuffer;
}
void killAudio() {
@@ -159,23 +165,27 @@
* Callback from TTS engine.
* Directly speaks using AudioTrack or write to file
*/
-static void ttsSynthDoneCB(void * userdata, uint32_t rate,
+static tts_callback_status ttsSynthDoneCB(void *& userdata, uint32_t rate,
AudioSystem::audio_format format, int channel,
- int8_t *wav, size_t bufferSize) {
+ int8_t *&wav, size_t &bufferSize, tts_synth_status status) {
LOGI("ttsSynthDoneCallback: %d bytes", bufferSize);
+ if (userdata == NULL){
+ LOGE("userdata == NULL");
+ return TTS_CALLBACK_HALT;
+ }
afterSynthData_t* pForAfter = (afterSynthData_t*)userdata;
+ SynthProxyJniStorage* pJniData = (SynthProxyJniStorage*)(pForAfter->jniStorage);
if (pForAfter->usageMode == USAGEMODE_PLAY_IMMEDIATELY){
LOGI("Direct speech");
if (wav == NULL) {
+ delete pForAfter;
LOGI("Null: speech has completed");
}
if (bufferSize > 0) {
- SynthProxyJniStorage* pJniData =
- (SynthProxyJniStorage*)(pForAfter->jniStorage);
prepAudioTrack(pJniData, rate, format, channel);
if (pJniData->mAudioOut) {
pJniData->mAudioOut->write(wav, bufferSize);
@@ -187,6 +197,7 @@
} else if (pForAfter->usageMode == USAGEMODE_WRITE_TO_FILE) {
LOGI("Save to file");
if (wav == NULL) {
+ delete pForAfter;
LOGI("Null: speech has completed");
}
if (bufferSize > 0){
@@ -195,10 +206,17 @@
}
// TODO update to call back into the SynthProxy class through the
// javaTTSFields.synthProxyMethodPost methode to notify
- // playback has completed
+ // playback has completed if the synthesis is done, i.e.
+ // if status == TTS_SYNTH_DONE
+ //delete pForAfter;
- delete pForAfter;
- return;
+ // we don't update the wav (output) parameter as we'll let the next callback
+ // write at the same location, we've consumed the data already, but we need
+ // to update bufferSize to let the TTS engine know how much it can write the
+ // next time it calls this function.
+ bufferSize = pJniData->mBufferSize;
+
+ return TTS_CALLBACK_CONTINUE;
}
@@ -223,7 +241,9 @@
} else {
TtsEngine *(*get_TtsEngine)() =
reinterpret_cast<TtsEngine* (*)()>(dlsym(engine_lib_handle, "getTtsEngine"));
+
pJniStorage->mNativeSynthInterface = (*get_TtsEngine)();
+
if (pJniStorage->mNativeSynthInterface) {
pJniStorage->mNativeSynthInterface->init(ttsSynthDoneCB);
}
@@ -323,7 +343,7 @@
// TODO check return codes
if (pSynthData->mNativeSynthInterface) {
- pSynthData->mNativeSynthInterface->synthesizeText(textNativeString,
+ pSynthData->mNativeSynthInterface->synthesizeText(textNativeString, pSynthData->mBuffer, pSynthData->mBufferSize,
(void *)pForAfter);
}
@@ -395,7 +415,7 @@
if (pSynthData->mNativeSynthInterface) {
const char *textNativeString = env->GetStringUTFChars(textJavaString, 0);
- pSynthData->mNativeSynthInterface->synthesizeText(textNativeString,
+ pSynthData->mNativeSynthInterface->synthesizeText(textNativeString, pSynthData->mBuffer, pSynthData->mBufferSize,
(void *)pForAfter);
env->ReleaseStringUTFChars(textJavaString, textNativeString);
}
@@ -442,6 +462,7 @@
android_tts_SynthProxy_playAudioBuffer(JNIEnv *env, jobject thiz, jint jniData,
int bufferPointer, int bufferSize)
{
+LOGI("android_tts_SynthProxy_playAudioBuffer");
if (jniData == 0) {
LOGE("android_tts_SynthProxy_playAudioBuffer(): invalid JNI data");
return;