diff --git a/internal/webrtc/client_creality.go b/internal/webrtc/client_creality.go index 0a3685a9..4618044e 100644 --- a/internal/webrtc/client_creality.go +++ b/internal/webrtc/client_creality.go @@ -10,6 +10,7 @@ import ( "github.com/AlexxIT/go2rtc/pkg/core" "github.com/AlexxIT/go2rtc/pkg/webrtc" + "github.com/pion/sdp/v3" ) // https://github.com/AlexxIT/go2rtc/issues/1600 @@ -27,7 +28,6 @@ func crealityClient(url string) (core.Producer, error) { medias := []*core.Media{ {Kind: core.KindVideo, Direction: core.DirectionRecvonly}, - {Kind: core.KindAudio, Direction: core.DirectionRecvonly}, } // TODO: return webrtc.SessionDescription @@ -36,6 +36,8 @@ func crealityClient(url string) (core.Producer, error) { return nil, err } + log.Trace().Msgf("[webrtc] offer:\n%s", offer) + body, err := offerToB64(offer) if err != nil { return nil, err @@ -61,6 +63,12 @@ func crealityClient(url string) (core.Producer, error) { return nil, err } + log.Trace().Msgf("[webrtc] answer:\n%s", answer) + + if answer, err = fixCrealitySDP(answer); err != nil { + return nil, err + } + if err = prod.SetAnswer(answer); err != nil { return nil, err } @@ -108,3 +116,37 @@ func answerFromB64(r io.Reader) (string, error) { // string "v=0..." return v["sdp"], nil } + +func fixCrealitySDP(value string) (string, error) { + var sd sdp.SessionDescription + if err := sd.UnmarshalString(value); err != nil { + return "", err + } + + md := sd.MediaDescriptions[0] + + // important to skip first codec, because second codec will be used + skip := md.MediaName.Formats[0] + md.MediaName.Formats = md.MediaName.Formats[1:] + + attrs := make([]sdp.Attribute, 0, len(md.Attributes)) + for _, attr := range md.Attributes { + switch attr.Key { + case "fmtp", "rtpmap": + // important to skip fmtp with x-google, because this is second fmtp for same codec + // and pion library will fail parsing this SDP + if strings.HasPrefix(attr.Value, skip) || strings.Contains(attr.Value, "x-google") { + continue + } + } + attrs = append(attrs, attr) + } + + md.Attributes = attrs + + b, err := sd.Marshal() + if err != nil { + return "", err + } + return string(b), nil +} diff --git a/internal/webrtc/webrtc_test.go b/internal/webrtc/webrtc_test.go index 98de4de3..1f82a0a7 100644 --- a/internal/webrtc/webrtc_test.go +++ b/internal/webrtc/webrtc_test.go @@ -2,6 +2,7 @@ package webrtc import ( "encoding/json" + "strings" "testing" "github.com/AlexxIT/go2rtc/internal/api/ws" @@ -36,3 +37,37 @@ func TestWebRTCAPIv2(t *testing.T) { require.Equal(t, "v=0\n...", offer.SDP) require.Equal(t, "stun:stun.l.google.com:19302", offer.ICEServers[0].URLs[0]) } + +func TestCrealitySDP(t *testing.T) { + sdp := `v=0 +o=- 1495799811084970 1495799811084970 IN IP4 0.0.0.0 +s=- +t=0 0 +a=msid-semantic:WMS * +a=group:BUNDLE 0 +m=video 9 UDP/TLS/RTP/SAVPF 96 98 +a=rtcp-fb:98 nack +a=rtcp-fb:98 nack pli +a=fmtp:96 profile-level-id=42e01f;level-asymmetry-allowed=1 +a=fmtp:98 profile-level-id=42e01f;packetization-mode=1;level-asymmetry-allowed=1 +a=fmtp:98 x-google-max-bitrate=6000;x-google-min-bitrate=2000;x-google-start-bitrate=4000 +a=rtpmap:96 H264/90000 +a=rtpmap:98 H264/90000 +a=ssrc:1 cname:pear +c=IN IP4 0.0.0.0 +a=sendonly +a=mid:0 +a=rtcp-mux +a=ice-ufrag:7AVa +a=ice-pwd:T+F/5y05Paw+mtG5Jrd8N3 +a=ice-options:trickle +a=fingerprint:sha-256 A5:AB:C0:4E:29:5B:BD:3B:7D:88:24:6C:56:6B:2A:79:A3:76:99:35:57:75:AD:C8:5A:A6:34:20:88:1B:68:EF +a=setup:passive +a=candidate:1 1 UDP 2015363327 172.22.233.10 48929 typ host +a=candidate:2 1 TCP 1015021823 172.22.233.10 0 typ host tcptype active +a=candidate:3 1 TCP 1010827519 172.22.233.10 60677 typ host tcptype passive +` + sdp, err := fixCrealitySDP(sdp) + require.Nil(t, err) + require.False(t, strings.Contains(sdp, "x-google-max-bitrate")) +}