import 'dart:convert'; import 'package:diplomaticquarterapp/uitl/SignalRUtil.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter_webrtc/flutter_webrtc.dart'; typedef void StreamStateCallback(MediaStream stream); typedef void RTCIceGatheringStateCallback(RTCIceGatheringState state); typedef void RTCPeerConnectionStateCallback(RTCPeerConnectionState state); typedef void RTCSignalingStateCallback(RTCSignalingState state); class Signaling { dispose() { if (peerConnection != null) peerConnection.dispose(); signalR.closeConnection(); } init() { // Create Peer Connection createPeerConnection(configuration).then((value) { peerConnection = value; registerPeerConnectionListeners(); }); } initializeSignalR(String userName) async { if (signalR != null) await signalR.closeConnection(); // https://vcallapi.hmg.com/webRTCHub?source=web&username=zohaib signalR = SignalRUtil(hubName: "https://vcallapi.hmg.com/webRTCHub?source=mobile&username=$userName"); final connected = await signalR.openConnection(); if (!connected) throw 'Failed to connect SignalR'; } Map configuration = { // 'iceServers': [ // { // 'urls': ['stun:stun1.l.google.com:19302', 'stun:stun2.l.google.com:19302'] // } // ] 'iceServers': [ // { // 'urls': ['stun:stun1.l.google.com:19302', 'stun:stun2.l.google.com:19302'] // } {'url': "stun:ec2-15-185-116-59.me-south-1.compute.amazonaws.com:3478"}, {'url': "turn:ec2-15-185-116-59.me-south-1.compute.amazonaws.com:3479", 'credential': "admin", 'username': "admin"} ] }; SignalRUtil signalR; RTCPeerConnection peerConnection; MediaStream localStream; MediaStream remoteStream; RTCDataChannel dataChannel; // Future call(String patientId, String mobile, {@required RTCVideoRenderer localVideo, @required RTCVideoRenderer remoteVideo}) async { // await initializeSignalR(patientId); // // // final isCallPlaced = await FCM.sendCallNotifcationTo(DOCTOR_TOKEN, patientId, mobile); // if(!isCallPlaced) // throw 'Failed to notify target for call'; // // return isCallPlaced; // } Future acceptCall(String caller, String receiver, {@required MediaStream localMediaStream, @required Function(MediaStream) onRemoteMediaStream}) async { await initializeSignalR(receiver); signalR.setContributors(caller: caller, receiver: receiver); await signalR.acceptCall(receiver, caller).catchError((e) => throw 'Failed to inform signalR that i accepted a call'); peerConnection.addStream(localMediaStream); peerConnection?.onAddStream = (MediaStream stream) { remoteStream = stream; onRemoteMediaStream?.call(stream); }; return true; } Future hangupCall(String caller, String receiver) async { await signalR.hangupCall(caller, receiver); dispose(); } answerOffer(String sdp) async { final offer = jsonDecode(sdp); final caller = offer['caller']; final receiver = offer['target']; final offerSdp = offer['sdp']; peerConnection.setRemoteDescription(rtcSessionDescriptionFrom(offerSdp)).then((value) { return peerConnection.createAnswer(); }).then((anwser) { return peerConnection.setLocalDescription(anwser); }).then((value) { return peerConnection.getLocalDescription(); }).then((answer) { return signalR.answerOffer(answer, caller, receiver); }); } Future hangUp(RTCVideoRenderer localVideo) async {} Future createSdpAnswer(String toOfferSdp) async { final offerSdp = rtcSessionDescriptionFrom(jsonDecode(toOfferSdp)); peerConnection.setRemoteDescription(offerSdp); final answer = await peerConnection.createAnswer(); var answerSdp = json.encode(answer); // Send SDP via Push or any channel return answerSdp; } Future createSdpOffer() async { final offer = await peerConnection.createOffer(); await peerConnection.setLocalDescription(offer); final map = offer.toMap(); var offerSdp = json.encode(map); // Send SDP via Push or any channel return offerSdp; } addCandidate(String candidateJson) { peerConnection.addCandidate(rtcIceCandidateFrom(candidateJson)); } void registerPeerConnectionListeners() { peerConnection.onIceCandidate = (RTCIceCandidate candidate) { // print(json.encode(candidate.toMap())); signalR.addIceCandidate(json.encode(candidate.toMap())); }; peerConnection?.onIceGatheringState = (RTCIceGatheringState state) { // print('ICE gathering state changed: $state'); }; peerConnection?.onConnectionState = (RTCPeerConnectionState state) { // print('Connection state change: $state ${state.index}'); }; peerConnection?.onSignalingState = (RTCSignalingState state) { // print('Signaling state change: $state'); }; } } rtcSessionDescriptionFrom(Map sdp) { return RTCSessionDescription( sdp['sdp'], sdp['type'], ); } rtcIceCandidateFrom(String json) { final map = jsonDecode(json)['candidate']; return RTCIceCandidate(map['candidate'], map['sdpMid'], map['sdpMLineIndex']); }