我正在尝试使用 mplayer 直接将视频播放到帧缓冲区中。目前我无法让音频和视频在同一运行级别上播放。
仅当我处于用户级别时,音频设备才会连接,而视频设备则被拒绝。
例如我可以运行:
mplayer -ao alsa -vo fbdev2 test.mp4
它将播放音频但拒绝视频连接
can't open /dev/fb0: Permission Denied
如果我使用,sudo mplayer -ao alsa -vo fbdev2 test.mp4
则视频会播放,但没有音频。
[AO_ALSA] alsa-lib: pulse.c:243:(pulse_connect) PulseAudio: Unable to connect: Connection Refused
[AO_ALSA] Playback open error: Connection Refused
Failed to initialize audio driver 'alsa'
Could not open/initialize audio device -> no sound
Audio: no sound
如何让音频和视频一起播放?它们都在不同的运行级别上分别工作。
答案1
简短的回答,使用 root 驻留虚拟控制台(即 Ctrl+Alt+N)登录,然后启动pulseaudio 守护进程并播放视频:
/usr/bin/pulseaudio --start
mplayer -vo fbdev2 test.mp4
[重要的]/usr/bin/pulseaudio --system
这里不需要尝试过。你呢必须驻留在 root(不是 sudo 甚至 su)和虚拟控制台才能执行所有步骤包括启动守护进程和播放视频。没有效果如果您尝试su
在 X Session 的虚拟终端内启动守护进程。
长答案,我是如何弄清楚的:
第一步,使用新的虚拟控制台打开新终端。背后的原因是 X 会话很可能无法与帧缓冲区一起工作。
现在我需要知道它是否仅限于 mplayer。所以我尝试使用 play 命令来播放基本音乐,例如内置的 kde 声音,并play /usr/share/sounds/KDE-Im-Cant-Connect.ogg
在新的虚拟控制台上使用 sudo :
$ sudo play /usr/share/sounds/KDE-Im-Cant-Connect.ogg
ALSA lib pulse.c:243:(pulse_connect) PulseAudio: Unable to connect: Connection refused
play FAIL formats: can't open output file `default': snd_pcm_open error: Connection refused
$
它不限于 mplayer 或复杂的歌曲。
所以现在我们必须深入研究之间的区别有声音和没有声音。让我们在 X 会话上对普通用户尝试 strace(有声音),(文件名 su1.log 在这里具有误导性,与 su 无关):
strace -o /tmp/su1.log -v -s 1000000 播放 /usr/share/sounds/KDE-Im-Cant-Connect.ogg
和虚拟控制台(没有声音):
strace -o /tmp/su2.log -v -s 1000000 播放 /usr/share/sounds/KDE-Im-Cant-Connect.ogg
vi /tmp/su2.log,导航到末尾:
connect(8, {sa_family=AF_LOCAL, sun_path="/run/user/0/pulse/native"}, 110) = -1 ENOENT (No such file or directory)
close(8) = 0
socket(PF_LOCAL, SOCK_STREAM|SOCK_CLOEXEC, 0) = 8
fcntl(8, F_GETFD) = 0x1 (flags FD_CLOEXEC)
setsockopt(8, SOL_SOCKET, SO_PRIORITY, [6], 4) = 0
fcntl(8, F_GETFL) = 0x2 (flags O_RDWR)
fcntl(8, F_SETFL, O_RDWR|O_NONBLOCK) = 0
connect(8, {sa_family=AF_LOCAL, sun_path="/var/run/pulse/native"}, 110) = -1 ENOENT (No such file or directory)
close(8) = 0
write(5, "x", 1) = 1
write(2, "ALSA lib pulse.c:243:(pulse_connect) ", 37) = 37
write(2, "PulseAudio: Unable to connect: Connection refused\n", 50) = 50
write(2, "\n", 1) = 1
futex(0x135a8e0, FUTEX_UNLOCK_PI_PRIVATE, 0) = 0
sendto(7, "W", 1, MSG_NOSIGNAL, NULL, 0) = -1 ENOTSOCK (Socket operation on non-socket)
write(7, "W", 1) = 1
futex(0x135a8e0, FUTEX_UNLOCK_PI_PRIVATE, 0) = 0
futex(0x7f34065089d0, FUTEX_WAIT, 7956, NULL) = -1 EAGAIN (Resource temporarily unavailable)
munmap(0x7f3406509000, 67112960) = 0
unlink("/dev/shm/pulse-shm-3719764676") = 0
close(6) = 0
close(7) = 0
close(5) = 0
close(4) = 0
write(2, "play FAIL formats: ", 19) = 19
write(2, "can't open output file `default': snd_pcm_open error: Connection refused", 72) = 72
write(2, "\n", 1) = 1
还有 kdiff3 来比较两个日志的“open(”:
$ grep 'open(' /tmp/su1.log > /tmp/su1_open.log
$ grep 'open(' /tmp/su2.log > /tmp/su2_open.log
$ kdiff3 /tmp/su1_open.log /tmp/su2_open.log
$
对于以下情况略有不同/运行/用户/0/脉冲,现在我实现了uid 1000(普通用户)和0(root)的东西,其中“/run/user/1000/pulse”和“run/user/0/pulse”仅在分别使用uid 1000和0时请求:
$ grep 'run/user/0/pulse' /tmp/su1.log
$ grep 'run/user/1000/pulse' /tmp/su2.log
$ grep 'run/user/1000/pulse' /tmp/su1.log
recvmsg(5, {msg_name(0)=NULL, msg_iov(1)=[{"\1\10\2\0\21\0\0\0\37\0\0\0\0\0\0\0B\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0{34959d136592433aad171659a5cd523f}unix:/run/user/1000/pulse/native\0\0", 4096}], msg_controllen=0, msg_flags=0}, 0) = 100
connect(5, {sa_family=AF_LOCAL, sun_path="/run/user/1000/pulse/native"}, 110) = 0
recvmsg(6, {msg_name(0)=NULL, msg_iov(1)=[{"\1\10\2\0\21\0\0\0\37\0\0\0\0\0\0\0B\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0{34959d136592433aad171659a5cd523f}unix:/run/user/1000/pulse/native\0\0", 4096}], msg_controllen=0, msg_flags=0}, 0) = 100
connect(6, {sa_family=AF_LOCAL, sun_path="/run/user/1000/pulse/native"}, 110) = 0
$ grep 'run/user/0/pulse' /tmp/su2.log
mkdir("/run/user/0/pulse", 0700) = -1 EEXIST (File exists)
open("/run/user/0/pulse", O_RDONLY|O_NOCTTY|O_NOFOLLOW|O_CLOEXEC) = 5
lstat("/run/user/0/pulse", {st_dev=makedev(0, 41), st_ino=86867, st_mode=S_IFDIR|0700, st_nlink=2, st_uid=0, st_gid=0, st_blksize=4096, st_blocks=0, st_size=40, st_atime=2015/07/22-01:44:45, st_mtime=2015/07/22-01:44:45, st_ctime=2015/07/22-01:47:59}) = 0
lstat("/run/user/0/pulse", {st_dev=makedev(0, 41), st_ino=86867, st_mode=S_IFDIR|0700, st_nlink=2, st_uid=0, st_gid=0, st_blksize=4096, st_blocks=0, st_size=40, st_atime=2015/07/22-01:44:45, st_mtime=2015/07/22-01:44:45, st_ctime=2015/07/22-01:47:59}) = 0
connect(5, {sa_family=AF_LOCAL, sun_path="/run/user/0/pulse/native"}, 110) = -1 ENOENT (No such file or directory)
mkdir("/run/user/0/pulse", 0700) = -1 EEXIST (File exists)
open("/run/user/0/pulse", O_RDONLY|O_NOCTTY|O_NOFOLLOW|O_CLOEXEC) = 8
lstat("/run/user/0/pulse", {st_dev=makedev(0, 41), st_ino=86867, st_mode=S_IFDIR|0700, st_nlink=2, st_uid=0, st_gid=0, st_blksize=4096, st_blocks=0, st_size=40, st_atime=2015/07/22-01:44:45, st_mtime=2015/07/22-01:44:45, st_ctime=2015/07/22-01:47:59}) = 0
lstat("/run/user/0/pulse", {st_dev=makedev(0, 41), st_ino=86867, st_mode=S_IFDIR|0700, st_nlink=2, st_uid=0, st_gid=0, st_blksize=4096, st_blocks=0, st_size=40, st_atime=2015/07/22-01:44:45, st_mtime=2015/07/22-01:44:45, st_ctime=2015/07/22-01:47:59}) = 0
connect(8, {sa_family=AF_LOCAL, sun_path="/run/user/0/pulse/native"}, 110) = -1 ENOENT (No such file or directory)
$
仅当 /run/user/0/pulse 时“没有这样的文件或目录”,让我们检查(使用 root):
# l /run/user/0/pulse/
total 0
84490 drwx------. 4 root root 80 Jul 22 01:44 ..
86867 drwx------. 2 root root 40 Jul 22 01:44 .
#
# l /run/user/1000/pulse/
total 4.0K
29328 -rw-------. 1 xiaobai xiaobai 5 Jul 22 00:58 pid
30544 srwxrwxrwx. 1 xiaobai xiaobai 0 Jul 22 00:58 native
31058 drwx------. 2 xiaobai xiaobai 80 Jul 22 00:58 .
27430 drwx------. 14 xiaobai xiaobai 280 Jul 22 01:06 ..
# l /run/user/1000/pulse/native
30544 srwxrwxrwx. 1 xiaobai xiaobai 0 Jul 22 00:58 /run/user/1000/pulse/native
# file /run/user/1000/pulse/native
/run/user/1000/pulse/native: socket
# file /run/user/1000/pulse/pid
/run/user/1000/pulse/pid: ASCII text
# cat /run/user/1000/pulse/pid
2205
#
此时我知道进程号 2205正在运行并且应该以 uid 0 存在才能使其正常工作。
我谷歌并发现脉冲音频——检查:
# pulseaudio --check
尝试使用 arg verbose,发现了!守护进程运行为进程号 2205,证明了我上面观察到的:
# pulseaudio --check -v
I: [pulseaudio] main.c: Daemon running as PID 2205
#
所以现在我相信脉冲音频可以让它发挥作用。检查 pid 2205 以了解它是如何触发的:
# ps aux|grep 2205
xiaobai 2205 0.0 0.2 565980 11080 ? S<l 00:58 0:01 /usr/bin/pulseaudio --start
root 8747 0.0 0.0 113008 2300 pts/2 S+ 01:58 0:00 grep --color=auto 2205
#
那么让我们尝试一下/usr/bin/pulseaudio --start
:
# /usr/bin/pulseaudio --start
W: [pulseaudio] main.c: This program is not intended to be run as root (unless --system is specified).
N: [pulseaudio] main.c: User-configured server at {34959d136592433aad171659a5cd523f}unix:/run/user/1000/pulse/native, which appears to be local. Probing deeper.
现在,新的pulse目录出现在uid 0下,并带有新的pid:
# l /run/user/0/
total 0
17794 drwxr-xr-x. 4 root root 80 Jul 22 01:44 ..
85629 drwxr-xr-x. 2 root root 80 Jul 22 01:44 systemd
84490 drwx------. 4 root root 80 Jul 22 01:44 .
86867 drwx------. 2 root root 80 Jul 22 02:02 pulse
# cat /run/user/0/pulse/pid
9731
#
最后声音就可以工作了。现在自己尝试一下mplayer -vo fbdev2 test.mp4
[注意]su
可能会在一些奇怪的情况下工作。例如 X 会话 11 -> Ctrl+Alt+2 -> 使用 uid 1000 登录 -> su - root ->/usr/bin/pulseaudio --start
和 mplayer -vo fbdev2 工作正常。然后 Ctrl+Alt+3 -> 使用 root 登录 ->/usr/bin/pulseaudio --start
和 mplayer 一起工作 -> 返回 Ctrl+Alt+2 -> 虚拟控制台 2 上的 mplayer 不再工作。