Найти в Дзене

Unity WebGL. Чиним звук в браузерах.

Очень много разработчиков жалуются на отсутствие звука в мобильных браузерах, в частности в Яндекс браузере. На данном этапе (на дворе у нас 2023г.) юнитеки не исправили эту проблему, поэтому придётся делать небольшой костыль. Причину я могу только предполагать и, на мой взгляд, вся проблема в кодеках, которыми сжимается аудиофайл. Unity когда билдит проект все звуки конвертирует собственным кодеком, и при воспроизведении их даёт браузеру команду проиграть звук. Так вот если браузер не дружит с кодеком от Unity, то и с воспроизведением будут проблемы. Что же можно сделать? Пока я нашёл самое простое решение - не включать звуковые файлы в билд, а грузить их уже после запуска игры по Url. Далее игра уже будет передавать браузерам понятный им аудиофайл и с воспроизведением не должно возникнуть проблем. Ну что ж, можно приступать к делу. 1. Обрабатываем аудиофайл в редакторе Я использую самый простой онлайн редактор https://sodaphonic.com/editor Здесь я по максимуму уменьшаю вес трека. Дел
Оглавление

Очень много разработчиков жалуются на отсутствие звука в мобильных браузерах, в частности в Яндекс браузере. На данном этапе (на дворе у нас 2023г.) юнитеки не исправили эту проблему, поэтому придётся делать небольшой костыль.

Причину я могу только предполагать и, на мой взгляд, вся проблема в кодеках, которыми сжимается аудиофайл. Unity когда билдит проект все звуки конвертирует собственным кодеком, и при воспроизведении их даёт браузеру команду проиграть звук. Так вот если браузер не дружит с кодеком от Unity, то и с воспроизведением будут проблемы.

Что же можно сделать? Пока я нашёл самое простое решение - не включать звуковые файлы в билд, а грузить их уже после запуска игры по Url. Далее игра уже будет передавать браузерам понятный им аудиофайл и с воспроизведением не должно возникнуть проблем.

Ну что ж, можно приступать к делу.

1. Обрабатываем аудиофайл в редакторе

Необработанный аудиофайл
Необработанный аудиофайл

Я использую самый простой онлайн редактор https://sodaphonic.com/editor

Здесь я по максимуму уменьшаю вес трека. Делаю его моно, нормализую, вырезаю паузы спереди и сзади, также обрезаю трек так, чтобы он получился зацикленным. Чем меньше вес файла - тем лучше.

Далее экспортирую из редактора в файл .mp3

2. Загружаем файл в проект

В папке Assets в проекте создаём папку StreamingAssets

-2

В эту папку складываем все обработанные звуки

-3

3. Подготавливаем объекты с AudioSource.

-4

Я обычно все звуки держу в мигрирующих (DontDestroyOnLoad) между сценами объектах. Делаю синглтон Game и там создаю структуру из неубиваемых объектов.

Для музыки - один объект, для звуков - другой. Всего в проекте получается два AudioSource.

Итак при старте игры у нас будет два источника звука и не будет клипов для воспроизведения. Для загрузки клипов пишем скрипты.

Я выложу здесь скрипт для загрузки звуков, для музыки можно написать аналогичный или упростить (чтобы загружался только один трек):

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Networking;

public class Sounds : MonoBehaviour
{
[SerializeField] private AudioSource _as;
[SerializeField] private List<AudioClip> _audioClips;
private bool _isAssetsLoaded = false;
private bool _inProcess = false;
private void Start()
{
_isAssetsLoaded = false;
_inProcess = false;
}
public void Init()
{
if (_inProcess) return;
if (_isAssetsLoaded) return;
_inProcess = true;
LoadAssets();
}
public void Play(int id)
{
if (id >= _audioClips.Count) return;
if (_audioClips[id] == null) return;
_as.PlayOneShot(_audioClips[id]);
}

#region -LOAD ASSETS-
[SerializeField] private List<string> _clipUrl;
private void LoadAssets()
{
var url = Application.streamingAssetsPath + "/";
foreach (var clip in _clipUrl)
{
_audioClips.Add(null);
StartCoroutine(LoadClip(url + clip + ".mp3", _audioClips.Count - 1));
}
}
IEnumerator LoadClip(string url, int id)
{
using (UnityWebRequest www = UnityWebRequestMultimedia.GetAudioClip(url, AudioType.MPEG))
{
yield return www.SendWebRequest();

if (www.result == UnityWebRequest.Result.Success)
{
_audioClips[id] = DownloadHandlerAudioClip.GetContent(www);
if (IsDone())
{
_inProcess = false;
_isAssetsLoaded = true;
}
}
else
{
Debug.Log(www.error);
}
}
}
private bool IsDone()
{
for (int i = 0; i < _audioClips.Count; i++)
{
if (_audioClips[i] == null) return false;
}
return true;
}
#endregion
}

Здесь два публичных метода, Init(); вызывается только один раз, при старте игры и Play(int id); при воспроизведении звука (для проигрывания музыки музыки нужно использовать другой метод воспроизведения, вместо PlayOneShot() просто Play()).

Вкратце, при запуске метода Init() скрипт пробегается по всем именам файлов в списке _clipUrl, и стартует загрузку файла из внешнего хранилища (в нашем случае по url адресу). Далее по мере загрузки все клипы складываются в список _audioClips, откуда мы их потом воспроизводим при помощи AudioSource.

Вот, собственно и весь фокус.

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