gowebrtcturnsimplewebrtcopenwebrtc

why there pion/webrtc generate candidate list have no tcp address


I want use golang pion/webrtc to publish local video file to a video server, bug this video server only support TCP connection, when i generate offer SDP by pion/webrtc code and candidate list have no one TCP candidate, so ICE connect failed. When I use chrome as a webrtc client to publish camera video, it's success, I don't how to make chrome disable TCP candidate, I checked candidcate from chrome and pion/webrtc, I found the difference is the candidate TCP address, I tried all way to let pion/webrtc generate an TCP candidate address, but all failed, please help me.

there is my code:

package main

import (
    "fmt"
    "io"
    "os"
    "path/filepath"
    "sync"
    "time"

    "github.com/google/uuid"
    "github.com/pion/webrtc/v3"
    "github.com/pion/webrtc/v3/pkg/media"
    "github.com/pion/webrtc/v3/pkg/media/h264reader"
)

func main() {

    // 创建PeerConnection配置
    config := webrtc.Configuration{
        ICEServers: []webrtc.ICEServer{
            {
                URLs: []string{"stun:stun.l.google.com:19302"},
            },
        },
        ICETransportPolicy: webrtc.ICETransportPolicyAll,
    }

    // 创建PeerConnection
    peerConnection, err := webrtc.NewPeerConnection(config)
    if err != nil {
        panic(err)
    }

    videoTrack, err := NewH264LocalStaticSampleVideoTrack("test.h264", 25)
    if err != nil {
        panic(err)
    }

    if rtpSender, err := peerConnection.AddTrack(videoTrack); err != nil {
        panic(err)
    } else {
        go func() {
            for {

                buf := make([]byte, 1024*1024)
                var rtcpErr error
                if _, _, rtcpErr = rtpSender.Read(buf); rtcpErr != nil {
                    fmt.Printf("read error: %v", rtcpErr.Error())
                    return
                }
            }
        }()
    }

    offer, err := peerConnection.CreateOffer(nil)
    if err != nil {
        panic(err)
    }
    err = peerConnection.SetLocalDescription(offer)
    if err != nil {
        panic(err)
    }

    wait := webrtc.GatheringCompletePromise(peerConnection)
    <-wait

    fmt.Printf("Local SDP: %v", peerConnection.LocalDescription().SDP)
}

func NewH264LocalStaticSampleVideoTrack(videoFile string, fps int) (videoTrack *webrtc.TrackLocalStaticSample, err error) {
    if videoFile == "" {
        err = fmt.Errorf("videoFile is empty")
        return
    }

    var videoFileAbs string
    videoFileAbs, err = filepath.Abs(videoFile)
    if err != nil {
        return
    }

    _, err = os.Stat(videoFileAbs)
    if err != nil {
        return
    }

    videoTrack, err = webrtc.NewTrackLocalStaticSample(webrtc.RTPCodecCapability{
        MimeType: webrtc.MimeTypeH264,
    }, "video", fmt.Sprintf("rtckit/%s", uuid.New().String()))
    if err != nil {
        return
    }

    go h264VideoFileConsumer(videoTrack, videoFileAbs, time.Duration(1000/fps)*time.Millisecond)

    return
}

func h264VideoFileConsumer(videoTrack *webrtc.TrackLocalStaticSample, videoFile string, videoFps time.Duration) {
    for {
        file, h264Err := os.Open(videoFile)
        if h264Err != nil {

            continue
        }

        h264, h264Err := h264reader.NewReader(file)
        if h264Err != nil {

            continue
        }

        buf := make(chan []byte, 1024*1024) // 1MB?

        var wg sync.WaitGroup

        wg.Add(2)
        go func() {
            defer wg.Done()
            for data := range buf {
                sample := media.Sample{Data: data, Duration: videoFps}

                if h264Err1 := videoTrack.WriteSample(sample); h264Err1 != nil {

                    continue
                }
            }
        }()

        go func() {
            defer wg.Done()
            ticker := time.NewTicker(videoFps)
            for ; true; <-ticker.C {
                nal, h264Err := h264.NextNAL()
                if h264Err == io.EOF {

                    break
                }
                if h264Err != nil {

                    break
                }

                buf <- nal.Data
            }

            close(buf)
        }()

        wg.Wait()
        _ = file.Close()
    }
}

this the offer i get:

offer2: v=0
o=- 3976125905671053001 1681720949 IN IP4 0.0.0.0
s=-
t=0 0
a=fingerprint:sha-256 31:A1:C7:4B:05:14:A3:7E:FE:CA:9C:4D:91:F0:29:6C:01:BF:20:67:DF:AA:EA:06:29:A4:DD:3F:F0:AA:5B:BD
a=extmap-allow-mixed
a=group:BUNDLE 0
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:ZjDGAGZtPHgWMfWa
a=ice-pwd:bJJRYUMfPcshoPCHTSfkyfrzwiJIiQkm
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:554659860 cname:rtckit/53bd9691-40c4-4a58-9165-c7579c4b5031
a=ssrc:554659860 msid:rtckit/53bd9691-40c4-4a58-9165-c7579c4b5031 video
a=ssrc:554659860 mslabel:rtckit/53bd9691-40c4-4a58-9165-c7579c4b5031
a=ssrc:554659860 label:video
a=msid:rtckit/53bd9691-40c4-4a58-9165-c7579c4b5031 video
a=sendrecv
a=candidate:4113284106 1 udp 2130706431 101.4.122.16 41267 typ host
a=candidate:4113284106 2 udp 2130706431 101.4.122.16 41267 typ host
a=candidate:3528925834 1 udp 2130706431 172.18.0.1 33655 typ host
a=candidate:3528925834 2 udp 2130706431 172.18.0.1 33655 typ host
a=candidate:233762139 1 udp 2130706431 172.17.0.1 53508 typ host
a=candidate:233762139 2 udp 2130706431 172.17.0.1 53508 typ host
a=candidate:300762037 1 udp 1694498815 178.173.224.70 56107 typ srflx raddr 0.0.0.0 rport 56107
a=candidate:300762037 2 udp 1694498815 178.173.224.70 56107 typ srflx raddr 0.0.0.0 rport 56107
a=end-of-candidates

Best withes~

I try to add ICE Server In localhost and use stun:stun.l.google.com:19302, and ask from chatGPT, it all didn't works.


Solution

  • By default Pion doesn't enable ICE-TCP candidates.

    You can enable them via the SettingEngine.SetICETCPMux

    See examples/ice-tcp for a full featured example of how to use this API.

    Best of luck, and thanks for using Pion!