Casi todos los días escucho música en mi teléfono inteligente y uso los botones de control de los auriculares. Pero siempre no me gustó una cosa. Llego a casa, sigo escuchando, el auricular se conecta a la PC de mi casa y, de repente, los botones dejan de funcionar.
Por supuesto, busqué en Google la solución a este problema. Desafortunadamente, en Windows esta maravillosa característica no es muy compatible. Un par de minutos de búsqueda solo dieron menciones confusas en Stack Overflow sobre tarjetas de sonido y mensajes de algunas personas de que todo funcionaba bien en sus computadoras portátiles.
Esto no me asustó, y decidí aceptar el problema como un desafío interesante: ¿es posible crear algún tipo de programa para activar los botones de control, si no hay soporte de hardware para ellos? La respuesta es sí, puedes. Y aquí está cómo hacerlo en media hora.
Cómo funcionan los botones de los auriculares con Android
Lo primero que hay que entender es cómo funcionan los botones de los auriculares. Una búsqueda rápida en Internet encontró
esta especificación de la documentación de Android. Hay un cuadro allí.

Como puede comprender, cuando presiona un botón en el auricular, el circuito de una de las resistencias se cierra. De particular interés es el Botón A (Play / Pause / Hook) con una resistencia de 0 ohmios, es decir, un cortocircuito en el micrófono. Si podemos detectar un cortocircuito en el micrófono, entonces podemos determinar la presión del botón Reproducir / Pausa.
Prueba de hipótesis
Antes de comenzar la programación, me gustaría comprobar la razonabilidad de nuestro razonamiento en principio. Es decir, el hecho de que la señal del micrófono se puede determinar presionando el botón Reproducir / Pausa. Afortunadamente, para esto es suficiente simplemente grabar el sonido en la computadora y ver el resultado. Lancé Audacity, presioné el botón Reproducir / Pausa durante la grabación y recibí esa señal.
BingoComo puede ver, presionar el botón obviamente se refleja en la forma de onda: una caída repentina a -1 seguido de una transición repentina a 1 y una disminución gradual a 0. Intuitivamente por especificación, supondría que la señal salta a 1 y permanece allí hasta que se suelta el botón, pero en realidad se ve diferente. Sin embargo, una imagen así es fácil de detectar si captura la transmisión de audio del micrófono.
Captura de sonido con Python
Conociendo la forma de detectar las pulsaciones de botones en los auriculares, puede pensar en el objetivo principal: cómo controlar el reproductor en el escritorio utilizando los botones de los auriculares.
El primer paso es detectar el clic de un botón. Para hacer esto, debe tomar la transmisión de audio del micrófono y descubrir la firma distintiva que vimos anteriormente. Para simplificar, implementamos la solución en Python. Después de otra pequeña búsqueda en Internet, encontré un paquete llamado dispositivo de sonido, que le permite abstraer de la parte más difícil: la captura de audio real desde un micrófono.
Un poco de codificación nos da lo siguiente:
import sounddevice as sd SAMPLE_RATE = 1000
Tal código produce continuamente el valor promedio de cada lote de muestras. Establecemos la frecuencia de muestreo en 1000, que es terriblemente pequeña para el procesamiento de sonido (generalmente se usa 44100), pero realmente no necesitamos mucha precisión. El tamaño del bloque determina cuántas muestras en el búfer desencadenan una devolución de llamada. Nuevamente, establecemos valores muy bajos. Un tamaño de bloque de 100 y una frecuencia de muestreo de 1000 en realidad significa disparar 10 veces por segundo, donde solo se procesan 100 muestras con cada llamada.
Detección de clic de botón: probablemente demasiado fácil
Ahora capturamos la transmisión de audio y podemos implementar un mecanismo real para detectar las pulsaciones de botones. Recuerde que la señal salta a 1 cada vez que presiona. Esto sugiere la manera más fácil de detectar si el valor de la señal en
N bloques sucesivos por encima de 0,9, es decir, prensado.
Implementamos el algoritmo en nuestra función:
import sounddevice as sd SAMPLE_RATE = 1000
De hecho, lanzamos un contador interno, cuántos bloques procesados cumplen con el requisito de umbral, que simplemente se establece en 0.9, proporcionando el ruido inevitable de la muestra. Si el bloque no cumple el requisito, el contador se reinicia y comenzamos de nuevo. La variable
is_held
monitorea los disparadores para no registrarlos repetidamente si no se suelta el botón.
Control de reproducción de Windows
Ahora solo queda reemplazar el comentario
"¡Se presionó el botón!" En código real para controlar la reproducción de audio en Windows. Vuelve a Google para descubrir cómo hacer esto: resulta que puedes controlar la reproducción simulando pulsaciones de teclas con los
códigos de teclas virtuales correspondientes.
Resultó que simular pulsaciones de teclas es muy fácil con el paquete
pywin32 , que es solo un shell de Python para la API de Windows. Poniendo todo junto, podemos crear la siguiente función:
import win32api import win32con VK_MEDIA_PLAY_PAUSE = 0xB3 def toggle_play(): win32api.keybd_event(VK_MEDIA_PLAY_PAUSE, 0, 0, 0)
Y lo hicimos!
toggle_play
función
toggle_play
en el lugar del código donde el comentario
"¡Se presionó el botón!" , le permite controlar cualquier reproductor multimedia en Windows utilizando los botones del auricular Android.
Las pruebas han demostrado que el código funciona sorprendentemente bien. La única diferencia entre la funcionalidad en Android y Windows es un ligero retraso cuando presiona el botón, pero puede vivir con él.
Y entonces que pasoLa secuencia de comandos de Python consta de 51 líneas que activan los botones de los auriculares con Android en Windows. El código fuente final para este proyecto está
en Github .
¡Espera, eso no es todo!
Después de usar el programa felizmente durante varias horas, noté un problema grave:

¡El programa usa casi el 30% de la CPU! Obviamente, esto es inaceptable durante un trabajo largo, hay que hacer algo. Al mirar el código, me di cuenta de que el hilo principal está en el estado inactivo en el bucle principal, aunque no sucede nada allí. La solución más lógica es simplemente sacrificar el hilo para siempre: dado que la devolución de llamada se llama automáticamente, todavía no necesitamos un bucle.
from time import sleep if __name__ == '__main__': controller = HeadsetButtonController() while True: sleep(10)

Tampoco quería ejecutar el script Python manualmente después de cada inicio de computadora. Afortunadamente, Python para Windows viene con una útil utilidad llamada pythonw.exe que inicia el proceso del demonio sin un terminal conectado. Colocamos un acceso directo a este proceso en el directorio
Microsoft \ Windows \ Start Menu \ Programs \ Startup , especificando nuestro script como primer argumento, luego la aplicación se inicia automáticamente y se ejecuta silenciosamente en segundo plano.