IcecastKit

Quand vous écoutez une webradio ou un live audio en ligne, il y a un serveur derrière qui reçoit le flux d'un diffuseur et le redistribue aux auditeurs. Ce serveur, c'est souvent Icecast — un projet open-source créé par la fondation Xiph.org — ou SHOUTcast, son équivalent historique.

Le principe : un client source se connecte au serveur, envoie un flux audio continu (MP3, AAC, Ogg…), et le serveur le redistribue à tous les auditeurs connectés en HTTP. Simple en apparence, mais le protocole a ses subtilités — négociation PUT vs SOURCE, authentification HTTP Basic ou par mot de passe en clair, métadonnées ICY binaires à intercaler dans le flux, ports source automatiques pour SHOUTcast, et gestion des déconnexions.

En travaillant sur l'écosystème streaming d'Atelier Socle — PodcastFeedMaker pour les flux RSS, HLSKit pour le HTTP Live Streaming — il manquait la brique de diffusion live vers les serveurs Icecast et SHOUTcast. Pas un wrapper autour d'une lib C, pas un script shell — un vrai client Swift natif, avec la concurrence structurée de Swift 6.2, zéro dépendance dans le cœur, et un transport TCP cross-platform (Network.framework sur Apple, sockets POSIX sur Linux).

J'ai cherché. Rien n'existait en Swift. IcecastKit est née de ce besoin.

La version 0.2.0 — Broadcast Engine — transforme IcecastKit d'un simple client de streaming en un véritable moteur de diffusion : bitrate adaptatif avec détection de congestion, publication multi-destination simultanée, sondage de bande passante, scoring de qualité de connexion, enregistrement local avec rotation de fichiers, relay/ingest depuis des flux existants, authentification avancée (Digest, Bearer, query token), presets serveur pour 7 plateformes, et export de métriques Prometheus et StatsD. Le tout avec 1246 tests et 97.13% de couverture.

La version 0.3.0 ajoute le wrapping ADTS (ISO 13818-7) pour envoyer de l'AAC brut sans se soucier du framing, active TCP_NODELAY sur les deux couches transport pour éliminer le buffering de Nagle sur les petites trames audio, et déplace le monitoring hors du chemin critique d'envoi. 1281 tests.

Nouveautés de la version 0.2.0

La version 0.2.0 — Broadcast Engine — ajoute 9 modules majeurs :

  • Bitrate adaptatif — Détection de congestion basée sur EWMA avec politiques configurables (conservative, responsive, aggressive, custom)

  • Multi-destination — Streaming simultané vers plusieurs serveurs avec isolation des pannes

  • Sondage de bande passante — Mesure de la bande passante upload avant le streaming avec recommandations de bitrate par format

  • Qualité de connexion — Score composite (0.0–1.0) à partir de cinq métriques pondérées avec recommandations automatiques

  • Enregistrement de flux — Enregistrement local avec rotation par taille/durée et tokens de nommage de fichiers

  • Relay / Ingest — Pull audio depuis des flux Icecast/SHOUTcast existants avec démuxage ICY

  • Authentification avancée — Digest (RFC 7616), Bearer token, query token, et credentials embarqués dans l'URL

  • Presets serveur — Configuration en une ligne pour AzuraCast, LibreTime, Radio.co, Centova Cast, SHOUTcast DNAS, Icecast Official, et Broadcastify

  • Export de métriques — Exporteurs Prometheus (OpenMetrics) et StatsD avec labels automatiques par destination

Nouveautés de la version 0.3.0

La version 0.3.0 ajoute le wrapping ADTS et des optimisations de transport :

  • Wrapping ADTS — API send(rawAAC:audioConfiguration:) pour envoyer de l'AAC brut : IcecastKit ajoute automatiquement le header ADTS 7 bytes (ISO 13818-7). AudioConfiguration pour sample rate, channels et profil AAC (LC, Main, SSR, LTP). Détection isADTS() pour les données déjà encapsulées

  • TCP_NODELAY — Activé par défaut sur les deux couches transport (Network.framework et POSIX) pour éliminer le buffering de Nagle (~200ms) sur les petites trames AAC (200-400 bytes)

  • Chemin d'envoi optimisé — L'enregistrement des métriques (bytes envoyés, latence, condition réseau, écriture recorder) est déplacé hors du do/catch critique pour ne s'exécuter qu'après un envoi réussi

Wrapping ADTS (0.3.0)

La nouvelle API send(rawAAC:audioConfiguration:) permet d'envoyer la sortie brute d'un encodeur AAC sans se soucier du framing ADTS. IcecastKit construit automatiquement le header 7 bytes conforme ISO 13818-7 avec le sync word, le profil, l'index de sample rate, la configuration des canaux et la longueur de trame :

Ce que fait IcecastKit

IcecastKit est une bibliothèque Swift pure pour streamer de l'audio vers des serveurs Icecast et SHOUTcast. Elle couvre l'ensemble du cycle de vie d'une diffusion : connexion, authentification, envoi du flux audio, mise à jour des métadonnées, statistiques temps réel, et déconnexion propre. Le tout avec conformité Sendable stricte de bout en bout.

  • Icecast 2.x — Protocole HTTP PUT (moderne, Icecast 2.4+) et protocole SOURCE legacy avec fallback automatique pour les serveurs pré-2.4.0

  • SHOUTcast v1/v2 — Authentification par mot de passe pour serveurs mono-flux (v1) et multi-flux avec stream IDs (v2), avec calcul automatique du port source (port listener + 1)

  • Métadonnées ICY — Encodage/décodage complet du format binaire wire avec support Unicode (CJK, emoji), quotes échappées, blocs zero-padded, et intervalles configurables

  • API Admin — Mise à jour des métadonnées côté serveur via /admin/metadata, statistiques globales via /admin/stats, et stats par mountpoint avec nombre d'auditeurs, bitrate, genre et durée de connexion

  • Reconnexion automatique — Backoff exponentiel avec jitter configurable, limite de tentatives, plafond de délai, et quatre presets (.default, .aggressive, .conservative, .none). Les erreurs non récupérables (auth, conflit mountpoint) sautent la reconnexion

  • Monitoring temps réel — Bus d'événements basé sur AsyncStream avec 7 types d'événements (connected, disconnected, reconnecting, metadataUpdated, error, statistics, protocolNegotiated), calcul de bitrate en fenêtre glissante, et snapshots statistiques périodiques

  • Cross-platform — macOS 14+, iOS 17+, tvOS 17+, watchOS 10+, visionOS 1+, et Linux (Ubuntu 22.04+ avec Swift 6.2)

  • Bitrate adaptatif — Détection de congestion basée sur EWMA avec trois presets et politiques custom, paliers de qualité par format (MP3, AAC, Opus, Vorbis), et événements BitrateRecommendation

  • Multi-destination — Actor MultiIcecastClient pour streamer vers plusieurs serveurs avec connexions indépendantes, isolation des pannes, ajout/suppression live, et statistiques agrégées

  • Sondage de bande passanteIcecastBandwidthProbe mesure la bande passante upload, la latence et la stabilité avant le streaming, avec recommandations de bitrate par format

  • Qualité de connexion — Score de qualité composite (0.0–1.0) à partir de cinq métriques pondérées (latence d'écriture, débit, stabilité, succès d'envoi, reconnexion) avec QualityGrade et recommandations automatiques

  • Enregistrement de flux — Actor StreamRecorder écrit l'audio sur disque avec rotation par taille/durée, tokens de nommage ({date}, {mountpoint}, {index}), et extensions par format

  • Relay / ingest — Actor IcecastRelay pull l'audio depuis des flux existants avec démuxage ICY des métadonnées, détection du content type, et chaînes relay-to-publish/relay-to-record

  • Authentification avancée — Enum IcecastAuthentication avec Digest (RFC 7616, MD5/SHA-256), Bearer token, query token, SHOUTcast v1/v2, parsing de credentials depuis l'URL, et stripping de credentials

  • Presets serveurIcecastServerPreset avec 7 configurations en une ligne (AzuraCast, LibreTime, Radio.co, Centova Cast, SHOUTcast DNAS, Icecast Official, Broadcastify)

  • Export de métriques — Protocole IcecastMetricsExporter avec PrometheusExporter (OpenMetrics, 8 métriques, callback onRender) et StatsDExporter (UDP POSIX), labels automatiques, export périodique

  • Outil CLIicecast-cli pour streamer, sonder la bande passante, relayer, tester les connexions et diagnostiquer les serveurs avec sortie colorée et codes de sortie structurés

  • Swift 6.2 strict concurrency — Actors pour les types stateful, Sendable partout, async/await de bout en bout, zéro @unchecked Sendable ou nonisolated(unsafe)

  • Zéro dépendance core — Le target IcecastKit n'a aucune dépendance tierce. Seul swift-argument-parser pour le CLI et swift-crypto conditionnellement sur Linux

Quick start

Se connecter à un serveur Icecast, streamer de l'audio, mettre à jour les métadonnées now-playing, et se déconnecter proprement — en quelques lignes :

Installation

Via Swift Package Manager, en ajoutant la dépendance dans votre Package.swift :

Puis dans le target concerné :

Plateformes supportées

PlateformeVersion minimum

macOS

14+

iOS

17+

tvOS

17+

watchOS

10+

visionOS

1+

Linux

Swift 6.2 (Ubuntu 22.04+)

Le transport TCP s'adapte automatiquement : Network.framework sur les plateformes Apple, sockets POSIX sur Linux.

Standards implémentés

StandardVersionRéférence

Icecast Source Protocol

2.5.0

ICY Metadata Protocol

SHOUTcast DNAS

2.6.1

HTTP Basic Auth

RFC 7617

HTTP Digest Auth

RFC 7616

ADTS / AAC Transport

ISO 13818-7

Streaming Icecast PUT avec infos station

On peut configurer une station complète avec nom, genre, bitrate, sample rate et canaux. Le client négocie automatiquement le meilleur protocole — HTTP PUT d'abord, puis fallback vers SOURCE legacy si le serveur est pré-2.4.0 :

Configuration par URL

On peut parser une URL de connexion en configuration + credentials en un seul appel. Les schémas icecast://, shoutcast://, http:// et https:// sont supportés :

SHOUTcast v1 et v2

SHOUTcast v1 utilise une authentification par mot de passe seul. IcecastKit se connecte automatiquement au port source (port listener + 1) et envoie le mot de passe suivi des headers icy-* :

SHOUTcast v2 étend v1 avec les stream IDs pour les serveurs multi-flux. Le mot de passe est envoyé sous la forme password:#streamId :

Monitoring temps réel

Le bus d'événements basé sur AsyncStream permet de réagir en temps réel aux changements d'état de connexion, mises à jour de métadonnées, erreurs, et statistiques périodiques :

Reconnexion automatique

IcecastKit gère la reconnexion automatique quand une connexion est perdue en cours de streaming. Quatre presets sont disponibles, et les politiques custom sont supportées avec jitter pour éviter les problèmes de thundering herd :

Le délai de reconnexion suit la formule : min(initialDelay × backoffMultiplier^attempt, maxDelay) ± jitter. Les erreurs non récupérables (échec d'authentification, mountpoint occupé, content type rejeté) passent directement à l'état .failed sans tentative de reconnexion. Appeler disconnect() pendant la reconnexion annule la boucle immédiatement.

Métadonnées ICY

IcecastKit gère l'encodage et le décodage complet du format binaire ICY pour l'insertion inline dans le flux. Support Unicode, quotes échappées, et champs custom :

Interleaving de métadonnées

Le MetadataInterleaver insère des blocs de métadonnées dans un flux audio à intervalles fixes. C'est un actor qui garde la trace de sa position entre les appels, ce qui permet d'envoyer l'audio par chunks de n'importe quelle taille :

API Admin

La mise à jour des métadonnées côté serveur via l'API HTTP admin Icecast est la méthode privilégiée (plutôt que l'insertion inline). On peut aussi interroger les statistiques globales et par mountpoint :

Quand des adminCredentials sont définies sur IcecastConfiguration, IcecastClient.updateMetadata() utilise automatiquement l'API admin et bascule sur les métadonnées inline si l'endpoint admin renvoie un 404 :

Détection du content type

IcecastKit détecte automatiquement le content type audio à partir de l'extension du fichier :

Opérations concurrentes

IcecastClient est un actor — toutes les opérations sont thread-safe par construction. On peut appeler send() et updateMetadata() depuis plusieurs tâches concurrentes sans data race :

Bitrate adaptatif

IcecastKit surveille les conditions réseau en temps réel et émet des recommandations de bitrate. Le NetworkConditionMonitor détecte la congestion via des pics de latence EWMA, des pics de RTT et des ralentissements de bande passante. AudioQualityStep fournit des paliers de bitrate par format (MP3 : 7 paliers de 32 à 320 kbps, plus AAC, Opus, Vorbis). Trois presets (conservative, responsive, aggressive) plus une configuration custom complète :

Publication multi-destination

L'actor MultiIcecastClient permet de streamer vers plusieurs serveurs simultanément avec des connexions indépendantes et une isolation des pannes. On peut ajouter ou retirer des destinations à chaud pendant le streaming. Chaque destination a sa propre politique de reconnexion :

Sondage de bande passante

IcecastBandwidthProbe mesure la bande passante upload et la latence avant de lancer un stream live. Le résultat inclut la bande passante mesurée, la latence moyenne d'écriture, la classe de latence, un score de stabilité et une recommandation de bitrate adaptée au format :

Qualité de connexion

Le scoring de qualité de connexion fournit un score composite (0.0–1.0) calculé à partir de cinq métriques pondérées : latence d'écriture (30%), débit (25%), stabilité (20%), succès d'envoi (15%), reconnexion (10%). Le QualityGrade est Comparable et cinq niveaux sont définis :

Les événements de qualité arrivent via le bus d'événements : .qualityChanged(_:) et .qualityWarning(_:).

Enregistrement de flux

L'actor StreamRecorder écrit l'audio sur disque avec rotation automatique des fichiers. La rotation peut se faire par taille maximale ou par durée. Les noms de fichiers supportent des tokens dynamiques ({date}, {mountpoint}, {index}) et les extensions sont détectées automatiquement par format :

L'enregistrement s'intègre avec IcecastClient via IcecastConfiguration.recording pour un démarrage automatique. Événements émis : .recordingStarted, .recordingStopped, .recordingFileRotated.

Relay / Ingest

L'actor IcecastRelay permet de puller de l'audio depuis un flux Icecast ou SHOUTcast existant. Il gère le démuxage des métadonnées ICY, la détection du content type, et peut être chaîné avec IcecastClient pour un relay-to-publish ou avec StreamRecorder pour un relay-to-record :

Authentification avancée

IcecastKit supporte six méthodes d'authentification via l'enum IcecastAuthentication. Au-delà du HTTP Basic classique et du mot de passe SHOUTcast, la version 0.2.0 ajoute Digest (RFC 7616 avec MD5 et SHA-256 — le mot de passe ne transite jamais en clair), Bearer token, query token, et le parsing/stripping automatique de credentials depuis les URLs :

TypeDescription

.basic

HTTP Basic (RFC 7617)

.digest

HTTP Digest (RFC 7616, MD5/SHA-256)

.bearer

Bearer token

.queryToken

Token dans la query string de l'URL

.shoutcast

SHOUTcast v1 mot de passe seul

.shoutcastV2

SHOUTcast v2 avec stream ID

Presets serveur

IcecastServerPreset fournit une configuration en une ligne pour 7 plateformes de streaming populaires. Port, méthode d'authentification, protocole et mountpoint par défaut sont préconfigurés :

PresetPortAuthProtocole

.azuracast

8000

Basic

Icecast PUT

.libretime

8000

Basic

Icecast PUT

.radioCo

8000

Bearer

Icecast PUT

.centovaCast

8000

SHOUTcast v2

SHOUTcast v2

.shoutcastDNAS

8000

Password

SHOUTcast v1

.icecastOfficial

8000

Basic

Icecast PUT

.broadcastify

80

Bearer

Icecast PUT

Export de métriques

IcecastKit peut exporter les métriques de streaming vers Prometheus (format OpenMetrics) ou StatsD (datagrammes UDP). Le protocole IcecastMetricsExporter définit l'interface commune, et les labels sont auto-générés à partir de la configuration (mountpoint, serveur) avec possibilité de surcharge côté consommateur :

Métriques exportées : bytes_sent, stream_duration_seconds, current_bitrate, metadata_updates_total, reconnections_total, write_latency_ms, peak_bitrate, connection_quality_score. Les labels sont auto-générés depuis la configuration (mountpoint, serveur) avec surcharges consommateur.

Architecture

Architecture d'IcecastKit — 16 modules : Client, Protocol, Metadata, Transport, Monitoring, AdaptiveBitrate, MultiClient, Probe, Quality, Recording, Relay, Authentication, ServerPresets, Metrics, Errors, Extensions
Vue d'ensemble de l'architecture modulaire d'IcecastKit (16 modules)

La bibliothèque est organisée en 16 modules clairement séparés, chacun avec une responsabilité bien définie :

Outil CLI

icecast-cli fournit le streaming en ligne de commande, le sondage de bande passante, le relay, le test de connexion, et le diagnostic serveur avec sortie colorée et codes de sortie structurés (0 = succès, 2 = erreur connexion, 3 = erreur auth, 4 = erreur fichier, 6 = erreur serveur, 7 = timeout).

CommandeDescription

stream

Streamer un fichier audio avec multi-destination optionnelle, types d'auth, boucle et reconnexion automatique

probe

Mesurer la bande passante upload et la latence vers un serveur

relay

Puller l'audio d'une source et optionnellement re-publier ou enregistrer

test-connection

Tester la connectivité TCP, la négociation de protocole et l'authentification, puis se déconnecter

info

Interroger les stats globales du serveur ou les stats par mountpoint via l'API admin

Écosystème

IcecastKit fait partie de l'écosystème streaming d'Atelier Socle :

  • PodcastFeedMaker — Génération de flux RSS podcast

  • HLSKit — HTTP Live Streaming

  • IcecastKit (cette bibliothèque) — Streaming Icecast/SHOUTcast

  • RTMPKit — Streaming RTMP

  • SRTKit — Streaming SRT

  • CaptureKit — Capture média unifiée

Liens

GitHub - atelier-socle/swift-icecast-kit: Pure Swift client for Icecast/SHOUTcast streaming. Adaptive bitrate, multi-destination, relay/ingest, recording, Digest auth, server presets, Prometheus/StatsD metrics. Zero dependencies. macOS · iOS · Linux

GitHub - atelier-socle/swift-icecast-kit: Pure Swift client for Icecast/SHOUTcast streaming. Adaptive bitrate, multi-destination, relay/ingest, recording, Digest auth, server presets, Prometheus/StatsD metrics. Zero dependencies. macOS · iOS · Linux

Pure Swift client for Icecast/SHOUTcast streaming. Adaptive bitrate, multi-destination, relay/ingest, recording, Digest auth, server presets, Promethe…

GitHub