Java TargetDataLine没有拾取任何音频?

nuypyhwy  于 5个月前  发布在  Java
关注(0)|答案(2)|浏览(63)

我正在编写一个函数,使用TargetDataLine捕获一个大约7.5秒的音频剪辑。代码执行并呈现一个“input.wav”文件,但当我播放它时没有声音。
我的方法,如本文底部的代码所示,是做以下事情:
1.创建AudioFormat并获取目标数据行的信息,
1.通过从AudioSystem获取行来创建目标数据行。
1.打开并启动TargetDataLine,它将为录制分配系统资源。
1.创建一个辅助线程,该线程将通过写入文件来录制音频。
1.启动辅助线程,同时暂停主线程,然后关闭目标数据行,以停止记录。
到目前为止,我所尝试的:
1.更改AudioFormat。最初,我使用的是另一个AudioFormat构造函数,它也接受文件类型(其中第一个参数是AudioFormat.Encoding.PCM_SIGNED等)。我在另一个格式上使用了44100的采样率、16位、2个通道和small-Endian设置,这产生了相同的结果。
1.更改我的辅助线程和主线程上的命令顺序(例如,在其他位置执行TLine.open()或start())。
1.检查我的辅助线程是否真的启动了。
作为参考,我在Mac OS Big Sur上使用IntelliJ。

public static void captureAudio() {
        try {
            AudioFormat f = new AudioFormat(22050, 8, 1, false, false);
            DataLine.Info secure = new DataLine.Info(TargetDataLine.class, f);
            if (!AudioSystem.isLineSupported(secure)) {
                System.err.println("Unsupported Line");
            }
            TargetDataLine tLine = (TargetDataLine)AudioSystem.getLine(secure);
            System.out.println("Starting recording...");
            tLine.open(f);
            tLine.start();
            File writeTo = new File("input.wav");
            Thread t = new Thread(){
                    public void run() {
                        try {
                            AudioInputStream is = new AudioInputStream(tLine);
                            AudioSystem.write(is, AudioFileFormat.Type.WAVE, writeTo);
                        } catch(IOException e) {
                            System.err.println("Encountered system I/O error in recording:");
                            e.printStackTrace();
                        }
                    }
            };
            t.start();
            Thread.sleep(7500);
            tLine.stop();
            tLine.close();
            System.out.println("Recording has ended.");
        } catch(Exception e) {
            e.printStackTrace();
        }
    }

字符串

  • 更新1:一些新的测试和结果 *

1.我的麦克风和扬声器都与其他应用程序一起工作-用QuickTime Player录制的工作音频。
1.我对TargetDataLines做了大量的测试,并运行了以下代码:

public static void main(String[] args) {
AudioFormat f = new AudioFormat(48000, 16, 2, true, false);
        //DataLine.Info inf = new DataLine.Info(SourceDataLine.class, f);
        try {
            TargetDataLine line = AudioSystem.getTargetDataLine(f);
            DataLine.Info test = new DataLine.Info(TargetDataLine.class, f);
            TargetDataLine other = (TargetDataLine)AudioSystem.getLine(test);
            String output = line.equals(other) ? "Yes" : "No";
            if (output.equals("No")) {
                System.out.println(other.toString());
            }
            System.out.println(line.toString());
            System.out.println("_______________________________");
            for (Mixer.Info i : AudioSystem.getMixerInfo()) {
                Line.Info[] tli = AudioSystem.getMixer(i).getTargetLineInfo();
                if (tli.length != 0) {
                   Line comp = AudioSystem.getLine(tli[0]);
                   System.out.println(comp.toString() + ":" +i.getName());
                   if (comp.equals(line) || comp.equals(other)) {
                       System.out.println("The TargetDataLine is from " + i.getName());
                   }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
}


长话短说,我在执行TargetDataLine line = AudioSystem.getTargetDataLine(f);TargetDataLine other = (TargetDataLine)AudioSystem.getLine(new DataLine.Info(TargetDataLine.class, f));时收到的TargetDataLine是不同的,而且,与我的系统的混音器关联的任何TargetDataLine都不匹配。
以上代码的输出如下(其中第一行分别为otherline):

com.sun.media.sound.DirectAudioDevice$DirectTDL@cc34f4d
com.sun.media.sound.DirectAudioDevice$DirectTDL@17a7cec2
_______________________________
com.sun.media.sound.PortMixer$PortMixerPort@79fc0f2f:Port MacBook Pro Speakers
com.sun.media.sound.PortMixer$PortMixerPort@4d405ef7:Port ZoomAudioDevice
com.sun.media.sound.DirectAudioDevice$DirectTDL@3f91beef:Default Audio Device
com.sun.media.sound.DirectAudioDevice$DirectTDL@1a6c5a9e:MacBook Pro Microphone
com.sun.media.sound.DirectAudioDevice$DirectTDL@37bba400:ZoomAudioDevice


1.在这一认识上,我手动加载了所有的TargetDataLines从我的混音器,并尝试记录音频与他们中的每一个,看看我是否得到了任何声音。
我使用以下方法收集了所有TargetDataLines:

public static ArrayList<Line.Info> allTDL() {
        ArrayList<Line.Info> all = new ArrayList<>();
        for (Mixer.Info i : AudioSystem.getMixerInfo()) {
            Line.Info[] tli = AudioSystem.getMixer(i).getTargetLineInfo();
            if (tli.length != 0) {
                for (int f = 0; f < tli.length; f += 1) {
                    all.add(tli[f]);
                }
            }
        }
        return all;
    }


我的捕获/录制音频方法保持不变,只是将格式切换为AudioFormat f = new AudioFormat(48000, 16, 2, true, false);,将录制时间更改为5000毫秒,并将方法头写入为public static void recordAudio(Line.Info inf),这样我就可以使用每个TargetDataLine的信息单独加载它。
然后,我执行了以下代码来旋转TargetDataLines:

public static void main(String[] args) {
   for (Line.Info inf : allTDL()) {
            recordAudio(inf);
            try {
                Thread.sleep(5000);
            } catch(Exception e) {
                e.printStackTrace();
            }
            if (!soundless(loadAsBytes("input.wav"))) {
                System.out.println("The recording with " + inf.toString() + " has sound!");
            }
            System.out.println("The last recording with " + inf.toString() + " was soundless.");
        }

    }
}


输出如下:

Recording...
Was unable to cast com.sun.media.sound.PortMixer$PortMixerPort@506e1b77 to a TargetDataLine.
End recording.
The last recording with SPEAKER target port was soundless.
Recording...
Was unable to cast com.sun.media.sound.PortMixer$PortMixerPort@5e9f23b4 to a TargetDataLine.
End recording.
The last recording with ZoomAudioDevice target port was soundless.
Recording...
End recording.
The last recording with interface TargetDataLine supporting 8 audio formats, and buffers of at least 32 bytes was soundless.
Recording...
End recording.
The last recording with interface TargetDataLine supporting 8 audio formats, and buffers of at least 32 bytes was soundless.
Recording...
End recording.
The last recording with interface TargetDataLine supporting 14 audio formats, and buffers of at least 32 bytes was soundless.

TL;DR每个TargetDataLine的声音都是无声的。为了完整起见,以下是soundlessloadAsBytes函数:

public static byte[] loadAsBytes(String name) {
        assert name.contains(".wav");
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        File retrieve = new File("src/"+ name);
        try {
            InputStream input = AudioSystem.getAudioInputStream(retrieve);

            int read;
            byte[] b = new byte[1024];
            while ((read = input.read(b)) > 0) {
                out.write(b, 0, read);
            }
            out.flush();
            byte[] full = out.toByteArray();
            return full;

        } catch(UnsupportedAudioFileException e) {
            System.err.println("The File " + name + " is unsupported on this system.");
            e.printStackTrace();
        } catch (IOException e) {
            System.err.println("Input-Output Exception on retrieval of file " + name);
            e.printStackTrace();
        }
        return null;

    }

  static boolean soundless(byte[] s) {
        if (s == null) {
            return true;
        }
        for (int i = 0; i < s.length; i += 1) {
            if (s[i] != 0) {
                return false;
            }
        }
        return true;
    }


我真的不知道问题出在哪里保存操作系统不允许Java访问音频线,但我不知道如何解决这个问题--看看系统偏好设置,没有任何明显的方法允许访问。我想可能必须用终端命令来完成,但也不知道我必须在那里执行什么命令。

1wnzp6jl

1wnzp6jl1#

我没有看到你所展示的代码有任何错误。我还没有尝试在我的系统上测试它。(Linux,Eclipse)
在我看来,您的代码与this tutorial非常匹配。作者 Nam Ha Minh 非常有意识地回答问题。您可以尝试他的确切代码示例,如果他的版本也失败了,请咨询他。
但首先,生成的.wav文件的大小是多少?文件大小是否与您录制的持续时间内预期的数据量相匹配?如果是,您确定有数据从麦克风传入吗?Nam有another code example,其中记录的声音被逐步读取并放入内存。基本上,而不是使用AudioInputStream作为AudioSystem.write方法的参数,在AudioInputStream上执行多个read方法调用,并直接检查传入数据。这可能有助于故障排除,无论问题是否发生在进程的传入与传出部分。
我对格式的了解不够,不知道Mac的操作方式是否不同。我很惊讶你把格式设置为 unsigned。出于我有限的目的,我坚持使用“CD质量立体声”和签名PCM。
编辑:根据反馈,似乎问题是传入的线路不返回数据。从看其他类似的教程,似乎有几个人在他们的Mac系统上遇到了同样的问题。
首先要验证的是:您的麦克风是否可以与其他应用程序一起使用?
至于接下来的步骤,我会尝试验证所选的行。暴露给java的行可以被枚举/检查。教程Accessing Audio System Resources有一些关于如何做到这一点的基本信息。看起来AudioSystem.getMixerInfo()将返回一个可以检查的可用混合器列表。也许AudioSystem.getTargetLineInfo()会更中肯。
我想有可能在获取TargetDataLine时使用的默认LinePort不是运行麦克风的那个。如果某个特定的线路或端口是您需要的,那么可以通过重写的getTargetDataLine方法显式指定它。
我在阅读,可能有一个安全策略需要处理。我不完全理解代码,但如果这是问题,一个Exception大概会被抛出。也许有新的安全措施来自MacOS,以防止外部程序偷偷打开麦克风线?
如果你确实解决了这个问题,一定要把答案贴出来,并标记它已经解决了。

pes8fvy9

pes8fvy92#

我注意到您遇到的问题与我在Mac上使用MacOS Big Sur及更高版本时遇到的问题类似。和您一样,我在Eclipse中使用基本的音频采样器程序,并且还必须通过设置声音面板选择输入设备。
问题似乎出在安全管理器上。当我在Eclipse中运行该程序时,它从设备上给我零值数据-没有声音。然而,在将该程序导出为可运行的监听器并从命令行运行时,我从安全管理器收到一个提示,要求获得麦克风访问权限。一旦我允许,该程序工作正常,并按预期读取音频数据。
很明显,当从Eclipse运行时,程序没有触发安全管理器的必要权限提示。我也在寻找一个解决方案,让安全管理器在Eclipse中运行程序时提示麦克风访问。如果你有任何进展或找到解决方案,我也很想听听。

相关问题