Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a6cc9b85 authored by Niels Egberts's avatar Niels Egberts
Browse files

Markup support for framework

Change-Id: Ia5ad6cff7593c295944a90775a1b061c95f5cc3f
parent 55cef957
Loading
Loading
Loading
Loading
+105 −1
Original line number Diff line number Diff line
@@ -26581,6 +26581,28 @@ package android.speech {
package android.speech.tts {
  public final class Markup implements android.os.Parcelable {
    ctor public Markup();
    ctor public Markup(java.lang.String);
    ctor public Markup(android.speech.tts.Markup);
    method public android.speech.tts.Markup addNestedMarkup(android.speech.tts.Markup);
    method public int describeContents();
    method public android.speech.tts.Markup getNestedMarkup(int);
    method public java.util.List<android.speech.tts.Markup> getNestedMarkups();
    method public java.lang.String getParameter(java.lang.String);
    method public java.lang.String getPlainText();
    method public java.lang.String getType();
    method public static android.speech.tts.Markup markupFromString(java.lang.String) throws java.lang.IllegalArgumentException;
    method public int nestedMarkupSize();
    method public int parametersSize();
    method public boolean removeNestedMarkup(android.speech.tts.Markup);
    method public void removeParameter(java.lang.String);
    method public android.speech.tts.Markup setParameter(java.lang.String, java.lang.String);
    method public void setPlainText(java.lang.String);
    method public void setType(java.lang.String);
    method public void writeToParcel(android.os.Parcel, int);
  }
  public final class RequestConfig {
    method public android.os.Bundle getAudioParams();
    method public android.speech.tts.VoiceInfo getVoice();
@@ -26643,9 +26665,10 @@ package android.speech.tts {
  }
  public final class SynthesisRequestV2 implements android.os.Parcelable {
    ctor public SynthesisRequestV2(java.lang.String, java.lang.String, java.lang.String, android.os.Bundle, android.os.Bundle);
    ctor public SynthesisRequestV2(android.speech.tts.Markup, java.lang.String, java.lang.String, android.os.Bundle, android.os.Bundle);
    method public int describeContents();
    method public android.os.Bundle getAudioParams();
    method public android.speech.tts.Markup getMarkup();
    method public java.lang.String getText();
    method public java.lang.String getUtteranceId();
    method public java.lang.String getVoiceName();
@@ -26748,7 +26771,9 @@ package android.speech.tts {
    method public void queueAudio(android.net.Uri, android.speech.tts.TextToSpeechClient.UtteranceId, android.speech.tts.RequestConfig, android.speech.tts.TextToSpeechClient.RequestCallbacks);
    method public void queueSilence(long, android.speech.tts.TextToSpeechClient.UtteranceId, android.speech.tts.TextToSpeechClient.RequestCallbacks);
    method public void queueSpeak(java.lang.String, android.speech.tts.TextToSpeechClient.UtteranceId, android.speech.tts.RequestConfig, android.speech.tts.TextToSpeechClient.RequestCallbacks);
    method public void queueSpeak(android.speech.tts.Markup, android.speech.tts.TextToSpeechClient.UtteranceId, android.speech.tts.RequestConfig, android.speech.tts.TextToSpeechClient.RequestCallbacks);
    method public void queueSynthesizeToFile(java.lang.String, android.speech.tts.TextToSpeechClient.UtteranceId, java.io.File, android.speech.tts.RequestConfig, android.speech.tts.TextToSpeechClient.RequestCallbacks);
    method public void queueSynthesizeToFile(android.speech.tts.Markup, android.speech.tts.TextToSpeechClient.UtteranceId, java.io.File, android.speech.tts.RequestConfig, android.speech.tts.TextToSpeechClient.RequestCallbacks);
    method public void stop();
  }
@@ -26822,6 +26847,85 @@ package android.speech.tts {
    method protected void onVoicesInfoChange();
  }
  public class Utterance {
    ctor public Utterance();
    method public android.speech.tts.Utterance append(android.speech.tts.Utterance.AbstractTts<? extends android.speech.tts.Utterance.AbstractTts<?>>);
    method public android.speech.tts.Utterance append(java.lang.String);
    method public android.speech.tts.Utterance append(int);
    method public android.speech.tts.Markup createMarkup();
    method public android.speech.tts.Utterance.AbstractTts<? extends android.speech.tts.Utterance.AbstractTts<?>> get(int);
    method public android.speech.tts.Utterance setNoWarningOnFallback(boolean);
    method public int size();
    method public static android.speech.tts.Utterance utteranceFromString(java.lang.String) throws java.lang.IllegalArgumentException;
    field public static final int ANIMACY_ANIMATE = 1; // 0x1
    field public static final int ANIMACY_INANIMATE = 2; // 0x2
    field public static final int ANIMACY_UNKNOWN = 0; // 0x0
    field public static final int CASE_ABLATIVE = 4; // 0x4
    field public static final int CASE_ACCUSATIVE = 2; // 0x2
    field public static final int CASE_DATIVE = 3; // 0x3
    field public static final int CASE_GENITIVE = 5; // 0x5
    field public static final int CASE_INSTRUMENTAL = 8; // 0x8
    field public static final int CASE_LOCATIVE = 7; // 0x7
    field public static final int CASE_NOMINATIVE = 1; // 0x1
    field public static final int CASE_UNKNOWN = 0; // 0x0
    field public static final int CASE_VOCATIVE = 6; // 0x6
    field public static final int GENDER_FEMALE = 3; // 0x3
    field public static final int GENDER_MALE = 2; // 0x2
    field public static final int GENDER_NEUTRAL = 1; // 0x1
    field public static final int GENDER_UNKNOWN = 0; // 0x0
    field public static final java.lang.String KEY_NO_WARNING_ON_FALLBACK = "no_warning_on_fallback";
    field public static final int MULTIPLICITY_DUAL = 2; // 0x2
    field public static final int MULTIPLICITY_PLURAL = 3; // 0x3
    field public static final int MULTIPLICITY_SINGLE = 1; // 0x1
    field public static final int MULTIPLICITY_UNKNOWN = 0; // 0x0
    field public static final java.lang.String TYPE_UTTERANCE = "utterance";
  }
  public static abstract class Utterance.AbstractTts {
    ctor protected Utterance.AbstractTts();
    ctor protected Utterance.AbstractTts(android.speech.tts.Markup);
    method public java.lang.String generatePlainText();
    method public android.speech.tts.Markup getMarkup();
    method protected java.lang.String getParameter(java.lang.String);
    method public java.lang.String getPlainText();
    method public java.lang.String getType();
    method protected C removeParameter(java.lang.String);
    method protected C setParameter(java.lang.String, java.lang.String);
    method public C setPlainText(java.lang.String);
    field protected android.speech.tts.Markup mMarkup;
  }
  public static abstract class Utterance.AbstractTtsSemioticClass extends android.speech.tts.Utterance.AbstractTts {
    ctor protected Utterance.AbstractTtsSemioticClass();
    ctor protected Utterance.AbstractTtsSemioticClass(android.speech.tts.Markup);
    method public int getAnimacy();
    method public int getCase();
    method public int getGender();
    method public int getMultiplicity();
    method public C setAnimacy(int);
    method public C setCase(int);
    method public C setGender(int);
    method public C setMultiplicity(int);
  }
  public static class Utterance.TtsCardinal extends android.speech.tts.Utterance.AbstractTtsSemioticClass {
    ctor public Utterance.TtsCardinal();
    ctor public Utterance.TtsCardinal(int);
    ctor public Utterance.TtsCardinal(java.lang.String);
    method public java.lang.String getInteger();
    method public android.speech.tts.Utterance.TtsCardinal setInteger(int);
    method public android.speech.tts.Utterance.TtsCardinal setInteger(java.lang.String);
    field protected static final java.lang.String TYPE_CARDINAL = "cardinal";
  }
  public static class Utterance.TtsText extends android.speech.tts.Utterance.AbstractTtsSemioticClass {
    ctor public Utterance.TtsText();
    ctor public Utterance.TtsText(java.lang.String);
    method public java.lang.String getText();
    method public android.speech.tts.Utterance.TtsText setText(java.lang.String);
    field protected static final java.lang.String TYPE_TEXT = "text";
  }
  public abstract class UtteranceProgressListener {
    ctor public UtteranceProgressListener();
    method public abstract void onDone(java.lang.String);
+537 −0

File added.

Preview size limit exceeded, changes collapsed.

+28 −10
Original line number Diff line number Diff line
@@ -4,11 +4,12 @@ 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 utterance to synthesize</li>
 *   <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>
@@ -16,8 +17,11 @@ import android.speech.tts.TextToSpeechClient.UtteranceId;
 * </ul>
 */
public final class SynthesisRequestV2 implements Parcelable {
    /** Synthesis utterance. */
    private final String mText;

    private static final String TAG = "SynthesisRequestV2";

    /** Synthesis markup */
    private final Markup mMarkup;

    /** Synthesis id. */
    private final String mUtteranceId;
@@ -34,9 +38,9 @@ public final class SynthesisRequestV2 implements Parcelable {
    /**
     * Constructor for test purposes.
     */
    public SynthesisRequestV2(String text, String utteranceId, String voiceName,
    public SynthesisRequestV2(Markup markup, String utteranceId, String voiceName,
            Bundle voiceParams, Bundle audioParams) {
        this.mText = text;
        this.mMarkup = markup;
        this.mUtteranceId = utteranceId;
        this.mVoiceName = voiceName;
        this.mVoiceParams = voiceParams;
@@ -49,15 +53,18 @@ public final class SynthesisRequestV2 implements Parcelable {
     * @hide
     */
    public SynthesisRequestV2(Parcel in) {
        this.mText = in.readString();
        this.mMarkup = (Markup) in.readValue(Markup.class.getClassLoader());
        this.mUtteranceId = in.readString();
        this.mVoiceName = in.readString();
        this.mVoiceParams = in.readBundle();
        this.mAudioParams = in.readBundle();
    }

    SynthesisRequestV2(String text, String utteranceId, RequestConfig rconfig) {
        this.mText = text;
    /**
     * 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();
@@ -71,7 +78,7 @@ public final class SynthesisRequestV2 implements Parcelable {
     */
    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(mText);
        dest.writeValue(mMarkup);
        dest.writeString(mUtteranceId);
        dest.writeString(mVoiceName);
        dest.writeBundle(mVoiceParams);
@@ -82,7 +89,18 @@ public final class SynthesisRequestV2 implements Parcelable {
     * @return the text which should be synthesized.
     */
    public String getText() {
        return mText;
        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;
    }

    /**
+60 −7
Original line number Diff line number Diff line
@@ -512,7 +512,6 @@ public class TextToSpeechClient {
        }
    }


    /**
     * Connects the client to TTS service. This method returns immediately, and connects to the
     * service in the background.
@@ -876,7 +875,7 @@ public class TextToSpeechClient {
    private static final String ACTION_QUEUE_SPEAK_NAME = "queueSpeak";

    /**
     * Speaks the string using the specified queuing strategy using current
     * 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.
@@ -887,12 +886,35 @@ public class TextToSpeechClient {
     *            in {@link RequestCallbacks}.
     * @param config Synthesis request configuration. Can't be null. Has to contain a
     *            voice.
     * @param callbacks Synthesis request callbacks. If null, default request
     * @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(ACTION_QUEUE_SPEAK_NAME) {
            @Override
            public void run(ITextToSpeechService service) throws RemoteException {
@@ -908,7 +930,7 @@ public class TextToSpeechClient {

                int queueResult = service.speakV2(
                        getCallerIdentity(),
                        new SynthesisRequestV2(utterance, utteranceId.toUniqueString(), config));
                        new SynthesisRequestV2(markup, utteranceId.toUniqueString(), config));
                if (queueResult != Status.SUCCESS) {
                    removeCallbackAndErr(utteranceId.toUniqueString(), queueResult);
                }
@@ -931,12 +953,37 @@ public class TextToSpeechClient {
     * @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, default request
     * @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(ACTION_QUEUE_SYNTHESIZE_TO_FILE) {
            @Override
            public void run(ITextToSpeechService service) throws RemoteException {
@@ -964,8 +1011,7 @@ public class TextToSpeechClient {

                    int queueResult = service.synthesizeToFileDescriptorV2(getCallerIdentity(),
                            fileDescriptor,
                            new SynthesisRequestV2(utterance, utteranceId.toUniqueString(),
                                    config));
                            new SynthesisRequestV2(markup, utteranceId.toUniqueString(), config));
                    fileDescriptor.close();
                    if (queueResult != Status.SUCCESS) {
                        removeCallbackAndErr(utteranceId.toUniqueString(), queueResult);
@@ -981,6 +1027,13 @@ public class TextToSpeechClient {
        });
    }

    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";

    /**
+49 −4
Original line number Diff line number Diff line
@@ -352,6 +352,12 @@ public abstract class TextToSpeechService extends Service {
            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();
@@ -856,14 +862,53 @@ public abstract class TextToSpeechService extends Service {
            }
        }

        /**
         * 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.getText() == null) {
                Log.e(TAG, "null synthesis text");
            if (mSynthesisRequest.getMarkup() == null) {
                Log.e(TAG, "No markup in request.");
                return false;
            }
            if (mSynthesisRequest.getText().length() >= TextToSpeech.getMaxSpeechInputLength()) {
                Log.w(TAG, "Text too long: " + mSynthesisRequest.getText().length() + " chars");
            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;
            }

Loading