¿Existe un elegante OSD de notificación vertical que funcione tanto para ALSA como para pulseaudio?

15

¿Hay alguna forma elegante de hacer que la OSD de notificación de volumen funcione con pulseaudio y ALSA? En este momento, las de escritorio estándar solo funcionan con pulseaudio para mí. ¿Qué tal un OSD vertical que puedo usar como una caída en el reemplazo o llamar desde la línea de comando para informar gráficamente los cambios en porcentajes arbitrarios, como una barra que se mueve hacia arriba y hacia abajo?

La razón por la que necesito que funcione tanto con ALSA como con pulseaudio es que estoy usando una aplicación WINE que no funciona bien con el pulso, por lo que elimino el pulso antes de iniciar la aplicación de Windows para usar ALSA sin la capa de abstracción adicional. Cuando me di cuenta de que las teclas de volumen en mi teclado no funcionaban sin pulso, escribí algunos scripts de bash que llamo con Compiz u Openbox (configurados a través de CCSM y lxde-rc.xml, respectivamente) para captar la señal de salida de pulseaudio --checky luego ajuste el volumen en consecuencia:

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

Los scripts funcionan muy bien y se asignan a los botones muy bien, pero ya no tengo una buena forma de ver los comentarios visuales, ni siquiera con los de pulseaudio ya que estoy captando los eventos de los botones (XF86AudioLowerVolume, etc.). Obviamente, podría asignar las teclas de volumen ALSA a otra cosa, pero no tiene sentido duplicar las teclas de acceso directo.

Encontré un control de volumen de Python al que puedo llamar en los scripts anteriores:
https://github.com/fishman/utils/blob/master/pvol.py

pvol.py -s muestra el nivel de volumen actual en pantalla para ALSA y pulseaudio, pero es terriblemente pequeño en comparación con el OSD de gnomo que había estado usando, y no es vertical (barra en la parte superior, OSD antiguo en la parte inferior):

Comparación de tamaño de OSD estándar y pvol.py

Entonces, lo hice más grande y lo dejé caer:

ingrese la descripción de la imagen aquí

Pero, incluso al cambiar la orientación a una vertical, el tema GTK predeterminado azul no es tan elegante como VLC (ver más abajo).

Gran parte de lo que he encontrado al buscar implementaciones de OSD son publicaciones sobre comandos de notificación y envío que carecen de todo el concepto de barra de progreso. De lo contrario, se trata principalmente de barras horizontales (y muchos marcadores de posición de conteo dentro de los scripts de bash). Realmente, todo lo que necesito hacer es llamar a amix & pactl, por lo que algo simple como la barra de progreso gtk en pvol.py sería genial, simplemente no tan azul y no justo en el medio de la pantalla.

VLC tiene un buen ejemplo de lo que tengo en mente al desplazar la rueda del mouse en modo de pantalla completa:

Barra de volumen vertical VLC

Es mucho menos obstructivo que las cajas habituales que se encuentran en el centro de la pantalla:

Notificación de volumen horizontal OSD

Toda la analogía del control deslizante horizontal nunca ha tenido mucho sentido para mí fuera del panorama del audio entre los altavoces izquierdo y derecho.

De todos modos, ¿cómo es que se llaman las notificaciones de escritorio predeterminadas (especialmente LXDE)? Veo muchas publicaciones sobre la configuración de eventos de pulsación de teclas, pero no mucho sobre qué scripts desencadenan esos eventos. ¿Qué otras opciones hay en el departamento de lujo vertical?

Además, ¿hay algún paquete que deba desinstalar para evitar que surjan conflictos entre los eventos que estoy manejando a través de scripts y comandos compiz o openbox?

Actualización: en aras de averiguar qué OSD estoy usando actualmente, no cambié la forma en que manejo el botón de silencio de inmediato. Al matar a xfce4-notifyd y luego presionar el botón de silencio se genera un nuevo proceso de xfce4-notifyd, así que supuse que el ícono del altavoz grande provenía de algo como xfce4-volumed, pero en realidad no tengo ese paquete instalado ... ¡Ah, ja! Matar a gnome-settings-daemon detiene el gran OSD en el centro de la pantalla.

Adán
fuente
1
NOTA: con LXDE, debe eliminar el panel y volver a generarlo cuando detenga pulseaudio o lxpanel comenzará a consumir la CPU.
Adam
55
¡Qué pregunta tan maravillosa y bien pensada! +1
Seth

Respuestas:

10

Muy bien, a riesgo de responder mi propia pregunta, se me ocurrió un poco de una versión pirateada de pvol de pvol desde el enlace en la pregunta anterior. Por lo menos, tal vez alguien más pueda mejorar mi código. Eventualmente, planeo deshacerme de las partes en la secuencia de comandos a continuación que no se usan o eliminar las secuencias de comandos bash de la ecuación y hacer que una secuencia de comandos pyqt maneje todos los eventos de botón. En este momento, el OSD se agota a un ritmo constante desde la primera vez que se presiona el botón en lugar de permanecer encendido durante un período de tiempo fijo después de la última vez que se presiona el botón.

Simplemente copie, pegue y guarde los archivos (con los nombres en negrita), póngalos en el mismo directorio, configure los bits ejecutables y modifique las llamadas del sistema en el script pyqt de acuerdo con el lugar donde los guarde, o póngalos todos en directorio que está en su camino. Luego, asigne los scripts de shell a los comandos de Compiz, los atajos de Openbox o algo similar, y cambie el script de pyqt si no está utilizando los botones de volumen del teclado multimedia.

Nota: El nombre de clase Qvol era un título funcional, y no me molesté en cambiarlo. Tenga en cuenta también que el botón de silencio no se controla: este es solo un prototipo para expresar una posible vía para cumplir con las características solicitadas, y actualmente no está asociado con ningún tipo de proyecto alojado o modelo de desarrollo estándar. Cualquier tipo de desarrollo significativo derivado del siguiente código probablemente debería pertenecer a Sourceforge, GitHub o un sitio web del proyecto. Dicho esto, siéntase libre de editar esta respuesta o sugerir un proyecto existente que permita que sea similar en función y diseño.

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án
fuente
Los argumentos "silenciosos" para los scripts de bash de paso de volumen son una especie de truco ficticio: los scripts en realidad no hacen nada con el argumento aparte de probar si existe. Entonces puedes enchufar cualquier cosa con el mismo efecto.
Adam