如何使用 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>
110169 次浏览

yes, as you understood, MediaStreamRecorder is currently unimplemented.

MediaStreamRecorder is a WebRTC API for recording getUserMedia() streams . It allows web apps to create a file from a live audio/video session.

alternatively you may do like this http://ericbidelman.tumblr.com/post/31486670538/creating-webm-video-from-getusermedia but audio is missing part.

Please, check the RecordRTC

RecordRTC is MIT licensed on github.

You can use RecordRTC-together, which is based on RecordRTC.

It supports recording video and audio together in separate files. You will need tool like ffmpeg to merge two files into one on server.

Technically you can use FFMPEG on backend to mix video and audio

You should definitely have a look at Kurento. It provides a WebRTC server infrastructure that allows you to record from a WebRTC feed and much more. You can also find some examples for the application you are planning here. It is really easy to add recording capabilities to that demo, and store the media file in a URI (local disk or wherever).

The project is licensed under LGPL Apache 2.0


EDIT 1

Since this post, we've added a new tutorial that shows how to add the recorder in a couple of scenarios

Disclaimer: I'm part of the team that develops Kurento.

Web Call Server 4 can record WebRTC audio and video to WebM container. The recording is done using Vorbis codec for audio and VP8 codec for video. Iniitial WebRTC codecs are Opus or G.711 and VP8. So, the server-side recording requires either Opus/G.711 to Vorbis server-side transcoding or VP8-H.264 transcoding if it is necessary to use another container, i.e. AVI.

I believe using kurento or other MCUs just for recording videos would be bit of overkill, especially considering the fact that Chrome has MediaRecorder API support from v47 and Firefox since v25. So at this junction, you might not even need an external js library to do the job, try this demo I made to record video/ audio using MediaRecorder:

Demo - would work in chrome and firefox (intentionally left out pushing blob to server code)

Github Code Source

If running firefox, you could test it in here itself( chrome needs 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>

For the record I also don't have enough knowledge about this,

But I found this on Git hub-

<!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>

On Line number 89 in my case code OnrecordComplete actually append a link of recorder file, if you will click on that link it will start the download, you can save that path to your server as a file.

The Recording code looks something like this

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);
};

The blobUrl holds the path. I solved my problem with this, hope someone will find this useful

Currently the browsers support recording on the client side.

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

One can push the recorded file after the connection has been ended to server by uploading through some HTTP requests.

https://webrtc.github.io/samples/src/content/getusermedia/record/ https://github.com/webrtc/samples/tree/gh-pages/src/content/getusermedia/record

This has some kind of drawbacks that in case if the user just closes the tab and don't run these operations in the backend side, it may not uploaded the files fully to the server.

As a more stable solution Ant Media Server can record the stream on server side and recording functionality is one of the basic feature of Ant Media Server.

antmedia.io

Note: I'm a member of Ant Media team.