WebRTC 数据通道类型不匹配
Posted
技术标签:
【中文标题】WebRTC 数据通道类型不匹配【英文标题】:WebRTC Data channel type mismatch 【发布时间】:2021-12-07 16:08:00 【问题描述】:我正在尝试在 playCanvas 中实现 WebRTC 通信,但在建立 Peers 之间的连接时遇到问题。
从本地环境开始,我使用的是 Brave Browser 和 Ubuntu OS,连接已建立,我可以在对等点之间发送消息。以下是使用正确的协议 RTP 创建的正确报价。
"v=0
o=- 6768969287305795266 2 IN IP4 127.0.0.1
s=-
t=0 0
a=group:BUNDLE 0
a=msid-semantic: WMS
m=application 9 UDP/TLS/RTP/SAVPF 118
c=IN IP4 0.0.0.0
b=AS:30
a=rtcp:9 IN IP4 0.0.0.0
a=ice-ufrag:kpEN
a=ice-pwd:0cEFgezZPzFBSsTbtx03XZUv
a=ice-options:trickle
a=fingerprint:sha-256 CD:93:28:C9:A1:17:59:C7:3C:E3:F9:03:48:02:59:08:50:FF:A1:8A:AF:53:9B:65:3B:62:B0:5E:E6:23:46:9F
a=setup:actpass
a=mid:0
a=sendrecv
a=msid:channel1 channel1
a=rtcp-mux
a=rtpmap:118 google-data/90000
a=s-s-rc:3090418315 cname:qaxoIuO1ybfnQaqY
a=s-s-rc:3090418315 msid:channel1 channel1
a=s-s-rc:3090418315 mslabel:channel1
a=s-s-rc:3090418315 label:channel1
"
这是有效的报价,在本地 PC 上,我可以在对等方之间连接和发送消息。但这仅适用于 Brave 浏览器,如果我打开 Chrome 或另一台装有 Brave 浏览器的 PC,它将无法工作,而且如果我在 playcanvas 上实现 WebRTC,它也将无法工作。
以下是我从某个报价中获得的数据,我认为这是我无法正常工作的主要原因。因为它使用SCTP协议。
"v=0
o=- 5811252825165405755 3 IN IP4 127.0.0.1
s=-
t=0 0
a=group:BUNDLE 0
a=extmap-allow-mixed
a=msid-semantic: WMS
m=application 9 UDP/DTLS/SCTP webrtc-datachannel
c=IN IP4 0.0.0.0
a=candidate:1528355922 1 udp 2113937151 920a8f71-bd47-4dac-9a24-497783686050.local 59907 typ host generation 0 network-cost 999
a=ice-ufrag:NjXz
a=ice-pwd:M3FdXA3wNEA25FQaFU3GwcVd
a=ice-options:trickle
a=fingerprint:sha-256 F0:59:BF:FF:AB:8B:4A:1A:A2:D8:0E:57:DD:AD:7B:14:24:7E:A7:6F:CC:C3:B2:BB:83:96:BB:53:49:71:CE:9A
a=setup:actpass
a=mid:0
a=sctp-port:5000
a=max-message-size:262144
"
这是我在 playcanvas 上收到的错误。
Uncaught (in promise) DOMException: Failed to execute 'setRemoteDescription' on 'RTCPeerConnection': Failed to set remote offer sdp: Data channel type mismatch. Expected RTP, got SCTP.
下面是playcanvas里面的实现。
NetworkManager.id = null;
NetworkManager.socket = null;
NetworkManager.clients = null;
NetworkManager.user = null;
NetworkManager.username = null;
NetworkManager.connectedUser = null;
NetworkManager.yourConn = null;
NetworkManager.dataChannel = null;
// initialize code called once per entity
NetworkManager.prototype.initialize = function()
// Context
var self = this;
this.socket = new WebSocket(this.address, "wss");
this.clients = [];
// Listeners
this.socket.onopen = function(event)
self.initState();
;
this.socket.onmessage = function(message)
const data = JSON.parse(message.data);
switch (data.type)
case 'login':
self.handleLogin(data.success, data.name);
break;
case 'offer':
self.handleOffer(data.offer, data.name);
break;
case 'answer':
self.handleAnswer(data.answer);
break;
case 'candidate':
self.handleCandidate(data.candidate);
break;
default:
break;
;
this.socket.onerror = function (err)
console.log('Got error', err);
;
;
// Called every frame
NetworkManager.prototype.update = function(dt)
// this.updatePosition();
// if(this.app.keyboard.wasPressed(pc.KEY_SPACE))
// this.sendPayload("Soldo");
//
;
// Functions
NetworkManager.prototype.handleMembers = function(users)
this.clients = users;
this.initializePlayers(this.clients);
;
NetworkManager.prototype.handleLogin = function(success, username)
if (!success)
alert('try different username');
else
this.clients.push(username);
var configuration =
iceServers: [ url: 'stun:stun2.1.google.com:19302' ],
;
this.yourConn = new RTCPeerConnection(configuration,
optional: [ RtpDataChannels: true ],
);
this.yourConn.onicecandidate = event =>
if (event.candidate)
this.sendMessage(
type: 'candidate',
candidate: event.candidate,
);
;
this.dataChannel = this.yourConn.createDataChannel('channel1',
reliable: true,
);
this.dataChannel.onerror = function(error)
console.log('Error: ', error);
;
this.dataChannel.onmessage = function(event)
console.log('on message data channel');
console.log(event.data.data);
;
this.dataChannel.onclose = () =>
console.log('data channel is closed.');
;
;
NetworkManager.prototype.login = function(name)
username = name;
if (username.length > 0)
this.sendMessage(
type: 'login',
name: username,
);
;
NetworkManager.prototype.createOffer = function(name)
const callToUsername = name;
if (callToUsername.length > 0)
this.connectedUser = callToUsername;
this.yourConn.createOffer(
offer =>
this.sendMessage(
type: 'offer',
offer: offer,
);
this.yourConn.setLocalDescription(offer);
,
error =>
alert('Error when creating an offer');
);
;
NetworkManager.prototype.sendMessage = function(message)
if (this.connectedUser)
message.name = this.connectedUser;
this.socket.send(JSON.stringify(message));
;
NetworkManager.prototype.initState = function()
// this.login(this.username);
;
NetworkManager.prototype.handleCandidate = function(candidate)
this.yourConn.addIceCandidate(new RTCIceCandidate(candidate));
;
NetworkManager.prototype.handleOffer = function(offer, name)
this.connectedUser = name;
this.yourConn.setRemoteDescription(new RTCSessionDescription(offer));
this.yourConn.createAnswer(
answer =>
this.yourConn.setLocalDescription(answer);
this.sendMessage(
type: 'answer',
answer: answer,
);
,
error =>
alert('Error while creating an answer');
);
;
NetworkManager.prototype.handleAnswer = function(answer)
this.yourConn.setRemoteDescription(new RTCSessionDescription(answer));
;
NetworkManager.prototype.sendPayload = function (message)
this.dataChannel.send(message);
;
我将不胜感激。
【问题讨论】:
【参考方案1】:基于 RTP 的数据通道是一个非标准的仅限 Chrome 的扩展程序,并且已被弃用很长时间以支持 SCTP 数据通道(请参阅https://www.chromestatus.com/feature/6485681910054912)。您的 Brave 浏览器可能是一个非常旧的版本。
【讨论】:
以上是关于WebRTC 数据通道类型不匹配的主要内容,如果未能解决你的问题,请参考以下文章
通过 websocket 或使用 WebRTC 的数据通道逐个字符发送?