Package com.tulskiy.musique.audio.player

Source Code of com.tulskiy.musique.audio.player.BufferingThread

/*
* Copyright (c) 2008, 2009, 2010, 2011 Denis Tulskiy
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* version 3 along with this work.  If not, see <http://www.gnu.org/licenses/>.
*/

package com.tulskiy.musique.audio.player;

import java.util.logging.Logger;

import com.tulskiy.musique.audio.Decoder;
import com.tulskiy.musique.audio.player.io.Buffer;
import com.tulskiy.musique.playlist.PlaybackOrder;
import com.tulskiy.musique.playlist.Track;
import com.tulskiy.musique.playlist.TrackData;
import com.tulskiy.musique.system.Codecs;
import com.tulskiy.musique.util.AudioMath;

/**
* Author: Denis Tulskiy
* Date: 1/15/11
*/
public class BufferingThread extends Actor implements Runnable {
    private final Logger logger = Logger.getLogger(getClass().getName());
    private PlaybackOrder order;

    private final Object lock = new Object();
    private long currentByte = 0;
    private Track currentTrack;
    private Track nextTrack;
    private Decoder decoder;
    private long cueTotalBytes;
    private boolean active;

    private Buffer buffer;
    private PlayingThread playingThread;
    private boolean stopAfterCurrent = false;

    public BufferingThread(Buffer buffer, PlayingThread playingThread) {
        this.buffer = buffer;
        this.playingThread = playingThread;
    }

    @Override
    public void process(Message message) {
        Object[] params = message.getParams();
        switch (message) {
            case OPEN:
                if (params.length > 0 && params[0] instanceof Track) {
                    Track track = (Track) params[0];
                    pause(true);
                    open(track, true);
                }
                break;
            case SEEK:
                if (params.length > 0 && params[0] instanceof Long) {
                    Long sample = (Long) params[0];
                    seek(sample);
                }
                break;
            case STOP:
                stop(true);
                break;
        }
    }

    @SuppressWarnings({"InfiniteLoopStatement"})
    @Override
    public void run() {
        byte[] buf = new byte[65536];
        int len;
        while (true) {
            synchronized (lock) {
                try {
                    while (!active) {
                        lock.wait();
                    }
                    if (decoder == null) {
                        stop(false);
                        continue;
                    }

                    while (active) {
                        if (nextTrack != null) {
                            if (stopAfterCurrent) {
                                stop(false);
                                stopAfterCurrent = false;
                                continue;
                            }
                            open(nextTrack, false);
                            nextTrack = null;
                            continue;
                        }

                        len = decoder.decode(buf);

                        if (len == -1) {
                            nextTrack = null;
                            if (order != null)
                                nextTrack = order.next(currentTrack);
                            if (nextTrack == null) {
                                stop(false);
                            }
                            continue;
                        }

                        if (currentTrack.getTrackData().isCue()) {
                            if (cueTotalBytes <= currentByte + len) {
                                Track s = null;
                                if (order != null)
                                    s = order.next(currentTrack);

                                len = (int) (cueTotalBytes - currentByte);
                                if (s != null) {
                                    nextTrack = s;
                                } else {
                                    stop(false);
                                }
                            }
                        }

                        currentByte += len;

                        buffer.write(buf, 0, len);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public void stop(boolean flush) {
        logger.fine("Stop buffering");
        nextTrack = null;
        pause(flush);
        buffer.addNextTrack(null, null, -1, false);
        if (decoder != null) {
            decoder.close();
        }
        decoder = null;
    }

    private void pause(boolean flush) {
        active = false;
        if (flush)
            buffer.flush();
        synchronized (lock) {
        }
        if (flush)
            buffer.flush();
    }

    private void start() {
        active = true;
        synchronized (lock) {
            lock.notifyAll();
        }
    }

    public synchronized void open(Track track, boolean forced) {
        if (decoder != null) {
            decoder.close();
        }

        if (track != null) {
            TrackData trackData = track.getTrackData();
            logger.fine("Opening track " + trackData.getLocation());

            if (trackData.isFile() && !trackData.getFile().exists()) {
                //try to get the next one
                track = order.next(track);
                if (track == null || (
                    trackData.isFile() && !trackData.getFile().exists())) {
                    stop(false);
                    return;
                }
            }
            decoder = Codecs.getDecoder(track);
            currentTrack = track;
            currentByte = 0;

            if (decoder == null || !decoder.open(track)) {
                currentTrack = null;
                stop(false);
                return;
            }

            buffer.addNextTrack(currentTrack, decoder.getAudioFormat(), -1, forced);

            if (trackData.getStartPosition() > 0)
                decoder.seekSample(trackData.getStartPosition());
            if (trackData.getSubsongIndex() > 0) {
                cueTotalBytes = AudioMath.samplesToBytes(trackData.getTotalSamples(), decoder.getAudioFormat().getFrameSize());
            } else {
                cueTotalBytes = 0;
            }

            start();
            logger.fine("Finished opening track");
            if (forced)
                playingThread.send(Message.FLUSH);
            playingThread.send(Message.PLAY);
        }
    }

    public void seek(long sample) {
        boolean oldState = active;
        pause(true);

        if (decoder != null) {
            decoder.seekSample(currentTrack.getTrackData().getStartPosition() + sample);
            currentByte = AudioMath.samplesToBytes(sample, decoder.getAudioFormat().getFrameSize());
            buffer.addNextTrack(currentTrack, decoder.getAudioFormat(), sample, true);
            if (oldState) {
                start();
            }
        }
    }

    public PlaybackOrder getOrder() {
        return order;
    }

    public void setOrder(PlaybackOrder order) {
        this.order = order;
    }

    public boolean isActive() {
        return active;
    }

    public void setStopAfterCurrent(boolean stopAfterCurrent) {
        this.stopAfterCurrent = stopAfterCurrent;
    }
}
TOP

Related Classes of com.tulskiy.musique.audio.player.BufferingThread

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.