WebRTC 使用 RTCPeerConnection 接口来管理对等连接,该接口提供了建立、管理、监控、关闭对等连接的方法。
//RTCPeerConnection接口定义
interface RTCPeerConnection : EventTarget {
constructor(optional RTCConfiguration configuration = {});
static Promise<RTccertificate> generateCertificate(AlgorithmIdentifier keygenAlgorithm);
Promise<RTCSessionDescriptionInit> createOffer(optional RicofferOptions options = {});
Promise<RTCSessionDescriptionInit> createAnswer(optional RTCAnswerOptions options = {});
Promise<void> setLocalDescription(optional RTcSessionDescriptionInit description = {});
readonly attribute RTCSessionDescription? localDescription;
readonly attribute RTcSessionDescription? currentLocalDescription;
readonly attribute RTCSessionDescription? pendingLocalDescription;
Promise<void> setRemoteDescription(optional RrcsessionDescriptionInit description = {});
readonly attribute RTCSessionDescription? remoteDescription;
readonly attribute RTCSessionDescription? currentRemoteDescription;
readonly attribute RTCSessionDescription? pendingRemoteDescription;
Promise<void> addIceCandidate(optional RTCIceCandidateInit candidate = {});
readonly attribute RTCSignalingState signalingState;
readonly attribute RTCIceGatheringState iceGatheringState;
readonly attribute RTCIceConnectionState iceConnectionState;
readonly attribute RTCPeerConnectionState connectionState;
readonly attribute boolean? canTricklelceCandidates;
void restartIce();
RTCConfiguration getConfiguration();
void setConfiguration(optional RTcConfiguration configuration = {});
void close();
attribute EventHandler onnegotiationneeded;
attribute EventHandler onicecandidate;
attribute EventHandler onicecandidateerror;
attribute EventHandler onsignalingstatechange;
attribute EventHandler oniceconnectionstatechange;
attribute EventHandler onicegatheringstatechange;
attribute EventHandler onconnectionstatechange;
}
该构造函数返回一个新创建的 RTCPeerConnection 对象,代表本地与对等端的一个连接。
pc = new RTcPeerConnection([configuration]);
参数:confguration,可选参数,是一个类型为RTCConfiguration的字典对象,提供了创建新连接的配置选项。
返回值:RTCPeerConnection 对象。
下面的代码清单创建了一个 RTCPeerConnection对象,并在参数中指定了TURN和STUN的地址信息,其中TURN服务器地址提供了用户名和密码。
//RTCPeerConnection构造函数示例
const iceConfiguration = {
iceServers: [
{
urls: 'turn:my-turn-server.mycompany.com:19403',
username: 'optional-username',
credentials: 'auth-token'
},
{
urls: [
"stun:stun.example.com",
"stun:stun-l.example.com"
]
}
]
}
const peerConnection = new RTcPeerConnection(iceConfiguration);
出于网络安全性的考虑,通常为TURN服务器指定用户名和密码,这需要configuration参数中指定相应的username和credentials。
RTCConfiguration 的属性说明 | ||
属性 | 类型 | 说明 |
iceServers | sequence<RTCIceServer> | 可选参数,包含 STUN 和 TURN 服务器信息的数组 |
iceTransportPolicy | RTCleeTransportPolicey |
可选参数,指定传输策略,默认值为 all。RTCIceTransportPolicy为枚举类型,枚举值如下: 1) relay,流量全部通过 TURN 服务转发; 2) all,使用任意类型的网络候选,这是 WebRTC 的默认策略 |
bundlePolicy | RTCBundlePolicy | 可选参数,指定 ICE 协商过程中的媒体绑定策略,默认值为 balanced |
rtepMuxPolicy | RTCRtepMuxPolicy | RTC 多路复用策略,当前唯一取值为 require,其含义是仅为 RTP 和 RTCP 收集 ICE 候选者,如果对等端不支持 rtcpmux,则协商失败 |
certificates | sequence<RTCCertificate> | 可选参数,包含证书的数组。如果该参数未指定 WebRTC 将自动为每一个连接创建-套证书 |
iceCandidatePoolSize | octet | 可选参数,指定了 ICE 预取池的大小,默认值为 0,表示关闭 ICE 预取。通常开启 ICE 预取功能,以加速建立连接过程 |
RTCIceServer 的属性说明 | ||
属性 | 类型 | 说明 |
urls | 字符串或者字符串数组 | 必选参数,为 STUN 或 TURN 的服务器地址 |
username | 字符串 | 可选参数,为 TURN 服务器指定的用户名 |
credential | 字符串 | 可选参数,为 TURN 服务器指定的密码 |
credentialType | RTCIceCredentialType | 可选参数,为 TURN 服务器指定的认证方式,默认是 password |
如果对等端不支持绑定(Bundle),绑定策略将影响协商哪些媒体轨道,以及收集哪些 ICE 候选者。如果对等端支持绑定,则所有媒体轨道和数据通道都绑定在同一传输通道上。
RTCBundlePolicy 枚举值说明 | |
枚举值 | 说明 |
balanced | 如果对等端不支持绑定,则为每个音视频轨道单独建立一个传输通道 |
max-compat | 如果对等端不支持绑定,则所有媒体轨道使用同一个传输通道 |
max-bundle | 如果对等端不支持绑定,则只选择一个媒体轨道进行协商,并且只发送一个 |
// RTCCertificate 的定义
interface RTCCertificate {
readonly attribute DOMTimeStamp expires;
sequence<RTCDtlsFingerprint> getFingerprints();
};
dictionary RTCDtlsFingerprint {
DOMString algorithm;
DOMString value;
};
在 RTCCertificate 的属性中,expires 的单位是毫秒,表示证书过期时间,使用过期证书构造 RTCPeerConnection 将返回失败。
getFingerprints() 方法返回证书指纹数组,数组成员类型为 RTCDtlsFingerprint。在 RTCDtlsFingerprint 中,algorithm 是计算指纹数据用到的哈希算法,value 是以小写十六进制字符串表示的指纹数据,使用 generateCertificate() 方法可以创建证书,但我们通常不需要为 WebRTC 指定证书,WebRTC 将自动为每一个连接创建一套证书。
该属性表示对等端是否支持ICETrickle,类型为布尔,值为true表示支持,值为false 表示不支持。
目前大部分支持WebRTC的浏览器,也都支持ICE Trickle,如果不确定是否支持,可以检查该值进行判断。若值为false,则需要等待iceGatheringState值变为completed才能开始获取本地会话描述信息,此时已经完成了ICE候选者的收集,会话描述里包含所有的候选者。该属性由RTCPeerConnection.setRemoteDescription()方法设置,所以必须在此方法成功调用后才能获取。
下面的代码清单演示了属性 canTrickleIceCandidates的使用方法。该示例首先创建了RTCPeerConnection对象pc,调用setRemoteDescription()方法设置从信令服务器收到的会话描述信息remoteOffer,创建并设置本地会话描述 answer,成功后获取属性 canTricklelceCandidates值并判断对等端是否支持ICETrickle,如果支持则获取本地会话描述并回复给对等端。注意,该会话描述只包含已收集的候选者,候选收集过程并没有结束,新的候选者仍然需要发送到对等端。如果不支持则等待icegatheringstatechange事件,待全部完成ICE候选者收集后再获取本地会话描述并回复给对等端。
//canTricklelceCandidates示例
const pc = new RTCPeerConnection();
pc.setRemoteDescription(remoteOffer)
.then(()=> pc.createAnswer())
.then(answer => pc.setLocalDescription(answer))
.then(_ => {
if (pc.canTrickleIceCandidates) {
return pc.localDescription;
}
return new Promise(resolve => {
pc.addEventListener('icegatheringstatechange', e => {
if(e.target.iceGatheringState ==='complete') {
resolve(pc.localDescription);
}
});
});
})
.then(answer => sendAnswerToPeer(answer))
.catch(e => handleError(e));
pc.addEventListener('icecandidate', e => {
if (pc.canTrickleIceCandidates) {
sendCandidateToPeer(e.candidate);
}
});
ICE Trickle 流程要求只要收集到新的ICE候选者,就马上发送给对等端,所以该示例监听了icecandidate事件,在该事件中将新的ICE候选者发送给对等端。
该属性表示建立连接过程中ICE地址收集的状态,类型为RTCSignalingState。可以通过事件 signalingstatechange 探测该属性值的变化。RTCSignalingState 的定义如下面的代码清单所示。
//RTCSignalingState的定义
enum RTCsignalingState {
"stable",
"have-local-offer",
"have-remote-offer",
"have-local-pranswer",
"have-remote-pranswer",
"closed"
};
WebRTC中信号处理使用的是状态机,所以可以通过检查信号状态排查错误。如果收到了应答,但是signalingState值不是have-local-offer,这时候就知道是哪儿出错了,因为只有创建、设置(setLocalDescription)了本地提案并将提案发送给对等端,才有可能收到应答。这时候检查代码,就能找出导致状态错乱的问题。
RTCSignalingState 枚举常量说明 | |
枚举值 | 说明 |
stable | 没有进行中的SDP交换。这种情况出现在:1)RTCPcerConnection刚刚创建,还没有开始SDP交换;2)协商已经完成,连接成功建立 |
have-local-offer | 已经创建了本地提案,并成功调用了setLocalDescription()方法 |
have-remote-offer | 收到了对等端的提案,并成功调用了setRemoteDescription()方法 |
have-local-pranswer | 已经创建了本地应答,并成功调用了setLocalDescription()方法 |
have-remote-pranswer | 收到了对等端的应答,并成功调用了setRemoteDescription()方法 |
closed | 连接已关闭 |
该属性表示建立连接过程中信号处理的状态,类型为RTCIceGatheringState。可以通过事件icegatheringstatechange探测该属性值的变化。RTCIceGatheringState的定义如下面的代码清单所示。
//RTCIceGatheringState的定义
enum RTCIceGatheringState {
"new",
"gathering",
"complete"
}
RTCIceGatheringState的定义 | |
枚举值 | 说明 |
new | RTCPeerConnection 中的 RTCIceTransport 至少有一个处于new状态,并且都没有处于 gathering状态 |
gathering | RTCPeerConnection 中至少有一个 RTCIceTransport 处于 gathering 状态 |
complete | RTCPeerConnection 中所有的 RTCIceTransport 都处于 complete 状态 |
该属性表示与对等连接关联的ICE代理的状态,类型为RTCIceConnectionState。可以通过事件 iceconnectionstatechange探测该属性值的变化。RTCIceConnectionState 的定义如下面的代码清单所示。
//RTCIceConnectionState的定义
enum RTCIceConnectionState {
"closed",
"failed",
"disconnected",
"new",
"checking",
"completed",
"connected"
}
RTCIceConnectionState的定义 | |
枚举值 | 说明 |
new | 所有 RTCIceTransport 对象都处于 new 或 closed 状态 |
checking | 任意一个 RTCIceTransport 对象处于 checking 或 new 状态 |
connected | 所有 RTCIceTransport 对象都处于 connected、completed 或 closed 状态 |
completed | 所有 RTCIceTransport 对象都处于 completed 或 closed 状态 |
disconnected | 任意一个 RTCIceTransport 对象处于 disconnected 状态 |
failed | 任意一个 RTCIceTransport 对象处于 failed 状态 |
closed | RTCPeerConnection 对象处于关闭状态 |
该属性表示对等连接当前的状态,类型为RTCPeerConnectionState。通过事件connectionstatechange可以探测该属性值的变化。RTCPeerConnectionState的定义如下面的代码清单所示。
//RTCPeerConnectionState的定义
enum RTCPeerConnectionState {
"closed",
"failed",
"disconnected",
"new",
"connecting",
"connected"
}
RTCPeerConnectionState 枚举值说明 | |
枚举值 | 说明 |
closed | RTCPcerConnection 对象处于关闭状态 |
failed | 任意一个 RTCIceTransport 或 RTCDtlsTransport 处于 failed 状态 |
disconnected | 任意一个 RTCIceTransport 处于 disconnected 状态 |
new | 所有 RTCIceTransport 和 RTCDtlsTranspot 都处于 new 或 closed 状态,或者当前没有传输通道 |
connecting | 任意一个 RTCIceTransport 处于 checking 状态,或者任意一个 RTCDtlsTransport 处于 connecting 状态 |
connected | 所有 RTCIceTransport 都处于 connected、completed、closed 三种状态之一,并且所有 RTCDtlsTransport 都处于 connected 或 closed 状态 |
该属性表示上一次RTCPeerConnection成功建立连接时使用的本地会话描述,类型为RTCSessionDescription。
该属性表示上一次RTCPeerConnection成功建立连接时使用的对等端会话描述,类型为RTCSessionDescription。
该属性表示处于等待协商状态中的本地会话描述,类型为RTCSessionDescription。
该属性表示处于等待协商状态中的对等端会话描述,类型为RTCSessionDescription。
该属性表示当前本地会话描述,类型为RTCSessionDescription。该属性由setLocalDescription()方法设置,如果在未成功调用setLocalDescription()方法之前获取该属性,则返回空值。
该属性表示当前对等端会话描述,类型为RTCSessionDescription。该属性由setRemoteDescription()方法设置,如果在未成功调用方法setRemoteDescription()之前获取该属性,则返回空值。
WebRTC要求两端的通信必须基于安全连接,在RTCConfiguration里为安全连接提供证书,如果当前没有证书,则可以调用该方法创建证书。
const cert = RTCPeerConnection.generateCertificate(keygenAlgorithm)
参数:keygenAlgorithm,指定创建证书使用的算法。
返回值:RTCCertificate 对象。
下面的代码清单创建证书并在新建连接中使用证书。注意为generateCertificate()方法传入参数的格式和取值,目前大部分浏览器都支持RSASSA-PKCS1-v1_5算法。
//generateCertificate()方法示例
RTCPeerConnection.generateCertificate({
name: "RSASSA-PKCS1-v1_5",
hash: "SHA-256",
modulusLength: 2048,
publicExponent: new Uint8Array([1, 0, 1])
}).then((cert) => {
const pc = new RTCPeerConnection({certificates: [cert]});
});
WebRTC应用从信令服务器收到来自对等端的ICE候选者信息后,调用该方法将候选者信息通知给本地ICE代理层。
aPromise = pc.addIceCandidate(candidate);
参数:candidate,可选参数,类型为RTCIceCandidateInit或者RTCIceCandidate。如果该参数为null,或者传入的对象参数中没有包含candidate属性,则意味着对等端没有更多ICE候选者信息。
返回值:无决议值的Promise对象。
异常:如果该方法调用出错,会抛出如下表所示的异常。
addIceCandidate 调用异常 | |
异常名称 | 说明 |
TypeError | 传人的参数中,属性 sdpMid 和 sdpMLinelndex 同时为空 |
InvalidStateError | RTCPeerConnection 还没有收到对等端的SDP信息,remoteDescription 为空 |
OperationError |
以下原因都可能导致该错误: 1)sdpMid 不为空,但是与 remoteDescription 不匹配; 2)sdpMLineIndex 索引值越界; 3)ufrag 不为空,但是与 remoteDescription 不匹配: 4)candidate 字符串值无效,或者解析失败 |
//addlceCandidate()方法示例
signaling.onmessage = async ({data: {description, candidate}}) => {
try {
if (description) {
await pc.setRemoteDescription(description);
// 如果收到的是提案,则开始应答
if (description.type == 'offer') {
await pc.setLocalDescription();
signaling.send({description: pc.localDescription});
}
// 如果收到的是ICE候选者信息,则调用addIceCandidate()方法
} else if (candidate) {
await pc.addIceCandidate(candidate);
}
} catch (err) {
console.error(err);
}
};
该方法创建SDP提案信息,用于发起WebRTC连接,信息里包含已添加的媒体轨道编码格式、浏览器支持项,以及收集到的ICE候选者等信息。通过信令服务器将提案信息发送给对等端,开始进行建立连接协商。
调用该方法时,signalingState须处于stable或have-local-offer状态,否则将导致InvalidStateError错误。
aPromise = pc.createoffer([options]);
参数:options,可选参数,类型为RTCOfferOptions,包含创建提案的选项。
返回值:Promise值,调用成功则获得类型为RTCSessionDescriptionInit的决议值。
异常:如果调用失败,会抛出如下表所示的异常。
createOffer 调用异常 | |
异常名称 | 说明 |
InvalidStateError | 当前 signalingState 状态为非 stable 或 have-local-offer,或当前连接已关闭 |
NotReadableError | 没有提供安全证书,并且WebRTC也不能创建证书 |
OperationError | 非上述原因导致的其他失败 |
//RTCOfferOptions的定义
dictionary RTCOfferOptions : RTCOfferAnswerOptions {
boolean iceRestart = false:
boolean offerToReceiveAudio;
boolean offerToReceiveVideo;
};
RTCOfferOptions 属性说明 | |
属性 | 说明 |
iceRestart | 默认为false,表示创建的SDP中ICE候选者与currentLocalDescription 相同;true表示创建的SDP中,ICE候选者与currentocalDescription不同 |
offerToReceiveAudio | 默认为true,表示允许对等端发送音频; false表示不允许对等端发送音频 |
offerToReceiveVideo | 默认为true,表示允许对等端发送视频; false表示不允许对等端发送视频 |
下面的代码清单创建了提案信息,如果成功则通过信令服务器发送给对等端,如果失败则进入错误处理流程。
//createOffer()方法示例
pc.createOffer().then((offer) => {
return pc.setLocalDescription(offer);
}).then(() => {
sendToServer({
name: myUsername,
target: targetUsername,
type: "video-offer",
sdp: pc.localDescription
});
}).catch((reason) => {
// 错误处理
});
该方法创建SDP应答信息,信息里包含已添加的媒体轨道、编码格式、浏览器支持项,以及收集到的ICE候选者等信息。通过信令服务器将应答信息发送给提案方,继续进行协商过程。
aPromise = pc.createAnswer([options]);
参数:options,可选参数,类型为RTCAnswerOptions,包含创建应答的选项。
返回值:Promise值,调用成功则获得类型为RTCSessionDescriptionInit的决议值。
异常:如果调用失败,会抛出如下表所示的异常。
createAnswer()异常 | |
异常名称 | 说明 |
NotReadableError | 没有提供安全证书,并且WebRTC也不能创建证书 |
OperationError | 因为资源缺失导致创建失败 |
//RTCAnswerOptions的定义
dictionary RTCAnswerOptions : RTCOfferAnswerOptions {};
dictionary RTCOfferOptions : RTCOfferAnswerOptions {
boolean iceRestart = false;
};
下面的代码清单调用createAnswer()方法创建SDP应答,并通过信令服务器将应答发送给对等端,如果过程中出错,则进入错误处理流程。
//createAnswer()方法示例
try{
answer = await pc.createAnswer();
await pc.setLocalDescription(answer);
sendToServer({
name: myUsername,
target: targetUsername,
type: "video-answer",
sdp: pc.localDescription
});
} catch (err) {
// 错误处理流程
}
我们在 createAnswer() 及 createOffer() 方法的示例中分别使用了 await 和 promise 两种不同的 JavaScript 调用语法,所有返回 Promise 对象的方法都支持这两种调用方式,二者没有优劣之分,读者可以结合应用场景进行选择。
该方法返回 RTCPeerConnection 的当前配置,返回对象类型为RTCConfiguration,配置里包含ICE 服务器列表、传输策略和标识信息。
const configuration = pc.getConfiguration();
参数:无。
返回值:RTCConfiguration 对象。
下面的代码清单调用 getConfguration() 方法获取当前连接的配置,创建新的证书并添加到证书中,再调用 setConfguration() 方法设置新配置。
//getConfiguration()方法示例
let configuration = pc.getConfiguration();
if ((configuration.certificates != undefined) && (!configuration.certificates.length)) {
RTCPeerConnection.generateCertificate({
name: 'RSASSA-PKCS1-v1_5',
hash: 'SHA-256',
modulusLength: 2048,
publicExponent: new Uint8Array([1, 0, 1])
}).then((cert) => {
configuration.certificates = [cert];
pc.setConfiguration(configuration);
});
}
6.setConfiguration() 方法
该方法为当前连接设置配置,通常在以下场景调用该方法。
在创建 RTCPeerConnection 时没有指定 STUN/TURN 服务器地址,随后在ICE协商开始前调用该方法设置 STUN/TURN 服务器地址。
替换原有的 STUN/TURN 服务器地址,然后发起 ICE restart,建立新的连接。
pc.setConfiguration(configuration);
参数: configuration,RTCConfiguration 对象,新的配置将完全替换掉旧的配置。
返回值:无。
异常:如果调用失败,会抛出如下表所示的异常。
setConfiguration 调用异常 | |
异常名称 | 说明 |
InvalidAccessError | 在 iceServers 处指定 TURN 服务器地址,但是因为用户名(RTCIceServer.username) 或者密码(RTCIceServer.credentials)设置错误,导致认证失败 |
InvalidModificationError | peerIdentity 或者 certificates 与当前使用的不一致 |
InvalidStateError | 当前 RTCPeerConnection 连接已关闭 |
SyntaxError | iceServers 地址配置出现语法错误 |
// 设置了 TURN 服务器地址,并重新发起协商。
const restartConfig = {
iceServers: [{
urls: "turn:asia.myturnserver.net",
username: "allie@oopcode.com",
credential: "topsecretpassword"
}]
};
pc.setConfiguration(restartConfig);
pc.createOffer({"iceRestart": true}).then((offer) => {
return pc.setLocalDescription(offer);
}).then() => {
// 将offer发送给对等端
}).catch(error => {
// 错误处理流程
});
该方法为当前连接设置本地会话描述信息。
如果连接已经建立,则意味着需要重新进行协商,此时该调用不会马上生效,而是等 到新的协商完成后才会生效。
aPromise = pc.setLocalDescription(sessionDescription);
参数:sessionDescription,可选参数,类型为RTCSessionDescriptionInit或者RTCSessionDescription,指定了应用到当前连接的本地会话描述信息。如果该参数未指定,则WebRTC会自动创建一个会话描述,并作为该调用的参数默认传入。
返回值:Promise 值,如果成功设置 RTCPeerConnection.localDescription,则返回成
功,否则返回失败。决议值为空值。
下面的代码清单演示了如何隐式设置本地会话描述,该例没有为setLocalDescription()方法指定参数,这会使WebRTC自动调用createOffer()方法生成一个本地会话描述信息这么做的好处是减少调用步骤,使代码更加简洁。
//setLocalDescription()方法的隐式调用
pc.addEventListener("negotiationneeded", async (event) => {
await myPeerConnection.setLocalDescription();
signalRemotePeer({ description: pc.localDescription });
});
下面的代码清单演示了如何显式创建本地会话描述,调用createOffer()方法并将其决议值作为参数传给setLocalDescription()方法,注意与上述隐式调用的区别。
//setLocalDescription()方法的显式调用
pc.addEventListener("negotiationneeded", (event) => {
pc.createOffer().then((offer) => {
return pc.setLocalDescription(offer);
}).then(() => {
signalRemotePeer({ description: pc.localDescription });
}).catch(error => {
// 错误处理流程
});
});
该方法为当前连接设置对等端会话描述信息,通常在收到对等端的提案或者应答后调用该方法。
如果连接已经建立,则意味着需要重新进行协商,此时该调用不会马上生效,而是等到新的协商完成后才会生效。
aPromise = pc.setRemoteDescription(sessionDescription);
参数:sessionDescription,类型为RTCSessionDescriptionInit或者RTCSessionDescription,指定了应用到当前连接的对等端会话描述信息。
返回值:Promise值,如果成功设置remoteDescription,则返回成功,否则返回失败。决议值为空值。
异常:该方法调用失败时,会抛出如下表所示的异常。
setRemoteDescription 调用异常 | |
异常名称 | 说明 |
InvalidAccessError | 传入的会话描述信息包含了无效数据 |
InvalidStateError | 当前 RTCPeerConnection 连接处于关闭状态 |
TyрeError | 传入的会话描述信息没有包含type或者sdp属性 |
RTCError | 传入的会话描述信息包含了错误的语法 |
OperationError | 非以上错误导致的调用失败 |
下面的代码清单演示了 setRemoteDescription() 方法的用法。该示例收到对等端传输过来的 offer 信息,将其作为参数传递给 setRemoteDeseription() 方法,如果调用成功,则调用 getUserMedia() 方法获取本地媒体流,将获取到的媒体流添加到本地连接,然后生成 answer,通过信令服务器传输给对等端。
//setRemoteDescription()方法示例
function handleOffer(msg) {
pc.setRemoteDescription(msg.description).then(()=> {
return navigator.mediaDevices.getUserMedia(mediaConstraints);
}).then((stream) => {
document.getElementById("local_video").srcObject= stream;
return pc.addStream(stream);
}).then(() => {
return pc.createAnswer();
}).then((answer) => {
return pc.setLocalDescription(answer);
}).then(() => {
// 使用信令服务器将answer发送到对等端
}).catch(error => {
// 错误处理流程
});
}
9.restartIce() 方法
调用该方法重新发起 ICE 协商,在该方法之后调用 createOffer() 方法会自动将 iceRestart 设置为 true。
因为该方法将触发 negotiationneeded 事件,所以应该在该事件处理函数中进行ICE协商。在ICE 重新协商的过程中,原有的连接继续生效,媒体流可以正常传输。
pc.restartIce();
参数:无。
返回值:无。
下面的代码清单演示了 restartIce() 方法的用法。当网络连接状态 connectionState 处理 failed 时,调用 restartIce() 方法重新进行ICE协商。
pc.onconnectionstatechange = ev => {
if (pc.connectionState === "failed") {
//网络连接中断,重新进行协商
pc.restartIce();
}
};
10.close() 方法
调用该方法关闭当前连接,终止正在进行的ICE协商,将 signalingState 值改为 closed。
pc.close();
参数:无。
返回值:无。
下面的代码清单演示了 close() 方法的用法。该示例建立网络连接,并创建了数据通道当从数据通道收到第一条消息后主动关闭连接。
const pc = new RTCPeerConnection();
const dc = pc.createDataChannel("my channel");
dc.onmessage = (event) => {
console.log("received:" + event.data);
//收到第一条消息后关闭连接
pc.close();
};
dc.onopen = () => {
console.log("datachannel open");
};
dc.onclose = () => {
console.log("datachannel close");
};
当WebRTC连接状态变化时触发该事件,此时 connectionState 值变为新的状态值。该事件对应事件句柄 onconnectionstatechange。
下面的代码清单演示了 onconnectionstatechange 事件句柄的用法。当触发 connectionstatechange 事件时,打印提示信息。
//onconnectionstatechange事件句柄示例
pc.onconnectionstatechange = ev => {
switch (pc.connectionState)
{
case "new":
case "checking":
console.log("Connecting...");
break;
case "connected":
console.log("Online");
break;
case "disconnected":
console.log("Disconnecting...");
break;
case "closed":
console.log("offline");
break;
case "failed":
console.log("Error");
break;
default:
console.log("Unknown");
break;
}
};
也可以使用 addEventListener() 方法监听事件 connectionstatechange
在ICE协商过程中,当ICE连接状态发生变化时触发该事件,新的连接状态可以通过iceConnectionState 属性获取。该事件对应事件句柄 oniceconnectionstatechange。
//oniceconnectionstatechange 事件句柄示例
pc.oniceconnectionstatechange = ev => {
if(pc.iceConnectionState === "disconnected") {
//当ICE连接状态变为disconnected时,关闭网络连接
closevideoCall(pc);
}
}
也可以使用 addEventListener() 方法监听事件 iceconnectionstatechange。
在ICE协商建立连接的过程中,如果ICE候选者的收集过程发生状态改变,则触发该事件,新的状态值可以通过iceGatheringState 属性获取。该事件对应事件句柄onicegatheringstatechange。
//onicegatheringstatechange 事件句柄示例
pc.onicegatheringstatechange = ev => {
let connection = ev.target;
switch (connection.iceGatheringState) {
case "gathering":
//开始收集ICE候选者信息
break;
case "complete":
//完成ICE候选者信息的收集
break;
}
}
也可以使用 addEventListener() 方法监听事件 icegatheringstatechange。
当信令状态发生改变时触发该事件,新的状态值可以通过属性signalingState获取,该事件对应事件句柄 onsignalingstatechange。
//onsignalingstatechange 事件句柄示例
pc.onsignalingstatechange = ev => {
switch (pc.signalingstate) {
case "stable":
updateStatus("ICE negotiation complete");
break;
}
}
也可以使用 addEventListener() 方法监听事件 signalingstatechange。
当需要进行ICE协商时触发该事件,对应事件句柄 onnegotiationneeded。以下两种情况需要进行 ICE 协商。
下面的代码清单演示了 onnegotiationneeded 事件句柄的用法。当触发 negotiationneeded事件时,意味着需要进行ICE协商,此时创建并设置本地提案,通过信令服务器将提案发送给对等端。
//onnegotiationneeded 事件句柄示例
pc.onnegotiationneeded = ev => {
pc.createOffer()
.then(offer => return pc.setLocalDescription(offer))
.then(() => sendSignalingMessage({
type: "video-offer",
sdp: pc.localDescription
}))
.catch(err => {
// 异常处理流程
});
};
也可以使用 addEventListener() 方法监听事件 negotiationneeded。
当有新的ICE候选者加入或者完成了ICE候选者收集时触发该事件,此时需要将新的ICE 候选者发送到对等端,对等端收到ICE候选者信息后,调用addIceCandidate()方法将候选者信息通知给ICE代理层。此事件对应事件句柄onicecandidate。此事件有传入参数,参数类型为RTCPeerlceCandidateEvent,其定义如下面的代码清单所示。
//RTCPeerlceCandidateEvent的定义
interface RTCPeerConnectionIceEvent : Event {
constructor(DOMString type, optional RTCPeerconnectionIceEventInit eventInitDict={});
readonly attribute RTCIceCandidate? candidate;
readonly attribute DOMString? url;
};
//onicecandidate事件句柄示例
pc.onicecandidate = ev => {
if (ev.candidate) {
sendMessage({
type: "new-ice-candidate",
candidate: ev.candidate
});
}
};
也可以使用 addEventListener() 方法监听事件 icecandidate。
在ICE候选者收集失败时触发该事件,对应事件句柄onicecandidateerror。该事件有传入参数,参数类型为RTCPeerConnectionlceErrorEvent,其定义如下面的代码清单所示。
//RTCPeerConnectionlceErrorEvent的定义
interface RTCPeerConnectionIceErrorEvent : Event {
constructor(DOMString type, RTCPeerConnectionIceErrorEventInit eventInitDict);
readonly attribute DOMString? address;
readonly attribute unsigned short? port;
readonly attribute DOMString url;
readonly attribute unsigned short errorCode;
readonly attribute USVString errorText;
};
RTCPeerConnectionlceErrorEvent 的属性说明 | |
属性 | 说明 |
address | 与 STUN/TURN 通信的本地 IP 地址 |
port | 与 STUN/TURN 通信的端口 |
url | STUN/TURN 服务器的URL地址 |
errorCode | STUN/TURN 服务器返回的错误代码 |
errorText | STUN/TURN 服务器返回的错误信息 |
//onicecandidateerror事件句柄示例
pc.onicecandidateerror = (event) => {
if (event.errorCode >= 300 && event.errorCode <= 699) {
// STUN返回的错误代码范围为300-699
}
}
也可以使用 addEventListener() 方法监听事件 icecandidateerror。