package controller.soundEngine.lib;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.net.URLConnection;
import java.nio.file.Files;
import java.util.List;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.FloatControl;
import javax.sound.sampled.SourceDataLine;
import model.Track;
import net.sourceforge.jaad.aac.AACException;
import net.sourceforge.jaad.aac.Decoder;
import net.sourceforge.jaad.aac.SampleBuffer;
import net.sourceforge.jaad.mp4.MP4Container;
import net.sourceforge.jaad.mp4.api.AudioTrack;
import net.sourceforge.jaad.mp4.api.Frame;
import net.sourceforge.jaad.mp4.api.Movie;
import controller.interfaces.JukeboxChangedTrackListener;
import controller.listener.AudioPositionListener;
import controller.soundEngine.Player;
import controller.soundEngine.PlayerAbstractionLayer;
public class M4A extends Player {
private Thread locationThread = null;
AudioTrack audioTrack;
SourceDataLine line = null;
int curSec=0;
int secOffset=0;
public M4A(JukeboxChangedTrackListener l, AudioPositionListener p, PlayerAbstractionLayer master) {
super(l, p, master);
this.locationThread = new Thread(new Runnable() {
public void run() {
while (true) {
updateLocation();
try {
Thread.sleep(1000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
}
@Override
public boolean playTrack(Track t, int volume) {
final String path = t.getPath().toString();
curSec=0;
secOffset=0;
try {
new Thread(){
public void run() {try {
decodeMP4(path);
} catch (Exception e) {
e.printStackTrace();
}};
}.start();
} catch (Exception e) {
e.printStackTrace();
}
locationThread.start();
return false;
}
@Override
public void setVolume(int percent) {
FloatControl volume = (FloatControl) line
.getControl(FloatControl.Type.MASTER_GAIN);
float max = volume.getMaximum();
float min = volume.getMinimum();
float range = 0;
if (max < 0) {
range = Math.abs(min) - Math.abs(max);
} else {
if (min >= 0) {
range = max - min;
} else {
range = Math.abs(min) + max;
}
}
float value = percent * range / 100F;
volume.setValue(min + value);
}
@Override
public void seek(int sec) {
audioTrack.seek(sec);
long pos = line.getMicrosecondPosition();
secOffset=sec - (int) ((pos - (pos % 1000000)) / 1000000);
updateLocation();
}
@Override
public void resume() {
line.start();
}
@Override
public void stop() {
line.stop();
line.close();
}
@Override
public void pause() {
line.stop();
}
@Override
public void play() {
line.start();
}
private void updateLocation() {
long pos = line.getMicrosecondPosition();
curSec= (int) ((pos - (pos % 1000000)) / 1000000);
System.out.println("cursec: "+curSec);
System.out.println("secOffset: "+secOffset);
int intPos = curSec+secOffset;
tweetAudioPosition(intPos);
System.out.println("################");
}
@Override
public boolean canPlay(Track t) {
File f = t.getPath().toFile();
String mimeType="";
try {
mimeType = Files.probeContentType(t.getPath());
} catch (IOException e) {
e.printStackTrace();
return false;
}
URLConnection.guessContentTypeFromName(f.getName());
if(mimeType.equals("audio/mp4")){
return true;
}else {
return false;
}
}
private void decodeMP4(String in) throws Exception {
byte[] b;
try {
//create container
final MP4Container cont = new MP4Container(new RandomAccessFile(in, "r"));
final Movie movie = cont.getMovie();
//find AAC track
List<net.sourceforge.jaad.mp4.api.Track> tracks = movie.getTracks(AudioTrack.AudioCodec.AAC);
if(tracks.isEmpty()) throw new Exception("movie does not contain any AAC track");
audioTrack = (AudioTrack) tracks.get(0);
//create audio format
final AudioFormat aufmt = new AudioFormat(audioTrack.getSampleRate(), audioTrack.getSampleSize(), audioTrack.getChannelCount(), true, true);
line = AudioSystem.getSourceDataLine(aufmt);
// InputStream is = new FileInputStream(new File(in));
// is = new BufferedInputStream(is);
line.open();
line.start();
// locationThread.start();
//create AAC decoder
Decoder dec = new Decoder(audioTrack.getDecoderSpecificInfo());
//decode
Frame frame;
SampleBuffer buf = new SampleBuffer();
while(audioTrack.hasMoreFrames()) {
frame = audioTrack.readNextFrame();
try {
dec.decodeFrame(frame.getData(), buf);
b = buf.getData();
line.write(b, 0, b.length);
}
catch(AACException e) {
e.printStackTrace();
//since the frames are separate, decoding can continue if one fails
}
}
}
finally {
if(line!=null) {
line.stop();
line.close();
}
}
}
}