diff options
author | Przemyslaw Szczepaniak <pszczepaniak@google.com> | 2014-06-26 11:52:20 +0100 |
---|---|---|
committer | Przemyslaw Szczepaniak <pszczepaniak@google.com> | 2014-06-30 11:25:12 +0100 |
commit | fc4b2890378eb1b6e0b11d60d703eb6854268064 (patch) | |
tree | 181cd577565b415446beb75cbf7bf0c30ee0bf1c /core/java/android/speech | |
parent | 1422c5f6856a98464690a433da2c38205e70146e (diff) | |
download | frameworks_base-fc4b2890378eb1b6e0b11d60d703eb6854268064.zip frameworks_base-fc4b2890378eb1b6e0b11d60d703eb6854268064.tar.gz frameworks_base-fc4b2890378eb1b6e0b11d60d703eb6854268064.tar.bz2 |
Remove TextToSpeechClient API.
Removed all of TTS V2 api with exception of error codes.
Bug: 15834470
Change-Id: I9d9d2aad01811af9b86bf7a3fd018a8d4e5c2f33
Diffstat (limited to 'core/java/android/speech')
23 files changed, 109 insertions, 2947 deletions
diff --git a/core/java/android/speech/tts/AbstractEventLogger.java b/core/java/android/speech/tts/AbstractEventLogger.java index 37f8656..6d27d8c 100644 --- a/core/java/android/speech/tts/AbstractEventLogger.java +++ b/core/java/android/speech/tts/AbstractEventLogger.java @@ -104,7 +104,7 @@ abstract class AbstractEventLogger { // onAudioDataWritten() should normally always be called, and hence mPlaybackStartTime // should be set, if an error does not occur. - if (statusCode != TextToSpeechClient.Status.SUCCESS + if (statusCode != TextToSpeech.SUCCESS || mPlaybackStartTime == -1 || mEngineCompleteTime == -1) { logFailure(statusCode); return; diff --git a/core/java/android/speech/tts/AbstractSynthesisCallback.java b/core/java/android/speech/tts/AbstractSynthesisCallback.java index 91e119b..67f7431 100644 --- a/core/java/android/speech/tts/AbstractSynthesisCallback.java +++ b/core/java/android/speech/tts/AbstractSynthesisCallback.java @@ -54,6 +54,6 @@ abstract class AbstractSynthesisCallback implements SynthesisCallback { * while in {@link TextToSpeechService#onSynthesizeText}. */ int errorCodeOnStop() { - return mClientIsUsingV2 ? TextToSpeechClient.Status.STOPPED : TextToSpeech.ERROR; + return mClientIsUsingV2 ? TextToSpeech.STOPPED : TextToSpeech.ERROR; } } diff --git a/core/java/android/speech/tts/AudioPlaybackHandler.java b/core/java/android/speech/tts/AudioPlaybackHandler.java index dcf49b0..1f1863c 100644 --- a/core/java/android/speech/tts/AudioPlaybackHandler.java +++ b/core/java/android/speech/tts/AudioPlaybackHandler.java @@ -43,7 +43,7 @@ class AudioPlaybackHandler { return; } - item.stop(TextToSpeechClient.Status.STOPPED); + item.stop(TextToSpeech.STOPPED); } public void enqueue(PlaybackQueueItem item) { diff --git a/core/java/android/speech/tts/AudioPlaybackQueueItem.java b/core/java/android/speech/tts/AudioPlaybackQueueItem.java index c514639..03e53ec 100644 --- a/core/java/android/speech/tts/AudioPlaybackQueueItem.java +++ b/core/java/android/speech/tts/AudioPlaybackQueueItem.java @@ -53,7 +53,7 @@ class AudioPlaybackQueueItem extends PlaybackQueueItem { dispatcher.dispatchOnStart(); mPlayer = MediaPlayer.create(mContext, mUri); if (mPlayer == null) { - dispatcher.dispatchOnError(TextToSpeechClient.Status.ERROR_OUTPUT); + dispatcher.dispatchOnError(TextToSpeech.ERROR_OUTPUT); return; } diff --git a/core/java/android/speech/tts/EventLoggerV1.java b/core/java/android/speech/tts/EventLoggerV1.java index f484347..2b02b43 100644 --- a/core/java/android/speech/tts/EventLoggerV1.java +++ b/core/java/android/speech/tts/EventLoggerV1.java @@ -35,7 +35,7 @@ class EventLoggerV1 extends AbstractEventLogger { // We don't report stopped syntheses because their overall // total time spent will be inaccurate (will not correlate with // the length of the utterance). - if (statusCode != TextToSpeechClient.Status.STOPPED) { + if (statusCode != TextToSpeech.STOPPED) { EventLogTags.writeTtsSpeakFailure(mServiceApp, mCallerUid, mCallerPid, getUtteranceLength(), getLocaleString(), mRequest.getSpeechRate(), mRequest.getPitch()); diff --git a/core/java/android/speech/tts/EventLoggerV2.java b/core/java/android/speech/tts/EventLoggerV2.java deleted file mode 100644 index b8e4dae..0000000 --- a/core/java/android/speech/tts/EventLoggerV2.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (C) 2013 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; - - - -/** - * Writes data about a given speech synthesis request for V2 API to the event logs. - * The data that is logged includes the calling app, length of the utterance, - * synthesis request configuration and the latency and overall time taken. - */ -class EventLoggerV2 extends AbstractEventLogger { - private final SynthesisRequestV2 mRequest; - - EventLoggerV2(SynthesisRequestV2 request, int callerUid, int callerPid, String serviceApp) { - super(callerUid, callerPid, serviceApp); - mRequest = request; - } - - @Override - protected void logFailure(int statusCode) { - // We don't report stopped syntheses because their overall - // total time spent will be inaccurate (will not correlate with - // the length of the utterance). - if (statusCode != TextToSpeechClient.Status.STOPPED) { - EventLogTags.writeTtsV2SpeakFailure(mServiceApp, - mCallerUid, mCallerPid, getUtteranceLength(), getRequestConfigString(), statusCode); - } - } - - @Override - protected void logSuccess(long audioLatency, long engineLatency, long engineTotal) { - EventLogTags.writeTtsV2SpeakSuccess(mServiceApp, - mCallerUid, mCallerPid, getUtteranceLength(), getRequestConfigString(), - engineLatency, engineTotal, audioLatency); - } - - /** - * @return the length of the utterance for the given synthesis, 0 - * if the utterance was {@code null}. - */ - private int getUtteranceLength() { - final String utterance = mRequest.getText(); - return utterance == null ? 0 : utterance.length(); - } - - /** - * Returns a string representation of the synthesis request configuration. - */ - private String getRequestConfigString() { - // Ensure the bundles are unparceled. - mRequest.getVoiceParams().size(); - mRequest.getAudioParams().size(); - - return new StringBuilder(64).append("VoiceName: ").append(mRequest.getVoiceName()) - .append(" ,VoiceParams: ").append(mRequest.getVoiceParams()) - .append(" ,SystemParams: ").append(mRequest.getAudioParams()) - .append("]").toString(); - } -} diff --git a/core/java/android/speech/tts/FileSynthesisCallback.java b/core/java/android/speech/tts/FileSynthesisCallback.java index d84f7f0..a88eead 100644 --- a/core/java/android/speech/tts/FileSynthesisCallback.java +++ b/core/java/android/speech/tts/FileSynthesisCallback.java @@ -60,7 +60,7 @@ class FileSynthesisCallback extends AbstractSynthesisCallback { mFileChannel = fileChannel; mDispatcher = dispatcher; mCallerIdentity = callerIdentity; - mStatusCode = TextToSpeechClient.Status.SUCCESS; + mStatusCode = TextToSpeech.SUCCESS; } @Override @@ -69,11 +69,11 @@ class FileSynthesisCallback extends AbstractSynthesisCallback { if (mDone) { return; } - if (mStatusCode == TextToSpeechClient.Status.STOPPED) { + if (mStatusCode == TextToSpeech.STOPPED) { return; } - mStatusCode = TextToSpeechClient.Status.STOPPED; + mStatusCode = TextToSpeech.STOPPED; cleanUp(); if (mDispatcher != null) { mDispatcher.dispatchOnStop(); @@ -109,11 +109,11 @@ class FileSynthesisCallback extends AbstractSynthesisCallback { } FileChannel fileChannel = null; synchronized (mStateLock) { - if (mStatusCode == TextToSpeechClient.Status.STOPPED) { + if (mStatusCode == TextToSpeech.STOPPED) { if (DBG) Log.d(TAG, "Request has been aborted."); return errorCodeOnStop(); } - if (mStatusCode != TextToSpeechClient.Status.SUCCESS) { + if (mStatusCode != TextToSpeech.SUCCESS) { if (DBG) Log.d(TAG, "Error was raised"); return TextToSpeech.ERROR; } @@ -139,7 +139,7 @@ class FileSynthesisCallback extends AbstractSynthesisCallback { Log.e(TAG, "Failed to write wav header to output file descriptor", ex); synchronized (mStateLock) { cleanUp(); - mStatusCode = TextToSpeechClient.Status.ERROR_OUTPUT; + mStatusCode = TextToSpeech.ERROR_OUTPUT; } return TextToSpeech.ERROR; } @@ -153,17 +153,17 @@ class FileSynthesisCallback extends AbstractSynthesisCallback { } FileChannel fileChannel = null; synchronized (mStateLock) { - if (mStatusCode == TextToSpeechClient.Status.STOPPED) { + if (mStatusCode == TextToSpeech.STOPPED) { if (DBG) Log.d(TAG, "Request has been aborted."); return errorCodeOnStop(); } - if (mStatusCode != TextToSpeechClient.Status.SUCCESS) { + if (mStatusCode != TextToSpeech.SUCCESS) { if (DBG) Log.d(TAG, "Error was raised"); return TextToSpeech.ERROR; } if (mFileChannel == null) { Log.e(TAG, "File not open"); - mStatusCode = TextToSpeechClient.Status.ERROR_OUTPUT; + mStatusCode = TextToSpeech.ERROR_OUTPUT; return TextToSpeech.ERROR; } if (!mStarted) { @@ -180,7 +180,7 @@ class FileSynthesisCallback extends AbstractSynthesisCallback { Log.e(TAG, "Failed to write to output file descriptor", ex); synchronized (mStateLock) { cleanUp(); - mStatusCode = TextToSpeechClient.Status.ERROR_OUTPUT; + mStatusCode = TextToSpeech.ERROR_OUTPUT; } return TextToSpeech.ERROR; } @@ -202,12 +202,12 @@ class FileSynthesisCallback extends AbstractSynthesisCallback { // setStatusCode is set. return TextToSpeech.ERROR; } - if (mStatusCode == TextToSpeechClient.Status.STOPPED) { + if (mStatusCode == TextToSpeech.STOPPED) { if (DBG) Log.d(TAG, "Request has been aborted."); return errorCodeOnStop(); } - if (mDispatcher != null && mStatusCode != TextToSpeechClient.Status.SUCCESS && - mStatusCode != TextToSpeechClient.Status.STOPPED) { + if (mDispatcher != null && mStatusCode != TextToSpeech.SUCCESS && + mStatusCode != TextToSpeech.STOPPED) { mDispatcher.dispatchOnError(mStatusCode); return TextToSpeech.ERROR; } @@ -247,7 +247,7 @@ class FileSynthesisCallback extends AbstractSynthesisCallback { @Override public void error() { - error(TextToSpeechClient.Status.ERROR_SYNTHESIS); + error(TextToSpeech.ERROR_SYNTHESIS); } @Override @@ -304,17 +304,4 @@ class FileSynthesisCallback extends AbstractSynthesisCallback { return header; } - - @Override - public int fallback() { - synchronized (mStateLock) { - if (hasStarted() || hasFinished()) { - return TextToSpeech.ERROR; - } - - mDispatcher.dispatchOnFallback(); - mStatusCode = TextToSpeechClient.Status.SUCCESS; - return TextToSpeechClient.Status.SUCCESS; - } - } } diff --git a/core/java/android/speech/tts/ITextToSpeechCallback.aidl b/core/java/android/speech/tts/ITextToSpeechCallback.aidl index 3c808ff..96f7e0e 100644 --- a/core/java/android/speech/tts/ITextToSpeechCallback.aidl +++ b/core/java/android/speech/tts/ITextToSpeechCallback.aidl @@ -15,8 +15,6 @@ */ package android.speech.tts; -import android.speech.tts.VoiceInfo; - /** * Interface for callbacks from TextToSpeechService * @@ -56,12 +54,8 @@ oneway interface ITextToSpeechCallback { * * @param utteranceId Unique id identifying synthesis request. * @param errorCode One of the values from - * {@link android.speech.tts.v2.TextToSpeechClient.Status}. + * {@link android.speech.tts.v2.TextToSpeech}. */ void onError(String utteranceId, int errorCode); - /** - * Inform the client that set of available voices changed. - */ - void onVoicesInfoChange(in List<VoiceInfo> voices); } diff --git a/core/java/android/speech/tts/ITextToSpeechService.aidl b/core/java/android/speech/tts/ITextToSpeechService.aidl index 9cf49ff..4d322df 100644 --- a/core/java/android/speech/tts/ITextToSpeechService.aidl +++ b/core/java/android/speech/tts/ITextToSpeechService.aidl @@ -20,8 +20,6 @@ import android.net.Uri; import android.os.Bundle; import android.os.ParcelFileDescriptor; import android.speech.tts.ITextToSpeechCallback; -import android.speech.tts.VoiceInfo; -import android.speech.tts.SynthesisRequestV2; /** * Interface for TextToSpeech to talk to TextToSpeechService. @@ -170,45 +168,4 @@ interface ITextToSpeechService { * @param cb The callback. */ void setCallback(in IBinder caller, ITextToSpeechCallback cb); - - /** - * Tells the engine to synthesize some speech and play it back. - * - * @param callingInstance a binder representing the identity of the calling - * TextToSpeech object. - * @param text The text to synthesize. - * @param queueMode Determines what to do to requests already in the queue. - * @param request Request parameters. - */ - int speakV2(in IBinder callingInstance, in SynthesisRequestV2 request); - - /** - * Tells the engine to synthesize some speech and write it to a file. - * - * @param callingInstance a binder representing the identity of the calling - * TextToSpeech object. - * @param text The text to synthesize. - * @param fileDescriptor The file descriptor to write the synthesized audio to. Has to be - writable. - * @param request Request parameters. - */ - int synthesizeToFileDescriptorV2(in IBinder callingInstance, - in ParcelFileDescriptor fileDescriptor, in SynthesisRequestV2 request); - - /** - * Plays an existing audio resource. V2 version - * - * @param callingInstance a binder representing the identity of the calling - * TextToSpeech object. - * @param audioUri URI for the audio resource (a file or android.resource URI) - * @param utteranceId Unique identifier. - * @param audioParameters Parameters for audio playback (from {@link SynthesisRequestV2}). - */ - int playAudioV2(in IBinder callingInstance, in Uri audioUri, in String utteranceId, - in Bundle audioParameters); - - /** - * Request the list of available voices from the service. - */ - List<VoiceInfo> getVoicesInfo(); } diff --git a/core/java/android/speech/tts/PlaybackQueueItem.java b/core/java/android/speech/tts/PlaybackQueueItem.java index b2e323e..0e54c33 100644 --- a/core/java/android/speech/tts/PlaybackQueueItem.java +++ b/core/java/android/speech/tts/PlaybackQueueItem.java @@ -29,8 +29,8 @@ abstract class PlaybackQueueItem implements Runnable { * Stop the playback. * * @param errorCode Cause of the stop. Can be either one of the error codes from - * {@link android.speech.tts.TextToSpeechClient.Status} or - * {@link android.speech.tts.TextToSpeechClient.Status#STOPPED} + * {@link android.speech.tts.TextToSpeech} or + * {@link android.speech.tts.TextToSpeech#STOPPED} * if stopped on a client request. */ abstract void stop(int errorCode); diff --git a/core/java/android/speech/tts/PlaybackSynthesisCallback.java b/core/java/android/speech/tts/PlaybackSynthesisCallback.java index e345e89..7e68d27 100644 --- a/core/java/android/speech/tts/PlaybackSynthesisCallback.java +++ b/core/java/android/speech/tts/PlaybackSynthesisCallback.java @@ -76,7 +76,7 @@ class PlaybackSynthesisCallback extends AbstractSynthesisCallback { mDispatcher = dispatcher; mCallerIdentity = callerIdentity; mLogger = logger; - mStatusCode = TextToSpeechClient.Status.SUCCESS; + mStatusCode = TextToSpeech.SUCCESS; } @Override @@ -88,13 +88,13 @@ class PlaybackSynthesisCallback extends AbstractSynthesisCallback { if (mDone) { return; } - if (mStatusCode == TextToSpeechClient.Status.STOPPED) { + if (mStatusCode == TextToSpeech.STOPPED) { Log.w(TAG, "stop() called twice"); return; } item = mItem; - mStatusCode = TextToSpeechClient.Status.STOPPED; + mStatusCode = TextToSpeech.STOPPED; } if (item != null) { @@ -102,14 +102,14 @@ class PlaybackSynthesisCallback extends AbstractSynthesisCallback { // point it will write an additional buffer to the item - but we // won't worry about that because the audio playback queue will be cleared // soon after (see SynthHandler#stop(String). - item.stop(TextToSpeechClient.Status.STOPPED); + item.stop(TextToSpeech.STOPPED); } else { // This happens when stop() or error() were called before start() was. // In all other cases, mAudioTrackHandler.stop() will // result in onSynthesisDone being called, and we will // write data there. - mLogger.onCompleted(TextToSpeechClient.Status.STOPPED); + mLogger.onCompleted(TextToSpeech.STOPPED); mDispatcher.dispatchOnStop(); } } @@ -145,14 +145,14 @@ class PlaybackSynthesisCallback extends AbstractSynthesisCallback { synchronized (mStateLock) { if (channelConfig == 0) { Log.e(TAG, "Unsupported number of channels :" + channelCount); - mStatusCode = TextToSpeechClient.Status.ERROR_OUTPUT; + mStatusCode = TextToSpeech.ERROR_OUTPUT; return TextToSpeech.ERROR; } - if (mStatusCode == TextToSpeechClient.Status.STOPPED) { + if (mStatusCode == TextToSpeech.STOPPED) { if (DBG) Log.d(TAG, "stop() called before start(), returning."); return errorCodeOnStop(); } - if (mStatusCode != TextToSpeechClient.Status.SUCCESS) { + if (mStatusCode != TextToSpeech.SUCCESS) { if (DBG) Log.d(TAG, "Error was raised"); return TextToSpeech.ERROR; } @@ -183,14 +183,14 @@ class PlaybackSynthesisCallback extends AbstractSynthesisCallback { SynthesisPlaybackQueueItem item = null; synchronized (mStateLock) { if (mItem == null) { - mStatusCode = TextToSpeechClient.Status.ERROR_OUTPUT; + mStatusCode = TextToSpeech.ERROR_OUTPUT; return TextToSpeech.ERROR; } - if (mStatusCode != TextToSpeechClient.Status.SUCCESS) { + if (mStatusCode != TextToSpeech.SUCCESS) { if (DBG) Log.d(TAG, "Error was raised"); return TextToSpeech.ERROR; } - if (mStatusCode == TextToSpeechClient.Status.STOPPED) { + if (mStatusCode == TextToSpeech.STOPPED) { return errorCodeOnStop(); } item = mItem; @@ -206,7 +206,7 @@ class PlaybackSynthesisCallback extends AbstractSynthesisCallback { item.put(bufferCopy); } catch (InterruptedException ie) { synchronized (mStateLock) { - mStatusCode = TextToSpeechClient.Status.ERROR_OUTPUT; + mStatusCode = TextToSpeech.ERROR_OUTPUT; return TextToSpeech.ERROR; } } @@ -228,7 +228,7 @@ class PlaybackSynthesisCallback extends AbstractSynthesisCallback { // setStatusCode return TextToSpeech.ERROR; } - if (mStatusCode == TextToSpeechClient.Status.STOPPED) { + if (mStatusCode == TextToSpeech.STOPPED) { if (DBG) Log.d(TAG, "Request has been aborted."); return errorCodeOnStop(); } @@ -238,7 +238,7 @@ class PlaybackSynthesisCallback extends AbstractSynthesisCallback { // .done() was called before .start. Treat it as successful synthesis // for a client, despite service bad implementation. Log.w(TAG, "done() was called before start() call"); - if (mStatusCode == TextToSpeechClient.Status.SUCCESS) { + if (mStatusCode == TextToSpeech.SUCCESS) { mDispatcher.dispatchOnSuccess(); } else { mDispatcher.dispatchOnError(mStatusCode); @@ -252,7 +252,7 @@ class PlaybackSynthesisCallback extends AbstractSynthesisCallback { } // Signal done or error to item - if (statusCode == TextToSpeechClient.Status.SUCCESS) { + if (statusCode == TextToSpeech.SUCCESS) { item.done(); } else { item.stop(statusCode); @@ -263,7 +263,7 @@ class PlaybackSynthesisCallback extends AbstractSynthesisCallback { @Override public void error() { - error(TextToSpeechClient.Status.ERROR_SYNTHESIS); + error(TextToSpeech.ERROR_SYNTHESIS); } @Override @@ -276,17 +276,4 @@ class PlaybackSynthesisCallback extends AbstractSynthesisCallback { mStatusCode = errorCode; } } - - @Override - public int fallback() { - synchronized (mStateLock) { - if (hasStarted() || hasFinished()) { - return TextToSpeech.ERROR; - } - - mDispatcher.dispatchOnFallback(); - mStatusCode = TextToSpeechClient.Status.SUCCESS; - return TextToSpeechClient.Status.SUCCESS; - } - } } diff --git a/core/java/android/speech/tts/RequestConfig.java b/core/java/android/speech/tts/RequestConfig.java deleted file mode 100644 index 84880c0..0000000 --- a/core/java/android/speech/tts/RequestConfig.java +++ /dev/null @@ -1,228 +0,0 @@ -/* - * Copyright (C) 2014 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.AudioManager; -import android.os.Bundle; - -/** - * Synthesis request configuration. - * - * This class is immutable, and can only be constructed using - * {@link RequestConfig.Builder}. - */ -public final class RequestConfig { - - /** Builder for constructing RequestConfig objects. */ - public static final class Builder { - private VoiceInfo mCurrentVoiceInfo; - private Bundle mVoiceParams; - private Bundle mAudioParams; - - Builder(VoiceInfo currentVoiceInfo, Bundle voiceParams, Bundle audioParams) { - mCurrentVoiceInfo = currentVoiceInfo; - mVoiceParams = voiceParams; - mAudioParams = audioParams; - } - - /** - * Create new RequestConfig builder. - */ - public static Builder newBuilder() { - return new Builder(null, new Bundle(), new Bundle()); - } - - /** - * Create new RequestConfig builder. - * @param prototype - * Prototype of new RequestConfig. Copies all fields of the - * prototype to the constructed object. - */ - public static Builder newBuilder(RequestConfig prototype) { - return new Builder(prototype.mCurrentVoiceInfo, - (Bundle)prototype.mVoiceParams.clone(), - (Bundle)prototype.mAudioParams.clone()); - } - - /** Set voice for request. Will reset voice parameters to the defaults. */ - public Builder setVoice(VoiceInfo voice) { - mCurrentVoiceInfo = voice; - mVoiceParams = (Bundle)voice.getParamsWithDefaults().clone(); - return this; - } - - /** - * Set request voice parameter. - * - * @param paramName - * The name of the parameter. It has to be one of the keys - * from {@link VoiceInfo#getParamsWithDefaults()} - * @param value - * Value of the parameter. Its type can be one of: Integer, Float, - * Boolean, String, VoiceInfo (will be set as a String, result of a call to - * the {@link VoiceInfo#getName()}) or byte[]. It has to be of the same type - * as the default value from {@link VoiceInfo#getParamsWithDefaults()} - * for that parameter. - * @throws IllegalArgumentException - * If paramName is not a valid parameter name or its value is of a wrong - * type. - * @throws IllegalStateException - * If no voice is set. - */ - public Builder setVoiceParam(String paramName, Object value){ - if (mCurrentVoiceInfo == null) { - throw new IllegalStateException( - "Couldn't set voice parameter, no voice is set"); - } - Object defaultValue = mCurrentVoiceInfo.getParamsWithDefaults().get(paramName); - if (defaultValue == null) { - throw new IllegalArgumentException( - "Parameter \"" + paramName + "\" is not available in set voice with " + - "name: " + mCurrentVoiceInfo.getName()); - } - - // If it's VoiceInfo, get its name - if (value instanceof VoiceInfo) { - value = ((VoiceInfo)value).getName(); - } - - // Check type information - if (!defaultValue.getClass().equals(value.getClass())) { - throw new IllegalArgumentException( - "Parameter \"" + paramName +"\" is of different type. Value passed has " + - "type " + value.getClass().getSimpleName() + " but should have " + - "type " + defaultValue.getClass().getSimpleName()); - } - - setParam(mVoiceParams, paramName, value); - return this; - } - - /** - * Set request audio parameter. - * - * Doesn't requires a set voice. - * - * @param paramName - * Name of parameter. - * @param value - * Value of parameter. Its type can be one of: Integer, Float, Boolean, String - * or byte[]. - */ - public Builder setAudioParam(String paramName, Object value) { - setParam(mAudioParams, paramName, value); - return this; - } - - /** - * Set the {@link TextToSpeechClient.Params#AUDIO_PARAM_STREAM} audio parameter. - * - * @param streamId One of the STREAM_ constants defined in {@link AudioManager}. - */ - public void setAudioParamStream(int streamId) { - setAudioParam(TextToSpeechClient.Params.AUDIO_PARAM_STREAM, streamId); - } - - /** - * Set the {@link TextToSpeechClient.Params#AUDIO_PARAM_VOLUME} audio parameter. - * - * @param volume Float in range of 0.0 to 1.0. - */ - public void setAudioParamVolume(float volume) { - setAudioParam(TextToSpeechClient.Params.AUDIO_PARAM_VOLUME, volume); - } - - /** - * Set the {@link TextToSpeechClient.Params#AUDIO_PARAM_PAN} audio parameter. - * - * @param pan Float in range of -1.0 to +1.0. - */ - public void setAudioParamPan(float pan) { - setAudioParam(TextToSpeechClient.Params.AUDIO_PARAM_PAN, pan); - } - - private void setParam(Bundle bundle, String featureName, Object value) { - if (value instanceof String) { - bundle.putString(featureName, (String)value); - } else if(value instanceof byte[]) { - bundle.putByteArray(featureName, (byte[])value); - } else if(value instanceof Integer) { - bundle.putInt(featureName, (Integer)value); - } else if(value instanceof Float) { - bundle.putFloat(featureName, (Float)value); - } else if(value instanceof Double) { - bundle.putFloat(featureName, (Float)value); - } else if(value instanceof Boolean) { - bundle.putBoolean(featureName, (Boolean)value); - } else { - throw new IllegalArgumentException("Illegal type of object"); - } - return; - } - - /** - * Build new RequestConfig instance. - */ - public RequestConfig build() { - RequestConfig config = - new RequestConfig(mCurrentVoiceInfo, mVoiceParams, mAudioParams); - return config; - } - } - - private RequestConfig(VoiceInfo voiceInfo, Bundle voiceParams, Bundle audioParams) { - mCurrentVoiceInfo = voiceInfo; - mVoiceParams = voiceParams; - mAudioParams = audioParams; - } - - /** - * Currently set voice. - */ - private final VoiceInfo mCurrentVoiceInfo; - - /** - * Voice parameters bundle. - */ - private final Bundle mVoiceParams; - - /** - * Audio parameters bundle. - */ - private final Bundle mAudioParams; - - /** - * @return Currently set request voice. - */ - public VoiceInfo getVoice() { - return mCurrentVoiceInfo; - } - - /** - * @return Request audio parameters. - */ - public Bundle getAudioParams() { - return mAudioParams; - } - - /** - * @return Request voice parameters. - */ - public Bundle getVoiceParams() { - return mVoiceParams; - } - -} diff --git a/core/java/android/speech/tts/RequestConfigHelper.java b/core/java/android/speech/tts/RequestConfigHelper.java deleted file mode 100644 index bc65280..0000000 --- a/core/java/android/speech/tts/RequestConfigHelper.java +++ /dev/null @@ -1,187 +0,0 @@ -/* - * Copyright (C) 2014 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.TextToSpeechClient.EngineStatus; - -import java.util.Locale; - -/** - * Set of common heuristics for selecting {@link VoiceInfo} from - * {@link TextToSpeechClient#getEngineStatus()} output. - */ -public final class RequestConfigHelper { - private RequestConfigHelper() {} - - /** - * Interface for scoring VoiceInfo object. - */ - public static interface VoiceScorer { - /** - * Score VoiceInfo. If the score is less than or equal to zero, that voice is discarded. - * If two voices have same desired primary characteristics (highest quality, lowest - * latency or others), the one with the higher score is selected. - */ - public int scoreVoice(VoiceInfo voiceInfo); - } - - /** - * Score positively voices that exactly match the locale supplied to the constructor. - */ - public static final class ExactLocaleMatcher implements VoiceScorer { - private final Locale mLocale; - - /** - * Score positively voices that exactly match the given locale - * @param locale Reference locale. If null, the system default locale for the - * current user will be used ({@link Locale#getDefault()}). - */ - public ExactLocaleMatcher(Locale locale) { - if (locale == null) { - mLocale = Locale.getDefault(); - } else { - mLocale = locale; - } - } - @Override - public int scoreVoice(VoiceInfo voiceInfo) { - return mLocale.equals(voiceInfo.getLocale()) ? 1 : 0; - } - } - - /** - * Score positively voices that match exactly the given locale (score 3) - * or that share same language and country (score 2), or that share just a language (score 1). - */ - public static final class LanguageMatcher implements VoiceScorer { - private final Locale mLocale; - - /** - * Score positively voices with similar locale. - * @param locale Reference locale. If null, the system default locale for the - * current user will be used ({@link Locale#getDefault()}). - */ - public LanguageMatcher(Locale locale) { - if (locale == null) { - mLocale = Locale.getDefault(); - } else { - mLocale = locale; - } - } - - @Override - public int scoreVoice(VoiceInfo voiceInfo) { - final Locale voiceLocale = voiceInfo.getLocale(); - if (mLocale.equals(voiceLocale)) { - return 3; - } else { - if (mLocale.getLanguage().equals(voiceLocale.getLanguage())) { - if (mLocale.getCountry().equals(voiceLocale.getCountry())) { - return 2; - } - return 1; - } - return 0; - } - } - } - - /** - * Get the highest quality voice from voices that score more than zero from the passed scorer. - * If there is more than one voice with the same highest quality, then this method returns one - * with the highest score. If they share same score as well, one with the lower index in the - * voices list is returned. - * - * @param engineStatus - * Voices status received from a {@link TextToSpeechClient#getEngineStatus()} call. - * @param voiceScorer - * Used to discard unsuitable voices and help settle cases where more than - * one voice has the desired characteristic. - * @param hasToBeEmbedded - * If true, require the voice to be an embedded voice (no network - * access will be required for synthesis). - */ - private static VoiceInfo getHighestQualityVoice(EngineStatus engineStatus, - VoiceScorer voiceScorer, boolean hasToBeEmbedded) { - VoiceInfo bestVoice = null; - int bestScoreMatch = 1; - int bestVoiceQuality = 0; - - for (VoiceInfo voice : engineStatus.getVoices()) { - int score = voiceScorer.scoreVoice(voice); - if (score <= 0 || hasToBeEmbedded && voice.getRequiresNetworkConnection() - || voice.getQuality() < bestVoiceQuality) { - continue; - } - - if (bestVoice == null || - voice.getQuality() > bestVoiceQuality || - score > bestScoreMatch) { - bestVoice = voice; - bestScoreMatch = score; - bestVoiceQuality = voice.getQuality(); - } - } - return bestVoice; - } - - /** - * Get highest quality voice. - * - * Highest quality voice is selected from voices that score more than zero from the passed - * scorer. If there is more than one voice with the same highest quality, then this method - * will return one with the highest score. If they share same score as well, one with the lower - * index in the voices list is returned. - - * @param engineStatus - * Voices status received from a {@link TextToSpeechClient#getEngineStatus()} call. - * @param hasToBeEmbedded - * If true, require the voice to be an embedded voice (no network - * access will be required for synthesis). - * @param voiceScorer - * Scorer is used to discard unsuitable voices and help settle cases where more than - * one voice has highest quality. - * @return RequestConfig with selected voice or null if suitable voice was not found. - */ - public static RequestConfig highestQuality(EngineStatus engineStatus, - boolean hasToBeEmbedded, VoiceScorer voiceScorer) { - VoiceInfo voice = getHighestQualityVoice(engineStatus, voiceScorer, hasToBeEmbedded); - if (voice == null) { - return null; - } - return RequestConfig.Builder.newBuilder().setVoice(voice).build(); - } - - /** - * Get highest quality voice for the TTS default locale. - * - * Call {@link #highestQuality(EngineStatus, boolean, VoiceScorer)} with - * {@link LanguageMatcher} set to the {@link EngineStatus#getDefaultLocale()}. - * - * @param engineStatus - * Voices status received from a {@link TextToSpeechClient#getEngineStatus()} call. - * @param hasToBeEmbedded - * If true, require the voice to be an embedded voice (no network - * access will be required for synthesis). - * @return RequestConfig with selected voice or null if suitable voice was not found. - */ - public static RequestConfig highestQuality(EngineStatus engineStatus, - boolean hasToBeEmbedded) { - return highestQuality(engineStatus, hasToBeEmbedded, - new LanguageMatcher(engineStatus.getDefaultLocale())); - } - -} diff --git a/core/java/android/speech/tts/SynthesisCallback.java b/core/java/android/speech/tts/SynthesisCallback.java index bc2f239..e32438b 100644 --- a/core/java/android/speech/tts/SynthesisCallback.java +++ b/core/java/android/speech/tts/SynthesisCallback.java @@ -43,16 +43,14 @@ public interface SynthesisCallback { * request. * * This method should only be called on the synthesis thread, - * while in {@link TextToSpeechService#onSynthesizeText} or - * {@link TextToSpeechService#onSynthesizeTextV2}. + * 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. Must be {@code 1} or {@code 2}. - * @return {@link TextToSpeech#SUCCESS}, {@link TextToSpeech#ERROR}. - * {@link TextToSpeechClient.Status#STOPPED} is also possible if called in context of - * {@link TextToSpeechService#onSynthesizeTextV2}. + * @return {@link TextToSpeech#SUCCESS}, {@link TextToSpeech#ERROR} or + * {@link TextToSpeech#STOPPED}. */ public int start(int sampleRateInHz, int audioFormat, int channelCount); @@ -60,17 +58,15 @@ public interface SynthesisCallback { * 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} or - * {@link TextToSpeechService#onSynthesizeTextV2}. + * 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}. This must be * less than or equal to the return value of {@link #getMaxBufferSize}. - * @return {@link TextToSpeech#SUCCESS} or {@link TextToSpeech#ERROR}. - * {@link TextToSpeechClient.Status#STOPPED} is also possible if called in context of - * {@link TextToSpeechService#onSynthesizeTextV2}. + * @return {@link TextToSpeech#SUCCESS}, {@link TextToSpeech#ERROR} or + * {@link TextToSpeech#STOPPED}. */ public int audioAvailable(byte[] buffer, int offset, int length); @@ -79,14 +75,12 @@ public interface SynthesisCallback { * been passed to {@link #audioAvailable}. * * This method should only be called on the synthesis thread, - * while in {@link TextToSpeechService#onSynthesizeText} or - * {@link TextToSpeechService#onSynthesizeTextV2}. + * while in {@link TextToSpeechService#onSynthesizeText}. * * This method has to be called if {@link #start} and/or {@link #error} was called. * - * @return {@link TextToSpeech#SUCCESS} or {@link TextToSpeech#ERROR}. - * {@link TextToSpeechClient.Status#STOPPED} is also possible if called in context of - * {@link TextToSpeechService#onSynthesizeTextV2}. + * @return {@link TextToSpeech#SUCCESS}, {@link TextToSpeech#ERROR} or + * {@link TextToSpeech#STOPPED}. */ public int done(); @@ -103,40 +97,18 @@ public interface SynthesisCallback { * The service should call this method if the speech synthesis fails. * * This method should only be called on the synthesis thread, - * while in {@link TextToSpeechService#onSynthesizeText} or - * {@link TextToSpeechService#onSynthesizeTextV2}. + * while in {@link TextToSpeechService#onSynthesizeText}. * * @param errorCode Error code to pass to the client. One of the ERROR_ values from - * {@link TextToSpeechClient.Status} + * {@link TextToSpeech} */ public void error(int errorCode); /** - * Communicate to client that the original request can't be done and client-requested - * fallback is happening. - * - * Fallback can be requested by the client by setting - * {@link TextToSpeechClient.Params#FALLBACK_VOICE_NAME} voice parameter with a id of - * the voice that is expected to be used for the fallback. - * - * This method will fail if user called {@link #start(int, int, int)} and/or - * {@link #done()}. - * - * This method should only be called on the synthesis thread, - * while in {@link TextToSpeechService#onSynthesizeTextV2}. - * - * @return {@link TextToSpeech#SUCCESS}, {@link TextToSpeech#ERROR} if client already - * called {@link #start(int, int, int)}, {@link TextToSpeechClient.Status#STOPPED} - * if stop was requested. - */ - public int fallback(); - - /** * Check if {@link #start} was called or not. * * This method should only be called on the synthesis thread, - * while in {@link TextToSpeechService#onSynthesizeText} or - * {@link TextToSpeechService#onSynthesizeTextV2}. + * while in {@link TextToSpeechService#onSynthesizeText}. * * Useful for checking if a fallback from network request is possible. */ @@ -146,8 +118,7 @@ public interface SynthesisCallback { * Check if {@link #done} was called or not. * * This method should only be called on the synthesis thread, - * while in {@link TextToSpeechService#onSynthesizeText} or - * {@link TextToSpeechService#onSynthesizeTextV2}. + * while in {@link TextToSpeechService#onSynthesizeText}. * * Useful for checking if a fallback from network request is possible. */ diff --git a/core/java/android/speech/tts/SynthesisPlaybackQueueItem.java b/core/java/android/speech/tts/SynthesisPlaybackQueueItem.java index b424356..104f486 100644 --- a/core/java/android/speech/tts/SynthesisPlaybackQueueItem.java +++ b/core/java/android/speech/tts/SynthesisPlaybackQueueItem.java @@ -72,7 +72,7 @@ final class SynthesisPlaybackQueueItem extends PlaybackQueueItem { mStopped = false; mDone = false; - mStatusCode = TextToSpeechClient.Status.SUCCESS; + mStatusCode = TextToSpeech.SUCCESS; mAudioTrack = new BlockingAudioTrack(streamType, sampleRate, audioFormat, channelCount, volume, pan); @@ -86,7 +86,7 @@ final class SynthesisPlaybackQueueItem extends PlaybackQueueItem { dispatcher.dispatchOnStart(); if (!mAudioTrack.init()) { - dispatcher.dispatchOnError(TextToSpeechClient.Status.ERROR_OUTPUT); + dispatcher.dispatchOnError(TextToSpeech.ERROR_OUTPUT); return; } @@ -110,9 +110,9 @@ final class SynthesisPlaybackQueueItem extends PlaybackQueueItem { mAudioTrack.waitAndRelease(); - if (mStatusCode == TextToSpeechClient.Status.SUCCESS) { + if (mStatusCode == TextToSpeech.SUCCESS) { dispatcher.dispatchOnSuccess(); - } else if(mStatusCode == TextToSpeechClient.Status.STOPPED) { + } else if(mStatusCode == TextToSpeech.STOPPED) { dispatcher.dispatchOnStop(); } else { dispatcher.dispatchOnError(mStatusCode); diff --git a/core/java/android/speech/tts/SynthesisRequestV2.aidl b/core/java/android/speech/tts/SynthesisRequestV2.aidl deleted file mode 100644 index 2ac7da6..0000000 --- a/core/java/android/speech/tts/SynthesisRequestV2.aidl +++ /dev/null @@ -1,20 +0,0 @@ -/* -** -** Copyright 2013, 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; - -parcelable SynthesisRequestV2;
\ No newline at end of file diff --git a/core/java/android/speech/tts/SynthesisRequestV2.java b/core/java/android/speech/tts/SynthesisRequestV2.java deleted file mode 100644 index 938458c..0000000 --- a/core/java/android/speech/tts/SynthesisRequestV2.java +++ /dev/null @@ -1,175 +0,0 @@ -/* - * Copyright (C) 2014 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.os.Bundle; -import android.os.Parcel; -import android.os.Parcelable; -import android.speech.tts.TextToSpeechClient.UtteranceId; -import android.util.Log; - -/** - * Service-side representation of a synthesis request from a V2 API client. Contains: - * <ul> - * <li>The markup object to synthesize containing the utterance.</li> - * <li>The id of the utterance (String, result of {@link UtteranceId#toUniqueString()}</li> - * <li>The synthesis voice name (String, result of {@link VoiceInfo#getName()})</li> - * <li>Voice parameters (Bundle of parameters)</li> - * <li>Audio parameters (Bundle of parameters)</li> - * </ul> - */ -public final class SynthesisRequestV2 implements Parcelable { - - private static final String TAG = "SynthesisRequestV2"; - - /** Synthesis markup */ - private final Markup mMarkup; - - /** Synthesis id. */ - private final String mUtteranceId; - - /** Voice ID. */ - private final String mVoiceName; - - /** Voice Parameters. */ - private final Bundle mVoiceParams; - - /** Audio Parameters. */ - private final Bundle mAudioParams; - - /** - * Constructor for test purposes. - */ - public SynthesisRequestV2(Markup markup, String utteranceId, String voiceName, - Bundle voiceParams, Bundle audioParams) { - this.mMarkup = markup; - this.mUtteranceId = utteranceId; - this.mVoiceName = voiceName; - this.mVoiceParams = voiceParams; - this.mAudioParams = audioParams; - } - - /** - * Parcel based constructor. - * - * @hide - */ - public SynthesisRequestV2(Parcel in) { - this.mMarkup = (Markup) in.readValue(Markup.class.getClassLoader()); - this.mUtteranceId = in.readString(); - this.mVoiceName = in.readString(); - this.mVoiceParams = in.readBundle(); - this.mAudioParams = in.readBundle(); - } - - /** - * Constructor to request the synthesis of a sentence. - */ - SynthesisRequestV2(Markup markup, String utteranceId, RequestConfig rconfig) { - this.mMarkup = markup; - this.mUtteranceId = utteranceId; - this.mVoiceName = rconfig.getVoice().getName(); - this.mVoiceParams = rconfig.getVoiceParams(); - this.mAudioParams = rconfig.getAudioParams(); - } - - /** - * Write to parcel. - * - * @hide - */ - @Override - public void writeToParcel(Parcel dest, int flags) { - dest.writeValue(mMarkup); - dest.writeString(mUtteranceId); - dest.writeString(mVoiceName); - dest.writeBundle(mVoiceParams); - dest.writeBundle(mAudioParams); - } - - /** - * @return the text which should be synthesized. - */ - public String getText() { - if (mMarkup.getPlainText() == null) { - Log.e(TAG, "Plaintext of markup is null."); - return ""; - } - return mMarkup.getPlainText(); - } - - /** - * @return the markup which should be synthesized. - */ - public Markup getMarkup() { - return mMarkup; - } - - /** - * @return the id of the synthesis request. It's an output of a call to the - * {@link UtteranceId#toUniqueString()} method of the {@link UtteranceId} associated with - * this request. - */ - public String getUtteranceId() { - return mUtteranceId; - } - - /** - * @return the name of the voice to use for this synthesis request. Result of a call to - * the {@link VoiceInfo#getName()} method. - */ - public String getVoiceName() { - return mVoiceName; - } - - /** - * @return bundle of voice parameters. - */ - public Bundle getVoiceParams() { - return mVoiceParams; - } - - /** - * @return bundle of audio parameters. - */ - public Bundle getAudioParams() { - return mAudioParams; - } - - /** - * Parcel creators. - * - * @hide - */ - public static final Parcelable.Creator<SynthesisRequestV2> CREATOR = - new Parcelable.Creator<SynthesisRequestV2>() { - @Override - public SynthesisRequestV2 createFromParcel(Parcel source) { - return new SynthesisRequestV2(source); - } - - @Override - public SynthesisRequestV2[] newArray(int size) { - return new SynthesisRequestV2[size]; - } - }; - - /** @hide */ - @Override - public int describeContents() { - return 0; - } -} diff --git a/core/java/android/speech/tts/TextToSpeech.java b/core/java/android/speech/tts/TextToSpeech.java index c527acf..a338c19 100644 --- a/core/java/android/speech/tts/TextToSpeech.java +++ b/core/java/android/speech/tts/TextToSpeech.java @@ -53,10 +53,7 @@ import java.util.Set; * notified of the completion of the initialization.<br> * When you are done using the TextToSpeech instance, call the {@link #shutdown()} method * to release the native resources used by the TextToSpeech engine. - * - * @deprecated Use {@link TextToSpeechClient} instead */ -@Deprecated public class TextToSpeech { private static final String TAG = "TextToSpeech"; @@ -71,6 +68,42 @@ public class TextToSpeech { public static final int ERROR = -1; /** + * Denotes a stop requested by a client. It's used only on the service side of the API, + * client should never expect to see this result code. + */ + public static final int STOPPED = -2; + + /** + * Denotes a failure of a TTS engine to synthesize the given input. + */ + public static final int ERROR_SYNTHESIS = -3; + + /** + * Denotes a failure of a TTS service. + */ + public static final int ERROR_SERVICE = -4; + + /** + * Denotes a failure related to the output (audio device or a file). + */ + public static final int ERROR_OUTPUT = -5; + + /** + * Denotes a failure caused by a network connectivity problems. + */ + public static final int ERROR_NETWORK = -6; + + /** + * Denotes a failure caused by network timeout. + */ + public static final int ERROR_NETWORK_TIMEOUT = -7; + + /** + * Denotes a failure caused by an invalid request. + */ + public static final int ERROR_INVALID_REQUEST = -8; + + /** * Queue mode where all entries in the playback queue (media to be played * and text to be synthesized) are dropped and replaced by the new entry. * Queues are flushed with respect to a given calling app. Entries in the queue @@ -1478,11 +1511,6 @@ public class TextToSpeech { listener.onStart(utteranceId); } } - - @Override - public void onVoicesInfoChange(List<VoiceInfo> voicesInfo) throws RemoteException { - // Ignore it - } }; private class SetupConnectionAsyncTask extends AsyncTask<Void, Void, Integer> { diff --git a/core/java/android/speech/tts/TextToSpeechClient.java b/core/java/android/speech/tts/TextToSpeechClient.java deleted file mode 100644 index f726743..0000000 --- a/core/java/android/speech/tts/TextToSpeechClient.java +++ /dev/null @@ -1,1192 +0,0 @@ -/* - * Copyright (C) 2013 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.Activity; -import android.app.Application; -import android.content.ComponentName; -import android.content.Context; -import android.content.Intent; -import android.content.ServiceConnection; -import android.media.AudioManager; -import android.net.Uri; -import android.os.AsyncTask; -import android.os.Handler; -import android.os.IBinder; -import android.os.Looper; -import android.os.Message; -import android.os.ParcelFileDescriptor; -import android.os.RemoteException; -import android.speech.tts.ITextToSpeechCallback; -import android.speech.tts.ITextToSpeechService; -import android.util.Log; -import android.util.Pair; - -import java.io.File; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Locale; -import java.util.concurrent.atomic.AtomicInteger; - -/** - * Synthesizes speech from text for immediate playback or to create a sound - * file. - * <p> - * This is an updated version of the speech synthesis client that supersedes - * {@link android.speech.tts.TextToSpeech}. - * <p> - * A TextToSpeechClient instance can only be used to synthesize text once it has - * connected to the service. The TextToSpeechClient instance will start establishing - * the connection after a call to the {@link #connect()} method. This is usually done in - * {@link Application#onCreate()} or {@link Activity#onCreate}. When the connection - * is established, the instance will call back using the - * {@link TextToSpeechClient.ConnectionCallbacks} interface. Only after a - * successful callback is the client usable. - * <p> - * After successful connection, the list of all available voices can be obtained - * by calling the {@link TextToSpeechClient#getEngineStatus()} method. The client can - * choose a voice using some custom heuristic and build a {@link RequestConfig} object - * using {@link RequestConfig.Builder}, or can use one of the common heuristics found - * in ({@link RequestConfigHelper}. - * <p> - * When you are done using the TextToSpeechClient instance, call the - * {@link #disconnect()} method to release the connection. - * <p> - * In the rare case of a change to the set of available voices, the service will call to the - * {@link ConnectionCallbacks#onEngineStatusChange} with new set of available voices as argument. - * In response, the client HAVE to recreate all {@link RequestConfig} instances in use. - */ -public class TextToSpeechClient { - private static final String TAG = TextToSpeechClient.class.getSimpleName(); - - private final Object mLock = new Object(); - private final TtsEngines mEnginesHelper; - private final Context mContext; - - // Guarded by mLock - private Connection mServiceConnection; - private final RequestCallbacks mDefaultRequestCallbacks; - private final ConnectionCallbacks mConnectionCallbacks; - private EngineStatus mEngineStatus; - private String mRequestedEngine; - private boolean mFallbackToDefault; - private HashMap<String, Pair<UtteranceId, RequestCallbacks>> mCallbacks; - // Guarded by mLock - - private InternalHandler mMainHandler = new InternalHandler(); - - /** Common voices parameters */ - public static final class Params { - private Params() {} - - /** - * Maximum allowed time for a single request attempt, in milliseconds, before synthesis - * fails (or fallback request starts, if requested using - * {@link #FALLBACK_VOICE_NAME}). - */ - public static final String NETWORK_TIMEOUT_MS = "networkTimeoutMs"; - - /** - * Number of network request retries that are attempted in case of failure - */ - public static final String NETWORK_RETRIES_COUNT = "networkRetriesCount"; - - /** - * Should synthesizer report sub-utterance progress on synthesis. Only applicable - * for the {@link TextToSpeechClient#queueSpeak} method. - */ - public static final String TRACK_SUBUTTERANCE_PROGRESS = "trackSubutteranceProgress"; - - /** - * If a voice exposes this parameter then it supports the fallback request feature. - * - * If it is set to a valid name of some other voice ({@link VoiceInfo#getName()}) then - * in case of request failure (due to network problems or missing data), fallback request - * will be attempted. Request will be done using the voice referenced by this parameter. - * If it is the case, the client will be informed by a callback to the {@link - * RequestCallbacks#onSynthesisFallback(UtteranceId)}. - */ - public static final String FALLBACK_VOICE_NAME = "fallbackVoiceName"; - - /** - * Audio parameter for specifying a linear multiplier to the speaking speed of the voice. - * The value is a float. Values below zero decrease speed of the synthesized speech - * values above one increase it. If the value of this parameter is equal to zero, - * then it will be replaced by a settings-configurable default before it reaches - * TTS service. - */ - public static final String SPEECH_SPEED = "speechSpeed"; - - /** - * Audio parameter for controlling the pitch of the output. The Value is a positive float, - * with default of {@code 1.0}. The value is used to scale the primary frequency linearly. - * Lower values lower the tone of the synthesized voice, greater values increase it. - */ - public static final String SPEECH_PITCH = "speechPitch"; - - /** - * Audio parameter for controlling output volume. Value is a float with scale of 0 to 1 - */ - public static final String AUDIO_PARAM_VOLUME = TextToSpeech.Engine.KEY_PARAM_VOLUME; - - /** - * Audio parameter for controlling output pan. - * Value is a float ranging from -1 to +1 where -1 maps to a hard-left pan, - * 0 to center (the default behavior), and +1 to hard-right. - */ - public static final String AUDIO_PARAM_PAN = TextToSpeech.Engine.KEY_PARAM_PAN; - - /** - * Audio parameter for specifying the audio stream type to be used when speaking text - * or playing back a file. The value should be one of the STREAM_ constants - * defined in {@link AudioManager}. - */ - public static final String AUDIO_PARAM_STREAM = TextToSpeech.Engine.KEY_PARAM_STREAM; - } - - /** - * Result codes for TTS operations. - */ - public static final class Status { - private Status() {} - - /** - * Denotes a successful operation. - */ - public static final int SUCCESS = 0; - - /** - * Denotes a stop requested by a client. It's used only on the service side of the API, - * client should never expect to see this result code. - */ - public static final int STOPPED = 100; - - /** - * Denotes a generic failure. - */ - public static final int ERROR_UNKNOWN = -1; - - /** - * Denotes a failure of a TTS engine to synthesize the given input. - */ - public static final int ERROR_SYNTHESIS = 10; - - /** - * Denotes a failure of a TTS service. - */ - public static final int ERROR_SERVICE = 11; - - /** - * Denotes a failure related to the output (audio device or a file). - */ - public static final int ERROR_OUTPUT = 12; - - /** - * Denotes a failure caused by a network connectivity problems. - */ - public static final int ERROR_NETWORK = 13; - - /** - * Denotes a failure caused by network timeout. - */ - public static final int ERROR_NETWORK_TIMEOUT = 14; - - /** - * Denotes a failure caused by an invalid request. - */ - public static final int ERROR_INVALID_REQUEST = 15; - - /** - * Denotes a failure related to passing a non-unique utterance id. - */ - public static final int ERROR_NON_UNIQUE_UTTERANCE_ID = 16; - - /** - * Denotes a failure related to missing data. The TTS implementation may download - * the missing data, and if so, request will succeed in future. This error can only happen - * for voices with {@link VoiceInfo#FEATURE_MAY_AUTOINSTALL} feature. - * Note: the recommended way to avoid this error is to create a request with the fallback - * voice. - */ - public static final int ERROR_DOWNLOADING_ADDITIONAL_DATA = 17; - } - - /** - * Set of callbacks for the events related to the progress of a synthesis request - * through the synthesis queue. Each synthesis request is associated with a call to - * {@link #queueSpeak} or {@link #queueSynthesizeToFile}. - * - * The callbacks specified in this method will NOT be called on UI thread. - */ - public static abstract class RequestCallbacks { - /** - * Called after synthesis of utterance successfully starts. - */ - public void onSynthesisStart(UtteranceId utteranceId) {} - - /** - * Called after synthesis successfully finishes. - * @param utteranceId - * Unique identifier of synthesized utterance. - */ - public void onSynthesisSuccess(UtteranceId utteranceId) {} - - /** - * Called after synthesis was stopped in middle of synthesis process. - * @param utteranceId - * Unique identifier of synthesized utterance. - */ - public void onSynthesisStop(UtteranceId utteranceId) {} - - /** - * Called when requested synthesis failed and fallback synthesis is about to be attempted. - * - * Requires voice with available {@link TextToSpeechClient.Params#FALLBACK_VOICE_NAME} - * parameter, and request with this parameter enabled. - * - * This callback will be followed by callback to the {@link #onSynthesisStart}, - * {@link #onSynthesisFailure} or {@link #onSynthesisSuccess} that depends on the - * fallback outcome. - * - * For more fallback feature reference, look at the - * {@link TextToSpeechClient.Params#FALLBACK_VOICE_NAME}. - * - * @param utteranceId - * Unique identifier of synthesized utterance. - */ - public void onSynthesisFallback(UtteranceId utteranceId) {} - - /** - * Called after synthesis of utterance fails. - * - * It may be called instead or after a {@link #onSynthesisStart} callback. - * - * @param utteranceId - * Unique identifier of synthesized utterance. - * @param errorCode - * One of the values from {@link Status}. - */ - public void onSynthesisFailure(UtteranceId utteranceId, int errorCode) {} - - /** - * Called during synthesis to mark synthesis progress. - * - * Requires voice with available - * {@link TextToSpeechClient.Params#TRACK_SUBUTTERANCE_PROGRESS} parameter, and - * request with this parameter enabled. - * - * @param utteranceId - * Unique identifier of synthesized utterance. - * @param charIndex - * String index (java char offset) of recently synthesized character. - * @param msFromStart - * Miliseconds from the start of the synthesis. - */ - public void onSynthesisProgress(UtteranceId utteranceId, int charIndex, - int msFromStart) {} - } - - /** - * Interface definition of callbacks that are called when the client is - * connected or disconnected from the TTS service. - * - * The callbacks specified in this method will be called on the UI thread. - */ - public static interface ConnectionCallbacks { - /** - * After calling {@link TextToSpeechClient#connect()}, this method will be invoked - * asynchronously when the connect request has successfully completed. - * - * Clients are strongly encouraged to call {@link TextToSpeechClient#getEngineStatus()} - * and create {@link RequestConfig} objects used in subsequent synthesis requests. - */ - public void onConnectionSuccess(); - - /** - * After calling {@link TextToSpeechClient#connect()}, this method may be invoked - * asynchronously when the connect request has failed to complete. - * - * It may be also invoked synchronously, from the body of - * {@link TextToSpeechClient#connect()} method. - */ - public void onConnectionFailure(); - - /** - * Called when the connection to the service is lost. This can happen if there is a problem - * with the speech service (e.g. a crash or resource problem causes it to be killed by the - * system). When called, all requests have been canceled and no outstanding listeners will - * be executed. Applications should disable UI components that require the service. - * - * When the service is working again, the client will receive a callback to the - * {@link #onConnectionSuccess()} method. - */ - public void onServiceDisconnected(); - - /** - * After receiving {@link #onConnectionSuccess()} callback, this method may be invoked - * if engine status obtained from {@link TextToSpeechClient#getEngineStatus()}) changes. - * It usually means that some voices were removed, changed or added. - * - * Clients are required to recreate {@link RequestConfig} objects used in subsequent - * synthesis requests. - */ - public void onEngineStatusChange(EngineStatus newEngineStatus); - } - - /** State of voices as provided by engine and user. */ - public static final class EngineStatus { - /** All available voices. */ - private final List<VoiceInfo> mVoices; - - /** Name of the TTS engine package */ - private final String mPackageName; - - /** Engine default locale */ - private final Locale mDefaultLocale; - - private EngineStatus(String packageName, List<VoiceInfo> voices, Locale defaultLocale) { - this.mVoices = Collections.unmodifiableList(voices); - this.mPackageName = packageName; - this.mDefaultLocale = defaultLocale; - } - - /** - * Get an immutable list of all Voices exposed by the TTS engine. - */ - public List<VoiceInfo> getVoices() { - return mVoices; - } - - /** - * Get name of the TTS engine package currently in use. - */ - public String getEnginePackage() { - return mPackageName; - } - - /** - * Get the default locale to use for TTS with this TTS engine. - * Unless the user changed the TTS settings for this engine, the value returned should be - * the same as the system default locale for the current user - * ({@link Locale#getDefault()}). - */ - public Locale getDefaultLocale() { - return mDefaultLocale; - } - } - - /** Unique synthesis request identifier. */ - public static class UtteranceId { - /** Unique identifier */ - private final int id; - - /** Unique identifier generator */ - private static final AtomicInteger ID_GENERATOR = new AtomicInteger(); - - /** - * Create new, unique UtteranceId instance. - */ - public UtteranceId() { - id = ID_GENERATOR.getAndIncrement(); - } - - /** - * Returns a unique string associated with an instance of this object. - * - * This string will be used to identify the synthesis request/utterance inside the - * TTS service. - */ - public final String toUniqueString() { - return "UID" + id; - } - } - - /** - * Create TextToSpeech service client. - * - * Will connect to the default TTS service. In order to be usable, {@link #connect()} need - * to be called first and successful connection callback need to be received. - * - * @param context - * The context this instance is running in. - * @param engine - * Package name of requested TTS engine. If it's null, then default engine will - * be selected regardless of {@code fallbackToDefaultEngine} parameter value. - * @param fallbackToDefaultEngine - * If requested engine is not available, should we fallback to the default engine? - * @param defaultRequestCallbacks - * Default request callbacks, it will be used for all synthesis requests without - * supplied RequestCallbacks instance. Can't be null. - * @param connectionCallbacks - * Callbacks for connecting and disconnecting from the service. Can't be null. - */ - public TextToSpeechClient(Context context, - String engine, boolean fallbackToDefaultEngine, - RequestCallbacks defaultRequestCallbacks, - ConnectionCallbacks connectionCallbacks) { - if (context == null) - throw new IllegalArgumentException("context can't be null"); - if (defaultRequestCallbacks == null) - throw new IllegalArgumentException("defaultRequestCallbacks can't be null"); - if (connectionCallbacks == null) - throw new IllegalArgumentException("connectionCallbacks can't be null"); - mContext = context; - mEnginesHelper = new TtsEngines(mContext); - mCallbacks = new HashMap<String, Pair<UtteranceId, RequestCallbacks>>(); - mDefaultRequestCallbacks = defaultRequestCallbacks; - mConnectionCallbacks = connectionCallbacks; - - mRequestedEngine = engine; - mFallbackToDefault = fallbackToDefaultEngine; - } - - /** - * Create TextToSpeech service client. Will connect to the default TTS - * service. In order to be usable, {@link #connect()} need to be called - * first and successful connection callback need to be received. - * - * @param context Context this instance is running in. - * @param defaultRequestCallbacks Default request callbacks, it - * will be used for all synthesis requests without supplied - * RequestCallbacks instance. Can't be null. - * @param connectionCallbacks Callbacks for connecting and disconnecting - * from the service. Can't be null. - */ - public TextToSpeechClient(Context context, RequestCallbacks defaultRequestCallbacks, - ConnectionCallbacks connectionCallbacks) { - this(context, null, true, defaultRequestCallbacks, connectionCallbacks); - } - - - private boolean initTts(String requestedEngine, boolean fallbackToDefaultEngine) { - // Step 1: Try connecting to the engine that was requested. - if (requestedEngine != null) { - if (mEnginesHelper.isEngineInstalled(requestedEngine)) { - if ((mServiceConnection = connectToEngine(requestedEngine)) != null) { - return true; - } else if (!fallbackToDefaultEngine) { - Log.w(TAG, "Couldn't connect to requested engine: " + requestedEngine); - return false; - } - } else if (!fallbackToDefaultEngine) { - Log.w(TAG, "Requested engine not installed: " + requestedEngine); - return false; - } - } - - // Step 2: Try connecting to the user's default engine. - final String defaultEngine = mEnginesHelper.getDefaultEngine(); - if (defaultEngine != null && !defaultEngine.equals(requestedEngine)) { - if ((mServiceConnection = connectToEngine(defaultEngine)) != null) { - return true; - } - } - - // Step 3: Try connecting to the highest ranked engine in the - // system. - final String highestRanked = mEnginesHelper.getHighestRankedEngineName(); - if (highestRanked != null && !highestRanked.equals(requestedEngine) && - !highestRanked.equals(defaultEngine)) { - if ((mServiceConnection = connectToEngine(highestRanked)) != null) { - return true; - } - } - - Log.w(TAG, "Couldn't find working TTS engine"); - return false; - } - - private Connection connectToEngine(String engine) { - Connection connection = new Connection(engine); - Intent intent = new Intent(TextToSpeech.Engine.INTENT_ACTION_TTS_SERVICE); - intent.setPackage(engine); - boolean bound = mContext.bindService(intent, connection, Context.BIND_AUTO_CREATE); - if (!bound) { - Log.e(TAG, "Failed to bind to " + engine); - return null; - } else { - Log.i(TAG, "Successfully bound to " + engine); - return connection; - } - } - - /** - * Connects the client to TTS service. This method returns immediately, and connects to the - * service in the background. - * - * After connection initializes successfully, {@link ConnectionCallbacks#onConnectionSuccess()} - * is called. On a failure {@link ConnectionCallbacks#onConnectionFailure} is called. - * - * Both of those callback may be called asynchronously on the main thread, - * {@link ConnectionCallbacks#onConnectionFailure} may be called synchronously, before - * this method returns. - */ - public void connect() { - synchronized (mLock) { - if (mServiceConnection != null) { - return; - } - if(!initTts(mRequestedEngine, mFallbackToDefault)) { - mConnectionCallbacks.onConnectionFailure(); - } - } - } - - /** - * Checks if the client is currently connected to the service, so that - * requests to other methods will succeed. - */ - public boolean isConnected() { - synchronized (mLock) { - return mServiceConnection != null && mServiceConnection.isEstablished(); - } - } - - /** - * Closes the connection to TextToSpeech service. No calls can be made on this object after - * calling this method. - * It is good practice to call this method in the onDestroy() method of an Activity - * so the TextToSpeech engine can be cleanly stopped. - */ - public void disconnect() { - synchronized (mLock) { - if (mServiceConnection != null) { - mServiceConnection.disconnect(); - mServiceConnection = null; - mCallbacks.clear(); - } - } - } - - /** - * Register callback. - * - * @param utteranceId Non-null UtteranceId instance. - * @param callback Non-null callbacks for the request - * @return Status.SUCCESS or error code in case of invalid arguments. - */ - private int addCallback(UtteranceId utteranceId, RequestCallbacks callback) { - synchronized (mLock) { - if (utteranceId == null || callback == null) { - return Status.ERROR_INVALID_REQUEST; - } - if (mCallbacks.put(utteranceId.toUniqueString(), - new Pair<UtteranceId, RequestCallbacks>(utteranceId, callback)) != null) { - return Status.ERROR_NON_UNIQUE_UTTERANCE_ID; - } - return Status.SUCCESS; - } - } - - /** - * Remove and return callback. - * - * @param utteranceIdStr Unique string obtained from {@link UtteranceId#toUniqueString}. - */ - private Pair<UtteranceId, RequestCallbacks> removeCallback(String utteranceIdStr) { - synchronized (mLock) { - return mCallbacks.remove(utteranceIdStr); - } - } - - /** - * Get callback and utterance id. - * - * @param utteranceIdStr Unique string obtained from {@link UtteranceId#toUniqueString}. - */ - private Pair<UtteranceId, RequestCallbacks> getCallback(String utteranceIdStr) { - synchronized (mLock) { - return mCallbacks.get(utteranceIdStr); - } - } - - /** - * Remove callback and call {@link RequestCallbacks#onSynthesisFailure} with passed - * error code. - * - * @param utteranceIdStr Unique string obtained from {@link UtteranceId#toUniqueString}. - * @param errorCode argument to {@link RequestCallbacks#onSynthesisFailure} call. - */ - private void removeCallbackAndErr(String utteranceIdStr, int errorCode) { - synchronized (mLock) { - Pair<UtteranceId, RequestCallbacks> c = mCallbacks.remove(utteranceIdStr); - c.second.onSynthesisFailure(c.first, errorCode); - } - } - - /** - * Retrieve TTS engine status {@link EngineStatus}. Requires connected client. - */ - public EngineStatus getEngineStatus() { - synchronized (mLock) { - return mEngineStatus; - } - } - - /** - * Query TTS engine about available voices and defaults. - * - * @return EngineStatus is connected or null if client is disconnected. - */ - private EngineStatus requestEngineStatus(ITextToSpeechService service) - throws RemoteException { - List<VoiceInfo> voices = service.getVoicesInfo(); - if (voices == null) { - Log.e(TAG, "Requested engine doesn't support TTS V2 API"); - return null; - } - - return new EngineStatus(mServiceConnection.getEngineName(), voices, - mEnginesHelper.getLocalePrefForEngine( - mServiceConnection.getEngineName())); - } - - private class Connection implements ServiceConnection { - private final String mEngineName; - - private ITextToSpeechService mService; - - private boolean mEstablished; - - private PrepareConnectionAsyncTask mSetupConnectionAsyncTask; - - public Connection(String engineName) { - this.mEngineName = engineName; - } - - private final ITextToSpeechCallback.Stub mCallback = new ITextToSpeechCallback.Stub() { - - @Override - public void onStart(String utteranceIdStr) { - synchronized (mLock) { - Pair<UtteranceId, RequestCallbacks> callbacks = getCallback(utteranceIdStr); - callbacks.second.onSynthesisStart(callbacks.first); - } - } - - public void onStop(String utteranceIdStr) { - synchronized (mLock) { - Pair<UtteranceId, RequestCallbacks> callbacks = removeCallback(utteranceIdStr); - callbacks.second.onSynthesisStop(callbacks.first); - } - } - - @Override - public void onSuccess(String utteranceIdStr) { - synchronized (mLock) { - Pair<UtteranceId, RequestCallbacks> callbacks = removeCallback(utteranceIdStr); - callbacks.second.onSynthesisSuccess(callbacks.first); - } - } - - public void onFallback(String utteranceIdStr) { - synchronized (mLock) { - Pair<UtteranceId, RequestCallbacks> callbacks = getCallback( - utteranceIdStr); - callbacks.second.onSynthesisFallback(callbacks.first); - } - }; - - @Override - public void onError(String utteranceIdStr, int errorCode) { - removeCallbackAndErr(utteranceIdStr, errorCode); - } - - @Override - public void onVoicesInfoChange(List<VoiceInfo> voicesInfo) { - synchronized (mLock) { - mEngineStatus = new EngineStatus(mServiceConnection.getEngineName(), - voicesInfo, - mEnginesHelper.getLocalePrefForEngine( - mServiceConnection.getEngineName())); - mMainHandler.obtainMessage(InternalHandler.WHAT_ENGINE_STATUS_CHANGED, - mEngineStatus).sendToTarget(); - } - } - }; - - private class PrepareConnectionAsyncTask extends AsyncTask<Void, Void, EngineStatus> { - - private final ComponentName mName; - - public PrepareConnectionAsyncTask(ComponentName name) { - mName = name; - } - - @Override - protected EngineStatus doInBackground(Void... params) { - synchronized(mLock) { - if (isCancelled()) { - return null; - } - try { - mService.setCallback(getCallerIdentity(), mCallback); - return requestEngineStatus(mService); - } catch (RemoteException re) { - Log.e(TAG, "Error setting up the TTS service"); - return null; - } - } - } - - @Override - protected void onPostExecute(EngineStatus result) { - synchronized(mLock) { - if (mSetupConnectionAsyncTask == this) { - mSetupConnectionAsyncTask = null; - } - if (result == null) { - Log.e(TAG, "Setup task failed"); - disconnect(); - mConnectionCallbacks.onConnectionFailure(); - return; - } - - mEngineStatus = result; - mEstablished = true; - } - mConnectionCallbacks.onConnectionSuccess(); - } - } - - @Override - public void onServiceConnected(ComponentName name, IBinder service) { - Log.i(TAG, "Connected to " + name); - - synchronized(mLock) { - mEstablished = false; - mService = ITextToSpeechService.Stub.asInterface(service); - startSetupConnectionTask(name); - } - } - - @Override - public void onServiceDisconnected(ComponentName name) { - Log.i(TAG, "Asked to disconnect from " + name); - - synchronized(mLock) { - mEstablished = false; - mService = null; - stopSetupConnectionTask(); - } - mMainHandler.obtainMessage(InternalHandler.WHAT_SERVICE_DISCONNECTED).sendToTarget(); - } - - private void startSetupConnectionTask(ComponentName name) { - stopSetupConnectionTask(); - mSetupConnectionAsyncTask = new PrepareConnectionAsyncTask(name); - mSetupConnectionAsyncTask.execute(); - } - - private boolean stopSetupConnectionTask() { - boolean result = false; - if (mSetupConnectionAsyncTask != null) { - result = mSetupConnectionAsyncTask.cancel(false); - mSetupConnectionAsyncTask = null; - } - return result; - } - - IBinder getCallerIdentity() { - return mCallback; - } - - boolean isEstablished() { - return mService != null && mEstablished; - } - - <T> ActionResult<T> runAction(Action<T> action) { - synchronized (mLock) { - try { - return new ActionResult<T>(true, action.run(mService)); - } catch (Exception ex) { - Log.e(TAG, action.getName() + " failed", ex); - disconnect(); - return new ActionResult<T>(false); - } - } - } - - void disconnect() { - mContext.unbindService(this); - stopSetupConnectionTask(); - mService = null; - mEstablished = false; - if (mServiceConnection == this) { - mServiceConnection = null; - } - } - - String getEngineName() { - return mEngineName; - } - } - - private abstract class Action<T> { - private final String mName; - - public Action(String name) { - mName = name; - } - - public String getName() {return mName;} - abstract T run(ITextToSpeechService service) throws RemoteException; - } - - private class ActionResult<T> { - boolean mSuccess; - T mResult; - - ActionResult(boolean success) { - mSuccess = success; - } - - ActionResult(boolean success, T result) { - mSuccess = success; - mResult = result; - } - } - - private IBinder getCallerIdentity() { - if (mServiceConnection != null) { - return mServiceConnection.getCallerIdentity(); - } - return null; - } - - private <T> ActionResult<T> runAction(Action<T> action) { - synchronized (mLock) { - if (mServiceConnection == null) { - Log.w(TAG, action.getName() + " failed: not bound to TTS engine"); - return new ActionResult<T>(false); - } - if (!mServiceConnection.isEstablished()) { - Log.w(TAG, action.getName() + " failed: not fully bound to TTS engine"); - return new ActionResult<T>(false); - } - return mServiceConnection.runAction(action); - } - } - - private static final String ACTION_STOP_NAME = "stop"; - - /** - * Interrupts the current utterance spoken (whether played or rendered to file) and discards - * other utterances in the queue. - */ - public void stop() { - runAction(new Action<Void>(ACTION_STOP_NAME) { - @Override - public Void run(ITextToSpeechService service) throws RemoteException { - if (service.stop(getCallerIdentity()) != Status.SUCCESS) { - Log.e(TAG, "Stop failed"); - } - mCallbacks.clear(); - return null; - } - }); - } - - private static final String ACTION_QUEUE_SPEAK_NAME = "queueSpeak"; - - /** - * Speaks the string using the specified queuing strategy and the current - * voice. This method is asynchronous, i.e. the method just adds the request - * to the queue of TTS requests and then returns. The synthesis might not - * have finished (or even started!) at the time when this method returns. - * - * @param utterance The string of text to be spoken. No longer than - * 1000 characters. - * @param utteranceId Unique identificator used to track the synthesis progress - * in {@link RequestCallbacks}. - * @param config Synthesis request configuration. Can't be null. Has to contain a - * voice. - * @param callbacks Synthesis request callbacks. If null, the default request - * callbacks object will be used. - */ - public void queueSpeak(final String utterance, final UtteranceId utteranceId, - final RequestConfig config, - final RequestCallbacks callbacks) { - queueSpeak(createMarkupFromString(utterance), utteranceId, config, callbacks); - } - - /** - * Speaks the {@link Markup} (which can be constructed with {@link Utterance}) using - * the specified queuing strategy and the current voice. This method is - * asynchronous, i.e. the method just adds the request to the queue of TTS - * requests and then returns. The synthesis might not have finished (or even - * started!) at the time when this method returns. - * - * @param markup The Markup to be spoken. The written equivalent of the spoken - * text should be no longer than 1000 characters. - * @param utteranceId Unique identificator used to track the synthesis progress - * in {@link RequestCallbacks}. - * @param config Synthesis request configuration. Can't be null. Has to contain a - * voice. - * @param callbacks Synthesis request callbacks. If null, the default request - * callbacks object will be used. - */ - public void queueSpeak(final Markup markup, - final UtteranceId utteranceId, - final RequestConfig config, - final RequestCallbacks callbacks) { - runAction(new Action<Void>(ACTION_QUEUE_SPEAK_NAME) { - @Override - public Void run(ITextToSpeechService service) throws RemoteException { - RequestCallbacks c = mDefaultRequestCallbacks; - if (callbacks != null) { - c = callbacks; - } - int addCallbackStatus = addCallback(utteranceId, c); - if (addCallbackStatus != Status.SUCCESS) { - c.onSynthesisFailure(utteranceId, Status.ERROR_INVALID_REQUEST); - return null; - } - - int queueResult = service.speakV2( - getCallerIdentity(), - new SynthesisRequestV2(markup, utteranceId.toUniqueString(), config)); - if (queueResult != Status.SUCCESS) { - removeCallbackAndErr(utteranceId.toUniqueString(), queueResult); - } - return null; - } - }); - } - - private static final String ACTION_QUEUE_SYNTHESIZE_TO_FILE = "queueSynthesizeToFile"; - - /** - * Synthesizes the given text to a file using the specified parameters. This - * method is asynchronous, i.e. the method just adds the request to the - * queue of TTS requests and then returns. The synthesis might not have - * finished (or even started!) at the time when this method returns. - * - * @param utterance The text that should be synthesized. No longer than - * 1000 characters. - * @param utteranceId Unique identificator used to track the synthesis progress - * in {@link RequestCallbacks}. - * @param outputFile File to write the generated audio data to. - * @param config Synthesis request configuration. Can't be null. Have to contain a - * voice. - * @param callbacks Synthesis request callbacks. If null, the default request - * callbacks object will be used. - */ - public void queueSynthesizeToFile(final String utterance, final UtteranceId utteranceId, - final File outputFile, final RequestConfig config, - final RequestCallbacks callbacks) { - queueSynthesizeToFile(createMarkupFromString(utterance), utteranceId, outputFile, config, callbacks); - } - - /** - * Synthesizes the given {@link Markup} (can be constructed with {@link Utterance}) - * to a file using the specified parameters. This method is asynchronous, i.e. the - * method just adds the request to the queue of TTS requests and then returns. The - * synthesis might not have finished (or even started!) at the time when this method - * returns. - * - * @param markup The Markup that should be synthesized. The written equivalent of - * the spoken text should be no longer than 1000 characters. - * @param utteranceId Unique identificator used to track the synthesis progress - * in {@link RequestCallbacks}. - * @param outputFile File to write the generated audio data to. - * @param config Synthesis request configuration. Can't be null. Have to contain a - * voice. - * @param callbacks Synthesis request callbacks. If null, the default request - * callbacks object will be used. - */ - public void queueSynthesizeToFile( - final Markup markup, - final UtteranceId utteranceId, - final File outputFile, final RequestConfig config, - final RequestCallbacks callbacks) { - runAction(new Action<Void>(ACTION_QUEUE_SYNTHESIZE_TO_FILE) { - @Override - public Void run(ITextToSpeechService service) throws RemoteException { - RequestCallbacks c = mDefaultRequestCallbacks; - if (callbacks != null) { - c = callbacks; - } - int addCallbackStatus = addCallback(utteranceId, c); - if (addCallbackStatus != Status.SUCCESS) { - c.onSynthesisFailure(utteranceId, Status.ERROR_INVALID_REQUEST); - return null; - } - - ParcelFileDescriptor fileDescriptor = null; - try { - if (outputFile.exists() && !outputFile.canWrite()) { - Log.e(TAG, "No permissions to write to " + outputFile); - removeCallbackAndErr(utteranceId.toUniqueString(), Status.ERROR_OUTPUT); - return null; - } - fileDescriptor = ParcelFileDescriptor.open(outputFile, - ParcelFileDescriptor.MODE_WRITE_ONLY | - ParcelFileDescriptor.MODE_CREATE | - ParcelFileDescriptor.MODE_TRUNCATE); - - int queueResult = service.synthesizeToFileDescriptorV2(getCallerIdentity(), - fileDescriptor, - new SynthesisRequestV2(markup, utteranceId.toUniqueString(), config)); - fileDescriptor.close(); - if (queueResult != Status.SUCCESS) { - removeCallbackAndErr(utteranceId.toUniqueString(), queueResult); - } - } catch (FileNotFoundException e) { - Log.e(TAG, "Opening file " + outputFile + " failed", e); - removeCallbackAndErr(utteranceId.toUniqueString(), Status.ERROR_OUTPUT); - } catch (IOException e) { - Log.e(TAG, "Closing file " + outputFile + " failed", e); - removeCallbackAndErr(utteranceId.toUniqueString(), Status.ERROR_OUTPUT); - } - return null; - } - }); - } - - private static Markup createMarkupFromString(String str) { - return new Utterance() - .append(new Utterance.TtsText(str)) - .setNoWarningOnFallback(true) - .createMarkup(); - } - - private static final String ACTION_QUEUE_SILENCE_NAME = "queueSilence"; - - /** - * Plays silence for the specified amount of time. This method is asynchronous, - * i.e. the method just adds the request to the queue of TTS requests and then - * returns. The synthesis might not have finished (or even started!) at the time - * when this method returns. - * - * @param durationInMs The duration of the silence in milliseconds. - * @param utteranceId Unique identificator used to track the synthesis progress - * in {@link RequestCallbacks}. - * @param callbacks Synthesis request callbacks. If null, default request - * callbacks object will be used. - */ - public void queueSilence(final long durationInMs, final UtteranceId utteranceId, - final RequestCallbacks callbacks) { - runAction(new Action<Void>(ACTION_QUEUE_SILENCE_NAME) { - @Override - public Void run(ITextToSpeechService service) throws RemoteException { - RequestCallbacks c = mDefaultRequestCallbacks; - if (callbacks != null) { - c = callbacks; - } - int addCallbackStatus = addCallback(utteranceId, c); - if (addCallbackStatus != Status.SUCCESS) { - c.onSynthesisFailure(utteranceId, Status.ERROR_INVALID_REQUEST); - } - - int queueResult = service.playSilence(getCallerIdentity(), durationInMs, - TextToSpeech.QUEUE_ADD, utteranceId.toUniqueString()); - - if (queueResult != Status.SUCCESS) { - removeCallbackAndErr(utteranceId.toUniqueString(), queueResult); - } - return null; - } - }); - } - - - private static final String ACTION_QUEUE_AUDIO_NAME = "queueAudio"; - - /** - * Plays the audio resource using the specified parameters. - * This method is asynchronous, i.e. the method just adds the request to the queue of TTS - * requests and then returns. The synthesis might not have finished (or even started!) at the - * time when this method returns. - * - * @param audioUrl The audio resource that should be played - * @param utteranceId Unique identificator used to track synthesis progress - * in {@link RequestCallbacks}. - * @param config Synthesis request configuration. Can't be null. Doesn't have to contain a - * voice (only system parameters are used). - * @param callbacks Synthesis request callbacks. If null, default request - * callbacks object will be used. - */ - public void queueAudio(final Uri audioUrl, final UtteranceId utteranceId, - final RequestConfig config, final RequestCallbacks callbacks) { - runAction(new Action<Void>(ACTION_QUEUE_AUDIO_NAME) { - @Override - public Void run(ITextToSpeechService service) throws RemoteException { - RequestCallbacks c = mDefaultRequestCallbacks; - if (callbacks != null) { - c = callbacks; - } - int addCallbackStatus = addCallback(utteranceId, c); - if (addCallbackStatus != Status.SUCCESS) { - c.onSynthesisFailure(utteranceId, Status.ERROR_INVALID_REQUEST); - } - - int queueResult = service.playAudioV2(getCallerIdentity(), audioUrl, - utteranceId.toUniqueString(), config.getVoiceParams()); - - if (queueResult != Status.SUCCESS) { - removeCallbackAndErr(utteranceId.toUniqueString(), queueResult); - } - return null; - } - }); - } - - private static final String ACTION_IS_SPEAKING_NAME = "isSpeaking"; - - /** - * Checks whether the TTS engine is busy speaking. Note that a speech item is - * considered complete once it's audio data has been sent to the audio mixer, or - * written to a file. There might be a finite lag between this point, and when - * the audio hardware completes playback. - * - * @return {@code true} if the TTS engine is speaking. - */ - public boolean isSpeaking() { - ActionResult<Boolean> result = runAction(new Action<Boolean>(ACTION_IS_SPEAKING_NAME) { - @Override - public Boolean run(ITextToSpeechService service) throws RemoteException { - return service.isSpeaking(); - } - }); - if (!result.mSuccess) { - return false; // We can't really say, return false - } - return result.mResult; - } - - - class InternalHandler extends Handler { - final static int WHAT_ENGINE_STATUS_CHANGED = 1; - final static int WHAT_SERVICE_DISCONNECTED = 2; - - @Override - public void handleMessage(Message msg) { - switch (msg.what) { - case WHAT_ENGINE_STATUS_CHANGED: - mConnectionCallbacks.onEngineStatusChange((EngineStatus) msg.obj); - return; - case WHAT_SERVICE_DISCONNECTED: - mConnectionCallbacks.onServiceDisconnected(); - return; - } - } - } -} diff --git a/core/java/android/speech/tts/TextToSpeechService.java b/core/java/android/speech/tts/TextToSpeechService.java index 20f3ad7..a53518f 100644 --- a/core/java/android/speech/tts/TextToSpeechService.java +++ b/core/java/android/speech/tts/TextToSpeechService.java @@ -74,26 +74,6 @@ import java.util.Set; * * {@link #onGetLanguage} is not required as of JELLYBEAN_MR2 (API 18) and later, it is only * called on earlier versions of Android. - * <p> - * In order to fully support the V2 API ({@link TextToSpeechClient}), - * these methods must be implemented: - * <ul> - * <li>{@link #onSynthesizeTextV2}</li> - * <li>{@link #checkVoicesInfo}</li> - * <li>{@link #onVoicesInfoChange}</li> - * <li>{@link #implementsV2API}</li> - * </ul> - * In addition {@link #implementsV2API} has to return true. - * <p> - * If the service does not implement these methods and {@link #implementsV2API} returns false, - * then the V2 API will be provided by converting V2 requests ({@link #onSynthesizeTextV2}) - * to V1 requests ({@link #onSynthesizeText}). On service setup, all of the available device - * locales will be fed to {@link #onIsLanguageAvailable} to check if they are supported. - * If they are, embedded and/or network voices will be created depending on the result of - * {@link #onGetFeaturesForLanguage}. - * <p> - * Note that a V2 service will still receive requests from V1 clients and has to implement all - * of the V1 API methods. */ public abstract class TextToSpeechService extends Service { @@ -114,9 +94,6 @@ public abstract class TextToSpeechService extends Service { private final Object mVoicesInfoLock = new Object(); - private List<VoiceInfo> mVoicesInfoList; - private Map<String, VoiceInfo> mVoicesInfoLookup; - @Override public void onCreate() { if (DBG) Log.d(TAG, "onCreate()"); @@ -236,149 +213,6 @@ public abstract class TextToSpeechService extends Service { SynthesisCallback callback); /** - * Check the available voices data and return an immutable list of the available voices. - * The output of this method will be passed to clients to allow them to configure synthesis - * requests. - * - * Can be called on multiple threads. - * - * The result of this method will be saved and served to all TTS clients. If a TTS service wants - * to update the set of available voices, it should call the {@link #forceVoicesInfoCheck()} - * method. - */ - protected List<VoiceInfo> checkVoicesInfo() { - if (implementsV2API()) { - throw new IllegalStateException("For proper V2 API implementation this method has to" + - " be implemented"); - } - - // V2 to V1 interface adapter. This allows using V2 client interface on V1-only services. - Bundle defaultParams = new Bundle(); - defaultParams.putFloat(TextToSpeechClient.Params.SPEECH_PITCH, 1.0f); - // Speech speed <= 0 makes it use a system wide setting - defaultParams.putFloat(TextToSpeechClient.Params.SPEECH_SPEED, 0.0f); - - // Enumerate all locales and check if they are available - ArrayList<VoiceInfo> voicesInfo = new ArrayList<VoiceInfo>(); - int id = 0; - for (Locale locale : Locale.getAvailableLocales()) { - int expectedStatus = TextToSpeech.LANG_COUNTRY_VAR_AVAILABLE; - if (locale.getVariant().isEmpty()) { - if (locale.getCountry().isEmpty()) { - expectedStatus = TextToSpeech.LANG_AVAILABLE; - } else { - expectedStatus = TextToSpeech.LANG_COUNTRY_AVAILABLE; - } - } - try { - int localeStatus = onIsLanguageAvailable(locale.getISO3Language(), - locale.getISO3Country(), locale.getVariant()); - if (localeStatus != expectedStatus) { - continue; - } - } catch (MissingResourceException e) { - // Ignore locale without iso 3 codes - continue; - } - - Set<String> features = onGetFeaturesForLanguage(locale.getISO3Language(), - locale.getISO3Country(), locale.getVariant()); - - VoiceInfo.Builder builder = new VoiceInfo.Builder(); - builder.setLatency(VoiceInfo.LATENCY_NORMAL); - builder.setQuality(VoiceInfo.QUALITY_NORMAL); - builder.setLocale(locale); - builder.setParamsWithDefaults(defaultParams); - - if (features == null || features.contains( - TextToSpeech.Engine.KEY_FEATURE_EMBEDDED_SYNTHESIS)) { - builder.setName(locale.toString() + "-embedded"); - builder.setRequiresNetworkConnection(false); - voicesInfo.add(builder.build()); - } - - if (features != null && features.contains( - TextToSpeech.Engine.KEY_FEATURE_NETWORK_SYNTHESIS)) { - builder.setName(locale.toString() + "-network"); - builder.setRequiresNetworkConnection(true); - voicesInfo.add(builder.build()); - } - } - - return voicesInfo; - } - - /** - * Tells the synthesis thread that it should reload voice data. - * There's a high probability that the underlying set of available voice data has changed. - * Called only on the synthesis thread. - */ - protected void onVoicesInfoChange() { - - } - - /** - * Tells the service to synthesize speech from the given text. This method - * should block until the synthesis is finished. Used for requests from V2 - * client {@link android.speech.tts.TextToSpeechClient}. Called on the - * synthesis thread. - * - * @param request The synthesis request. - * @param callback The callback the the engine must use to make data - * available for playback or for writing to a file. - */ - protected void onSynthesizeTextV2(SynthesisRequestV2 request, - VoiceInfo selectedVoice, - SynthesisCallback callback) { - if (implementsV2API()) { - throw new IllegalStateException("For proper V2 API implementation this method has to" + - " be implemented"); - } - - // Convert to V1 params - int speechRate = (int) (request.getVoiceParams().getFloat( - TextToSpeechClient.Params.SPEECH_SPEED, 1.0f) * 100); - int speechPitch = (int) (request.getVoiceParams().getFloat( - TextToSpeechClient.Params.SPEECH_PITCH, 1.0f) * 100); - - // Provide adapter to V1 API - Bundle params = new Bundle(); - params.putString(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID, request.getUtteranceId()); - params.putInt(TextToSpeech.Engine.KEY_PARAM_PITCH, speechPitch); - params.putInt(TextToSpeech.Engine.KEY_PARAM_RATE, speechRate); - if (selectedVoice.getRequiresNetworkConnection()) { - params.putString(TextToSpeech.Engine.KEY_FEATURE_NETWORK_SYNTHESIS, "true"); - } else { - params.putString(TextToSpeech.Engine.KEY_FEATURE_EMBEDDED_SYNTHESIS, "true"); - } - - String noWarning = request.getMarkup().getParameter(Utterance.KEY_NO_WARNING_ON_FALLBACK); - if (noWarning == null || noWarning.equals("false")) { - Log.w("TextToSpeechService", "The synthesis engine does not support Markup, falling " + - "back to the given plain text."); - } - - // Build V1 request - SynthesisRequest requestV1 = new SynthesisRequest(request.getText(), params); - Locale locale = selectedVoice.getLocale(); - requestV1.setLanguage(locale.getISO3Language(), locale.getISO3Country(), - locale.getVariant()); - requestV1.setSpeechRate(speechRate); - requestV1.setPitch(speechPitch); - - // Synthesize using V1 interface - onSynthesizeText(requestV1, callback); - } - - /** - * If true, this service implements proper V2 TTS API service. If it's false, - * V2 API will be provided through adapter. - */ - protected boolean implementsV2API() { - return false; - } - - /** * Queries the service for a set of features supported for a given language. * * Can be called on multiple threads. @@ -392,69 +226,6 @@ public abstract class TextToSpeechService extends Service { return null; } - private List<VoiceInfo> getVoicesInfo() { - synchronized (mVoicesInfoLock) { - if (mVoicesInfoList == null) { - // Get voices. Defensive copy to make sure TTS engine won't alter the list. - mVoicesInfoList = new ArrayList<VoiceInfo>(checkVoicesInfo()); - // Build lookup map - mVoicesInfoLookup = new HashMap<String, VoiceInfo>((int) ( - mVoicesInfoList.size()*1.5f)); - for (VoiceInfo voiceInfo : mVoicesInfoList) { - VoiceInfo prev = mVoicesInfoLookup.put(voiceInfo.getName(), voiceInfo); - if (prev != null) { - Log.e(TAG, "Duplicate name (" + voiceInfo.getName() + ") of the voice "); - } - } - } - return mVoicesInfoList; - } - } - - public VoiceInfo getVoicesInfoWithName(String name) { - synchronized (mVoicesInfoLock) { - if (mVoicesInfoLookup != null) { - return mVoicesInfoLookup.get(name); - } - } - return null; - } - - /** - * Force TTS service to reevaluate the set of available languages. Will result in - * a call to {@link #checkVoicesInfo()} on the same thread, {@link #onVoicesInfoChange} - * on the synthesizer thread and callback to - * {@link TextToSpeechClient.ConnectionCallbacks#onEngineStatusChange} of all connected - * TTS clients. - * - * Use this method only if you know that set of available languages changed. - * - * Can be called on multiple threads. - */ - public void forceVoicesInfoCheck() { - synchronized (mVoicesInfoLock) { - List<VoiceInfo> old = mVoicesInfoList; - - mVoicesInfoList = null; // Force recreation of voices info list - getVoicesInfo(); - - if (mVoicesInfoList == null) { - throw new IllegalStateException("This method applies only to services " + - "supporting V2 TTS API. This services doesn't support V2 TTS API."); - } - - if (old != null) { - // Flush all existing items, and inform synthesis thread about the change. - mSynthHandler.enqueueSpeechItem(TextToSpeech.QUEUE_FLUSH, - new VoicesInfoChangeItem()); - // TODO: Handle items that may be added to queue after SynthesizerRestartItem - // but before client reconnection - // Disconnect all of them - mCallbacks.dispatchVoicesInfoChange(mVoicesInfoList); - } - } - } - private int getDefaultSpeechRate() { return getSecureSettingInt(Settings.Secure.TTS_DEFAULT_RATE, Engine.DEFAULT_RATE); } @@ -558,7 +329,7 @@ public abstract class TextToSpeechService extends Service { if (!speechItem.isValid()) { if (utterenceProgress != null) { utterenceProgress.dispatchOnError( - TextToSpeechClient.Status.ERROR_INVALID_REQUEST); + TextToSpeech.ERROR_INVALID_REQUEST); } return TextToSpeech.ERROR; } @@ -589,7 +360,7 @@ public abstract class TextToSpeechService extends Service { } else { Log.w(TAG, "SynthThread has quit"); if (utterenceProgress != null) { - utterenceProgress.dispatchOnError(TextToSpeechClient.Status.ERROR_SERVICE); + utterenceProgress.dispatchOnError(TextToSpeech.ERROR_SERVICE); } return TextToSpeech.ERROR; } @@ -834,232 +605,6 @@ public abstract class TextToSpeechService extends Service { } } - class SynthesisSpeechItemV2 extends UtteranceSpeechItem { - private final SynthesisRequestV2 mSynthesisRequest; - private AbstractSynthesisCallback mSynthesisCallback; - private final EventLoggerV2 mEventLogger; - - public SynthesisSpeechItemV2(Object callerIdentity, int callerUid, int callerPid, - SynthesisRequestV2 synthesisRequest) { - super(callerIdentity, callerUid, callerPid); - - mSynthesisRequest = synthesisRequest; - mEventLogger = new EventLoggerV2(synthesisRequest, callerUid, callerPid, - mPackageName); - - updateSpeechSpeedParam(synthesisRequest); - } - - private void updateSpeechSpeedParam(SynthesisRequestV2 synthesisRequest) { - Bundle voiceParams = mSynthesisRequest.getVoiceParams(); - - // Inject default speech speed if needed - if (voiceParams.containsKey(TextToSpeechClient.Params.SPEECH_SPEED)) { - if (voiceParams.getFloat(TextToSpeechClient.Params.SPEECH_SPEED) <= 0) { - voiceParams.putFloat(TextToSpeechClient.Params.SPEECH_SPEED, - getDefaultSpeechRate() / 100.0f); - } - } - } - - /** - * Estimate of the character count equivalent of a Markup instance. Calculated - * by summing the characters of all Markups of type "text". Each other node - * is counted as a single character, as the character count of other nodes - * is non-trivial to calculate and we don't want to accept arbitrarily large - * requests. - */ - private int estimateSynthesisLengthFromMarkup(Markup m) { - int size = 0; - if (m.getType() != null && - m.getType().equals("text") && - m.getParameter("text") != null) { - size += m.getParameter("text").length(); - } else if (m.getType() == null || - !m.getType().equals("utterance")) { - size += 1; - } - for (Markup nested : m.getNestedMarkups()) { - size += estimateSynthesisLengthFromMarkup(nested); - } - return size; - } - - @Override - public boolean isValid() { - if (mSynthesisRequest.getMarkup() == null) { - Log.e(TAG, "No markup in request."); - return false; - } - String type = mSynthesisRequest.getMarkup().getType(); - if (type == null) { - Log.w(TAG, "Top level markup node should have type \"utterance\", not null"); - return false; - } else if (!type.equals("utterance")) { - Log.w(TAG, "Top level markup node should have type \"utterance\" instead of " + - "\"" + type + "\""); - return false; - } - - int estimate = estimateSynthesisLengthFromMarkup(mSynthesisRequest.getMarkup()); - if (estimate >= TextToSpeech.getMaxSpeechInputLength()) { - Log.w(TAG, "Text too long: estimated size of text was " + estimate + " chars."); - return false; - } - - if (estimate <= 0) { - Log.e(TAG, "null synthesis text"); - return false; - } - - return true; - } - - @Override - protected void playImpl() { - AbstractSynthesisCallback synthesisCallback; - if (mEventLogger != null) { - mEventLogger.onRequestProcessingStart(); - } - synchronized (this) { - // stop() might have been called before we enter this - // synchronized block. - if (isStopped()) { - return; - } - mSynthesisCallback = createSynthesisCallback(); - synthesisCallback = mSynthesisCallback; - } - - // Get voice info - VoiceInfo voiceInfo = getVoicesInfoWithName(mSynthesisRequest.getVoiceName()); - if (voiceInfo != null) { - // Primary voice - TextToSpeechService.this.onSynthesizeTextV2(mSynthesisRequest, voiceInfo, - synthesisCallback); - } else { - Log.e(TAG, "Unknown voice name:" + mSynthesisRequest.getVoiceName()); - synthesisCallback.error(TextToSpeechClient.Status.ERROR_INVALID_REQUEST); - } - - // Fix for case where client called .start() & .error(), but did not called .done() - if (!synthesisCallback.hasFinished()) { - synthesisCallback.done(); - } - } - - @Override - protected void stopImpl() { - AbstractSynthesisCallback synthesisCallback; - synchronized (this) { - synthesisCallback = mSynthesisCallback; - } - if (synthesisCallback != null) { - // If the synthesis callback is null, it implies that we haven't - // entered the synchronized(this) block in playImpl which in - // turn implies that synthesis would not have started. - synthesisCallback.stop(); - TextToSpeechService.this.onStop(); - } - } - - protected AbstractSynthesisCallback createSynthesisCallback() { - return new PlaybackSynthesisCallback(getStreamType(), getVolume(), getPan(), - mAudioPlaybackHandler, this, getCallerIdentity(), mEventLogger, - implementsV2API()); - } - - private int getStreamType() { - return getIntParam(mSynthesisRequest.getAudioParams(), - TextToSpeechClient.Params.AUDIO_PARAM_STREAM, - Engine.DEFAULT_STREAM); - } - - private float getVolume() { - return getFloatParam(mSynthesisRequest.getAudioParams(), - TextToSpeechClient.Params.AUDIO_PARAM_VOLUME, - Engine.DEFAULT_VOLUME); - } - - private float getPan() { - return getFloatParam(mSynthesisRequest.getAudioParams(), - TextToSpeechClient.Params.AUDIO_PARAM_PAN, - Engine.DEFAULT_PAN); - } - - @Override - public String getUtteranceId() { - return mSynthesisRequest.getUtteranceId(); - } - } - - private class SynthesisToFileOutputStreamSpeechItemV2 extends SynthesisSpeechItemV2 { - private final FileOutputStream mFileOutputStream; - - public SynthesisToFileOutputStreamSpeechItemV2(Object callerIdentity, int callerUid, - int callerPid, - SynthesisRequestV2 synthesisRequest, - FileOutputStream fileOutputStream) { - super(callerIdentity, callerUid, callerPid, synthesisRequest); - mFileOutputStream = fileOutputStream; - } - - @Override - protected AbstractSynthesisCallback createSynthesisCallback() { - return new FileSynthesisCallback(mFileOutputStream.getChannel(), - this, getCallerIdentity(), implementsV2API()); - } - - @Override - protected void playImpl() { - super.playImpl(); - try { - mFileOutputStream.close(); - } catch(IOException e) { - Log.w(TAG, "Failed to close output file", e); - } - } - } - - private class AudioSpeechItemV2 extends UtteranceSpeechItem { - private final AudioPlaybackQueueItem mItem; - private final Bundle mAudioParams; - private final String mUtteranceId; - - public AudioSpeechItemV2(Object callerIdentity, int callerUid, int callerPid, - String utteranceId, Bundle audioParams, Uri uri) { - super(callerIdentity, callerUid, callerPid); - mUtteranceId = utteranceId; - mAudioParams = audioParams; - mItem = new AudioPlaybackQueueItem(this, getCallerIdentity(), - TextToSpeechService.this, uri, getStreamType()); - } - - @Override - public boolean isValid() { - return true; - } - - @Override - protected void playImpl() { - mAudioPlaybackHandler.enqueue(mItem); - } - - @Override - protected void stopImpl() { - // Do nothing. - } - - protected int getStreamType() { - return mAudioParams.getInt(TextToSpeechClient.Params.AUDIO_PARAM_STREAM); - } - - public String getUtteranceId() { - return mUtteranceId; - } - } - - class SynthesisSpeechItemV1 extends SpeechItemV1 { // Never null. private final String mText; @@ -1256,30 +801,6 @@ public abstract class TextToSpeechService extends Service { } /** - * Call {@link TextToSpeechService#onVoicesInfoChange} on synthesis thread. - */ - private class VoicesInfoChangeItem extends SpeechItem { - public VoicesInfoChangeItem() { - super(null, 0, 0); // It's never initiated by an user - } - - @Override - public boolean isValid() { - return true; - } - - @Override - protected void playImpl() { - TextToSpeechService.this.onVoicesInfoChange(); - } - - @Override - protected void stopImpl() { - // No-op - } - } - - /** * Call {@link TextToSpeechService#onLoadLanguage} on synth thread. */ private class LoadLanguageItem extends SpeechItem { @@ -1475,58 +996,6 @@ public abstract class TextToSpeechService extends Service { } return true; } - - @Override - public List<VoiceInfo> getVoicesInfo() { - return TextToSpeechService.this.getVoicesInfo(); - } - - @Override - public int speakV2(IBinder callingInstance, - SynthesisRequestV2 request) { - if (!checkNonNull(callingInstance, request)) { - return TextToSpeech.ERROR; - } - - SpeechItem item = new SynthesisSpeechItemV2(callingInstance, - Binder.getCallingUid(), Binder.getCallingPid(), request); - return mSynthHandler.enqueueSpeechItem(TextToSpeech.QUEUE_ADD, item); - } - - @Override - public int synthesizeToFileDescriptorV2(IBinder callingInstance, - ParcelFileDescriptor fileDescriptor, - SynthesisRequestV2 request) { - if (!checkNonNull(callingInstance, request, fileDescriptor)) { - return TextToSpeech.ERROR; - } - - // In test env, ParcelFileDescriptor instance may be EXACTLY the same - // one that is used by client. And it will be closed by a client, thus - // preventing us from writing anything to it. - final ParcelFileDescriptor sameFileDescriptor = ParcelFileDescriptor.adoptFd( - fileDescriptor.detachFd()); - - SpeechItem item = new SynthesisToFileOutputStreamSpeechItemV2(callingInstance, - Binder.getCallingUid(), Binder.getCallingPid(), request, - new ParcelFileDescriptor.AutoCloseOutputStream(sameFileDescriptor)); - return mSynthHandler.enqueueSpeechItem(TextToSpeech.QUEUE_ADD, item); - - } - - @Override - public int playAudioV2( - IBinder callingInstance, Uri audioUri, String utteranceId, - Bundle systemParameters) { - if (!checkNonNull(callingInstance, audioUri, systemParameters)) { - return TextToSpeech.ERROR; - } - - SpeechItem item = new AudioSpeechItemV2(callingInstance, - Binder.getCallingUid(), Binder.getCallingPid(), utteranceId, systemParameters, - audioUri); - return mSynthHandler.enqueueSpeechItem(TextToSpeech.QUEUE_ADD, item); - } }; private class CallbackMap extends RemoteCallbackList<ITextToSpeechCallback> { @@ -1617,18 +1086,6 @@ public abstract class TextToSpeechService extends Service { } } - public void dispatchVoicesInfoChange(List<VoiceInfo> voicesInfo) { - synchronized (mCallerToCallback) { - for (ITextToSpeechCallback callback : mCallerToCallback.values()) { - try { - callback.onVoicesInfoChange(voicesInfo); - } catch (RemoteException e) { - Log.e(TAG, "Failed to request reconnect", e); - } - } - } - } - private ITextToSpeechCallback getCallbackFor(Object caller) { ITextToSpeechCallback cb; IBinder asBinder = (IBinder) caller; diff --git a/core/java/android/speech/tts/UtteranceProgressListener.java b/core/java/android/speech/tts/UtteranceProgressListener.java index cf0d22c..6769794 100644 --- a/core/java/android/speech/tts/UtteranceProgressListener.java +++ b/core/java/android/speech/tts/UtteranceProgressListener.java @@ -40,10 +40,26 @@ public abstract class UtteranceProgressListener { * the same utterance. * * @param utteranceId the utterance ID of the utterance. + * @deprecated Use {@link #onError(String,int)} instead */ + @Deprecated public abstract void onError(String utteranceId); /** + * Called when an error has occurred during processing. This can be called + * at any point in the synthesis process. Note that there might be calls + * to {@link #onStart(String)} for specified utteranceId but there will never + * be a call to both {@link #onDone(String)} and {@link #onError(String,int)} for + * the same utterance. The default implementation calls {@link #onError(String)}. + * + * @param utteranceId the utterance ID of the utterance. + * @param errorCode one of the ERROR_* codes from {@link TextToSpeech} + */ + public void onError(String utteranceId, int errorCode) { + onError(utteranceId); + } + + /** * Wraps an old deprecated OnUtteranceCompletedListener with a shiny new * progress listener. * diff --git a/core/java/android/speech/tts/VoiceInfo.aidl b/core/java/android/speech/tts/VoiceInfo.aidl deleted file mode 100644 index 4005f8b..0000000 --- a/core/java/android/speech/tts/VoiceInfo.aidl +++ /dev/null @@ -1,20 +0,0 @@ -/* -** -** Copyright 2013, 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; - -parcelable VoiceInfo;
\ No newline at end of file diff --git a/core/java/android/speech/tts/VoiceInfo.java b/core/java/android/speech/tts/VoiceInfo.java deleted file mode 100644 index 71629dc..0000000 --- a/core/java/android/speech/tts/VoiceInfo.java +++ /dev/null @@ -1,340 +0,0 @@ -/* - * Copyright (C) 2014 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.os.Bundle; -import android.os.Parcel; -import android.os.Parcelable; - -import java.util.Locale; - -/** - * Characteristics and features of a Text-To-Speech Voice. Each TTS Engine can expose - * multiple voices for multiple locales, with different set of features. - * - * Each VoiceInfo has an unique name. This name can be obtained using the {@link #getName()} method - * and will persist until the client is asked to re-evaluate the list of available voices in the - * {@link TextToSpeechClient.ConnectionCallbacks#onEngineStatusChange(android.speech.tts.TextToSpeechClient.EngineStatus)} - * callback. The name can be used to reference a VoiceInfo in an instance of {@link RequestConfig}; - * the {@link TextToSpeechClient.Params#FALLBACK_VOICE_NAME} voice parameter is an example of this. - * It is recommended that the voice name never change during the TTS service lifetime. - */ -public final class VoiceInfo implements Parcelable { - /** Very low, but still intelligible quality of speech synthesis */ - public static final int QUALITY_VERY_LOW = 100; - - /** Low, not human-like quality of speech synthesis */ - public static final int QUALITY_LOW = 200; - - /** Normal quality of speech synthesis */ - public static final int QUALITY_NORMAL = 300; - - /** High, human-like quality of speech synthesis */ - public static final int QUALITY_HIGH = 400; - - /** Very high, almost human-indistinguishable quality of speech synthesis */ - public static final int QUALITY_VERY_HIGH = 500; - - /** Very low expected synthesizer latency (< 20ms) */ - public static final int LATENCY_VERY_LOW = 100; - - /** Low expected synthesizer latency (~20ms) */ - public static final int LATENCY_LOW = 200; - - /** Normal expected synthesizer latency (~50ms) */ - public static final int LATENCY_NORMAL = 300; - - /** Network based expected synthesizer latency (~200ms) */ - public static final int LATENCY_HIGH = 400; - - /** Very slow network based expected synthesizer latency (> 200ms) */ - public static final int LATENCY_VERY_HIGH = 500; - - /** Additional feature key, with string value, gender of the speaker */ - public static final String FEATURE_SPEAKER_GENDER = "speakerGender"; - - /** Additional feature key, with integer value, speaking speed in words per minute - * when {@link TextToSpeechClient.Params#SPEECH_SPEED} parameter is set to {@code 1.0} */ - public static final String FEATURE_WORDS_PER_MINUTE = "wordsPerMinute"; - - /** - * Additional feature key, with boolean value, that indicates that voice may need to - * download additional data if used for synthesis. - * - * Making a request with a voice that has this feature may result in a - * {@link TextToSpeechClient.Status#ERROR_DOWNLOADING_ADDITIONAL_DATA} error. It's recommended - * to set the {@link TextToSpeechClient.Params#FALLBACK_VOICE_NAME} voice parameter to reference - * a fully installed voice (or network voice) that can serve as replacement. - * - * Note: It's a good practice for a TTS engine to provide a sensible fallback voice as the - * default value for {@link TextToSpeechClient.Params#FALLBACK_VOICE_NAME} parameter if this - * feature is present. - */ - public static final String FEATURE_MAY_AUTOINSTALL = "mayAutoInstall"; - - private final String mName; - private final Locale mLocale; - private final int mQuality; - private final int mLatency; - private final boolean mRequiresNetworkConnection; - private final Bundle mParams; - private final Bundle mAdditionalFeatures; - - private VoiceInfo(Parcel in) { - this.mName = in.readString(); - String[] localesData = new String[3]; - in.readStringArray(localesData); - this.mLocale = new Locale(localesData[0], localesData[1], localesData[2]); - - this.mQuality = in.readInt(); - this.mLatency = in.readInt(); - this.mRequiresNetworkConnection = (in.readByte() == 1); - - this.mParams = in.readBundle(); - this.mAdditionalFeatures = in.readBundle(); - } - - private VoiceInfo(String name, - Locale locale, - int quality, - int latency, - boolean requiresNetworkConnection, - Bundle params, - Bundle additionalFeatures) { - this.mName = name; - this.mLocale = locale; - this.mQuality = quality; - this.mLatency = latency; - this.mRequiresNetworkConnection = requiresNetworkConnection; - this.mParams = params; - this.mAdditionalFeatures = additionalFeatures; - } - - /** Builder, allows TTS engines to create VoiceInfo instances. */ - public static final class Builder { - private String name; - private Locale locale; - private int quality = VoiceInfo.QUALITY_NORMAL; - private int latency = VoiceInfo.LATENCY_NORMAL; - private boolean requiresNetworkConnection; - private Bundle params; - private Bundle additionalFeatures; - - public Builder() { - - } - - /** - * Copy fields from given VoiceInfo instance. - */ - public Builder(VoiceInfo voiceInfo) { - this.name = voiceInfo.mName; - this.locale = voiceInfo.mLocale; - this.quality = voiceInfo.mQuality; - this.latency = voiceInfo.mLatency; - this.requiresNetworkConnection = voiceInfo.mRequiresNetworkConnection; - this.params = (Bundle)voiceInfo.mParams.clone(); - this.additionalFeatures = (Bundle) voiceInfo.mAdditionalFeatures.clone(); - } - - /** - * Sets the voice's unique name. It will be used by clients to reference the voice used by a - * request. - * - * It's recommended that each voice use the same consistent name during the TTS service - * lifetime. - */ - public Builder setName(String name) { - this.name = name; - return this; - } - - /** - * Sets voice locale. This has to be a valid locale, built from ISO 639-1 and ISO 3166-1 - * two letter codes. - */ - public Builder setLocale(Locale locale) { - this.locale = locale; - return this; - } - - /** - * Sets map of all available request parameters with their default values. - * Some common parameter names can be found in {@link TextToSpeechClient.Params} static - * members. - */ - public Builder setParamsWithDefaults(Bundle params) { - this.params = params; - return this; - } - - /** - * Sets map of additional voice features. Some common feature names can be found in - * {@link VoiceInfo} static members. - */ - public Builder setAdditionalFeatures(Bundle additionalFeatures) { - this.additionalFeatures = additionalFeatures; - return this; - } - - /** - * Sets the voice quality (higher is better). - */ - public Builder setQuality(int quality) { - this.quality = quality; - return this; - } - - /** - * Sets the voice latency (lower is better). - */ - public Builder setLatency(int latency) { - this.latency = latency; - return this; - } - - /** - * Sets whether the voice requires network connection to work properly. - */ - public Builder setRequiresNetworkConnection(boolean requiresNetworkConnection) { - this.requiresNetworkConnection = requiresNetworkConnection; - return this; - } - - /** - * @return The built VoiceInfo instance. - */ - public VoiceInfo build() { - if (name == null || name.isEmpty()) { - throw new IllegalStateException("Name can't be null or empty"); - } - if (locale == null) { - throw new IllegalStateException("Locale can't be null"); - } - - return new VoiceInfo(name, locale, quality, latency, - requiresNetworkConnection, - ((params == null) ? new Bundle() : - (Bundle)params.clone()), - ((additionalFeatures == null) ? new Bundle() : - (Bundle)additionalFeatures.clone())); - } - } - - /** - * @hide - */ - @Override - public int describeContents() { - return 0; - } - - /** - * @hide - */ - @Override - public void writeToParcel(Parcel dest, int flags) { - dest.writeString(mName); - String[] localesData = new String[]{mLocale.getLanguage(), mLocale.getCountry(), mLocale.getVariant()}; - dest.writeStringArray(localesData); - dest.writeInt(mQuality); - dest.writeInt(mLatency); - dest.writeByte((byte) (mRequiresNetworkConnection ? 1 : 0)); - dest.writeBundle(mParams); - dest.writeBundle(mAdditionalFeatures); - } - - /** - * @hide - */ - public static final Parcelable.Creator<VoiceInfo> CREATOR = new Parcelable.Creator<VoiceInfo>() { - @Override - public VoiceInfo createFromParcel(Parcel in) { - return new VoiceInfo(in); - } - - @Override - public VoiceInfo[] newArray(int size) { - return new VoiceInfo[size]; - } - }; - - /** - * @return The voice's locale - */ - public Locale getLocale() { - return mLocale; - } - - /** - * @return The voice's quality (higher is better) - */ - public int getQuality() { - return mQuality; - } - - /** - * @return The voice's latency (lower is better) - */ - public int getLatency() { - return mLatency; - } - - /** - * @return Does the Voice require a network connection to work. - */ - public boolean getRequiresNetworkConnection() { - return mRequiresNetworkConnection; - } - - /** - * @return Bundle of all available parameters with their default values. - */ - public Bundle getParamsWithDefaults() { - return mParams; - } - - /** - * @return Unique voice name. - * - * Each VoiceInfo has an unique name, that persists until client is asked to re-evaluate the - * set of the available languages in the {@link TextToSpeechClient.ConnectionCallbacks#onEngineStatusChange(android.speech.tts.TextToSpeechClient.EngineStatus)} - * callback (Voice may disappear from the set if voice was removed by the user). - */ - public String getName() { - return mName; - } - - /** - * @return Additional features of the voice. - */ - public Bundle getAdditionalFeatures() { - return mAdditionalFeatures; - } - - @Override - public String toString() { - StringBuilder builder = new StringBuilder(64); - return builder.append("VoiceInfo[Name: ").append(mName) - .append(" ,locale: ").append(mLocale) - .append(" ,quality: ").append(mQuality) - .append(" ,latency: ").append(mLatency) - .append(" ,requiresNetwork: ").append(mRequiresNetworkConnection) - .append(" ,paramsWithDefaults: ").append(mParams.toString()) - .append(" ,additionalFeatures: ").append(mAdditionalFeatures.toString()) - .append("]").toString(); - } -} |