【问题标题】:Code doesn't even enter the onIceCandiate() while answering the SDP for webRTC in flutter在颤振中回答 webRTC 的 SDP 时,代码甚至没有进入 onIceCandiate()
【发布时间】:2021-06-10 11:24:51
【问题描述】:

在回答用于 webRTC 连接的 SDP 时,代码流甚至没有进入 onIceCandidate 函数。 webRTC 用于 android 中的 VOIP 语音呼叫,我还使用 viagene 网站设置了 TURN 服务器。

import 'dart:convert';

import 'package:flutter/material.dart';
import 'package:flutter_webrtc/flutter_webrtc.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:cloud_firestore/cloud_firestore.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp();
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: MyHomePage(title: 'WebRTC lets learn together'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  CollectionReference firebaseInstance =
      FirebaseFirestore.instance.collection("dmeet");
  RTCPeerConnection _peerConnection;

  MediaStream _localStream;
  RTCVideoRenderer _remoteRenderer = RTCVideoRenderer();
  var docId = TextEditingController();
  var l;

  var document;

  _createOfferSdp() async {
    RTCSessionDescription description =
        await _peerConnection.createOffer({'offerToReceiveAudio': 1});
    Map<String, dynamic> session = {"sdp": description.sdp};
    document = firebaseInstance.doc();
    document.collection("sdp").doc("offersdp").set(session);
    await _peerConnection.setLocalDescription(description);
    document.collection("icecandidate").snapshots().listen((result) async {
      dynamic candidate = new RTCIceCandidate(
          result['candidate'], result['sdpMid'], result['sdpMlineIndex']);
      await _peerConnection.addCandidate(candidate);
    });
    print(session);
    _peerConnection.onIceCandidate = (event) {
      if (event.candidate != null) {
        Map<String, dynamic> icecandidate = {
          "candidate": event.candidate,
          "sdpMid": event.sdpMid,
          "sdpMlineIndex": event.sdpMlineIndex
        };
        document.collection("candidate").doc().set(icecandidate);
      }
    };
  }

  bool remotesaved = false;

  _createAnswerSdp() async {
    _peerConnection.onIceCandidate = (event) {
      print("Candiate ${event.candidate}");
      if (event.candidate != null) {
        // Map<String, dynamic> icecandidate = {
        //   "candidate": event.candidate,
        //   "sdpMid": event.sdpMid,
        //   "sdpMlineIndex": event.sdpMlineIndex
        // };
        // document.collection("candidate").doc().set(icecandidate);
        print("Candidate: ${event.candidate}");
      }
    };
    firebaseInstance
        .doc(docId.text)
        .collection("sdp")
        .doc("offersdp")
        .get()
        .then((value) async {
      var remoteSession = value.data()["sdp"];
      RTCSessionDescription description1 =
          RTCSessionDescription(remoteSession, "offer");
      await _peerConnection
          .setRemoteDescription(description1)
          .then((value) async {
        RTCSessionDescription description2 =
            await _peerConnection.createAnswer({'offerToReceiveAudio': 1});
        Map<String, dynamic> session = {"sdp": description2.sdp};
        firebaseInstance
            .doc(docId.text)
            .collection("sdp")
            .doc("answersdp")
            .set(session);

        final iceCandidate = await firebaseInstance
             .doc(docId.text)
             .collection("candidate")
             .get();
        iceCandidate.docs.forEach((element) async {
          print("Candidate ${element.data()["candidate"]}");
          dynamic candidate = RTCIceCandidate(element.data()['candidate'],
               element.data()['sdpMid'], element.data()['sdpMlineIndex']);
           await _peerConnection.addCandidate(candidate);
         });
      });
    });
  }

  showAlertDialog(BuildContext context) {
    // set up the buttons
    Widget cancelButton = FlatButton(
      child: Text("Cancel"),
      onPressed: () {},
    );
    Widget continueButton = FlatButton(
      child: Text("Continue"),
      onPressed: _createAnswerSdp,
    );

    // set up the AlertDialog
    AlertDialog alert = AlertDialog(
      title: Text("AlertDialog"),
      content: TextField(
        controller: docId,
      ),
      actions: [
        cancelButton,
        continueButton,
      ],
    );

    // show the dialog
    showDialog(
      context: context,
      builder: (BuildContext context) {
        return alert;
      },
    );
  }

  initRenderer() async {
    await _remoteRenderer.initialize();
  }

  @override
  void initState() {
    _createPeerConnection().then((pc) {
      _peerConnection = pc;
    });
    initRenderer();
    // _localStream.initialize();
    super.initState();
  }

  @override
  void dispose() {
    _remoteRenderer.dispose();
    super.dispose();
  }

  _getUserMedia() async {
    final Map<String, dynamic> mediaConstraints = {
      'audio': true,
      'video': false,
    };

    MediaStream stream = await navigator.getUserMedia(mediaConstraints);

    // _localStream = stream;

    // _peerConnection.addStream(stream);

    return stream;
  }

  _createPeerConnection() async {
    Map<String, dynamic> configuration = {
      "iceServers": [
        {"url": "stun:stun.l.google.com:19302"},
        {
          "url": "turn:numb.viagenie.ca",
          "username": "******@gmail.com",
          "credential": "*****",
        }
      ]
    };

    final Map<String, dynamic> offerSdpConstraints = {
      "mandatory": {
        "OfferToReceiveAudio": true,
        "OfferToReceiveVideo": false,
      },
      "optional": [],
    };

    _localStream = await _getUserMedia();

    RTCPeerConnection pc =
        await createPeerConnection(configuration, offerSdpConstraints);
    pc.addStream(_localStream);

    pc.onIceCandidate = (e) {
      if (e.candidate != null) {
        l = json.encode({
          'candidate': e.candidate.toString(),
          'sdpMid': e.sdpMid.toString(),
          'sdpMlineIndex': e.sdpMlineIndex,
        });
        print("Her $l");
      }
    };

    pc.onAddStream = (stream) {
      print('addStream: ' + stream.id);
      _remoteRenderer.srcObject = stream;
    };

    return pc;
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Container(
        child: Center(
          child: Row(
            children: [
              Flexible(child: RTCVideoView(_remoteRenderer)),
              ElevatedButton(
                child: Text("Create"),
                onPressed: _createOfferSdp,
              ),
              ElevatedButton(
                onPressed: () {
                  showAlertDialog(context);
                },
                child: Text("Join"),
              )
            ],
          ),
        ),
      ),
    );
  }
}

甚至没有输入的行是函数_createAnwerSdp() 和它的下一行! createAnswerSdp 函数用于在获取候选冰块时接听电话。

问题的原因可能是什么?

【问题讨论】:

    标签: flutter webrtc voip


    【解决方案1】:

    所以,我可以清楚地看到,您没有为要接听此呼叫的远程用户设置任何本地描述。

    _peerConnection.setLocalDescription(description2);
    

    希望这可能会有所帮助!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-04-03
      • 2017-01-11
      • 2021-10-07
      • 2021-06-20
      • 1970-01-01
      • 2021-01-20
      • 1970-01-01
      相关资源
      最近更新 更多