一、API
有些浏览器获取音视频设备的权限要求不高,比如Chrome浏览器;不过狐火相对就比较高了,要想在诸如火狐或者MAC的浏览器中获取设备名称,可以在允许浏览器访问摄像头之后,再去显示(Promise对象多次调用,在放置媒体流后返回enumerateDevices()
)。
var newPromise = navigator.mediaDevices.getUserMedia(restrict).then(showVideo).catch(handleErorrs);
var nPromise = newPromise.then(gotDevices).catch(handleErorrs);
function showVideo(stream) {
videoPlayer.srcObject = stream;
return navigator.mediaDevices.enumerateDevices();
}
稍微看下某些API的源码,也可以帮助记忆,下图圈出来的Promise对象数组都是带有一些属性的,可以在then里面的函数中作为参数传入。
录音视频的时候,WebRTC对于不同的媒体流合并的时候很可能会有错误,最好每次都将data清空。
当start()
不写时间片的时候,执行到stop()
才会触发MediaRecorder.ondataavailable事件
。这个事件是异步调用的,最好将生成Blob对象的代码和stop函数分开。
btnStart.click(() => {
if (btnStart.html() == 'Start Recorder') {
buffer = [];
var options = {
mimeType: "video/webm;codecs=vp8"
}
try {
recorder = new MediaRecorder(globalStream, options);
} catch (e) {
console.error("发生了" + e + "错误");
}
recorder.ondataavailable = pushData; //位置比较随意
recorder.start();
btnStart.html('Stop Recorder');
btnPause.prop("disabled", false);
} else if (btnStart.html() == 'Stop Recorder') {
recorder.stop();
btnStart.html('Start Recorder');
btnPlay.prop("disabled", false);
btnPause.prop("disabled", true);
}
});
btnPause.click(() => {
if (btnPause.text() == 'Pause Recorder') {
recorder.pause(); //暂停录制
btnPause.text('Resume Recorder');
} else if (btnPause.text() == 'Resume Recorder') {
recorder.resume(); //恢复录制
btnPause.text('Pause Recorder');
}
});
btnPlay.click(function () {
var bb = new Blob(buffer, { type: 'video/webm' });
rePlayer.src = window.URL.createObjectURL(bb);
rePlayer.srcObject = null;
rePlayer.controls = true;
rePlayer.play();
});
function pushData(e) {
console.log(e);
if (e.data && e.data.size > 0) {
buffer.push(e.data);
}
}
二、SignalServer
WebRTC的服务端采用的当然是长连接。此时我不由得陷入了思考,那之前java做的两个helloworld系统都是短连接了。。。
1、服务端
//在客户端连接时被触发
io.sockets.on("connection", function(socket) {
socket.on("join", (room)=>{
socket.join(room); //客户端加入到指定的房间
var myRoom = io.sockets.adapter.rooms[room]; //若房间不存在会自动创建
var usersCount = Object.keys(myRoom.sockets).length; //获取指定房间内的用户
});
});
2、客户端
客户端通过用socket.on()
注册处理函数,socket.emit()
发送消息。客户端、服务端都部署在同一nodejs服务器下面,可以相互通信。自定义注册函数的时候,最好不要命名为connent、disconnect、message等,这些都有特殊用法。
由于传输流媒体一般是与服务端的长连接,为减轻服务器压力,所以服务端需要通过socket.leave(room);
断开和客户端的连接句柄。断开之后,服务器和客户端不能再交换消息(一定要放在服务端注册函数的最后!)。
传消息的不同函数:
socket.emit(); //给本次连接发消息
io.sockets.in(room).emit(); //给房间内的所有人发消息
socket.to(room).emit(); //给房间内除本次连接外的所有人发消息
socket.broadcast.emit(); //给站点上除本次连接外的所有人发消息