Playing streamed mp3 data repeatedly with jlayer
Asked Answered
F

0

1

I am working on an mp3 streaming application in Java. The user at the server end plays a music file at the server end (although the server is just currently sending the file) and the player at the client end reads the stream and plays the music. I'm using JLayer to play the music file. The server sends the files in chunks and also receives the file in chunks and plays it. I'm using jgroups library for group membership management as I plan to scale the application to be used by many clients. Here is what I have tried so far:

import javazoom.jl.decoder.JavaLayerException;
import javazoom.jl.player.Player;
import org.apache.commons.io.input.CountingInputStream;
import org.jgroups.*;
import org.jgroups.conf.ClassConfigurator;
import org.jgroups.util.Util;

import java.io.*;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * Created by Xabush on 1/25/2016 21:43.
 * Project: DSP_Java
 */
public class SimpleMPlayer extends ReceiverAdapter {

    private CountingInputStream in;
    private Player player;
    private String filename;
    protected File file;
    protected int offest = 0;
    protected JChannel channel;
    protected int frames;
    protected boolean isServer = true;
    protected Map<String, OutputStream> files = new ConcurrentHashMap<String, OutputStream>();
    protected static final short ID = 3500;

    public SimpleMPlayer(String filename) throws IOException, JavaLayerException {
        this.filename = filename;
        file = new File(this.filename);
        in = new CountingInputStream(new FileInputStream(filename));
        player = new Player(new FileInputStream("src/np/test.mp3"));
    }

    public void start(String name) throws Exception {
        ClassConfigurator.add((short) 3500, FileHeader.class);
        channel = new JChannel("src/jgroups/fast.xml").name(name);
        channel.setReceiver(this);
        channel.connect("File_Cluster");
        if (isServer)
            eventLoop();
    }

    private void eventLoop() throws Exception {
        Util.keyPress(String.format("<enter to send %s>\n", file.getName()));
        sendFile();

        System.out.print("Finished sending file");

    }

    protected void sendFile() throws Exception {
        try {
            int read = 0;
            while (read != -1) {
                byte[] buff = new byte[2304];
                read = in.read(buff);
                offest += in.getByteCount();
                frames += 1;
                sendMessage(buff, 0, buff.length, false, frames);
            }

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            sendMessage(null, 0, 0, true, frames);
        }
    }

    protected void sendMessage(byte[] buf, int offset, int length, boolean eof, int fr) throws Exception {
        Message msg = new Message(null, buf, offset, length).putHeader(ID, new FileHeader(filename, eof, fr));
        // set this if the sender doesn't want to receive the file
        msg.setTransientFlag(Message.TransientFlag.DONT_LOOPBACK);
        channel.send(msg);
    }

    public void receive(Message msg) {
        byte[] buf = msg.getRawBuffer();
        FileHeader hdr = (FileHeader) msg.getHeader(ID);
        if (hdr == null)
            return;
        OutputStream out = files.get(hdr.filename);
        int frame = hdr.frame;
        try {
            if (out == null) {
                File tmp = new File(hdr.filename);
                String fname = tmp.getName();
                fname = "src/np/" + fname;
                out = new FileOutputStream(fname);
                files.put(hdr.filename, out);

            }
            if (hdr.eof) {
                Util.close(files.remove(hdr.filename));
            } else {
                out.write(msg.getRawBuffer(), msg.getOffset(), msg.getLength());
                playFromStream(frame);
            }

        } catch (Throwable t) {
            System.err.println(t);
        }
    }

    public void playFromStream(int fr) throws IOException {
        try {
            player.play(fr);
        } catch (JavaLayerException e) {
            player.close();
            e.printStackTrace();
        }

    }

    public boolean isServer() {
        return isServer;
    }

    public void setServer(boolean server) {
        isServer = server;
    }

    protected static class FileHeader extends Header {
        protected String filename;
        protected boolean eof;
        protected int frame;

        public FileHeader() {
        } // for de-serialization

        public FileHeader(String filename, boolean eof, int fr) {
            this.filename = filename;
            this.eof = eof;
            this.frame = fr;
        }

        public int size() {
            return Util.size(filename) + Global.BYTE_SIZE;
        }

        public void writeTo(DataOutput out) throws Exception {
            Util.writeObject(filename, out);
            out.writeBoolean(eof);
            out.writeInt(frame);
        }

        public void readFrom(DataInput in) throws Exception {
            filename = (String) Util.readObject(in);
            eof = in.readBoolean();
            frame = in.readInt();
        }
    }

    public static void main(String[] args) throws Exception {
        SimpleMPlayer mplayer = new SimpleMPlayer("src/jgroups/test.mp3"); // name and file

        if (args[0].equalsIgnoreCase("server")) {
            mplayer.setServer(true);
        } else {
            mplayer.setServer(false);
        }
        mplayer.start("MusicChannel");
    }
}

With my current implementation, the player plays only one frame but I want it to play the whole mp3 file as it is received. What am I doing wrong here? How can I synchronize the server and the client so that the client plays the whole stream as soon as it receives the file? Any suggestions are welcome.

Forsook answered 2/2, 2016 at 15:20 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.