Contrôles média
Publie les métadonnées "Now Playing" et reçois les événements de lecture depuis le HUD OS — MPNowPlayingInfoCenter macOS, SMTC Windows, MPRIS Linux — par une seule API Kotlin.
Chaque OS moderne expose un HUD média système — Control Center sur macOS, overlay volume Windows 11, indicateurs GNOME / KDE sous Linux. L'app y apparaît avec les métadonnées et on réagit aux events play / pause / next / prev via un seul module Kotlin.
En bref
- Linux : spec MPRIS D-Bus — intégré à GNOME Shell, KDE Plasma,
playerctl. - macOS :
MPNowPlayingInfoCenter+MPRemoteCommandCenter. Intégré à Control Center, le widget Now Playing, les touches médias. - Windows :
SystemMediaTransportControls. Intégré à l'overlay Windows 10/11, SoundBar, écran de verrouillage, touches médias matérielles. - Un callback pour les events entrants, un setter pour métadonnées et état sortants.
Installation
dependencies {
implementation("dev.nucleusframework:nucleus.media-control:<version>")
}Démarrage rapide
import dev.nucleusframework.media.control.*
if (MediaControlService.isAvailable()) {
MediaControlService.configure()
MediaControlService.attach { event ->
when (event) {
MediaControlEvent.Play -> player.play()
MediaControlEvent.Pause -> player.pause()
MediaControlEvent.Next -> player.skipToNext()
MediaControlEvent.Previous -> player.skipToPrevious()
is MediaControlEvent.Seek -> player.seekTo(event.toUs)
else -> {}
}
}
MediaControlService.setMetadata(
MediaMetadata(
title = "Strobe",
artist = "deadmau5",
album = "For Lack of a Better Name",
artUri = "https://example.com/cover.png",
durationUs = 10 * 60 * 1_000_000L,
),
)
MediaControlService.setPlaybackState(
MediaPlaybackState(status = MediaPlaybackStatus.Playing, positionUs = 0, rate = 1.0),
)
}Fonctionnement
MediaControlService est un singleton qui enveloppe un pont natif par OS :
- Linux : GLib/GIO (
libgio-2.0) publie un objet D-Busorg.mpris.MediaPlayer2.Player. - macOS :
MediaPlayer.frameworkvia un pont JNI Objective-C. - Windows :
SystemMediaTransportControlsvia C++/WRL.
Configuration une fois au démarrage, puis on pousse métadonnées et état de lecture au fil de la lecture. Les events entrants arrivent sur le thread du pont — fais le marshalling vers le thread audio ou la boucle principale manuellement.
Capacités par plateforme
Les events que l'OS peut renvoyer diffèrent :
- Linux (MPRIS) peut émettre toutes les variantes de
MediaControlEvent. - macOS émet uniquement
Play,Pause,Toggle,Next,Previous,Stop,SetPosition. - Windows (SMTC) émet
Play,Pause,Next,Previous,Stop,SetPosition, plusSeekByrelatif (±10 s avance / retour). SetVolume,OpenUri,Raise,Quitsont Linux uniquement.setVolume(...)est un no-op sur macOS et Windows — le volume système est géré séparément.
Référence
Métadonnées
MediaControlService.setMetadata(
MediaMetadata(
title = "Track",
artist = "Artist",
album = "Album",
artUri = "file:///tmp/cover.png",
durationUs = 3 * 60 * 1_000_000L,
),
)État de lecture
MediaControlService.setPlaybackState(
MediaPlaybackState(
status = MediaPlaybackStatus.Playing,
positionUs = currentPositionUs,
rate = 1.0,
),
)Pousse une mise à jour à chaque démarrage, pause ou seek — la barre du HUD reflète positionUs et rate.
Listener
MediaControlService.attach { event -> /* gère */ }
MediaControlService.detach()Intégration par OS
Configurer LSApplicationCategoryType à public.app-category.music (ou media) dans l'Info.plist pour que le widget Now Playing traite le app correctement. Les touches médias matérielles livrent Play/Pause/Next/Prev quand le app est le client "now playing" actif.
L'intégration Action Center est automatique. Le système prend le dernier publisher SMTC comme source "now playing".
Mets appId correctement via NucleusApp.appId — MPRIS expose le bus name comme org.mpris.MediaPlayer2.<appId>. playerctl et les indicateurs découvrent le player par énumération de ce préfixe.
Notes
- Appelle toujours
MediaControlService.isAvailable()avantconfigure()— sur Linux sans D-Bus session, le service se dégrade silencieusement. - Mets
setPlaybackStateà jour au moins une fois par seconde pendant la lecture, sinon la barre du HUD dérive.
Raccourcis globaux
Enregistre des raccourcis clavier au niveau OS qui se déclenchent même quand le app n'a pas le focus — lecteurs média, captures d'écran, outils d'accessibilité.
Détecteur de mode sombre
Un composable isSystemInDarkMode() réactif plus une API à base de Flow — le thème système en état live, pas une lecture unique.