我有一个 bash 脚本,它ffplay
在后台启动,无限循环一个短的声音样本。然后它做了一些其他的工作,最后它杀死了ffplay。
foo() {
ffplay -loop 0 sound.wav &>/dev/null &
trap "kill $!" RETURN
(do work...)
}
我希望 ffplay 完成当前播放的样本的播放,然后才死亡。这可能吗?
答案1
您可以获得连续的统计信息或调试输出,ffplay
其中包含以回车符 (^M) 结尾的行,如下所示:
nan M-A: nan fd= 0 aq= 0KB vq= 0KB sq= 0B f=0/0 ^M
-0.07 M-A: -0.000 fd= 0 aq= 0KB vq= 0KB sq= 0B f=0/0 ^M
-0.01 M-A: -0.000 fd= 0 aq= 0KB vq= 0KB sq= 0B f=0/0 ^M
0.02 M-A: 0.000 fd= 0 aq= 0KB vq= 0KB sq= 0B f=0/0 ^M
看起来第一列是“nan”,不是数字,或者在循环开始时为负数。您可以检查这一点并在看到它时终止该进程。以下 bash 脚本演示了这一点。
#!/bin/bash
sound=somefile.wav
touch flagfile
(sleep 4; rm -f flagfile) &
ffplay -nodisp -stats -loop 0 "$sound" 2>&1 |
while read -d $'\r' time rest
do case $time in
nan|-*|0.00) [ ! -f flagfile ] && exit ;;
esac
done
它创建一个文件flagfile
,您需要删除该文件才能停止循环。在这个演示中,4 秒后就完成了。
ffplay
使用选项运行-stats
。统计信息写在 stderr 上,因此我们将其重定向到 stdout 2>&1
。统计数据通过管道传送到一个 while 循环,该循环使用read
分隔符回车符 ( $'\r'
) 将第一个单词放入变量中
time
,其余单词放入 中rest
。
将case
第一个单词与模式nan
或以 或数字 0 开头的任何内容进行比较-
,如果标志文件不再存在,则脚本退出。
再写入几次统计数据后,ffplay 将被信号 SIGPIPE 杀死。您必须决定这个短暂的延迟是否适合您。这取决于声音文件的前几毫秒的噪音有多大。
如果您ffplay
没有响应 SIGPIPE,您可以通过在临时文件中记下该命令的进程 ID 来运行您自己的终止命令
pidfile
。请注意使用$BASHPID
而不是$$
,因为后者在子 shell 内不会改变。
#!/bin/bash
sound=somefile.wav
touch flagfile
(sleep 4; rm -f flagfile) &
( echo $BASHPID >pidfile
exec ffplay -nodisp -stats -loop 0 $sound 2>&1 ) |
while read -d $'\r' time rest
do case $time in
nan|-*|0.00) [ ! -f flagfile ] && break ;;
esac
done
kill -hup $(<pidfile)
rm -f pidfile