Aller au contenu
Documentation
Le projet

Serveur — App et API

Appareils audio réseau

Lire les originaux sur des appareils SlimProto, UPnP AV et OpenHome avec des limites réseau explicites.

M4 commence par une lecture explicite et finie depuis le Terminal : SlimProto d’abord, puis UPnP AVTransport, OpenHome Playlist et un émetteur Google Cast expérimental. Ce sont de premiers profils de contrôle, pas un serveur Lyrion complet, une certification DLNA ni une garantie pour tous les appareils. La validation sur du matériel réel reste à faire.

Où se fait la lecture#

aede play décode localement, applique le DSP partagé et utilise normalement CPAL pour la sortie audio du système. aede cast transmet le fichier original inchangé par HTTP à un seul lecteur du réseau local. Ce lecteur le décode et gère sa sortie et son horloge. Aucune normalisation, égalisation, conversion de fréquence, dither ni compression avec pertes n’est appliqué côté serveur à ces originaux. Un format non annoncé comme compatible est refusé plutôt que converti silencieusement. Le lecteur peut avoir son propre traitement.

La vérification MD5 du FLAC décodé, effectuée pendant la lecture locale ou PCM native, ne s’exécute pas lors de ce transfert du fichier encodé : Aède ne décode pas la source ici. Les contrôles du décodeur dépendent du lecteur destinataire ; une vérification explicite de l’intégrité de la bibliothèque reste une opération distincte.

La sélection reprend celle de la lecture locale : fichier, dossier, M3U/M3U8, collection ou artiste/album/piste catalogué. Ce premier profil accepte 1 à 64 occurrences, dans l’ordre, en conservant les doublons volontaires. Il n’ajoute ni répétition, aléatoire, déplacement dans le morceau ni édition directe de file au Terminal. Garder la commande ouverte pendant la lecture. Ctrl-C demande Stop au lecteur et ferme la distribution HTTP. Un appareil déconnecté ne peut pas confirmer Stop ; un téléchargement ou état déclaré par l’appareil ne crée pas d’écoute dans l’historique.

Ce contrôleur temporaire est distinct de aede serve : il ne demande pas d’API déjà lancée et n’expose ni catalogue, comptes ni administration. Le registre permanent d’appareils et leur contrôle authentifié par une interface graphique viendront dans une étape suivante.

Le crate autonome aede-devices implémente ces protocoles et leur distribution HTTP des originaux sélectionnés. Le Terminal l’appelle directement ; Subsonic/OpenSubsonic et les autorisations de comptes restent dans aede-server. Les deux transports partagent les mêmes règles de types MIME et de plages d’octets. Le chemin Rust existant aede_server::devices réexporte le nouveau crate, sans seconde implémentation.

SlimProto#

Sur le serveur, choisir son interface et l’adresse du lecteur attendu :

aede cast /chemin/vers/album --protocol slimproto --bind 192.168.1.10 --device 192.168.1.20

Sur la machine équipée de Squeezelite, le connecter à ce serveur :

squeezelite -s 192.168.1.10:3483

Pour un essai logiciel local, les deux adresses peuvent être 127.0.0.1. Démarrer Aède d’abord : il attend le lecteur sélectionné pendant une minute au maximum. --port N change le port TCP SlimProto. Autoriser ce port et le port média temporaire affiché au lancement dans le pare-feu local. La découverte SlimProto UDP, l’API de contrôle HTTP/JSON de Lyrion et l’émulation des écrans ne sont pas fournies.

La connexion vérifie les codecs annoncés. Ce premier profil accepte FLAC, MP3 et WAV PCM entier, mono/stéréo, avec des paramètres pris en charge explicitement. Le WAV flottant et les formats inconnus/non pris en charge sont refusés. MaxSampleRate limite la sélection ; en son absence, les fréquences supérieures à 48 kHz sont refusées par prudence. La résolution FLAC doit être connue et limitée à 24 bits dans ce premier profil. Le WAV haute fréquence doit aussi avoir un code de fréquence SlimProto représentable. Toute la sélection est vérifiée avant le premier démarrage.

La fin du téléchargement ou du décodage ne signifie pas que la sortie a fini. Le passage au suivant attend les confirmations du démarrage, du décodage terminé et de la sortie vidée. Le gapless SlimProto n’est donc pas promis. Des interrogations régulières et des délais de progression bornés détectent une perte de connexion. Pause/boutons du lecteur et multiroom synchronisé restent hors de ce premier contrôleur.

UPnP AV et OpenHome#

Découvrir les lecteurs annoncés sur une interface :

aede devices --bind 192.168.1.10

Reprendre l’URL HTTP de description affichée dans la colonne Endpoint, sans inventer une adresse de contrôle :

aede cast /chemin/vers/album --protocol upnp --bind 192.168.1.10 --device http://192.168.1.20:49152/device.xml
aede cast /chemin/vers/album --protocol openhome --bind 192.168.1.10 --device http://192.168.1.20:49152/device.xml

UPnP utilise ConnectionManager/GetProtocolInfo et AVTransport/SetAVTransportURI/Play, avec des métadonnées DIDL-Lite. Un lecteur actif doit être arrêté d’abord. La file passe au suivant après confirmation de lecture puis d’arrêt. SetNextAVTransportURI n’est pas utilisé : le gapless n’est pas garanti. Les erreurs sont signalées.

ConnectionManager doit appartenir au même lecteur qu’AVTransport, y compris dans une description avec appareils intégrés. Aède vérifie GetPositionInfo/TrackURI avant de passer au suivant : une URI étrangère, ou effacée après confirmation de lecture, termine le contrôleur sans envoyer Stop à un son qu’il ne contrôle plus. Un appareil qui efface son URI en fin de piste nécessitera donc un profil de compatibilité validé séparément pour permettre l’enchaînement ; ce refus prudent évite de reprendre la lecture d’un autre contrôleur.

OpenHome vérifie Playlist/ProtocolInfo, TracksMax, répétition/aléatoire et file existante avant d’insérer la sélection ordonnée. Une file déjà remplie est refusée, sauf avec --replace, qui autorise explicitement son remplacement. Répétition ou aléatoire déjà actif sur l’appareil est refusé plutôt que changé silencieusement. L’appareil conserve la file ; Aède reste actif pour servir les originaux et détecter les modifications. Une modification extérieure termine le contrôleur. Si l’insertion échoue après certaines entrées, elles peuvent rester sur l’appareil : Stop est demandé et l’erreur signalée, sans restaurer une ancienne file. UPnP/OpenHome ne modifient pas le volume. SlimProto conserve également le gain par défaut ; --device-volume 0..100 demande explicitement un pourcentage de gain numérique linéaire (0 coupe le son, 100 est le gain unité). Un nouveau processus Squeezelite peut démarrer muet : ajouter, par exemple, --device-volume 20 à la commande Aède, puis ajuster volontairement. Ce pourcentage ne garantit pas un volume acoustique ni une échelle logarithmique.

Un type MIME compatible http-get doit être annoncé. Cette déclaration ne garantit pas les limites de canaux, résolution, fréquence ou firmware : les vérifier sur le lecteur réel. Les simulations logicielles vérifient les messages et les limites. La découverte SSDP M-SEARCH reste explicite, bornée et absente des commandes normales du catalogue.

Les entrées OpenHome terminées restent sur l’appareil, mais leurs URL temporaires expirent quand Aède se ferme. Les rejouer demande une nouvelle session : cette file ne constitue pas une bibliothèque persistante accessible depuis l’appareil.

Google Cast#

Ce premier émetteur relie Aède au port TLS Cast V2 du récepteur choisi, puis fournit les URL des originaux au Default Media Receiver de Google (CC1AD845). Il réutilise JSON, Tokio et Rustls déjà présents, sans nouveau paquet tiers ni code unsafe. C'est un profil d'interopérabilité expérimental, distinct du SDK Sender officiel et sans certification Google. Un essai sur Chromecast, Nest ou un récepteur tiers réel reste nécessaire.

Découvrir explicitement les appareils :

aede devices --bind 192.168.1.10 --protocol googlecast

Cette recherche DNS-SD interroge _googlecast._tcp.local avec réponse mDNS unicast. Elle accepte les associations PTR/SRV/TXT/A complètes dont l'adresse correspond à l'émetteur local, pendant trois secondes au maximum, avec une limite de 256 paquets et 32 appareils. Elle ne contacte pas de nom DNS annoncé. Annonces fragmentées entre plusieurs paquets, IPv6, groupes Cast, réseaux routés et authentification du récepteur restent hors de ce premier profil. Une adresse IPv4 connue peut être donnée directement si la découverte ne trouve rien ; route multicast du système et pare-feu doivent permettre d'atteindre ce réseau.

Les certificats Cast ne sont pas des certificats HTTPS publics ordinaires. Observer celui de l'appareil choisi, sans lecture ni connexion TLS déclarée de confiance :

aede devices --bind 192.168.1.10 --protocol googlecast --device 192.168.1.20

La commande affiche seulement l'empreinte SHA-256 du certificat présenté. Au premier usage, identifier indépendamment le récepteur sur un réseau de confiance, puis fournir explicitement ces 64 chiffres hexadécimaux, sans deux-points :

aede cast /chemin/vers/album --protocol googlecast --bind 192.168.1.10 --device 192.168.1.20 --device-certificate EMPREINTE_SHA256_DU_RECEPTEUR_VERIFIE

EMPREINTE_SHA256_DU_RECEPTEUR_VERIFIE est un emplacement à remplacer, pas une empreinte valide. Le port de contrôle est 8009 par défaut ; IP:PORT permet d'en préciser un autre. --port et --device-volume restent propres à SlimProto. Cast conserve le volume du récepteur. Un certificat différent bloque la lecture : réidentifier l'appareil avant de changer l'empreinte, notamment après réinitialisation ou renouvellement du certificat. Découverte et inspection ne mémorisent aucune confiance. L'empreinte exacte et les signatures TLS vérifiées prouvent la possession de la clé épinglée ; elles ne vérifient pas la chaîne d'authentification fabricant Google, les dates du certificat ou le nom d'hôte selon la PKI Web. Aucun mode de lecture n'accepte tous les certificats. Le flux média temporaire reste HTTP sur le réseau local de confiance.

Une session d'application existante est refusée sans --replace, qui autorise explicitement son remplacement. L'ordre et les occurrences répétées sont conservés. LOAD/GET_STATUS et les heartbeats sont bornés. Le suivant attend IDLE/FINISHED pour la session média courante ; annulation, interruption, état inconnu et erreur de chargement ne sont jamais une fin normale. Un changement d'application, de session ou d'identité média fournie termine le contrôleur sans arrêter une session étrangère. Ctrl-C demande Stop pour la session possédée et signale une confirmation absente ou échouée. Un chargement annulé/déconnecté sans identifiant de session peut avoir commencé sur l'appareil : Aède ferme son serveur média et indique qu'il n'a pas pu confirmer Stop. Un fichier déjà mis en tampon par le récepteur ne peut pas être rappelé.

Le profil prudent accepte FLAC, MP3, Ogg Vorbis/Opus, AAC en MP4 ou ADTS et WAV PCM entier, avec canaux mono/stéréo et fréquence connus. Les formats sans perte demandent une résolution connue jusqu'à 24 bits et une fréquence jusqu'à 96 kHz ; les formats avec perte sont limités à 48 kHz. ALAC, AIFF, WAV flottant/32 bits, conteneur non pris en charge et paramètres manquants sont refusés sans transcodage. Cette vérification de profil ne négocie pas les codecs avec chaque récepteur : décodage réel et firmware restent à tester, et un échec LOAD arrête la file. Aucun DSP, normalisation, réduction de qualité ou événement d'historique n'est appliqué. Des LOAD successifs ne garantissent ni gapless ni multiroom synchronisé. Pause/déplacement sur l'appareil peuvent être observés ; commandes interactives du Terminal, reconnexion et file Cast persistante restent à développer.

Le serveur média, limité au secret de session et à l'IP choisie, fournit GET/HEAD, byte ranges et réponses OPTIONS/CORS bornées au lecteur Web du récepteur. Seuls URL des médias sélectionnés et titres sont fournis, sans identifiants de comptes, chemins de fichiers ni accès au catalogue. Le Default Media Receiver peut dépendre des services Google ; ce protocole ne promet pas un fonctionnement entièrement hors ligne.

Références : architecture Cast, messages média, formats pris en charge et schéma CastMessage de Chromium. Google Cast est une marque de Google LLC.

Limites réseau et fichiers#

--bind et le lecteur utilisent des adresses IPv4 précises, privées, de lien local ou de boucle locale. Écoute sur toutes les interfaces, adresses publiques, DNS et IPv6 ne font pas partie de ce premier profil. Les descriptions/contrôles utilisent HTTP, sans identifiants ni fragments. Une description découverte doit correspondre à l’émetteur SSDP ; URLBase et contrôles gardent son hôte et son port. Redirections, traversées de chemin, DTD/entités XML personnalisées et messages surdimensionnés sont refusés.

Certains lecteurs anciens ne peuvent pas utiliser l’API HTTPS authentifiée d’Aède. Leur serveur média HTTP temporaire utilise donc un secret aléatoire de session, l’IP exacte du lecteur et des routes limitées à la sélection, sans accès général aux fichiers ni à l’API. Garder les URL secrètes. HTTP et ces contrôles sont réservés au réseau local de confiance, sans publication Internet. L’IP limite l’admission mais ne constitue pas une identité cryptographique.

Les originaux sont ouverts en lecture seule. Taille, date précise, statut de fichier ordinaire et identité Unix sont vérifiés à la préparation, à l’ouverture et pendant le transfert. Un fichier changé ou remplacé par un lien arrête le transfert. Quatre requêtes au maximum détiennent les places de transfert ; en-têtes, délais et files de deux blocs de 32 Kio bornent le travail et la mémoire. Byte ranges et HEAD reprennent la politique existante de distribution des originaux. Une opération du système de fichiers ou du pilote peut encore se bloquer ; l’arrêt du contrôleur borne l’attente du runtime sans promettre d’interrompre le système d’exploitation. Fichiers et tags ne sont jamais réécrits.

Validation et suite de M4#

Tester de vrais Squeezelite/Squeezebox, lecteurs UPnP/OpenHome et récepteurs Cast : FLAC/MP3/WAV, déplacement effectué par le lecteur, pause/reprise et déconnexion/reconnexion. Capturer la sortie sous charge avant toute garantie gapless ou multiroom. Ensuite : enchaînements continus, contrôles/métadonnées plus riches, registre d’appareils, API authentifiée et politique explicite de preuve d’écoute. Parcourir Aède depuis un autre contrôleur DLNA demande aussi MediaServer/ContentDirectory ; contrôler un lecteur ne fournit pas ce rôle serveur.

La roadmap distingue ces premiers profils des protocoles optionnels. Références primaires : Squeezelite, spécifications UPnP AV et service OpenHome Playlist.

Essais par la communauté#

Ces premiers adaptateurs restent expérimentaux jusqu’à validation par des retours matériels. Squeezelite permet un premier essai logiciel sans acheter de streamer ; choisir volontairement --device-volume s’il démarre avec un gain muet. Cela ne remplace pas une mesure sur une sortie physique.

Pour un retour utile : version/commit Aède, système, modèle/firmware du lecteur ou version de Squeezelite, protocole choisi, codec/conteneur, fréquence, résolution et nombre de canaux. Décrire connexion, premier son, passage de piste, pause/déplacement côté lecteur, fin de file et Ctrl-C. Joindre l’erreur exacte et une commande anonymisée. Retirer URL secrètes de session, noms privés et chemins de bibliothèque des captures/journaux.

Commencer avec un FLAC stéréo ordinaire, puis un album, un M3U avec entrée répétée, MP3 et WAV entier pris en charge. Essayer une déconnexion pendant le transfert et une file modifiée sur l’appareil. Décrire le passage entre pistes sans parler de gapless mesuré en l’absence d’une capture appropriée. Utiliser un fichier synthétique ou non privé pour une reproduction. Conserver le premier problème observé plutôt que changer plusieurs réglages à la fois.

Profil API UPnP de Phémios#

La capacité network_audio_upnp donne accès à un premier contrôle UPnP fini, réservé aux sessions nominatives administrateur, y compris l’administrateur du moteur local. Les anciens jetons administratifs, les utilisateurs et les auditeurs sont refusés. Ce profil ne fournit pas AirPlay.

  • POST /api/admin/v1/network-audio/discover reçoit { "bind": "192.168.1.10" } : c’est l’interface du serveur Aède. Une seule découverte est admise à la fois ; items contient les noms et descriptions validées.
  • POST /api/admin/v1/network-audio/play reçoit bind, device (URL de description) et 1 à 64 références exactes dans tracks. Aucun chemin libre n’est accepté et une session active ne peut pas être remplacée implicitement.
  • GET /api/admin/v1/network-audio donne {id,status} pour la connexion propriétaire uniquement, ou null. Cette consultation renouvelle son bail de cinq secondes.
  • POST /api/admin/v1/network-audio/stop reçoit {id} et exige la même connexion propriétaire. stopping désigne une demande, pas un arrêt confirmé ; les résultats terminaux distinguent completed, stopped, failed et stop_unconfirmed.

Toutes les routes de contrôle réseau revérifient la session administrateur après réception du corps de la requête. Une déconnexion ou un changement de droits pendant cette réception interdit de consulter ou renouveler une session, lancer une découverte ou une inspection de certificat, préparer la lecture ou demander Stop.

La révocation, la fermeture du serveur et la perte du bail demandent l’annulation. Un appareil muet peut conserver des données déjà reçues ; Stop reste soumis à confirmation et aucun transfert ne crée un événement d’écoute. Le registre persistant, les contrôles complets et la validation sur matériel réel restent distincts de ce premier profil. Voir le contrat détaillé.

Sélecteur commun de lecteurs réseau#

La capacité additive network_audio_profiles étend les mêmes routes administrateur à OpenHome, Cast et SlimProto. {bind} conserve le comportement UPnP ; {bind,all:true} recherche aussi OpenHome et Cast et fournit un champ protocol par appareil. La lecture accepte protocol, replace (faux par défaut) et certificate_sha256 (Cast uniquement). Les limites de 64 pistes, les contrôles de fichiers, le propriétaire exact et le bail restent communs.

POST /api/admin/v1/network-audio/inspect reçoit {bind,device} et renvoie {sha256} : il observe le certificat Cast sans lecture ni confiance automatique. L’utilisateur doit vérifier cette empreinte avant de la valider. Le remplacement d’une liste OpenHome ou d’une lecture Cast reste explicite. SlimProto nécessite une IPv4 privée renseignée manuellement, puis une connexion du lecteur à Aède sur le port 3483 dans la minute suivant le lancement.

Phémios présente un sélecteur réseau unique, dans l’ordre OpenHome, Cast, SlimProto, UPnP. Les moteurs existants transmettent directement les originaux ; les commandes locales ne deviennent pas des commandes distantes de volume, DSP ou recherche dans le morceau. La validation sur appareil réel reste nécessaire. Voir le contrat détaillé.