Java:SourceDataLine.write(...) 屏蔽中断吗?

标签 java audio interrupt

我有一个循环调用 SourceDataLine.write(...) 直到写入(播放)所有音频数据的线程。我希望能够提前停止播放(在循环通常被 EOF 类型的条件终止之前)并且正在(尝试)使用中断。当我调用 playbackThread.interrupt() 时,它只会偶尔中断和终止线程。代码中的微小更改或连续调用会产生不同的(看似随机的)结果。我已经调试并尝试使用 Thread.currentThread.isInterrupted() 而不是 Thread.interrupted()。我注意到,如果我用其他东西(例如长计数循环)替换 SourceDataLine.write(...) 调用,线程确实会以可预测和一致的方式终止。

SourceDataLine.write(...) 是否“消耗”了一个中断但没有抛出 InterruptedException?意思是,它是否清除中断标志(可能使用 Thread.interrupted()),忽略它,然后继续?这可以解释为什么中断会间歇性地工作:如果它发生在 SDL.write(...) 方法中,它会被丢弃;否则,在我使用 Thread.interrupted() 调用进行测试之前,它会保持“完整”。这太糟糕了,但这是我花了一整天时间想出来的唯一解释。我找不到 SourceDataLine.write(...) 的任何来源,因为它是一个接口(interface),而且(我想)实现是依赖于机器的。

由于我没有使用 try/catch 并期望在我的循环中捕获 InterruptedExeption,而是在每次循环的底部调用 Thread.interrupted()(或 Thread.currentThread.isInterrupted()),我可以轻松创建我自己的 interruptFlag 并对其进行测试。这正是我在几个月前为了赶时间而中断 TargetDataLine.read(...) 方法时在其他地方所做的。我周末的大部分时间都在一劳永逸地调查这个长期存在的谜团的根源,但没有成功。

使用实际的 Java 中断机制似乎更一致/更优雅 - 但如果它不起作用则不是。这个解释合理吗?

playbackThread的代码:

public void run() {
    int offset = 0;
    int remaining = cRawAudioBuffer.length;
    int length = WRITE_LENGTH;
    int bytesWritten = 0;
    cOutputLine.start();
    while (remaining>0) {
        length = Math.min(length,remaining);
        bytesWritten = cOutputLine.write(cRawAudioBuffer,offset,length);
        offset += bytesWritten;
        remaining -= bytesWritten;
        if (Thread.currentThread().isInterrupted()) {
            System.out.println("I Was interrupted");
            break;
        }
    }
    cOutputLine.close();
}

更新:

仍在调查以更全面地了解这里发生的事情。我通过从写循环本身内部调用 Thread.interrupt() 强制中断了 playbackThread,并插入了对 Thread.currentThread().isInterrupted() 的调用——因此没有用测试本身清除中断标志——之前和在 write() 调用之后。我发现对于前几个循环,从 write() 方法返回后中断被保留。在前 3 个循环之后,从 write() 返回后中断被清除。此后,它几乎总是,但总是,在从 write() 返回后被清除。我的猜测是,如果 write() 在等待缓冲区清除时被阻塞,它将检测、忽略并清除中断标志。仍然只是一个猜测,我宁愿确定(以避免传播我做错的事情并让它以后咬我)。关于如何在不访问源代码的情况下验证此假设的任何想法?

public void run() {
    ....
    while (remaining>0) {
        length = Math.min(length,remaining);
        Thread.currentThread().interrupt();
        System.out.println("Player interrupt flag is " + (Thread.currentThread().isInterrupted()?"":"not ") + "set before write()");
        bytesWritten = cOutputLine.write(cRawAudioBuffer,offset,length);
        System.out.println("Player interrupt flag is " + (Thread.currentThread().isInterrupted()?"":"not ") + "set after write()");
        offset += bytesWritten;
        remaining -= bytesWritten;
        if (Thread.interrupted()) {
            System.out.println("I Was interrupted");
            //break;
        }
    }
    cOutputLine.close();
}

最佳答案

事实证明,SourceDataLine.write() 在写入过程中会阻塞,如果在写入过程中发生中断,它将被忽略并重置中断标志。没有办法直接检测中断。我想这是使用 Java Audio 的人们的常识,如果不理解这一点,就无法创建可靠的可中断音频播放。我将(遗憾地)不得不求助于在每次 write() 之后读取的同步标志来检测中断。

关于Java:SourceDataLine.write(...) 屏蔽中断吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10275366/

相关文章:

java - 如何从java调用用汇编语言代码编写的函数?

java继承的误区

c++ - 如何使用 QAudioOutput 和 QAudioDecoder 播放 mp3 文件?

actionscript-3 - 在 Flash Player 11 中按 channel 分析声音

c - BIOS中断_int86

Java的3DES加密在加密数据末尾产生垃圾

Java 反射没有按预期工作

ios - 使用AudioConverter将PCM转换为AAC并使用AVAssetWriter写入.mp4文件时,音频失真

c++ - Qt 中的可中断 sleep ?

linux - Octave Ctrl-C 关闭编辑窗口