"Unable to RTCPeerConnection::setRemoteDescription: Failed to set remote answer sdp: Called in wrong state: kStable"

638

I cannot comment yet under your post but I had this problem with the newest version of flutter_webrtc. Three days of head-scratching later and I used:

  flutter_webrtc: ^0.2.7

Worked on the first try. Cheers.

Share:
638
ilovecse
Author by

ilovecse

Updated on December 13, 2022

Comments

  • ilovecse
    ilovecse 11 months

    I am using flutter_webrtc to connect to users peer to peer. I am getting this error on the offer side. I have been looking all over the internet for a fix but couldn't find the solution.

    class Webrtc {
          bool _offer = false;
          RTCPeerConnection _peerConnection;
          MediaStream _localStream;
          RTCVideoRenderer _localRenderer = new RTCVideoRenderer();
              RTCVideoRenderer _remoteRenderer = new RTCVideoRenderer();
            
              get localRe
    
    nderer => _localRenderer;
          get remoteRenderer => _remoteRenderer;
    
      //final sdpController = TextEditingController();
    
      Webrtc() {
        initRenderers();
        _createPeerConnection().then((pc) {
          _peerConnection = pc;
        });
      }
    
      initRenderers() async {
        await _localRenderer.initialize();
        await _remoteRenderer.initialize();
      }
    
      createOffer() async {
        _offer = true;
        RTCSessionDescription description =
            await _peerConnection.createOffer({'offerToReceiveVideo': 1});
        // var session = parse(description.sdp);
        // print(json.encode(session));
        // _offer = true;
        var roomDef = Firestore.instance.collection("rooms").document("test");
    
        var data = {
          "offer": {
            'sdp': description.sdp.toString(),
            'type': description.type.toString(),
          }
        };
        await roomDef.setData(data, merge: true);
        await _peerConnection.setLocalDescription(description);
        Firestore.instance.collection("rooms").document("test").snapshots().listen((event) {
          if(event.data["answer"] != null){
            _setRemoteDescription(event.data["answer"]);
          }
        });
      }
    
      createAnswer() async {
        //  Firestore.instance.collection("rooms").document("test").snapshots().listen((event) {
        //   if(event.data["offer"] != null){
        //     _setRemoteDescription(event.data["offer"]);
        //   }
        // });
        var doc = await Firestore.instance.collection("rooms").document("test").get();
        print(doc.data["offer"]);
        await _setRemoteDescription(doc.data["offer"]);
        RTCSessionDescription description =
            await _peerConnection.createAnswer({'offerToReceiveVideo': 1});
        
        //var session = parse(description.sdp);
        //print(json.encode(session));
     
    
        await _peerConnection.setLocalDescription(description);
    
           var data = {
          "answer": {
            'sdp': description.sdp.toString(),
            'type': description.type.toString(),
          }
        };
        Firestore.instance
            .collection("rooms")
            .document("test")
            .setData(data, merge: true);
      }
    
       _setRemoteDescription(doc) async {
        // String jsonString = doc.toString();
        // dynamic session = await jsonDecode('$jsonString');
        //String sdp = write(session, null);
    
        // RTCSessionDescription description =
        //     new RTCSessionDescription(session['sdp'], session['type']);
        RTCSessionDescription description =
            new RTCSessionDescription(doc["sdp"],doc["type"]);
        print(description.toMap());
    
        await _peerConnection.setRemoteDescription(description);
      }
    
      void _addCandidate(data) async {
        dynamic session = data;
        dynamic candidate = new RTCIceCandidate(
            session['candidate'], session['sdpMid'], session['sdpMlineIndex']);
        await _peerConnection.addCandidate(candidate);
      }
    
      _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);
    
        pc.onIceCandidate = (e) {
          if (_offer && e.candidate != null) {
            Firestore.instance.collection("caller").add({
              'candidate': e.candidate.toString(),
              'sdpMid': e.sdpMid.toString(),
              'sdpMlineIndex': e.sdpMlineIndex,
            });
    
            Firestore.instance.collection("callee").snapshots().listen((event) {
              event.documentChanges.forEach((element) {
                print(element.document.data);
                _addCandidate(element.document.data);
              });
            });
          }
          if (!_offer && e.candidate != null) {
            Firestore.instance.collection("callee").add({
              'candidate': e.candidate.toString(),
              'sdpMid': e.sdpMid.toString(),
              'sdpMlineIndex': e.sdpMlineIndex,
            });
            Firestore.instance.collection("caller").snapshots().listen((event) {
              event.documentChanges.forEach((element) {
                print(element.document.data);
                _addCandidate(element.document.data);
              });
            });
          }
          // if (e.candidate != null) {
          //   print(json.encode({
          //     'candidate': e.candidate.toString(),
          //     'sdpMid': e.sdpMid.toString(),
          //     'sdpMlineIndex': e.sdpMlineIndex,
          //   }));
          // }
        };
    
        pc.onIceConnectionState = (e) {
          print(e);
        };
    
        pc.onAddStream = (stream) {
          print('addStream: ' + stream.id);
          _remoteRenderer.srcObject = stream;
        };
    
        return pc;
      }
    
      _getUserMedia() async {
        final Map<String, dynamic> mediaConstraints = {
          'audio': true,
          'video': {
            'facingMode': 'user',
          },
        };
    
        MediaStream stream = await navigator.getUserMedia(mediaConstraints);
    
        // _localStream = stream;
        _localRenderer.srcObject = stream;
        _localRenderer.mirror = true;
    
        // _peerConnection.addStream(stream);
    
        return stream;
      }
    }
    

    I tried switching the setlocaldescption and setremotedescption but no use. Offer button calls create offer from the ui and answer button calls createanswer function.

    • ilovecse
      ilovecse over 3 years
      Managed to fix the issue..but now remote stream not working on both peers
    • ilovecse
      ilovecse over 3 years
      Audio is also not working
    • ilovecse
      ilovecse over 3 years
      remote stream is blank screen