[已解决:成功实现在星际译王对单词发音时, 自动让正在播放的音乐临时降低音量]有没有办法临时禁止其它程序播放声音?

Totem,mplayer,sopcast,realplayer,bmp
头像
潇洒走一回
帖子: 735
注册时间: 2009-05-20 21:43

[已解决:成功实现在星际译王对单词发音时, 自动让正在播放的音乐临时降低音量]有没有办法临时禁止其它程序播放声音?

#1

帖子 潇洒走一回 » 2010-03-27 11:14

情景:
使用xmms播放音乐, 同时在读英文, 遇到不会的单词使用星际译王查看释义和朗读. 星际译王发音时需要暂停音乐, 不然听不见, 朗读完之后还要继续音乐的播放...
首先我在星际译王的首选项中将发音命令改为smart-play, 然后是smart-play的代码...

代码: 全选

#!/bin/sh
# aplay 发音程序的包装, 用于在stardict播放声音文件时, 暂停音乐的播放
[ -z "$1" ] && exit 1
MusicOn=`pgrep xmms2`
[ -n "$MusicOn" ] && sleep 0.5 && xmms2 pause
aplay $1
[ -n "$MusicOn" ] && sleep 1 && xmms2 play
可是以上代码是不足以完成任务的(当前代码假设如果xmms进程存在的话, 其正出于播放状态):
如果xmms正处于pause状态, 第一个pause自然不生效, 可是后面的play执行后破坏了现场...
遗憾的是xmms2 info中的输出中没有包含是否正在播放的信息...
请求更好的办法...
如果能临时禁用其它程序的声音输出, 应该很妙!
谢谢!!!
上次由 潇洒走一回 在 2010-03-31 17:21,总共编辑 1 次。
delectate
帖子: 18311
注册时间: 2008-01-09 22:41

Re: 有没有办法临时禁止其它程序播放声音?

#2

帖子 delectate » 2010-03-27 11:16

use oss audio output

... :em06

or maybe you can use pulse audio manager
头像
潇洒走一回
帖子: 735
注册时间: 2009-05-20 21:43

Re: 有没有办法临时禁止其它程序播放声音?

#3

帖子 潇洒走一回 » 2010-03-27 11:24

delectate 写了:use oss audio output

... :em06

or maybe you can use pulse audio manager
谢谢!
我不懂 oss 和 pulse...
头像
eexpress
帖子: 58428
注册时间: 2005-08-14 21:55
来自: 长沙

Re: 有没有办法临时禁止其它程序播放声音?

#4

帖子 eexpress » 2010-03-27 19:34

那音量界面,进去,最后一个页面,有当前的使用声音的软件,按需要,点静音。
● 鸣学
头像
潇洒走一回
帖子: 735
注册时间: 2009-05-20 21:43

Re: 有没有办法临时禁止其它程序播放声音?

#5

帖子 潇洒走一回 » 2010-03-28 21:52

eexpress 写了:那音量界面,进去,最后一个页面,有当前的使用声音的软件,按需要,点静音。
大婶真幽默~
不过这个方法说明独占声音输出是不难做到的, 现在需要把它自动化...
头像
foolegg
帖子: 249
注册时间: 2007-12-01 14:56

Re: 有没有办法临时禁止其它程序播放声音?

#6

帖子 foolegg » 2010-03-30 1:38

代码: 全选

pacmd list-sink-inputs
可以查询使用pulseaudio的程序。查询结果类似这样:

代码: 全选

$ pacmd list-sink-inputs
Welcome to PulseAudio! Use "help" for usage information.
>>> 1 sink input(s) available.
    index: 2
	driver: <protocol-native.c>
	flags: START_CORKED 
	state: RUNNING
	sink: 0 <alsa_output.pci-0000_00_1b.0.analog-stereo>
	volume: 0: 100%
	        0: 0.00 dB
	        balance 0.00
	muted: no
	current latency: 364.07 ms
	requested latency: 90.00 ms
	sample spec: uLaw 1ch 8000Hz
	channel map: mono
	             Mono
	resample method: speex-float-1
	module: 8
	client: 45 <Totem Movie Player>
	properties:
		media.name = "Playback Stream"
		application.name = "Totem Movie Player"
		native-protocol.peer = "UNIX socket client"
		native-protocol.version = "16"
		media.role = "video"
		application.process.id = "3242"
		application.process.user = "l11"
		application.process.host = "ldm"
		application.process.binary = "totem"
		application.icon_name = "totem"
		window.x11.display = ":0.0"
		application.language = "en_US.UTF-8"
		application.process.machine_id = "b233a67ef7272ba2a039427c4b5e552d"
		application.process.session_id = "b233a67ef7272ba2a039427c4b5e552d-1269879906.377950-1910608641"
		module-stream-restore.id = "sink-input-by-media-role:video"
>>> 
然后使用

代码: 全选

pacmd "set-sink-input-volume $index $volume"
设置音量。$index通过上面的查询获得,$volume介于0和65536(0x10000)之间

以上内容参考自:

http://ubuntu-ky.ubuntuforums.org/showt ... ?p=8720929

http://www.pulseaudio.org/wiki/CLI

具体脚本怎么写,怎么分析查询的输出……好麻烦……楼主我看你骨骼清奇,天资异禀,必然是雄霸一方的linux霸主,这点区区小事,肯定难不倒您老人家的
头像
潇洒走一回
帖子: 735
注册时间: 2009-05-20 21:43

Re: 有没有办法临时禁止其它程序播放声音?

#7

帖子 潇洒走一回 » 2010-03-30 16:45

感谢 foolegg 提醒, 我已经搞定!
下面的脚本在执行 参数1 中的命令 之前, 会暂停(发送STOP信号)所有使用 pulse audio 的进程的执行! 完成任务后恢复现场!

代码: 全选

#!/bin/sh
#@Name: stop-paserver-while
#@Action: 在执行参数提供的命令时, 停止所有使用 PulseAudio 进程的执行,
#并在完成任务后恢复现场...
#@Usage: stop-paserver-while COMMANDs

PLAYERS=`pacmd list-sink-inputs | egrep application.process.id | \
	sed -E 's/^[^=]+= *"([^"]+)"$/\1/'`

echo kill -STOP $PLAYERS
kill -STOP $PLAYERS

echo $1 | sh	#执行参数传递的命令.

echo kill -CONT $PLAYERS	#恢复现场
kill -CONT $PLAYERS	#恢复现场
下面的脚本(smart-play)用来包装星际译王使用的 aplay 程序(在首选项中将发音命令改为smart-play)

代码: 全选

#!/bin/sh
#@Name: smart-play
#@Info: aplay 发音程序的包装
#@Action: 用于在stardict播放声音文件时, 暂停音乐的播放

# 短暂的停顿(sleep)是为了避免和其它声音混在一起, 难以分辨.
stop-paserver-while "sleep 0.5; aplay $1; sleep 1"
再次感谢 foolegg!!!
上次由 潇洒走一回 在 2010-03-30 19:49,总共编辑 1 次。
头像
潇洒走一回
帖子: 735
注册时间: 2009-05-20 21:43

Re: 有没有办法临时禁止其它程序播放声音?

#8

帖子 潇洒走一回 » 2010-03-30 17:17

刚写了一个更加智能的 smart-play, 在星际译王的主窗口上, 当鼠标划过某些按钮时, 会发出响铃声...这也会调用我们设置smart-play程序, 我当然不希望这些响铃声干扰我听音乐, 于是拒绝了这样的请求...

代码: 全选

#!/bin/sh
#@Name: smart-play
#@Info: aplay 发音程序的包装
#@Action: 用于在stardict播放声音文件时, 暂停音乐的播放

# 当鼠标触碰到某些按钮时, 拒绝星际译王的发音请求,
# 如果声音文件不是来自以下两个词库, 就忽略请求!
[ `expr substr "$1" 12 4` != "Wyab" ] && \
[ `expr substr "$1" 12 4` != "OtdR" ] && exit 0

# 短暂的停顿(sleep)是为了避免和其它声音混在一起, 难以分辨.
stop-paserver-while "sleep 0.5; aplay $1; sleep 1"
头像
foolegg
帖子: 249
注册时间: 2007-12-01 14:56

Re: 有没有办法临时禁止其它程序播放声音?

#9

帖子 foolegg » 2010-03-30 17:34

其实我觉得不用stop这么暴力,音乐突然暂停几秒又恢复感觉很奇怪

把音量调轻点,能听清读音就好了吧

代码: 全选

INDEX=`pacmd list-sink-inputs | egrep index | \
    sed xxxxxx
echo INDEX | xargs pacmd xxxxx.....
 
这样怎么样?(我不会写正则,就劳烦楼主大侠了)
头像
潇洒走一回
帖子: 735
注册时间: 2009-05-20 21:43

Re: 有没有办法临时禁止其它程序播放声音?

#10

帖子 潇洒走一回 » 2010-03-30 18:16

foolegg 写了:其实我觉得不用stop这么暴力,音乐突然暂停几秒又恢复感觉很奇怪

把音量调轻点,能听清读音就好了吧

代码: 全选

INDEX=`pacmd list-sink-inputs | egrep index | \
    sed xxxxxx
echo INDEX | xargs pacmd xxxxx.....
 
这样怎么样?(我不会写正则,就劳烦楼主大侠了)
我倒很喜欢暂停的感觉, 之后依然接着原来的位置放... 不会感觉突兀, 因为有心理准备啊...

稍等, 我想下怎么解决你的问题, 问题之一就是在把音量调小之前, 需要把当前音量大小保存下来以恢复现场, 可是 pacmd list-sink-inputs 输出中仅包含当前音量的一个百分值, 你之前说volume的最大值是65536我不知道是如何获取的. 还有, 如果有多个播放声音的进程的话还要分析出哪个index对应哪个volume, 我就假设你只有一个播放声音的进程吧...
头像
foolegg
帖子: 249
注册时间: 2007-12-01 14:56

Re: 有没有办法临时禁止其它程序播放声音?

#11

帖子 foolegg » 2010-03-30 18:52

我从pulseaudio的wiki查到的
volume的取值从0(静音)到65536(正常音量)之间,我觉得就是说,0-65535对应0%-100%
你把一次pacmd list-sink-inputs的输出保存下来,分析一下,可以找到index,app name,volume之间的对应关系
我可以用python写出来,但用正则不会写……
头像
潇洒走一回
帖子: 735
注册时间: 2009-05-20 21:43

Re: 有没有办法临时禁止其它程序播放声音?

#12

帖子 潇洒走一回 » 2010-03-30 19:32

好吧, 用shell写的, 有一个命令调用了python2.X...
临时降低其它程序的音量:

代码: 全选

#!/bin/bash

maxvolume=65536

index=`pacmd list-sink-inputs | grep index | sed -E 's/^ *index: *//'`

#以分数形式保存百分比:
percentage=\
`pacmd list-sink-inputs|grep volume|sed -E 's/^.+: *([[:digit:]]+)%$/\1/'`/100

#使用python作为计算器, 得出原始的 volume 值:
origvolume=`echo "print int($maxvolume * ($percentage.0))" | python`

#将index的volume值设置为原始值的1/3:
lowervolume=$[$origvolume/3]
echo pacmd "set-sink-input-volume $index $lowervolume"
pacmd "set-sink-input-volume $index $lowervolume"

#Here play your own sond while quiet
#...
#For example:
#echo $1 | sh

#然后把 volume 值还原为原始值
echo pacmd "set-sink-input-volume $index $origvolume"
pacmd "set-sink-input-volume $index $origvolume"

上次由 潇洒走一回 在 2010-03-31 17:16,总共编辑 2 次。
头像
潇洒走一回
帖子: 735
注册时间: 2009-05-20 21:43

Re: 有没有办法临时禁止其它程序播放声音?

#13

帖子 潇洒走一回 » 2010-03-30 19:35

把里面的 #echo $1 | sh
一行的注释去掉, 执行:
./lower-paservers-while "sleep 3"
效果还是不错的, 比突然刹车的效果要好!
头像
潇洒走一回
帖子: 735
注册时间: 2009-05-20 21:43

Re: 有没有办法临时禁止其它程序播放声音?

#14

帖子 潇洒走一回 » 2010-03-30 19:46

至于当存在多个播放声音的程序时, 如何分析出哪个index对应哪个volume, 这个看起来你更需要(我使用STOP不会有此问题, 只需把所有的进程ID传给kill就行了), 就交给你来实现吧!
谢谢你的指点!
头像
潇洒走一回
帖子: 735
注册时间: 2009-05-20 21:43

Re: 有没有办法临时禁止其它程序播放声音?

#15

帖子 潇洒走一回 » 2010-03-30 22:03

补充一下, 我在 13 楼发的脚本里面, 将音量降低为原来的1/3, 但经过我的体验证明, 1/2就已经很好了, 即可以听清发音, 又不显得突兀...

另外, 你说用python可以写出来, 用正则不会写...
如果在python中不使用正则的话, 逐行逐字手工扫描文本不很费力吗?
python处理文本如果不使用正则的话, 有什么巧妙的办法?
回复