Skip to content

Голос

Varion передаёт голос по выделенному голосовому каналу транспорта. Сервер — источник истины и «регулировщик»: он создаёт голосовые каналы, хранит их состав, ретранслирует голос между участниками одного канала и для пространственных каналов отсекает слушателей по дистанции. Клиент управляет только локальным воспроизведением и захватом (громкость, свой микрофон, устройство, порог активации, шумоподавление, локальный mute); он не может создавать каналы или переносить игроков между ними.

Аудио непрозрачно для сервера: кадры голоса ретранслируются как есть и никогда не декодируются и не перекодируются. Поддерживаются кодеки PCM и Opus, формат — 48 кГц, кадр 20 мс.

Модель

СторонаЧто делает
Серверсоздаёт и уничтожает каналы, добавляет и убирает участников, авторитетный mute говорящего, приоритет, фильтр канала, ретрансляция и отсечение по дистанции
Клиентлокальная громкость воспроизведения, mute своего микрофона, выбор устройства захвата, порог активации, шумоподавление, локальный mute отдельного игрока, чтение состояния каналов

Голосовой канал принадлежит серверному ресурсу, который его создал, и уничтожается при stop/restart этого ресурса — ручная очистка не нужна. Клиент начинает передавать голос только после того, как сервер добавит его в канал (этот канал становится активным). При отключении игрок автоматически убирается из всех каналов.

Серверная сторона

Создание канала

varion.createVoiceChannel(spatial, maxDistance?) возвращает VoiceChannel — это эквивалент new varion.VoiceChannel(spatial, maxDistance). Вызывается в контексте ресурса (иначе бросает исключение).

  • spatial = true — пространственный канал: слушатель слышит говорящего только в пределах maxDistance (3D-дистанция по позициям игроков). maxDistance по умолчанию 50, допустимый диапазон 1..10000.
  • spatial = false — непространственный канал: все участники слышат всех, дистанция не учитывается (maxDistance равен 0).
javascript
const proximity = varion.createVoiceChannel(true, 20);   // пространственный, 20 м
const team = varion.createVoiceChannel(false);           // командный, без дистанции

Свойства VoiceChannel

СвойствоТипДоступНазначение
idnumberread-onlyid канала, выделяется сервером
type'voiceChannel'read-onlyтип объекта
validbooleanread-onlyжив ли канал
isSpatialbooleanread-onlyпространственный ли канал
maxDistancenumberread-onlyрадиус слышимости (0 для непространственного)
playersPlayer[]read-onlyтекущие участники как proxy Player
playerCountnumberread-onlyчисло участников
prioritynumberread/writeприоритет при пересечении каналов (по умолчанию 0)
filternumberread/writehash аудиофильтра канала (0 — без фильтра)

Методы VoiceChannel

МетодНазначение
addPlayer(player)добавить игрока в канал
removePlayer(player)убрать игрока из канала
hasPlayer(player)состоит ли игрок в канале (алиас isPlayerInChannel)
isPlayerInChannel(player)состоит ли игрок в канале
isPlayerMuted(player)заглушён ли игрок на сервере
mutePlayer(player, muted?)серверный mute (по умолчанию true; false = снять)
unmutePlayer(player)снять серверный mute
setFilter(filterHash)задать фильтр (то же, что filter = filterHash)
destroy()уничтожить канал

Аргумент player принимает proxy Player или числовой id.

Статические члены: VoiceChannel.all (все валидные каналы), VoiceChannel.getByID(id) (канал или null).

Серверный mute (авторитетный)

channel.mutePlayer(player) заглушает исходящий голос указанного участника для всего канала — его перестают слышать все остальные участники. Это серверное, авторитетное решение, в отличие от локального клиентского mute, который влияет только на то, что слышит один игрок. Вызов mutePlayer(player, false) эквивалентен unmutePlayer(player). Замьютить можно только игрока, который уже состоит в канале.

Приоритет

Если слушатель состоит с говорящим сразу в нескольких каналах, сервер выбирает один канал для доставки голоса: сначала — с наибольшим priority; при равенстве предпочитается непространственный канал; при дальнейшем равенстве — канал с меньшим id. Так priority определяет, чей голос «побеждает» при пересечении каналов (например, командный канал важнее общего proximity).

Фильтры

channel.setFilter(hash) или channel.filter = hash задаёт hash аудиофильтра. Сервер передаёт этот hash клиентам, а DSP применяется на клиенте к входящему голосу этого канала. Хеши считаются через varion.hash(name) (JOAAT, нижний регистр). Встроенные пресеты:

ИмяЭффект
walkietalkieполосовой фильтр (рация)
phoneполосовой фильтр (телефон)
underwaterфильтр нижних частот (под водой)

Любой другой hash доставляется клиентам, но без встроенного эффекта — голос проходит без изменений. channel.filter = 0 снимает фильтр.

javascript
const radio = varion.createVoiceChannel(false);
radio.setFilter(varion.hash('walkietalkie'));
radio.priority = 10;

Как сервер ретранслирует голос

  • Клиент загружает один кадр микрофона; состав VoiceChannel решает, кто его услышит. Указанный клиентом id канала сохраняется только для совместимости — маршрут определяет членство в каналах на сервере.
  • Аудио непрозрачно: сервер не декодирует кадры, только проверяет их размер и ретранслирует.
  • Для пространственных каналов сервер отсекает участников за пределами maxDistance.
  • Кадры голоса идут по ненадёжному каналу транспорта, а изменения состава и конфигурации каналов — по надёжному.

Пример (сервер)

javascript
const proximity = varion.createVoiceChannel(true, 15);

varion.on('playerReady', (player) => {
  proximity.addPlayer(player);           // сервер решает, кто в каком канале
});

varion.onClient('voice:report', (reporter, targetId) => {
  proximity.mutePlayer(targetId);        // авторитетно глушим для всего канала
});

// Явно убирать игрока при отключении не нужно — он снимается со всех каналов сам.

Клиентская сторона

Клиент управляет локальным воспроизведением и захватом через varion.Voice. Ни один клиентский вызов не меняет состав канала — это делает только сервер.

varion.Voice — воспроизведение и захват

ЧленТип / сигнатураНазначение
activeChannelnumber (get)id активного канала
pushToTalkboolean (get)удерживается ли клавиша PTT сейчас
volumenumber (get/set)локальная громкость воспроизведения, 0..2
muteInputboolean (get/set)заглушить свой микрофон
inputMutedboolean (get)алиас muteInput
activationLevelnumber (get/set)порог голосовой активации, 0..100
noiseSuppressionEnabledboolean (get/set)шумоподавление
inputDevicestring | null (get/set)id устройства захвата
activityInputEnabledboolean (get/set)режим голосовой активации (вместо PTT)
activationKeynumber (get)клавиша PTT
voiceControlsEnabledboolean (get)включены ли встроенные голосовые контролы
toggleInput(enabled)вручную открыть или закрыть микрофон
getAvailableInputDevices(){ name, uuid }[]устройства захвата (uuid равен null для устройства по умолчанию)

Игроки и mute (клиент)

МетодНазначение
getChannel(channelId?)клиентский VoiceChannel (по умолчанию активный) или null
getPlayersInChannel(channelId?)Player[] в канале (по умолчанию активном)
isPlayerTalking(player)говорит ли игрок сейчас
isPlayerMuted(player)заглушён ли игрок на сервере в активном канале
isPlayerLocallyMuted(player)заглушён ли игрок локально
mutePlayer(player)локально приглушить воспроизведение игрока и отправить varion:voice:mute на сервер
unmutePlayer(player)снять локальный mute и уведомить сервер
clearLocallyMuted()очистить локальный список mute

Локальный mute влияет только на то, что слышит этот клиент; серверный mute (isPlayerMuted) авторитетен. Метод Voice.mutePlayer дополнительно отправляет серверное событие varion:voice:mute (channelId, playerId, muted), которое ресурс может обработать через varion.onClient — само по себе оно не является авторитетным серверным mute.

Клиентский VoiceChannel (только чтение)

Получить снимок канала можно через varion.Voice.getChannel(id) или varion.VoiceChannel.getByID(id).

ЧленНазначение
idid канала
spatialпространственный ли канал
maxDistanceрадиус слышимости (по умолчанию 50)
volume (get/set)громкость воспроизведения этого канала, 0..2
membersмассив id участников
mutedмассив id заглушённых на сервере
filterAudioFilter или null
getPlayers()Player[] участников
isActive()активный ли это канал

Статический член: VoiceChannel.getByID(id).

AudioFilter

varion.AudioFilter.create(nameOrHash) возвращает кэшированный AudioFilter по имени (имя хешируется через JOAAT) или по числовому hash. У объекта есть поле hash.

Утилиты верхнего уровня

  • varion.muteInput(muted = true) — то же, что Voice.muteInput = ....
  • varion.toggleVoiceControls(enabled) — включить или выключить встроенные голосовые контролы.
  • varion.clearLocallyMuted() — то же, что Voice.clearLocallyMuted().

Пример (клиент)

javascript
varion.Voice.volume = 1.2;
varion.Voice.noiseSuppressionEnabled = true;
varion.Voice.activationLevel = 35;

// Индикатор «говорит» в HUD
varion.on('voice:playerStartTalking', (player) => hud.setTalking(player.id, true));
varion.on('voice:playerStopTalking', (player) => hud.setTalking(player.id, false));

// Локально приглушить надоедливого игрока
varion.Voice.mutePlayer(annoyingPlayer);

// Ручной push-to-talk по клавише N
varion.on('keydown', (key) => { if (key === 0x4E) varion.Voice.toggleInput(true); });
varion.on('keyup', (key) => { if (key === 0x4E) varion.Voice.toggleInput(false); });

Голосовые события

События приходят на клиенте; подписка — varion.on(name, callback). Полный контракт событий описан в События и RPC — здесь только краткая сводка.

СобытиеАргументыКогда
playerStartTalking / voice:playerStartTalking(player)игрок начал говорить
playerStopTalking / voice:playerStopTalking(player)игрок перестал говорить
voice:channelChange(previousChannelId, activeChannelId)сменился активный канал
voice:channelCreate(voiceChannel)клиент узнал о новом канале
voice:channelDestroy(channelId)канал исчез
voice:pushToTalk(active)состояние push-to-talk изменилось

Смежные страницы

Источник

Страница сверена с sdk/Varion.Server/npm/@varion/server/index.d.ts (класс VoiceChannel, varion.createVoiceChannel), рантаймом Node-host server/host/varion-host.cjs, серверным релеем server/src/CVoiceManager.{h,cpp} и клиентским рантаймом sdk/client-js-runtime/injected/services-bootstrap.js (объект Voice, классы VoiceChannel и AudioFilter). Список голосовых событий — События и RPC.

Varion Multiplayer Platform