diff --git a/lib/helpers/websocket_helper.dart b/lib/helpers/websocket_helper.dart index 8b1c244..ec52fb3 100644 --- a/lib/helpers/websocket_helper.dart +++ b/lib/helpers/websocket_helper.dart @@ -182,7 +182,9 @@ class WebSocketHelper { peerID: msg.data["peerID"], candidate: signalData.containsKey("candidate") ? RTCIceCandidate( - signalData["candidate"], null, signalData["sdpMLineIndex"]) + signalData["candidate"], + "${signalData["sdpMLineIndex"]}" /* fix plugin crash */, + signalData["sdpMLineIndex"]) : null, sessionDescription: signalData.containsKey("type") ? RTCSessionDescription(signalData["sdp"], signalData["type"]) diff --git a/lib/models/call_config.dart b/lib/models/call_config.dart index b34eee7..000fd04 100644 --- a/lib/models/call_config.dart +++ b/lib/models/call_config.dart @@ -10,4 +10,9 @@ class CallConfig { const CallConfig({ @required this.iceServers, }) : assert(iceServers != null); + + /// Turn this call configuration into the right for the WebRTC plugin + Map get pluginConfig => { + "iceServers": iceServers.map((f) => {"url": f}).toList() + }; } diff --git a/lib/ui/screens/call_screen.dart b/lib/ui/screens/call_screen.dart index a999c27..421106b 100644 --- a/lib/ui/screens/call_screen.dart +++ b/lib/ui/screens/call_screen.dart @@ -13,6 +13,8 @@ import 'package:comunic/utils/account_utils.dart'; import 'package:comunic/utils/intl_utils.dart'; import 'package:comunic/utils/ui_utils.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_webrtc/rtc_peerconnection.dart'; +import 'package:flutter_webrtc/webrtc.dart'; /// Call screen /// @@ -41,6 +43,7 @@ class _CallScreenState extends SafeState { var _error = false; CallMembersList _membersList; UsersList _usersList; + final _peersConnections = Map(); @override void initState() { @@ -141,6 +144,18 @@ class _CallScreenState extends SafeState { _membersList.getUser(memberID).status = MemberStatus.READY; setState(() {}); + // Create peer connection + final peerConnection = await createPeerConnection(_conf.pluginConfig, { + "mandatory": { + "OfferToReceiveAudio": true, + "OfferToReceiveVideo": + _conversation.callCapabilities == CallCapabilities.VIDEO, + }, + "optional": [], + }); + + _peersConnections[memberID] = peerConnection; + // Request an offer to establish a peer connection await CallsHelper.requestOffer(convID, memberID); } catch (e, stack) { @@ -150,9 +165,38 @@ class _CallScreenState extends SafeState { } /// Call this method each time we get a new signal - void _newSignal(NewCallSignalEvent ev) { - print( - "${ev.peerID} - ${ev.sessionDescription != null ? ev.sessionDescription.toMap() : ev.candidate.toMap()}"); + void _newSignal(NewCallSignalEvent ev) async { + try { + // Check if we can process this message + if (!_peersConnections.containsKey(ev.peerID)) { + print( + "Could not process a signal for the connection with peer ${ev.peerID}!"); + return; + } + + // Check the kind of signal + // SessionDescription + if (ev.sessionDescription != null) { + await _peersConnections[ev.peerID] + .setRemoteDescription(ev.sessionDescription); + + // Send answer if required + if (ev.sessionDescription.type == "offer") { + final answer = await _peersConnections[ev.peerID].createAnswer({}); + + //TODO : Send answer back to server + print("ANSWER TO SEND ${answer.toMap()}"); + } + } + + // Ice Candidate + else { + await _peersConnections[ev.peerID].addCandidate(ev.candidate); + } + } catch (e, stack) { + print("Error while handling new signal ! $e\n$stack"); + showSimpleSnack(context, tr("Error while processing new signal!")); + } } /// Call this when a user has interrupted streaming