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

Commit 334b861e authored by Android (Google) Code Review's avatar Android (Google) Code Review
Browse files

Merge change 6925 into donut

* changes:
  Propagate optional audio stream type to the creation of the audio resources to enable the playback of TTS content on various stream types.
parents aa459370 9440bce8
Loading
Loading
Loading
Loading
+24 −18
Original line number Original line Diff line number Diff line
@@ -33,6 +33,8 @@
#define DEFAULT_TTS_FORMAT      AudioSystem::PCM_16_BIT
#define DEFAULT_TTS_FORMAT      AudioSystem::PCM_16_BIT
#define DEFAULT_TTS_NB_CHANNELS 1
#define DEFAULT_TTS_NB_CHANNELS 1
#define DEFAULT_TTS_BUFFERSIZE  1024
#define DEFAULT_TTS_BUFFERSIZE  1024
// TODO use the TTS stream type when available
#define DEFAULT_TTS_STREAM_TYPE AudioSystem::MUSIC


#define USAGEMODE_PLAY_IMMEDIATELY 0
#define USAGEMODE_PLAY_IMMEDIATELY 0
#define USAGEMODE_WRITE_TO_FILE    1
#define USAGEMODE_WRITE_TO_FILE    1
@@ -46,10 +48,12 @@ struct fields_t {
    jmethodID   synthProxyMethodPost;
    jmethodID   synthProxyMethodPost;
};
};


// structure to hold the data that is used each time the TTS engine has synthesized more data
struct afterSynthData_t {
struct afterSynthData_t {
    jint jniStorage;
    jint jniStorage;
    int  usageMode;
    int  usageMode;
    FILE* outputFile;
    FILE* outputFile;
    AudioSystem::stream_type streamType;
};
};


// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
@@ -62,6 +66,7 @@ class SynthProxyJniStorage {
        jobject                   tts_ref;
        jobject                   tts_ref;
        TtsEngine*                mNativeSynthInterface;
        TtsEngine*                mNativeSynthInterface;
        AudioTrack*               mAudioOut;
        AudioTrack*               mAudioOut;
        AudioSystem::stream_type  mStreamType;
        uint32_t                  mSampleRate;
        uint32_t                  mSampleRate;
        AudioSystem::audio_format mAudFormat;
        AudioSystem::audio_format mAudFormat;
        int                       mNbChannels;
        int                       mNbChannels;
@@ -73,6 +78,7 @@ class SynthProxyJniStorage {
            tts_ref = NULL;
            tts_ref = NULL;
            mNativeSynthInterface = NULL;
            mNativeSynthInterface = NULL;
            mAudioOut = NULL;
            mAudioOut = NULL;
            mStreamType = DEFAULT_TTS_STREAM_TYPE;
            mSampleRate = DEFAULT_TTS_RATE;
            mSampleRate = DEFAULT_TTS_RATE;
            mAudFormat  = DEFAULT_TTS_FORMAT;
            mAudFormat  = DEFAULT_TTS_FORMAT;
            mNbChannels = DEFAULT_TTS_NB_CHANNELS;
            mNbChannels = DEFAULT_TTS_NB_CHANNELS;
@@ -97,34 +103,33 @@ class SynthProxyJniStorage {
            }
            }
        }
        }


        void createAudioOut(uint32_t rate, AudioSystem::audio_format format,
        void createAudioOut(AudioSystem::stream_type streamType, uint32_t rate,
                int channel) {
                AudioSystem::audio_format format, int channel) {
            mSampleRate = rate;
            mSampleRate = rate;
            mAudFormat  = format;
            mAudFormat  = format;
            mNbChannels = channel;
            mNbChannels = channel;


            // TODO use the TTS stream type
            mStreamType = streamType;
            int streamType = AudioSystem::MUSIC;


            // retrieve system properties to ensure successful creation of the
            // retrieve system properties to ensure successful creation of the
            // AudioTrack object for playback
            // AudioTrack object for playback
            int afSampleRate;
            int afSampleRate;
            if (AudioSystem::getOutputSamplingRate(&afSampleRate, streamType) != NO_ERROR) {
            if (AudioSystem::getOutputSamplingRate(&afSampleRate, mStreamType) != NO_ERROR) {
                afSampleRate = 44100;
                afSampleRate = 44100;
            }
            }
            int afFrameCount;
            int afFrameCount;
            if (AudioSystem::getOutputFrameCount(&afFrameCount, streamType) != NO_ERROR) {
            if (AudioSystem::getOutputFrameCount(&afFrameCount, mStreamType) != NO_ERROR) {
                afFrameCount = 2048;
                afFrameCount = 2048;
            }
            }
            uint32_t afLatency;
            uint32_t afLatency;
            if (AudioSystem::getOutputLatency(&afLatency, streamType) != NO_ERROR) {
            if (AudioSystem::getOutputLatency(&afLatency, mStreamType) != NO_ERROR) {
                afLatency = 500;
                afLatency = 500;
            }
            }
            uint32_t minBufCount = afLatency / ((1000 * afFrameCount)/afSampleRate);
            uint32_t minBufCount = afLatency / ((1000 * afFrameCount)/afSampleRate);
            if (minBufCount < 2) minBufCount = 2;
            if (minBufCount < 2) minBufCount = 2;
            int minFrameCount = (afFrameCount * rate * minBufCount)/afSampleRate;
            int minFrameCount = (afFrameCount * rate * minBufCount)/afSampleRate;


            mAudioOut = new AudioTrack(streamType, rate, format, channel,
            mAudioOut = new AudioTrack(mStreamType, rate, format, channel,
                    minFrameCount > 4096 ? minFrameCount : 4096,
                    minFrameCount > 4096 ? minFrameCount : 4096,
                    0, 0, 0, 0); // not using an AudioTrack callback
                    0, 0, 0, 0); // not using an AudioTrack callback


@@ -142,21 +147,21 @@ class SynthProxyJniStorage {




// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
void prepAudioTrack(SynthProxyJniStorage* pJniData,
void prepAudioTrack(SynthProxyJniStorage* pJniData, AudioSystem::stream_type streamType,
        uint32_t rate, AudioSystem::audio_format format, int channel)
        uint32_t rate, AudioSystem::audio_format format, int channel) {
{
    // Don't bother creating a new audiotrack object if the current
    // Don't bother creating a new audiotrack object if the current
    // object is already set.
    // object is already initialized with the same audio parameters.
    if ( pJniData->mAudioOut &&
    if ( pJniData->mAudioOut &&
         (rate == pJniData->mSampleRate) &&
         (rate == pJniData->mSampleRate) &&
         (format == pJniData->mAudFormat) &&
         (format == pJniData->mAudFormat) &&
         (channel == pJniData->mNbChannels) ){
         (channel == pJniData->mNbChannels) &&
         (streamType == pJniData->mStreamType) ){
        return;
        return;
    }
    }
    if (pJniData->mAudioOut){
    if (pJniData->mAudioOut){
        pJniData->killAudio();
        pJniData->killAudio();
    }
    }
    pJniData->createAudioOut(rate, format, channel);
    pJniData->createAudioOut(streamType, rate, format, channel);
}
}




@@ -186,7 +191,7 @@ static tts_callback_status ttsSynthDoneCB(void *& userdata, uint32_t rate,
        }
        }


        if (bufferSize > 0) {
        if (bufferSize > 0) {
            prepAudioTrack(pJniData, rate, format, channel);
            prepAudioTrack(pJniData, pForAfter->streamType, rate, format, channel);
            if (pJniData->mAudioOut) {
            if (pJniData->mAudioOut) {
                pJniData->mAudioOut->write(wav, bufferSize);
                pJniData->mAudioOut->write(wav, bufferSize);
                //LOGV("AudioTrack wrote: %d bytes", bufferSize);
                //LOGV("AudioTrack wrote: %d bytes", bufferSize);
@@ -241,7 +246,7 @@ android_tts_SynthProxy_native_setup(JNIEnv *env, jobject thiz,
    SynthProxyJniStorage* pJniStorage = new SynthProxyJniStorage();
    SynthProxyJniStorage* pJniStorage = new SynthProxyJniStorage();


    prepAudioTrack(pJniStorage,
    prepAudioTrack(pJniStorage,
            DEFAULT_TTS_RATE, DEFAULT_TTS_FORMAT, DEFAULT_TTS_NB_CHANNELS);
            DEFAULT_TTS_STREAM_TYPE, DEFAULT_TTS_RATE, DEFAULT_TTS_FORMAT, DEFAULT_TTS_NB_CHANNELS);


    const char *nativeSoLibNativeString =
    const char *nativeSoLibNativeString =
            env->GetStringUTFChars(nativeSoLib, 0);
            env->GetStringUTFChars(nativeSoLib, 0);
@@ -526,7 +531,7 @@ android_tts_SynthProxy_synthesizeToFile(JNIEnv *env, jobject thiz, jint jniData,


static int
static int
android_tts_SynthProxy_speak(JNIEnv *env, jobject thiz, jint jniData,
android_tts_SynthProxy_speak(JNIEnv *env, jobject thiz, jint jniData,
        jstring textJavaString)
        jstring textJavaString, jint javaStreamType)
{
{
    int result = TTS_FAILURE;
    int result = TTS_FAILURE;


@@ -545,6 +550,7 @@ android_tts_SynthProxy_speak(JNIEnv *env, jobject thiz, jint jniData,
    afterSynthData_t* pForAfter = new (afterSynthData_t);
    afterSynthData_t* pForAfter = new (afterSynthData_t);
    pForAfter->jniStorage = jniData;
    pForAfter->jniStorage = jniData;
    pForAfter->usageMode  = USAGEMODE_PLAY_IMMEDIATELY;
    pForAfter->usageMode  = USAGEMODE_PLAY_IMMEDIATELY;
    pForAfter->streamType = (AudioSystem::stream_type) javaStreamType;


    if (pSynthData->mNativeSynthInterface) {
    if (pSynthData->mNativeSynthInterface) {
        const char *textNativeString = env->GetStringUTFChars(textJavaString, 0);
        const char *textNativeString = env->GetStringUTFChars(textJavaString, 0);
@@ -672,7 +678,7 @@ static JNINativeMethod gMethods[] = {
        (void*)android_tts_SynthProxy_stop
        (void*)android_tts_SynthProxy_stop
    },
    },
    {   "native_speak",
    {   "native_speak",
        "(ILjava/lang/String;)I",
        "(ILjava/lang/String;I)I",
        (void*)android_tts_SynthProxy_speak
        (void*)android_tts_SynthProxy_speak
    },
    },
    {   "native_synthesizeToFile",
    {   "native_synthesizeToFile",
+10 −3
Original line number Original line Diff line number Diff line
@@ -15,6 +15,8 @@
 */
 */
package android.tts;
package android.tts;


import android.media.AudioManager;
import android.media.AudioSystem;
import android.util.Log;
import android.util.Log;
import java.lang.ref.WeakReference;
import java.lang.ref.WeakReference;


@@ -52,8 +54,13 @@ public class SynthProxy {
    /**
    /**
     * Synthesize speech and speak it directly using AudioTrack.
     * Synthesize speech and speak it directly using AudioTrack.
     */
     */
    public int speak(String text) {
    public int speak(String text, int streamType) {
        return native_speak(mJniData, text);
        if ((streamType > -1) && (streamType < AudioSystem.getNumStreamTypes())) {
            return native_speak(mJniData, text, streamType);
        } else {
            Log.e("SynthProxy", "Trying to speak with invalid stream type " + streamType);
            return native_speak(mJniData, text, AudioManager.STREAM_MUSIC);
        }
    }
    }


    /**
    /**
@@ -156,7 +163,7 @@ public class SynthProxy {


    private native final int native_stop(int jniData);
    private native final int native_stop(int jniData);


    private native final int native_speak(int jniData, String text);
    private native final int native_speak(int jniData, String text, int streamType);


    private native final int native_synthesizeToFile(int jniData, String text, String filename);
    private native final int native_synthesizeToFile(int jniData, String text, String filename);


+33 −5
Original line number Original line Diff line number Diff line
@@ -22,6 +22,7 @@ import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.PackageManager.NameNotFoundException;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnCompletionListener;
import android.media.MediaPlayer.OnCompletionListener;
import android.net.Uri;
import android.net.Uri;
@@ -109,6 +110,8 @@ public class TtsService extends Service implements OnCompletionListener {


    private static final int MAX_SPEECH_ITEM_CHAR_LENGTH = 4000;
    private static final int MAX_SPEECH_ITEM_CHAR_LENGTH = 4000;
    private static final int MAX_FILENAME_LENGTH = 250;
    private static final int MAX_FILENAME_LENGTH = 250;
    // TODO use the TTS stream type when available
    private static final int DEFAULT_STREAM_TYPE = AudioManager.STREAM_MUSIC;


    private static final String ACTION = "android.intent.action.START_TTS_SERVICE";
    private static final String ACTION = "android.intent.action.START_TTS_SERVICE";
    private static final String CATEGORY = "android.intent.category.TTS";
    private static final String CATEGORY = "android.intent.category.TTS";
@@ -450,6 +453,7 @@ public class TtsService extends Service implements OnCompletionListener {
                        synth.start();
                        synth.start();
                        return;
                        return;
                    }
                    }
                    int streamType = DEFAULT_STREAM_TYPE;
                    if (params != null){
                    if (params != null){
                        String language = "";
                        String language = "";
                        String country = "";
                        String country = "";
@@ -465,6 +469,12 @@ public class TtsService extends Service implements OnCompletionListener {
                                    country = params.get(i+1);
                                    country = params.get(i+1);
                                } else if (param.equals(TextToSpeech.Engine.TTS_KEY_PARAM_VARIANT)){
                                } else if (param.equals(TextToSpeech.Engine.TTS_KEY_PARAM_VARIANT)){
                                    variant = params.get(i+1);
                                    variant = params.get(i+1);
                                } else if (param.equals(TextToSpeech.Engine.TTS_KEY_PARAM_STREAM)) {
                                    try {
                                        streamType = Integer.parseInt(params.get(i + 1));
                                    } catch (NumberFormatException e) {
                                        streamType = DEFAULT_STREAM_TYPE;
                                    }
                                }
                                }
                            }
                            }
                        }
                        }
@@ -472,7 +482,7 @@ public class TtsService extends Service implements OnCompletionListener {
                            setLanguage("", language, country, variant);
                            setLanguage("", language, country, variant);
                        }
                        }
                    }
                    }
                    nativeSynth.speak(text);
                    nativeSynth.speak(text, streamType);
                } catch (InterruptedException e) {
                } catch (InterruptedException e) {
                    Log.e("TTS speakInternalOnly", "tryLock interrupted");
                    Log.e("TTS speakInternalOnly", "tryLock interrupted");
                    e.printStackTrace();
                    e.printStackTrace();
@@ -651,8 +661,7 @@ public class TtsService extends Service implements OnCompletionListener {
                    // Utterance is part of the app calling the library
                    // Utterance is part of the app calling the library
                    Context ctx;
                    Context ctx;
                    try {
                    try {
                        ctx = this.createPackageContext(sr.mSourcePackageName,
                        ctx = this.createPackageContext(sr.mSourcePackageName, 0);
                                0);
                    } catch (NameNotFoundException e) {
                    } catch (NameNotFoundException e) {
                        e.printStackTrace();
                        e.printStackTrace();
                        mSpeechQueue.remove(0); // Remove it from the queue and
                        mSpeechQueue.remove(0); // Remove it from the queue and
@@ -675,6 +684,7 @@ public class TtsService extends Service implements OnCompletionListener {
                }
                }
                mPlayer.setOnCompletionListener(this);
                mPlayer.setOnCompletionListener(this);
                try {
                try {
                    mPlayer.setAudioStreamType(getStreamTypeFromParams(currentSpeechItem.mParams));
                    mPlayer.start();
                    mPlayer.start();
                } catch (IllegalStateException e) {
                } catch (IllegalStateException e) {
                    mSpeechQueue.clear();
                    mSpeechQueue.clear();
@@ -695,6 +705,24 @@ public class TtsService extends Service implements OnCompletionListener {
        }
        }
    }
    }


    private int getStreamTypeFromParams(ArrayList<String> paramList) {
        int streamType = DEFAULT_STREAM_TYPE;
        if (paramList == null) {
            return streamType;
        }
        for (int i = 0; i < paramList.size() - 1; i = i + 2) {
            String param = paramList.get(i);
            if ((param != null) && (param.equals(TextToSpeech.Engine.TTS_KEY_PARAM_STREAM))) {
                try {
                    streamType = Integer.parseInt(paramList.get(i + 1));
                } catch (NumberFormatException e) {
                    streamType = DEFAULT_STREAM_TYPE;
                }
            }
        }
        return streamType;
    }

    private void cleanUpPlayer() {
    private void cleanUpPlayer() {
        if (mPlayer != null) {
        if (mPlayer != null) {
            mPlayer.release();
            mPlayer.release();