/*
 * Copyright (C) 2011 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.content.Context;
import android.media.AudioSystem;
import android.media.MediaPlayer;
import android.net.Uri;
import android.os.ConditionVariable;
import android.speech.tts.TextToSpeechService.AudioOutputParams;
import android.speech.tts.TextToSpeechService.UtteranceProgressDispatcher;
import android.util.Log;

class AudioPlaybackQueueItem extends PlaybackQueueItem {
    private static final String TAG = "TTS.AudioQueueItem";

    private final Context mContext;
    private final Uri mUri;
    private final AudioOutputParams mAudioParams;

    private final ConditionVariable mDone;
    private MediaPlayer mPlayer;
    private volatile boolean mFinished;

    AudioPlaybackQueueItem(UtteranceProgressDispatcher dispatcher,
            Object callerIdentity,
            Context context, Uri uri, AudioOutputParams audioParams) {
        super(dispatcher, callerIdentity);

        mContext = context;
        mUri = uri;
        mAudioParams = audioParams;

        mDone = new ConditionVariable();
        mPlayer = null;
        mFinished = false;
    }
    @Override
    public void run() {
        final UtteranceProgressDispatcher dispatcher = getDispatcher();

        dispatcher.dispatchOnStart();

        int sessionId = mAudioParams.mSessionId;
        mPlayer = MediaPlayer.create(
                mContext, mUri, null, mAudioParams.mAudioAttributes,
                sessionId > 0 ? sessionId : AudioSystem.AUDIO_SESSION_ALLOCATE);
        if (mPlayer == null) {
            dispatcher.dispatchOnError(TextToSpeech.ERROR_OUTPUT);
            return;
        }

        try {
            mPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() {
                @Override
                public boolean onError(MediaPlayer mp, int what, int extra) {
                    Log.w(TAG, "Audio playback error: " + what + ", " + extra);
                    mDone.open();
                    return true;
                }
            });
            mPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
                @Override
                public void onCompletion(MediaPlayer mp) {
                    mFinished = true;
                    mDone.open();
                }
            });

            setupVolume(mPlayer, mAudioParams.mVolume, mAudioParams.mPan);
            mPlayer.start();
            mDone.block();
            finish();
        } catch (IllegalArgumentException ex) {
            Log.w(TAG, "MediaPlayer failed", ex);
            mDone.open();
        }

        if (mFinished) {
            dispatcher.dispatchOnSuccess();
        } else {
            dispatcher.dispatchOnStop();
        }
    }

    private static void setupVolume(MediaPlayer player, float volume, float pan) {
        final float vol = clip(volume, 0.0f, 1.0f);
        final float panning = clip(pan, -1.0f, 1.0f);

        float volLeft = vol, volRight = vol;
        if (panning > 0.0f) {
            volLeft *= (1.0f - panning);
        } else if (panning < 0.0f) {
            volRight *= (1.0f + panning);
        }
        player.setVolume(volLeft, volRight);
    }

    private static final float clip(float value, float min, float max) {
        return value < min ? min : (value < max ? value : max);
    }

    private void finish() {
        try {
            mPlayer.stop();
        } catch (IllegalStateException ex) {
            // Do nothing, the player is already stopped
        }
        mPlayer.release();
    }

    @Override
    void stop(int errorCode) {
        mDone.open();
    }
}
