Zurück zum Blog
Tutorial8 Min. Lesezeit

FiveM-Musik- und Radio-Player-Skripte: xSound und mehr

Spiele Musik im Spiel richtig ab. Entdecke xSound, Radio-Player-Apps, Boombox-Objekte und die besten FiveM-Audio-Skripte für Partys, Bars und Autos.

Agency Scripts

Gründer und leitender Entwickler bei Agency Scripts

Warum ein benutzerdefiniertes Radio im Roleplay wichtig ist

Musik und Radio sind wichtige atmosphärische Elemente, die einen FiveM-Roleplay-Server zum Leben erwecken. GTA V enthält zwar eigene Radiosender, aber mit benutzerdefinierten Radiosystemen können Serverbetreiber thematische Sender erstellen, die zur Identität ihrer Community passen, Live-DJ-Sets streamen, von der Community zusammengestellte Playlists abspielen und sogar Nachrichtenbulletins aus der Spielwelt senden. Ein gut entwickeltes Musiksystem kann mehr als nur Audio abspielen. Es bietet synchronisierte Hörerlebnisse für Spieler im selben Fahrzeug, räumliches Audio von Boomboxen und Clublautsprechern, persönliche Playlists, die Spieler über eine Handy-App verwalten können, sowie die Integration eines DJ-Pults für das Roleplay in Nachtclubs. Die technische Grundlage bilden die NUI-Audiofunktionen, mit denen du die Möglichkeiten browserbasierter Audio-APIs im FiveM-Client voll ausschöpfen kannst.

Audioarchitektur und NUI-Integration

Die NUI-Ebene von FiveM verwendet einen Chromium-basierten Browser, der in den Spielclient eingebettet ist. Dadurch kannst du auf die Web Audio API, HTML5-Audioelemente und sogar die MediaSource API für adaptives Streaming zugreifen. Die Architektur besteht aus drei Komponenten: Das Lua-Clientskript verarbeitet Interaktionen mit der Spielwelt, etwa das Einsteigen in Fahrzeuge oder das Annähern an Lautsprecher. Die NUI-HTML- und JavaScript-Ebene verwaltet die Audiowiedergabe und Visualisierung, und der Server koordiniert synchronisierte Wiedergabezustände über mehrere Clients hinweg. Wenn ein Spieler in ein Fahrzeug einsteigt, sendet das Clientskript eine NUI-Nachricht, um den aktuellen Sender abzuspielen. Die NUI-Ebene erstellt ein Audioelement, legt die Quell-URL fest und startet die Wiedergabe. Die Lautstärke wird vollständig in der NUI-Ebene über den GainNode der Web Audio API gesteuert, der sanfte Lautstärkeübergänge ermöglicht:

-- Client-side: Vehicle radio controller
local currentStation = nil
local radioActive = false

CreateThread(function()
    while true do
        Wait(500)
        local ped = PlayerPedId()

        if IsPedInAnyVehicle(ped, false) then
            local vehicle = GetVehiclePedIsIn(ped, false)

            if not radioActive then
                radioActive = true
                -- Disable default GTA radio
                SetVehicleRadioEnabled(vehicle, false)

                -- Load saved station preference
                local savedStation = LocalPlayer.state.radioStation or 'station_1'
                SetStation(savedStation)
            end
        elseif radioActive then
            radioActive = false
            SendNUIMessage({action = 'stopRadio'})
            currentStation = nil
        end
    end
end)

function SetStation(stationId)
    local station = Config.Stations[stationId]
    if not station then return end

    currentStation = stationId
    SendNUIMessage({
        action = 'playStation',
        url = station.url,
        name = station.name,
        volume = LocalPlayer.state.radioVolume or 0.5,
    })
end

NUI-Audioplayer einrichten

Die NUI-Seite braucht einen robusten Audioplayer, der Streamverbindungen, Pufferung, Fehlerbehandlung und Lautstärkeregelung verwaltet. Verwende die Web Audio API statt einfacher HTML5-Audioelemente, denn damit kannst du das Audio-Routing steuern, Visualisierungen anhand von Frequenzdaten erstellen und räumliche Audioverarbeitung unterstützen. Erstelle einen AudioContext mit einem GainNode zur Lautstärkeregelung und einem AnalyserNode für Visualisierungsdaten:

// NUI JavaScript: Audio engine
class RadioPlayer {
    constructor() {
        this.audioContext = new (window.AudioContext || window.webkitAudioContext)();
        this.gainNode = this.audioContext.createGain();
        this.analyser = this.audioContext.createAnalyser();
        this.analyser.fftSize = 256;

        this.gainNode.connect(this.analyser);
        this.analyser.connect(this.audioContext.destination);

        this.audio = new Audio();
        this.audio.crossOrigin = 'anonymous';
        this.source = null;
        this.isPlaying = false;
    }

    play(url, volume) {
        this.stop();
        this.audio = new Audio(url);
        this.audio.crossOrigin = 'anonymous';
        this.audio.volume = 1.0;

        this.source = this.audioContext.createMediaElementSource(this.audio);
        this.source.connect(this.gainNode);
        this.gainNode.gain.value = volume;

        this.audio.play().then(() => {
            this.isPlaying = true;
        }).catch(err => {
            console.error('Radio playback failed:', err);
            setTimeout(() => this.play(url, volume), 3000);
        });
    }

    stop() {
        if (this.audio) {
            this.audio.pause();
            this.audio.src = '';
            this.isPlaying = false;
        }
    }

    setVolume(vol) {
        this.gainNode.gain.linearRampToValueAtTime(
            vol, this.audioContext.currentTime + 0.1
        );
    }

    getFrequencyData() {
        const data = new Uint8Array(this.analyser.frequencyBinCount);
        this.analyser.getByteFrequencyData(data);
        return data;
    }
}

const radio = new RadioPlayer();

Senderkonfiguration und Streaming

Definiere deine Radiosender mit Stream-URLs, Metadaten und Genre-Kategorien. Die meisten benutzerdefinierten FiveM-Radiosysteme verwenden Internetradiostreams im MP3- oder AAC-Format, da diese weitgehend unterstützt werden und einfach einzurichten sind. Du kannst für volle Kontrolle einen eigenen Icecast- oder Shoutcast-Server hosten oder öffentliche Radio-Stream-URLs verwenden. Speichere für jeden Sender die Stream-URL, einen Anzeigenamen, ein Genre-Tag und optional ein Logo für die Benutzeroberfläche. Erwäge, URLs von YouTube und SoundCloud über Proxy-Dienste zu unterstützen, beachte dabei jedoch die Nutzungsbedingungen und Urheberrechtsbeschränkungen. Für Live-DJ-Funktionen kannst du Dienste integrieren, die RTMP-Streams in HTTP-Streams umwandeln, damit DJs mit OBS oder ähnlicher Software senden können:

Config.Stations = {
    ['station_1'] = {
        name = 'Agency Radio',
        genre = 'Hip Hop',
        url = 'https://stream.example.com/hiphop',
        logo = 'station_hiphop.webp',
        description = 'The freshest beats in Los Santos',
    },
    ['station_2'] = {
        name = 'LS Rock Radio',
        genre = 'Rock',
        url = 'https://stream.example.com/rock',
        logo = 'station_rock.webp',
        description = 'Classic and modern rock anthems',
    },
    ['station_3'] = {
        name = 'Vinewood Lounge',
        genre = 'Jazz / Lofi',
        url = 'https://stream.example.com/lofi',
        logo = 'station_lofi.webp',
        description = 'Smooth vibes for the night drive',
    },
    ['station_live'] = {
        name = 'Live DJ',
        genre = 'Live',
        url = 'https://stream.example.com/live',
        logo = 'station_live.webp',
        description = 'Live DJ sets from the community',
        isLive = true,
    },
}

Synchronisiertes Autoradio

Wenn mehrere Spieler im selben Fahrzeug mitfahren, sollten alle denselben Radiosender hören. Dafür ist eine serverseitige Koordination über State Bags oder Netzwerkereignisse erforderlich. Wenn der Fahrer den Sender wechselt, sendet der Server den neuen Sender an alle Insassen. Verwende für eine effiziente Synchronisierung das State-Bag-System von FiveM, da es die Netzwerkreplikation automatisch und ohne manuelle Ereignisverwaltung übernimmt. Lege den Sender im State Bag der Fahrzeug-Entity fest, damit jeder Spieler, der in das Fahrzeug einsteigt, automatisch den aktuellen Sender übernimmt. Berücksichtige Sonderfälle, etwa wenn Passagiere in ein Fahrzeug einsteigen, in dem bereits ein Sender läuft, der Fahrer aussteigt, während Passagiere im Fahrzeug bleiben, oder wenn Passagiere den Sender ändern und der Fahrer dadurch die Kontrolle verliert, sofern du Änderungen durch Mitfahrer erlaubst:

-- Server-side: Sync radio state via state bags
RegisterNetEvent('radio:server:setStation', function(vehicleNet, stationId)
    local src = source
    local vehicle = NetworkGetEntityFromNetworkId(vehicleNet)
    if not DoesEntityExist(vehicle) then return end

    -- Verify player is the driver
    local ped = GetPlayerPed(src)
    if GetPedInVehicleSeat(vehicle, -1) ~= ped then return end

    -- Set station on vehicle state bag
    Entity(vehicle).state:set('radioStation', stationId, true)
end)

-- Client-side: Listen for state bag changes
AddStateBagChangeHandler('radioStation', nil, function(bagName, key, value)
    if not value then return end
    local entity = GetEntityFromStateBagName(bagName)
    if not DoesEntityExist(entity) then return end

    local ped = PlayerPedId()
    if not IsPedInVehicle(ped, entity, false) then return end

    SetStation(value)
end)

Räumliches Audio und Boombox-Systeme

Räumliches Audio sorgt für eine immersive Erfahrung, die eine einfache Audiowiedergabe nicht bieten kann. Boomboxen, Clublautsprecher und Autoradios sollten Klang ausgeben, der mit zunehmender Entfernung leiser wird und je nach Position des Zuhörers zur Quelle im Raum wandert. FiveM bietet native Audiofunktionen wie PlaySoundFromCoord für einfache räumliche Klänge. Bei Streaming-Audio musst du die Lautstärke jedoch in der NUI-Ebene anhand der Entfernung skalieren. Berechne in jedem Frame die Entfernung zwischen dem Spieler und der Audioquelle und ordne sie dann einer Lautstärke-Kurve zu. Verwende für eine realistische Schalldämpfung eine Abnahme nach dem inversen Quadratgesetz und konfigurierbare minimale und maximale Hörweiten. Erstelle für Boomboxen, die Spieler in der Welt aufstellen können, ein platzierbares Item, das an der Position des Spielers ein Prop erzeugt und es als Audioquelle registriert. Andere Spieler in Reichweite sollten die Musik automatisch hören, wobei die Lautstärke anhand ihrer Entfernung zum Boombox-Prop angepasst wird.

Spieler-Playlists und Handy-Integration

Gib Spielern mit einem in die Handy-Resource deines Servers integrierten Playlist-System persönliche Kontrolle über ihre Musik. Spieler sollten eigene Playlists erstellen können, indem sie URLs einzelner Tracks hinzufügen, Songs per Drag-and-drop neu anordnen, zufällige Wiedergabe oder Wiederholung einstellen und Playlists mit anderen Spielern teilen. Speichere Playlists in der Datenbank und verknüpfe sie mit der Spielerkennung, damit sie sitzungsübergreifend erhalten bleiben. Die Handy-App sollte den aktuell wiedergegebenen Track mit Künstler- und Titel-Metadaten, Wiedergabesteuerungen für Start, Pause, Überspringen und Zurück, einen Lautstärkeregler sowie eine Liste gespeicherter Playlists anzeigen. Befindet sich der Spieler in einem Fahrzeug, sollte der Handyplayer das Audio automatisch über das Autoradio ausgeben, damit Mitfahrer die Musik hören können. Ist der Spieler zu Fuß und trägt Ohrhörer als Item, wird die Musik privat abgespielt. Ein kleines Ohrhörer-Symbol zeigt anderen Spielern an, dass der Charakter Musik hört, ohne dass sie diese hören können.

Visualizer und UI-Design

Eine Musikplayer-Oberfläche sollte lebendig wirken und auf die laufende Audiowiedergabe reagieren. Verwende den AnalyserNode der Web Audio API, um Frequenzdaten in Echtzeit auszulesen und einen Audio-Visualizer darzustellen. Balkenvisualisierungen, Wellenformdarstellungen und kreisförmige Spektrumanalysatoren eignen sich je nach Stil deiner Benutzeroberfläche. Rendere den Visualizer für eine gute Performance über ein Canvas-Element und aktualisiere ihn je nach Komplexität der Visualisierung 30 oder 60 Mal pro Sekunde. Die Radio-Oberfläche selbst sollte minimal und unaufdringlich sein. Sie sollte als kleines Widget in der Bildschirmecke erscheinen und den aktuellen Sendernamen, den Tracktitel, sofern über Stream-Metadaten verfügbar, sowie grundlegende Wiedergabesteuerungen anzeigen. Wenn der Spieler das vollständige Radiomenü öffnet, um den Sender zu wechseln, zeige eine Übersicht oder Liste verfügbarer Sender mit Logos, Genres und Hörerzahlen an. Bei Servern mit vielen Sendern solltest du eine Suchleiste und ein Favoritensystem einbauen, damit Spieler ihre bevorzugten Sender schnell finden können, ohne die gesamte Liste durchzugehen.

Leistungsaspekte

Audiostreaming verbraucht Bandbreite und Client-Ressourcen, optimiere deine Implementierung daher sorgfältig. Begrenze die Anzahl gleichzeitiger Audiostreams pro Client, um Speicherlecks und CPU-Spitzen zu vermeiden. Wenn ein Spieler nicht in einem Fahrzeug sitzt und sich keine Boombox in der Nähe befindet, zerstöre den AudioContext vollständig, statt ihn nur anzuhalten. Erstelle für räumliches Audio von mehreren Boomboxen nur Streams für Quellen innerhalb der Hörweite und bereinige sie, sobald sich die Quellen außerhalb der Reichweite befinden. Verwende Streams mit niedriger Bitrate für atmosphärische Hintergrundmusik und reserviere Streams mit höherer Qualität für das primäre Hörerlebnis. Sende serverseitig keine Stream-URLs direkt in Ereignissen, da sie abgefangen und missbraucht werden können. Verwende stattdessen ein Callback-System, bei dem der Client die Stream-URL für eine bestimmte Sender-ID anfordert und der Server eine zeitlich begrenzte, signierte URL zurückgibt. Überwache vom Client gemeldete Wiedergabefehler und verbinde abgebrochene Streams automatisch erneut. Verwende dabei exponentielles Backoff, damit ein instabiler Streamingserver nicht mit Anfragen überlastet wird.

Bereit loszulegen?

Hol dir die Scripts in unserem Shop, oder komm auf den Discord für Support, Updates und einen Blick auf das, was kommt.