Search code examples
flutternetworkingvideowebrtcvideocall

flutter: Unhandled Exception: Unable to RTCPeerConnection::createAnswer: Error (null)


Guys I quite not understand this exception, anyone encountered this before ?

Libraries I use:

dependencies:
  flutter:
    sdk: flutter
  flutter_webrtc: ^0.2.8
  toast: ^0.1.5
  web_socket_channel: ^1.1.0
  random_string: ^1.1.0
  shared_preferences: ^0.5.10
  http: ^0.12.0+4
  simple_permissions: ^0.1.9
  sdp_transform: ^0.2.0

My intention was to try to connect a call in 0.0.0.0 using flutter_webrtc: ^0.2.8 following tutorial of this project : https://github.com/jamalag/flutter-webrtc-part2.

I coded in Flutter (main.dart)

/// Server Changes Here 服务器在此更改
  _createPeerConnection() async {
    Map<String, dynamic> config = {
      "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(config, offerSdpConstraints);

    if (pc != null) print('HERE ==> $pc');

    pc.addStream(_localStream);

    pc.onIceCandidate = (e) {
      if (e.candidate != null) {
        print(json.encode(
          {
            'candidate': e.candidate.toString(),
            'sdpMid': e.sdpMid.toString(),
            'sdpMlineIndex': e.sdpMlineIndex,
          },
        ));
      } else {
        print('无效');
      }
    };

    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': false,
      'video': {
        'facingMode': 'user',
      },
    };

    MediaStream mediaStream = await navigator.getUserMedia(mediaConstraints);

    _localRenderer.srcObject = mediaStream;
    _localRenderer.mirror = true;

    return mediaStream;
  }

  initRenderers() async {
    await _localRenderer.initialize();
    await _remoteRenderer.initialize();
  }

  requestPermission() {
    if (Platform.isAndroid) {
      AndroidOperatingSystemPermission().requestAndroidUserPermission();
    } else if (Platform.isIOS) {
      IOSOperatingSystemPermission().requestIOSUserPermission();
    } else {
      logger('没有这样的操作系统');
    }
  }

  void _setCandidate() async {
    String jsonString = sdpController.text;
    dynamic session = await jsonDecode('$jsonString');
    print(session['candidate']);
    dynamic candidate = RTCIceCandidate(
        session['candidate'], session['sdpMid'], session['sdpMlineIndex']);
    await _peerConnection.addCandidate(candidate);
  }

  void _setRemoteDescription() async {
    String jsonString = sdpController.text;
    dynamic session = await jsonDecode('$jsonString');
    String sdp = write(session, null);

    RTCSessionDescription description =
        RTCSessionDescription(sdp, _offer ? 'answer' : 'offer');

    print(description.toMap());

    // debugPrint(description.toMap().toString(), wrapWidth: 2048);

    await _peerConnection.setRemoteDescription(description);
  }

  void _createOffer() async {
    RTCSessionDescription description =
        await _peerConnection.createOffer({'offerToReceiveVideo': 1});

    var session = parse(description.sdp);

    print(json.encode(session));

    _offer = true;

    // print('__CREATE_OFFER__');

    print(
      json.encode({
        'sdp': description.sdp.toString(),
        'type': description.type.toString(),
      }),
    );

    _peerConnection.setLocalDescription(description);
  }

  void _createAnswer() async {
    RTCSessionDescription description =
        await _peerConnection.createAnswer({'offerToReceiveVideo': 1});
    var session = parse(description.sdp);

    debugPrint(json.encode(session), wrapWidth: 2048);


    _peerConnection.setLocalDescription(description);
  }

The Error I have encountered :

2020-09-22 16:54:56.539143+0800 Runner[603:86509] [VERBOSE-2:ui_dart_state.cc(166)] Unhandled Exception: Unable to RTCPeerConnection::createAnswer: Error (null)
#0      RTCPeerConnection.createAnswer (package:flutter_webrtc/rtc_peerconnection.dart:237:7)
<asynchronous suspension>
#1      _CallerAppState._createAnswer (package:/main.dart:190:31)
#2      _InkResponseState._handleTap (package:flutter/src/material/ink_well.dart:992:19)
#3      _InkResponseState.build.<anonymous closure> (package:flutter/src/material/ink_well.dart:1098:38)
#4      GestureRecognizer.invokeCallback (package:flutter/src/gestures/recognizer.dart:184:24)
#5      TapGestureRecognizer.handleTapUp (package:flutter/src/gestures/tap.dart:524:11)
#6      BaseTapGestureRecognizer._checkUp (package:flutter/src/gestures/tap.dart:284:5)
#7      BaseTapGestureRecognizer.acceptGesture (package:flutter/src/gestures/tap.dart:256:7)
#8      GestureArenaManager.sweep (package:flutter/src/gestures/arena.dart:158:27)
#9      GestureBinding.handleEvent (package:flutter/src/gestures/binding.dart:224:20)
#10     GestureBinding.dispatchEvent (package:flutter/src/gestures/binding.dart:200:22)
#11     GestureBinding._handlePointerEvent (package:flutter/src/gestures/binding.dart:158:7)
#12     GestureBinding._flushPointerEventQueue (package:flutter/src/gestures/binding.dart:104:7)
#13     GestureBinding._handlePointerDataPacket (package:flutter/src/gestures/binding.dart:88:7)
#14     _rootRunUnary (dart:async/zone.dart:1206:13)
#15     _CustomZone.runUnary (dart:async/zone.dart:1100:19)
#16     _CustomZone.runUnaryGuarded (dart:async/zone.dart:1005:7)
#17     _invoke1 (dart:ui/hooks.dart:267:10)
#18     _dispatchPointerDataPacket (dart:ui/hooks.dart:176:5)

The Method I had tried to solve this,

 debugPrint(json.encode(session), wrapWidth: 2048);

to print out a clear and long output , I thought this was the problem. As I am new to this , I need some clue.

Thanks in advance.


Solution

  • Instead of using _localRenderer.mirror = true; I'm using RTCVideoView(_localRenderer, mirror: true),

    I followed him on YouTube and worked for me. You can follow him or my code.