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

Java游戏声音引擎报错ClassCastException:DirectClip无法转为SourceDataLine

声音引擎开发中的ClassCastException问题分析

我正在为游戏开发新的声音引擎以替换性能不佳的旧引擎,采用SourceDataLine进行开发,但运行时抛出如下异常:

java.lang.ClassCastException: com.sun.media.sound.DirectAudioDevice$DirectClip cannot be cast to javax.sound.sampled.SourceDataLine
        at com.glowiak.aws.SoundLibrary.play(Main.java:1360)
        at com.glowiak.aws.UIButton.loop(Main.java:475)
        at com.glowiak.aws.Renderer.paintComponent(Main.java:174)
        at javax.swing.JComponent.paint(JComponent.java:1056)
        at javax.swing.JComponent.paintToOffscreen(JComponent.java:5210)
        at javax.swing.BufferStrategyPaintManager.paint(BufferStrategyPaintManager.java:290)
        at javax.swing.RepaintManager.paint(RepaintManager.java:1272)
        at javax.swing.JComponent._paintImmediately(JComponent.java:5158)
        at javax.swing.JComponent.paintImmediately(JComponent.java:4969)
        at javax.swing.RepaintManager$4.run(RepaintManager.java:831)
        at javax.swing.RepaintManager$4.run(RepaintManager.java:814)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:74)
        at javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:814)
        at javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:789)
        at javax.swing.RepaintManager.prePaintDirtyRegions(RepaintManager.java:738)
        at javax.swing.RepaintManager.access$1200(RepaintManager.java:64)
        at javax.swing.RepaintManager$ProcessingRunnable.run(RepaintManager.java:1732)
        at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:311)
        at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:758)
        at java.awt.EventQueue.access$500(EventQueue.java:97)
        at java.awt.EventQueue$3.run(EventQueue.java:709)
        at java.awt.EventQueue$3.run(EventQueue.java:703)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:74)
        at java.awt.EventQueue.dispatchEvent(EventQueue.java:728)
        at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:205)
        at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:116)
        at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:105)
        at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
        at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:93)
        at java.awt.EventDispatchThread.run(EventDispatchThread.java:82)

对应的声音引擎实现代码如下:

// the second option from https://www.baeldung.com/java-play-sound modified to fit my engine idea
class SoundLibrary 
{
    public static final int BUFFER_SIZE = 4096;
    public ArrayList<String> urls;    
    public void registerSound(String fp)
    {
        urls.add(fp);
    }
    public boolean play(int i)
    {
        try {
            InputStream is = getClass().getResourceAsStream(urls.get(urls.size() - 1));
            AudioInputStream ais = AudioSystem.getAudioInputStream(is);
            SourceDataLine.Info dli = new DataLine.Info(Clip.class, ais.getFormat());
            SourceDataLine sdl = (SourceDataLine)AudioSystem.getLine(dli);
            sdl.open(ais.getFormat()); 
            sdl.start();        
            byte[] buffer = new byte[BUFFER_SIZE];
            int rb = -1;
            while ((rb = ais.read(buffer)) != -1)
            {
                sdl.write(buffer, 0, rb);
            }
            sdl.drain();
            sdl.close();
            ais.close();            
            return true;
        } catch (Exception e)
        {
            e.printStackTrace();            
            return false;
        }
    }

    public static void cleanup()
    {
    }

    public SoundLibrary()
    {
        this.urls = new ArrayList<String>();        
        this.registerSound("/resources/sound/bow.wav");
        this.registerSound("NULL");
        this.registerSound("/resources/sound/buttonpress.wav");
    }
}

代码中的错误分析

  • 类型转换异常的直接原因:创建DataLine.Info时,错误传入了Clip.class作为线路类型,但你需要的是SourceDataLine。AudioSystem.getLine()会返回符合指定类型的线路实例,这里返回的是Clip对象,强转成SourceDataLine必然抛出ClassCastException。

  • play方法逻辑错误:方法接收参数i用于指定播放的声音索引,但实际代码中调用的是urls.get(urls.size() - 1),始终获取最后一个注册的声音,完全忽略了传入的索引参数,导致无法按需求播放指定声音。

  • 无效路径注册问题:构造方法中注册了"NULL"这个无效的资源路径,当后续尝试访问该索引时,getResourceAsStream()会返回null,进而导致AudioSystem.getAudioInputStream()抛出空指针或非法参数异常。

修正后的关键代码示例

public boolean play(int i) {
    // 先判断索引是否合法
    if (i < 0 || i >= urls.size()) {
        return false;
    }
    try {
        InputStream is = getClass().getResourceAsStream(urls.get(i));
        if (is == null) {
            System.err.println("Invalid sound resource path: " + urls.get(i));
            return false;
        }
        AudioInputStream ais = AudioSystem.getAudioInputStream(is);
        // 修正DataLine.Info的类型为SourceDataLine.class
        DataLine.Info dli = new DataLine.Info(SourceDataLine.class, ais.getFormat());
        SourceDataLine sdl = (SourceDataLine) AudioSystem.getLine(dli);
        sdl.open(ais.getFormat()); 
        sdl.start();        
        byte[] buffer = new byte[BUFFER_SIZE];
        int rb = -1;
        while ((rb = ais.read(buffer)) != -1) {
            sdl.write(buffer, 0, rb);
        }
        sdl.drain();
        sdl.close();
        ais.close();            
        return true;
    } catch (Exception e) {
        e.printStackTrace();            
        return false;
    }
}

public SoundLibrary() {
    this.urls = new ArrayList<String>();        
    this.registerSound("/resources/sound/bow.wav");
    // 移除无效的"NULL"注册,或替换为有效路径
    // this.registerSound("NULL");
    this.registerSound("/resources/sound/buttonpress.wav");
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 14:40:15