{Современный 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
- Нужен интернет
- WebRTC создан для Real-time коммуникаций, поэтому:
Качество становится жертвой риалтайму
Особенности работы WebRTC
# CHAPTER 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
video-ugc
By Igor Sheko
video-ugc
- 131