PlaybackSynthesisCallback.java revision 8d1fc2403b8277e68d7816b2bbf05464a4c7a58a
150e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert/*
250e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert * Copyright (C) 2011 The Android Open Source Project
350e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert *
450e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert * Licensed under the Apache License, Version 2.0 (the "License"); you may not
550e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert * use this file except in compliance with the License. You may obtain a copy of
650e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert * the License at
750e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert *
850e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert * http://www.apache.org/licenses/LICENSE-2.0
950e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert *
1050e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert * Unless required by applicable law or agreed to in writing, software
1150e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
1250e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
1350e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert * License for the specific language governing permissions and limitations under
1450e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert * the License.
1550e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert */
1650e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringertpackage android.speech.tts;
1750e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert
18b956f37e375bb2588208d4b5e8a40fae6fae5f86Narayan Kamathimport android.os.Bundle;
198d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamathimport android.speech.tts.TextToSpeechService.UtteranceCompletedDispatcher;
2050e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringertimport android.util.Log;
2150e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert
2250e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert/**
2350e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert * Speech synthesis request that plays the audio as it is received.
2450e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert */
2550e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringertclass PlaybackSynthesisRequest extends SynthesisRequest {
2650e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert
2750e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert    private static final String TAG = "PlaybackSynthesisRequest";
2850e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert    private static final boolean DBG = false;
2950e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert
3050e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert    private static final int MIN_AUDIO_BUFFER_SIZE = 8192;
3150e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert
3250e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert    /**
3350e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert     * Audio stream type. Must be one of the STREAM_ contants defined in
3450e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert     * {@link android.media.AudioManager}.
3550e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert     */
3650e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert    private final int mStreamType;
3750e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert
3850e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert    /**
3950e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert     * Volume, in the range [0.0f, 1.0f]. The default value is
4050e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert     * {@link TextToSpeech.Engine#DEFAULT_VOLUME} (1.0f).
4150e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert     */
4250e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert    private final float mVolume;
4350e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert
4450e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert    /**
4550e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert     * Left/right position of the audio, in the range [-1.0f, 1.0f].
4650e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert     * The default value is {@link TextToSpeech.Engine#DEFAULT_PAN} (0.0f).
4750e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert     */
4850e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert    private final float mPan;
4950e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert
508d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath    /**
518d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath     * Guards {@link #mAudioTrackHandler}, {@link #mToken} and {@link #mStopped}.
528d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath     */
5350e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert    private final Object mStateLock = new Object();
548d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath
558d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath    // Handler associated with a thread that plays back audio requests.
568d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath    private final AudioPlaybackHandler mAudioTrackHandler;
578d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath    // A request "token", which will be non null after start() or
588d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath    // completeAudioAvailable() have been called.
598d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath    private SynthesisMessageParams mToken = null;
608d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath    // Whether this request has been stopped. This is useful for keeping
618d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath    // track whether stop() has been called before start(). In all other cases,
628d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath    // a non-null value of mToken will provide the same information.
6350e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert    private boolean mStopped = false;
6450e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert
658d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath    private volatile boolean mDone = false;
668d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath
678d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath    private final UtteranceCompletedDispatcher mDispatcher;
688d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath
698d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath    PlaybackSynthesisRequest(String text, Bundle params, int streamType, float volume, float pan,
708d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath            AudioPlaybackHandler audioTrackHandler, UtteranceCompletedDispatcher dispatcher) {
71b956f37e375bb2588208d4b5e8a40fae6fae5f86Narayan Kamath        super(text, params);
7250e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert        mStreamType = streamType;
7350e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert        mVolume = volume;
7450e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert        mPan = pan;
75c90f1c815dc06d5bb563474a340f7bb158fab2e2Narayan Kamath        mAudioTrackHandler = audioTrackHandler;
768d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath        mDispatcher = dispatcher;
7750e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert    }
7850e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert
7950e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert    @Override
8050e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert    void stop() {
8150e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert        if (DBG) Log.d(TAG, "stop()");
828d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath
8350e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert        synchronized (mStateLock) {
848d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath            if (mToken == null || mStopped) {
858d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath                Log.w(TAG, "stop() called twice, before start(), or after done()");
868d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath                return;
878d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath            }
888d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath            mAudioTrackHandler.stop(mToken);
898d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath            mToken = null;
9050e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert            mStopped = true;
9150e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert        }
9250e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert    }
9350e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert
9471e0b4807797c602e7fc787d00d27c4f9c92a507Bjorn Bringert    @Override
9571e0b4807797c602e7fc787d00d27c4f9c92a507Bjorn Bringert    public int getMaxBufferSize() {
9671e0b4807797c602e7fc787d00d27c4f9c92a507Bjorn Bringert        // The AudioTrack buffer will be at least MIN_AUDIO_BUFFER_SIZE, so that should always be
9771e0b4807797c602e7fc787d00d27c4f9c92a507Bjorn Bringert        // a safe buffer size to pass in.
9871e0b4807797c602e7fc787d00d27c4f9c92a507Bjorn Bringert        return MIN_AUDIO_BUFFER_SIZE;
9971e0b4807797c602e7fc787d00d27c4f9c92a507Bjorn Bringert    }
10071e0b4807797c602e7fc787d00d27c4f9c92a507Bjorn Bringert
101360eb168d6f9c967543852c7bbab370ef5d8c1bdBjorn Bringert    @Override
102360eb168d6f9c967543852c7bbab370ef5d8c1bdBjorn Bringert    boolean isDone() {
103360eb168d6f9c967543852c7bbab370ef5d8c1bdBjorn Bringert        return mDone;
104360eb168d6f9c967543852c7bbab370ef5d8c1bdBjorn Bringert    }
105360eb168d6f9c967543852c7bbab370ef5d8c1bdBjorn Bringert
10650e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert    @Override
10750e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert    public int start(int sampleRateInHz, int audioFormat, int channelCount) {
10850e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert        if (DBG) {
10950e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert            Log.d(TAG, "start(" + sampleRateInHz + "," + audioFormat
11050e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert                    + "," + channelCount + ")");
11150e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert        }
11250e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert
1138d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath        int channelConfig = AudioPlaybackHandler.getChannelConfig(channelCount);
1148d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath        if (channelConfig == 0) {
1158d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath            Log.e(TAG, "Unsupported number of channels :" + channelCount);
1168d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath            return TextToSpeech.ERROR;
1178d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath        }
1188d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath
11950e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert        synchronized (mStateLock) {
12050e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert            if (mStopped) {
1218d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath                if (DBG) Log.d(TAG, "stop() called before start(), returning.");
12250e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert                return TextToSpeech.ERROR;
12350e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert            }
1248d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath            SynthesisMessageParams params = new SynthesisMessageParams(
1258d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath                    mStreamType, sampleRateInHz, audioFormat, channelCount, mVolume, mPan,
1268d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath                    mDispatcher);
1278d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath            mAudioTrackHandler.enqueueSynthesisStart(params);
12850e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert
1298d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath            mToken = params;
13050e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert        }
13150e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert
13250e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert        return TextToSpeech.SUCCESS;
13350e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert    }
13450e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert
13550e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert
13650e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert    @Override
13750e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert    public int audioAvailable(byte[] buffer, int offset, int length) {
13850e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert        if (DBG) {
13950e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert            Log.d(TAG, "audioAvailable(byte[" + buffer.length + "],"
14071e0b4807797c602e7fc787d00d27c4f9c92a507Bjorn Bringert                    + offset + "," + length + ")");
14171e0b4807797c602e7fc787d00d27c4f9c92a507Bjorn Bringert        }
142c90f1c815dc06d5bb563474a340f7bb158fab2e2Narayan Kamath        if (length > getMaxBufferSize() || length <= 0) {
143c90f1c815dc06d5bb563474a340f7bb158fab2e2Narayan Kamath            throw new IllegalArgumentException("buffer is too large or of zero length (" +
144c90f1c815dc06d5bb563474a340f7bb158fab2e2Narayan Kamath                    + length + " bytes)");
14550e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert        }
1468d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath
14750e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert        synchronized (mStateLock) {
1488d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath            if (mToken == null) {
14950e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert                return TextToSpeech.ERROR;
15050e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert            }
1518d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath
152c90f1c815dc06d5bb563474a340f7bb158fab2e2Narayan Kamath            // Sigh, another copy.
153c90f1c815dc06d5bb563474a340f7bb158fab2e2Narayan Kamath            final byte[] bufferCopy = new byte[length];
154c90f1c815dc06d5bb563474a340f7bb158fab2e2Narayan Kamath            System.arraycopy(buffer, offset, bufferCopy, 0, length);
1558d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath            mToken.addBuffer(bufferCopy);
1568d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath            mAudioTrackHandler.enqueueSynthesisDataAvailable(mToken);
15750e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert        }
1588d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath
1598d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath        return TextToSpeech.SUCCESS;
16050e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert    }
16150e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert
16250e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert    @Override
16350e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert    public int done() {
16450e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert        if (DBG) Log.d(TAG, "done()");
1658d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath
16650e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert        synchronized (mStateLock) {
1678d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath            if (mDone) {
1688d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath                Log.w(TAG, "Duplicate call to done()");
16950e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert                return TextToSpeech.ERROR;
17050e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert            }
1718d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath
1728d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath            mDone = true;
1738d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath
1748d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath            if (mToken == null) {
17550e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert                return TextToSpeech.ERROR;
17650e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert            }
1778d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath
1788d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath            mAudioTrackHandler.enqueueSynthesisDone(mToken);
17950e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert        }
18050e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert        return TextToSpeech.SUCCESS;
18150e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert    }
18271e0b4807797c602e7fc787d00d27c4f9c92a507Bjorn Bringert
18371e0b4807797c602e7fc787d00d27c4f9c92a507Bjorn Bringert    @Override
184360eb168d6f9c967543852c7bbab370ef5d8c1bdBjorn Bringert    public void error() {
1858d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath        if (DBG) Log.d(TAG, "error() [will call stop]");
1868d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath        stop();
187360eb168d6f9c967543852c7bbab370ef5d8c1bdBjorn Bringert    }
188360eb168d6f9c967543852c7bbab370ef5d8c1bdBjorn Bringert
189360eb168d6f9c967543852c7bbab370ef5d8c1bdBjorn Bringert    @Override
19071e0b4807797c602e7fc787d00d27c4f9c92a507Bjorn Bringert    public int completeAudioAvailable(int sampleRateInHz, int audioFormat, int channelCount,
19171e0b4807797c602e7fc787d00d27c4f9c92a507Bjorn Bringert            byte[] buffer, int offset, int length) {
1928d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath        int channelConfig = AudioPlaybackHandler.getChannelConfig(channelCount);
1938d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath        if (channelConfig == 0) {
1948d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath            Log.e(TAG, "Unsupported number of channels :" + channelCount);
1958d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath            return TextToSpeech.ERROR;
1968d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath        }
1978d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath
1988d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath        int bytesPerFrame = AudioPlaybackHandler.getBytesPerFrame(audioFormat);
1998d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath        if (bytesPerFrame < 0) {
2008d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath            Log.e(TAG, "Unsupported audio format :" + audioFormat);
2018d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath            return TextToSpeech.ERROR;
20271e0b4807797c602e7fc787d00d27c4f9c92a507Bjorn Bringert        }
20371e0b4807797c602e7fc787d00d27c4f9c92a507Bjorn Bringert
20471e0b4807797c602e7fc787d00d27c4f9c92a507Bjorn Bringert        synchronized (mStateLock) {
20571e0b4807797c602e7fc787d00d27c4f9c92a507Bjorn Bringert            if (mStopped) {
20671e0b4807797c602e7fc787d00d27c4f9c92a507Bjorn Bringert                return TextToSpeech.ERROR;
20771e0b4807797c602e7fc787d00d27c4f9c92a507Bjorn Bringert            }
2088d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath            SynthesisMessageParams params = new SynthesisMessageParams(
2098d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath                    mStreamType, sampleRateInHz, audioFormat, channelCount, mVolume, mPan,
2108d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath                    mDispatcher);
2118d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath            params.addBuffer(buffer, offset, length);
21271e0b4807797c602e7fc787d00d27c4f9c92a507Bjorn Bringert
2138d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath            mAudioTrackHandler.enqueueSynthesisCompleteDataAvailable(params);
2148d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath            mToken = params;
21571e0b4807797c602e7fc787d00d27c4f9c92a507Bjorn Bringert        }
21671e0b4807797c602e7fc787d00d27c4f9c92a507Bjorn Bringert
21771e0b4807797c602e7fc787d00d27c4f9c92a507Bjorn Bringert        return TextToSpeech.SUCCESS;
21871e0b4807797c602e7fc787d00d27c4f9c92a507Bjorn Bringert    }
21971e0b4807797c602e7fc787d00d27c4f9c92a507Bjorn Bringert
22053f6f95308854e7da1fcd15081030d7de2fc5a7fNarayan Kamath}
221