You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Kotlin/Java中获取网络链接音频文件时长?解决UnsupportedAudioFileException异常

解决Java/Kotlin中AudioSystem不支持MP3/MP4格式的问题

哈哈,这个坑我踩过!你遇到的UnsupportedAudioFileException根本不是MP3/MP4格式的问题——而是Java标准库的AudioSystem天生就不支持这些受专利保护的音频格式。

为什么会报错?

JDK自带的音频API只原生支持WAV、AU、AIFF这类无专利的开源格式。MP3和MP4因为历史上的专利授权限制,Oracle并没有将它们的解码器打包进JDK标准库,所以直接调用AudioSystem.getAudioInputStream()处理MP3/MP4时,必然会抛出格式不支持的异常。

解决方案

下面给你几种实用的解决思路,根据你的项目需求选择即可:

方案1:用JLayer处理MP3(轻量专用)

JLayer是一个成熟的开源MP3解码库,专门针对MP3格式,依赖小、用法简单。

首先添加依赖(以Maven为例):

<dependency>
    <groupId>javazoom</groupId>
    <artifactId>jlayer</artifactId>
    <version>1.0.1</version>
</dependency>

然后用Kotlin代码获取MP3时长:

import javazoom.jl.player.advanced.AdvancedPlayer
import javazoom.jl.player.advanced.PlaybackEvent
import javazoom.jl.player.advanced.PlaybackListener
import java.net.URL

fun getMp3Duration(url: String): Double {
    var durationSeconds = 0.0
    val urlObj = URL(url)
    
    // 初始化播放器,仅用于获取元数据
    val player = AdvancedPlayer(urlObj.openStream())
    player.setPlayBackListener(object : PlaybackListener() {
        override fun playbackStarted(event: PlaybackEvent?) {
            event?.source?.player?.let {
                durationSeconds = it.mpegAudioDecoder.streamLengthInSeconds.toDouble()
            }
        }
    })
    
    // 播放1帧即可触发元数据加载,不需要完整播放
    try {
        player.play(0, 1)
    } catch (e: Exception) {
        // 捕获播放1帧时的正常终止异常
    } finally {
        player.close()
    }
    
    return durationSeconds
}

// 使用示例
fun main() {
    val url = "https://cdn.bandithemepark.net/lindburgh/HyperionHal.mp3"
    val duration = getMp3Duration(url)
    val lengthTicks = duration * 20
    println("时长(秒):$duration,Ticks:$lengthTicks")
}

方案2:用JavaFX Media API支持多格式(MP3/MP4通用)

如果你的项目可以引入JavaFX模块,那Media API是更优选择——它原生支持MP3、MP4、WAV等多种常见音频格式,获取时长的代码更简洁。

注意:JDK 11及以上版本中JavaFX是单独模块,需要单独添加依赖(以Maven为例):

<dependency>
    <groupId>org.openjfx</groupId>
    <artifactId>javafx-media</artifactId>
    <version>21.0.1</version>
    <classifier>linux</classifier> <!-- 根据你的系统替换:win/mac -->
</dependency>

对应的Kotlin代码:

import javafx.scene.media.Media
import javafx.scene.media.MediaPlayer
import java.net.URL

fun getAudioDuration(url: String): Double {
    val mediaUrl = URL(url).toExternalForm()
    val media = Media(mediaUrl)
    
    // 等待元数据加载完成(JavaFX媒体对象是异步加载的)
    val duration = if (media.duration.isUnknown) {
        // 同步等待加载完成,实际项目中建议用异步回调
        Thread.sleep(1000)
        media.duration.toSeconds()
    } else {
        media.duration.toSeconds()
    }
    
    // 释放资源
    MediaPlayer(media).dispose()
    return duration
}

方案3:用Apache Tika解析通用音频元数据

如果你需要处理多种音频格式(不止MP3/MP4),Apache Tika可以解析几乎所有常见媒体文件的元数据,包括时长。不过它的依赖相对较重,适合需要全面格式支持的场景。

添加Maven依赖:

<dependency>
    <groupId>org.apache.tika</groupId>
    <artifactId>tika-core</artifactId>
    <version>2.9.1</version>
</dependency>
<dependency>
    <groupId>org.apache.tika</groupId>
    <artifactId>tika-parsers-standard-package</artifactId>
    <version>2.9.1</version>
</dependency>

Kotlin代码示例:

import org.apache.tika.metadata.Metadata
import org.apache.tika.parser.ParseContext
import org.apache.tika.parser.audio.AudioParser
import java.io.InputStream
import java.net.URL

fun getAudioDurationWithTika(url: String): Double {
    val metadata = Metadata()
    val inputStream: InputStream = URL(url).openStream()
    
    try {
        val parser = AudioParser()
        parser.parse(inputStream, null, metadata, ParseContext())
        // 从元数据中获取时长(单位:秒)
        val durationStr = metadata.get("xmpDM:duration")
        return durationStr?.toDouble() ?: 0.0
    } finally {
        inputStream.close()
    }
}

注意事项

  • 所有方案都要处理网络异常(比如链接失效、超时)和文件损坏的情况,记得添加try-catch块。
  • 如果是Android项目,建议使用Android自带的MediaMetadataRetriever类,比上面的方案更适配移动端。

内容的提问来源于stack exchange,提问作者PartyPlanet

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.29 18:42:44