import 'dart:convert'; // import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:diplomaticquarterapp/pages/webRTC/fcm/FCMSendNotification.dart'; import 'package:diplomaticquarterapp/uitl/SignalRUtil.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter_webrtc/flutter_webrtc.dart'; import 'call_page.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'] } ] }; 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']); }