WebRTC通信:getUserMedia访问视频和音频设备

目前Web世界中的一个重大挑战就是实现音频与视频的实时通信(Real Time Communi-cation,RTC)。

最近,由于WebRTC(Web Real Time Communication,Web实时通信)API的出现,媒体数据捕捉技术又有了一个很大的发展。Google、Opera、Mozilla等公司或组织均正在努力将其在自己的浏览器中实现。
WebRTC API是一个与getUserMedia方法紧密相关的API,它提供一种访问客户端本地的摄像头或麦克风设备的能力。
WebRTC项目的目标原则是其API是开源、免费、标准的,内置在Web浏览器中,因此比许多现有技术更经济实用。
总体来说,WebRTC包含以下三个API:
MediaStream(亦称getUserMedia)
RTCPeerConnection
RTCDataChannel
目前在Chrome 26以上、Firefox 24以上、Opera 18以上版本的浏览器中均支持WebRTC的实现。目前在Chrome及Opera浏览器中将RTCPeerConnection命名为webkitRTCPeerConnection,在Firefox浏览器中将RTCPeerConnection命名为mozRTCPeerConnection。当WebRTC标准稳定后,其前缀将会被移除。

使用getUserMedia方法访问本地设备

通过使用getUserMedia方法,我们可以不依靠插件而直接访问客户端本地的摄像头设备与麦克风设备。

可以通过如下方法来检测浏览器是否支持getUserMedia方法。

function hasGetUserMedia() {
    return !!(navigator.getUserMedia || navigator.webkitGetUserMedia ||
    navigator.mozGetUserMedia);
}
if (hasGetUserMedia()) {
    alert('您的浏览器支持getUserMedia方法');
}
else {
    alert('您的浏览器不支持getUserMedia方法');
}

获取对视频输入设备或音频输入设备的访问权限

为了访问客户端摄像头或麦克风等视频或音频输入设备,我们首先需要使用getUserMedia方法获取对这些设备的访问权限。

<video id="myVideo" width="400" height="300" autoplay></video>
navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || window.navigator.mozGetUserMedia;
window.URL = window.URL || window.webkitURL;
var video = document.getElementById('myVideo');
navigator.getUserMedia({video:true,audio:false},function(stream){
    video.src = window.URL.createObjectURL(stream);
},function(err){
    console.log(err)
})

在Chrome浏览器中打开示例页面,浏览器将首先询问用户是否允许脚本访问本地摄像头

当用户鼠标单击图中的“允许”按钮后,浏览器中显示从用户本地摄像头中捕捉到的影像

在getUserMedia方法中,使用三个参数,其中第一个参数值为一个约束(constraints)对象,该对象具有一个video属性及一个audio属性,属性值均为布尔类型,当video属性值为true时代表捕捉视频信息,当video属性值为false时代表不捕捉视频信息,当audio属性值为true时代表捕捉音频信息,当audio属性值为false时代表不捕捉音频信息。浏览器中弹出的要求用户给予权限的请求窗口内容也会根据约束对象的不同而有所改变

getUserMedia方法中的第二个参数值为开发者自行定义的当访问用户本地设备成功时所执行的回调函数,该回调函数具有一个参数,参数值为一个MediaStream对象,当浏览器执行getUserMedia方法时将自动创建该对象。该对象代表同步媒体数据流。例如,一个来自于摄像头及麦克风输入设备的同步媒体数据流往往是来自于视频轨道及音频轨道的同步数据。每一个MediaStream对象都拥有一个字符串类型的ID属性,例如“D1f LEJGBS9SZFdp6YwWu6VDQY1g PL2kCfAAJ”,以标识每一个同步媒体数据流。该对象的getAudioTracks()方法或getVideoTracks()方法将返回一个MediaStreamTrack对象数组。每一个MediaStreamTrack对象代表一个视频轨道或一个音频轨道,每一个MediaStreamTrack对象均具有一个字符串类型的kind属性值,以标识轨道种类,例如“video”或“audio”。每一个MediaStreamTrack对象均具有一个字符串类型的label属性值,以标识音频通道或视频通道,例如“USB2.0 PC CAMERA(1908:2310)”。
getUserMedia方法中的第三个参数值为开发者自行定义的当访问用户本地设备失败时所执行的回调函数,该回调函数具有一个参数,参数值为一个error对象,代表浏览器抛出的错误对象。

所示示例中,同时结合了video元素的使用。URL.createObjectURL()方法允许将一个MediaStream对象转换为一个Blob URL,以便将其设置为一个video元素的属性(在支持WebRTC的浏览器中,可以将video元素的src属性值直接设置为数据流)。

同时为video元素使用autoplay属性,如果不使用该属性,则video元素将停留在所获取的第一帧画面处。

实现拍照功能

在Canvas API中,可以使用图形上下文对象的drawImage方法将video元素中的某一帧画面输出到canvas元素中。当然,既然我们已经将捕捉到的用户摄像头中的图像信息输出到video元素中,当然也可以将图像信息通过video元素输出到canvas元素中,即实现实时拍照功能

<video id="myVideo" width="400" height="300" autoplay></video>
<img src="" id="img" />
<canvas width="400" height="300" id="canvas" style="display: none;"></canvas>
navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || window.navigator.mozGetUserMedia;
window.URL = window.URL || window.webkitURL;
var video = document.getElementById('myVideo');
video.addEventListener('click',snapshot,false);
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
var localMediaStream = null;
navigator.getUserMedia({video:true,audio:false},function(stream){
    video.src = window.URL.createObjectURL(stream);
    localMediaStream = stream;
},function(err){
    console.log(err);
});

function snapshot(){
    if(localMediaStream){
        ctx.drawImage(video,0,0);
        document.getElementById('img').src = canvas.toDataURL('image/png')
    }
}

在浏览器中访问示例页面,给予页面访问本地摄像头的权限,待video元素中显示从摄像头实时捕捉到的视频信息后,用鼠标单击video元素,页面中的img元素中将显示鼠标单击video元素时video元素中显示的影像