Player.java

// SPDX-License-Identifier: Apache-2.0
package com.shengzhiai.yugu.stcompat.internal;

import android.media.MediaPlayer;

/** Plays a recording with {@link MediaPlayer}. All methods must be called on the main thread. */
public final class Player {
    /** Playback events, called on the main thread. */
    public interface Events {
        void onStart();

        void onFail(String reason);

        void onEnd();
    }

    private MediaPlayer player;
    private Events events;

    public boolean isPlaying() {
        return player != null;
    }

    public void play(String path, Events e) {
        stop(false);
        if (path == null || path.isEmpty()) {
            if (e != null) {
                e.onFail("no audio file to play");
            }
            return;
        }
        final MediaPlayer mp = new MediaPlayer();
        player = mp;
        events = e;
        mp.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
            @Override
            public void onCompletion(MediaPlayer m) {
                if (player == mp) {
                    finish(true);
                }
            }
        });
        mp.setOnErrorListener(new MediaPlayer.OnErrorListener() {
            @Override
            public boolean onError(MediaPlayer m, int what, int extra) {
                if (player == mp) {
                    Events ev = events;
                    release();
                    if (ev != null) {
                        ev.onFail("playback error " + what + "/" + extra);
                    }
                }
                return true;
            }
        });
        try {
            mp.setDataSource(path);
            mp.prepare();
            mp.start();
        } catch (Exception ex) {
            release();
            if (e != null) {
                e.onFail("cannot play " + path + ": " + ex.getMessage());
            }
            return;
        }
        if (e != null) {
            e.onStart();
        }
    }

    /** Stops playback; {@code notify} reports onEnd for a playback that was running. */
    public void stop(boolean notify) {
        if (player == null) {
            return;
        }
        finish(notify);
    }

    private void finish(boolean notify) {
        Events ev = events;
        release();
        if (notify && ev != null) {
            ev.onEnd();
        }
    }

    private void release() {
        MediaPlayer mp = player;
        player = null;
        events = null;
        if (mp != null) {
            try {
                mp.stop();
            } catch (IllegalStateException ignored) {
                // not started
            }
            mp.release();
        }
    }
}