js创建audioTrack和videoTrack并绑定到stream上
最近用webRTC做P2P音视频通讯时,开始是在getUserMedia()成功调用后的回调函数中,处理pc.addTrack(track, stream),可是这样出现一个bug:A作为主持人,B作为参会者,当A没有摄像头设备,B有摄像头时,A和B成功建立通讯,可是A却看不到B的画面,研究发现:
参会方B的audioTrack和videoTrack都成功addTrack了,可是主持人方A在onTrack时却只收到了B的audioTrack,个人猜测可能是因为WebRTC的sender和receiver对应一个通道,当发送方没有videoTrack时,也无法收到接收方的videoTrack,但是反之却不影响(并不肯定)。
这是一个问题,还有一个问题就是:如果开会前没有媒体设备,而在会议中途插入媒体设备,该如何处理,双方需要重新协商吗?我并不想重新协商,因为P2P的多方重新协商太繁琐,我想尽量避免。
于是就想能否提前产生audioTrack和videoTrack,PC端用C实现也是这一原理,这样就不必等到getUserMedia()成功后addTrack,在开始addTrack,初始如果没有摄像头设备自然没有画面,等到有媒体设备后只要利用我上一篇博客替换摄像头的原理,将track替换掉就行,成功避免了上述问题,而且还加快了入会速度。
下面就简单记录一下创建audioTrack和videoTrack的几种方法:
1. 创建audioTrack
主要有两种方法:1)从video元素上获取;2)利用WebRTC的Audio API创建。
1.1 从video元素获取audioTrack/videoTrack
要注意这个方法是异步操作。要先保证video能够play,然后在oncanplay监听事件的回调中才能获取audiotrack。
var video;
var stream_video ;
var stream_media ;
video = document.getElementById('streamVideo');
video.play();
video.oncanplay = await maybeCreateStream;
function maybeCreateStream () {
stream_video = video.captureStream() || video.mozCaptureStream();
// 创建一个用于视频的空stream
stream_media = new MediaStream();
videoTrack_media = stream_video .getVideoTracks()[0].clone();
audioTrack_media = stream_video .getAudioTracks()[0].clone();
// 绑定
stream_media.addTrack(videoTrack_media);
stream_media.addTrack(audioTrack_media);
}
1.2 利用WebRTC的Audio API创建audioTrack
let audioCtx = new AudioContext();
let dest = audioCtx.createMediaStreamDestination();
let aStream = dest.stream;
var audioTrack_media = aStream.getAudioTracks()[0];
console.log(audioTrack_media);
2. 创建videoTrack
主要有两种方法:1)从video元素上获取;2)从canvas元素上获取。
2.1 从video元素获取audioTrack/videoTrack
同1.1
2.2 从canvas元素上获取
特别注意:火狐从canvas上获取stream时的兼容性处理
还有,canvas上获取的流是MediaStream类型,但是该stream上获取的videoTrack其实并不是MediaStreamTrack类型,而是CanvasCaptureMediaStreamTrack类型,但是不影响addTrack()
//初始化用于获取track的canvas/video的流
var screenTrackId;
var videoTrack_media;
let canvas = document.getElementById('emptyCanvas')
// Eden 21-01-29 处理兼容性,火狐浏览器必须加上
let ctx = canvas.getContext('2d')
let stream_canvas = canvas.captureStream() || canvas.mozCaptureStream();
videoTrack_media = stream_canvas.getVideoTracks()[0].clone();
上面的方案中我推荐方案2,方案2是同步方法,可以加快入会速度。
3. 创建空的stream,并绑定track
track创建完之后,注意还要和stream绑定,所以还需要创建空的stream,分别绑定上面创建audioTrack和videoTrack。
var stream_media = new MediaStream(); // 提前视频流
stream_media .addTrack(audioTrack_media);
stream_media .addTrack(videoTrack_media);