英文:
Running ProcessBuilder as root gives 'No such file or directory'
问题
我理解你想要翻译的部分如下:
"我有一个Java程序,在树莓派上使用混音器记录音频。我正在使用ProcessBuilder来实现这个功能,去年它运行得很好。然而,现在它不再运行,当以root用户身份运行应用程序时,我会收到以下错误:
启动录音 /tmp/test.wav - 19:14:36.64
/usr/bin/arecord -f dat /tmp/test.wav 异常:命令退出,返回代码:1,输出:arecord: main:830: 音频打开错误:没有该文件或目录java.lang.Exception: 命令退出,返回代码:1,输出:arecord: main:830: 音频打开错误:没有该文件或目录
at Main.record(Main.java:38) at Main.main(Main.java:11)
当我以默认的 'pi' 用户身份运行(java -jar audioTest.jar),它可以正常运行。
去年和今年唯一的区别是我现在编译到Java 11,而不是8,可能在较新的Raspbian OS(11 bullseye)上运行。
我使用nohup通过一个init.d脚本运行它,因此它以root用户身份运行。据我所知,这也是访问树莓派GPIO所需的。
这是我的测试代码:
import java.io.BufferedReader;
import java.io.File;
import java.io.InputStreamReader;
import java.text.SimpleDateFormat;
import java.util.Date;
public class Main {
public static void main(String[] args) {
System.out.println("Starting");
record(new File("/tmp/test.mp3"));
}
public static void record(File file) {
try {
String wavFile = file.getAbsolutePath().substring(0, file.getAbsolutePath().lastIndexOf(".")) + ".wav";
try {
String player = "/usr/bin/arecord";
ProcessBuilder pb = new ProcessBuilder(player, "-f", "dat", wavFile);
pb.redirectErrorStream(true);
System.out.println("Starting recording " + wavFile + " - " + new SimpleDateFormat("HH:mm:ss.S").format(new Date()));
System.out.println(String.join(" ", pb.command().toArray(new String[0])));
Process recorderProcess = pb.start();
BufferedReader error = new BufferedReader(new InputStreamReader(recorderProcess.getInputStream()));
String errorLine;
StringBuilder accErrorString = new StringBuilder();
while ((errorLine = error.readLine()) != null) {
accErrorString.append(errorLine).append("\n");
}
int exitVal = recorderProcess.waitFor();
if (exitVal != 0) {
throw new Exception("Command exited with code: " + exitVal + " with output: " + accErrorString);
}
} catch (java.io.IOException ioex) {
// This would be the normal exit it seems.
}
} catch (Exception ex){
System.out.println("Exception: " + ex.getMessage());
ex.printStackTrace(System.out);
}
}
}
有任何疑问,欢迎提出。
英文:
I have a Java program which record audio using mixer on a Raspberry Pi. I am using ProcessBuilder to achieve this and was working fine last year. Now it doesn't however, and I get the following error when running the application as root:
> Starting Starting recording /tmp/test.wav - 19:14:36.64
> /usr/bin/arecord -f dat /tmp/test.wav Exception: Command exited with
> code: 1 with output: arecord: main:830: audio open error: No such file
> or directory
>
> java.lang.Exception: Command exited with code: 1 with output: arecord:
> main:830: audio open error: No such file or directory
>
> at Main.record(Main.java:38) at Main.main(Main.java:11)
When I run as the default 'pi' user (java -jar audioTest.jar) it runs fine.
The only difference between last year is that I am now compiling to Java 11 instead of 8 and possibly running on a newer version of Raspbian OS (11 bullseye).
I have it running with nohup through an init.d script so it is running as the root user. This is also required to access the GPIO of the Raspberry as far as I know.
This is my test code:
import java.io.BufferedReader;
import java.io.File;
import java.io.InputStreamReader;
import java.text.SimpleDateFormat;
import java.util.Date;
public class Main {
public static void main(String[] args) {
System.out.println("Starting");
record(new File("/tmp/test.mp3"));
}
public static void record(File file) {
try {
String wavFile = file.getAbsolutePath().substring(0, file.getAbsolutePath().lastIndexOf(".")) + ".wav";
try {
String player = "/usr/bin/arecord";
ProcessBuilder pb = new ProcessBuilder(player, "-f", "dat", wavFile);
pb.redirectErrorStream(true);
System.out.println("Starting recording " + wavFile + " - " + new SimpleDateFormat("HH:mm:ss.S").format(new Date()));
System.out.println(String.join(" ",pb.command().toArray(new String[0])));
//Process pr = pb.start();
Process recorderProcess = pb.start();
BufferedReader error = new BufferedReader(new InputStreamReader(recorderProcess.getInputStream()));
String errorLine;
StringBuilder accErrorString = new StringBuilder();
while ((errorLine = error.readLine()) != null) {
accErrorString.append(errorLine).append("\n");
}
int exitVal = recorderProcess.waitFor();
if (exitVal != 0) {
throw new Exception("Command exited with code: " + exitVal + " with output: " + accErrorString);
}
} catch (java.io.IOException ioex) {
// This would be the normal exit it seems.
}
} catch (Exception ex){
System.out.println("Exception: " + ex.getMessage());
ex.printStackTrace(System.out);
}
}
}
Any idea why this is happening would be greatly appreciated.
[Edit]
The output of record -l:
**** List of CAPTURE Hardware Devices ****
card 3: Device [USB Audio Device], device 0: USB Audio [USB Audio]
Subdevices: 1/1
Subdevice #0: subdevice #0
But adding -D hw:0,0 now gives the error on both. So for th e'pi' user it might select it correctly and not for the root. With hw:3,0 it works, and then add the -c 1 flag to select the channel.
答案1
得分: 0
错误可能与正在记录的文件无关,而与arecord正在使用的声音设备有关。要解决此问题,请考虑以下步骤:
-
验证是否需要传递 -D hw:1,0(更改设备ID)作为arecord的设备参数。
-
确保根用户可以访问音频设备文件(位于/dev/下)。
-
检查arecord命令是否在根用户的$PATH中。您可以通过以根用户身份运行“which arecord”来验证这一点。
-
您可以将根用户添加到音频组,以授予对音频设备的访问权限。
您可能也会发现这些链接有用:
https://github.com/synesthesiam/voice2json/issues/28
英文:
The error may not be related to the file being recorded, but rather to the sound device that arecord is using.
To resolve this issue, consider the following steps:
-
Verify if you need to pass -D hw:1,0 (change the device id) as a device parameter to arecord.
-
Ensure that the audio device files (located under /dev/) are accessible by the root user.
-
Check if the arecord command is in the $PATH for the root user. You can verify this by running “which arecord” as root.
-
You can add the root user to the audio group to grant access to audio devices.
You may also find these links helpful:
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论