New post on /r/flutterdev subreddit:
<b>Flutter webrtc multiple peer connection</b>
I am trying to make 3 peer video chats using Webrtc in Flutter. A needs to see B and C. B needs to see A and C. C needs to A and B. I also use
socket.io for the signaling server. I used 2 peer connections. two peer connection is successful. When I tried to connect the third one and tried to pass offer I got an error.​<strong>to execute 'createAnswer' on 'RTCPeerConnection': PeerConnection cannot create an answer in a state other than have-remote-offer or have-local-pranswer.</strong>is my approach is bad for multiple peer connection? I also posted in stackoverflow.<a href="
https://stackoverflow.com/questions/67465534/multipeer-connection-webrtc-flutter">
https://stackoverflow.com/questions/67465534/multipeer-connection-webrtc-flutter</a>No answer.<code>import 'dart:convert';import 'package:flutter/material.dart';import 'package:flutter_webrtc/flutter_webrtc.dart';import 'package:sdp_transform/sdp_transform.dart';import 'package:socket_io_client/socket_io_client.dart' as IO;class Home extends StatefulWidget {final String title;const Home({Key key, this.title}) : super(key: key);<a href="/u/override">u/override</a>_HomeState createState() => _HomeState();}class _HomeState extends State<Home> {bool _offer = false;bool firstTimeOffer = true;bool firstTimeRemoteDescription = true;bool firstTimeAnswer = true;bool firstTimeCandidate = true;RTCPeerConnection _peerConnection;RTCPeerConnection _peerConnection2;MediaStream _localStream;final _localVideoRenderer = new RTCVideoRenderer();final _remoteVideoRenderer = new RTCVideoRenderer();final _remoteVideoRenderer2 = RTCVideoRenderer();IO.Socket socket;var pcConfig = {};var candidates = [];final txtController = TextEditingController();<a href="/u/overridevoid">u/overridevoid</a> dispose() {txtController.dispose();_localVideoRenderer.dispose();super.dispose(); }<a href="/u/overridevoid">u/overridevoid</a> initState() {initRenderers();_createPeerConnection().then((pc) {_peerConnection = pc; });_createPeerConnection2().then((pc) {_peerConnection2 = pc; });_getUserMedia();connectToServer();super.initState(); }void connectToServer() {// connectToServer();socket =
IO.io('http://localhost:3000', <String, dynamic>{'transports': ['websocket'],'autoConnect': false, });socket.connect();socket.onDisconnect((_) => print("disconnected"));socket.on('connection-success', (data) => print(data));socket.on('offerOrAnswer', (sdp) async {this.txtController.text = sdp; });socket.on('candidate', (candidate) {// print('From Peer.....');// print(json.encode(candidate));this.candidates = [...this.candidates, candidate]; }); }_getUserMedia() async {final Map<String, dynamic> mediaConstraints = {'audio': false,'video': {'facingMode': 'user'} };MediaStream stream =await navigator.mediaDevices.getUserMedia(mediaConstraints);_localVideoRenderer.srcObject = stream;// _localVideoRenderer.mirror = true;return stream; }initRenderers() async {await _localVideoRenderer.initialize();await _remoteVideoRenderer.initialize(); }_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);// triggered when a new candidate is returnedpc.onIceCandidate = (e) {//send the candidates to the remote peer// see addCandidate below to be triggeredif (e.candidate != null) {var candidate = {'candidate': e.candidate.toString(),'sdpMid': e.sdpMid.toString(),'sdpMlineIndex': e.sdpMlineIndex };print(e.candidate);this.sendToPeer('candidate', candidate); } };pc.onIceConnectionState = (e) {print(e); };pc.onAddStrea…