Tutorial 2026-05-21

Criar um Leitor de Música e Rádio para FiveM

OntelMonke

OntelMonke

Developer na Agency Scripts

Por que o rádio personalizado é importante no RPG

Música e rádio são elementos atmosféricos essenciais que dão vida a um servidor de RPG FiveM. Embora GTA V venha com suas próprias estações de rádio, os sistemas de rádio personalizados permitem que os proprietários de servidores criem estações temáticas que correspondam à identidade de sua comunidade, transmitam DJs ao vivo, reproduzam playlists com curadoria da comunidade e até mesmo transmitam boletins de notícias dos personagens. Um sistema de música bem construído vai além da simples reprodução de áudio. Ele fornece experiências de audição sincronizadas para jogadores no mesmo veículo, áudio espacial de boomboxes e alto-falantes de clubes, listas de reprodução pessoais que os jogadores podem gerenciar por meio de um aplicativo de telefone e integração de cabine de DJ para roleplay em casas noturnas. A base técnica depende dos recursos de áudio NUI, que permitem aproveitar todo o poder das APIs de áudio baseadas em navegador no cliente FiveM.

Arquitetura de áudio e integração NUI

A camada NUI do FiveM executa um navegador baseado em Chromium incorporado no cliente do jogo, o que significa que você tem acesso à API de áudio da Web, elementos de áudio HTML5 e até mesmo à API MediaSource para streaming adaptável. A arquitetura se divide em três componentes: o script do cliente Lua lida com as interações do mundo do jogo, como entrar em veículos ou se aproximar de alto-falantes, a camada NUI HTML e JavaScript gerencia a reprodução e visualização de áudio real, e o servidor coordena os estados de reprodução sincronizados em vários clientes. Quando um jogador entra em um veículo, o script do cliente envia uma mensagem NUI para iniciar a reprodução da estação atual. A camada NUI cria um elemento de áudio, define o URL de origem e inicia a reprodução. Os controles de volume são manipulados inteiramente na camada NUI usando o GainNode da API de áudio da Web para transições de volume suaves:

-- 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

Configuração do reprodutor de áudio NUI

O lado NUI precisa de um reprodutor de áudio robusto que lide com conexões de fluxo, buffer, recuperação de erros e gerenciamento de volume. Use a API de áudio da Web em vez de simples elementos de áudio HTML5 porque ela oferece controle sobre o roteamento de áudio, permite criar visualizações a partir de dados de frequência e oferece suporte ao processamento de áudio espacial. Crie um AudioContext com um GainNode para controle de volume e um AnalyserNode para visualização de dados:

// 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();

Configuração e streaming da estação

Defina suas estações de rádio com URLs de stream, metadados e categorias de gênero. A maioria dos sistemas de rádio FiveM personalizados usam fluxos de rádio da Internet em formato MP3 ou AAC porque são amplamente suportados e fáceis de configurar. Você pode hospedar seu próprio servidor Icecast ou Shoutcast para controle total ou usar URLs de transmissão de rádio pública. Para cada estação, armazene o URL do stream, um nome de exibição, uma tag de gênero e, opcionalmente, uma imagem de logotipo para a IU. Considere adicionar suporte para URLs do YouTube e SoundCloud por meio de serviços de proxy, mas esteja atento aos termos de serviço e às restrições de direitos autorais. Para funcionalidade de DJ ao vivo, integre-se a serviços que fornecem conversão de stream RTMP para HTTP para que DJs possam transmitir usando OBS ou software semelhante:

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,
    },
}

Rádio veicular sincronizado

Quando vários jogadores viajam no mesmo veículo, todos devem ouvir a mesma estação de rádio. Isso requer coordenação do lado do servidor por meio de bolsas de estado ou eventos em rede. Quando o motorista muda de estação, o servidor transmite a nova estação para todos os ocupantes. Use o sistema state bag do FiveM para sincronização eficiente porque ele lida automaticamente com a replicação de rede sem gerenciamento manual de eventos. Defina a estação na bolsa de estado da entidade veículo para que qualquer jogador que entre no veículo pegue automaticamente a estação atual. Lide com casos extremos, como passageiros entrando em um veículo que já tem uma estação em execução, o motorista saindo enquanto os passageiros permanecem e mudanças de estação conflitantes por parte dos passageiros se você permitir o controle de quem não é o motorista:

-- 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)

Sistemas de Áudio Espacial e Boombox

O áudio espacial adiciona uma camada de imersão que a reprodução de áudio plana não consegue igualar. Caixas de som, alto-falantes de clubes e aparelhos de som automotivos devem emitir um som que diminui com a distância e se desloca com base na posição do ouvinte em relação à fonte. FiveM fornece funções de áudio nativas como PlaySoundFromCoord para sons espaciais simples, mas para streaming de áudio você precisa implementar escala de volume baseada em distância na camada NUI. Calcule a distância entre o player e a fonte de áudio em cada quadro e, em seguida, mapeie essa distância para uma curva de volume. Use um enfraquecimento do quadrado inverso para uma atenuação sonora realista, com distâncias auditivas mínimas e máximas configuráveis. Para boomboxes que os jogadores podem colocar no mundo, crie um item implantável que gere um acessório no local do jogador e o registre como uma fonte de áudio. Outros jogadores dentro do alcance devem ouvir a música automaticamente, com escala de volume baseada na distância do suporte do boombox.

Lista de reprodução do player e integração com telefone

Dê aos jogadores controle pessoal sobre sua experiência musical por meio de um sistema de lista de reprodução integrado ao recurso telefônico do seu servidor. Os jogadores devem ser capazes de criar listas de reprodução personalizadas adicionando URLs a faixas individuais, reordenar músicas arrastando e soltando, definir uma lista de reprodução para embaralhar ou repetir e compartilhar listas de reprodução com outros jogadores. Armazene playlists no banco de dados vinculadas ao identificador do player para que persistam durante as sessões. A interface do aplicativo do telefone deve exibir a faixa atualmente em reprodução com metadados de artista e título, controles de reprodução para reproduzir, pausar, pular e anterior, um controle deslizante de volume e uma lista de listas de reprodução salvas. Quando o player está em um veículo, o player do telefone deve encaminhar automaticamente o áudio através do sistema de rádio do veículo para que os passageiros possam ouvir a música. Quando a pé com fones de ouvido equipados como item, a música toca de forma privada com um pequeno ícone de fone de ouvido visível para outros jogadores, indicando que o personagem está ouvindo música sem que ela seja audível para outras pessoas.

Visualizador e UI Design

A interface do usuário de um reprodutor de música deve parecer viva e responsiva ao áudio que está sendo reproduzido. Use o AnalyserNode da API Web Audio para extrair dados de frequência em tempo real e renderizar um visualizador de áudio. Visualizadores de barras, exibições de formas de onda e analisadores de espectro circular funcionam bem dependendo da estética da interface do usuário. Renderize o visualizador usando um elemento canvas para desempenho, atualizando a 30 ou 60 quadros por segundo, dependendo da complexidade da visualização. A interface do rádio em si deve ser mínima e não intrusiva, aparecendo como um pequeno widget no canto da tela mostrando o nome da estação atual, o título da faixa, se disponível nos metadados do stream, e controles básicos de reprodução. Quando o player abre o menu completo do rádio para mudar de estação, exibe uma grade ou lista de estações disponíveis com seus logotipos, gêneros e contagem de ouvintes. Inclui uma barra de pesquisa para servidores com muitas estações e um sistema de favoritos para que os jogadores possam acessar rapidamente suas estações preferidas sem percorrer a lista inteira.

Considerações de desempenho

O streaming de áudio consome largura de banda e recursos do cliente, portanto, otimize sua implementação com cuidado. Limite o número de fluxos de áudio simultâneos por cliente para evitar vazamentos de memória e picos de CPU. Quando um jogador não estiver em um veículo e não tiver nenhum aparelho de som por perto, destrua completamente o contexto de áudio em vez de apenas pausá-lo. Para áudio espacial de vários boomboxes, crie fluxos de áudio apenas para fontes dentro do alcance auditivo e limpe os fluxos à medida que as fontes se movem para fora do alcance. Use fluxos de baixa taxa de bits para música ambiente de fundo e reserve fluxos de qualidade mais alta para a experiência auditiva principal. No lado do servidor, evite enviar URLs de stream diretamente em eventos porque eles podem ser interceptados e abusados. Em vez disso, use um sistema de retorno de chamada onde o cliente solicita a URL do stream para um ID de estação específico e o servidor responde com uma URL assinada por tempo limitado. Monitore erros de reprodução relatados pelo cliente e reconecte automaticamente streams que caem devido a problemas de rede, com espera exponencial para evitar sobrecarregar um servidor de stream com dificuldades.

Partilhar este artigo

Pronto para melhorar o teu servidor?

Explora os nossos scripts FiveM premium na loja Agency Scripts ou junta-te à nossa comunidade no Discord para suporte e atualizações.