ags*_*ags 2 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(...) 的任何来源,因为它是一个接口,并且(我想)实现是依赖于机器的。
由于我没有使用 try/catch 并期望在循环中捕获 InterruptedExeption,而是在每次循环的底部调用 Thread.interrupted() (或 Thread.currentThread.isInterrupted()),因此我可以轻松创建我自己的中断标志并测试它。这正是我几个月前在赶时间赶进度时中断 TargetDataLine.read(...) 方法时所做的事情。我花了周末的大部分时间来一劳永逸地调查这个长期存在的谜团的根源,但没有成功。
使用实际的 Java 中断机制似乎更一致/更优雅 - 但如果它不起作用,则不然。这个解释可信吗?
播放线程代码:
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();
}
Run Code Online (Sandbox Code Playgroud)
更新:
仍在调查以更全面地了解这里发生的事情。我通过从写入循环本身调用 Thread.interrupt() 来强制播放线程中断,并插入对 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();
}
Run Code Online (Sandbox Code Playgroud)
事实证明,SourceDataLine.write() 在写入期间会阻塞,如果在写入期间发生中断,则会忽略该中断并重置中断标志。没有办法直接检测中断。我想这是使用 Java Audio 的人的常识,如果不理解这一点,就无法创建可靠的可中断音频播放。我将(遗憾地)不得不求助于每次 write() 之后读取的同步标志来检测中断。
| 归档时间: |
|
| 查看次数: |
860 次 |
| 最近记录: |