diff --git a/go.mod b/go.mod index b4c29deb..25685338 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/aler9/rtsp-simple-server go 1.17 require ( - github.com/aler9/gortsplib v0.0.0-20220130132715-cd0db96a5d41 + github.com/aler9/gortsplib v0.0.0-20220130155047-8c02b12955f8 github.com/asticode/go-astits v1.10.0 github.com/fsnotify/fsnotify v1.4.9 github.com/gin-gonic/gin v1.7.2 @@ -12,7 +12,6 @@ require ( github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 github.com/notedit/rtmp v0.0.2 github.com/pion/rtp v1.6.2 - github.com/pion/sdp/v3 v3.0.2 github.com/stretchr/testify v1.6.1 golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad gopkg.in/alecthomas/kingpin.v2 v2.2.6 @@ -37,6 +36,7 @@ require ( github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 // indirect github.com/pion/randutil v0.1.0 // indirect github.com/pion/rtcp v1.2.4 // indirect + github.com/pion/sdp/v3 v3.0.2 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/ugorji/go/codec v1.1.7 // indirect github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 // indirect diff --git a/go.sum b/go.sum index 4819c160..262408ff 100644 --- a/go.sum +++ b/go.sum @@ -2,8 +2,8 @@ github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafo github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d h1:UQZhZ2O0vMHr2cI+DC1Mbh0TJxzA3RcLoMsFw+aXw7E= github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= -github.com/aler9/gortsplib v0.0.0-20220130132715-cd0db96a5d41 h1:Ib0hUXSsNYBWeSYAFz4n76qJesJ/i3IpEThnmH6uY38= -github.com/aler9/gortsplib v0.0.0-20220130132715-cd0db96a5d41/go.mod h1:fyQrQyHo8QvdR/h357tkv1g36VesZlzEPsdAu2VrHHc= +github.com/aler9/gortsplib v0.0.0-20220130155047-8c02b12955f8 h1:kGq65HZMjRo2ay0eJO/MxkEhD2DcDTkcX4qCgsjUkSs= +github.com/aler9/gortsplib v0.0.0-20220130155047-8c02b12955f8/go.mod h1:fyQrQyHo8QvdR/h357tkv1g36VesZlzEPsdAu2VrHHc= github.com/aler9/rtmp v0.0.0-20210403095203-3be4a5535927 h1:95mXJ5fUCYpBRdSOnLAQAdJHHKxxxJrVCiaqDi965YQ= github.com/aler9/rtmp v0.0.0-20210403095203-3be4a5535927/go.mod h1:vzuE21rowz+lT1NGsWbreIvYulgBpCGnQyeTyFblUHc= github.com/asticode/go-astikit v0.20.0 h1:+7N+J4E4lWx2QOkRdOf6DafWJMv6O4RRfgClwQokrH8= diff --git a/internal/core/api_test.go b/internal/core/api_test.go index ec7dc55e..87b2f571 100644 --- a/internal/core/api_test.go +++ b/internal/core/api_test.go @@ -186,7 +186,7 @@ func TestAPIPathsList(t *testing.T) { require.Equal(t, true, ok) track, err := gortsplib.NewTrackH264(96, - &gortsplib.TrackConfigH264{SPS: []byte{0x01, 0x02, 0x03, 0x04}, PPS: []byte{0x01, 0x02, 0x03, 0x04}}) + []byte{0x01, 0x02, 0x03, 0x04}, []byte{0x01, 0x02, 0x03, 0x04}, nil) require.NoError(t, err) func() { @@ -251,7 +251,7 @@ func TestAPIList(t *testing.T) { defer p.close() track, err := gortsplib.NewTrackH264(96, - &gortsplib.TrackConfigH264{SPS: []byte{0x01, 0x02, 0x03, 0x04}, PPS: []byte{0x01, 0x02, 0x03, 0x04}}) + []byte{0x01, 0x02, 0x03, 0x04}, []byte{0x01, 0x02, 0x03, 0x04}, nil) require.NoError(t, err) switch ca { @@ -382,7 +382,7 @@ func TestAPIKick(t *testing.T) { defer p.close() track, err := gortsplib.NewTrackH264(96, - &gortsplib.TrackConfigH264{SPS: []byte{0x01, 0x02, 0x03, 0x04}, PPS: []byte{0x01, 0x02, 0x03, 0x04}}) + []byte{0x01, 0x02, 0x03, 0x04}, []byte{0x01, 0x02, 0x03, 0x04}, nil) require.NoError(t, err) switch ca { diff --git a/internal/core/core_test.go b/internal/core/core_test.go index 482fcf06..acd8e450 100644 --- a/internal/core/core_test.go +++ b/internal/core/core_test.go @@ -1,8 +1,11 @@ package core import ( + "bufio" + "bytes" "fmt" "io/ioutil" + "net" "os" "os/exec" "path/filepath" @@ -12,7 +15,7 @@ import ( "github.com/aler9/gortsplib" "github.com/aler9/gortsplib/pkg/base" - psdp "github.com/pion/sdp/v3" + "github.com/aler9/gortsplib/pkg/headers" "github.com/stretchr/testify/require" ) @@ -160,33 +163,61 @@ func TestCorePathAutoDeletion(t *testing.T) { defer p.close() func() { - c := gortsplib.Client{} - - err := c.Start("rtsp", "localhost:8554") + conn, err := net.Dial("tcp", "localhost:8554") require.NoError(t, err) - defer c.Close() + defer conn.Close() + br := bufio.NewReader(conn) if ca == "describe" { - ur, err := base.ParseURL("rtsp://localhost:8554/mypath") + u, err := base.ParseURL("rtsp://localhost:8554/mypath") require.NoError(t, err) - _, _, _, err = c.Describe(ur) - require.EqualError(t, err, "bad status code: 404 (Not Found)") + var bb bytes.Buffer + base.Request{ + Method: base.Describe, + URL: u, + Header: base.Header{ + "CSeq": base.HeaderValue{"1"}, + }, + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) + require.NoError(t, err) + + var res base.Response + err = res.Read(br) + require.NoError(t, err) + require.Equal(t, base.StatusNotFound, res.StatusCode) } else { - baseURL, err := base.ParseURL("rtsp://localhost:8554/mypath/") + u, err := base.ParseURL("rtsp://localhost:8554/mypath/trackID=0") require.NoError(t, err) - track, err := gortsplib.NewTrackH264(96, - &gortsplib.TrackConfigH264{SPS: []byte{0x01, 0x02, 0x03, 0x04}, PPS: []byte{0x01, 0x02, 0x03, 0x04}}) + var bb bytes.Buffer + base.Request{ + Method: base.Setup, + URL: u, + Header: base.Header{ + "CSeq": base.HeaderValue{"1"}, + "Transport": headers.Transport{ + Mode: func() *headers.TransportMode { + v := headers.TransportModePlay + return &v + }(), + Delivery: func() *headers.TransportDelivery { + v := headers.TransportDeliveryUnicast + return &v + }(), + Protocol: headers.TransportProtocolUDP, + ClientPorts: &[2]int{35466, 35467}, + }.Write(), + }, + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) - track.Media.Attributes = append(track.Media.Attributes, psdp.Attribute{ - Key: "control", - Value: "trackID=0", - }) - - _, err = c.Setup(true, track, baseURL, 0, 0) - require.EqualError(t, err, "bad status code: 404 (Not Found)") + var res base.Response + err = res.Read(br) + require.NoError(t, err) + require.Equal(t, base.StatusNotFound, res.StatusCode) } }() @@ -219,7 +250,7 @@ func main() { } track, err := gortsplib.NewTrackH264(96, - &gortsplib.TrackConfigH264{SPS: []byte{0x01, 0x02, 0x03, 0x04}, PPS: []byte{0x01, 0x02, 0x03, 0x04}}) + []byte{0x01, 0x02, 0x03, 0x04}, []byte{0x01, 0x02, 0x03, 0x04}, nil) if err != nil { panic(err) } @@ -270,35 +301,59 @@ func main() { defer p1.close() func() { - c := gortsplib.Client{} - - err := c.Start("rtsp", "localhost:8554") + conn, err := net.Dial("tcp", "localhost:8554") require.NoError(t, err) - defer c.Close() + defer conn.Close() + br := bufio.NewReader(conn) if ca == "describe" || ca == "describe and setup" { - ur, err := base.ParseURL("rtsp://localhost:8554/ondemand") + u, err := base.ParseURL("rtsp://localhost:8554/ondemand") require.NoError(t, err) - _, _, _, err = c.Describe(ur) + var bb bytes.Buffer + base.Request{ + Method: base.Describe, + URL: u, + Header: base.Header{ + "CSeq": base.HeaderValue{"1"}, + }, + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) + + var res base.Response + err = res.Read(br) + require.NoError(t, err) + require.Equal(t, base.StatusOK, res.StatusCode) } if ca == "setup" || ca == "describe and setup" { - baseURL, err := base.ParseURL("rtsp://localhost:8554/ondemand/") + u, err := base.ParseURL("rtsp://localhost:8554/ondemand/trackID=0") require.NoError(t, err) - track, err := gortsplib.NewTrackH264(96, - &gortsplib.TrackConfigH264{SPS: []byte{0x01, 0x02, 0x03, 0x04}, PPS: []byte{0x01, 0x02, 0x03, 0x04}}) + var bb bytes.Buffer + base.Request{ + Method: base.Setup, + URL: u, + Header: base.Header{ + "CSeq": base.HeaderValue{"2"}, + "Transport": headers.Transport{ + Mode: func() *headers.TransportMode { + v := headers.TransportModePlay + return &v + }(), + Protocol: headers.TransportProtocolTCP, + InterleavedIDs: &[2]int{0, 1}, + }.Write(), + }, + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) - track.Media.Attributes = append(track.Media.Attributes, psdp.Attribute{ - Key: "control", - Value: "trackID=0", - }) - - _, err = c.Setup(true, track, baseURL, 0, 0) + var res base.Response + err = res.Read(br) require.NoError(t, err) + require.Equal(t, base.StatusOK, res.StatusCode) } }() @@ -326,7 +381,7 @@ func TestCorePathRunOnReady(t *testing.T) { require.Equal(t, true, ok) defer p.close() track, err := gortsplib.NewTrackH264(96, - &gortsplib.TrackConfigH264{SPS: []byte{0x01, 0x02, 0x03, 0x04}, PPS: []byte{0x01, 0x02, 0x03, 0x04}}) + []byte{0x01, 0x02, 0x03, 0x04}, []byte{0x01, 0x02, 0x03, 0x04}, nil) require.NoError(t, err) c := gortsplib.Client{} @@ -360,7 +415,7 @@ func TestCoreHotReloading(t *testing.T) { func() { track, err := gortsplib.NewTrackH264(96, - &gortsplib.TrackConfigH264{SPS: []byte{0x01, 0x02, 0x03, 0x04}, PPS: []byte{0x01, 0x02, 0x03, 0x04}}) + []byte{0x01, 0x02, 0x03, 0x04}, []byte{0x01, 0x02, 0x03, 0x04}, nil) require.NoError(t, err) c := gortsplib.Client{} @@ -380,7 +435,7 @@ func TestCoreHotReloading(t *testing.T) { func() { track, err := gortsplib.NewTrackH264(96, - &gortsplib.TrackConfigH264{SPS: []byte{0x01, 0x02, 0x03, 0x04}, PPS: []byte{0x01, 0x02, 0x03, 0x04}}) + []byte{0x01, 0x02, 0x03, 0x04}, []byte{0x01, 0x02, 0x03, 0x04}, nil) require.NoError(t, err) conn := gortsplib.Client{} diff --git a/internal/core/hls_muxer.go b/internal/core/hls_muxer.go index 99f9366b..9ff75526 100644 --- a/internal/core/hls_muxer.go +++ b/internal/core/hls_muxer.go @@ -276,37 +276,32 @@ func (m *hlsMuxer) runInner(innerCtx context.Context, innerReady chan struct{}) m.path.onReaderRemove(pathReaderRemoveReq{author: m}) }() - var videoTrack *gortsplib.Track + var videoTrack *gortsplib.TrackH264 videoTrackID := -1 var h264Decoder *rtph264.Decoder - var audioTrack *gortsplib.Track + var audioTrack *gortsplib.TrackAAC audioTrackID := -1 var aacDecoder *rtpaac.Decoder - for i, t := range res.stream.tracks() { - if t.IsH264() { + for i, track := range res.stream.tracks() { + switch tt := track.(type) { + case *gortsplib.TrackH264: if videoTrack != nil { - return fmt.Errorf("can't read track %d with HLS: too many tracks", i+1) + return fmt.Errorf("can't encode track %d with HLS: too many tracks", i+1) } - videoTrack = t + videoTrack = tt videoTrackID = i - h264Decoder = rtph264.NewDecoder() - } else if t.IsAAC() { + + case *gortsplib.TrackAAC: if audioTrack != nil { - return fmt.Errorf("can't read track %d with HLS: too many tracks", i+1) + return fmt.Errorf("can't encode track %d with HLS: too many tracks", i+1) } - audioTrack = t + audioTrack = tt audioTrackID = i - - conf, err := t.ExtractConfigAAC() - if err != nil { - return err - } - - aacDecoder = rtpaac.NewDecoder(conf.SampleRate) + aacDecoder = rtpaac.NewDecoder(track.ClockRate()) } } diff --git a/internal/core/hls_source.go b/internal/core/hls_source.go index ace35aad..8bffd8c7 100644 --- a/internal/core/hls_source.go +++ b/internal/core/hls_source.go @@ -99,7 +99,7 @@ func (s *hlsSource) runInner() bool { } }() - onTracks := func(videoTrack *gortsplib.Track, audioTrack *gortsplib.Track) error { + onTracks := func(videoTrack gortsplib.Track, audioTrack gortsplib.Track) error { var tracks gortsplib.Tracks if videoTrack != nil { diff --git a/internal/core/metrics_test.go b/internal/core/metrics_test.go index f41ff353..103afbc9 100644 --- a/internal/core/metrics_test.go +++ b/internal/core/metrics_test.go @@ -30,7 +30,7 @@ func TestMetrics(t *testing.T) { defer p.close() track, err := gortsplib.NewTrackH264(96, - &gortsplib.TrackConfigH264{SPS: []byte{0x01, 0x02, 0x03, 0x04}, PPS: []byte{0x01, 0x02, 0x03, 0x04}}) + []byte{0x01, 0x02, 0x03, 0x04}, []byte{0x01, 0x02, 0x03, 0x04}, nil) require.NoError(t, err) source := gortsplib.Client{} diff --git a/internal/core/rtmp_conn.go b/internal/core/rtmp_conn.go index 1799a427..30bc7a1e 100644 --- a/internal/core/rtmp_conn.go +++ b/internal/core/rtmp_conn.go @@ -249,32 +249,33 @@ func (c *rtmpConn) runRead(ctx context.Context) error { c.state = gortsplib.ServerSessionStateRead c.stateMutex.Unlock() - var videoTrack *gortsplib.Track + var videoTrack *gortsplib.TrackH264 videoTrackID := -1 var h264Decoder *rtph264.Decoder - var audioTrack *gortsplib.Track + var audioTrack *gortsplib.TrackAAC audioTrackID := -1 var audioClockRate int var aacDecoder *rtpaac.Decoder - for i, t := range res.stream.tracks() { - if t.IsH264() { + for i, track := range res.stream.tracks() { + switch tt := track.(type) { + case *gortsplib.TrackH264: if videoTrack != nil { return fmt.Errorf("can't read track %d with RTMP: too many tracks", i+1) } - videoTrack = t + videoTrack = tt videoTrackID = i h264Decoder = rtph264.NewDecoder() - } else if t.IsAAC() { + + case *gortsplib.TrackAAC: if audioTrack != nil { return fmt.Errorf("can't read track %d with RTMP: too many tracks", i+1) } - audioTrack = t + audioTrack = tt audioTrackID = i - audioClockRate, _ = audioTrack.ClockRate() - aacDecoder = rtpaac.NewDecoder(audioClockRate) + aacDecoder = rtpaac.NewDecoder(track.ClockRate()) } } @@ -283,7 +284,10 @@ func (c *rtmpConn) runRead(ctx context.Context) error { } c.conn.SetWriteDeadline(time.Now().Add(time.Duration(c.writeTimeout))) - c.conn.WriteMetadata(videoTrack, audioTrack) + err := c.conn.WriteMetadata(videoTrack, audioTrack) + if err != nil { + return err + } c.ringBuffer = ringbuffer.New(uint64(c.readBufferCount)) @@ -456,8 +460,7 @@ func (c *rtmpConn) runPublish(ctx context.Context) error { var aacEncoder *rtpaac.Encoder if audioTrack != nil { - clockRate, _ := audioTrack.ClockRate() - aacEncoder = rtpaac.NewEncoder(96, clockRate, nil, nil, nil) + aacEncoder = rtpaac.NewEncoder(96, audioTrack.ClockRate(), nil, nil, nil) audioTrackID = len(tracks) tracks = append(tracks, audioTrack) } diff --git a/internal/core/rtmp_source.go b/internal/core/rtmp_source.go index c070facf..b78866f7 100644 --- a/internal/core/rtmp_source.go +++ b/internal/core/rtmp_source.go @@ -142,8 +142,7 @@ func (s *rtmpSource) runInner() bool { var aacEncoder *rtpaac.Encoder if audioTrack != nil { - clockRate, _ := audioTrack.ClockRate() - aacEncoder = rtpaac.NewEncoder(96, clockRate, nil, nil, nil) + aacEncoder = rtpaac.NewEncoder(96, audioTrack.ClockRate(), nil, nil, nil) audioTrackID = len(tracks) tracks = append(tracks, audioTrack) } diff --git a/internal/core/rtsp_server_test.go b/internal/core/rtsp_server_test.go index 52ae915f..de9cce22 100644 --- a/internal/core/rtsp_server_test.go +++ b/internal/core/rtsp_server_test.go @@ -230,7 +230,7 @@ func TestRTSPServerAuth(t *testing.T) { } track, err := gortsplib.NewTrackH264(96, - &gortsplib.TrackConfigH264{SPS: []byte{0x01, 0x02, 0x03, 0x04}, PPS: []byte{0x01, 0x02, 0x03, 0x04}}) + []byte{0x01, 0x02, 0x03, 0x04}, []byte{0x01, 0x02, 0x03, 0x04}, nil) require.NoError(t, err) source := gortsplib.Client{} @@ -268,7 +268,7 @@ func TestRTSPServerAuth(t *testing.T) { defer p.close() track, err := gortsplib.NewTrackH264(96, - &gortsplib.TrackConfigH264{SPS: []byte{0x01, 0x02, 0x03, 0x04}, PPS: []byte{0x01, 0x02, 0x03, 0x04}}) + []byte{0x01, 0x02, 0x03, 0x04}, []byte{0x01, 0x02, 0x03, 0x04}, nil) require.NoError(t, err) source := gortsplib.Client{} @@ -314,7 +314,7 @@ func TestRTSPServerAuthFail(t *testing.T) { defer p.close() track, err := gortsplib.NewTrackH264(96, - &gortsplib.TrackConfigH264{SPS: []byte{0x01, 0x02, 0x03, 0x04}, PPS: []byte{0x01, 0x02, 0x03, 0x04}}) + []byte{0x01, 0x02, 0x03, 0x04}, []byte{0x01, 0x02, 0x03, 0x04}, nil) require.NoError(t, err) c := gortsplib.Client{} @@ -377,7 +377,7 @@ func TestRTSPServerAuthFail(t *testing.T) { defer p.close() track, err := gortsplib.NewTrackH264(96, - &gortsplib.TrackConfigH264{SPS: []byte{0x01, 0x02, 0x03, 0x04}, PPS: []byte{0x01, 0x02, 0x03, 0x04}}) + []byte{0x01, 0x02, 0x03, 0x04}, []byte{0x01, 0x02, 0x03, 0x04}, nil) require.NoError(t, err) c := gortsplib.Client{} @@ -401,7 +401,7 @@ func TestRTSPServerAuthFail(t *testing.T) { defer a.close() track, err := gortsplib.NewTrackH264(96, - &gortsplib.TrackConfigH264{SPS: []byte{0x01, 0x02, 0x03, 0x04}, PPS: []byte{0x01, 0x02, 0x03, 0x04}}) + []byte{0x01, 0x02, 0x03, 0x04}, []byte{0x01, 0x02, 0x03, 0x04}, nil) require.NoError(t, err) c := gortsplib.Client{} @@ -434,7 +434,7 @@ func TestRTSPServerPublisherOverride(t *testing.T) { defer p.close() track, err := gortsplib.NewTrackH264(96, - &gortsplib.TrackConfigH264{SPS: []byte{0x01, 0x02, 0x03, 0x04}, PPS: []byte{0x01, 0x02, 0x03, 0x04}}) + []byte{0x01, 0x02, 0x03, 0x04}, []byte{0x01, 0x02, 0x03, 0x04}, nil) require.NoError(t, err) s1 := gortsplib.Client{} diff --git a/internal/core/rtsp_session.go b/internal/core/rtsp_session.go index c3d7dffb..c3b9842b 100644 --- a/internal/core/rtsp_session.go +++ b/internal/core/rtsp_session.go @@ -41,10 +41,10 @@ type rtspSession struct { path *path state gortsplib.ServerSessionState stateMutex sync.Mutex - setuppedTracks map[int]*gortsplib.Track // read - onReadCmd *externalcmd.Cmd // read - announcedTracks gortsplib.Tracks // publish - stream *stream // publish + setuppedTracks map[int]gortsplib.Track // read + onReadCmd *externalcmd.Cmd // read + announcedTracks gortsplib.Tracks // publish + stream *stream // publish } func newRTSPSession( @@ -126,30 +126,11 @@ func (s *rtspSession) onClose(err error) { // onAnnounce is called by rtspServer. func (s *rtspSession) onAnnounce(c *rtspConn, ctx *gortsplib.ServerHandlerOnAnnounceCtx) (*base.Response, error) { for i, track := range ctx.Tracks { - if track.IsH264() { - _, err := track.ExtractConfigH264() - if err != nil { + if th264, ok := track.(*gortsplib.TrackH264); ok { + if th264.SPS() == nil || th264.PPS() == nil { return &base.Response{ StatusCode: base.StatusBadRequest, - }, fmt.Errorf("H264 track %d is not valid: %v", i+1, err) - } - } - - if track.IsAAC() { - _, err := track.ExtractConfigAAC() - if err != nil { - return &base.Response{ - StatusCode: base.StatusBadRequest, - }, fmt.Errorf("AAC track %d is not valid: %v", i+1, err) - } - } - - if track.IsOpus() { - _, err := track.ExtractConfigOpus() - if err != nil { - return &base.Response{ - StatusCode: base.StatusBadRequest, - }, fmt.Errorf("Opus track %d is not valid: %v", i+1, err) + }, fmt.Errorf("track %d can't be used: H264 SPS or PPS not provided into the SDP", i) } } } @@ -257,7 +238,7 @@ func (s *rtspSession) onSetup(c *rtspConn, ctx *gortsplib.ServerHandlerOnSetupCt } if s.setuppedTracks == nil { - s.setuppedTracks = make(map[int]*gortsplib.Track) + s.setuppedTracks = make(map[int]gortsplib.Track) } s.setuppedTracks[ctx.TrackID] = res.stream.tracks()[ctx.TrackID] diff --git a/internal/core/rtsp_source.go b/internal/core/rtsp_source.go index aa960b4e..96f82c1e 100644 --- a/internal/core/rtsp_source.go +++ b/internal/core/rtsp_source.go @@ -239,20 +239,21 @@ func (s *rtspSource) runInner() bool { } func (s *rtspSource) handleMissingH264Params(c *gortsplib.Client, tracks gortsplib.Tracks) error { - h264TrackID := func() int { + h264Track, h264TrackID := func() (*gortsplib.TrackH264, int) { for i, t := range tracks { - if t.IsH264() { - return i + if th264, ok := t.(*gortsplib.TrackH264); ok { + if th264.SPS() == nil { + return th264, i + } } } - return -1 + return nil, -1 }() if h264TrackID < 0 { return nil } - _, err := tracks[h264TrackID].ExtractConfigH264() - if err == nil { + if h264Track.SPS() != nil && h264Track.PPS() != nil { return nil } @@ -261,7 +262,6 @@ func (s *rtspSource) handleMissingH264Params(c *gortsplib.Client, tracks gortspl var streamMutex sync.RWMutex var stream *stream - var payloadType uint8 decoder := rtph264.NewDecoder() var sps []byte var pps []byte @@ -293,8 +293,6 @@ func (s *rtspSource) handleMissingH264Params(c *gortsplib.Client, tracks gortspl return } - payloadType = pkt.Header.PayloadType - for _, nalu := range nalus { typ := h264.NALUType(nalu[0] & 0x1F) switch typ { @@ -325,7 +323,7 @@ func (s *rtspSource) handleMissingH264Params(c *gortsplib.Client, tracks gortspl } } - _, err = c.Play(nil) + _, err := c.Play(nil) if err != nil { return err } @@ -348,15 +346,8 @@ func (s *rtspSource) handleMissingH264Params(c *gortsplib.Client, tracks gortspl case <-paramsReceived: s.log(logger.Info, "H264 parameters extracted") - track, err := gortsplib.NewTrackH264(payloadType, &gortsplib.TrackConfigH264{ - SPS: sps, - PPS: pps, - }) - if err != nil { - return err - } - - tracks[h264TrackID] = track + h264Track.SetSPS(sps) + h264Track.SetPPS(pps) res := s.parent.onSourceStaticSetReady(pathSourceStaticSetReadyReq{ source: s, diff --git a/internal/core/rtsp_source_test.go b/internal/core/rtsp_source_test.go index bb4d7858..e8cdbda6 100644 --- a/internal/core/rtsp_source_test.go +++ b/internal/core/rtsp_source_test.go @@ -11,7 +11,6 @@ import ( "github.com/aler9/gortsplib/pkg/base" "github.com/aler9/gortsplib/pkg/rtph264" "github.com/pion/rtp" - psdp "github.com/pion/sdp/v3" "github.com/stretchr/testify/require" ) @@ -41,8 +40,7 @@ func TestRTSPSource(t *testing.T) { "tls", } { t.Run(source, func(t *testing.T) { - track, _ := gortsplib.NewTrackH264(96, - &gortsplib.TrackConfigH264{SPS: []byte{0x01, 0x02, 0x03, 0x04}, PPS: []byte{0x05, 0x06}}) + track, _ := gortsplib.NewTrackH264(96, []byte{0x01, 0x02, 0x03, 0x04}, []byte{0x05, 0x06}, nil) stream := gortsplib.NewServerStream(gortsplib.Tracks{track}) var authValidator *auth.Validator @@ -151,8 +149,7 @@ func TestRTSPSource(t *testing.T) { } func TestRTSPSourceNoPassword(t *testing.T) { - track, _ := gortsplib.NewTrackH264(96, - &gortsplib.TrackConfigH264{SPS: []byte{0x01, 0x02, 0x03, 0x04}, PPS: []byte{0x05, 0x06}}) + track, _ := gortsplib.NewTrackH264(96, []byte{0x01, 0x02, 0x03, 0x04}, []byte{0x05, 0x06}, nil) stream := gortsplib.NewServerStream(gortsplib.Tracks{track}) var authValidator *auth.Validator done := make(chan struct{}) @@ -210,15 +207,8 @@ func TestRTSPSourceNoPassword(t *testing.T) { } func TestRTSPSourceMissingH264Params(t *testing.T) { - track, _ := gortsplib.NewTrackH264(96, - &gortsplib.TrackConfigH264{SPS: []byte{0x01, 0x02, 0x03, 0x04}, PPS: []byte{0x05, 0x06}}) - var newattrs []psdp.Attribute - for _, attr := range track.Media.Attributes { - if attr.Key != "fmtp" { - newattrs = append(newattrs, attr) - } - } - track.Media.Attributes = newattrs + track, err := gortsplib.NewTrackH264(96, nil, nil, nil) + require.NoError(t, err) stream := gortsplib.NewServerStream(gortsplib.Tracks{track}) @@ -275,7 +265,7 @@ func TestRTSPSourceMissingH264Params(t *testing.T) { }, RTSPAddress: "127.0.0.1:8555", } - err := s.Start() + err = s.Start() require.NoError(t, err) defer s.Wait() defer s.Close() @@ -314,10 +304,10 @@ func TestRTSPSourceMissingH264Params(t *testing.T) { require.NoError(t, err) defer c.Close() - conf, err := c.Tracks()[0].ExtractConfigH264() - require.NoError(t, err) - require.Equal(t, []byte{7, 1, 2, 3}, conf.SPS) - require.Equal(t, []byte{8}, conf.PPS) + h264Track, ok := c.Tracks()[0].(*gortsplib.TrackH264) + require.Equal(t, true, ok) + require.Equal(t, []byte{7, 1, 2, 3}, h264Track.SPS()) + require.Equal(t, []byte{8}, h264Track.PPS()) <-received } diff --git a/internal/hls/client.go b/internal/hls/client.go index 077d1391..d47bbf79 100644 --- a/internal/hls/client.go +++ b/internal/hls/client.go @@ -134,7 +134,7 @@ type clientVideoProcessorData struct { type clientVideoProcessor struct { ctx context.Context - onTrack func(*gortsplib.Track) error + onTrack func(gortsplib.Track) error onPacket func([]byte) queue chan clientVideoProcessorData @@ -146,7 +146,7 @@ type clientVideoProcessor struct { func newClientVideoProcessor( ctx context.Context, - onTrack func(*gortsplib.Track) error, + onTrack func(gortsplib.Track) error, onPacket func([]byte), ) *clientVideoProcessor { p := &clientVideoProcessor{ @@ -203,7 +203,7 @@ func (p *clientVideoProcessor) doProcess( p.sps = append([]byte(nil), nalu...) if p.encoder == nil && p.pps != nil { - err := p.initializeTrack() + err := p.initializeEncoder() if err != nil { return err } @@ -218,7 +218,7 @@ func (p *clientVideoProcessor) doProcess( p.pps = append([]byte(nil), nalu...) if p.encoder == nil && p.sps != nil { - err := p.initializeTrack() + err := p.initializeEncoder() if err != nil { return err } @@ -272,8 +272,8 @@ func (p *clientVideoProcessor) process( p.queue <- clientVideoProcessorData{data, pts, dts} } -func (p *clientVideoProcessor) initializeTrack() error { - track, err := gortsplib.NewTrackH264(96, &gortsplib.TrackConfigH264{SPS: p.sps, PPS: p.pps}) +func (p *clientVideoProcessor) initializeEncoder() error { + track, err := gortsplib.NewTrackH264(96, p.sps, p.pps, nil) if err != nil { return err } @@ -290,18 +290,17 @@ type clientAudioProcessorData struct { type clientAudioProcessor struct { ctx context.Context - onTrack func(*gortsplib.Track) error + onTrack func(gortsplib.Track) error onPacket func([]byte) queue chan clientAudioProcessorData - conf *gortsplib.TrackConfigAAC encoder *rtpaac.Encoder clockStartRTC time.Time } func newClientAudioProcessor( ctx context.Context, - onTrack func(*gortsplib.Track) error, + onTrack func(gortsplib.Track) error, onPacket func([]byte), ) *clientAudioProcessor { p := &clientAudioProcessor{ @@ -354,18 +353,17 @@ func (p *clientAudioProcessor) doProcess( } } - if p.conf == nil { - p.conf = &gortsplib.TrackConfigAAC{ - Type: pkt.Type, - SampleRate: pkt.SampleRate, - ChannelCount: pkt.ChannelCount, + if p.encoder == nil { + track, err := gortsplib.NewTrackAAC(97, pkt.Type, pkt.SampleRate, pkt.ChannelCount, nil) + if err != nil { + return err } - if p.encoder == nil { - err := p.initializeTrack() - if err != nil { - return err - } + p.encoder = rtpaac.NewEncoder(97, track.ClockRate(), nil, nil, nil) + + err = p.onTrack(track) + if err != nil { + return err } } @@ -373,10 +371,6 @@ func (p *clientAudioProcessor) doProcess( pktPts += 1000 * time.Second / time.Duration(pkt.SampleRate) } - if p.encoder == nil { - return nil - } - pkts, err := p.encoder.Encode(aus, pts) if err != nil { return fmt.Errorf("error while encoding AAC: %v", err) @@ -407,17 +401,6 @@ func (p *clientAudioProcessor) process( } } -func (p *clientAudioProcessor) initializeTrack() error { - track, err := gortsplib.NewTrackAAC(97, p.conf) - if err != nil { - return err - } - - p.encoder = rtpaac.NewEncoder(97, p.conf.SampleRate, nil, nil, nil) - - return p.onTrack(track) -} - // ClientParent is the parent of a Client. type ClientParent interface { Log(level logger.Level, format string, args ...interface{}) @@ -425,7 +408,7 @@ type ClientParent interface { // Client is a HLS client. type Client struct { - onTracks func(*gortsplib.Track, *gortsplib.Track) error + onTracks func(gortsplib.Track, gortsplib.Track) error onPacket func(bool, []byte) parent ClientParent @@ -447,8 +430,8 @@ type Client struct { audioProc *clientAudioProcessor tracksMutex sync.RWMutex - videoTrack *gortsplib.Track - audioTrack *gortsplib.Track + videoTrack gortsplib.Track + audioTrack gortsplib.Track // in allocateProcs chan clientAllocateProcsReq @@ -461,7 +444,7 @@ type Client struct { func NewClient( primaryPlaylistURLStr string, fingerprint string, - onTracks func(*gortsplib.Track, *gortsplib.Track) error, + onTracks func(gortsplib.Track, gortsplib.Track) error, onPacket func(bool, []byte), parent ClientParent, ) (*Client, error) { @@ -896,33 +879,33 @@ func (c *Client) processSegment(innerCtx context.Context, byts []byte) error { } } -func (c *Client) onVideoTrack(track *gortsplib.Track) error { +func (c *Client) onVideoTrack(track gortsplib.Track) error { c.tracksMutex.Lock() defer c.tracksMutex.Unlock() c.videoTrack = track if c.audioPID == nil || c.audioTrack != nil { - return c.initializeTracks() + return c.initializeEncoders() } return nil } -func (c *Client) onAudioTrack(track *gortsplib.Track) error { +func (c *Client) onAudioTrack(track gortsplib.Track) error { c.tracksMutex.Lock() defer c.tracksMutex.Unlock() c.audioTrack = track if c.videoPID == nil || c.videoTrack != nil { - return c.initializeTracks() + return c.initializeEncoders() } return nil } -func (c *Client) initializeTracks() error { +func (c *Client) initializeEncoders() error { return c.onTracks(c.videoTrack, c.audioTrack) } diff --git a/internal/hls/client_test.go b/internal/hls/client_test.go index 9da94f88..3be5d95d 100644 --- a/internal/hls/client_test.go +++ b/internal/hls/client_test.go @@ -200,7 +200,7 @@ func TestClient(t *testing.T) { c, err := NewClient( prefix+"://localhost:5780/stream.m3u8", "33949E05FFFB5FF3E8AA16F8213A6251B4D9363804BA53233C4DA9A46D6F2739", - func(*gortsplib.Track, *gortsplib.Track) error { + func(gortsplib.Track, gortsplib.Track) error { return nil }, func(isVideo bool, byts []byte) { diff --git a/internal/hls/muxer.go b/internal/hls/muxer.go index 87c9ed45..d430e06a 100644 --- a/internal/hls/muxer.go +++ b/internal/hls/muxer.go @@ -1,6 +1,7 @@ package hls import ( + "fmt" "io" "time" @@ -18,27 +19,15 @@ type Muxer struct { func NewMuxer( hlsSegmentCount int, hlsSegmentDuration time.Duration, - videoTrack *gortsplib.Track, - audioTrack *gortsplib.Track) (*Muxer, error) { - var h264Conf *gortsplib.TrackConfigH264 + videoTrack *gortsplib.TrackH264, + audioTrack *gortsplib.TrackAAC) (*Muxer, error) { if videoTrack != nil { - var err error - h264Conf, err = videoTrack.ExtractConfigH264() - if err != nil { - return nil, err + if videoTrack.SPS() == nil || videoTrack.PPS() == nil { + return nil, fmt.Errorf("invalid H264 track: SPS or PPS not provided into the SDP") } } - var aacConf *gortsplib.TrackConfigAAC - if audioTrack != nil { - var err error - aacConf, err = audioTrack.ExtractConfigAAC() - if err != nil { - return nil, err - } - } - - primaryPlaylist := newMuxerPrimaryPlaylist(videoTrack, audioTrack, h264Conf, aacConf) + primaryPlaylist := newMuxerPrimaryPlaylist(videoTrack, audioTrack) streamPlaylist := newMuxerStreamPlaylist(hlsSegmentCount) @@ -47,8 +36,6 @@ func NewMuxer( hlsSegmentDuration, videoTrack, audioTrack, - h264Conf, - aacConf, streamPlaylist) m := &Muxer{ diff --git a/internal/hls/muxer_primary_playlist.go b/internal/hls/muxer_primary_playlist.go index 95fb6c85..a84cb26b 100644 --- a/internal/hls/muxer_primary_playlist.go +++ b/internal/hls/muxer_primary_playlist.go @@ -11,34 +11,30 @@ import ( ) type muxerPrimaryPlaylist struct { - videoTrack *gortsplib.Track - audioTrack *gortsplib.Track - h264Conf *gortsplib.TrackConfigH264 + videoTrack *gortsplib.TrackH264 + audioTrack *gortsplib.TrackAAC cnt []byte } func newMuxerPrimaryPlaylist( - videoTrack *gortsplib.Track, - audioTrack *gortsplib.Track, - h264Conf *gortsplib.TrackConfigH264, - aacConf *gortsplib.TrackConfigAAC, + videoTrack *gortsplib.TrackH264, + audioTrack *gortsplib.TrackAAC, ) *muxerPrimaryPlaylist { p := &muxerPrimaryPlaylist{ videoTrack: videoTrack, audioTrack: audioTrack, - h264Conf: h264Conf, } var codecs []string if p.videoTrack != nil { - codecs = append(codecs, "avc1."+hex.EncodeToString(p.h264Conf.SPS[1:4])) + codecs = append(codecs, "avc1."+hex.EncodeToString(p.videoTrack.SPS()[1:4])) } // https://developer.mozilla.org/en-US/docs/Web/Media/Formats/codecs_parameter if p.audioTrack != nil { - codecs = append(codecs, "mp4a.40."+strconv.FormatInt(int64(aacConf.Type), 10)) + codecs = append(codecs, "mp4a.40."+strconv.FormatInt(int64(p.audioTrack.Type()), 10)) } p.cnt = []byte("#EXTM3U\n" + diff --git a/internal/hls/muxer_test.go b/internal/hls/muxer_test.go index 70705ba1..bbaef2e4 100644 --- a/internal/hls/muxer_test.go +++ b/internal/hls/muxer_test.go @@ -18,12 +18,10 @@ func checkTSPacket(t *testing.T, byts []byte, pid int, afc int) { } func TestMuxerVideoAudio(t *testing.T) { - videoTrack, err := gortsplib.NewTrackH264(96, - &gortsplib.TrackConfigH264{SPS: []byte{0x07, 0x01, 0x02, 0x03}, PPS: []byte{0x08}}) + videoTrack, err := gortsplib.NewTrackH264(96, []byte{0x07, 0x01, 0x02, 0x03}, []byte{0x08}, nil) require.NoError(t, err) - audioTrack, err := gortsplib.NewTrackAAC(97, - &gortsplib.TrackConfigAAC{Type: 2, SampleRate: 44100, ChannelCount: 2}) + audioTrack, err := gortsplib.NewTrackAAC(97, 2, 44100, 2, nil) require.NoError(t, err) m, err := NewMuxer(3, 1*time.Second, videoTrack, audioTrack) @@ -129,8 +127,7 @@ func TestMuxerVideoAudio(t *testing.T) { } func TestMuxerAudio(t *testing.T) { - audioTrack, err := gortsplib.NewTrackAAC(97, - &gortsplib.TrackConfigAAC{Type: 2, SampleRate: 44100, ChannelCount: 2}) + audioTrack, err := gortsplib.NewTrackAAC(97, 2, 44100, 2, nil) require.NoError(t, err) m, err := NewMuxer(3, 1*time.Second, nil, audioTrack) @@ -178,15 +175,10 @@ func TestMuxerAudio(t *testing.T) { } func TestMuxerCloseBeforeFirstSegment(t *testing.T) { - videoTrack, err := gortsplib.NewTrackH264(96, - &gortsplib.TrackConfigH264{SPS: []byte{0x07, 0x01, 0x02, 0x03}, PPS: []byte{0x08}}) + videoTrack, err := gortsplib.NewTrackH264(96, []byte{0x07, 0x01, 0x02, 0x03}, []byte{0x08}, nil) require.NoError(t, err) - audioTrack, err := gortsplib.NewTrackAAC(97, - &gortsplib.TrackConfigAAC{Type: 2, SampleRate: 44100, ChannelCount: 2}) - require.NoError(t, err) - - m, err := NewMuxer(3, 1*time.Second, videoTrack, audioTrack) + m, err := NewMuxer(3, 1*time.Second, videoTrack, nil) require.NoError(t, err) // group with IDR diff --git a/internal/hls/muxer_ts_generator.go b/internal/hls/muxer_ts_generator.go index c00beacc..287dc9de 100644 --- a/internal/hls/muxer_ts_generator.go +++ b/internal/hls/muxer_ts_generator.go @@ -28,10 +28,8 @@ func idrPresent(nalus [][]byte) bool { type muxerTSGenerator struct { hlsSegmentCount int hlsSegmentDuration time.Duration - videoTrack *gortsplib.Track - audioTrack *gortsplib.Track - h264Conf *gortsplib.TrackConfigH264 - aacConf *gortsplib.TrackConfigAAC + videoTrack *gortsplib.TrackH264 + audioTrack *gortsplib.TrackAAC streamPlaylist *muxerStreamPlaylist writer *muxerTSWriter @@ -45,10 +43,8 @@ type muxerTSGenerator struct { func newMuxerTSGenerator( hlsSegmentCount int, hlsSegmentDuration time.Duration, - videoTrack *gortsplib.Track, - audioTrack *gortsplib.Track, - h264Conf *gortsplib.TrackConfigH264, - aacConf *gortsplib.TrackConfigAAC, + videoTrack *gortsplib.TrackH264, + audioTrack *gortsplib.TrackAAC, streamPlaylist *muxerStreamPlaylist, ) *muxerTSGenerator { m := &muxerTSGenerator{ @@ -56,8 +52,6 @@ func newMuxerTSGenerator( hlsSegmentDuration: hlsSegmentDuration, videoTrack: videoTrack, audioTrack: audioTrack, - h264Conf: h264Conf, - aacConf: aacConf, streamPlaylist: streamPlaylist, writer: newMuxerTSWriter(videoTrack, audioTrack), } @@ -109,7 +103,7 @@ func (m *muxerTSGenerator) writeH264(pts time.Duration, nalus [][]byte) error { case h264.NALUTypeIDR: // add SPS and PPS before every IDR - filteredNALUs = append(filteredNALUs, m.h264Conf.SPS, m.h264Conf.PPS) + filteredNALUs = append(filteredNALUs, m.videoTrack.SPS(), m.videoTrack.PPS()) } filteredNALUs = append(filteredNALUs, nalu) @@ -157,9 +151,9 @@ func (m *muxerTSGenerator) writeAAC(pts time.Duration, aus [][]byte) error { for i, au := range aus { pkts[i] = &aac.ADTSPacket{ - Type: m.aacConf.Type, - SampleRate: m.aacConf.SampleRate, - ChannelCount: m.aacConf.ChannelCount, + Type: m.audioTrack.Type(), + SampleRate: m.audioTrack.ClockRate(), + ChannelCount: m.audioTrack.ChannelCount(), AU: au, } } diff --git a/internal/hls/muxer_ts_segment.go b/internal/hls/muxer_ts_segment.go index 81e6faab..70568c5c 100644 --- a/internal/hls/muxer_ts_segment.go +++ b/internal/hls/muxer_ts_segment.go @@ -11,7 +11,7 @@ import ( ) type muxerTSSegment struct { - videoTrack *gortsplib.Track + videoTrack gortsplib.Track writer *muxerTSWriter name string @@ -22,7 +22,7 @@ type muxerTSSegment struct { } func newMuxerTSSegment( - videoTrack *gortsplib.Track, + videoTrack gortsplib.Track, writer *muxerTSWriter, ) *muxerTSSegment { t := &muxerTSSegment{ diff --git a/internal/hls/muxer_ts_writer.go b/internal/hls/muxer_ts_writer.go index 034c97e0..cef89b9a 100644 --- a/internal/hls/muxer_ts_writer.go +++ b/internal/hls/muxer_ts_writer.go @@ -13,8 +13,8 @@ type muxerTSWriter struct { } func newMuxerTSWriter( - videoTrack *gortsplib.Track, - audioTrack *gortsplib.Track) *muxerTSWriter { + videoTrack gortsplib.Track, + audioTrack gortsplib.Track) *muxerTSWriter { w := &muxerTSWriter{} w.innerMuxer = astits.NewMuxer(context.Background(), w) diff --git a/internal/rtcpsenderset/rtcpsenderset.go b/internal/rtcpsenderset/rtcpsenderset.go index e6156a18..4812462a 100644 --- a/internal/rtcpsenderset/rtcpsenderset.go +++ b/internal/rtcpsenderset/rtcpsenderset.go @@ -31,9 +31,8 @@ func New( } s.senders = make([]*rtcpsender.RTCPSender, len(tracks)) - for i, t := range tracks { - clockRate, _ := t.ClockRate() - s.senders[i] = rtcpsender.New(clockRate) + for i, track := range tracks { + s.senders[i] = rtcpsender.New(track.ClockRate()) } go s.run() diff --git a/internal/rtmp/conn.go b/internal/rtmp/conn.go index 51747db6..1d27b331 100644 --- a/internal/rtmp/conn.go +++ b/internal/rtmp/conn.go @@ -82,9 +82,9 @@ func (c *Conn) WritePacket(pkt av.Packet) error { } // ReadMetadata reads track informations. -func (c *Conn) ReadMetadata() (*gortsplib.Track, *gortsplib.Track, error) { - var videoTrack *gortsplib.Track - var audioTrack *gortsplib.Track +func (c *Conn) ReadMetadata() (*gortsplib.TrackH264, *gortsplib.TrackAAC, error) { + var videoTrack *gortsplib.TrackH264 + var audioTrack *gortsplib.TrackAAC md, err := func() (flvio.AMFMap, error) { pkt, err := c.ReadPacket() @@ -198,7 +198,7 @@ func (c *Conn) ReadMetadata() (*gortsplib.Track, *gortsplib.Track, error) { return nil, nil, err } - videoTrack, err = gortsplib.NewTrackH264(96, &gortsplib.TrackConfigH264{SPS: codec.SPS[0], PPS: codec.PPS[0]}) + videoTrack, err = gortsplib.NewTrackH264(96, codec.SPS[0], codec.PPS[0], nil) if err != nil { return nil, nil, err } @@ -218,12 +218,8 @@ func (c *Conn) ReadMetadata() (*gortsplib.Track, *gortsplib.Track, error) { return nil, nil, err } - audioTrack, err = gortsplib.NewTrackAAC(96, &gortsplib.TrackConfigAAC{ - Type: int(mpegConf.Type), - SampleRate: mpegConf.SampleRate, - ChannelCount: mpegConf.ChannelCount, - AOTSpecificConfig: mpegConf.AOTSpecificConfig, - }) + audioTrack, err = gortsplib.NewTrackAAC(96, int(mpegConf.Type), mpegConf.SampleRate, + mpegConf.ChannelCount, mpegConf.AOTSpecificConfig) if err != nil { return nil, nil, err } @@ -237,7 +233,7 @@ func (c *Conn) ReadMetadata() (*gortsplib.Track, *gortsplib.Track, error) { } // WriteMetadata writes track informations. -func (c *Conn) WriteMetadata(videoTrack *gortsplib.Track, audioTrack *gortsplib.Track) error { +func (c *Conn) WriteMetadata(videoTrack *gortsplib.TrackH264, audioTrack *gortsplib.TrackAAC) error { err := c.WritePacket(av.Packet{ Type: av.Metadata, Data: flvio.FillAMF0ValMalloc(flvio.AMFMap{ @@ -274,17 +270,16 @@ func (c *Conn) WriteMetadata(videoTrack *gortsplib.Track, audioTrack *gortsplib. } if videoTrack != nil { - conf, err := videoTrack.ExtractConfigH264() - if err != nil { - return err + if videoTrack.SPS() == nil || videoTrack.PPS() == nil { + return fmt.Errorf("invalid H264 track: SPS or PPS not provided into the SDP") } codec := nh264.Codec{ SPS: map[int][]byte{ - 0: conf.SPS, + 0: videoTrack.SPS(), }, PPS: map[int][]byte{ - 0: conf.PPS, + 0: videoTrack.PPS(), }, } b := make([]byte, 128) @@ -302,16 +297,11 @@ func (c *Conn) WriteMetadata(videoTrack *gortsplib.Track, audioTrack *gortsplib. } if audioTrack != nil { - conf, err := audioTrack.ExtractConfigAAC() - if err != nil { - return err - } - enc, err := aac.MPEG4AudioConfig{ - Type: aac.MPEG4AudioType(conf.Type), - SampleRate: conf.SampleRate, - ChannelCount: conf.ChannelCount, - AOTSpecificConfig: conf.AOTSpecificConfig, + Type: aac.MPEG4AudioType(audioTrack.Type()), + SampleRate: audioTrack.ClockRate(), + ChannelCount: audioTrack.ChannelCount(), + AOTSpecificConfig: audioTrack.AOTSpecificConfig(), }.Encode() if err != nil { return err