{Современный UGC}

cбор видео отзывов в браузере без WebRTC

Игорь Шеко

Head of frontend @ Voximplant

with Osoka.io

Table of Content

UGC

Что это такое. Причем тут видео в общем и фронтенд в частности

1.

2.

WebRTC

Что это такое, как оно работает внутри и почему не подходит для UGC 

3.

MediaDevices API

Как работать с камерой и микрофоном для записи, с какими проблемами можно столкнуться

# TOC

4.

MediaRecorder API

Непосредственно про запись видео на устройстве. Как это сделать лучше всего и что может пойти не так

5.

Speech Recognition API

Бонусная секция про встроенные бесплатные API распознавания речи в браузере.

Что такое UGC

UGC это:

  • пользовательские посты
  • пользовательское аудио/видео
  • отзывы на товары
  • HR интервью
  • мемы
  • ... и прочее, что пользователи создают сами
# CHAPTER 1

Но сегодня мы поговорим в основном про видео

Почему именно видео для UGC

  • Видео - это круто 😊
  • Видео позволяет собрать больше данных​
  • мы можем подключить AI
    • определить эмоции
    • перевести голос в текст
    • опознать человека
    • точно определить пол и возраст человека
    • определить акцент
    • считать жесты
  • Записать видео проще для пользователя
# CHAPTER 1

Немного про кейсы

# CHAPTER 1

https://nesomnoi.jewish-museum.ru/

Немного про кейсы

# CHAPTER 1

https://notforme.introvert.moscow/

https://osoka.io/

Что такое WebRTC

# CHAPTER 2

Как работает WebRTC

# CHAPTER 2

User A

User B

Offer SDP

Answer SDP

Media

Что такое WebRTC

# CHAPTER 2

https://caniuse.com/rtcpeerconnection

Особенности работы WebRTC

# CHAPTER 2
  1. Нужен интернет
  2. WebRTC создан для Real-time коммуникаций, поэтому:

Качество становится жертвой риалтайму

Особенности работы WebRTC

# CHAPTER 2
  1. Нужен интернет
  2. WebRTC создан для Real-time коммуникаций, поэтому:

Качество становится жертвой риалтайму

30 FPS

20 FPS

3 FPS

Что от WebRTC можно взять?

# CHAPTER 3

MediaDevices API

State of MediaDevices API

# CHAPTER 3

https://caniuse.com/mediarecorder

Просто о MediaDevices API

# CHAPTER 3
const constraints = {
  audio: true, 
  video: true
}

stream = await navigator.mediaDevices.getUserMedia(constraints);

https://webrtc.github.io/samples/

Немного глубже о MediaDevices API

# CHAPTER 3

При стандартном запросе:

  • Win 10 отдаст последнюю подключенную камеру
  • iPhone отдаст селфи камеру
  • Pixel 6 Pro отдаст поток с широкоугольной задней камеры

Немного глубже о MediaDevices API

# CHAPTER 3
const constraints = {audio: true, video: true}
stream = await navigator.mediaDevices.getUserMedia(constraints);

const devices = await navigatorLink.mediaDevices.enumerateDevices();

deviceInfo.forEach(info => {
  const capabilities = info.getCapabilities();
})
{
    "aspectRatio": {
        "max": 1920,
        "min": 0.000925925925925926
    },
    "deviceId": "8278d69560f5f3bd8b4c87d5900cf041c58380f0738bcac3bf8cb03204bfdac8",
    "facingMode": [],
    "frameRate": {
        "max": 30.000030517578125,
        "min": 1
    },
    "groupId": "9f9a61500830cb6fbbfdecdb5da077ab3dd469b47c26ca767fe89666d2b7ee23",
    "height": {
        "max": 1080,
        "min": 1
    },
    "resizeMode": [
        "none",
        "crop-and-scale"
    ],
    "width": {
        "max": 1920,
        "min": 1
    }
}

Немного глубже о MediaDevices API

# CHAPTER 3
const constraints = {
  audio: {
    deviceId: '7889879785cdf767f986cd865900cf041c58380f0738bcac3bf8cb03204bfdac8',
    autoGainControl: { exact: true },
    echoCancellation: { exact: true },
    noiseSuppression: { exact: true }
  }, 
  video: {
    deviceId: '8278d69560f5f3bd8b4c87d5900cf041c58380f0738bcac3bf8cb03204bfdac8',
    aspectRatio: { exact: 1 },
    width: { ideal: 1280 },
    height: { exact: 720 }
  }
}

stream = await navigator.mediaDevices.getUserMedia(constraints);

State of MediaRecorder API

# CHAPTER 4

MediaRecorder API

State of MediaRecorder API

# CHAPTER 4

https://caniuse.com/mediarecorder

Что может MediaRecorder API

# CHAPTER 4
  • Записывать один поток (аудио, видео, аудио + видео)
  • Ставить запись на паузу
  • Кодировать различными кодеками
  • Сохранять результат в BLOB

MediaRecorder API

# CHAPTER 4
let recordedChunks = [];

let recorder = new MediaRecorder(mediaStream);
recorder.start();

recorder.ondataavailable = (e) => {
  recordedChunks.push(e.data);
}
recorder.onstop = () => {
  const blob = new Blob(recordedChunks, { type:recorder.mimeType });
  sendBlobToServer(blob);
}

setTimeout(() => { recorder.stop() }, 15000);

MediaRecorder API

# CHAPTER 4
let recordedChunks = [];

let recorder = new MediaRecorder(mediaStream);
recorder.start();

recorder.ondataavailable = (e) => {
  recordedChunks.push(e.data);
}
recorder.onstop = () => {
  const blob = new Blob(recordedChunks, { type:recorder.mimeType });
  sendBlobToServer(blob);
}

setTimeout(() => { recorder.stop() }, 15000);

MediaRecorder API. Кодеки.

# CHAPTER 4
Chrome Firefox macOS Safari iOS Safari
Контейнер webm webm mp4 mp4
Видео кодек VP8/VP9/H264/AV1 VP8 H264 H264
Аудио кодек Opus @ 48kHz Vorbis @ 44.1 kHz Stereo AAC @ 48kHz Stereo AAC @ 44.1kHz 

MediaRecorder API. Кодеки.

# CHAPTER 4

function getSupportedMimeTypes() {
  const possibleTypes = [
    'video/webm;codecs=h264',
    'video/webm;codecs=vp9',
    'video/webm',
    'video/mp4'
  ];
  return possibleTypes.filter(mimeType => {
    return MediaRecorder.isTypeSupported(mimeType);
  });
}

MediaRecorder API. Чанки.

# CHAPTER 4
const TIMESLICE = 5000;

recorder.start(TIMESLICE);

recorder.ondataavailable = (e) => {
  sendPartToServer(e.data);
}

Примеры MediaRecorder API

# CHAPTER 4
  • https://mozdevs.github.io/MediaRecorder-examples/
  • https://webrtc.github.io/samples/src/content/getusermedia/record/
  • https://addpipe.com/media-recorder-api-demo/
  • https://osoka.io/demo/

Bonus. Speech recognition API

# CHAPTER 5

Bonus

Bonus. Speech recognition API

# CHAPTER 5
  • API для распознавания коротких команд и текстов
  • Работает по сети
  • Поддерживает множество языков (в Chrome)
  • Бесплатно

State of Speech recognition API

# CHAPTER 5

https://caniuse.com/speech-recognition

State of Speech recognition API

# CHAPTER 5

Минусы

  • Слабая поддержка
  • Нельзя выбрать устройство ввода
  • Не всегда стабильно

Speech recognition API

# CHAPTER 5
window.SpeechRecognition = window.SpeechRecognition ||window.webkitSpeechRecognition || null;
if(!window.SpeechRecognition) return;

let speech = new window.SpeechRecognition();

speech.onresult = function(event) {
  if (event.results.length > 0) {
    console.log(event.results[0][0].transcript);
  }
}

speech.start();

Speech recognition API. Опции.

# CHAPTER 5
let speech = new window.SpeechRecognition();
speech.continuous  = true;
speech.lang = 'RU-ru';
speech.interimResults = true;
speech.maxAlternatives = 10;

const window.SpeechGrammarList =    window.SpeechGrammarList 
                                 || window.webkitSpeechGrammarList 
                                 || null;
if(window.SpeechGrammarList){
  const grammars = new SpeechGrammarList();
  grammars.addFromString('старт');
  grammars.addFromString('стоп');
  speech.grammars = grammars;
}

Speech recognition API. События.

# CHAPTER 5
let speech = new window.SpeechRecognition();

speech.onaudiostart = ()=>{};
speech.onsoundstart = ()=>{};
speech.onspeechstart = ()=>{};
speech.onspeechend = ()=>{};
speech.onsoundend = ()=>{};
speech.onaudioend = ()=>{};
speech.onnomatch = ()=>{};

speech.onresult = ()=>{};
speech.onerror = ()=>{};
speech.onstart = ()=>{};
speech.onend = ()=>{};

Speech recognition API. Ошибки.

# CHAPTER 5
let speech = new window.SpeechRecognition();

speech.onerror = (ev) => {
  console.log(ev.error);
}
  •  "no-speech" - нет речи в аудио потоке
  •  "aborted" - прервано через speech.abort()
  •  "audio-capture" - ошибка получения аудио
  •  "network" - нет связи с сервером
  •  "not-allowed" - пользователь не разрешил доступ к микрофону
  •  "service-not-allowed" - на странице запрещено распознавание
  •  "bad-grammar" - ошибки настроек
  •  "language-not-supported" - ошибки настроек

Примеры.Speech recognition API 

# CHAPTER 5
  • https://www.audero.it/demo/web-speech-api-demo.html

Спасибо!

Игорь Шеко

Head of frontend @ Voximplant

telegram

github

Made with Slides.com