programing tip

webRTC 및 서버 기반 피어 연결을 사용하여 웹캠 및 오디오를 녹음하는 방법

itbloger 2020. 10. 6. 07:57
반응형

webRTC 및 서버 기반 피어 연결을 사용하여 웹캠 및 오디오를 녹음하는 방법


사용자 웹캠과 오디오를 녹음하고 서버의 파일에 저장하고 싶습니다. 이 파일은 다른 사용자에게 제공 될 수 있습니다.

재생에는 문제가 없지만 녹화 할 콘텐츠를 가져 오는 데 문제가 있습니다.

내 이해는 getUserMedia .record()함수가 아직 작성되지 않았다는 것입니다. 지금까지 제안 만 작성되었습니다.

PeerConnectionAPI를 사용하여 내 서버에서 피어 연결을 만들고 싶습니다. 나는 이것이 약간 해키하다는 것을 이해하지만 서버에 피어를 만들고 클라이언트-피어가 보내는 것을 기록하는 것이 가능해야한다고 생각합니다.

이것이 가능하다면이 데이터를 flv 또는 다른 비디오 형식으로 저장할 수 있어야합니다.

내가 선호하는 것은 실제로 웹캠 + 오디오 클라이언트 측을 녹화하여 클라이언트가 업로드하기 전에 첫 번째 시도가 마음에 들지 않으면 비디오를 다시 녹화 할 수 있도록하는 것입니다. 이것은 또한 네트워크 연결의 중단을 허용합니다. 데이터를 캔버스로 전송하여 웹캠에서 개별 '이미지'를 기록 할 수있는 코드를 보았습니다. 멋지지만 오디오도 필요합니다.

지금까지 가지고있는 클라이언트 측 코드는 다음과 같습니다.

  <video autoplay></video>

<script language="javascript" type="text/javascript">
function onVideoFail(e) {
    console.log('webcam fail!', e);
  };

function hasGetUserMedia() {
  // Note: Opera is unprefixed.
  return !!(navigator.getUserMedia || navigator.webkitGetUserMedia ||
            navigator.mozGetUserMedia || navigator.msGetUserMedia);
}

if (hasGetUserMedia()) {
  // Good to go!
} else {
  alert('getUserMedia() is not supported in your browser');
}

window.URL = window.URL || window.webkitURL;
navigator.getUserMedia  = navigator.getUserMedia || navigator.webkitGetUserMedia ||
                          navigator.mozGetUserMedia || navigator.msGetUserMedia;

var video = document.querySelector('video');
var streamRecorder;
var webcamstream;

if (navigator.getUserMedia) {
  navigator.getUserMedia({audio: true, video: true}, function(stream) {
    video.src = window.URL.createObjectURL(stream);
    webcamstream = stream;
//  streamrecorder = webcamstream.record();
  }, onVideoFail);
} else {
    alert ('failed');
}

function startRecording() {
    streamRecorder = webcamstream.record();
    setTimeout(stopRecording, 10000);
}
function stopRecording() {
    streamRecorder.getRecordedData(postVideoToServer);
}
function postVideoToServer(videoblob) {
/*  var x = new XMLHttpRequest();
    x.open('POST', 'uploadMessage');
    x.send(videoblob);
*/
    var data = {};
    data.video = videoblob;
    data.metadata = 'test metadata';
    data.action = "upload_video";
    jQuery.post("http://www.foundthru.co.uk/uploadvideo.php", data, onUploadSuccess);
}
function onUploadSuccess() {
    alert ('video uploaded');
}

</script>

<div id="webcamcontrols">
    <a class="recordbutton" href="javascript:startRecording();">RECORD</a>
</div>

당신은 확실히 Kurento봐야 합니다. WebRTC 피드 등에서 기록 할 수있는 WebRTC 서버 인프라를 제공합니다. 여기에서 계획중인 응용 프로그램에 대한 몇 가지 예를 찾을 수도 있습니다 . 데모에 레코딩 기능을 추가하고 미디어 파일을 URI (로컬 디스크 또는 모든 위치)에 저장하는 것은 정말 쉽습니다.

이 프로젝트는 LGPL Apache 2.0에 따라 라이센스가 부여되었습니다


1 편집

이 게시물 이후로 몇 가지 시나리오에서 레코더를 추가하는 방법을 보여주는 새 자습서를 추가했습니다.

면책 조항 : 저는 Kurento를 개발하는 팀의 일원입니다.


RecordRTC를 확인하십시오

RecordRTC는 github에서 MIT 라이센스를 받았습니다 .


특히 Chrome이 v25 이후 v47 및 Firefox에서 MediaRecorder API를 지원 한다는 사실을 고려할 때 비디오 녹화를 위해 kurento 또는 기타 MCU를 사용하는 것은 약간 과잉 일 것이라고 생각합니다 . 따라서이 교차점에서 작업을 수행하기 위해 외부 js 라이브러리가 필요하지 않을 수도 있습니다. MediaRecorder를 사용하여 비디오 / 오디오를 녹화하기 위해 만든이 데모를 시도해보십시오.

데모 -크롬 및 파이어 폭스에서 작동합니다 (의도적으로 blob을 서버 코드로 푸시하지 않음)

Github 코드 소스

파이어 폭스를 실행하는 경우 여기에서 직접 테스트 할 수 있습니다 (크롬 필요 https).

'use strict'

let log = console.log.bind(console),
  id = val => document.getElementById(val),
  ul = id('ul'),
  gUMbtn = id('gUMbtn'),
  start = id('start'),
  stop = id('stop'),
  stream,
  recorder,
  counter = 1,
  chunks,
  media;


gUMbtn.onclick = e => {
  let mv = id('mediaVideo'),
    mediaOptions = {
      video: {
        tag: 'video',
        type: 'video/webm',
        ext: '.mp4',
        gUM: {
          video: true,
          audio: true
        }
      },
      audio: {
        tag: 'audio',
        type: 'audio/ogg',
        ext: '.ogg',
        gUM: {
          audio: true
        }
      }
    };
  media = mv.checked ? mediaOptions.video : mediaOptions.audio;
  navigator.mediaDevices.getUserMedia(media.gUM).then(_stream => {
    stream = _stream;
    id('gUMArea').style.display = 'none';
    id('btns').style.display = 'inherit';
    start.removeAttribute('disabled');
    recorder = new MediaRecorder(stream);
    recorder.ondataavailable = e => {
      chunks.push(e.data);
      if (recorder.state == 'inactive') makeLink();
    };
    log('got media successfully');
  }).catch(log);
}

start.onclick = e => {
  start.disabled = true;
  stop.removeAttribute('disabled');
  chunks = [];
  recorder.start();
}


stop.onclick = e => {
  stop.disabled = true;
  recorder.stop();
  start.removeAttribute('disabled');
}



function makeLink() {
  let blob = new Blob(chunks, {
      type: media.type
    }),
    url = URL.createObjectURL(blob),
    li = document.createElement('li'),
    mt = document.createElement(media.tag),
    hf = document.createElement('a');
  mt.controls = true;
  mt.src = url;
  hf.href = url;
  hf.download = `${counter++}${media.ext}`;
  hf.innerHTML = `donwload ${hf.download}`;
  li.appendChild(mt);
  li.appendChild(hf);
  ul.appendChild(li);
}
      button {
        margin: 10px 5px;
      }
      li {
        margin: 10px;
      }
      body {
        width: 90%;
        max-width: 960px;
        margin: 0px auto;
      }
      #btns {
        display: none;
      }
      h1 {
        margin-bottom: 100px;
      }
<link type="text/css" rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css">
<h1> MediaRecorder API example</h1>

<p>For now it is supported only in Firefox(v25+) and Chrome(v47+)</p>
<div id='gUMArea'>
  <div>
    Record:
    <input type="radio" name="media" value="video" checked id='mediaVideo'>Video
    <input type="radio" name="media" value="audio">audio
  </div>
  <button class="btn btn-default" id='gUMbtn'>Request Stream</button>
</div>
<div id='btns'>
  <button class="btn btn-default" id='start'>Start</button>
  <button class="btn btn-default" id='stop'>Stop</button>
</div>
<div>
  <ul class="list-unstyled" id='ul'></ul>
</div>
<script src="https://code.jquery.com/jquery-2.2.0.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js"></script>


예, 이해했듯이 MediaStreamRecorder는 현재 구현되지 않았습니다.

MediaStreamRecorder는 getUserMedia () 스트림을 기록하기위한 WebRTC API입니다. 웹 앱이 라이브 오디오 / 비디오 세션에서 파일을 생성 할 수 있습니다.

또는 http://ericbidelman.tumblr.com/post/31486670538/creating-webm-video-from-getusermedia 와 같이 할 수 있지만 오디오가 누락되었습니다.


RecordRTC를 기반으로하는 RecordRTC-together를 사용할 수 있습니다 .

비디오와 오디오를 별도의 파일로 함께 녹화 할 수 있습니다. ffmpeg서버에서 두 개의 파일을 하나로 병합하는 것과 같은 도구가 필요 합니다.


Web Call Server 4 는 WebRTC 오디오 및 비디오를 WebM 컨테이너에 녹음 할 수 있습니다. 녹음은 오디오 용 Vorbis 코덱과 비디오 용 VP8 코덱을 사용하여 수행됩니다. 초기 WebRTC 코덱은 Opus 또는 G.711 및 VP8입니다. 따라서 서버 측 레코딩에는 다른 컨테이너 (예 : AVI)를 사용해야하는 경우 Opus / G.711에서 Vorbis 서버 측 트랜스 코딩 또는 VP8-H.264 트랜스 코딩이 필요합니다.


Janus를 확인하십시오. 다음은 레코딩 데모입니다.

https://janus.conf.meetecho.com/recordplaytest.html

Twilio 인수 후 개발 속도가 크게 둔화 된 Kurento와 달리 Janus는 계속해서 적극적으로 개발 및 지원되고 있습니다.


기록상 저도 이것에 대한 충분한 지식이 없습니다.

하지만 나는 이것을 Git 허브에서 찾았습니다.

<!DOCTYPE html>
 <html>
<head>
  <title>XSockets.WebRTC Client example</title>
  <meta charset="utf-8" />


<style>
body {

  }
.localvideo {
position: absolute;
right: 10px;
top: 10px;
}

.localvideo video {
max-width: 240px;
width:100%;
margin-right:auto;
margin-left:auto;
border: 2px solid #333;

 }
 .remotevideos {
height:120px;
background:#dadada;
padding:10px; 
}

.remotevideos video{
max-height:120px;
float:left;
 }
</style>
</head>
<body>
<h1>XSockets.WebRTC Client example </h1>
<div class="localvideo">
    <video autoplay></video>
</div>

<h2>Remote videos</h2>
<div class="remotevideos">

</div>
<h2>Recordings  ( Click on your camera stream to start record)</h2>
<ul></ul>


<h2>Trace</h2>
<div id="immediate"></div>
<script src="XSockets.latest.js"></script>
<script src="adapter.js"></script>
<script src="bobBinder.js"></script>
<script src="xsocketWebRTC.js"></script>
<script>
    var $ = function (selector, el) {
        if (!el) el = document;
        return el.querySelector(selector);
    }
    var trace = function (what, obj) {
        var pre = document.createElement("pre");
        pre.textContent = JSON.stringify(what) + " - " + JSON.stringify(obj || "");
        $("#immediate").appendChild(pre);
    };
    var main = (function () {
        var broker;
        var rtc;
        trace("Ready");
        trace("Try connect the connectionBroker");
        var ws = new XSockets.WebSocket("wss://rtcplaygrouund.azurewebsites.net:443", ["connectionbroker"], {
            ctx: '23fbc61c-541a-4c0d-b46e-1a1f6473720a'
        });
        var onError = function (err) {
            trace("error", arguments);
        };
        var recordMediaStream = function (stream) {
            if ("MediaRecorder" in window === false) {
                trace("Recorder not started MediaRecorder not available in this browser. ");
                return;
            }
            var recorder = new XSockets.MediaRecorder(stream);
            recorder.start();
            trace("Recorder started.. ");
            recorder.oncompleted = function (blob, blobUrl) {
                trace("Recorder completed.. ");
                var li = document.createElement("li");
                var download = document.createElement("a");
                download.textContent = new Date();
                download.setAttribute("download", XSockets.Utils.randomString(8) + ".webm");
                download.setAttribute("href", blobUrl);
                li.appendChild(download);
                $("ul").appendChild(li);
            };
        };
        var addRemoteVideo = function (peerId, mediaStream) {
            var remoteVideo = document.createElement("video");
            remoteVideo.setAttribute("autoplay", "autoplay");
            remoteVideo.setAttribute("rel", peerId);
            attachMediaStream(remoteVideo, mediaStream);
            $(".remotevideos").appendChild(remoteVideo);
        };
        var onConnectionLost = function (remotePeer) {
            trace("onconnectionlost", arguments);
            var peerId = remotePeer.PeerId;
            var videoToRemove = $("video[rel='" + peerId + "']");
            $(".remotevideos").removeChild(videoToRemove);
        };
        var oncConnectionCreated = function () {
            console.log(arguments, rtc);
            trace("oncconnectioncreated", arguments);
        };
        var onGetUerMedia = function (stream) {
            trace("Successfully got some userMedia , hopefully a goat will appear..");
            rtc.connectToContext(); // connect to the current context?
        };
        var onRemoteStream = function (remotePeer) {
            addRemoteVideo(remotePeer.PeerId, remotePeer.stream);
            trace("Opps, we got a remote stream. lets see if its a goat..");
        };
        var onLocalStream = function (mediaStream) {
            trace("Got a localStream", mediaStream.id);
            attachMediaStream($(".localvideo video "), mediaStream);
            // if user click, video , call the recorder
            $(".localvideo video ").addEventListener("click", function () {
                recordMediaStream(rtc.getLocalStreams()[0]);
            });
        };
        var onContextCreated = function (ctx) {
            trace("RTC object created, and a context is created - ", ctx);
            rtc.getUserMedia(rtc.userMediaConstraints.hd(false), onGetUerMedia, onError);
        };
        var onOpen = function () {
            trace("Connected to the brokerController - 'connectionBroker'");
            rtc = new XSockets.WebRTC(this);
            rtc.onlocalstream = onLocalStream;
            rtc.oncontextcreated = onContextCreated;
            rtc.onconnectioncreated = oncConnectionCreated;
            rtc.onconnectionlost = onConnectionLost;
            rtc.onremotestream = onRemoteStream;
            rtc.onanswer = function (event) {
            };
            rtc.onoffer = function (event) {
            };
        };
        var onConnected = function () {
            trace("connection to the 'broker' server is established");
            trace("Try get the broker controller form server..");
            broker = ws.controller("connectionbroker");
            broker.onopen = onOpen;
        };
        ws.onconnected = onConnected;
    });
    document.addEventListener("DOMContentLoaded", main);
</script>

필자의 경우 89 번 줄에서 OnrecordComplete는 실제로 레코더 파일의 링크를 추가합니다. 해당 링크를 클릭하면 다운로드가 시작되고 해당 경로를 서버에 파일로 저장할 수 있습니다.

녹음 코드는 다음과 같습니다.

recorder.oncompleted = function (blob, blobUrl) {
                trace("Recorder completed.. ");
                var li = document.createElement("li");
                var download = document.createElement("a");
                download.textContent = new Date();
                download.setAttribute("download", XSockets.Utils.randomString(8) + ".webm");
                download.setAttribute("href", blobUrl);
                li.appendChild(download);
                $("ul").appendChild(li);
            };

blobUrl은 경로를 보유합니다. 나는 이것으로 내 문제를 해결했고 누군가가 이것을 유용하게 생각하기를 바랍니다.


기술적으로 백엔드에서 FFMPEG를 사용하여 비디오와 오디오를 혼합 할 수 있습니다.

참고 URL : https://stackoverflow.com/questions/16571044/how-to-record-webcam-and-audio-using-webrtc-and-a-server-based-peer-connection

반응형