簡體   English   中英

WebRTC ICE 與有效 ICE 服務器和候選者的連接失敗

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

這是我之前的問題延續。

我開始在這個庫中使用webrtc板條箱來創建 WebRTC 連接,但是我遇到了 ICE 連接失敗的問題。 我檢查了該站點使用的 STUN 和 TURN 服務器,它們都可以正常工作。

這是我當前的代碼:

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

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

生成的遠程 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

設置遠程應答 SDP 后,ICE 連接 state 變為“檢查”,但大約 20 秒后變為“失敗”並終止連接。 我在 SDP 或我的代碼方面做錯了什么?

編輯:我開始記錄工作,這里是連接日志: https://pastebin.com/vNvd3Af6

編輯 2:我沒有收到來自 STUN 服務器的任何入站流量。 使用相同 ICE 服務器的其他程序運行良好,那么在基本網絡配置之外我會做錯什么?

編輯 3: 是一個有效的 ICE 連接捕獲, 是我目前正在處理的一個。

編輯 4:我運行netstat以查看我的代碼正在偵聽哪些端口,並且存在一些差異。 我刪掉了所有其他程序。

這是工作的 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/

這是非工作連接:

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/ 

我正在與之通信的服務器僅接受 LF 行結尾,而我在新實現中發送 CRLF。 將其更改為 LF 解決了該問題。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM