附加麦克风后Java声音刷新线路列表

Posted

技术标签:

【中文标题】附加麦克风后Java声音刷新线路列表【英文标题】:Java Sound refresh Lines list after attaching a microphone 【发布时间】:2012-03-26 15:10:51 【问题描述】:

我有一个简单的捕获/播放 Swing 应用程序,它必须检测计算机是否没有连接适当的麦克风并警告用户。经过大量的摆弄,我找到了唯一能让我检测到新连接或移除的麦克风的解决方案:

     com.sun.media.sound.JDK13Services.setCachingPeriod(0);

     private static boolean isMicrophoneAvailable() 
        try 
            if (!Audiosystem.isLineSupported(Port.Info.MICROPHONE)) 
                log.debug("NO MICROPHONE FOUND");
                return false;
             else 
                log.debug("MICROPHONE FOUND");
                return true;
            
         catch (IllegalArgumentException e) 
            log.debug("INCONSISTENT");
        
        return false;
    

这样在后台线程中调用:

   new Thread() 
       public void run() 
            while(!thisFrame.isClosed())
                if(isMicrophoneAvailable() == true)
                     //OK
                else
                     //WARN
                
                try 
                    Thread.sleep(1000);
                 catch (InterruptedException e) 
                    e.printStackTrace();
                
            
      
    ).start();

问题在于,尽管使用所描述的方法可以正确检测到设备,但基础线路列表并未刷新。也就是在程序启动时,稍后附加设备时,尝试录制声音时会抛出以下异常:

 java.lang.IllegalArgumentException: No line matching interface TargetDataLine supporting format PCM_SIGNED 44100.0 Hz, 16 bit, stereo, 4 bytes/frame, big-endian is supported.

有什么方法可以刷新 AudioSystem 的行列表吗?也许类似于一开始使用的JDK13Services 解决方法以避免缓存?

更新:引发异常的代码:

        AudioFormat format = formatControls.getDefaultFormat();
        DataLine.Info info = new DataLine.Info(TargetDataLine.class,format);
        try 
            line = (TargetDataLine) AudioSystem.getLine(info);
            line.open(format, line.getBufferSize());
         catch (LineUnavailableException ex) 
            shutDown("No audio input device available. Please make sure that a microphone is attached to your computer");
            return;
         catch (Exception ex) 
            log.error(ex.toString());
            shutDown(ex.toString());
            return;
        

以及异常本身:

 java.lang.IllegalArgumentException: No line matching interface TargetDataLine supporting format PCM_SIGNED 44100.0 Hz, 16 bit, stereo, 4 bytes/frame, big-endian is supported.

【问题讨论】:

有趣的问题,+1。只是检查一下,您确实意识到在 com.sun 包中使用类的脆弱性,对吧?即使在它存在的 JRE 中,它也可能在下一个版本中被删除/移动/重命名。 确实,我确实意识到这至少是一种不好的做法,但这确实是我最后的手段。我想它可以被认为是一个 Java Sound 实现缺陷。 众多之一。 JavaSound 对于它旨在支持的有限范围的东西很有用,但 Sun 从未真正进一步开发它。 【参考方案1】:

以原始帖子为灵感,我想出了这个方法来检测麦克风何时丢失或获得。它在插入或拔出 USB 麦克风时检测(在我的系统上)。我从后台线程循环中调用它。原来的方法对我不起作用,因为笔记本电脑上有一个内置麦克风,所以我需要检测第二个麦克风的添加。

...
//call this once somewhere to turn the caching period down for faster detection
    try
    
        //try to set the caching period, defaults to something like 55 seconds
        com.sun.media.sound.JDK13Services.setCachingPeriod(5);
    
    catch( Exception e)
    
        System.err.println("exception attempting to call com.sun.media.sound.JDK13Services.setCachingPeriod->" + e);
    
...

private int lastNumMics = -1;
private synchronized void micCheck()

    Line.Info[] lineInfoArray = AudioSystem.getSourceLineInfo(Port.Info.MICROPHONE);
    int numMics = lineInfoArray == null ? 0 : lineInfoArray.length;
    if( lastNumMics > -1 )
    
        if( numMics < lastNumMics )
        
            //MICROPHONE_LOST
        
        else if( numMics > lastNumMics )
        
            //MICROPHONE_GAINED
        
    
    lastNumMics = numMics;

【讨论】:

【参考方案2】:

发布引发异常的代码可能会有所帮助。

我假设您仅使用 Port.Info 来检测麦克风的存在,然后获取数据线进行记录:

TargetDataLine dataLine = (TargetDataLine) AudioSystem.getLine(new DataLine.Info(TargetDataLine.class, audioFormat));                       
dataLine.open();
dataLine.start();               
dataLine.read(b, offset, len);

请注意,如果在您检查是否存在与您尝试让 Dataline 进行记录之间物理断开麦克风但连接 microhpone 应该不成问题,则断开麦克风时您可能仍会遇到类似的异常。

【讨论】:

看来我在做几乎相同的事情。无论如何,我已经用代码和异常更新了问题。 确保线路支持该音频格式。列出该行支持的所有音频格式: AudioFormat adfs[] = ((DataLine.Info)dataLine.getLineInfo()).getFormats(); for (AudioFormat adf : adfs) System.out.println(adf.toString()); 我不太明白你的想法。 line = (TargetDataLine) AudioSystem.getLine(info);是引发异常的地方,所以我一开始就无法得到这条线。也许我不够清楚:麦克风工作正常,如果它在程序启动之前连接到计算机。正确检测到断开连接,“记录”按钮被禁用。重新插入后,它再次工作。如果在 jvm 启动之前未连接麦克风,则会出现问题。在这种情况下,即使检测到 Port.Info.MICROPHONE,它的线路仍然不起作用。 误解了您之前的帖子...我可以给您一个失败的原因:减少 JDK13Services 中的缓存期适用于 PortMixer 的发现,但不适用于 DirectAudioDevice Mixer(TargetDataLine)。虽然不能给你解决方案

以上是关于附加麦克风后Java声音刷新线路列表的主要内容,如果未能解决你的问题,请参考以下文章

声卡和麦克风和功放怎么连接

如何使用麦克风从麦克风/线路输入进行FFT

使用 NAudio 从麦克风录制声音。为啥不能正确地从列表中记录整个缓冲区?

Java Sound API:从目标端口捕获声音输出

在 Java 中使用声音计将声音从麦克风录制到文件

如何将系统麦克风音频流传输到附加设备的麦克风音频流