Flutter WebRTC 服务器不允许我连接。

4
我最近开始使用flutter创建一个具有视频和音频通话功能的应用程序,所以我考虑使用WebRTC来实现这一点。然而,当我尝试从WebRTC Github创建本地WebRTC服务器时,它不允许我连接到它。当我从命令提示符中运行服务器时,它告诉我该服务器正在给定的本地IP上监听,但当我尝试连接时,它会显示无法访问该网站。此外,当我对URL进行ping时,它说无法找到主机的ping请求。非常感谢任何形式的帮助。
WebRTC服务器:https://github.com/flutter-webrtc/flutter-webrtc-server 在命令提示符中启动服务器 服务器运行时的netstat ping服务器

请在问题中发布收到的错误以及WebRTC的Github链接。 - dev-aentgs
你能从浏览器访问该URL吗? - dev-aentgs
2个回答

1

IP地址0.0.0.0不是服务器绑定/监听的IP地址。

服务器允许配置0.0.0.0来表示绑定到主机拥有的所有IPv4地址(请参见https://en.wikipedia.org/wiki/0.0.0.0)。要实际访问您的服务器,请使用主机上的任何IP地址(如果您在工作站上启动服务器,则应该使用127.0.0.1)

如果我没有记错,Windows上的Ping只是ICMP,这意味着TCP端口号不是其预期输入的一部分。例如,“0.0.0.0:8086”不是该命令的有效目标(请参见https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/ping

>ping 0.0.0.0:8086
Ping request could not find host 0.0.0.0:8086. Please check the name and try again.

>ping 0.0.0.0

Pinging 0.0.0.0 with 32 bytes of data:
PING: transmit failed. General failure.
PING: transmit failed. General failure.

Ping statistics for 0.0.0.0:
    Packets: Sent = 2, Received = 0, Lost = 2 (100% loss),
Control-C
^C
>ping 127.0.0.1

Pinging 127.0.0.1 with 32 bytes of data:
Reply from 127.0.0.1: bytes=32 time<1ms TTL=128
Reply from 127.0.0.1: bytes=32 time<1ms TTL=128

Ping statistics for 127.0.0.1:
    Packets: Sent = 2, Received = 2, Lost = 0 (0% loss),
Approximate round trip times in milli-seconds:
    Minimum = 0ms, Maximum = 0ms, Average = 0ms
Control-C
^C

由于您试图连接的是Web服务器,因此您可以使用类似curl的工具来验证您的连接。如果您使用的是Windows 10 1803或更高版本,则无需安装即可使用。

>curl https://0.0.0.0:8086
curl: (7) Failed to connect to 0.0.0.0 port 8086: Address not available
>curl https://127.0.0.1:8086
<html><head><title>Unauthorized</title></head><body><h1>401 Unauthorized</h1></body></html>

一些浏览器可能与服务器类似地支持https://0.0.0.0:8086,但我不会依赖它。请使用https://127.0.0.1:8086或主机的非本地IP地址。


0
    flutter_webrtc: ^0.9.8
    sdp_transform: ^0.3.2
    firebase_core: ^1.24.0
    firebase_auth: ^3.11.1
    cloud_firestore: ^3.5.0
    cloud_firestore_web: ^2.4.1
    flutter_math_fork: ^0.6.3+1
    google_fonts: ^3.0.1
    flutter_svg: ^1.1.5
 

    import 'package:cloud_firestore/cloud_firestore.dart';
    import 'package:flutter_webrtc/flutter_webrtc.dart';

    typedef StreamStateCallback = void Function(MediaStream stream);

    class Signaling {
    Map<String, dynamic> configuration = {
    'iceServers': [
      {
        'urls': [
          'stun:stun1.l.google.com:19302',
          'stun:stun2.l.google.com:19302'
        ]
      }
    ]
  };

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

  RTCPeerConnection? peerConnection;
  MediaStream? localStream;
  MediaStream? remoteStream;
  String? roomId;
  String? currentRoomText;
  StreamStateCallback? onAddRemoteStream;

  Future<String> createRoom(RTCVideoRenderer remoteRenderer) async {
    FirebaseFirestore db = FirebaseFirestore.instance;
    DocumentReference roomRef = db.collection('rooms').doc();
    final activecallers = db.collection('ActiveCallers');

    print('Create PeerConnection with configuration: $configuration');

    peerConnection =
        await createPeerConnection(configuration, offerSdpConstraints);
    // peerConnection = await createPeerConnection(configuration);

    registerPeerConnectionListeners();

    localStream?.getTracks().forEach((track) {
      peerConnection?.addTrack(track, localStream!);
    });

    // Code for collecting ICE candidates below
    var callerCandidatesCollection = roomRef.collection('callerCandidates');

    peerConnection?.onIceCandidate = (RTCIceCandidate candidate) {
      print('Got candidate: ${candidate.toMap()}');
      callerCandidatesCollection.add(candidate.toMap());
    };
    // Finish Code for collecting ICE candidate

    // Add code for creating a room
    RTCSessionDescription offer = await peerConnection!.createOffer();
    await peerConnection!.setLocalDescription(offer);
    print('Created offer: $offer');

    Map<String, dynamic> roomWithOffer = {'offer': offer.toMap()};

    await roomRef.set(roomWithOffer);
    var roomId = roomRef.id;
    print('New room created with SDK offer. Room ID: $roomId');
    currentRoomText = 'Current room is $roomId - You are the caller!';
    // Created a Room

    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);
      });
    };

    //add in active user list
    QuerySnapshot querySnapshot = await _activeUserCollRef.get();
    // Get data from docs and convert map to List
    int aciveusercount =
        querySnapshot.docs.map((doc) => doc.data()).toList().length + 1;
    final acitvecallerjson = {
      'id': roomId,
      'name': 'user_$aciveusercount',
      'start-on': DateTime.now()
    };
    activecallers.add(acitvecallerjson);
    // Listening for remote session description below
    roomRef.snapshots().listen((snapshot) async {
      print('Got updated room: ${snapshot.data()}');

      Map<String, dynamic> data = snapshot.data() as Map<String, dynamic>;
      if (peerConnection?.getRemoteDescription() != null &&
          data['answer'] != null) {
        var answer = RTCSessionDescription(
          data['answer']['sdp'],
          data['answer']['type'],
        );

        print("Someone tried to connect");
        await peerConnection?.setRemoteDescription(answer);
      }
    });
    // Listening for remote session description above

    // Listen for remote Ice candidates below
    roomRef.collection('calleeCandidates').snapshots().listen((snapshot) {
      snapshot.docChanges.forEach((change) {
        if (change.type == DocumentChangeType.added) {
          Map<String, dynamic> data = change.doc.data() as Map<String, 
          dynamic>;
          //print('Got new remote ICE candidate: ${jsonEncode(data)}');
          peerConnection!.addCandidate(
            RTCIceCandidate(
              data['candidate'],
              data['sdpMid'],
              data['sdpMLineIndex'],
            ),
          );
        }
      });
    });
    // Listen for remote ICE candidates above

    return roomId;
  }

  final CollectionReference _activeUserCollRef =
      FirebaseFirestore.instance.collection('ActiveCallers');

  Future<List> getData() async {
    // Get docs from collection reference
    QuerySnapshot querySnapshot = await _activeUserCollRef.get();

    // Get data from docs and convert map to List
    List listData = querySnapshot.docs.map((doc) => doc.data()).toList();
    print(
        'datalist================================================================');
    print(listData.length);
    return listData;
  }

  Future<void> joinRoom(String roomId, RTCVideoRenderer remoteVideo) async {
    FirebaseFirestore db = FirebaseFirestore.instance;
    DocumentReference roomRef = db.collection('rooms').doc('$roomId');
    var roomSnapshot = await roomRef.get();
    print('Got room ${roomSnapshot.exists}');

    if (roomSnapshot.exists) {
      print('Create PeerConnection with configuration: $configuration');
      peerConnection = await createPeerConnection(configuration);

      registerPeerConnectionListeners();

      localStream?.getTracks().forEach((track) {
        peerConnection?.addTrack(track, localStream!);
      });

      // Code for collecting ICE candidates below
      var calleeCandidatesCollection = 
      roomRef.collection('calleeCandidates');
      peerConnection!.onIceCandidate = (RTCIceCandidate candidate) {
        if (candidate == null) {
          print('onIceCandidate: complete!');
          return;
        }
        print('onIceCandidate: ${candidate.toMap()}');
        calleeCandidatesCollection.add(candidate.toMap());
      };
      // Code for collecting ICE candidate above

      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);
        });
      };

      // Code for creating SDP answer below
      var data = roomSnapshot.data() as Map<String, dynamic>;
      print('Got offer $data');
      var offer = data['offer'];
      await peerConnection?.setRemoteDescription(
        RTCSessionDescription(offer['sdp'], offer['type']),
      );
      var answer = await peerConnection!.createAnswer();
      print('Created Answer $answer');

      await peerConnection!.setLocalDescription(answer);

      Map<String, dynamic> roomWithAnswer = {
        'answer': {'type': answer.type, 'sdp': answer.sdp}
      };

      await roomRef.update(roomWithAnswer);
      // Finished creating SDP answer

      // Listening for remote ICE candidates below
      roomRef.collection('callerCandidates').snapshots().listen((snapshot) {
        snapshot.docChanges.forEach((document) {
          var data = document.doc.data() as Map<String, dynamic>;
          print(data);
          print('Got new remote ICE candidate: $data');
          peerConnection!.addCandidate(
            RTCIceCandidate(
              data['candidate'],
              data['sdpMid'],
              data['sdpMLineIndex'],
            ),
          );
        });
      });
    }
  }

  Future<void> openUserMedia(
    RTCVideoRenderer localVideo,
    RTCVideoRenderer remoteVideo,
  ) async {
    var stream = await navigator.mediaDevices
        .getUserMedia({'video': true, 'audio': true});

    localVideo.srcObject = stream;
    localStream = stream;

    remoteVideo.srcObject = await createLocalMediaStream('key');
  }

  Future<void> hangUp(RTCVideoRenderer localVideo) async {
    List<MediaStreamTrack> tracks = localVideo.srcObject!.getTracks();
    tracks.forEach((track) {
      track.stop();
    });

    if (remoteStream != null) {
      remoteStream!.getTracks().forEach((track) => track.stop());
    }
    if (peerConnection != null) peerConnection!.close();

    if (roomId != null) {
      var db = FirebaseFirestore.instance;
      var roomRef = db.collection('rooms').doc(roomId);
      var calleeCandidates = await 
      roomRef.collection('calleeCandidates').get();
      calleeCandidates.docs.forEach((document) => 
      document.reference.delete());

      var callerCandidates = await 
      roomRef.collection('callerCandidates').get();
      callerCandidates.docs.forEach((document) => 
      document.reference.delete());

      await roomRef.delete();
    }

    localStream!.dispose();
    remoteStream?.dispose();
  }

  void registerPeerConnectionListeners() {

    peerConnection?.onIceGatheringState = (RTCIceGatheringState state) {
      print('ICE gathering state changed: $state');
    };

    peerConnection?.onConnectionState = (RTCPeerConnectionState state) {
      print('Connection state change: $state');
    };

    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;
    };

  }
}

根据目前的写法,你的回答不够清晰。请编辑以添加更多细节,帮助其他人理解这如何回答所提出的问题。你可以在帮助中心找到关于如何撰写好回答的更多信息。 - Community

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接