简体   繁体   English

WebRTC ICE 与有效 ICE 服务器和候选者的连接失败

[英]WebRTC ICE Connection Failing with Valid ICE Servers and Candidates

This is a continuation of my previous question here .这是我之前的问题延续。

I started using the webrtc crate in this library to create a WebRTC connection, but I'm having issues with the ICE connection failing.我开始在这个库中使用webrtc板条箱来创建 WebRTC 连接,但是我遇到了 ICE 连接失败的问题。 I checked the STUN and TURN servers being used with this site and they all work correctly.我检查了该站点使用的 STUN 和 TURN 服务器,它们都可以正常工作。

Here is my current code:这是我当前的代码:

async fn new(...) {
    let webrtcredux = Arc::new(AsyncMutex::new(WebRtcRedux::default()));
    webrtcredux.lock().await.set_tokio_runtime(Handle::current());

    let servers = ice.urls.into_iter().map(|url| {
        if url.starts_with("turn") {
            RTCIceServer {
                urls: vec![url],
                username: ice.username.clone(),
                credential: ice.credential.clone(),
                .. RTCIceServer::default()
            }
        } else {
            RTCIceServer {
                urls: vec![url],
                .. RTCIceServer::default()
            }
        }
    }).collect::<Vec<_>>();

    debug!("Using ICE servers: {:#?}", servers);

    webrtcredux.lock().await.add_ice_servers(servers);

    // More gstreamer setup code...
}

async fn start(...) {
    self.pipeline.set_state(gst::State::Playing)?;
    let encoder = self.encoder_type;

    let arc_from_ws = Arc::new(AsyncMutex::new(from_ws_rx));

    self.webrtcredux.lock().await.on_peer_connection_state_change(Box::new(|state| {
        debug!("[WebRTC] Peer connection state changed to: {}", state);

        Box::pin(async {})
    })).await.expect("Failed to set on peer connection state change");

    self.webrtcredux.lock().await.on_ice_connection_state_change(Box::new(|state| {
        debug!("[WebRTC] ICE connection state changed to: {}", state);

        Box::pin(async {})
    })).await.expect("Failed to set on ice connection state change");

    // let redux_arc = self.webrtcredux.clone();
    // let candidates = Arc::new(AsyncMutex::new(Vec::new()));
    // let candidates_arc = candidates.clone();
    self.webrtcredux.lock().await.on_ice_candidate(Box::new(move |candidate| {
        // let redux_arc = redux_arc.clone()
        // let candidates = candidates_arc.clone();

        Box::pin(async move {
            if let Some(candidate) = candidate {
                debug!("ICE Candidate: {:#?}", candidate.to_json().await.unwrap());
                // candidates.lock().await.push(candidate.to_json().await.unwrap());
            }
            // redux_arc.lock().await.add_ice_candidate(candidate.unwrap().to_json().await.unwrap()).await.unwrap();
        })
    })).await.expect("Failed ice candidate");

    let redux_arc = self.webrtcredux.clone();
    self.webrtcredux.lock().await.on_negotiation_needed(Box::new(move || {
        let redux_arc = redux_arc.clone();

        info!("[WebRTC] Negotiation needed");

        Box::pin(async move {
            // Waits for all tracks to be added to create full SDP
            redux_arc.lock().await.wait_for_all_tracks().await;

            let offer = redux_arc.lock().await.create_offer(Some(RTCOfferOptions {
                voice_activity_detection: true,
                ice_restart: false,
            })).await.expect("Failed to create offer");

            // offer.props.insert(4, SdpProp::Attribute {
            //     key: "ice-options".to_string(),
            //     value: Some("trickle".to_string())
            // });

            // offer.props.insert(5, SdpProp::Attribute {
            //     key: "extmap-allow-mixed".to_string(),
            //     value: None
            // });

            // offer.props.insert(6, SdpProp::Attribute {
            //     key: "msid-semantic".to_string(),
            //     value: Some(" WMS".to_string())
            // });

            trace!("[WebRTC] Generated local SDP: {}", offer.to_string());

            redux_arc.lock().await.set_local_description(&offer, RTCSdpType::Offer).await.expect("Failed to set local description");

            info!("[WebRTC] Local description set");
        })
    })).await.expect("Failed to set on negotiation needed");

    let redux_arc = self.webrtcredux.clone();
    self.webrtcredux.lock().await.on_ice_gathering_state_change(Box::new(move |state| {
        debug!("[WebRTC] ICE gathering state changed to: {}", state);

        let redux_arc = redux_arc.clone();
        let to_ws_tx = to_ws_tx.clone();
        let from_ws_rx = arc_from_ws.clone();

        if state != RTCIceGathererState::Complete {
            return Box::pin(async {});
        }
        
        Box::pin(async move {
            let local = redux_arc.lock().await.local_description().await.unwrap().unwrap();

            let video_media: &SdpProp = local.props.iter().find(|v| match *v {
                SdpProp::Media { r#type, .. } => {
                    *r#type == MediaType::Video
                },
                _ => false
            }).unwrap();

            let (video_ssrc, video_payload_type, rtx_payload_type) = if let SdpProp::Media { props, .. } = video_media {
                let mut ssrc = 0u32;
                let mut video_payload = 0u8;
                let mut rtx_payload = 0u8;

                for prop in props {
                    match prop {
                        MediaProp::Attribute { key, value } => {
                            match key {
                                v if *v == "rtpmap".to_string() => {
                                    match value {
                                        Some(val) => {
                                            let num = val.clone().split(' ').collect::<Vec<_>>()[0].parse::<u8>().unwrap();
                                            if val.ends_with(&format!("{}/90000", encoder.type_string())) && video_payload == 0 {
                                                video_payload = num;
                                            } else if val.ends_with("rtx/90000") && rtx_payload == 0 {
                                                rtx_payload = num;
                                            }
                                        },
                                        None => unreachable!()
                                    }
                                },
                                v if *v == "ssrc".to_string() => {
                                    ssrc = match value {
                                        Some(val) => val.clone().split(' ').collect::<Vec<_>>()[0].parse::<u32>().unwrap(),
                                        None => unreachable!(),
                                    };
                                },
                                _ => continue
                            }
                        },
                        _ => continue
                    }
                }

                (ssrc, video_payload, rtx_payload)
            } else { unreachable!() };

            let audio_media: &SdpProp = local.props.iter().find(|v| match *v {
                SdpProp::Media { r#type, .. } => {
                    *r#type == MediaType::Audio
                },
                _ => false
            }).unwrap();

            let audio_ssrc = if let SdpProp::Media { props, .. } = audio_media {
                props.into_iter().find_map(|p| match p {
                    MediaProp::Attribute {key, value} => {
                        if key != "ssrc" {
                            return None;
                        }
                        let val = match value {
                            Some(val) => val.clone(),
                            None => unreachable!(),
                        };
                        Some(val.split(' ').collect::<Vec<_>>()[0].parse::<u32>().unwrap())
                    },
                    _ => None
                }).unwrap()
            } else { unreachable!() };

            trace!("[WebRTC] Updated local SDP: {}", local.to_string());

            to_ws_tx.send(ToWs {
                ssrcs: StreamSSRCs {
                    audio: audio_ssrc,
                    video: video_ssrc,
                    rtx: 0
                },
                local_sdp: local.to_string(),
                video_payload_type,
                rtx_payload_type,
            }).await.unwrap();

            let from_ws = from_ws_rx.lock().await.recv().await.unwrap();

            match SDP::from_str(&from_ws.remote_sdp).unwrap().props.pop().unwrap() {
                SdpProp::Media { ports, props, .. } => {
                    let mut main_ip = None;
                    let mut fingerprint = None;
                    let mut ufrag = None;
                    let mut pwd = None;
                    let mut candidate = None;

                    for prop in props {
                        let current = prop.clone();
                        match prop {
                            MediaProp::Connection { address, .. } => main_ip = Some(address),
                            MediaProp::Attribute { key, value: _ } => {
                                match &key[..] {
                                    "candidate" => candidate = Some(current),
                                    "fingerprint" => fingerprint = Some(current),
                                    "ice-ufrag" => ufrag = Some(current),
                                    "ice-pwd" => pwd = Some(current),
                                    _ => continue
                                }
                            }
                            _ => continue
                        }
                    }

                    let connection = MediaProp::Connection {
                        net_type: NetworkType::Internet,
                        address_type: AddressType::IPv4,
                        address: main_ip.unwrap(),
                        ttl: Some(127),
                        num_addresses: Some(1),
                        suffix: None,
                    };

                    let base_media_props = vec![
                        connection,
                        // candidate.unwrap(),
                        fingerprint.unwrap(),
                        ufrag.unwrap(),
                        pwd.unwrap(),
                        MediaProp::Attribute {
                            key: "rtcp-mux".to_string(),
                            value: None
                        },
                        MediaProp::Attribute {
                            key: "rtcp".to_string(),
                            value: Some(ports[0].to_string())
                        },
                        MediaProp::Attribute {
                            key: "setup".to_string(),
                            value: Some("passive".to_string())
                        },
                        MediaProp::Attribute {
                            key: "inactive".to_string(),
                            value: None
                        }
                    ];

                    let mut video_vec_attrs = ["ccm fir", "nack", "nack pli", "goog-remb", "transport-cc"].into_iter().map(|val| {
                        MediaProp::Attribute {
                            key: "rtcp-fb".to_string(),
                            value: Some(format!("{} {}", video_payload_type, val))
                        }
                    }).collect::<Vec<_>>();

                    video_vec_attrs.append(&mut [
                        "2 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time", 
                        "3 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01",
                        "14 urn:ietf:params:rtp-hdrext:toffset",
                        "13 urn:3gpp:video-orientation",
                        "5 http://www.webrtc.org/experiments/rtp-hdrext/playout-delay"
                    ].into_iter().map(|ext| {
                        MediaProp::Attribute {
                            key: "extmap".to_string(),
                            value: Some(ext.to_string())
                        }
                    }).collect::<Vec<_>>());

                    video_vec_attrs.append(&mut vec![
                        MediaProp::Attribute { 
                            key: "fmtp".to_string(), 
                            value: Some(format!("{} x-google-max-bitrate=2500;level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42e01f", video_payload_type))
                        },
                        MediaProp::Attribute {
                            key: "fmtp".to_string(),
                            value: Some(format!("{} apt={}", rtx_payload_type, video_payload_type))
                        },
                        MediaProp::Attribute {
                            key: "mid".to_string(),
                            value: Some(0.to_string())
                        },
                        MediaProp::Attribute {
                            key: "rtpmap".to_string(),
                            value: Some(format!("{} {}/90000", video_payload_type, encoder.type_string()))
                        },
                        MediaProp::Attribute {
                            key: "rtpmap".to_string(),
                            value: Some(format!("{} rtx/90000", rtx_payload_type))
                        },
                        candidate.unwrap(),
                        MediaProp::Attribute {
                            key: "end-of-candidates".to_string(),
                            value: None
                        }
                    ]);

                    let video_media = SdpProp::Media {
                        r#type: MediaType::Video,
                        ports: ports.clone(),
                        protocol: format!("UDP/TLS/RTP/SAVPF {} {}", video_payload_type, rtx_payload_type),
                        format: "".to_string(),
                        props: base_media_props.clone().into_iter().chain(video_vec_attrs.into_iter()).collect::<Vec<_>>()
                    };

                    let mut audio_vec_attrs = [
                        "1 urn:ietf:params:rtp-hdrext:ssrc-audio-level", 
                        "3 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01"
                    ].into_iter().map(|ext| {
                        MediaProp::Attribute {
                            key: "extmap".to_string(),
                            value: Some(ext.to_string())
                        }
                    }).collect::<Vec<_>>();

                    audio_vec_attrs.append(&mut vec![
                        MediaProp::Attribute {
                            key: "fmtp".to_string(),
                            value: Some("111 minptime=10;useinbandfec=1;usedtx=1".to_string())
                        },
                        MediaProp::Attribute {
                            key: "maxptime".to_string(),
                            value: Some(60.to_string())
                        },
                        MediaProp::Attribute {
                            key: "rtpmap".to_string(),
                            value: Some("111 opus/90000".to_string())
                        },
                        MediaProp::Attribute {
                            key: "rtcp-fb".to_string(),
                            value: Some("111 transport-cc".to_string())
                        },
                        MediaProp::Attribute {
                            key: "mid".to_string(),
                            value: Some(1.to_string())
                        }
                    ]);

                    let audio_media = SdpProp::Media {
                        r#type: MediaType::Audio,
                        ports,
                        protocol: "UDP/TLS/RTP/SAVPF 111".to_string(),
                        format: "".to_string(),
                        props: base_media_props.clone().into_iter().chain(audio_vec_attrs.into_iter()).collect::<Vec<_>>()
                    };

                    // Generate answer
                    let answer = SDP { props: vec![
                        SdpProp::Version(0),
                        SdpProp::Origin { 
                            username: "-".to_string(), 
                            session_id: "1420070400000".to_string(), 
                            session_version: 0, 
                            net_type: NetworkType::Internet, 
                            address_type: AddressType::IPv4, 
                            address: "127.0.0.1".to_string() 
                        },
                        SdpProp::SessionName("-".to_string()),
                        SdpProp::Timing {
                            start: 0,
                            stop: 0
                        },
                        SdpProp::Attribute {
                            key: "msid-semantic".to_string(),
                            value: Some(" WMS *".to_string())
                        },
                        SdpProp::Attribute {
                            key: "group".to_string(),
                            value: Some("BUNDLE 0 1".to_string())
                        },
                        video_media,
                        audio_media
                    ]};

                    trace!("[WebRTC] Generated remote SDP: {}", answer.to_string());

                    redux_arc.lock().await.set_remote_description(&answer, RTCSdpType::Answer).await.expect("Failed to set remote description");

                    info!("[WebRTC] Remote description set");
                }
                _ => unreachable!()
            }
        })
    })).await.expect("Failed to set on ice gathering change");

    Ok(StateChangeSuccess::Success)
}

Local SDP after ICE gathering completes: ICE 收集完成后的本地 SDP:

v=0
o=- 3006164469565782471 253007078 IN IP4 0.0.0.0
s=-
t=0 0
a=fingerprint:sha-256 F5:34:75:08:3E:AB:99:1E:5F:79:BF:6D:14:EC:D6:C2:F6:20:74:D6:D3:1D:78:48:58:B6:1E:2B:32:F3:D9:64
a=group:BUNDLE 0 1
m=video 9 UDP/TLS/RTP/SAVPF 96 97 98 99 100 101 102 121 127 120 125 107 108 109 123 118 116
c=IN IP4 0.0.0.0
a=setup:actpass
a=mid:0
a=ice-ufrag:cWRCBPTiuOohkLsf
a=ice-pwd:mHMqXcRexKOkbHKAZlvxjgvLFtdHiZAL
a=rtcp-mux
a=rtcp-rsize
a=rtpmap:96 VP8/90000
a=rtcp-fb:96 goog-remb
a=rtcp-fb:96 ccm fir
a=rtcp-fb:96 nack
a=rtcp-fb:96 nack pli
a=rtcp-fb:96 nack
a=rtcp-fb:96 nack pli
a=rtcp-fb:96 transport-cc
a=rtpmap:97 rtx/90000
a=fmtp:97 apt=96
a=rtcp-fb:97 nack
a=rtcp-fb:97 nack pli
a=rtcp-fb:97 transport-cc
a=rtpmap:98 VP9/90000
a=fmtp:98 profile-id=0
a=rtcp-fb:98 goog-remb
a=rtcp-fb:98 ccm fir
a=rtcp-fb:98 nack
a=rtcp-fb:98 nack pli
a=rtcp-fb:98 nack
a=rtcp-fb:98 nack pli
a=rtcp-fb:98 transport-cc
a=rtpmap:99 rtx/90000
a=fmtp:99 apt=98
a=rtcp-fb:99 nack
a=rtcp-fb:99 nack pli
a=rtcp-fb:99 transport-cc
a=rtpmap:100 VP9/90000
a=fmtp:100 profile-id=1
a=rtcp-fb:100 goog-remb
a=rtcp-fb:100 ccm fir
a=rtcp-fb:100 nack
a=rtcp-fb:100 nack pli
a=rtcp-fb:100 nack
a=rtcp-fb:100 nack pli
a=rtcp-fb:100 transport-cc
a=rtpmap:101 rtx/90000
a=fmtp:101 apt=100
a=rtcp-fb:101 nack
a=rtcp-fb:101 nack pli
a=rtcp-fb:101 transport-cc
a=rtpmap:102 H264/90000
a=fmtp:102 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42001f
a=rtcp-fb:102 goog-remb
a=rtcp-fb:102 ccm fir
a=rtcp-fb:102 nack
a=rtcp-fb:102 nack pli
a=rtcp-fb:102 nack
a=rtcp-fb:102 nack pli
a=rtcp-fb:102 transport-cc
a=rtpmap:121 rtx/90000
a=fmtp:121 apt=102
a=rtcp-fb:121 nack
a=rtcp-fb:121 nack pli
a=rtcp-fb:121 transport-cc
a=rtpmap:127 H264/90000
a=fmtp:127 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42001f
a=rtcp-fb:127 goog-remb
a=rtcp-fb:127 ccm fir
a=rtcp-fb:127 nack
a=rtcp-fb:127 nack pli
a=rtcp-fb:127 nack
a=rtcp-fb:127 nack pli
a=rtcp-fb:127 transport-cc
a=rtpmap:120 rtx/90000
a=fmtp:120 apt=127
a=rtcp-fb:120 nack
a=rtcp-fb:120 nack pli
a=rtcp-fb:120 transport-cc
a=rtpmap:125 H264/90000
a=fmtp:125 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42e01f
a=rtcp-fb:125 goog-remb
a=rtcp-fb:125 ccm fir
a=rtcp-fb:125 nack
a=rtcp-fb:125 nack pli
a=rtcp-fb:125 nack
a=rtcp-fb:125 nack pli
a=rtcp-fb:125 transport-cc
a=rtpmap:107 rtx/90000
a=fmtp:107 apt=125
a=rtcp-fb:107 nack
a=rtcp-fb:107 nack pli
a=rtcp-fb:107 transport-cc
a=rtpmap:108 H264/90000
a=fmtp:108 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42e01f
a=rtcp-fb:108 goog-remb
a=rtcp-fb:108 ccm fir
a=rtcp-fb:108 nack
a=rtcp-fb:108 nack pli
a=rtcp-fb:108 nack
a=rtcp-fb:108 nack pli
a=rtcp-fb:108 transport-cc
a=rtpmap:109 rtx/90000
a=fmtp:109 apt=108
a=rtcp-fb:109 nack
a=rtcp-fb:109 nack pli
a=rtcp-fb:109 transport-cc
a=rtpmap:123 H264/90000
a=fmtp:123 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=640032
a=rtcp-fb:123 goog-remb
a=rtcp-fb:123 ccm fir
a=rtcp-fb:123 nack
a=rtcp-fb:123 nack pli
a=rtcp-fb:123 nack
a=rtcp-fb:123 nack pli
a=rtcp-fb:123 transport-cc
a=rtpmap:118 rtx/90000
a=fmtp:118 apt=123
a=rtcp-fb:118 nack
a=rtcp-fb:118 nack pli
a=rtcp-fb:118 transport-cc
a=rtpmap:116 ulpfec/90000
a=rtcp-fb:116 nack
a=rtcp-fb:116 nack pli
a=rtcp-fb:116 transport-cc
a=extmap:1 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01
a=ssrc:3980097584 cname:video_0
a=ssrc:3980097584 msid:video_0 video
a=ssrc:3980097584 mslabel:video_0
a=ssrc:3980097584 label:video
a=msid:video_0 video
a=sendrecv
a=candidate:167090039 1 udp 2130706431 :: 48818 typ host
a=candidate:167090039 2 udp 2130706431 :: 48818 typ host
a=candidate:2938512866 1 udp 2130706431 192.168.1.100 47953 typ host
a=candidate:2938512866 2 udp 2130706431 192.168.1.100 47953 typ host
a=candidate:2414835526 1 udp 1694498815 72.196.215.130 35989 typ srflx raddr 0.0.0.0 rport 35989
a=candidate:2414835526 2 udp 1694498815 72.196.215.130 35989 typ srflx raddr 0.0.0.0 rport 35989
a=candidate:2414835526 1 udp 1694498815 72.196.215.130 37580 typ srflx raddr 0.0.0.0 rport 37580
a=candidate:2414835526 2 udp 1694498815 72.196.215.130 37580 typ srflx raddr 0.0.0.0 rport 37580
a=candidate:2414835526 1 udp 1694498815 72.196.215.130 59238 typ srflx raddr 0.0.0.0 rport 59238
a=candidate:2414835526 2 udp 1694498815 72.196.215.130 59238 typ srflx raddr 0.0.0.0 rport 59238
a=candidate:2414835526 1 udp 1694498815 72.196.215.130 53377 typ srflx raddr 0.0.0.0 rport 53377
a=candidate:2414835526 2 udp 1694498815 72.196.215.130 53377 typ srflx raddr 0.0.0.0 rport 53377
a=candidate:1022905401 1 udp 16777215 34.203.251.215 29290 typ relay raddr 0.0.0.0 rport 38594
a=candidate:1022905401 2 udp 16777215 34.203.251.215 29290 typ relay raddr 0.0.0.0 rport 38594
a=end-of-candidates
m=audio 9 UDP/TLS/RTP/SAVPF 111 9 0 8
c=IN IP4 0.0.0.0
a=setup:actpass
a=mid:1
a=ice-ufrag:cWRCBPTiuOohkLsf
a=ice-pwd:mHMqXcRexKOkbHKAZlvxjgvLFtdHiZAL
a=rtcp-mux
a=rtcp-rsize
a=rtpmap:111 opus/48000/2
a=fmtp:111 minptime=10;useinbandfec=1
a=rtcp-fb:111 transport-cc
a=rtpmap:9 G722/8000
a=rtcp-fb:9 transport-cc
a=rtpmap:0 PCMU/8000
a=rtcp-fb:0 transport-cc
a=rtpmap:8 PCMA/8000
a=rtcp-fb:8 transport-cc
a=extmap:1 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01
a=ssrc:597106938 cname:audio_0
a=ssrc:597106938 msid:audio_0 audio
a=ssrc:597106938 mslabel:audio_0
a=ssrc:597106938 label:audio
a=msid:audio_0 audio
a=sendrecv

Generated remote SDP:生成的远程 SDP:

v=0
o=- 1420070400000 0 IN IP4 127.0.0.1
s=-
t=0 0
a=msid-semantic: WMS *
a=group:BUNDLE 0 1
m=video 50016 UDP/TLS/RTP/SAVPF 98 97 
c=IN IP4 66.22.231.190/127/1
a=fingerprint:sha-256 4A:79:94:16:44:3F:BD:05:41:5A:C7:20:F3:12:54:70:00:73:5D:33:00:2D:2C:80:9B:39:E1:9F:2D:A7:49:87
a=ice-ufrag:PkLE
a=ice-pwd:o9QGn2N6YizFOM/UNojYai
a=rtcp-mux
a=rtcp:50016
a=setup:passive
a=inactive
a=rtcp-fb:98 ccm fir
a=rtcp-fb:98 nack
a=rtcp-fb:98 nack pli
a=rtcp-fb:98 goog-remb
a=rtcp-fb:98 transport-cc
a=extmap:2 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time
a=extmap:3 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01
a=extmap:14 urn:ietf:params:rtp-hdrext:toffset
a=extmap:13 urn:3gpp:video-orientation
a=extmap:5 http://www.webrtc.org/experiments/rtp-hdrext/playout-delay
a=fmtp:98 x-google-max-bitrate=2500;level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42e01f
a=fmtp:97 apt=98
a=mid:0
a=rtpmap:98 VP9/90000
a=rtpmap:97 rtx/90000
a=candidate:1 1 UDP 4261412862 66.22.231.190 50016 typ host
a=end-of-candidates
m=audio 50016 UDP/TLS/RTP/SAVPF 111 
c=IN IP4 66.22.231.190/127/1
a=fingerprint:sha-256 4A:79:94:16:44:3F:BD:05:41:5A:C7:20:F3:12:54:70:00:73:5D:33:00:2D:2C:80:9B:39:E1:9F:2D:A7:49:87
a=ice-ufrag:PkLE
a=ice-pwd:o9QGn2N6YizFOM/UNojYai
a=rtcp-mux
a=rtcp:50016
a=setup:passive
a=inactive
a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level
a=extmap:3 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01
a=fmtp:111 minptime=10;useinbandfec=1;usedtx=1
a=maxptime:60
a=rtpmap:111 opus/90000
a=rtcp-fb:111 transport-cc
a=mid:1

After setting the remote answer SDP the ICE connection state changes to "checking", but after about 20 seconds it changes to "failing" and kills the connection.设置远程应答 SDP 后,ICE 连接 state 变为“检查”,但大约 20 秒后变为“失败”并终止连接。 Is there something wrong I'm doing in terms of the SDPs or my code?我在 SDP 或我的代码方面做错了什么?

Edit: I got logging working, here is the connection log: https://pastebin.com/vNvd3Af6编辑:我开始记录工作,这里是连接日志: https://pastebin.com/vNvd3Af6

Edit 2: I'm not receiving any inbound traffic from the STUN servers.编辑 2:我没有收到来自 STUN 服务器的任何入站流量。 Other programs using the same ICE servers work fine, so what could I be doing wrong outside of basic network configuration?使用相同 ICE 服务器的其他程序运行良好,那么在基本网络配置之外我会做错什么?

Edit 3: Here is a working ICE connection capture and here is the one I'm currently dealing with.编辑 3: 是一个有效的 ICE 连接捕获, 是我目前正在处理的一个。

Edit 4: I ran netstat to see what ports my code is listening on, and there are some differences.编辑 4:我运行netstat以查看我的代码正在侦听哪些端口,并且存在一些差异。 I cut out all other programs.我删掉了所有其他程序。

Here is the working ICE connection:这是工作的 ICE 连接:

Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name         
tcp        0      0 192.168.1.100:41383     0.0.0.0:*               LISTEN      37973/target/debug/ 
tcp        0      0 192.168.1.100:51469     0.0.0.0:*               LISTEN      37973/target/debug/ 
tcp6       0      0 fe80::60d2:bcaa:a:40899 :::*                    LISTEN      37973/target/debug/        
udp        0      0 192.168.1.100:44897     0.0.0.0:*                           37973/target/debug/      
udp        0      0 239.255.255.250:1900    0.0.0.0:*                           37973/target/debug/ 
udp        0      0 192.168.1.100:1900      0.0.0.0:*                           37973/target/debug/ 
udp        0      0 239.255.255.250:1900    0.0.0.0:*                           37973/target/debug/ 
udp        0      0 127.0.0.1:1900          0.0.0.0:*                           37973/target/debug/ 
udp        0      0 127.0.0.1:37386         0.0.0.0:*                           37973/target/debug/      
udp        0      0 192.168.1.100:59877     0.0.0.0:*                           37973/target/debug/ 
udp6       0      0 fe80::60d2:bcaa:a:56003 :::*                                37973/target/debug/

Here is the non-working connection:这是非工作连接:

Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name          
udp        0      0 0.0.0.0:50651           0.0.0.0:*                           37186/target/debug/      
udp        0      0 0.0.0.0:51996           0.0.0.0:*                           37186/target/debug/ 
udp        0      0 0.0.0.0:35776           0.0.0.0:*                           37186/target/debug/ 
udp        0      0 0.0.0.0:53036           0.0.0.0:*                           37186/target/debug/ 
udp        0      0 224.0.0.251:5353        0.0.0.0:*                           37186/target/debug/ 
udp        0      0 0.0.0.0:40115           0.0.0.0:*                           37186/target/debug/ 
udp        0      0 192.168.1.100:40707     0.0.0.0:*                           37186/target/debug/        
udp6       0      0 :::37965                :::*                                37186/target/debug/ 

The server I was communicating with only accepted LF line endings, while I was sending CRLF in my new implementation.我正在与之通信的服务器仅接受 LF 行结尾,而我在新实现中发送 CRLF。 Changing it to LF fixed the issue.将其更改为 LF 解决了该问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM