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:
Bjorn Bringert
2011-03-08 16:00:40 +00:00
parent 720dd9a898
commit 50e657bb2d
24 changed files with 2106 additions and 4369 deletions

View File

@@ -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 \

View File

@@ -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

View 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();
}
}

View 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;
}
}

View File

@@ -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);
}

View 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);
}

View File

@@ -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();
}

View 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;
}
}

View 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

View 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();
}
}
}
}

View File

@@ -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

View File

@@ -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 */

View File

@@ -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))

View File

@@ -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>

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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