package net.yak.kiwi;

import android.media.AudioFormat;
import android.media.AudioTrack;

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;

public class Speaker extends RunStoppable implements RadioSink {

    private AudioTrack track = null;
    private int rate;
    public Speaker(int rate) {
        this.rate = rate;
    }

    void startPlayer() {
        log.info("Speaker: starting player.");

        // NEW API:
        int bufferSize = AudioTrack.getMinBufferSize(
                rate,
                AudioFormat.CHANNEL_OUT_MONO,
                AudioFormat.ENCODING_PCM_16BIT);

        track = new AudioTrack.Builder()  // API 23
                .setAudioFormat(new AudioFormat.Builder()  // API 21
                        .setEncoding(AudioFormat.ENCODING_PCM_16BIT)
                        .setSampleRate(rate)
                        .setChannelMask(AudioFormat.CHANNEL_OUT_MONO)
                        .build())
                .setBufferSizeInBytes(bufferSize)   // API 23
                .build();  // API 23

        // OLD API:
//        track = new AudioTrack(
//                AudioManager.STREAM_MUSIC,
//                8000, // SAMPLE_RATE,
//                AudioFormat.CHANNEL_CONFIGURATION_MONO,
//                AudioFormat.ENCODING_PCM_16BIT,
//                bufferSize,
//                AudioTrack.MODE_STREAM);

        android.os.Process.setThreadPriority(
                android.os.Process.THREAD_PRIORITY_URGENT_AUDIO);
        track.play();

        log.info("Speaker: player started.");
    }

    void stopPlayer() {
        log.info("Speaker: stopping player.");
        if (track != null) {
            track.stop();
            track.release();
            track = null;
        }
        log.info("Speaker: player stopped.");
    }

    BlockingQueue<short[]> queue = new LinkedBlockingQueue<>();

    @Override
    public void run() {
        startPlayer();
        try {
            short[] buf = null;
            while (true) {
                try {
                    buf = queue.poll(1, TimeUnit.SECONDS);
                } catch (InterruptedException ie) {
                    // ignore interrupt
                }
                if (getStopping()) break;
                if (buf != null) {
                    if (buf.length == 0) break;

                    track.write(buf, 0, buf.length);
                }
            }

        } catch (Exception ex) {
            log.error("Exception during Speaker: " + ex);
        } finally {
            stopPlayer();
        }
    }

    @Override
    public void addAudio(short[] buf) {
        queue.add(buf);
    }
}
