AudioPlaybackQueueItem.java revision 672695e42387a024083d198f3d665f354ef1d27c
1/*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5 * use this file except in compliance with the License. You may obtain a copy of
6 * the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 * License for the specific language governing permissions and limitations under
14 * the License.
15 */
16package android.speech.tts;
17
18import android.content.Context;
19import android.media.AudioSystem;
20import android.media.AudioTrack;
21import android.media.MediaPlayer;
22import android.net.Uri;
23import android.os.ConditionVariable;
24import android.speech.tts.TextToSpeechService.AudioOutputParams;
25import android.speech.tts.TextToSpeechService.UtteranceProgressDispatcher;
26import android.util.Log;
27
28class AudioPlaybackQueueItem extends PlaybackQueueItem {
29    private static final String TAG = "TTS.AudioQueueItem";
30
31    private final Context mContext;
32    private final Uri mUri;
33    private final AudioOutputParams mAudioParams;
34
35    private final ConditionVariable mDone;
36    private MediaPlayer mPlayer;
37    private volatile boolean mFinished;
38
39    AudioPlaybackQueueItem(UtteranceProgressDispatcher dispatcher,
40            Object callerIdentity,
41            Context context, Uri uri, AudioOutputParams audioParams) {
42        super(dispatcher, callerIdentity);
43
44        mContext = context;
45        mUri = uri;
46        mAudioParams = audioParams;
47
48        mDone = new ConditionVariable();
49        mPlayer = null;
50        mFinished = false;
51    }
52    @Override
53    public void run() {
54        final UtteranceProgressDispatcher dispatcher = getDispatcher();
55
56        dispatcher.dispatchOnStart();
57
58        int sessionId = mAudioParams.mSessionId;
59        mPlayer = MediaPlayer.create(
60                mContext, mUri, null, mAudioParams.mAudioAttributes,
61                sessionId > 0 ? sessionId : AudioSystem.AUDIO_SESSION_ALLOCATE);
62        if (mPlayer == null) {
63            dispatcher.dispatchOnError(TextToSpeech.ERROR_OUTPUT);
64            return;
65        }
66
67        try {
68            mPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() {
69                @Override
70                public boolean onError(MediaPlayer mp, int what, int extra) {
71                    Log.w(TAG, "Audio playback error: " + what + ", " + extra);
72                    mDone.open();
73                    return true;
74                }
75            });
76            mPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
77                @Override
78                public void onCompletion(MediaPlayer mp) {
79                    mFinished = true;
80                    mDone.open();
81                }
82            });
83
84            setupVolume(mPlayer, mAudioParams.mVolume, mAudioParams.mPan);
85            mPlayer.start();
86            mDone.block();
87            finish();
88        } catch (IllegalArgumentException ex) {
89            Log.w(TAG, "MediaPlayer failed", ex);
90            mDone.open();
91        }
92
93        if (mFinished) {
94            dispatcher.dispatchOnSuccess();
95        } else {
96            dispatcher.dispatchOnStop();
97        }
98    }
99
100    private static void setupVolume(MediaPlayer player, float volume, float pan) {
101        final float vol = clip(volume, 0.0f, 1.0f);
102        final float panning = clip(pan, -1.0f, 1.0f);
103
104        float volLeft = vol, volRight = vol;
105        if (panning > 0.0f) {
106            volLeft *= (1.0f - panning);
107        } else if (panning < 0.0f) {
108            volRight *= (1.0f + panning);
109        }
110        player.setVolume(volLeft, volRight);
111    }
112
113    private static final float clip(float value, float min, float max) {
114        return value < min ? min : (value < max ? value : max);
115    }
116
117    private void finish() {
118        try {
119            mPlayer.stop();
120        } catch (IllegalStateException ex) {
121            // Do nothing, the player is already stopped
122        }
123        mPlayer.release();
124    }
125
126    @Override
127    void stop(int errorCode) {
128        mDone.open();
129    }
130}
131