Add Java API for writing TTS engines
This removes the old non-public C++ API for TTS engines and replaces it with a Java API. The new API is still @hidden, until it has been approved. Bug: 4148636 Change-Id: I7614ff788e11f897e87052f684f1b4938d539fb7
This commit is contained in:
@@ -137,8 +137,8 @@ LOCAL_SRC_FILES += \
|
||||
core/java/android/view/IWindowSession.aidl \
|
||||
core/java/android/speech/IRecognitionListener.aidl \
|
||||
core/java/android/speech/IRecognitionService.aidl \
|
||||
core/java/android/speech/tts/ITts.aidl \
|
||||
core/java/android/speech/tts/ITtsCallback.aidl \
|
||||
core/java/android/speech/tts/ITextToSpeechCallback.aidl \
|
||||
core/java/android/speech/tts/ITextToSpeechService.aidl \
|
||||
core/java/com/android/internal/app/IBatteryStats.aidl \
|
||||
core/java/com/android/internal/app/IUsageStats.aidl \
|
||||
core/java/com/android/internal/app/IMediaContainerService.aidl \
|
||||
|
||||
@@ -96,6 +96,7 @@ $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/PerfTest_interme
|
||||
$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/RSTest_intermediates/)
|
||||
$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/core/java/android/hardware/IUsbManager.java)
|
||||
$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/core/java/android/nfc)
|
||||
$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates)
|
||||
|
||||
# ************************************************
|
||||
# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
|
||||
|
||||
146
core/java/android/speech/tts/BlockingMediaPlayer.java
Normal file
146
core/java/android/speech/tts/BlockingMediaPlayer.java
Normal file
@@ -0,0 +1,146 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
package android.speech.tts;
|
||||
|
||||
import android.content.Context;
|
||||
import android.media.MediaPlayer;
|
||||
import android.net.Uri;
|
||||
import android.os.ConditionVariable;
|
||||
import android.os.Handler;
|
||||
import android.os.HandlerThread;
|
||||
import android.os.Looper;
|
||||
import android.util.Log;
|
||||
|
||||
/**
|
||||
* A media player that allows blocking to wait for it to finish.
|
||||
*/
|
||||
class BlockingMediaPlayer {
|
||||
|
||||
private static final String TAG = "BlockMediaPlayer";
|
||||
|
||||
private static final String MEDIA_PLAYER_THREAD_NAME = "TTS-MediaPlayer";
|
||||
|
||||
private final Context mContext;
|
||||
private final Uri mUri;
|
||||
private final int mStreamType;
|
||||
private final ConditionVariable mDone;
|
||||
// Only accessed on the Handler thread
|
||||
private MediaPlayer mPlayer;
|
||||
private volatile boolean mFinished;
|
||||
|
||||
/**
|
||||
* Creates a new blocking media player.
|
||||
* Creating a blocking media player is a cheap operation.
|
||||
*
|
||||
* @param context
|
||||
* @param uri
|
||||
* @param streamType
|
||||
*/
|
||||
public BlockingMediaPlayer(Context context, Uri uri, int streamType) {
|
||||
mContext = context;
|
||||
mUri = uri;
|
||||
mStreamType = streamType;
|
||||
mDone = new ConditionVariable();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts playback and waits for it to finish.
|
||||
* Can be called from any thread.
|
||||
*
|
||||
* @return {@code true} if the playback finished normally, {@code false} if the playback
|
||||
* failed or {@link #stop} was called before the playback finished.
|
||||
*/
|
||||
public boolean startAndWait() {
|
||||
HandlerThread thread = new HandlerThread(MEDIA_PLAYER_THREAD_NAME);
|
||||
thread.start();
|
||||
Handler handler = new Handler(thread.getLooper());
|
||||
mFinished = false;
|
||||
handler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
startPlaying();
|
||||
}
|
||||
});
|
||||
mDone.block();
|
||||
handler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
finish();
|
||||
// No new messages should get posted to the handler thread after this
|
||||
Looper.myLooper().quit();
|
||||
}
|
||||
});
|
||||
return mFinished;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops playback. Can be called multiple times.
|
||||
* Can be called from any thread.
|
||||
*/
|
||||
public void stop() {
|
||||
mDone.open();
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts playback.
|
||||
* Called on the handler thread.
|
||||
*/
|
||||
private void startPlaying() {
|
||||
mPlayer = MediaPlayer.create(mContext, mUri);
|
||||
if (mPlayer == null) {
|
||||
Log.w(TAG, "Failed to play " + mUri);
|
||||
mDone.open();
|
||||
return;
|
||||
}
|
||||
try {
|
||||
mPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() {
|
||||
@Override
|
||||
public boolean onError(MediaPlayer mp, int what, int extra) {
|
||||
Log.w(TAG, "Audio playback error: " + what + ", " + extra);
|
||||
mDone.open();
|
||||
return true;
|
||||
}
|
||||
});
|
||||
mPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
|
||||
@Override
|
||||
public void onCompletion(MediaPlayer mp) {
|
||||
mFinished = true;
|
||||
mDone.open();
|
||||
}
|
||||
});
|
||||
mPlayer.setAudioStreamType(mStreamType);
|
||||
mPlayer.start();
|
||||
} catch (IllegalArgumentException ex) {
|
||||
Log.w(TAG, "MediaPlayer failed", ex);
|
||||
mDone.open();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops playback and release the media player.
|
||||
* Called on the handler thread.
|
||||
*/
|
||||
private void finish() {
|
||||
try {
|
||||
mPlayer.stop();
|
||||
} catch (IllegalStateException ex) {
|
||||
// Do nothing, the player is already stopped
|
||||
}
|
||||
mPlayer.release();
|
||||
}
|
||||
|
||||
}
|
||||
197
core/java/android/speech/tts/FileSynthesisRequest.java
Normal file
197
core/java/android/speech/tts/FileSynthesisRequest.java
Normal file
@@ -0,0 +1,197 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
package android.speech.tts;
|
||||
|
||||
import android.media.AudioFormat;
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.RandomAccessFile;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
/**
|
||||
* Speech synthesis request that writes the audio to a WAV file.
|
||||
*/
|
||||
class FileSynthesisRequest extends SynthesisRequest {
|
||||
|
||||
private static final String TAG = "FileSynthesisRequest";
|
||||
private static final boolean DBG = false;
|
||||
|
||||
private static final int WAV_HEADER_LENGTH = 44;
|
||||
private static final short WAV_FORMAT_PCM = 0x0001;
|
||||
|
||||
private final Object mStateLock = new Object();
|
||||
private final File mFileName;
|
||||
private int mSampleRateInHz;
|
||||
private int mAudioFormat;
|
||||
private int mChannelCount;
|
||||
private RandomAccessFile mFile;
|
||||
private boolean mStopped = false;
|
||||
|
||||
FileSynthesisRequest(String text, File fileName) {
|
||||
super(text);
|
||||
mFileName = fileName;
|
||||
}
|
||||
|
||||
@Override
|
||||
void stop() {
|
||||
synchronized (mStateLock) {
|
||||
mStopped = true;
|
||||
cleanUp();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Must be called while holding the monitor on {@link #mStateLock}.
|
||||
*/
|
||||
private void cleanUp() {
|
||||
closeFile();
|
||||
if (mFile != null) {
|
||||
mFileName.delete();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Must be called while holding the monitor on {@link #mStateLock}.
|
||||
*/
|
||||
private void closeFile() {
|
||||
try {
|
||||
if (mFile != null) {
|
||||
mFile.close();
|
||||
mFile = null;
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
Log.e(TAG, "Failed to close " + mFileName + ": " + ex);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int start(int sampleRateInHz, int audioFormat, int channelCount) {
|
||||
if (DBG) {
|
||||
Log.d(TAG, "FileSynthesisRequest.start(" + sampleRateInHz + "," + audioFormat
|
||||
+ "," + channelCount + ")");
|
||||
}
|
||||
synchronized (mStateLock) {
|
||||
if (mStopped) {
|
||||
if (DBG) Log.d(TAG, "Request has been aborted.");
|
||||
return TextToSpeech.ERROR;
|
||||
}
|
||||
if (mFile != null) {
|
||||
cleanUp();
|
||||
throw new IllegalArgumentException("FileSynthesisRequest.start() called twice");
|
||||
}
|
||||
mSampleRateInHz = sampleRateInHz;
|
||||
mAudioFormat = audioFormat;
|
||||
mChannelCount = channelCount;
|
||||
try {
|
||||
mFile = new RandomAccessFile(mFileName, "rw");
|
||||
// Reserve space for WAV header
|
||||
mFile.write(new byte[WAV_HEADER_LENGTH]);
|
||||
return TextToSpeech.SUCCESS;
|
||||
} catch (IOException ex) {
|
||||
Log.e(TAG, "Failed to open " + mFileName + ": " + ex);
|
||||
cleanUp();
|
||||
return TextToSpeech.ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int audioAvailable(byte[] buffer, int offset, int length) {
|
||||
if (DBG) {
|
||||
Log.d(TAG, "FileSynthesisRequest.audioAvailable(" + buffer + "," + offset
|
||||
+ "," + length + ")");
|
||||
}
|
||||
synchronized (mStateLock) {
|
||||
if (mStopped) {
|
||||
if (DBG) Log.d(TAG, "Request has been aborted.");
|
||||
return TextToSpeech.ERROR;
|
||||
}
|
||||
if (mFile == null) {
|
||||
Log.e(TAG, "File not open");
|
||||
return TextToSpeech.ERROR;
|
||||
}
|
||||
try {
|
||||
mFile.write(buffer, offset, length);
|
||||
return TextToSpeech.SUCCESS;
|
||||
} catch (IOException ex) {
|
||||
Log.e(TAG, "Failed to write to " + mFileName + ": " + ex);
|
||||
cleanUp();
|
||||
return TextToSpeech.ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int done() {
|
||||
if (DBG) Log.d(TAG, "FileSynthesisRequest.done()");
|
||||
synchronized (mStateLock) {
|
||||
if (mStopped) {
|
||||
if (DBG) Log.d(TAG, "Request has been aborted.");
|
||||
return TextToSpeech.ERROR;
|
||||
}
|
||||
if (mFile == null) {
|
||||
Log.e(TAG, "File not open");
|
||||
return TextToSpeech.ERROR;
|
||||
}
|
||||
try {
|
||||
// Write WAV header at start of file
|
||||
mFile.seek(0);
|
||||
int fileLen = (int) mFile.length();
|
||||
mFile.write(makeWavHeader(mSampleRateInHz, mAudioFormat, mChannelCount, fileLen));
|
||||
closeFile();
|
||||
return TextToSpeech.SUCCESS;
|
||||
} catch (IOException ex) {
|
||||
Log.e(TAG, "Failed to write to " + mFileName + ": " + ex);
|
||||
cleanUp();
|
||||
return TextToSpeech.ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private byte[] makeWavHeader(int sampleRateInHz, int audioFormat, int channelCount,
|
||||
int fileLength) {
|
||||
// TODO: is AudioFormat.ENCODING_DEFAULT always the same as ENCODING_PCM_16BIT?
|
||||
int sampleSizeInBytes = (audioFormat == AudioFormat.ENCODING_PCM_8BIT ? 1 : 2);
|
||||
int byteRate = sampleRateInHz * sampleSizeInBytes * channelCount;
|
||||
short blockAlign = (short) (sampleSizeInBytes * channelCount);
|
||||
short bitsPerSample = (short) (sampleSizeInBytes * 8);
|
||||
|
||||
byte[] headerBuf = new byte[WAV_HEADER_LENGTH];
|
||||
ByteBuffer header = ByteBuffer.wrap(headerBuf);
|
||||
header.order(ByteOrder.LITTLE_ENDIAN);
|
||||
|
||||
header.put(new byte[]{ 'R', 'I', 'F', 'F' });
|
||||
header.putInt(fileLength - 8); // RIFF chunk size
|
||||
header.put(new byte[]{ 'W', 'A', 'V', 'E' });
|
||||
header.put(new byte[]{ 'f', 'm', 't', ' ' });
|
||||
header.putInt(16); // size of fmt chunk
|
||||
header.putShort(WAV_FORMAT_PCM);
|
||||
header.putShort((short) channelCount);
|
||||
header.putInt(sampleRateInHz);
|
||||
header.putInt(byteRate);
|
||||
header.putShort(blockAlign);
|
||||
header.putShort(bitsPerSample);
|
||||
header.put(new byte[]{ 'd', 'a', 't', 'a' });
|
||||
int dataLength = fileLength - WAV_HEADER_LENGTH;
|
||||
header.putInt(dataLength);
|
||||
|
||||
return headerBuf;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2009 The Android Open Source Project
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -13,15 +13,13 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.speech.tts;
|
||||
|
||||
/**
|
||||
* AIDL for the callback from the TTS Service
|
||||
* ITtsCallback.java is autogenerated from this.
|
||||
* Interface for callbacks from TextToSpeechService
|
||||
*
|
||||
* {@hide}
|
||||
*/
|
||||
oneway interface ITtsCallback {
|
||||
oneway interface ITextToSpeechCallback {
|
||||
void utteranceCompleted(String utteranceId);
|
||||
}
|
||||
140
core/java/android/speech/tts/ITextToSpeechService.aidl
Normal file
140
core/java/android/speech/tts/ITextToSpeechService.aidl
Normal file
@@ -0,0 +1,140 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.speech.tts;
|
||||
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.speech.tts.ITextToSpeechCallback;
|
||||
|
||||
/**
|
||||
* Interface for TextToSpeech to talk to TextToSpeechService.
|
||||
*
|
||||
* {@hide}
|
||||
*/
|
||||
interface ITextToSpeechService {
|
||||
|
||||
/**
|
||||
* Tells the engine to synthesize some speech and play it back.
|
||||
*
|
||||
* @param callingApp The package name of the calling app. Used to connect requests
|
||||
* callbacks and to clear requests when the calling app is stopping.
|
||||
* @param text The text to synthesize.
|
||||
* @param queueMode Determines what to do to requests already in the queue.
|
||||
* @param param Request parameters.
|
||||
*/
|
||||
int speak(in String callingApp, in String text, in int queueMode, in Bundle params);
|
||||
|
||||
/**
|
||||
* Tells the engine to synthesize some speech and write it to a file.
|
||||
*
|
||||
* @param callingApp The package name of the calling app. Used to connect requests
|
||||
* callbacks and to clear requests when the calling app is stopping.
|
||||
* @param text The text to synthesize.
|
||||
* @param filename The file to write the synthesized audio to.
|
||||
* @param param Request parameters.
|
||||
*/
|
||||
int synthesizeToFile(in String callingApp, in String text,
|
||||
in String filename, in Bundle params);
|
||||
|
||||
/**
|
||||
* Plays an existing audio resource.
|
||||
*
|
||||
* @param callingApp The package name of the calling app. Used to connect requests
|
||||
* callbacks and to clear requests when the calling app is stopping.
|
||||
* @param audioUri URI for the audio resource (a file or android.resource URI)
|
||||
* @param queueMode Determines what to do to requests already in the queue.
|
||||
* @param param Request parameters.
|
||||
*/
|
||||
int playAudio(in String callingApp, in Uri audioUri, in int queueMode, in Bundle params);
|
||||
|
||||
/**
|
||||
* Plays silence.
|
||||
*
|
||||
* @param callingApp The package name of the calling app. Used to connect requests
|
||||
* callbacks and to clear requests when the calling app is stopping.
|
||||
* @param duration Number of milliseconds of silence to play.
|
||||
* @param queueMode Determines what to do to requests already in the queue.
|
||||
* @param param Request parameters.
|
||||
*/
|
||||
int playSilence(in String callingApp, in long duration, in int queueMode, in Bundle params);
|
||||
|
||||
/**
|
||||
* Checks whether the service is currently playing some audio.
|
||||
*/
|
||||
boolean isSpeaking();
|
||||
|
||||
/**
|
||||
* Interrupts the current utterance (if from the given app) and removes any utterances
|
||||
* in the queue that are from the given app.
|
||||
*
|
||||
* @param callingApp Package name of the app whose utterances
|
||||
* should be interrupted and cleared.
|
||||
*/
|
||||
int stop(in String callingApp);
|
||||
|
||||
/**
|
||||
* Returns the language, country and variant currently being used by the TTS engine.
|
||||
*
|
||||
* Can be called from multiple threads.
|
||||
*
|
||||
* @return A 3-element array, containing language (ISO 3-letter code),
|
||||
* country (ISO 3-letter code) and variant used by the engine.
|
||||
* The country and variant may be {@code ""}. If country is empty, then variant must
|
||||
* be empty too.
|
||||
*/
|
||||
String[] getLanguage();
|
||||
|
||||
/**
|
||||
* Checks whether the engine supports a given language.
|
||||
*
|
||||
* @param lang ISO-3 language code.
|
||||
* @param country ISO-3 country code. May be empty or null.
|
||||
* @param variant Language variant. May be empty or null.
|
||||
* @return Code indicating the support status for the locale.
|
||||
* One of {@link TextToSpeech#LANG_AVAILABLE},
|
||||
* {@link TextToSpeech#LANG_COUNTRY_AVAILABLE},
|
||||
* {@link TextToSpeech#LANG_COUNTRY_VAR_AVAILABLE},
|
||||
* {@link TextToSpeech#LANG_MISSING_DATA}
|
||||
* {@link TextToSpeech#LANG_NOT_SUPPORTED}.
|
||||
*/
|
||||
int isLanguageAvailable(in String lang, in String country, in String variant);
|
||||
|
||||
/**
|
||||
* Notifies the engine that it should load a speech synthesis language.
|
||||
*
|
||||
* @param lang ISO-3 language code.
|
||||
* @param country ISO-3 country code. May be empty or null.
|
||||
* @param variant Language variant. May be empty or null.
|
||||
* @return Code indicating the support status for the locale.
|
||||
* One of {@link TextToSpeech#LANG_AVAILABLE},
|
||||
* {@link TextToSpeech#LANG_COUNTRY_AVAILABLE},
|
||||
* {@link TextToSpeech#LANG_COUNTRY_VAR_AVAILABLE},
|
||||
* {@link TextToSpeech#LANG_MISSING_DATA}
|
||||
* {@link TextToSpeech#LANG_NOT_SUPPORTED}.
|
||||
*/
|
||||
int loadLanguage(in String lang, in String country, in String variant);
|
||||
|
||||
/**
|
||||
* Sets the callback that will be notified when playback of utterance from the
|
||||
* given app are completed.
|
||||
*
|
||||
* @param callingApp Package name for the app whose utterance the callback will handle.
|
||||
* @param cb The callback.
|
||||
*/
|
||||
void setCallback(in String callingApp, ITextToSpeechCallback cb);
|
||||
|
||||
}
|
||||
@@ -1,69 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2009 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.speech.tts;
|
||||
|
||||
import android.speech.tts.ITtsCallback;
|
||||
|
||||
import android.content.Intent;
|
||||
|
||||
/**
|
||||
* AIDL for the TTS Service
|
||||
* ITts.java is autogenerated from this.
|
||||
*
|
||||
* {@hide}
|
||||
*/
|
||||
interface ITts {
|
||||
int setSpeechRate(in String callingApp, in int speechRate);
|
||||
|
||||
int setPitch(in String callingApp, in int pitch);
|
||||
|
||||
int speak(in String callingApp, in String text, in int queueMode, in String[] params);
|
||||
|
||||
boolean isSpeaking();
|
||||
|
||||
int stop(in String callingApp);
|
||||
|
||||
void addSpeech(in String callingApp, in String text, in String packageName, in int resId);
|
||||
|
||||
void addSpeechFile(in String callingApp, in String text, in String filename);
|
||||
|
||||
String[] getLanguage();
|
||||
|
||||
int isLanguageAvailable(in String language, in String country, in String variant, in String[] params);
|
||||
|
||||
int setLanguage(in String callingApp, in String language, in String country, in String variant);
|
||||
|
||||
boolean synthesizeToFile(in String callingApp, in String text, in String[] params, in String outputDirectory);
|
||||
|
||||
int playEarcon(in String callingApp, in String earcon, in int queueMode, in String[] params);
|
||||
|
||||
void addEarcon(in String callingApp, in String earcon, in String packageName, in int resId);
|
||||
|
||||
void addEarconFile(in String callingApp, in String earcon, in String filename);
|
||||
|
||||
int registerCallback(in String callingApp, ITtsCallback cb);
|
||||
|
||||
int unregisterCallback(in String callingApp, ITtsCallback cb);
|
||||
|
||||
int playSilence(in String callingApp, in long duration, in int queueMode, in String[] params);
|
||||
|
||||
int setEngineByPackageName(in String enginePackageName);
|
||||
|
||||
String getDefaultEngine();
|
||||
|
||||
boolean areDefaultsEnforced();
|
||||
}
|
||||
197
core/java/android/speech/tts/PlaybackSynthesisRequest.java
Normal file
197
core/java/android/speech/tts/PlaybackSynthesisRequest.java
Normal file
@@ -0,0 +1,197 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
package android.speech.tts;
|
||||
|
||||
import android.media.AudioFormat;
|
||||
import android.media.AudioTrack;
|
||||
import android.util.Log;
|
||||
|
||||
/**
|
||||
* Speech synthesis request that plays the audio as it is received.
|
||||
*/
|
||||
class PlaybackSynthesisRequest extends SynthesisRequest {
|
||||
|
||||
private static final String TAG = "PlaybackSynthesisRequest";
|
||||
private static final boolean DBG = false;
|
||||
|
||||
private static final int MIN_AUDIO_BUFFER_SIZE = 8192;
|
||||
|
||||
/**
|
||||
* Audio stream type. Must be one of the STREAM_ contants defined in
|
||||
* {@link android.media.AudioManager}.
|
||||
*/
|
||||
private final int mStreamType;
|
||||
|
||||
/**
|
||||
* Volume, in the range [0.0f, 1.0f]. The default value is
|
||||
* {@link TextToSpeech.Engine#DEFAULT_VOLUME} (1.0f).
|
||||
*/
|
||||
private final float mVolume;
|
||||
|
||||
/**
|
||||
* Left/right position of the audio, in the range [-1.0f, 1.0f].
|
||||
* The default value is {@link TextToSpeech.Engine#DEFAULT_PAN} (0.0f).
|
||||
*/
|
||||
private final float mPan;
|
||||
|
||||
private final Object mStateLock = new Object();
|
||||
private AudioTrack mAudioTrack = null;
|
||||
private boolean mStopped = false;
|
||||
|
||||
PlaybackSynthesisRequest(String text, int streamType, float volume, float pan) {
|
||||
super(text);
|
||||
mStreamType = streamType;
|
||||
mVolume = volume;
|
||||
mPan = pan;
|
||||
}
|
||||
|
||||
@Override
|
||||
void stop() {
|
||||
if (DBG) Log.d(TAG, "stop()");
|
||||
synchronized (mStateLock) {
|
||||
mStopped = true;
|
||||
cleanUp();
|
||||
}
|
||||
}
|
||||
|
||||
private void cleanUp() {
|
||||
if (DBG) Log.d(TAG, "cleanUp()");
|
||||
if (mAudioTrack != null) {
|
||||
mAudioTrack.flush();
|
||||
mAudioTrack.stop();
|
||||
// TODO: do we need to wait for playback to finish before releasing?
|
||||
mAudioTrack.release();
|
||||
mAudioTrack = null;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: add a thread that writes to the AudioTrack?
|
||||
@Override
|
||||
public int start(int sampleRateInHz, int audioFormat, int channelCount) {
|
||||
if (DBG) {
|
||||
Log.d(TAG, "start(" + sampleRateInHz + "," + audioFormat
|
||||
+ "," + channelCount + ")");
|
||||
}
|
||||
|
||||
int channelConfig;
|
||||
if (channelCount == 1) {
|
||||
channelConfig = AudioFormat.CHANNEL_OUT_MONO;
|
||||
} else if (channelCount == 2){
|
||||
channelConfig = AudioFormat.CHANNEL_OUT_STEREO;
|
||||
} else {
|
||||
Log.e(TAG, "Unsupported number of channels: " + channelCount);
|
||||
return TextToSpeech.ERROR;
|
||||
}
|
||||
|
||||
int minBufferSizeInBytes
|
||||
= AudioTrack.getMinBufferSize(sampleRateInHz, channelConfig, audioFormat);
|
||||
int bufferSizeInBytes = Math.max(MIN_AUDIO_BUFFER_SIZE, minBufferSizeInBytes);
|
||||
|
||||
synchronized (mStateLock) {
|
||||
if (mStopped) {
|
||||
if (DBG) Log.d(TAG, "Request has been aborted.");
|
||||
return TextToSpeech.ERROR;
|
||||
}
|
||||
if (mAudioTrack != null) {
|
||||
Log.e(TAG, "start() called twice");
|
||||
cleanUp();
|
||||
return TextToSpeech.ERROR;
|
||||
}
|
||||
|
||||
mAudioTrack = new AudioTrack(mStreamType, sampleRateInHz, channelConfig, audioFormat,
|
||||
bufferSizeInBytes, AudioTrack.MODE_STREAM);
|
||||
if (mAudioTrack.getState() != AudioTrack.STATE_INITIALIZED) {
|
||||
cleanUp();
|
||||
return TextToSpeech.ERROR;
|
||||
}
|
||||
|
||||
setupVolume();
|
||||
}
|
||||
|
||||
return TextToSpeech.SUCCESS;
|
||||
}
|
||||
|
||||
private void setupVolume() {
|
||||
float vol = clip(mVolume, 0.0f, 1.0f);
|
||||
float panning = clip(mPan, -1.0f, 1.0f);
|
||||
float volLeft = vol;
|
||||
float volRight = vol;
|
||||
if (panning > 0.0f) {
|
||||
volLeft *= (1.0f - panning);
|
||||
} else if (panning < 0.0f) {
|
||||
volRight *= (1.0f + panning);
|
||||
}
|
||||
if (DBG) Log.d(TAG, "volLeft=" + volLeft + ",volRight=" + volRight);
|
||||
if (mAudioTrack.setStereoVolume(volLeft, volRight) != AudioTrack.SUCCESS) {
|
||||
Log.e(TAG, "Failed to set volume");
|
||||
}
|
||||
}
|
||||
|
||||
private float clip(float value, float min, float max) {
|
||||
return value > max ? max : (value < min ? min : value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int audioAvailable(byte[] buffer, int offset, int length) {
|
||||
if (DBG) {
|
||||
Log.d(TAG, "audioAvailable(byte[" + buffer.length + "],"
|
||||
+ offset + "," + length + "), thread ID=" + android.os.Process.myTid());
|
||||
}
|
||||
synchronized (mStateLock) {
|
||||
if (mStopped) {
|
||||
if (DBG) Log.d(TAG, "Request has been aborted.");
|
||||
return TextToSpeech.ERROR;
|
||||
}
|
||||
if (mAudioTrack == null) {
|
||||
Log.e(TAG, "audioAvailable(): Not started");
|
||||
return TextToSpeech.ERROR;
|
||||
}
|
||||
int playState = mAudioTrack.getPlayState();
|
||||
if (playState == AudioTrack.PLAYSTATE_STOPPED) {
|
||||
if (DBG) Log.d(TAG, "AudioTrack stopped, restarting");
|
||||
mAudioTrack.play();
|
||||
}
|
||||
// TODO: loop until all data is written?
|
||||
if (DBG) Log.d(TAG, "AudioTrack.write()");
|
||||
int count = mAudioTrack.write(buffer, offset, length);
|
||||
if (DBG) Log.d(TAG, "AudioTrack.write() returned " + count);
|
||||
if (count < 0) {
|
||||
Log.e(TAG, "Writing to AudioTrack failed: " + count);
|
||||
cleanUp();
|
||||
return TextToSpeech.ERROR;
|
||||
} else {
|
||||
return TextToSpeech.SUCCESS;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int done() {
|
||||
if (DBG) Log.d(TAG, "done()");
|
||||
synchronized (mStateLock) {
|
||||
if (mStopped) {
|
||||
if (DBG) Log.d(TAG, "Request has been aborted.");
|
||||
return TextToSpeech.ERROR;
|
||||
}
|
||||
if (mAudioTrack == null) {
|
||||
Log.e(TAG, "done(): Not started");
|
||||
return TextToSpeech.ERROR;
|
||||
}
|
||||
cleanUp();
|
||||
}
|
||||
return TextToSpeech.SUCCESS;
|
||||
}
|
||||
}
|
||||
151
core/java/android/speech/tts/SynthesisRequest.java
Normal file
151
core/java/android/speech/tts/SynthesisRequest.java
Normal file
@@ -0,0 +1,151 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
package android.speech.tts;
|
||||
|
||||
/**
|
||||
* A request for speech synthesis given to a TTS engine for processing.
|
||||
*
|
||||
* @hide Pending approval
|
||||
*/
|
||||
public abstract class SynthesisRequest {
|
||||
|
||||
private final String mText;
|
||||
private String mLanguage;
|
||||
private String mCountry;
|
||||
private String mVariant;
|
||||
private int mSpeechRate;
|
||||
private int mPitch;
|
||||
|
||||
public SynthesisRequest(String text) {
|
||||
mText = text;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the locale for the request.
|
||||
*/
|
||||
void setLanguage(String language, String country, String variant) {
|
||||
mLanguage = language;
|
||||
mCountry = country;
|
||||
mVariant = variant;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the speech rate.
|
||||
*/
|
||||
void setSpeechRate(int speechRate) {
|
||||
mSpeechRate = speechRate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the pitch.
|
||||
*/
|
||||
void setPitch(int pitch) {
|
||||
mPitch = pitch;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the text which should be synthesized.
|
||||
*/
|
||||
public String getText() {
|
||||
return mText;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the ISO 3-letter language code for the language to use.
|
||||
*/
|
||||
public String getLanguage() {
|
||||
return mLanguage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the ISO 3-letter country code for the language to use.
|
||||
*/
|
||||
public String getCountry() {
|
||||
return mCountry;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the language variant to use.
|
||||
*/
|
||||
public String getVariant() {
|
||||
return mVariant;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the speech rate to use. {@link TextToSpeech.Engine#DEFAULT_RATE} (100)
|
||||
* is the normal rate.
|
||||
*/
|
||||
public int getSpeechRate() {
|
||||
return mSpeechRate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the pitch to use. {@link TextToSpeech.Engine#DEFAULT_PITCH} (100)
|
||||
* is the normal pitch.
|
||||
*/
|
||||
public int getPitch() {
|
||||
return mPitch;
|
||||
}
|
||||
|
||||
/**
|
||||
* Aborts the speech request.
|
||||
*
|
||||
* Can be called from multiple threads.
|
||||
*/
|
||||
abstract void stop();
|
||||
|
||||
/**
|
||||
* The service should call this when it starts to synthesize audio for this
|
||||
* request.
|
||||
*
|
||||
* This method should only be called on the synthesis thread,
|
||||
* while in {@link TextToSpeechService#onSynthesizeText}.
|
||||
*
|
||||
* @param sampleRateInHz Sample rate in HZ of the generated audio.
|
||||
* @param audioFormat Audio format of the generated audio. Must be one of
|
||||
* the ENCODING_ constants defined in {@link android.media.AudioFormat}.
|
||||
* @param channelCount The number of channels
|
||||
* @return {@link TextToSpeech#SUCCESS} or {@link TextToSpeech#ERROR}.
|
||||
*/
|
||||
public abstract int start(int sampleRateInHz, int audioFormat, int channelCount);
|
||||
|
||||
/**
|
||||
* The service should call this method when synthesized audio is ready for consumption.
|
||||
*
|
||||
* This method should only be called on the synthesis thread,
|
||||
* while in {@link TextToSpeechService#onSynthesizeText}.
|
||||
*
|
||||
* @param buffer The generated audio data. This method will not hold on to {@code buffer},
|
||||
* so the caller is free to modify it after this method returns.
|
||||
* @param offset The offset into {@code buffer} where the audio data starts.
|
||||
* @param length The number of bytes of audio data in {@code buffer}.
|
||||
* Must be less than or equal to {@code buffer.length - offset}.
|
||||
* @return {@link TextToSpeech#SUCCESS} or {@link TextToSpeech#ERROR}.
|
||||
*/
|
||||
public abstract int audioAvailable(byte[] buffer, int offset, int length);
|
||||
|
||||
/**
|
||||
* The service should call this method when all the synthesized audio for a request has
|
||||
* been passed to {@link #audioAvailable}.
|
||||
*
|
||||
* This method should only be called on the synthesis thread,
|
||||
* while in {@link TextToSpeechService#onSynthesizeText}.
|
||||
*
|
||||
* @return {@link TextToSpeech#SUCCESS} or {@link TextToSpeech#ERROR}.
|
||||
*/
|
||||
public abstract int done();
|
||||
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
715
core/java/android/speech/tts/TextToSpeechService.java
Normal file
715
core/java/android/speech/tts/TextToSpeechService.java
Normal file
@@ -0,0 +1,715 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
package android.speech.tts;
|
||||
|
||||
import android.app.Service;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.os.ConditionVariable;
|
||||
import android.os.Handler;
|
||||
import android.os.HandlerThread;
|
||||
import android.os.IBinder;
|
||||
import android.os.Looper;
|
||||
import android.os.Message;
|
||||
import android.os.MessageQueue;
|
||||
import android.os.RemoteCallbackList;
|
||||
import android.os.RemoteException;
|
||||
import android.provider.Settings;
|
||||
import android.speech.tts.TextToSpeech.Engine;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
|
||||
|
||||
/**
|
||||
* Abstract base class for TTS engine implementations.
|
||||
*
|
||||
* @hide Pending approval
|
||||
*/
|
||||
public abstract class TextToSpeechService extends Service {
|
||||
|
||||
private static final boolean DBG = false;
|
||||
private static final String TAG = "TextToSpeechService";
|
||||
|
||||
private static final int MAX_SPEECH_ITEM_CHAR_LENGTH = 4000;
|
||||
private static final String SYNTH_THREAD_NAME = "SynthThread";
|
||||
|
||||
private SynthHandler mSynthHandler;
|
||||
|
||||
private CallbackMap mCallbacks;
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
if (DBG) Log.d(TAG, "onCreate()");
|
||||
super.onCreate();
|
||||
|
||||
SynthThread synthThread = new SynthThread();
|
||||
synthThread.start();
|
||||
mSynthHandler = new SynthHandler(synthThread.getLooper());
|
||||
|
||||
mCallbacks = new CallbackMap();
|
||||
|
||||
// Load default language
|
||||
onLoadLanguage(getDefaultLanguage(), getDefaultCountry(), getDefaultVariant());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
if (DBG) Log.d(TAG, "onDestroy()");
|
||||
|
||||
// Tell the synthesizer to stop
|
||||
mSynthHandler.quit();
|
||||
|
||||
// Unregister all callbacks.
|
||||
mCallbacks.kill();
|
||||
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the engine supports a given language.
|
||||
*
|
||||
* Can be called on multiple threads.
|
||||
*
|
||||
* @param lang ISO-3 language code.
|
||||
* @param country ISO-3 country code. May be empty or null.
|
||||
* @param variant Language variant. May be empty or null.
|
||||
* @return Code indicating the support status for the locale.
|
||||
* One of {@link TextToSpeech#LANG_AVAILABLE},
|
||||
* {@link TextToSpeech#LANG_COUNTRY_AVAILABLE},
|
||||
* {@link TextToSpeech#LANG_COUNTRY_VAR_AVAILABLE},
|
||||
* {@link TextToSpeech#LANG_MISSING_DATA}
|
||||
* {@link TextToSpeech#LANG_NOT_SUPPORTED}.
|
||||
*/
|
||||
protected abstract int onIsLanguageAvailable(String lang, String country, String variant);
|
||||
|
||||
/**
|
||||
* Returns the language, country and variant currently being used by the TTS engine.
|
||||
*
|
||||
* Can be called on multiple threads.
|
||||
*
|
||||
* @return A 3-element array, containing language (ISO 3-letter code),
|
||||
* country (ISO 3-letter code) and variant used by the engine.
|
||||
* The country and variant may be {@code ""}. If country is empty, then variant must
|
||||
* be empty too.
|
||||
* @see Locale#getISO3Language()
|
||||
* @see Locale#getISO3Country()
|
||||
* @see Locale#getVariant()
|
||||
*/
|
||||
protected abstract String[] onGetLanguage();
|
||||
|
||||
/**
|
||||
* Notifies the engine that it should load a speech synthesis language. There is no guarantee
|
||||
* that this method is always called before the language is used for synthesis. It is merely
|
||||
* a hint to the engine that it will probably get some synthesis requests for this language
|
||||
* at some point in the future.
|
||||
*
|
||||
* Can be called on multiple threads.
|
||||
*
|
||||
* @param lang ISO-3 language code.
|
||||
* @param country ISO-3 country code. May be empty or null.
|
||||
* @param variant Language variant. May be empty or null.
|
||||
* @return Code indicating the support status for the locale.
|
||||
* One of {@link TextToSpeech#LANG_AVAILABLE},
|
||||
* {@link TextToSpeech#LANG_COUNTRY_AVAILABLE},
|
||||
* {@link TextToSpeech#LANG_COUNTRY_VAR_AVAILABLE},
|
||||
* {@link TextToSpeech#LANG_MISSING_DATA}
|
||||
* {@link TextToSpeech#LANG_NOT_SUPPORTED}.
|
||||
*/
|
||||
protected abstract int onLoadLanguage(String lang, String country, String variant);
|
||||
|
||||
/**
|
||||
* Notifies the service that it should stop any in-progress speech synthesis.
|
||||
* This method can be called even if no speech synthesis is currently in progress.
|
||||
*
|
||||
* Can be called on multiple threads, but not on the synthesis thread.
|
||||
*/
|
||||
protected abstract void onStop();
|
||||
|
||||
/**
|
||||
* Tells the service to synthesize speech from the given text. This method should
|
||||
* block until the synthesis is finished.
|
||||
*
|
||||
* Called on the synthesis thread.
|
||||
*
|
||||
* @param request The synthesis request. The method should
|
||||
* call {@link SynthesisRequest#start}, {@link SynthesisRequest#audioAvailable},
|
||||
* and {@link SynthesisRequest#done} on this request.
|
||||
* @return {@link TextToSpeech#SUCCESS} or {@link TextToSpeech#ERROR}.
|
||||
*/
|
||||
protected abstract int onSynthesizeText(SynthesisRequest request);
|
||||
|
||||
private boolean areDefaultsEnforced() {
|
||||
return getSecureSettingInt(Settings.Secure.TTS_USE_DEFAULTS,
|
||||
TextToSpeech.Engine.USE_DEFAULTS) == 1;
|
||||
}
|
||||
|
||||
private int getDefaultSpeechRate() {
|
||||
return getSecureSettingInt(Settings.Secure.TTS_DEFAULT_RATE, Engine.DEFAULT_RATE);
|
||||
}
|
||||
|
||||
private String getDefaultLanguage() {
|
||||
return getSecureSettingString(Settings.Secure.TTS_DEFAULT_LANG,
|
||||
Locale.getDefault().getISO3Language());
|
||||
}
|
||||
|
||||
private String getDefaultCountry() {
|
||||
return getSecureSettingString(Settings.Secure.TTS_DEFAULT_COUNTRY,
|
||||
Locale.getDefault().getISO3Country());
|
||||
}
|
||||
|
||||
private String getDefaultVariant() {
|
||||
return getSecureSettingString(Settings.Secure.TTS_DEFAULT_VARIANT,
|
||||
Locale.getDefault().getVariant());
|
||||
}
|
||||
|
||||
private int getSecureSettingInt(String name, int defaultValue) {
|
||||
return Settings.Secure.getInt(getContentResolver(), name, defaultValue);
|
||||
}
|
||||
|
||||
private String getSecureSettingString(String name, String defaultValue) {
|
||||
String value = Settings.Secure.getString(getContentResolver(), name);
|
||||
return value != null ? value : defaultValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Synthesizer thread. This thread is used to run {@link SynthHandler}.
|
||||
*/
|
||||
private class SynthThread extends HandlerThread implements MessageQueue.IdleHandler {
|
||||
|
||||
private boolean mFirstIdle = true;
|
||||
|
||||
public SynthThread() {
|
||||
super(SYNTH_THREAD_NAME, android.os.Process.THREAD_PRIORITY_AUDIO);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onLooperPrepared() {
|
||||
getLooper().getQueue().addIdleHandler(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean queueIdle() {
|
||||
if (mFirstIdle) {
|
||||
mFirstIdle = false;
|
||||
} else {
|
||||
broadcastTtsQueueProcessingCompleted();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private void broadcastTtsQueueProcessingCompleted() {
|
||||
Intent i = new Intent(TextToSpeech.ACTION_TTS_QUEUE_PROCESSING_COMPLETED);
|
||||
if (DBG) Log.d(TAG, "Broadcasting: " + i);
|
||||
sendBroadcast(i);
|
||||
}
|
||||
}
|
||||
|
||||
private class SynthHandler extends Handler {
|
||||
|
||||
private SpeechItem mCurrentSpeechItem = null;
|
||||
|
||||
public SynthHandler(Looper looper) {
|
||||
super(looper);
|
||||
}
|
||||
|
||||
private void dispatchUtteranceCompleted(SpeechItem item) {
|
||||
String utteranceId = item.getUtteranceId();
|
||||
if (!TextUtils.isEmpty(utteranceId)) {
|
||||
mCallbacks.dispatchUtteranceCompleted(item.getCallingApp(), utteranceId);
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized SpeechItem getCurrentSpeechItem() {
|
||||
return mCurrentSpeechItem;
|
||||
}
|
||||
|
||||
private synchronized SpeechItem setCurrentSpeechItem(SpeechItem speechItem) {
|
||||
SpeechItem old = mCurrentSpeechItem;
|
||||
mCurrentSpeechItem = speechItem;
|
||||
return old;
|
||||
}
|
||||
|
||||
public boolean isSpeaking() {
|
||||
return getCurrentSpeechItem() != null;
|
||||
}
|
||||
|
||||
public void quit() {
|
||||
// Don't process any more speech items
|
||||
getLooper().quit();
|
||||
// Stop the current speech item
|
||||
SpeechItem current = setCurrentSpeechItem(null);
|
||||
if (current != null) {
|
||||
current.stop();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a speech item to the queue.
|
||||
*
|
||||
* Called on a service binder thread.
|
||||
*/
|
||||
public int enqueueSpeechItem(int queueMode, final SpeechItem speechItem) {
|
||||
if (!speechItem.isValid()) {
|
||||
return TextToSpeech.ERROR;
|
||||
}
|
||||
// TODO: The old code also supported the undocumented queueMode == 2,
|
||||
// which clears out all pending items from the calling app, as well as all
|
||||
// non-file items from other apps.
|
||||
if (queueMode == TextToSpeech.QUEUE_FLUSH) {
|
||||
stop(speechItem.getCallingApp());
|
||||
}
|
||||
Runnable runnable = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
setCurrentSpeechItem(speechItem);
|
||||
if (speechItem.play() == TextToSpeech.SUCCESS) {
|
||||
dispatchUtteranceCompleted(speechItem);
|
||||
}
|
||||
setCurrentSpeechItem(null);
|
||||
}
|
||||
};
|
||||
Message msg = Message.obtain(this, runnable);
|
||||
// The obj is used to remove all callbacks from the given app in stop(String).
|
||||
msg.obj = speechItem.getCallingApp();
|
||||
if (sendMessage(msg)) {
|
||||
return TextToSpeech.SUCCESS;
|
||||
} else {
|
||||
Log.w(TAG, "SynthThread has quit");
|
||||
return TextToSpeech.ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops all speech output and removes any utterances still in the queue for
|
||||
* the calling app.
|
||||
*
|
||||
* Called on a service binder thread.
|
||||
*/
|
||||
public int stop(String callingApp) {
|
||||
if (TextUtils.isEmpty(callingApp)) {
|
||||
return TextToSpeech.ERROR;
|
||||
}
|
||||
removeCallbacksAndMessages(callingApp);
|
||||
SpeechItem current = setCurrentSpeechItem(null);
|
||||
if (current != null && TextUtils.equals(callingApp, current.getCallingApp())) {
|
||||
current.stop();
|
||||
}
|
||||
return TextToSpeech.SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An item in the synth thread queue.
|
||||
*/
|
||||
private static abstract class SpeechItem {
|
||||
private final String mCallingApp;
|
||||
private final Bundle mParams;
|
||||
private boolean mStarted = false;
|
||||
private boolean mStopped = false;
|
||||
|
||||
public SpeechItem(String callingApp, Bundle params) {
|
||||
mCallingApp = callingApp;
|
||||
mParams = params;
|
||||
}
|
||||
|
||||
public String getCallingApp() {
|
||||
return mCallingApp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checker whether the item is valid. If this method returns false, the item should not
|
||||
* be played.
|
||||
*/
|
||||
public abstract boolean isValid();
|
||||
|
||||
/**
|
||||
* Plays the speech item. Blocks until playback is finished.
|
||||
* Must not be called more than once.
|
||||
*
|
||||
* Only called on the synthesis thread.
|
||||
*
|
||||
* @return {@link TextToSpeech#SUCCESS} or {@link TextToSpeech#ERROR}.
|
||||
*/
|
||||
public int play() {
|
||||
synchronized (this) {
|
||||
if (mStarted) {
|
||||
throw new IllegalStateException("play() called twice");
|
||||
}
|
||||
mStarted = true;
|
||||
}
|
||||
return playImpl();
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops the speech item.
|
||||
* Must not be called more than once.
|
||||
*
|
||||
* Can be called on multiple threads, but not on the synthesis thread.
|
||||
*/
|
||||
public void stop() {
|
||||
synchronized (this) {
|
||||
if (mStopped) {
|
||||
throw new IllegalStateException("stop() called twice");
|
||||
}
|
||||
mStopped = true;
|
||||
}
|
||||
stopImpl();
|
||||
}
|
||||
|
||||
protected abstract int playImpl();
|
||||
|
||||
protected abstract void stopImpl();
|
||||
|
||||
public int getStreamType() {
|
||||
return getIntParam(Engine.KEY_PARAM_STREAM, Engine.DEFAULT_STREAM);
|
||||
}
|
||||
|
||||
public float getVolume() {
|
||||
return getFloatParam(Engine.KEY_PARAM_VOLUME, Engine.DEFAULT_VOLUME);
|
||||
}
|
||||
|
||||
public float getPan() {
|
||||
return getFloatParam(Engine.KEY_PARAM_PAN, Engine.DEFAULT_PAN);
|
||||
}
|
||||
|
||||
public String getUtteranceId() {
|
||||
return getStringParam(Engine.KEY_PARAM_UTTERANCE_ID, null);
|
||||
}
|
||||
|
||||
protected String getStringParam(String key, String defaultValue) {
|
||||
return mParams == null ? defaultValue : mParams.getString(key, defaultValue);
|
||||
}
|
||||
|
||||
protected int getIntParam(String key, int defaultValue) {
|
||||
return mParams == null ? defaultValue : mParams.getInt(key, defaultValue);
|
||||
}
|
||||
|
||||
protected float getFloatParam(String key, float defaultValue) {
|
||||
return mParams == null ? defaultValue : mParams.getFloat(key, defaultValue);
|
||||
}
|
||||
}
|
||||
|
||||
private class SynthesisSpeechItem extends SpeechItem {
|
||||
private final String mText;
|
||||
private SynthesisRequest mSynthesisRequest;
|
||||
|
||||
public SynthesisSpeechItem(String callingApp, Bundle params, String text) {
|
||||
super(callingApp, params);
|
||||
mText = text;
|
||||
}
|
||||
|
||||
public String getText() {
|
||||
return mText;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValid() {
|
||||
if (TextUtils.isEmpty(mText)) {
|
||||
Log.w(TAG, "Got empty text");
|
||||
return false;
|
||||
}
|
||||
if (mText.length() >= MAX_SPEECH_ITEM_CHAR_LENGTH){
|
||||
Log.w(TAG, "Text too long: " + mText.length() + " chars");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int playImpl() {
|
||||
SynthesisRequest synthesisRequest;
|
||||
synchronized (this) {
|
||||
mSynthesisRequest = createSynthesisRequest();
|
||||
synthesisRequest = mSynthesisRequest;
|
||||
}
|
||||
setRequestParams(synthesisRequest);
|
||||
return TextToSpeechService.this.onSynthesizeText(synthesisRequest);
|
||||
}
|
||||
|
||||
protected SynthesisRequest createSynthesisRequest() {
|
||||
return new PlaybackSynthesisRequest(mText, getStreamType(), getVolume(), getPan());
|
||||
}
|
||||
|
||||
private void setRequestParams(SynthesisRequest request) {
|
||||
if (areDefaultsEnforced()) {
|
||||
request.setLanguage(getDefaultLanguage(), getDefaultCountry(), getDefaultVariant());
|
||||
request.setSpeechRate(getDefaultSpeechRate());
|
||||
} else {
|
||||
request.setLanguage(getLanguage(), getCountry(), getVariant());
|
||||
request.setSpeechRate(getSpeechRate());
|
||||
}
|
||||
request.setPitch(getPitch());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void stopImpl() {
|
||||
SynthesisRequest synthesisRequest;
|
||||
synchronized (this) {
|
||||
synthesisRequest = mSynthesisRequest;
|
||||
}
|
||||
synthesisRequest.stop();
|
||||
TextToSpeechService.this.onStop();
|
||||
}
|
||||
|
||||
public String getLanguage() {
|
||||
return getStringParam(Engine.KEY_PARAM_LANGUAGE, getDefaultLanguage());
|
||||
}
|
||||
|
||||
private boolean hasLanguage() {
|
||||
return !TextUtils.isEmpty(getStringParam(Engine.KEY_PARAM_LANGUAGE, null));
|
||||
}
|
||||
|
||||
private String getCountry() {
|
||||
if (!hasLanguage()) return getDefaultCountry();
|
||||
return getStringParam(Engine.KEY_PARAM_COUNTRY, "");
|
||||
}
|
||||
|
||||
private String getVariant() {
|
||||
if (!hasLanguage()) return getDefaultVariant();
|
||||
return getStringParam(Engine.KEY_PARAM_VARIANT, "");
|
||||
}
|
||||
|
||||
private int getSpeechRate() {
|
||||
return getIntParam(Engine.KEY_PARAM_RATE, getDefaultSpeechRate());
|
||||
}
|
||||
|
||||
private int getPitch() {
|
||||
return getIntParam(Engine.KEY_PARAM_PITCH, Engine.DEFAULT_PITCH);
|
||||
}
|
||||
}
|
||||
|
||||
private class SynthesisToFileSpeechItem extends SynthesisSpeechItem {
|
||||
private final File mFile;
|
||||
|
||||
public SynthesisToFileSpeechItem(String callingApp, Bundle params, String text,
|
||||
File file) {
|
||||
super(callingApp, params, text);
|
||||
mFile = file;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValid() {
|
||||
if (!super.isValid()) {
|
||||
return false;
|
||||
}
|
||||
return checkFile(mFile);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SynthesisRequest createSynthesisRequest() {
|
||||
return new FileSynthesisRequest(getText(), mFile);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that the given file can be used for synthesis output.
|
||||
*/
|
||||
private boolean checkFile(File file) {
|
||||
try {
|
||||
if (file.exists()) {
|
||||
Log.v(TAG, "File " + file + " exists, deleting.");
|
||||
if (!file.delete()) {
|
||||
Log.e(TAG, "Failed to delete " + file);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (!file.createNewFile()) {
|
||||
Log.e(TAG, "Can't create file " + file);
|
||||
return false;
|
||||
}
|
||||
if (!file.delete()) {
|
||||
Log.e(TAG, "Failed to delete " + file);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "Can't use " + file + " due to exception " + e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class AudioSpeechItem extends SpeechItem {
|
||||
|
||||
private final BlockingMediaPlayer mPlayer;
|
||||
|
||||
public AudioSpeechItem(String callingApp, Bundle params, Uri uri) {
|
||||
super(callingApp, params);
|
||||
mPlayer = new BlockingMediaPlayer(TextToSpeechService.this, uri, getStreamType());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValid() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int playImpl() {
|
||||
return mPlayer.startAndWait() ? TextToSpeech.SUCCESS : TextToSpeech.ERROR;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void stopImpl() {
|
||||
mPlayer.stop();
|
||||
}
|
||||
}
|
||||
|
||||
private class SilenceSpeechItem extends SpeechItem {
|
||||
private final long mDuration;
|
||||
private final ConditionVariable mDone;
|
||||
|
||||
public SilenceSpeechItem(String callingApp, Bundle params, long duration) {
|
||||
super(callingApp, params);
|
||||
mDuration = duration;
|
||||
mDone = new ConditionVariable();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValid() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int playImpl() {
|
||||
boolean aborted = mDone.block(mDuration);
|
||||
return aborted ? TextToSpeech.ERROR : TextToSpeech.SUCCESS;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void stopImpl() {
|
||||
mDone.open();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBinder onBind(Intent intent) {
|
||||
if (TextToSpeech.Engine.INTENT_ACTION_TTS_SERVICE.equals(intent.getAction())) {
|
||||
return mBinder;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Binder returned from {@code #onBind(Intent)}. The methods in this class can be
|
||||
* called called from several different threads.
|
||||
*/
|
||||
private final ITextToSpeechService.Stub mBinder = new ITextToSpeechService.Stub() {
|
||||
|
||||
public int speak(String callingApp, String text, int queueMode, Bundle params) {
|
||||
SpeechItem item = new SynthesisSpeechItem(callingApp, params, text);
|
||||
return mSynthHandler.enqueueSpeechItem(queueMode, item);
|
||||
}
|
||||
|
||||
public int synthesizeToFile(String callingApp, String text, String filename,
|
||||
Bundle params) {
|
||||
File file = new File(filename);
|
||||
SpeechItem item = new SynthesisToFileSpeechItem(callingApp, params, text, file);
|
||||
return mSynthHandler.enqueueSpeechItem(TextToSpeech.QUEUE_ADD, item);
|
||||
}
|
||||
|
||||
public int playAudio(String callingApp, Uri audioUri, int queueMode, Bundle params) {
|
||||
SpeechItem item = new AudioSpeechItem(callingApp, params, audioUri);
|
||||
return mSynthHandler.enqueueSpeechItem(queueMode, item);
|
||||
}
|
||||
|
||||
public int playSilence(String callingApp, long duration, int queueMode, Bundle params) {
|
||||
SpeechItem item = new SilenceSpeechItem(callingApp, params, duration);
|
||||
return mSynthHandler.enqueueSpeechItem(queueMode, item);
|
||||
}
|
||||
|
||||
public boolean isSpeaking() {
|
||||
return mSynthHandler.isSpeaking();
|
||||
}
|
||||
|
||||
public int stop(String callingApp) {
|
||||
return mSynthHandler.stop(callingApp);
|
||||
}
|
||||
|
||||
public String[] getLanguage() {
|
||||
return onGetLanguage();
|
||||
}
|
||||
|
||||
public int isLanguageAvailable(String lang, String country, String variant) {
|
||||
return onIsLanguageAvailable(lang, country, variant);
|
||||
}
|
||||
|
||||
public int loadLanguage(String lang, String country, String variant) {
|
||||
return onLoadLanguage(lang, country, variant);
|
||||
}
|
||||
|
||||
public void setCallback(String packageName, ITextToSpeechCallback cb) {
|
||||
mCallbacks.setCallback(packageName, cb);
|
||||
}
|
||||
};
|
||||
|
||||
private class CallbackMap extends RemoteCallbackList<ITextToSpeechCallback> {
|
||||
|
||||
private final HashMap<String, ITextToSpeechCallback> mAppToCallback
|
||||
= new HashMap<String, ITextToSpeechCallback>();
|
||||
|
||||
public void setCallback(String packageName, ITextToSpeechCallback cb) {
|
||||
synchronized (mAppToCallback) {
|
||||
ITextToSpeechCallback old;
|
||||
if (cb != null) {
|
||||
register(cb, packageName);
|
||||
old = mAppToCallback.put(packageName, cb);
|
||||
} else {
|
||||
old = mAppToCallback.remove(packageName);
|
||||
}
|
||||
if (old != null && old != cb) {
|
||||
unregister(old);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void dispatchUtteranceCompleted(String packageName, String utteranceId) {
|
||||
ITextToSpeechCallback cb;
|
||||
synchronized (mAppToCallback) {
|
||||
cb = mAppToCallback.get(packageName);
|
||||
}
|
||||
if (cb == null) return;
|
||||
try {
|
||||
cb.utteranceCompleted(utteranceId);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Callback failed: " + e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCallbackDied(ITextToSpeechCallback callback, Object cookie) {
|
||||
String packageName = (String) cookie;
|
||||
synchronized (mAppToCallback) {
|
||||
mAppToCallback.remove(packageName);
|
||||
}
|
||||
mSynthHandler.stop(packageName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void kill() {
|
||||
synchronized (mAppToCallback) {
|
||||
mAppToCallback.clear();
|
||||
super.kill();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,232 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2009 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#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
|
||||
// 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 {
|
||||
|
||||
#define ANDROID_TTS_ENGINE_PROPERTY_CONFIG "engineConfig"
|
||||
#define ANDROID_TTS_ENGINE_PROPERTY_PITCH "pitch"
|
||||
#define ANDROID_TTS_ENGINE_PROPERTY_RATE "rate"
|
||||
#define ANDROID_TTS_ENGINE_PROPERTY_VOLUME "volume"
|
||||
|
||||
|
||||
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. // TODO reword
|
||||
// The callback for synthesis completed takes:
|
||||
// @param [inout] void *& - The userdata pointer set in the original
|
||||
// synth call
|
||||
// @param [in] uint32_t - Track sampling rate in Hz
|
||||
// @param [in] uint32_t - The audio format
|
||||
// @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,
|
||||
uint32_t, int, int8_t *&, size_t&, tts_synth_status);
|
||||
|
||||
class TtsEngine;
|
||||
extern "C" TtsEngine* getTtsEngine();
|
||||
|
||||
enum tts_result {
|
||||
TTS_SUCCESS = 0,
|
||||
TTS_FAILURE = -1,
|
||||
TTS_FEATURE_UNSUPPORTED = -2,
|
||||
TTS_VALUE_INVALID = -3,
|
||||
TTS_PROPERTY_UNSUPPORTED = -4,
|
||||
TTS_PROPERTY_SIZE_TOO_SMALL = -5,
|
||||
TTS_MISSING_RESOURCES = -6
|
||||
};
|
||||
|
||||
enum tts_support_result {
|
||||
TTS_LANG_COUNTRY_VAR_AVAILABLE = 2,
|
||||
TTS_LANG_COUNTRY_AVAILABLE = 1,
|
||||
TTS_LANG_AVAILABLE = 0,
|
||||
TTS_LANG_MISSING_DATA = -1,
|
||||
TTS_LANG_NOT_SUPPORTED = -2
|
||||
};
|
||||
|
||||
class TtsEngine
|
||||
{
|
||||
public:
|
||||
virtual ~TtsEngine() {}
|
||||
|
||||
// Initialize the TTS engine and returns whether initialization succeeded.
|
||||
// @param synthDoneCBPtr synthesis callback function pointer
|
||||
// @return TTS_SUCCESS, or TTS_FAILURE
|
||||
virtual tts_result init(synthDoneCB_t synthDoneCBPtr, const char *engineConfig);
|
||||
|
||||
// Shut down the TTS engine and releases all associated resources.
|
||||
// @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.
|
||||
// @return TTS_SUCCESS, or TTS_FAILURE
|
||||
virtual tts_result stop();
|
||||
|
||||
// Returns the level of support for the language, country and variant.
|
||||
// @return TTS_LANG_COUNTRY_VAR_AVAILABLE if the language, country and variant are supported,
|
||||
// and the corresponding resources are correctly installed
|
||||
// TTS_LANG_COUNTRY_AVAILABLE if the language and country are supported and the
|
||||
// corresponding resources are correctly installed, but there is no match for
|
||||
// the specified variant
|
||||
// TTS_LANG_AVAILABLE if the language is supported and the
|
||||
// corresponding resources are correctly installed, but there is no match for
|
||||
// the specified country and variant
|
||||
// TTS_LANG_MISSING_DATA if the required resources to provide any level of support
|
||||
// for the language are not correctly installed
|
||||
// TTS_LANG_NOT_SUPPORTED if the language is not supported by the TTS engine.
|
||||
virtual tts_support_result isLanguageAvailable(const char *lang, const char *country,
|
||||
const char *variant);
|
||||
|
||||
// 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 and country values are coded according to the ISO three
|
||||
// letter codes for languages and countries, as can be retrieved from a java.util.Locale
|
||||
// instance. The variant value is encoded as the variant string retrieved from a
|
||||
// java.util.Locale instance built with that variant data.
|
||||
// @param lang pointer to the ISO three letter code for the language
|
||||
// @param country pointer to the ISO three letter code for the country
|
||||
// @param variant pointer to the variant code
|
||||
// @return TTS_SUCCESS, or TTS_FAILURE
|
||||
virtual tts_result loadLanguage(const char *lang, const char *country, const char *variant);
|
||||
|
||||
// Load the resources associated with the specified language, country and Locale variant.
|
||||
// The loaded language will only be used once a call to setLanguageFromLocale() with the same
|
||||
// language value is issued. Language and country values are coded according to the ISO three
|
||||
// letter codes for languages and countries, as can be retrieved from a java.util.Locale
|
||||
// instance. The variant value is encoded as the variant string retrieved from a
|
||||
// java.util.Locale instance built with that variant data.
|
||||
// @param lang pointer to the ISO three letter code for the language
|
||||
// @param country pointer to the ISO three letter code for the country
|
||||
// @param variant pointer to the variant code
|
||||
// @return TTS_SUCCESS, or TTS_FAILURE
|
||||
virtual tts_result setLanguage(const char *lang, const char *country, const char *variant);
|
||||
|
||||
// Retrieve the currently set language, country and variant, or empty strings if none of
|
||||
// parameters have been set. Language and country are represented by their 3-letter ISO code
|
||||
// @param[out] pointer to the retrieved 3-letter code language value
|
||||
// @param[out] pointer to the retrieved 3-letter code country value
|
||||
// @param[out] pointer to the retrieved variant value
|
||||
// @return TTS_SUCCESS, or TTS_FAILURE
|
||||
virtual tts_result getLanguage(char *language, char *country, char *variant);
|
||||
|
||||
// Notifies the engine what audio parameters should be used for the synthesis.
|
||||
// This is meant to be used as a hint, the engine implementation will set the output values
|
||||
// to those of the synthesis format, based on a given hint.
|
||||
// @param[inout] encoding in: the desired audio sample format
|
||||
// out: the format used by the TTS engine
|
||||
// @param[inout] rate in: the desired audio sample rate
|
||||
// out: the sample rate used by the TTS engine
|
||||
// @param[inout] channels in: the desired number of audio channels
|
||||
// out: the number of channels used by the TTS engine
|
||||
// @return TTS_SUCCESS, or TTS_FAILURE
|
||||
virtual tts_result setAudioFormat(AudioSystem::audio_format& encoding, uint32_t& rate,
|
||||
int& channels);
|
||||
|
||||
// Set a property for the the TTS engine
|
||||
// "size" is the maximum size of "value" for properties "property"
|
||||
// @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,
|
||||
// or TTS_VALUE_INVALID
|
||||
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);
|
||||
|
||||
// Synthesize the 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 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:
|
||||
// o interpret-as
|
||||
// * phoneme
|
||||
// * voice:
|
||||
// o gender,
|
||||
// o age,
|
||||
// o variant,
|
||||
// o name
|
||||
// * emphasis
|
||||
// * break:
|
||||
// o strength,
|
||||
// o time
|
||||
// * prosody:
|
||||
// o pitch,
|
||||
// o contour,
|
||||
// o range,
|
||||
// o rate,
|
||||
// o duration,
|
||||
// o volume
|
||||
// * mark
|
||||
// Differences between this text format and SSML are:
|
||||
// * full SSML documents are not supported
|
||||
// * namespaces are not supported
|
||||
// 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, int8_t *buffer,
|
||||
size_t bufferSize, void *userdata);
|
||||
|
||||
};
|
||||
|
||||
} // namespace android
|
||||
|
||||
@@ -1,313 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2009 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#ifndef ANDROID_TTS_H
|
||||
#define ANDROID_TTS_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.
|
||||
|
||||
// The shared library must contain a function named "android_getTtsEngine"
|
||||
// that returns an 'android_tts_engine_t' instance.
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define ANDROID_TTS_ENGINE_PROPERTY_CONFIG "engineConfig"
|
||||
#define ANDROID_TTS_ENGINE_PROPERTY_PITCH "pitch"
|
||||
#define ANDROID_TTS_ENGINE_PROPERTY_RATE "rate"
|
||||
#define ANDROID_TTS_ENGINE_PROPERTY_VOLUME "volume"
|
||||
|
||||
typedef enum {
|
||||
ANDROID_TTS_SUCCESS = 0,
|
||||
ANDROID_TTS_FAILURE = -1,
|
||||
ANDROID_TTS_FEATURE_UNSUPPORTED = -2,
|
||||
ANDROID_TTS_VALUE_INVALID = -3,
|
||||
ANDROID_TTS_PROPERTY_UNSUPPORTED = -4,
|
||||
ANDROID_TTS_PROPERTY_SIZE_TOO_SMALL = -5,
|
||||
ANDROID_TTS_MISSING_RESOURCES = -6
|
||||
} android_tts_result_t;
|
||||
|
||||
typedef enum {
|
||||
ANDROID_TTS_LANG_COUNTRY_VAR_AVAILABLE = 2,
|
||||
ANDROID_TTS_LANG_COUNTRY_AVAILABLE = 1,
|
||||
ANDROID_TTS_LANG_AVAILABLE = 0,
|
||||
ANDROID_TTS_LANG_MISSING_DATA = -1,
|
||||
ANDROID_TTS_LANG_NOT_SUPPORTED = -2
|
||||
} android_tts_support_result_t;
|
||||
|
||||
typedef enum {
|
||||
ANDROID_TTS_SYNTH_DONE = 0,
|
||||
ANDROID_TTS_SYNTH_PENDING = 1
|
||||
} android_tts_synth_status_t;
|
||||
|
||||
typedef enum {
|
||||
ANDROID_TTS_CALLBACK_HALT = 0,
|
||||
ANDROID_TTS_CALLBACK_CONTINUE = 1
|
||||
} android_tts_callback_status_t;
|
||||
|
||||
// Supported audio formats
|
||||
typedef enum {
|
||||
ANDROID_TTS_AUDIO_FORMAT_INVALID = -1,
|
||||
ANDROID_TTS_AUDIO_FORMAT_DEFAULT = 0,
|
||||
ANDROID_TTS_AUDIO_FORMAT_PCM_16_BIT = 1,
|
||||
ANDROID_TTS_AUDIO_FORMAT_PCM_8_BIT = 2,
|
||||
} android_tts_audio_format_t;
|
||||
|
||||
|
||||
/* An android_tts_engine_t object can be anything, but must have,
|
||||
* as its first field, a pointer to a table of functions.
|
||||
*
|
||||
* See the full definition of struct android_tts_engine_t_funcs_t
|
||||
* below for details.
|
||||
*/
|
||||
typedef struct android_tts_engine_funcs_t android_tts_engine_funcs_t;
|
||||
|
||||
typedef struct {
|
||||
android_tts_engine_funcs_t *funcs;
|
||||
} android_tts_engine_t;
|
||||
|
||||
/* This function must be located in the TTS Engine shared library
|
||||
* and must return the address of an android_tts_engine_t library.
|
||||
*/
|
||||
extern android_tts_engine_t *android_getTtsEngine();
|
||||
|
||||
/* Including the old version for legacy support (Froyo compatibility).
|
||||
* This should return the same thing as android_getTtsEngine.
|
||||
*/
|
||||
extern "C" android_tts_engine_t *getTtsEngine();
|
||||
|
||||
// A callback type used to notify the framework of new synthetized
|
||||
// audio samples, status will be SYNTH_DONE for the last sample of
|
||||
// the last request, of SYNTH_PENDING otherwise.
|
||||
//
|
||||
// This is passed by the framework to the engine through the
|
||||
// 'engine_init' function (see below).
|
||||
//
|
||||
// The callback for synthesis completed takes:
|
||||
// @param [inout] void *& - The userdata pointer set in the original
|
||||
// synth call
|
||||
// @param [in] uint32_t - Track sampling rate in Hz
|
||||
// @param [in] uint32_t - The audio format
|
||||
// @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 android_tts_callback_status_t (*android_tts_synth_cb_t)
|
||||
(void **pUserData,
|
||||
uint32_t trackSamplingHz,
|
||||
android_tts_audio_format_t audioFormat,
|
||||
int channelCount,
|
||||
int8_t **pAudioBuffer,
|
||||
size_t *pBufferSize,
|
||||
android_tts_synth_status_t status);
|
||||
|
||||
|
||||
// The table of function pointers that the android_tts_engine_t must point to.
|
||||
// Note that each of these functions will take a handle to the engine itself
|
||||
// as their first parameter.
|
||||
//
|
||||
|
||||
struct android_tts_engine_funcs_t {
|
||||
// reserved fields, ignored by the framework
|
||||
// they must be placed here to ensure binary compatibility
|
||||
// of legacy binary plugins.
|
||||
void *reserved[2];
|
||||
|
||||
// Initialize the TTS engine and returns whether initialization succeeded.
|
||||
// @param synthDoneCBPtr synthesis callback function pointer
|
||||
// @return TTS_SUCCESS, or TTS_FAILURE
|
||||
android_tts_result_t (*init)
|
||||
(void *engine,
|
||||
android_tts_synth_cb_t synthDonePtr,
|
||||
const char *engineConfig);
|
||||
|
||||
// Shut down the TTS engine and releases all associated resources.
|
||||
// @return TTS_SUCCESS, or TTS_FAILURE
|
||||
android_tts_result_t (*shutdown)
|
||||
(void *engine);
|
||||
|
||||
// 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
|
||||
android_tts_result_t (*stop)
|
||||
(void *engine);
|
||||
|
||||
// Returns the level of support for the language, country and variant.
|
||||
// @return TTS_LANG_COUNTRY_VAR_AVAILABLE if the language, country and variant are supported,
|
||||
// and the corresponding resources are correctly installed
|
||||
// TTS_LANG_COUNTRY_AVAILABLE if the language and country are supported and the
|
||||
// corresponding resources are correctly installed, but there is no match for
|
||||
// the specified variant
|
||||
// TTS_LANG_AVAILABLE if the language is supported and the
|
||||
// corresponding resources are correctly installed, but there is no match for
|
||||
// the specified country and variant
|
||||
// TTS_LANG_MISSING_DATA if the required resources to provide any level of support
|
||||
// for the language are not correctly installed
|
||||
// TTS_LANG_NOT_SUPPORTED if the language is not supported by the TTS engine.
|
||||
android_tts_support_result_t (*isLanguageAvailable)
|
||||
(void *engine,
|
||||
const char *lang,
|
||||
const char *country,
|
||||
const char *variant);
|
||||
|
||||
// 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 and country values are coded according to the ISO three
|
||||
// letter codes for languages and countries, as can be retrieved from a java.util.Locale
|
||||
// instance. The variant value is encoded as the variant string retrieved from a
|
||||
// java.util.Locale instance built with that variant data.
|
||||
// @param lang pointer to the ISO three letter code for the language
|
||||
// @param country pointer to the ISO three letter code for the country
|
||||
// @param variant pointer to the variant code
|
||||
// @return TTS_SUCCESS, or TTS_FAILURE
|
||||
android_tts_result_t (*loadLanguage)
|
||||
(void *engine,
|
||||
const char *lang,
|
||||
const char *country,
|
||||
const char *variant);
|
||||
|
||||
// Load the resources associated with the specified language, country and Locale variant.
|
||||
// The loaded language will only be used once a call to setLanguageFromLocale() with the same
|
||||
// language value is issued. Language and country values are coded according to the ISO three
|
||||
// letter codes for languages and countries, as can be retrieved from a java.util.Locale
|
||||
// instance. The variant value is encoded as the variant string retrieved from a
|
||||
// java.util.Locale instance built with that variant data.
|
||||
// @param lang pointer to the ISO three letter code for the language
|
||||
// @param country pointer to the ISO three letter code for the country
|
||||
// @param variant pointer to the variant code
|
||||
// @return TTS_SUCCESS, or TTS_FAILURE
|
||||
android_tts_result_t (*setLanguage)
|
||||
(void *engine,
|
||||
const char *lang,
|
||||
const char *country,
|
||||
const char *variant);
|
||||
|
||||
// Retrieve the currently set language, country and variant, or empty strings if none of
|
||||
// parameters have been set. Language and country are represented by their 3-letter ISO code
|
||||
// @param[out] pointer to the retrieved 3-letter code language value
|
||||
// @param[out] pointer to the retrieved 3-letter code country value
|
||||
// @param[out] pointer to the retrieved variant value
|
||||
// @return TTS_SUCCESS, or TTS_FAILURE
|
||||
android_tts_result_t (*getLanguage)
|
||||
(void *engine,
|
||||
char *language,
|
||||
char *country,
|
||||
char *variant);
|
||||
|
||||
// Notifies the engine what audio parameters should be used for the synthesis.
|
||||
// This is meant to be used as a hint, the engine implementation will set the output values
|
||||
// to those of the synthesis format, based on a given hint.
|
||||
// @param[inout] encoding in: the desired audio sample format
|
||||
// out: the format used by the TTS engine
|
||||
// @param[inout] rate in: the desired audio sample rate
|
||||
// out: the sample rate used by the TTS engine
|
||||
// @param[inout] channels in: the desired number of audio channels
|
||||
// out: the number of channels used by the TTS engine
|
||||
// @return TTS_SUCCESS, or TTS_FAILURE
|
||||
android_tts_result_t (*setAudioFormat)
|
||||
(void *engine,
|
||||
android_tts_audio_format_t* pEncoding,
|
||||
uint32_t* pRate,
|
||||
int* pChannels);
|
||||
|
||||
// Set a property for the the TTS engine
|
||||
// "size" is the maximum size of "value" for properties "property"
|
||||
// @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,
|
||||
// or TTS_VALUE_INVALID
|
||||
android_tts_result_t (*setProperty)
|
||||
(void *engine,
|
||||
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
|
||||
android_tts_result_t (*getProperty)
|
||||
(void *engine,
|
||||
const char *property,
|
||||
char *value,
|
||||
size_t *iosize);
|
||||
|
||||
// Synthesize the 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 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:
|
||||
// o interpret-as
|
||||
// * phoneme
|
||||
// * voice:
|
||||
// o gender,
|
||||
// o age,
|
||||
// o variant,
|
||||
// o name
|
||||
// * emphasis
|
||||
// * break:
|
||||
// o strength,
|
||||
// o time
|
||||
// * prosody:
|
||||
// o pitch,
|
||||
// o contour,
|
||||
// o range,
|
||||
// o rate,
|
||||
// o duration,
|
||||
// o volume
|
||||
// * mark
|
||||
// Differences between this text format and SSML are:
|
||||
// * full SSML documents are not supported
|
||||
// * namespaces are not supported
|
||||
// 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
|
||||
android_tts_result_t (*synthesizeText)
|
||||
(void *engine,
|
||||
const char *text,
|
||||
int8_t *buffer,
|
||||
size_t bufferSize,
|
||||
void *userdata);
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* ANDROID_TTS_H */
|
||||
@@ -1,15 +0,0 @@
|
||||
LOCAL_PATH:= $(call my-dir)
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
|
||||
LOCAL_SRC_FILES := $(call all-subdir-java-files) \
|
||||
|
||||
LOCAL_PACKAGE_NAME := TtsService
|
||||
LOCAL_CERTIFICATE := platform
|
||||
|
||||
LOCAL_PROGUARD_FLAG_FILES := proguard.flags
|
||||
|
||||
include $(BUILD_PACKAGE)
|
||||
|
||||
include $(call all-makefiles-under,$(LOCAL_PATH))
|
||||
@@ -1,17 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="android.tts">
|
||||
<application android:label="TTS Service"
|
||||
android:icon="@drawable/ic_launcher_text_to_speech">
|
||||
<service android:enabled="true"
|
||||
android:name=".TtsService"
|
||||
android:label="TTS Service">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.START_TTS_SERVICE"/>
|
||||
<category android:name="android.intent.category.TTS"/>
|
||||
</intent-filter>
|
||||
</service>
|
||||
</application>
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||
</manifest>
|
||||
@@ -1,190 +0,0 @@
|
||||
|
||||
Copyright (c) 2009, The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
LOCAL_PATH:= $(call my-dir)
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_SRC_FILES:= \
|
||||
android_tts_SynthProxy.cpp
|
||||
|
||||
LOCAL_C_INCLUDES += \
|
||||
frameworks/base/native/include \
|
||||
$(JNI_H_INCLUDE)
|
||||
|
||||
LOCAL_SHARED_LIBRARIES := \
|
||||
libandroid_runtime \
|
||||
libnativehelper \
|
||||
libmedia \
|
||||
libutils \
|
||||
libcutils
|
||||
|
||||
ifeq ($(TARGET_SIMULATOR),true)
|
||||
LOCAL_LDLIBS += -ldl
|
||||
else
|
||||
LOCAL_SHARED_LIBRARIES += libdl
|
||||
endif
|
||||
|
||||
|
||||
LOCAL_MODULE:= libttssynthproxy
|
||||
|
||||
LOCAL_ARM_MODE := arm
|
||||
|
||||
include $(BUILD_SHARED_LIBRARY)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,5 +0,0 @@
|
||||
-keep class android.tts.SynthProxy {
|
||||
int mJniData;
|
||||
# keep all declarations for native methods
|
||||
<methods>;
|
||||
}
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 6.8 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 6.6 KiB |
@@ -1,238 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2009 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
package android.tts;
|
||||
|
||||
import android.media.AudioManager;
|
||||
import android.media.AudioSystem;
|
||||
import android.util.Log;
|
||||
import java.lang.ref.WeakReference;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*
|
||||
* The SpeechSynthesis class provides a high-level api to create and play
|
||||
* synthesized speech. This class is used internally to talk to a native
|
||||
* TTS library that implements the interface defined in
|
||||
* frameworks/base/include/tts/TtsEngine.h
|
||||
*
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class SynthProxy {
|
||||
|
||||
// Default parameters of a filter to be applied when using the Pico engine.
|
||||
// Such a huge filter gain is justified by how much energy in the low frequencies is "wasted" at
|
||||
// the output of the synthesis. The low shelving filter removes it, leaving room for
|
||||
// amplification.
|
||||
private final static float PICO_FILTER_GAIN = 5.0f; // linear gain
|
||||
private final static float PICO_FILTER_LOWSHELF_ATTENUATION = -18.0f; // in dB
|
||||
private final static float PICO_FILTER_TRANSITION_FREQ = 1100.0f; // in Hz
|
||||
private final static float PICO_FILTER_SHELF_SLOPE = 1.0f; // Q
|
||||
|
||||
//
|
||||
// External API
|
||||
//
|
||||
|
||||
/**
|
||||
* Constructor; pass the location of the native TTS .so to use.
|
||||
*/
|
||||
public SynthProxy(String nativeSoLib, String engineConfig) {
|
||||
boolean applyFilter = nativeSoLib.toLowerCase().contains("pico");
|
||||
Log.v(TtsService.SERVICE_TAG, "About to load "+ nativeSoLib + ", applyFilter="+applyFilter);
|
||||
native_setup(new WeakReference<SynthProxy>(this), nativeSoLib, engineConfig);
|
||||
native_setLowShelf(applyFilter, PICO_FILTER_GAIN, PICO_FILTER_LOWSHELF_ATTENUATION,
|
||||
PICO_FILTER_TRANSITION_FREQ, PICO_FILTER_SHELF_SLOPE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops and clears the AudioTrack.
|
||||
*/
|
||||
public int stop() {
|
||||
return native_stop(mJniData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Synchronous stop of the synthesizer. This method returns when the synth
|
||||
* has completed the stop procedure and doesn't use any of the resources it
|
||||
* was using while synthesizing.
|
||||
*
|
||||
* @return {@link android.speech.tts.TextToSpeech.SUCCESS} or
|
||||
* {@link android.speech.tts.TextToSpeech.ERROR}
|
||||
*/
|
||||
public int stopSync() {
|
||||
return native_stopSync(mJniData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Synthesize speech and speak it directly using AudioTrack.
|
||||
*/
|
||||
public int speak(String text, int streamType, float volume, float pan) {
|
||||
Log.i(TAG, "speak() on stream "+ streamType);
|
||||
if ((streamType > -1) && (streamType < AudioSystem.getNumStreamTypes())) {
|
||||
return native_speak(mJniData, text, streamType, volume, pan);
|
||||
} else {
|
||||
Log.e("SynthProxy", "Trying to speak with invalid stream type " + streamType);
|
||||
return native_speak(mJniData, text, AudioManager.STREAM_MUSIC, volume, pan);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Synthesize speech to a file. The current implementation writes a valid
|
||||
* WAV file to the given path, assuming it is writable. Something like
|
||||
* "/sdcard/???.wav" is recommended.
|
||||
*/
|
||||
public int synthesizeToFile(String text, String filename) {
|
||||
Log.i(TAG, "synthesizeToFile() to file "+ filename);
|
||||
return native_synthesizeToFile(mJniData, text, filename);
|
||||
}
|
||||
|
||||
/**
|
||||
* Queries for language support.
|
||||
* Return codes are defined in android.speech.tts.TextToSpeech
|
||||
*/
|
||||
public int isLanguageAvailable(String language, String country, String variant) {
|
||||
return native_isLanguageAvailable(mJniData, language, country, variant);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the engine configuration.
|
||||
*/
|
||||
public int setConfig(String engineConfig) {
|
||||
return native_setConfig(mJniData, engineConfig);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the language.
|
||||
*/
|
||||
public int setLanguage(String language, String country, String variant) {
|
||||
return native_setLanguage(mJniData, language, country, variant);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the language: it's not set, but prepared for use later.
|
||||
*/
|
||||
public int loadLanguage(String language, String country, String variant) {
|
||||
return native_loadLanguage(mJniData, language, country, variant);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the speech rate.
|
||||
*/
|
||||
public final int setSpeechRate(int speechRate) {
|
||||
return native_setSpeechRate(mJniData, speechRate);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the pitch of the synthesized voice.
|
||||
*/
|
||||
public final int setPitch(int pitch) {
|
||||
return native_setPitch(mJniData, pitch);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the currently set language, country and variant information.
|
||||
*/
|
||||
public String[] getLanguage() {
|
||||
return native_getLanguage(mJniData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the currently set rate.
|
||||
*/
|
||||
public int getRate() {
|
||||
return native_getRate(mJniData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Shuts down the native synthesizer.
|
||||
*/
|
||||
public void shutdown() {
|
||||
native_shutdown(mJniData);
|
||||
}
|
||||
|
||||
//
|
||||
// Internal
|
||||
//
|
||||
|
||||
protected void finalize() {
|
||||
native_finalize(mJniData);
|
||||
mJniData = 0;
|
||||
}
|
||||
|
||||
static {
|
||||
System.loadLibrary("ttssynthproxy");
|
||||
}
|
||||
|
||||
private final static String TAG = "SynthProxy";
|
||||
|
||||
/**
|
||||
* Accessed by native methods
|
||||
*/
|
||||
private int mJniData = 0;
|
||||
|
||||
private native final int native_setup(Object weak_this, String nativeSoLib,
|
||||
String engineConfig);
|
||||
|
||||
private native final int native_setLowShelf(boolean applyFilter, float filterGain,
|
||||
float attenuationInDb, float freqInHz, float slope);
|
||||
|
||||
private native final void native_finalize(int jniData);
|
||||
|
||||
private native final int native_stop(int jniData);
|
||||
|
||||
private native final int native_stopSync(int jniData);
|
||||
|
||||
private native final int native_speak(int jniData, String text, int streamType, float volume,
|
||||
float pan);
|
||||
|
||||
private native final int native_synthesizeToFile(int jniData, String text, String filename);
|
||||
|
||||
private native final int native_isLanguageAvailable(int jniData, String language,
|
||||
String country, String variant);
|
||||
|
||||
private native final int native_setLanguage(int jniData, String language, String country,
|
||||
String variant);
|
||||
|
||||
private native final int native_loadLanguage(int jniData, String language, String country,
|
||||
String variant);
|
||||
|
||||
private native final int native_setConfig(int jniData, String engineConfig);
|
||||
|
||||
private native final int native_setSpeechRate(int jniData, int speechRate);
|
||||
|
||||
private native final int native_setPitch(int jniData, int speechRate);
|
||||
|
||||
private native final String[] native_getLanguage(int jniData);
|
||||
|
||||
private native final int native_getRate(int jniData);
|
||||
|
||||
private native final void native_shutdown(int jniData);
|
||||
|
||||
|
||||
/**
|
||||
* Callback from the C layer
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
private static void postNativeSpeechSynthesizedInJava(Object tts_ref,
|
||||
int bufferPointer, int bufferSize) {
|
||||
|
||||
Log.i("TTS plugin debug", "bufferPointer: " + bufferPointer
|
||||
+ " bufferSize: " + bufferSize);
|
||||
|
||||
SynthProxy nativeTTS = (SynthProxy)((WeakReference)tts_ref).get();
|
||||
// TODO notify TTS service of synthesis/playback completion,
|
||||
// method definition to be changed.
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user