From 4b4deaaaf25e4c9fd147330ac1f37e518ff822e0 Mon Sep 17 00:00:00 2001 From: Alexey Khit Date: Sat, 15 Apr 2023 12:52:52 +0300 Subject: [PATCH] Fix missed control in SDP --- pkg/core/media.go | 7 +++ pkg/rtsp/client.go | 8 ++-- pkg/rtsp/client_test.go | 94 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 105 insertions(+), 4 deletions(-) create mode 100644 pkg/rtsp/client_test.go diff --git a/pkg/core/media.go b/pkg/core/media.go index 1e972350..697e9806 100644 --- a/pkg/core/media.go +++ b/pkg/core/media.go @@ -82,6 +82,13 @@ func (m *Media) MatchAll() bool { return false } +func (m *Media) Equal(media *Media) bool { + if media.ID != "" { + return m.ID == media.ID + } + return m.String() == media.String() +} + func GetKind(name string) string { switch name { case CodecH264, CodecH265, CodecVP8, CodecVP9, CodecAV1, CodecJPEG: diff --git a/pkg/rtsp/client.go b/pkg/rtsp/client.go index d790e9bb..304203ae 100644 --- a/pkg/rtsp/client.go +++ b/pkg/rtsp/client.go @@ -276,7 +276,7 @@ func (c *Conn) SetupMedia(media *core.Media, first bool) (byte, error) { // try to use media position as channel number for i, m := range c.Medias { - if m.ID == media.ID { + if m.Equal(media) { transport = fmt.Sprintf( // i - RTP (data channel) // i+1 - RTCP (control channel) @@ -327,9 +327,9 @@ func (c *Conn) SetupMedia(media *core.Media, first bool) (byte, error) { return 0, err } - for _, newMedia := range c.Medias { - if newMedia.ID == media.ID { - return c.SetupMedia(newMedia, false) + for _, m := range c.Medias { + if m.Equal(media) { + return c.SetupMedia(m, false) } } } diff --git a/pkg/rtsp/client_test.go b/pkg/rtsp/client_test.go new file mode 100644 index 00000000..11bb3049 --- /dev/null +++ b/pkg/rtsp/client_test.go @@ -0,0 +1,94 @@ +package rtsp + +import ( + "github.com/stretchr/testify/require" + "net" + "os" + "testing" + "time" +) + +func TestTimeout(t *testing.T) { + Timeout = time.Millisecond + + ln, err := net.Listen("tcp", "localhost:0") + require.Nil(t, err) + + client := NewClient("rtsp://" + ln.Addr().String() + "/stream") + client.Backchannel = true + + err = client.Dial() + require.Nil(t, err) + + err = client.Describe() + require.ErrorIs(t, err, os.ErrDeadlineExceeded) +} + +func TestMissedControl(t *testing.T) { + Timeout = time.Millisecond + + ln, err := net.Listen("tcp", "localhost:0") + require.Nil(t, err) + + go func() { + conn, err := ln.Accept() + require.Nil(t, err) + + b := make([]byte, 8192) + for { + n, err := conn.Read(b) + require.Nil(t, err) + + req := string(b[:n]) + + switch req[:4] { + case "DESC": + _, _ = conn.Write([]byte(`RTSP/1.0 200 OK +Cseq: 1 +Content-Length: 495 +Content-Type: application/sdp + +v=0 +o=- 1 1 IN IP4 0.0.0.0 +s=go2rtc/1.2.0 +c=IN IP4 0.0.0.0 +t=0 0 +m=audio 0 RTP/AVP 96 +a=rtpmap:96 MPEG4-GENERIC/48000/2 +a=fmtp:96 profile-level-id=1;mode=AAC-hbr;sizelength=13;indexlength=3;indexdeltalength=3; config=119056E500 +m=audio 0 RTP/AVP 97 +a=rtpmap:97 OPUS/48000/2 +a=fmtp:97 sprop-stereo=1 +m=video 0 RTP/AVP 98 +a=rtpmap:98 H264/90000 +a=fmtp:98 packetization-mode=1; sprop-parameter-sets=Z2QAKaw0yAeAIn5cBagICAoAAAfQAAE4gdDAAjhAACOEF3lxoYAEcIAARwgu8uFA,aO48MAA=; profile-level-id=640029 +`)) + + case "SETU": + _, _ = conn.Write([]byte(`RTSP/1.0 200 OK +Transport: RTP/AVP/TCP;unicast;interleaved=4-5 +Cseq: 3 +Session: 1 + +`)) + + default: + t.Fail() + } + } + }() + + client := NewClient("rtsp://" + ln.Addr().String() + "/stream") + client.Backchannel = true + + err = client.Dial() + require.Nil(t, err) + + err = client.Describe() + require.Nil(t, err) + require.Len(t, client.Medias, 3) + + ch, err := client.SetupMedia(client.Medias[2], true) + require.Nil(t, err) + require.Equal(t, ch, byte(4)) +}