diff --git a/src/com/nokia/mid/sound/Sound.java b/src/com/nokia/mid/sound/Sound.java index 19426c4c..94705ec8 100644 --- a/src/com/nokia/mid/sound/Sound.java +++ b/src/com/nokia/mid/sound/Sound.java @@ -111,11 +111,12 @@ public void init(byte[] data, int type) try { if(player == null || !isPrevPlayerTone) // check for null because release() can be called after all. - { + { + if(Manager.dumpAudioStreams) { Manager.dumpAudioStream(new ByteArrayInputStream(data), "audio/x-tone-seq"); } // Dump original OTA as well player = Manager.createPlayer(new ByteArrayInputStream(convertToMidi(data)), "audio/x-tone-seq"); isPrevPlayerTone = true; } - else + else { player.deallocate(); ((ToneControl) player.getControl("ToneControl")).setSequence(convertToMidi(data)); diff --git a/src/javax/microedition/media/Manager.java b/src/javax/microedition/media/Manager.java index d270edbf..3bbd9265 100644 --- a/src/javax/microedition/media/Manager.java +++ b/src/javax/microedition/media/Manager.java @@ -40,6 +40,7 @@ public class Manager { public static final String TONE_DEVICE_LOCATOR = "device://tone"; + public static final String MIDI_DEVICE_LOCATOR = "device://midi"; /* Custom MIDI variables */ public static boolean useCustomMidi = false; @@ -64,40 +65,7 @@ public static synchronized Player createPlayer(InputStream stream, String type) * only a lot of testing will be able to determine which is preferable, or if we'd need a config toggle to alternate both. */ - if(dumpAudioStreams) - { - stream.mark(1024); - String streamMD5 = generateMD5Hash(stream, 1024); - stream.reset(); - - // Copy the stream contents into a temporary stream to be saved as file - final ByteArrayOutputStream streamCopy = new ByteArrayOutputStream(); - final byte[] copyBuffer = new byte[1024]; - int copyLength; - while ((copyLength = stream.read(copyBuffer)) > -1 ) { streamCopy.write(copyBuffer, 0, copyLength); } - streamCopy.flush(); - - // Make sure the initial stream will still be available for FreeJ2ME - stream = new ByteArrayInputStream(streamCopy.toByteArray()); - - // And save the copy to the specified dir - - OutputStream outStream; - String dumpPath = "." + File.separatorChar + "FreeJ2MEDumps" + File.separatorChar + "Audio" + File.separatorChar + Mobile.getPlatform().loader.suitename + File.separatorChar; - File dumpFile = new File(dumpPath); - - if (!dumpFile.isDirectory()) { dumpFile.mkdirs(); } - - if(type.equalsIgnoreCase("audio/x-mid") || type.equalsIgnoreCase("audio/mid") || type.equalsIgnoreCase("audio/midi") || type.equalsIgnoreCase("sp-midi") || type.equalsIgnoreCase("audio/spmidi")) - { dumpFile = new File(dumpPath + "Stream_" + streamMD5 + ".mid");} - else if(type.equalsIgnoreCase("audio/x-wav") || type.equalsIgnoreCase("audio/wav")) { dumpFile = new File(dumpPath + "Stream_" + streamMD5 + ".wav");} - else if(type.equalsIgnoreCase("audio/mpeg") || type.equalsIgnoreCase("audio/mp3")) { dumpFile = new File(dumpPath + "Stream_" + streamMD5 + ".mp3");} - else if(type.equalsIgnoreCase("audio/x-tone-seq")) { dumpFile = new File(dumpPath + "Stream_" + streamMD5 + ".mid");} // Tone Seq should arrive converted to midi - - outStream = new FileOutputStream(dumpFile); - - streamCopy.writeTo(outStream); - } + if(dumpAudioStreams) { stream = dumpAudioStream(stream, type); } return new PlatformPlayer(stream, type); } @@ -119,8 +87,17 @@ public static Player createPlayer(String locator) throws MediaException if(locator == null) { throw new IllegalArgumentException("Cannot create a player with a null locator"); } + InputStream stream = Mobile.getPlatform().loader.getResourceAsStream(locator); + + if(dumpAudioStreams && !locator.equals(Manager.TONE_DEVICE_LOCATOR) && !locator.equals(Manager.MIDI_DEVICE_LOCATOR)) + { + dumpAudioStream(stream, locator); // Using the locator, we can try find out what this is by parsing the file extension + } + Mobile.log(Mobile.LOG_WARNING, Manager.class.getPackage().getName() + "." + Manager.class.getSimpleName() + ": " + "Create Player "+locator); - return new PlatformPlayer(locator); + if(!locator.equals(Manager.TONE_DEVICE_LOCATOR) && !locator.equals(Manager.MIDI_DEVICE_LOCATOR)) { return new PlatformPlayer(stream, ""); } // Empty type, let PlatformPlayer handle it + else { return new PlatformPlayer(locator); } // If it's a dedicated locator, PlatformPlayer can handle it directly + } public static String[] getSupportedContentTypes(String protocol) @@ -177,6 +154,54 @@ public static void playTone(int note, int duration, int volume) throws MediaExce }).start(); } + public static final InputStream dumpAudioStream(InputStream stream, String type) + { + try + { + stream.mark(1024); + String streamMD5 = generateMD5Hash(stream, 1024); + stream.reset(); + + // Copy the stream contents into a temporary stream to be saved as file + final ByteArrayOutputStream streamCopy = new ByteArrayOutputStream(); + final byte[] copyBuffer = new byte[1024]; + int copyLength; + while ((copyLength = stream.read(copyBuffer)) > -1 ) { streamCopy.write(copyBuffer, 0, copyLength); } + streamCopy.flush(); + + // Make sure the initial stream will still be available for FreeJ2ME + stream = new ByteArrayInputStream(streamCopy.toByteArray()); + + // And save the copy to the specified dir + OutputStream outStream; + String dumpPath = "." + File.separatorChar + "FreeJ2MEDumps" + File.separatorChar + "Audio" + File.separatorChar + Mobile.getPlatform().loader.suitename + File.separatorChar; + File dumpFile = new File(dumpPath); + + if (!dumpFile.isDirectory()) { dumpFile.mkdirs(); } + + // TODO: Locators will break this sometimes, since file names might also contain those substrings. + if(type.toLowerCase().contains("mid") ) { dumpFile = new File(dumpPath + "Stream_" + streamMD5 + ".mid"); } + else if(type.toLowerCase().contains("wav")) { dumpFile = new File(dumpPath + "Stream_" + streamMD5 + ".wav"); } + else if(type.toLowerCase().contains("mp")) { dumpFile = new File(dumpPath + "Stream_" + streamMD5 + ".mp3"); } + else if(type.equalsIgnoreCase("audio/x-tone-seq")) + { + stream.mark(4); + byte[] data = new byte[4]; + stream.read(data); + if((data[0] == 'M' && data[1] == 'T' && data[2] == 'h' && data[3] == 'd') ) { dumpFile = new File(dumpPath + "Stream_" + streamMD5 + "_Decoded.mid"); } // Tone Seq is converted to midi, save it as "decoded" + else { dumpFile = new File(dumpPath + "Stream_" + streamMD5 + ".ota"); } // Only nokia OTA tones are going to be dumped in their original form right now. Dual Tone and MelodyComposer have no format of their own. + stream.reset(); + } + + outStream = new FileOutputStream(dumpFile); + + streamCopy.writeTo(outStream); + } + catch (Exception e) { Mobile.log(Mobile.LOG_ERROR, Manager.class.getPackage().getName() + "." + Manager.class.getSimpleName() + ": " + "Failed to dump media: " + e.getMessage()); } + + return stream; + } + private static String generateMD5Hash(InputStream stream, int byteCount) { try diff --git a/src/org/recompile/mobile/PlatformPlayer.java b/src/org/recompile/mobile/PlatformPlayer.java index 1b9dcf3c..c20f3b76 100644 --- a/src/org/recompile/mobile/PlatformPlayer.java +++ b/src/org/recompile/mobile/PlatformPlayer.java @@ -97,21 +97,12 @@ public PlatformPlayer(InputStream stream, String type) else { // Midi player will also play tones, as these are converted to midi in pretty much all cases at the moment - if(contentType.equalsIgnoreCase("audio/x-mid") || contentType.equalsIgnoreCase("audio/mid") || contentType.equalsIgnoreCase("audio/midi") || contentType.equalsIgnoreCase("sp-midi") || contentType.equalsIgnoreCase("audio/spmidi") || contentType.equalsIgnoreCase("audio/x-tone-seq")) - { - player = new midiPlayer(stream); - } - else if(contentType.equalsIgnoreCase("audio/x-wav") || contentType.equalsIgnoreCase("audio/wav")) - { - player = new wavPlayer(stream); - } - else if(contentType.equalsIgnoreCase("audio/mpeg") || contentType.equalsIgnoreCase("audio/mp3")) - { - player = new MP3Player(stream); - } + if(contentType.toLowerCase().contains("mid") || contentType.toLowerCase().contains("tone")) { player = new midiPlayer(stream); } + else if(contentType.toLowerCase().contains("wav")) { player = new wavPlayer(stream); } + else if(contentType.toLowerCase().contains("mp")) { player = new MP3Player(stream); } // MP1, MP2, MP3, MPEG, etc. No other J2ME format has those two letters in sequence. else /* If the stream doesn't have an accompanying type or its a type we don't have an explicit player for, do everything we can to try and load it */ { - Mobile.log(Mobile.LOG_WARNING, PlatformPlayer.class.getPackage().getName() + "." + PlatformPlayer.class.getSimpleName() + ": " + "Audio type <'" + contentType + "'> doesn't match any supported ones. Trying to find what it is..."); + Mobile.log(Mobile.LOG_DEBUG, PlatformPlayer.class.getPackage().getName() + "." + PlatformPlayer.class.getSimpleName() + ": " + "Audio type <'" + contentType + "'> doesn't match any supported ones. Trying to find what it is..."); try { final byte[] data = new byte[stream.available()]; @@ -119,7 +110,7 @@ else if(contentType.equalsIgnoreCase("audio/mpeg") || contentType.equalsIgnoreCa if(data.length >= 4 && data[0] == 'M' && data[1] == 'T' && data[2] == 'h' && data[3] == 'd') { - Mobile.log(Mobile.LOG_WARNING, PlatformPlayer.class.getPackage().getName() + "." + PlatformPlayer.class.getSimpleName() + ": " + "Format is MIDI!"); + Mobile.log(Mobile.LOG_DEBUG, PlatformPlayer.class.getPackage().getName() + "." + PlatformPlayer.class.getSimpleName() + ": " + "Format is MIDI!"); player = new midiPlayer(new ByteArrayInputStream(data)); contentType = "audio/mid"; } @@ -132,13 +123,13 @@ else if (data.length >= 15 && data[8] == 'Q' && data[9] == 'L' && data[10] == 'C } else if(data.length >= 4 && data[0] == 'R' && data[1] == 'I' && data[2] == 'F' && data[3] == 'F') { - Mobile.log(Mobile.LOG_WARNING, PlatformPlayer.class.getPackage().getName() + "." + PlatformPlayer.class.getSimpleName() + ": " + "Format is WAV!"); + Mobile.log(Mobile.LOG_DEBUG, PlatformPlayer.class.getPackage().getName() + "." + PlatformPlayer.class.getSimpleName() + ": " + "Format is WAV!"); player = new wavPlayer(new ByteArrayInputStream(data)); contentType = "audio/wav"; } else if(data.length >= 3 && data[0] == 'I' && data[1] == 'D' && data[2] == '3' || ((data[0] == (byte) 0xFF) && (data[1] & 0xE0) == 0xE0)) // Check for MPEG files WITH and WITHOUT the ID3 tag { - Mobile.log(Mobile.LOG_WARNING, PlatformPlayer.class.getPackage().getName() + "." + PlatformPlayer.class.getSimpleName() + ": " + "Format is MPEG!"); + Mobile.log(Mobile.LOG_DEBUG, PlatformPlayer.class.getPackage().getName() + "." + PlatformPlayer.class.getSimpleName() + ": " + "Format is MPEG!"); player = new MP3Player(new ByteArrayInputStream(data)); contentType = "audio/mpeg"; } @@ -199,7 +190,7 @@ else if(data.length >= 9 && data[0] == '#' && data[1] == '!' && data[2] == 'A' & public PlatformPlayer(String locator) { - if(locator.equals(Manager.TONE_DEVICE_LOCATOR)) + if(locator.equals(Manager.TONE_DEVICE_LOCATOR) || locator.equals(Manager.MIDI_DEVICE_LOCATOR)) { player = new midiPlayer(); listeners = new Vector();