diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 70ec55d..2c18e07 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -34,7 +34,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL @@ -47,7 +47,7 @@ jobs: # queries: ./path/to/local/query, your-org/your-repo/queries@main - name: Set up JDK 25 - uses: actions/setup-java@v4 + uses: actions/setup-java@v5 with: java-version: '25' distribution: 'temurin' diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml index 28b1252..4d6ff20 100644 --- a/.github/workflows/maven.yml +++ b/.github/workflows/maven.yml @@ -16,14 +16,14 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Check w/o SNAPSHOT when "bump version" if: ${{ contains(github.event.head_commit.message, 'bump version') }} run: grep "" pom.xml | head -1 | grep -v SNAPSHOT - name: Set up JDK 25 - uses: actions/setup-java@v4 + uses: actions/setup-java@v5 with: java-version: '25' distribution: 'temurin' diff --git a/README.md b/README.md index 5c751fc..6f39875 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ # MP3SPI -mp3 logo🅮 fraunhofer +logo MP3 Java Sound SPI. @@ -29,12 +29,23 @@ Both are in pure Java. * `mp3spi.weak` ... boolean: to skip controls, default `false` * `mp3spi.bufferSize` ... max buffer size for parsing mp3, default 20MiB -### note +### jvm args -* when you use `AudioSystem#getInputStream(InputStream)` not for only mp3, - you should use BufferedInputStream with enough buffer size referring to `mp3spi.bufferSize` - because given InputStream has smaller buffer, spi cannot enlarge it. -* as for `AudioSystem#getInputStream(URL)`, `AudioSystem#getInputStream(File)`, buffer is set automatically +``` +--add-opens java.desktop/com.sun.media.sound=ALL-UNNAMED +--add-opens java.base/java.io=ALL-UNNAMED +--add-opens java.base/sun.nio.ch=ALL-UNNAMED +``` + +### ⚠️ note + +* when you use `AudioSystem.getAudioInputStream(InputStream)` for formats other than aac, + you should wrap the input in a `BufferedInputStream` with a sufficiently large buffer. + (see `mp3spi.bufferSize`) + this is because the provided `InputStream` often has a small internal buffer, + and the spi cannot increase it on its own. +* for `AudioSystem.getAudioInputStream(URL)` and `AudioSystem.getAudioInputStream(File)`, + the buffering is handled automatically. ## References @@ -123,4 +134,8 @@ contribution. MP3SPI is licensed under LGPL (see [LICENSE](LICENSE.txt)). ### How to specify mp3 tag's encoding - Set the system property `javazoom.spi.mpeg.encoding`. e.g `javazoom.spi.mpeg.encoding=MS932` \ No newline at end of file + Set the system property `javazoom.spi.mpeg.encoding`. e.g `javazoom.spi.mpeg.encoding=MS932` + +--- + +image designed by @umjammer, drawn by nano banana diff --git a/pom.xml b/pom.xml index cc494c1..95f4adc 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ net.javazoom mp3spi - 1.9.19 + 1.9.20 com.github.umjammer.tritonus @@ -68,6 +68,8 @@ --add-opens java.desktop/com.sun.media.sound=ALL-UNNAMED + --add-opens java.base/java.io=ALL-UNNAMED + --add-opens java.base/sun.nio.ch=ALL-UNNAMED -Djava.util.logging.config.file=${project.build.testOutputDirectory}/logging.properties -Dvavi.test.volume=@{vavi.test.volume} @@ -89,7 +91,7 @@ org.junit junit-bom - 6.0.3 + 6.1.1 pom import @@ -100,7 +102,7 @@ com.github.umjammer vavi-sound - 1.0.27 + 1.0.30 @@ -116,7 +118,7 @@ com.github.umjammer jlayer - 1.0.3 + 1.0.4 diff --git a/src/main/java/javazoom/spi/mpeg/sampled/convert/DecodedMpegAudioInputStream.java b/src/main/java/javazoom/spi/mpeg/sampled/convert/DecodedMpegAudioInputStream.java index c5b8983..49992c9 100644 --- a/src/main/java/javazoom/spi/mpeg/sampled/convert/DecodedMpegAudioInputStream.java +++ b/src/main/java/javazoom/spi/mpeg/sampled/convert/DecodedMpegAudioInputStream.java @@ -38,7 +38,7 @@ import javazoom.jl.decoder.DecoderException; import javazoom.jl.decoder.Equalizer; import javazoom.jl.decoder.Header; -import javazoom.jl.decoder.Obuffer; +import javazoom.jl.decoder.OBuffer; import javazoom.spi.PropertiesContainer; import javazoom.spi.mpeg.sampled.file.IcyListener; import javazoom.spi.mpeg.sampled.file.tag.TagParseEvent; @@ -190,7 +190,7 @@ public void execute() { m_equalizer.setBand(b, m_equalizer_values[b]); } m_decoder.setEqualizer(m_equalizer); - Obuffer decoderOutput = m_decoder.decodeFrame(header, m_bitstream); + OBuffer decoderOutput = m_decoder.decodeFrame(header, m_bitstream); m_bitstream.closeFrame(); getCircularBuffer().write(m_oBuffer.getBuffer(), 0, m_oBuffer.getCurrentBufferSize()); m_oBuffer.reset(); @@ -253,7 +253,7 @@ public void close() throws IOException { m_encodedStream.close(); } - private class DMAISObuffer extends Obuffer { + private class DMAISObuffer extends OBuffer { private int m_nChannels; @@ -265,7 +265,7 @@ private class DMAISObuffer extends Obuffer { public DMAISObuffer(int nChannels) { m_nChannels = nChannels; - m_abBuffer = new byte[OBUFFERSIZE * nChannels]; + m_abBuffer = new byte[O_BUFFER_SIZE * nChannels]; m_anBufferPointers = new int[nChannels]; reset(); m_bIsBigEndian = DecodedMpegAudioInputStream.this.isBigEndian(); diff --git a/src/test/java/javazoom/spi/mpeg/sampled/file/MpegAudioFileReaderTest.java b/src/test/java/javazoom/spi/mpeg/sampled/file/MpegAudioFileReaderTest.java index 7891fb2..bb2473b 100644 --- a/src/test/java/javazoom/spi/mpeg/sampled/file/MpegAudioFileReaderTest.java +++ b/src/test/java/javazoom/spi/mpeg/sampled/file/MpegAudioFileReaderTest.java @@ -168,18 +168,18 @@ private void dumpAudioFileFormat(AudioFileFormat baseFileFormat, String info) throws UnsupportedAudioFileException { AudioFormat baseFormat = baseFileFormat.getFormat(); // AudioFileFormat - logger.info(" ----- " + info + " -----"); - logger.info(" ByteLength=" + baseFileFormat.getByteLength()); - logger.info(" FrameLength=" + baseFileFormat.getFrameLength()); - logger.info(" Type=" + baseFileFormat.getType()); + System.err.println(" ----- " + info + " -----"); + System.err.println(" ByteLength=" + baseFileFormat.getByteLength()); + System.err.println(" FrameLength=" + baseFileFormat.getFrameLength()); + System.err.println(" Type=" + baseFileFormat.getType()); // AudioFormat - logger.info(" SourceFormat=" + baseFormat.toString()); - logger.info(" Channels=" + baseFormat.getChannels()); - logger.info(" FrameRate=" + baseFormat.getFrameRate()); - logger.info(" FrameSize=" + baseFormat.getFrameSize()); - logger.info(" SampleRate=" + baseFormat.getSampleRate()); - logger.info(" SampleSizeInBits=" + baseFormat.getSampleSizeInBits()); - logger.info(" Encoding=" + baseFormat.getEncoding()); + System.err.println(" SourceFormat=" + baseFormat.toString()); + System.err.println(" Channels=" + baseFormat.getChannels()); + System.err.println(" FrameRate=" + baseFormat.getFrameRate()); + System.err.println(" FrameSize=" + baseFormat.getFrameSize()); + System.err.println(" SampleRate=" + baseFormat.getSampleRate()); + System.err.println(" SampleSizeInBits=" + baseFormat.getSampleSizeInBits()); + System.err.println(" Encoding=" + baseFormat.getEncoding()); assertEquals(props.getProperty("Type"), baseFileFormat.getType().toString(), "Type"); assertEquals(props.getProperty("SourceFormat"), baseFormat.toString(), "SourceFormat"); assertEquals(Integer.parseInt(props.getProperty("Channels")), baseFormat.getChannels(), "Channels"); @@ -194,17 +194,17 @@ private void dumpAudioFileFormat(AudioFileFormat baseFileFormat, private void dumpAudioInputStream(AudioInputStream in, String info) throws IOException { AudioFormat baseFormat = in.getFormat(); - logger.info(" ----- " + info + " -----"); - logger.info(" Available=" + in.available()); - logger.info(" FrameLength=" + in.getFrameLength()); + System.err.println(" ----- " + info + " -----"); + System.err.println(" Available=" + in.available()); + System.err.println(" FrameLength=" + in.getFrameLength()); // AudioFormat - logger.info(" SourceFormat=" + baseFormat.toString()); - logger.info(" Channels=" + baseFormat.getChannels()); - logger.info(" FrameRate=" + baseFormat.getFrameRate()); - logger.info(" FrameSize=" + baseFormat.getFrameSize()); - logger.info(" SampleRate=" + baseFormat.getSampleRate()); - logger.info(" SampleSizeInBits=" + baseFormat.getSampleSizeInBits()); - logger.info(" Encoding=" + baseFormat.getEncoding()); + System.err.println(" SourceFormat=" + baseFormat.toString()); + System.err.println(" Channels=" + baseFormat.getChannels()); + System.err.println(" FrameRate=" + baseFormat.getFrameRate()); + System.err.println(" FrameSize=" + baseFormat.getFrameSize()); + System.err.println(" SampleRate=" + baseFormat.getSampleRate()); + System.err.println(" SampleSizeInBits=" + baseFormat.getSampleSizeInBits()); + System.err.println(" Encoding=" + baseFormat.getEncoding()); assertEquals(props.getProperty("SourceFormat"), baseFormat.toString(), "SourceFormat"); assertEquals(Integer.parseInt(props.getProperty("Channels")), baseFormat.getChannels(), "Channels"); assertEquals(Float.parseFloat(props.getProperty("FrameRate")), baseFormat.getFrameRate(), "FrameRate"); diff --git a/src/test/java/javazoom/spi/mpeg/sampled/file/PropertiesTest.java b/src/test/java/javazoom/spi/mpeg/sampled/file/PropertiesTest.java index 8cfbcd1..108cf78 100644 --- a/src/test/java/javazoom/spi/mpeg/sampled/file/PropertiesTest.java +++ b/src/test/java/javazoom/spi/mpeg/sampled/file/PropertiesTest.java @@ -3,6 +3,7 @@ import java.io.File; import java.io.InputStream; +import java.net.URI; import java.net.URL; import java.util.Map; import java.util.Properties; @@ -64,16 +65,16 @@ void testPropertiesFile() throws Exception { File file = new File(fileName); AudioFileFormat baseFileFormat = AudioSystem.getAudioFileFormat(file); AudioFormat baseFormat = baseFileFormat.getFormat(); - logger.info("-> Filename : " + fileName + " <-"); - logger.info(baseFileFormat.toString()); + System.err.println("-> Filename : " + fileName + " <-"); + System.err.println(baseFileFormat.toString()); if (baseFileFormat instanceof TAudioFileFormat) { Map properties = baseFileFormat.properties(); - logger.info(properties.toString()); + System.err.println(properties.toString()); for (String key : testPropsAFF) { String val = null; if (properties.get(key) != null) val = (properties.get(key)).toString(); - logger.info(key + "='" + val + "'"); + System.err.println(key + "='" + val + "'"); String valexpected = props.getProperty(key); assertEquals(valexpected, val, key); } @@ -87,7 +88,7 @@ void testPropertiesFile() throws Exception { String val = null; if (properties.get(key) != null) val = (properties.get(key)).toString(); - logger.info(key + "='" + val + "'"); + System.err.println(key + "='" + val + "'"); String valexpected = props.getProperty(key); assertEquals(valexpected, val, key); } @@ -107,18 +108,18 @@ void testPropertiesURL() throws Exception { String[] testPropsAF = { "vbr", "bitrate" }; - URL url = new URL(fileUrl); + URL url = URI.create(fileUrl).toURL(); AudioFileFormat baseFileFormat = AudioSystem.getAudioFileFormat(url); AudioFormat baseFormat = baseFileFormat.getFormat(); - logger.info("-> URL: " + fileName + " <-"); - logger.info(baseFileFormat.toString()); + System.err.println("-> URL: " + fileName + " <-"); + System.err.println(baseFileFormat.toString()); if (baseFileFormat instanceof TAudioFileFormat) { Map properties = baseFileFormat.properties(); for (String key : testPropsAFF) { String val = null; if (properties.get(key) != null) val = (properties.get(key)).toString(); - logger.info(key + "='" + val + "'"); + System.err.println(key + "='" + val + "'"); String valexpected = props.getProperty(key); assertEquals(valexpected, val, key); } @@ -132,7 +133,7 @@ void testPropertiesURL() throws Exception { String val = null; if (properties.get(key) != null) val = (properties.get(key)).toString(); - logger.info(key + "='" + val + "'"); + System.err.println(key + "='" + val + "'"); String valexpected = props.getProperty(key); assertEquals(valexpected, val, key); } @@ -145,18 +146,18 @@ void testPropertiesURL() throws Exception { @Disabled void testPropertiesShoutcast() throws Exception { String shoutURL = props.getProperty("shoutcast"); - URL url = new URL(shoutURL); + URL url = URI.create(shoutURL).toURL(); AudioFileFormat baseFileFormat = AudioSystem.getAudioFileFormat(url); AudioFormat baseFormat = baseFileFormat.getFormat(); - logger.info("-> URL : " + url + " <-"); - logger.info(baseFileFormat.toString()); + System.err.println("-> URL : " + url + " <-"); + System.err.println(baseFileFormat.toString()); if (baseFileFormat instanceof TAudioFileFormat) { Map properties = baseFileFormat.properties(); for (String key : properties.keySet()) { String val = null; if (properties.get(key) != null) val = (properties.get(key)).toString(); - logger.info(key + "='" + val + "'"); + System.err.println(key + "='" + val + "'"); } } else { fail("testPropertiesShoutcast: TAudioFileFormat expected"); @@ -168,7 +169,7 @@ void testPropertiesShoutcast() throws Exception { String val = null; if (properties.get(key) != null) val = (properties.get(key)).toString(); - logger.info(key + "='" + val + "'"); + System.err.println(key + "='" + val + "'"); } } else { fail("testPropertiesShoutcast: TAudioFormat expected"); @@ -180,12 +181,12 @@ void testDumpPropertiesURL() throws Exception { URL file = new URL(fileUrl); AudioFileFormat baseFileFormat = AudioSystem.getAudioFileFormat(file); AudioFormat baseFormat = baseFileFormat.getFormat(); - logger.info("-> Filename: " + fileName + " <-"); + System.err.println("-> Filename: " + fileName + " <-"); if (baseFileFormat instanceof TAudioFileFormat) { Map properties = baseFileFormat.properties(); for (String key : properties.keySet()) { String val = (properties.get(key)).toString(); - logger.info(key + "='" + val + "'"); + System.err.println(key + "='" + val + "'"); } } else { fail("testDumpPropertiesFile: TAudioFileFormat expected"); @@ -195,7 +196,7 @@ void testDumpPropertiesURL() throws Exception { Map properties = baseFormat.properties(); for (String key : properties.keySet()) { String val = (properties.get(key)).toString(); - logger.info(key + "='" + val + "'"); + System.err.println(key + "='" + val + "'"); } } else { fail("testDumpPropertiesFile: TAudioFormat expected"); diff --git a/src/test/resources/duke_mp3.png b/src/test/resources/duke_mp3.png new file mode 100644 index 0000000..6a7a8b6 Binary files /dev/null and b/src/test/resources/duke_mp3.png differ diff --git a/src/test/resources/test.mp3.properties b/src/test/resources/test.mp3.properties index 289c97d..00281f6 100644 --- a/src/test/resources/test.mp3.properties +++ b/src/test/resources/test.mp3.properties @@ -46,7 +46,7 @@ mp3.mode=0 mp3.channels=2 mp3.version.mpeg=1 mp3.framesize.bytes=622 -mp3.vbr.scale=0 +mp3.vbr.scale=-1 mp3.version.encoding=MPEG1L3 mp3.header.pos=374 mp3.version.layer=3