flutter - “无法 RTCPeerConnection::setRemoteDescription:无法设置远程应答 sdp:在错误状态下调用:kStable”
问题描述
我正在使用 flutter_webrtc 连接到点对点的用户。我在报价方面收到此错误。我一直在互联网上寻找解决方案,但找不到解决方案。
class Webrtc {
bool _offer = false;
RTCPeerConnection _peerConnection;
MediaStream _localStream;
RTCVideoRenderer _localRenderer = new RTCVideoRenderer();
RTCVideoRenderer _remoteRenderer = new RTCVideoRenderer();
get localRe
nderer => _localRenderer;
get remoteRenderer => _remoteRenderer;
//final sdpController = TextEditingController();
Webrtc() {
initRenderers();
_createPeerConnection().then((pc) {
_peerConnection = pc;
});
}
initRenderers() async {
await _localRenderer.initialize();
await _remoteRenderer.initialize();
}
createOffer() async {
_offer = true;
RTCSessionDescription description =
await _peerConnection.createOffer({'offerToReceiveVideo': 1});
// var session = parse(description.sdp);
// print(json.encode(session));
// _offer = true;
var roomDef = Firestore.instance.collection("rooms").document("test");
var data = {
"offer": {
'sdp': description.sdp.toString(),
'type': description.type.toString(),
}
};
await roomDef.setData(data, merge: true);
await _peerConnection.setLocalDescription(description);
Firestore.instance.collection("rooms").document("test").snapshots().listen((event) {
if(event.data["answer"] != null){
_setRemoteDescription(event.data["answer"]);
}
});
}
createAnswer() async {
// Firestore.instance.collection("rooms").document("test").snapshots().listen((event) {
// if(event.data["offer"] != null){
// _setRemoteDescription(event.data["offer"]);
// }
// });
var doc = await Firestore.instance.collection("rooms").document("test").get();
print(doc.data["offer"]);
await _setRemoteDescription(doc.data["offer"]);
RTCSessionDescription description =
await _peerConnection.createAnswer({'offerToReceiveVideo': 1});
//var session = parse(description.sdp);
//print(json.encode(session));
await _peerConnection.setLocalDescription(description);
var data = {
"answer": {
'sdp': description.sdp.toString(),
'type': description.type.toString(),
}
};
Firestore.instance
.collection("rooms")
.document("test")
.setData(data, merge: true);
}
_setRemoteDescription(doc) async {
// String jsonString = doc.toString();
// dynamic session = await jsonDecode('$jsonString');
//String sdp = write(session, null);
// RTCSessionDescription description =
// new RTCSessionDescription(session['sdp'], session['type']);
RTCSessionDescription description =
new RTCSessionDescription(doc["sdp"],doc["type"]);
print(description.toMap());
await _peerConnection.setRemoteDescription(description);
}
void _addCandidate(data) async {
dynamic session = data;
dynamic candidate = new RTCIceCandidate(
session['candidate'], session['sdpMid'], session['sdpMlineIndex']);
await _peerConnection.addCandidate(candidate);
}
_createPeerConnection() async {
Map<String, dynamic> configuration = {
"iceServers": [
{"url": "stun:stun.l.google.com:19302"},
]
};
final Map<String, dynamic> offerSdpConstraints = {
"mandatory": {
"OfferToReceiveAudio": true,
"OfferToReceiveVideo": true,
},
"optional": [],
};
_localStream = await _getUserMedia();
RTCPeerConnection pc =
await createPeerConnection(configuration, offerSdpConstraints);
// if (pc != null) print(pc);
pc.addStream(_localStream);
pc.onIceCandidate = (e) {
if (_offer && e.candidate != null) {
Firestore.instance.collection("caller").add({
'candidate': e.candidate.toString(),
'sdpMid': e.sdpMid.toString(),
'sdpMlineIndex': e.sdpMlineIndex,
});
Firestore.instance.collection("callee").snapshots().listen((event) {
event.documentChanges.forEach((element) {
print(element.document.data);
_addCandidate(element.document.data);
});
});
}
if (!_offer && e.candidate != null) {
Firestore.instance.collection("callee").add({
'candidate': e.candidate.toString(),
'sdpMid': e.sdpMid.toString(),
'sdpMlineIndex': e.sdpMlineIndex,
});
Firestore.instance.collection("caller").snapshots().listen((event) {
event.documentChanges.forEach((element) {
print(element.document.data);
_addCandidate(element.document.data);
});
});
}
// if (e.candidate != null) {
// print(json.encode({
// 'candidate': e.candidate.toString(),
// 'sdpMid': e.sdpMid.toString(),
// 'sdpMlineIndex': e.sdpMlineIndex,
// }));
// }
};
pc.onIceConnectionState = (e) {
print(e);
};
pc.onAddStream = (stream) {
print('addStream: ' + stream.id);
_remoteRenderer.srcObject = stream;
};
return pc;
}
_getUserMedia() async {
final Map<String, dynamic> mediaConstraints = {
'audio': true,
'video': {
'facingMode': 'user',
},
};
MediaStream stream = await navigator.getUserMedia(mediaConstraints);
// _localStream = stream;
_localRenderer.srcObject = stream;
_localRenderer.mirror = true;
// _peerConnection.addStream(stream);
return stream;
}
}
我尝试切换 setlocaldescption 和 setremotedescption 但没有用。报价按钮调用从 ui 和应答按钮调用 createanswer 函数创建报价。
解决方案
我还不能在你的帖子下发表评论,但我对最新版本的 flutter_webrtc 有这个问题。三天后挠头,我使用了:
flutter_webrtc: ^0.2.7
在第一次尝试中工作。干杯。
推荐阅读
- python - Biopython 的 Pubmed 搜索在给定的时间范围内给出了不同的结果
- angular - 如何使用 nativescript 拨打电话?
- c# - 如何设置这些参数的参数?
- javascript - 为什么每次都重复相同的数组?
- sql - 如何在换行符或回车符后删除字段中的所有内容
- php - 无法解析列“uid”
- .net - .netcore 中的 BinaryFormatter
- android-studio - 如何告诉调试器不要停止异常?
- javascript - 未捕获的类型错误:无法读取 main.js:48 处未定义的属性“渲染”
- javascript - 如何在javascript中设置选择2框的默认值