webrtc-设备管理及采集

/post/webrtc-device article cover image

enumeratedevices

获取所有有效的输入输出设备(麦克风、摄像头、穿戴设备等)音视频设备,返回promise其resolve值是所有设备的列表

ts
type MediaDeviceInfo = {
	deviceID: "device's ID",
	label: "device's name",
	kind: "device's category"
	groupID: 'the groupID of several physical devices '
}

navigator.mediaDevices.enumerateDevices().then((deviceList: MediaDeviceInfo[]) => {
	deviceList.forEach(device => {
		console.log('device.label:', device.label, 'device.deviceID: ', device.deviceID);
	})
})

<Callout> 如果未能获取设备权限,返回的设备信息devideID和label则为空. <a target="_blank" href="https://stackoverflow.com/questions/46648645/navigator-mediadevices-enumeratedevices-not-display-device-label-on-firefox">参考StackOverflow</a> 需要下面要讲的api </Callout>

getusermediaconstraints

获取用户权限

constraints[audio: boolean, video: boolean]

用来设置要获取权限的设备媒体类型,如果不先获取权限enumerateDevices获取的设备信息将为空

js
function getDeviceInfo() {
  navigator.mediaDevices.enumerateDevices().then((deviceList) => {
		deviceList.forEach(device => {
			console.log({
				'label': device.label,
				'deviceID': device.deviceID
			});
		})
	})
}

// must be get user permission at first
navigator.mediaDevices.getUserMedia({audio: true, video: true})
	.then(stream => {
		getDeviceInfo();
		getMediaStream(stream);
	})
	.catch(error => {
		console.log('Error :', error)
	})

getusermedia的不同实现适配

使用属性探侦的方式获取可用方法

js
const getUserMedia = navigator.getUserMedia ||
					 navigator.webkitGetUserMedia ||
					 navigator.mozGetUserMedia;

使用Google开源库的adapter.js,实际项目中使用最近release的版本号而非latest版(可能会有break change功能,导致不同浏览器出现问题)

视频采集的约束

  • 视频一般的分辨率(aspectRatio)是4:3和16:9
  • frameRate: 帧率(30、60、120),帧率越高流就越大
  • facingMode: user(前置摄像头)、enviroment(后置摄像头)、left(前置左侧摄像头)、right(前置右侧摄像头)
  • resizeMode: 是否需要裁剪
js
const constraints = {
	audio: false,
	video: {
		width: 320,
		height: 240,
		frameRate: 30,
		facingMode: 'enviroment'
	}
}

navigator.mediaDevices.getUserMedia(constraints).then(res => {
	const video = document.querySelector('video');
	video.srcObject = mediaStream;
	video.onloadedmetadata = (e) => {
	  video.play();
	};
}).catch(err => console.log(err.name + ':' + err.message))

音频采集的约束

  • volume(声音): number
  • sampleRate(采样率): number
  • sampleSize(采样大小): number
  • echoCancellation(回音消除): boolean
  • autoGainControl(自动增音): boolean
  • noiseSuppression(降噪): boolean
  • latency(延迟大小200ms - 500ms): number
  • channelCount(单双声道): number
  • deviceId(设备ID): string
  • groupId(物理设备类ID): string

<Callout type="info"> 参考MDN文档查看具体参数及用法 <a target="_target" href="https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia">getUserMedia</a>、 <a target="_target" href="https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getSupportedConstraints">getSupportedConstraints</a>、 <a target="_target" href="https://developer.mozilla.org/en-US/docs/Web/API/MediaTrackConstraints">MediaTrackConstraints</a> <p className="mt-2"> 所有参数默认都是Boolean类型,同时也可设置为包含了exact、ideal、min、max属性的对象(根据具体属性的不同而异),如果传入属性的值不正确则会取系统最接近的值替换具体查看。 <a target="_target" href="https://developer.mozilla.org/en-US/docs/Web/API/Media_Streams_API/Constraints#example__constraint_exerciser">example__constraint_exerciser</a> </p> </Callout>

js
navigator.mediaDevices.getUserMedia({
  video: {
    width: { min: 640, ideal: 1920 },
    height: { min: 400, ideal: 1080 },
    aspectRatio: { ideal: 1.7777777778 }
  },
  audio: {
    sampleSize: 16,
    channelCount: 2
  }
}).then(stream => {
  videoElement.srcObject = stream;
}).catch(handleError);

浏览器视频特效

通过CSS filter、-webkit-filter/filter与video标签关联

<Callout type="info">只需将对应过滤特效css应用到video标签样式属性即可</Callout>

从视频中获取图片

只需要通过捕捉当前视频的当前帧即可

js
pictureCanvas.getContext('2d').drawImage(
	video,
	0,
	0,
	picture.width,
	picture.height
);

音频录制

和视频录制同理,通过getUserMedia获取媒体流并放置到audio源中

html
<audio autoplay controls id='audioplayer'></audio>
js
navigator.mediaDevices.getUserMedia({audio: true, video: false}).then(res => {
	audioplayer.srcObject = mediaStream;
}).catch(err => console.log(err.name + ':' + err.message))

mediastream

MediaStream中的方法与事件

<Callout type="info"> Mdn文档 <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/API/MediaStream">MediaStream</a>、 <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/API/MediaStream/addtrack_event">MediaStream event</a>、 <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/API/MediaStreamTrack">MediaStreamTrack</a> </Callout>

属性

  • MediaStream.active => boolean 是否活动状态
  • MediaStream.id => boolean 一个包含了36个字节的uuid

方法

  • MediaStream.addTrack() 添加媒体轨
  • MediaStream.removeTrack() 移除媒体轨
  • MediaStream.clone() 根据传入的MediaStream返回其副本,但是副本具有其唯一id
  • MediaStream.getTrackById() 根据trackid获取媒体轨
  • MediaStream.getTracks() 获取所有媒体轨
  • MediaStream.getVideoTracks() 获取视频轨
  • MediaStream.getAudioTracks() 获取音频轨

事件

  • onaddtrack 当添加媒体轨时触发
  • onremovetrack 当移除媒体轨时触发
  • active(不推荐) 当激活状态时触发
  • inactive(不推荐) 当失活状态时触发
  • onended 当流的readyState结束时触发

获取视频流的配置

js
navigator.mediaDevices.getUserMedia({audio: false, video: true})
.then(mediaStream => {
	const videoTrack = mediaStream.getVideoTracks()[0];
	const videoConstraints = videoTrack.getSettings();

	// 预期和传入的constraints相同否则展示默认配置
	divConstraints.textContent = JSON.stringify(videoConstraints, null, 2);
})