Перейти к содержанию

Передача звука: аудиомост и медиапотоки#

Бета-версия

Функциональность находится в режиме бета-версии. Функции могут быть изменены, а также могут работать нестабильно. В будущем за функционал может взиматься дополнительная плата.
Подключение к функционалу можно запросить через техподдержку GREEN-API

Сигнализация звонка (набор, приём, отклонение, завершение) идёт через методы клиента, а звук — отдельно, по WebRTC. Соединение поднимает звук не само: это делает метод calls.startAudioBridge(). Дальше в тексте мы называем это аудиомостом.

Порядок вызовов#

Аудиомост принадлежит звонку, поэтому звонок должен уже существовать на сервере:

  1. дождаться, пока завершится dial() (исходящий) или accept() (входящий);
  2. вызвать calls.startAudioBridge().

Если поднять мост раньше, сервер отклонит предложение о передаче звука с ошибкой no active call.

await client.dial('79991234567');
await calls.startAudioBridge();

Неудача с мостом сам звонок не отменяет: на сервере он остаётся, и startAudioBridge() можно вызвать ещё раз. Так же возвращают звук после перезагрузки страницы: если calls.state.state равно out-call или on-call, а calls.hasAudioBridge — false, поднимите мост, не набирая номер заново.

if (['out-call', 'on-call'].includes(calls.state.state) && !calls.hasAudioBridge) {
  await calls.startAudioBridge();
}

При завершении звонка библиотека разбирает мост сама — вызывать stopAudioBridge() в обработчике end-call не нужно. Метод calls.close() останавливает мост и закрывает соединение, когда звонки больше не нужны.

События с медиапотоками#

Когда мост поднят, соединение сообщает о двух потоках:

  • local-stream-ready — поток вашего микрофона; приходит первым, пригодится для индикатора уровня и для отключения микрофона;
  • remote-stream-ready — поток собеседника; его нужно начать воспроизводить.
const audioElement = document.createElement('audio');

calls.addEventListener('local-stream-ready', (event) => {
  console.log('Микрофон готов.', event.detail);
});

calls.addEventListener('remote-stream-ready', (event) => {
  audioElement.srcObject = event.detail;
  audioElement.play();

  console.log('Поток собеседника готов и воспроизводится.');
});

calls.addEventListener('end-call', () => {
  audioElement.srcObject = null;
  audioElement.pause();
});
Если звонок беззвучный

Оба события приходят в момент поднятия моста, то есть до того, как приложение успеет показать экран звонка. Компонент, который только подписывается на них при появлении, не услышит ничего — события уже прошли. Запоминайте последний полученный поток и отдавайте его аудиоэлементу, когда тот появится. Именно так сделано в React-примере, см. React клиент.

Отключение микрофона#

Отдельного метода для отключения микрофона в библиотеке нет, и он не нужен. Трек из события local-stream-ready — тот самый, который передаётся собеседнику, поэтому его отключение и есть то, что собеседник перестаёт слышать:

let localStream = null;

calls.addEventListener('local-stream-ready', (event) => {
  localStream = event.detail;
});

function setMicrophoneEnabled(enabled) {
  localStream.getAudioTracks().forEach((track) => { track.enabled = enabled; });
}

Две вещи, которые при этом легко упустить:

  • Переподключение заменяет микрофон. Если соединение оборвалось при поднятом мосте, библиотека разбирает мост, дожидается соединения и поднимает его заново — с новым запросом к микрофону и новым треком. Звонок при этом не завершается, события end-call не будет. Новый трек приходит включённым, поэтому отключение микрофона нужно перенести на него, иначе микрофон тихо заработает, а кнопка в интерфейсе продолжит показывать, что он выключен.
  • Остановленный трек — это не микрофон. Треки, остановленные при разборе моста, остаются в потоке, поэтому просто посчитать их недостаточно. Прежде чем показывать, что микрофон выключен, проверяйте, что трек живой: track.readyState === 'live'.