OpenJDK中AudioSystem.getMixerInfo截断设备名称问题及解决方案咨询
你碰到的这个问题确实是OpenJDK里一个长期未修复的已知Bug,从你测试的OpenJDK 12.0.2和14版本来看,这个问题依然存在——当获取Port Mixer和Capture类型设备的Mixer.Info名称时,会被强制截断到32字符,而Playback类设备的名称却能完整显示。这就导致像带麦克风的扬声器这类长名称设备,截断后只剩1个字符用于区分,完全失去了实用性。
问题根源
从你的调试输出能清晰看到差异:
- 被截断的设备:
Port Echo Cancelling Speakerphone (P)、Echo Cancelling Speakerphone (P)(对应Port Mixer和Capture设备) - 完整显示的设备:
Echo Cancelling Speakerphone (Poly Studio)(Playback设备)
这是因为OpenJDK底层的DirectSound实现对不同类型设备的名称缓冲区做了不同限制:Capture和Port设备的名称缓冲区被设置为32字节(包含字符串终止符),所以实际能显示的有效字符只有31个;而Playback设备没有这个限制。
可行的解决办法
针对这个未修复的Bug,你可以尝试以下几种workaround:
结合多字段匹配设备
虽然名称被截断,但可以利用Mixer.Info的其他字段(比如getDescription()、getVendor())来辅助筛选:- 先通过
description区分设备类型:Capture设备的描述是Direct Audio Device: DirectSound Capture,Port设备是Port Mixer - 再结合截断后的名称片段进行匹配,能大幅提高匹配的准确性
示例代码片段:
if (lineInfos.length >= 1 && lineInfos[0].getLineClass() == TargetDataLine.class) { // 先过滤Capture类型设备 if (info.getDescription().contains("DirectSound Capture") && info.getName().contains(deviceName)) { logger.info("Match found: " + info.getName()); return (TargetDataLine) m.getLine(lineInfos[0]); } }- 先通过
调用Windows本地API获取完整名称(仅限Windows环境)
如果你的应用只运行在Windows系统上,可以通过JNI或JNA调用Windows的Core Audio API(比如IMMDeviceEnumerator)直接获取设备的完整名称,再通过设备ID等唯一标识和Java Sound API中的设备进行关联,完全绕过Java层的名称截断限制。维护截断名称与完整名称的映射表
如果你能提前预知目标设备的截断后名称和完整名称的对应关系,可以在代码中维护一个映射表,提前做转换:private static final Map<String, String> TRUNCATED_TO_FULL_NAME = new HashMap<>(); static { TRUNCATED_TO_FULL_NAME.put("Echo Cancelling Speakerphone (P)", "Echo Cancelling Speakerphone (Poly Studio)"); TRUNCATED_TO_FULL_NAME.put("Port Echo Cancelling Speakerphone (P)", "Port Echo Cancelling Speakerphone (Poly Studio)"); // 根据你的设备情况添加更多映射 }在匹配时,先通过截断名称找到完整名称,再进行后续的逻辑处理。
补充说明
这个Bug在更早的Java版本(比如Java 8)中就已存在,且官方多年未更新修复,所以上述方案是目前最实用的解决途径。
内容的提问来源于stack exchange,提问作者Allen

