Le script core/audio.py agit comme un traducteur entre l'interface Python de GrimOS et le serveur de son natif de Linux (généralement ALSA via les commandes amixer). Il permet à la barre des tâches de lire le volume actuel et de le modifier.
subprocess : Le fichier ne s'appuie sur aucune bibliothèque externe complexe (comme PyAudio ou PulseAudio-libs). Il exécute directement des commandes shell avec subprocess.run().amixer sget Master. Il découpe ensuite la réponse texte (parsing) pour trouver une valeur en pourcentage (ex: [50%]) et l'état de la sourdine ([on] ou [off]).amixer sset Master X%.toggle_mute) qui utilise la commande amixer sset Master toggle.pactl ou wpctl au lieu d'amixer.aplay -l et permettre à l'utilisateur de choisir sa sortie audio depuis la barre des tâches.import subprocess
import re
import threading
class AudioManager:
def __init__(self, desktop):
self.desktop = desktop
self.control_name = self._find_master_control()
def _find_master_control(self):
"""Tente de trouver le contrôle principal ALSA (Master, PCM, ou autre)."""
try:
# Chercher le contrôle 'Master' en premier
res = subprocess.run(['amixer', 'sget', 'Master'], capture_output=True, text=True)
if res.returncode == 0:
return 'Master'
# Sinon, lister tous les contrôles scontrols
res = subprocess.run(['amixer', 'scontrols'], capture_output=True, text=True)
if "PCM" in res.stdout:
return "PCM"
# Prendre le premier dispo
match = re.search(r"Simple mixer control '([^']+)'", res.stdout)
if match:
return match.group(1)
except Exception:
pass
return 'Master' # Valeur par défaut de secours
def get_volume(self):
try:
res = subprocess.run(['amixer', 'sget', self.control_name], capture_output=True, text=True)
if res.returncode == 0:
# Chercher par ex: [50%]
match = re.search(r"\[(\d+)%\]", res.stdout)
if match:
return int(match.group(1))
except Exception:
pass
return 0
def set_volume(self, level):
try:
subprocess.run(['amixer', 'sset', self.control_name, f'{level}%', 'unmute'], capture_output=True)
# Démuter spécifiquement les haut-parleurs au cas où
subprocess.run(['amixer', 'sset', 'Speaker', 'unmute'], capture_output=True)
except Exception:
pass
def test_audio(self):
# speaker-test est bloquant, on le lance dans un thread
def run_test():
try:
# Test avec un son wav natif (court et reconnaissable : "Front Center")
# Si aplay ne trouve pas le fichier, speaker-test fera un bruit rose ou un bip.
res = subprocess.run(['aplay', '/usr/share/sounds/alsa/Front_Center.wav'], capture_output=True)
if res.returncode != 0:
# Fallback sur speaker-test
subprocess.run(['speaker-test', '-t', 'sine', '-f', '440', '-c', '1', '-l', '1'], timeout=2, capture_output=True)
except Exception:
pass
threading.Thread(target=run_test, daemon=True).start()