Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/codeql-analysis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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'
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/maven.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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 "<version>" 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'
Expand Down
29 changes: 22 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

# MP3SPI

<img alt="mp3 logo" src="https://github.com/umjammer/mp3spi/assets/493908/b718b78d-15c6-4356-a5ca-fca63ad7ffcb" width=160 /><sub><a href="https://www.iis.fraunhofer.de/de/ff/amm/unterhaltungselektronik/mp3.html">馃叜 fraunhofer</a></sub>
<img alt="logo" src="src/test/resources/duke_mp3.png" width=160 />

MP3 Java Sound SPI.

Expand All @@ -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

Expand Down Expand Up @@ -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`
Set the system property `javazoom.spi.mpeg.encoding`. e.g `javazoom.spi.mpeg.encoding=MS932`

---

<sub>image designed by @umjammer, drawn by nano banana</sub>
10 changes: 6 additions & 4 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

<groupId>net.javazoom</groupId>
<artifactId>mp3spi</artifactId>
<version>1.9.19</version>
<version>1.9.20</version>

<properties>
<tritonus.groupId>com.github.umjammer.tritonus</tritonus.groupId> <!-- org.tritonus / com.github.umjammer.tritonus -->
Expand Down Expand Up @@ -68,6 +68,8 @@
<configuration>
<argLine>
--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}
</argLine>
Expand All @@ -89,7 +91,7 @@
<dependency>
<groupId>org.junit</groupId>
<artifactId>junit-bom</artifactId>
<version>6.0.3</version>
<version>6.1.1</version>
<type>pom</type>
<scope>import</scope>
</dependency>
Expand All @@ -100,7 +102,7 @@
<dependency>
<groupId>com.github.umjammer</groupId> <!-- vavi / com.github.umjammer -->
<artifactId>vavi-sound</artifactId>
<version>1.0.27</version>
<version>1.0.30</version>
</dependency>

<dependency>
Expand All @@ -116,7 +118,7 @@
<dependency>
<groupId>com.github.umjammer</groupId> <!-- net.javazoom:jlayer / com.github.umjammer -->
<artifactId>jlayer</artifactId>
<version>1.0.3</version>
<version>1.0.4</version>
</dependency>

<dependency>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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;

Expand All @@ -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();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand All @@ -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");
Expand Down
37 changes: 19 additions & 18 deletions src/test/java/javazoom/spi/mpeg/sampled/file/PropertiesTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
}
Expand All @@ -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);
}
Expand All @@ -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<String, ?> 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);
}
Expand All @@ -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);
}
Expand All @@ -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<String, ?> 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");
Expand All @@ -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");
Expand All @@ -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<String, ?> 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");
Expand All @@ -195,7 +196,7 @@ void testDumpPropertiesURL() throws Exception {
Map<String, ?> 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");
Expand Down
Binary file added src/test/resources/duke_mp3.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion src/test/resources/test.mp3.properties
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Loading