本文将详细解析青龙流式系统的三大API:MediaStream、RTCPeerConnection和RTCDataChannel,帮助读者理解并应用这些技术。
MediaStream
MediaStream API是WebRTC中的关键组件之一,它允许使用JavaScript访问设备的摄像头和麦克风。通过使用这个API,开发者可以控制多媒体流数据的消费位置,并对产生媒体的设备进行一定的控制。此外,MediaStream API还提供了有关能够捕获和呈现媒体的设备的信息。
在使用MediaStream API时,我们需要注意以下几点:
- 确保浏览器支持该API,并在用户同意的情况下获取媒体访问权限。
- 根据需求选择合适的媒体类型和分辨率,以保证通信质量和性能。
- 在通信结束时,确保正确释放媒体资源,避免内存泄漏和性能问题。
getUserMedia
getUserMedia
是什么?
getUserMedia
是 WebRTC API 中用于访问用户音视频设备的接口,包括摄像头和麦克风。无论是通过 USB 连接的设备还是虚拟设备,都可以通过这个 API 进行访问。它允许用户授予网页访问其设备的权限,并返回一个MediaStream
对象,其中包含了音视频轨道。
如何使用 getUserMedia
?
在简单场景下,直接调用 getUserMedia
的默认参数即可获取 PC 的默认摄像头和麦克风。然而,在处理复杂场景时,例如选择特定的设备,可以按以下步骤操作:
- 列出所有可用的媒体设备:获取设备列表以便选择。
- 选择所需的设备:从设备列表中选择适合的摄像头和麦克风。
- 配置并传递设备信息:将所选设备的信息传递给浏览器 API 以进行设置。
// 1. 列出所有可用的媒体设备
navigator.mediaDevices.enumerateDevices()
.then(devices => {
devices.forEach(device => {
console.log(device.kind, device.label, device.deviceId);
});
// 2. 根据用户选择的 deviceId 请求媒体流
const constraints = {
audio: { deviceId: { exact: selectedAudioDeviceId } },
video: { deviceId: { exact: selectedVideoDeviceId } }
};
// 3. 请求用户媒体流
return navigator.mediaDevices.getUserMedia(constraints);
})
.then(stream => {
// 将媒体流绑定到视频或音频元素上
const videoElement.srcObject = stream;
})
.catch(error => {
// 处理获取媒体流失败的情况
console.error('媒体设备访问失败:', error);
});
媒体约束 constraints
在上述代码片段中,constraints
参数用于指定音视频设备和其属性。以下是几种常见配置及其应用场景:
- 同时获取视频和音频输入
const constraints = { audio: true, video: true }
如果没有视频设备,调用时会报错。可以先使用 enumerateDevices
判断是否有视频输入源,再决定是否设置 video
为 false
。
- 指定设备
const constraints = { audio: { deviceId: audioId }, video: { deviceId: videoId } }
- 指定分辨率
根据网络带宽和设备能力设置分辨率。例如:
// 高分辨率
const constraints = {
audio: true,
video: {
width: { min: 320, ideal: 1280, max: 1920 },
height: { min: 240, ideal: 720, max: 1080 }
}
}
// 低分辨率
const constraints = {
audio: true,
video: { width: 720, height: 480 }
}
- 指定摄像头方向
使用 facingMode
属性来选择前置或后置摄像头:
// 前置
const constraints = { audio: true, video: { facingMode: "user" } }
// 后置
const constraints = { audio: true, video: { facingMode: { exact: "environment" } } }
- 指定帧速率
frameRate
帧速率影响视频的流畅度。可以根据网络条件调整帧速率:
const constraints = {
audio: true,
video: {
width: 1920,
height: 1080,
frameRate: { ideal: 10, max: 24 }
}
}
getDisplayMedia
getDisplayMedia
是什么?
getDisplayMedia
API 用于在浏览器中实现屏幕分享功能。它允许用户选择并分享整个屏幕或特定应用窗口,适用于远程会议和在线演示等场景。
如何使用 getDisplayMedia
?
调用 getDisplayMedia
获取屏幕分享的媒体流。此 API 返回一个 Promise
,解析值为包含屏幕视频流的 MediaStream
对象。
async function getShareMedia() {
const constraints = {
video: { width: 1920, height: 1080 },
audio: false
};
// 停止之前的媒体流
if (window.stream) {
window.stream.getTracks().forEach(track => track.stop());
} try {
return await navigator.mediaDevices.getDisplayMedia(constraints);
} catch (error) {
console.error('屏幕分享失败:', error);
}
}
媒体约束 Constraints
- 基本配置
- 在屏幕分享中video属性不能设置为false。
const constraints = { video: true };
- 指定分辨率
constraints = { video: { width: 1920, height: 1080 } };
- 音频设置
- 如果需要分享系统音频,可以将
audio
设置为true
。注意,并非所有浏览器都支持音频分享功能。
const constraints = { audio: true, video: { width: 1920, height: 1080 }};
- 示例对比:
- 有音频:
- **无音频:**当audio设置为false后,底部就少了开启系统音频的按钮。
小提示:
在获取新的媒体流之前,建议停止之前的媒体流,以避免设备使用提示,并确保应用逻辑清晰。
if (window.stream) {
window.stream.getTracks().forEach(track => track.stop());
}
RTCPeerConnection
RTCPeerConnection
是什么?
RTCPeerConnection
用于管理音视频连接。它帮助你建立和维护与其他用户的实时通信,处理媒体流、网络连接等问题。
RTCPeerConnection API
是每个浏览器之间点对点连接的核心,RTCPeerConnection
是WebRTC
组件,用于处理对等体之间流数据的稳定和有效通信。
RTCPeerConnection
可以保护Web开发人员免受潜伏在其中的无数复杂性的影响。WebRTC
使用的编解码器和协议可以进行大量工作,即使在不可靠的网络上也可以进行实时通信:
- 丢包隐藏
- 回声消除
- 带宽适应性
- 动态抖动缓冲
- 自动增益控制
- 降噪和抑制
- 图像'清洁'。
如何使用 RTCPeerConnection
?
创建 RTCPeerConnection
需要提供一个配置对象,通常包含用于网络穿透的服务器信息(如 STUN 服务器)。
const configuration = {
iceServers: [{ urls: 'stun:stun.l.google.com:19302' }]
};
const peerConnection = new RTCPeerConnection(configuration);
主要功能:
1. 创建连接请求
createOffer()
: 发起连接请求。createAnswer()
: 响应连接请求。
peerConnection.createOffer()
.then(offer => peerConnection.setLocalDescription(offer))
.then(() => {
// 发送 offer 给对端
});
2. 设置描述信息
setLocalDescription(description)
: 设置本地的连接信息。setRemoteDescription(description)
: 设置对端的连接信息。
peerConnection.setRemoteDescription(new RTCSessionDescription(remoteOffer))
.then(() => peerConnection.createAnswer())
.then(answer => peerConnection.setLocalDescription(answer));
3. 处理媒体流
addTrack(track, stream)
: 添加音视频轨道到连接中。addIceCandidate(candidate)
: 添加网络候选地址。
navigator.mediaDevices.getUserMedia({ video: true, audio: true })
.then(stream => {
stream.getTracks().forEach(track => peerConnection.addTrack(track, stream));
});
peerConnection.addIceCandidate(new RTCIceCandidate(candidate));
4. 事件处理
onicecandidate
: 当新的网络候选地址出现时触发。ontrack
: 当接收到对端的媒体流时触发。oniceconnectionstatechange
: 当连接状态变化时触发。
peerConnection.onicecandidate = (event) => {
if (event.candidate) {
// 发送候选地址到信令服务器
}
};
peerConnection.ontrack = (event) => {
const remoteStream = event.streams[0];
// 显示远程媒体流
videoElement.srcObject = remoteStream;
};
RTCDataChannel
RTCDataChannel
是什么?
RTCDataChannel
是 WebRTC 提供的一个 API,用于在对等端之间传输任意数据。它支持低延迟、可靠性可选的数据传输方式,使得在音视频通信之外,还可以传输文本、文件等数据。
如何使用 RTCDataChannel
?
通过 RTCPeerConnection
创建一个数据通道,并定义其配置。
const dataChannel = peerConnection.createDataChannel("myDataChannel");
主要功能:
1. 发送和接收数据
send(data)
: 通过数据通道发送数据,可以是字符串、二进制数据等。onmessage
: 当接收到数据时触发。
dataChannel.send("Hello, WebRTC!");
dataChannel.onmessage = (event) => {
console.log("Received message:", event.data);
};
2. 事件处理
onopen
: 当数据通道打开时触发。onclose
: 当数据通道关闭时触发。
dataChannel.onopen = () => {
console.log("Data channel is open");
};
dataChannel.onclose = () => {
console.log("Data channel is closed");
};
参考资料
MDN:https://developer.mozilla.org/zh-CN/docs/Web/API/MediaStream