Создайте видео и аудио рекордер с JavaScript MediaRecorder API

Опубликовано: 26 Августа, 2022

WebRTC очень популярен для доступа к камерам и микрофонам устройств, а также для потоковой передачи видео или аудио в браузере. Но во многих случаях нам может потребоваться записать потоковую передачу для будущего использования или для пользователей (например, пользователь может захотеть загрузить потоковую передачу и т. д.). В этом случае мы можем использовать MediaRecorder API для записи потокового мультимедиа.

В этой статье мы создадим базовый веб-сайт Video and Audio Recorder, используя чистый JavaScript и его API MediaRecorder.

Описание проекта: Веб-сайт, который мы создаем, будет иметь:

  • Опция выбора, позволяющая пользователям выбирать, какой тип мультимедиа (аудио или видео со звуком) записывать.
  • Если пользователь решит записывать видео, браузер запросит разрешение на доступ к камере и микрофону устройства, и если пользователь разрешит, то —
    • Элемент видео будет отображать медиапоток камеры.
    • Кнопка «Начать запись» запускает запись.
    • Кнопка «Остановить запись» остановит запись.
    • Когда запись завершена, отображается новый элемент видео, содержащий записанный носитель.
    • Ссылка, позволяющая пользователям загружать записанное видео.
  • Если пользователь выберет запись только аудио, то браузер запросит разрешение на доступ к микрофону, а если пользователь разрешит, то —
    • Кнопка «Начать запись» запускает запись.
    • Кнопка «Остановить запись» остановит запись.
    • Когда запись завершена, отображается новый аудиоэлемент, содержащий записанный звук.
    • Дается ссылка, позволяющая пользователям загружать записанный звук.

Итак, давайте сначала настроим нашу простую HTML-страницу —

index.html




<!DOCTYPE html>
<html lang="en">
  
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" 
        content="IE=edge">
    <meta name="viewport" content=
        "width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="index.css">
    <title>Video & Audio Recorder</title>
</head>
  
<body>
    <h1> Video & Audio Recorder </h1>
    <label for="media">
        Select what you want to record:
    </label>
  
    <select id="media">
        <option value="choose-an-option"
            Choose an option
        </option>
        <option value="vid">Video</option>
        <option value="aud">Audio</option>
    </select>
  
    <div class="display-none" id="vid-recorder">
        <h3>Record Video </h3>
        <video autoplay id="web-cam-container" 
            style="background-color: black;">
            Your browser doesn"t support 
            the video tag
        </video>
  
        <div class="recording" id="vid-record-status">
            Click the "Start video Recording" 
            button to start recording
        </div>
  
        <!-- This button will start the video recording -->
        <button type="button" id="start-vid-recording" 
            onclick="startRecording(this, 
            document.getElementById("stop-vid-recording"))">
            Start video recording
        </button>
  
        <!-- This button will stop the video recording -->
        <button type="button" id="stop-vid-recording" 
            disabled onclick="stopRecording(this, 
            document.getElementById("start-vid-recording"))">
            Stop video recording
        </button>
  
        <!--The video element will be created using 
            JavaScript and contains recorded video-->
        <!-- <video id="recorded-video"  controls>
            Your browser doesn"t support the video tag
        </video> -->
  
        <!-- The below link will let the
             users download the recorded video -->
        <!-- <a href="" > Download it! </a> -->
    </div>
  
    <div class="display-none" id="aud-recorder">
        <h3> Record Audio</h3>
  
        <div class="recording" id="aud-record-status">
            Click the "Start Recording" 
            button to start recording
        </div>
  
        <button type="button" id="start-aud-recording" 
            onclick="startRecording(this, 
            document.getElementById("stop-aud-recording"))">
            Start recording 
        </button>
  
        <button type="button" id="stop-aud-recording" 
            disabled onclick="stopRecording(this, 
            document.getElementById("start-aud-recording"))">
            Stop recording
        </button>
  
        <!-- The audio element will contain the 
            recorded audio and will be created 
            using Javascript -->
        <!-- <audio id="recorded-audio" 
            controls></audio> -->
  
        <!-- The below link will let the users 
             download the recorded audio -->
        <!-- <a href="" > Download it! </a> -->
    </div>
  
    <script src="index.js"></script>
</body>
  
</html>

Выход:

Если вы внимательно проверите index.html , вы увидите, что теги видео и аудио не имеют никакого источника. Мы добавим источники позже, используя JavaScript. На данный момент у нас есть опция выбора, которая позволяет пользователю выбрать тип носителя, который он хочет записать. Первый элемент видео внутри элемента div «vid-recorder» будет содержать поток с веб-камеры, а элемент видео в комментариях будет содержать записанное видео. Обратите внимание, что только последний элемент видео имеет атрибут «controls» , так как первый элемент видео будет содержать поток и не нуждается ни в каких элементах управления.

Внутри div «aud-recorder» у нас есть две кнопки для запуска и остановки записи, элемент audio с комментариями будет содержать записанный звук.

Теперь давайте добавим немного CSS на HTML-страницу —

index.css




body {
    text-align: center;
    color: green;
    font-size: 1.2em;
}
  
.display-none {
    display: none;
}
  
.recording {
    color: red;
    background-color: rgb(241 211 211);
    padding: 5px;
    margin: 6px auto;
    width: fit-content;
}
  
video {
    background-color: black;
    display: block;
    margin: 6px auto;
    width: 420px;
    height: 240px;
}
  
audio {
    display: block;
    margin: 6px auto;
}
  
a {
    color: green;
}

Выход:

На данный момент мы добавили класс «display-none» в разделы «vid-Recorder» и «Aud-Recorder» . Поскольку мы хотим отображать правильный рекордер на основе выбора пользователя.

Теперь давайте реализуем логику для отображения только выбранного пользователем рекордера с помощью JavaScript —

index.js




const mediaSelector = document.getElementById("media");
let selectedMedia = null;
  
// Handler function to handle the "change" event
// when the user selects some option
mediaSelector.addEventListener("change", (e) => {
    selectedMedia = e.target.value;
    document.getElementById(
      `${selectedMedia}-recorder`).style.display = "block";
    document.getElementById(
      `${otherRecorder(selectedMedia)}-recorder`)
      .style.display = "none";
});
  
function otherRecorder(selectedMedia) {
    return selectedMedia === "vid" ? "aud" : "vid";
}

Вывод: когда пользователь выбирает «видео», отображается следующий видеомагнитофон —

Точно так же, когда пользователь выбирает опцию «аудио» , отображается аудиорекордер —

Приведенный выше код отображает только выбранный пользователем рекордер, т. е. аудио или видео. Мы добавили прослушиватель события «change» в элемент mediaSelector, когда значение элемента select изменяется, он генерирует событие «change» , и это событие обрабатывается заданной функцией обратного вызова. Функция обратного вызова изменяет свойство CSS «display» выбранного устройства записи мультимедиа на «block», а другого устройства записи мультимедиа — на «none» .

Доступ к веб-камере и микрофону: WebRTC API getUserMedia позволяет получить доступ к камере и микрофону устройства. Метод getUserMedia() возвращает Promise, который разрешается в MediaStream, который содержит мультимедийное содержимое (поток мультимедийных дорожек) на основе заданных спецификаций. Метод getUserMedia() принимает объект MediaStreamConstraints в качестве параметра, определяющего все ограничения, которым должен соответствовать результирующий медиапоток.

const mediaStreamConstraints = {
   audio: true,
   video: true
};
// The above MediaStreamConstraints object 
// specifies that the resulting media must have
// both the video and audio media content or tracks.

// The mediaStreamConstraints object is passed to 
// the getUserMedia method
navigator.mediaDevices.getUserMedia( MediaStreamConstraints )
.then( resultingMediaStream => {
   // Code to use the received media stream
});

Когда вызывается метод getUserMedia, браузер запрашивает у пользователя разрешение на использование камеры и микрофона устройства. Если пользователь разрешает это, то обещание, возвращаемое getUserMedia, разрешается в результирующий медиапоток, в противном случае генерируется исключение NotAllowedError . В приведенном выше коде полученный медиапоток содержит как видеоданные, так и аудиоданные.

Итак, добавьте следующие строки кода в файл index.js:

index.js




const mediaSelector = 
    document.getElementById("media");
  
// Added code
const webCamContainer = document
    .getElementById("web-cam-container");
  
let selectedMedia = null;
  
/* Previous code 
...
Added code */
  
const audioMediaConstraints = {
    audio: true,
    video: false
};
  
const videoMediaConstraints = {
    // or you can set audio to false 
    // to record only video
    audio: true,
    video: true
};
  
function startRecording(thisButton, otherButton) {
  
    navigator.mediaDevices.getUserMedia(
            selectedMedia === "vid"
            videoMediaConstraints : 
            audioMediaConstraints)
        .then(mediaStream => {
            // Use the mediaStream in 
            // your application
  
            // Make the mediaStream global
            window.mediaStream = mediaStream;
  
            if (selectedMedia === "vid") {
  
                // Remember to use the "srcObject" 
                // attribute since the "src" attribute 
                // doesn"t support media stream as a value
                webCamContainer.srcObject = mediaStream;
            }
  
            document.getElementById(
                `${selectedMedia}-record-status`)
                .innerText = "Recording";
            thisButton.disabled = true;
            otherButton.disabled = false;
        });
  
}
  
function stopRecording(thisButton, otherButton) {
  
    // Stop all the tracks in the received 
    // media stream i.e. close the camera
    // and microphone
    window.mediaStream.getTracks().forEach(track => {
        track.stop();
    });
  
    document.getElementById(
        `${selectedMedia}-record-status`)
        .innerText = "Recording done!";
          
    thisButton.disabled = true;
    otherButton.disabled = false;
}

Функция startRecording вызывает метод navigator.mediaDevices.getUserMedia() для доступа к камере и микрофону устройства, отключает кнопку «начать запись» и включает кнопку «остановить запись» . Принимая во внимание, что функция stopRecording закрывает камеру и микрофон, вызывая метод «stop()» каждой медиадорожки, используемой медиапотоком, отключает кнопку «остановить запись» и включает кнопку «начать запись» .

Внедрение рекордера: до сих пор мы имели доступ только к веб-камере и микрофону, но ничего не делали для записи мультимедиа.

Чтобы записать медиапоток, нам сначала нужно создать экземпляр MediaRecorder (интерфейс для записи медиапотоков) с помощью конструктора MediaRecorder.

Конструктор MediaRecorder принимает два параметра:

  • поток: поток похож на поток данных (данные любого типа). Здесь, в этой статье, мы будем использовать MediaStream, который в основном представляет собой поток медиа (видео или аудио или и того, и другого) данных или медиаконтента.
  • Опции (необязательные): объект, содержащий некоторые характеристики записи. Вы можете установить MIME-тип записанного медиафайла, битрейт аудио, видео и т. д. MIME-тип — это стандарт, представляющий формат записанного медиафайла (например, два типа MIME — «аудио/ webm», «video/mp4» обозначают аудиофайл webm и видеофайл mp4 соответственно).

Синтаксис:

const mediaRecorder = new MediaRecorder(
    stream, { mimeType: "audio/webm" });

Приведенная выше строка кода создает новый экземпляр MediaRecorder, который записывает данный поток и сохраняет его в виде аудиофайла WebM.

Итак, измените файл index.js:

index.js file




/* Previous code 
... */
  
function startRecording(thisButton, otherButton) {
  
    navigator.mediaDevices.getUserMedia(
        selectedMedia === "vid" ?
        videoMediaConstraints :
        audioMediaConstraints)
  
    .then(mediaStream => {
  
        /* New code */
        // Create a new MediaRecorder 
        // instance that records the