Existe um OSD sofisticado de notificação vertical que funciona tanto para o ALSA quanto para o pulseaudio?

15

Existe uma maneira elegante de fazer com que o OSD de notificação de volume funcione com o pulseaudio e o ALSA? No momento, os desktops padrão só funcionam com o pulseaudio para mim. Que tal um OSD vertical que eu possa usar como uma queda na substituição ou ligar na linha de comando para relatar alterações graficamente em porcentagens arbitrárias, como uma barra que se move para cima e para baixo?

A razão pela qual eu preciso que ele trabalhe com o ALSA e com o pulseaudio é que estou usando um aplicativo WINE que não funciona bem com o pulso, então eu mato o pulso antes de iniciar o aplicativo Windows para usar o ALSA sem a camada extra de abstração. Quando percebi que as teclas de volume do teclado não funcionavam sem pulso, escrevi alguns scripts bash que chamo com o Compiz ou o Openbox (configurados por meio do CCSM e lxde-rc.xml, respectivamente) para capturar o sinal de saída de pulseaudio --checke depois ajuste o volume de acordo:

vol_step_up

#!/bin/bash
pulseaudio --check
if [ $? -eq 0 ] ; then
        pactl set-sink-volume 0 -- +3db
    else
        amixer -c0 set Master playback 3+
fi

vol_step_down

#!/bin/bash
pulseaudio --check
if [ $? -eq 0 ] ; then
        pactl set-sink-volume 0 -- -3db
    else
        amixer -c0 set Master playback 3-
fi

Os scripts funcionam muito bem e são mapeados para os botões, mas não tenho mais uma boa maneira de ver o feedback visual - nem mesmo com os pulseaudio, pois estou capturando os eventos dos botões (XF86AudioLowerVolume, etc.). Obviamente, eu poderia apenas mapear as teclas de volume do ALSA para outra coisa, mas não faz sentido duplicar as teclas de atalho.

Encontrei um controle de volume python que posso chamar nos scripts acima:
https://github.com/fishman/utils/blob/master/pvol.py

pvol.py -s mostra o nível de volume atual na tela para ALSA e pulseaudio, mas é muito pequeno comparado ao OSD gnome que eu estava usando e não é vertical (barra na parte superior, OSD antigo na parte inferior):

Comparação de tamanho do OSD padrão e do pvol.py

Então, eu a ampliei e a rodei:

insira a descrição da imagem aqui

Mas, mesmo com a mudança da orientação para a vertical, o tema GTK padrão azul não é tão liso quanto o VLC (veja abaixo).

Muito do que encontrei na pesquisa de implementações de OSD são posts sobre comandos de notificação-envio que não possuem o conceito completo da barra de progresso. Caso contrário, são principalmente barras horizontais (e muitos espaços reservados de contagem nos scripts bash). Na verdade, tudo o que preciso fazer é chamar amix & pactl, para que algo simples como a barra de progresso gtk no pvol.py seja ótimo - apenas não tão azul e nem bem no meio da tela.

O VLC tem um bom exemplo do que tenho em mente quando você rola a roda do mouse no modo de tela cheia:

Barra de volume vertical VLC

É muito menos obstrutivo do que as caixas usuais que ficam no centro da tela:

Notificação de volume OSD horizontal

Toda a analogia do controle deslizante horizontal nunca fez muito sentido para mim fora do áudio panorâmico entre os alto-falantes esquerdo e direito.

Enfim, como é que as notificações padrão da área de trabalho são chamadas (especialmente o LXDE)? Eu vejo muitas postagens sobre a configuração de eventos de pressionamento de tecla, mas não muito sobre quais scripts esses eventos acionam. Que outras opções existem no departamento de fantasia vertical?

Além disso, há algum pacote que devo desinstalar para evitar a ocorrência de conflitos entre os eventos que estou manipulando por meio de comandos de script e compiz ou openbox?

Atualização: Para descobrir qual OSD eu estou usando atualmente, não mudei a maneira como manuseio o botão mudo imediatamente. Matar o xfce4-notifyd e pressionar o botão mudo gera um novo processo do xfce4-notifyd, então eu acho que o ícone do alto-falante veio de algo como o xfce4-volumed, mas na verdade não tenho esse pacote instalado ... Ah! Matar o gnome-settings-daemon interrompe o grande OSD no centro da tela.

Adão
fonte
11
NOTA: Com o LXDE, você deve matar o painel e reaparecer quando parar o pulseaudio ou o lxpanel começará a consumir a CPU.
Adam
5
Uau, que pergunta incrível e bem pensada! +1
Seth

Respostas:

10

Tudo bem, correndo o risco de responder à minha própria pergunta, eu vim com uma versão pyqt hackeada do pvol no link da pergunta acima. Se nada mais, talvez alguém possa melhorar meu código. Eventualmente, planejo me livrar das partes do script abaixo que não são utilizadas ou retirar os scripts bash da equação e ter um script pyqt para lidar com todos os eventos de botão. No momento, o OSD atinge o tempo limite a uma taxa constante desde o primeiro pressionamento do botão, em vez de permanecer ligado por um período fixo de tempo após o último pressionamento do botão.

Apenas copie, cole e salve os arquivos (com os nomes em negrito), coloque-os todos no mesmo diretório, defina os bits executáveis ​​e modifique as chamadas do sistema no script pyqt de acordo com onde quer que você os salve, ou coloque-os todos em diretório que está no seu caminho. Em seguida, mapeie os scripts de shell para comandos do Compiz, atalhos do Openbox ou algo semelhante e altere o script pyqt se você não estiver usando os botões de volume do teclado multimídia.

Nota: O nome da classe Qvol era um título de trabalho e não me preocupei em alterá-lo. Observe também que o botão mudo fica sem tratamento - este é apenas um protótipo para expressar uma possível via para o cumprimento dos recursos solicitados e atualmente não está associado a nenhum tipo de projeto hospedado ou modelo de desenvolvimento padrão. Qualquer tipo de desenvolvimento significativo derivado do código abaixo provavelmente deve pertencer ao Sourceforge, GitHub ou a um site de projeto. Dito isto, fique à vontade para editar esta resposta ou sugerir um projeto existente que permita uma função e design semelhantes.

pqvol

vol_step_down

#!/bin/bash
pulseaudio --check
#if [ $? -ne 0 ] ; then
if [ $? -eq 0 ] ; then
        pactl set-sink-volume 0 -- -3db
    else
        amixer -c0 set Master playback 3-
fi

if [ -z "$1" ] ; then
        pqvol -s
fi

vol_step_up

#!/bin/bash
pulseaudio --check
#if [ $? -ne 0 ] ; then
if [ $? -eq 0 ] ; then
        pactl set-sink-volume 0 -- +3db
    else
        amixer -c0 set Master playback 3+
fi

if [ -z "$1" ] ; then
    pqvol -s
fi

pqvol

#!/usr/bin/env python2

# pvol -- Commandline audio volume utility
#         with an optional GTK progressbar
# Copyright (C) 2009 Adrian C. <anrxc_sysphere_org>
# Modified by 2011 Reza Jelveh
# Ported to pyqt and renamed to pqvol 2013 by Adam R.

# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.


import os.path
import optparse
import alsaaudio
import sys
from PyQt4 import QtGui, QtCore
from PyQt4.QtCore import QTimer

appname = "Qvol"
#appicon = "/usr/share/icons/ubuntu-mono-light/status/24/audio-volume-high-panel.svg"

DEFAULT_STYLE = """
QProgressBar{
    border: 2px solid grey;
    border-radius: 5px;
    background-color: transparent;
}

QProgressBar::chunk {
    background-color: Gainsboro;
}
"""

class AlsaMixer():
    def __init__(self, pcm=False, mute=False, arg=None):
        self.mixer = alsaaudio.Mixer()
        self.percent = self.mixer.getvolume()[0]
        print self.percent
        self.label = "dB" #% name
        if arg:
            self.percent = min(100, max(0, self.percent + int(arg)))
            self.mixer.setvolume(self.percent)
        if mute:
            mutestate = self.mixer.getmute()[0]
            if mutestate:
                self.label = "Unmuted: "
            else:
                self.label = "Muted: "

            self.mixer.setmute(mutestate^1)
 #     self.label = self.label + "%.0f%%" % self.percent

class Qvol(QtGui.QWidget):

    def __init__(self):
        super(Qvol, self).__init__()
#       self.setWindowFlags(QtCore.Qt.WindowStaysOnTopHint)
        self.setWindowFlags(QtCore.Qt.FramelessWindowHint)
        self.setWindowFlags(QtCore.Qt.Popup)
        self.setAttribute(QtCore.Qt.WA_TranslucentBackground)
        self.setWindowTitle("Qvol")
        self.initUI()

    def initUI(self):     

        self.pbar = QtGui.QProgressBar(self)
        self.pbar.setGeometry(5, 5, 20, 470)
        self.pbar.setOrientation(QtCore.Qt.Vertical)
        self.pbar.setRange(0,100)
        volume = AlsaMixer()
        self.pbar.setValue(volume.percent)
        self.pbar.setTextVisible(False)
        self.setStyleSheet(DEFAULT_STYLE)

        self.setGeometry(1260, 180, 30, 480)
        self.setWindowTitle('QtGui.QProgressBar')
        self.show()


        QTimer.singleShot(2000, finished)

    def keyPressEvent(self, event):
        if event.key()==QtCore.Qt.Key_VolumeMute:
#           QtGui.QWidget.paintEvent()
            finished()
        elif event.key()==QtCore.Qt.Key_VolumeDown:
            launch_process ("vol_step_down silent")
            volume=AlsaMixer()
            self.pbar.setValue(volume.percent)
#           finished()
        elif event.key()==QtCore.Qt.Key_VolumeUp:
            launch_process ("vol_step_up silent")
            volume=AlsaMixer()
            self.pbar.setValue(volume.percent)
#           finished()

#       else:
#           QtGui.QWidget.keyPressEvent(self, event)


processes = set([])

def launch_process(process):
    # Do something asynchronously
    proc = QtCore.QProcess()
    processes.add(proc)
    proc.start(process)
    proc.waitForFinished(-1)

def finished():
    print "The process is done!"
    # Quit the app
    QtCore.QCoreApplication.instance().quit()


def main():

    app = QtGui.QApplication(sys.argv)
    ex = Qvol()
    sys.exit(app.exec_())


if __name__ == '__main__':
    main()  
Adão
fonte
Os argumentos "silenciosos" para os scripts bash da etapa de volume são uma espécie de truque falso - na verdade, os scripts não fazem nada com o argumento além de testar se ele existe. Então você pode conectar qualquer coisa com o mesmo efeito.
Adam