First off let me say hello! I'm new to the forums and was happy to see there is a community built around what has slowly become one of my favorite programming languages! I'm sure I will be back here time and time again .
Anyway I've been programming for probably close to 10 years now and have learned my fair share of languages (crappy and good alike). I didn't start with Java until about 2 years ago, as it was the main topic of my first two years of college Comp Sci classes. Anyway I've grown to love it, and recently started programming OpenGL with Java via the LWJGL (which I find quite nice). Anyway all of this is beside the point of the post, just a little get to know me rather... now back on track...
I don't know a whole lot about audio encoding and decoding, but I know that Java doesn't have much native support for different encoded files. So this morning I turned to 3rd party libraries to help me play all my audio files (I'm pretty sure all of them are either mp3 or m4a). A little bit of research showed me that m4a is essentially the same thing as a mp4 file. Anyway I downloaded and used the jl1.0.jar file to write a class that will play mp3 files, no problems there and it was pretty easy. Then I found JAAD (Java Advanced Audio Decoder?) for decoding AAC files, again more research will tell me that the *.m4a files fall into the AAC category (if I'm not missing something here). Keep in mind that my *.m4a files are just Audio and no Video mp4 files. So looking through the example code for JAAD I notice it has two methods of playing AAC files, the first (decodeMP4) seems to me to play a video/audio mp4 file, and the second (decodeAAC) seems to be just for audio (below is the code in question).
private static void decodeMP4(String in) throws Exception { SourceDataLine line = null; byte[] b; try { //create container final MP4Container cont = new MP4Container(new RandomAccessFile(in, "r")); final Movie movie = cont.getMovie(); //find AAC track final List<Track> tracks = movie.getTracks(AudioTrack.AudioCodec.AAC); if(tracks.isEmpty()) throw new Exception("movie does not contain any AAC track"); final AudioTrack track = (AudioTrack) tracks.get(0); //create audio format final AudioFormat aufmt = new AudioFormat(track.getSampleRate(), track.getSampleSize(), track.getChannelCount(), true, true); line = AudioSystem.getSourceDataLine(aufmt); line.open(); line.start(); //create AAC decoder final Decoder dec = new Decoder(track.getDecoderSpecificInfo()); //decode Frame frame; final SampleBuffer buf = new SampleBuffer(); while(track.hasMoreFrames()) { frame = track.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(); } } } private static void decodeAAC(String in) throws Exception { SourceDataLine line = null; byte[] b; try { final ADTSDemultiplexer adts = new ADTSDemultiplexer(new FileInputStream(in)); final Decoder dec = new Decoder(adts.getDecoderSpecificInfo()); final SampleBuffer buf = new SampleBuffer(); while(true) { b = adts.readNextFrame(); dec.decodeFrame(b, buf); if(line==null) { final AudioFormat aufmt = new AudioFormat(buf.getSampleRate(), buf.getBitsPerSample(), buf.getChannels(), true, true); line = AudioSystem.getSourceDataLine(aufmt); line.open(); line.start(); } b = buf.getData(); line.write(b, 0, b.length); } } finally { if(line!=null) { line.stop(); line.close(); } } }
So what I did was essentially take the code from decodeAAC and modify it ever so slightly and plug it into my own class. Then I gave it a whirl with a few different audio .m4a files, but they all return the same IOException: "java.io.IOException: no ADTS header found". Again I have very little knowledge of music encoding / decoding so I googled a bit and am still confused as to why it can't find the header info. I assume this means it's not there... but why would it not be there? It is after all an AAC encoded file? Just to make sure the file wasn't improperly labeled I took a look at the properties and sure enough the section labeled "Codec: " reads "MPEG-4 AAC audio". So now I'm stumped so I hope you guys can help out a bit and at least clear up some of the uncertainties. Below is my code, it's pretty simple, right now it's just supposed to play a file which is in "./Music/". Thanks for any help.
import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import javax.sound.sampled.AudioFormat; import javax.sound.sampled.AudioSystem; import javax.sound.sampled.LineUnavailableException; import javax.sound.sampled.SourceDataLine; import net.sourceforge.jaad.aac.Decoder; import net.sourceforge.jaad.aac.SampleBuffer; import net.sourceforge.jaad.adts.ADTSDemultiplexer; /** * @author howard * */ public class Mp4 { private static String fileName = "Music/Krytonite.m4a"; public Mp4(String file) { // If we have specified a file, set the fileName variable if (!file.equals("")) { fileName = file; } SourceDataLine line = null; byte[] b; try { ADTSDemultiplexer adts = new ADTSDemultiplexer(new FileInputStream( fileName)); Decoder dec = new Decoder(adts.getDecoderSpecificInfo()); SampleBuffer buf = new SampleBuffer(); while ((b = adts.readNextFrame()) != null) { dec.decodeFrame(b, buf); if (line == null) { AudioFormat aufmt = new AudioFormat(buf.getSampleRate(), buf.getBitsPerSample(), buf.getChannels(), true, true); line = AudioSystem.getSourceDataLine(aufmt); line.open(); line.start(); } b = buf.getData(); line.write(b, 0, b.length); } } catch (FileNotFoundException e) { System.out.println("Failed to load file: " + fileName); e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (LineUnavailableException e) { System.out.println("Failed to grab audio line!"); e.printStackTrace(); } finally { if (line != null) { line.stop(); line.close(); } } } /** * @param args */ public static void main(String[] args) { new Mp4(fileName); } }