import 'dart:convert'; import 'package:flutter_webrtc/flutter_webrtc.dart'; import 'package:job_app/singletons/user_info.dart'; import 'package:web_socket_channel/web_socket_channel.dart'; typedef void StreamStateCallback(MediaStream stream); class Signaling{ Map configuration = { 'iceServers': [ { 'urls': [ 'stun:stun.stunprotocol.org:3478', 'stun:stun.l.google.com:19302' , ] } ] }; WebSocketChannel channel; RTCPeerConnection peerConnection; MediaStream localStream; MediaStream remoteStream; String roomId; String currentRoomText; StreamStateCallback onAddRemoteStream; Future connectToWS()async{ channel = WebSocketChannel.connect( Uri.parse('wss://server.thejob.net/signaling'), ); channel.sink.add('{"fromuser":"${userInfo.user.id}","too":"153803","sdp":null,"candidate":null,"type":"join","data":"1538031640620283243"}'); } Future openUserMedia( RTCVideoRenderer localVideo, RTCVideoRenderer remoteVideo, ) async { await localVideo.initialize(); await remoteVideo.initialize(); var stream = await navigator.mediaDevices .getUserMedia({'video': true, 'audio': false}); localVideo.srcObject = stream; localStream = stream; remoteVideo.srcObject = await createLocalMediaStream('key'); } Future peerConnecting(Map sockRes, RTCVideoRenderer remoteRenderer)async{ peerConnection = await createPeerConnection(configuration); registerPeerConnectionListeners(); peerConnection.addStream(localStream); peerConnection.onTrack= (RTCTrackEvent event){ print('Got remote track: ${event.streams[0]}'); event.streams[0].getTracks().forEach((track) { print('Add a track to the remoteStream: $track'); remoteStream.addTrack(track); }); }; peerConnection.onIceCandidate = (RTCIceCandidate candidate) { if (candidate == null) { print('onIceCandidate: complete!'); return; } print('onIceCandidate: ${candidate.toMap()}'); }; //code for create answer and set Remote desc if(sockRes["type"]=="new_offer"){ Map desc = jsonDecode(sockRes["sdp"]); await peerConnection?.setRemoteDescription( RTCSessionDescription(desc['sdp'], 'offer'), ); var answer = await peerConnection.createAnswer(); await peerConnection.setLocalDescription(answer); channel.sink.add('{"fromuser":"${userInfo.user.id}","too":"153803","sdp":${jsonEncode(answer.sdp)},"candidate":null,"type":"answer","data":"1538031640620283243"}'); } //code for set candidates if(sockRes["type"]=="new_ice"){ String jsonString = sockRes["candidate"]; dynamic session = await jsonDecode(jsonString); peerConnection.addCandidate( RTCIceCandidate( session['candidate'], session['sdpMid'], session['sdpMLineIndex'], ), ); } } void registerPeerConnectionListeners() { peerConnection?.onIceGatheringState = (RTCIceGatheringState state) { print('ICE gathering state changed: $state'); }; peerConnection?.onConnectionState = (RTCPeerConnectionState state) { print('Connection state change: ${peerConnection.connectionState}'); }; peerConnection?.onSignalingState = (RTCSignalingState state) { print('Signaling state change: $state'); }; peerConnection?.onIceGatheringState = (RTCIceGatheringState state) { print('ICE connection state change: $state'); }; peerConnection?.onAddStream = (MediaStream stream) { print("Add remote stream"); onAddRemoteStream?.call(stream); remoteStream = stream; }; } Future cleanSession(RTCVideoRenderer renderer)async{ if (localStream != null) { renderer.srcObject.getTracks().forEach((element) async { await element.stop(); }); await renderer.srcObject.dispose(); renderer.srcObject = null; } } }