From 72e74f349e6bc3376a0e6bbad5da93974f2dd6de Mon Sep 17 00:00:00 2001 From: Alessandro Ros Date: Sun, 15 Sep 2024 22:51:55 +0200 Subject: [PATCH] server: use relative control attributes (#620) --- client_media.go | 2 +- client_record_test.go | 6 ++- client_udp_listener.go | 2 +- pkg/base/path.go | 2 + pkg/base/url.go | 2 + server_conn.go | 25 ++------- server_multicast_writer.go | 2 +- server_play_test.go | 86 ++++++++++++++++++------------- server_record_test.go | 42 --------------- server_session.go | 103 +++++++++++++++++-------------------- server_test.go | 22 ++++---- server_udp_listener.go | 2 +- 12 files changed, 126 insertions(+), 170 deletions(-) diff --git a/client_media.go b/client_media.go index 66c76277..bc974308 100644 --- a/client_media.go +++ b/client_media.go @@ -71,7 +71,7 @@ func (cm *clientMedia) allocateUDPListeners( } var err error - cm.udpRTPListener, cm.udpRTCPListener, err = clientAllocateUDPListenerPair(cm.c) + cm.udpRTPListener, cm.udpRTCPListener, err = allocateUDPListenerPair(cm.c) return err } diff --git a/client_record_test.go b/client_record_test.go index 88c4c972..8fb35eca 100644 --- a/client_record_test.go +++ b/client_record_test.go @@ -185,6 +185,10 @@ func TestClientRecordSerial(t *testing.T) { err = desc.Unmarshal(req.Body) require.NoError(t, err2) + var desc2 description.Session + err = desc2.Unmarshal(&desc) + require.NoError(t, err2) + err2 = conn.WriteResponse(&base.Response{ StatusCode: base.StatusOK, }) @@ -194,7 +198,7 @@ func TestClientRecordSerial(t *testing.T) { require.NoError(t, err2) require.Equal(t, base.Setup, req.Method) require.Equal(t, mustParseURL( - scheme+"://localhost:8554/teststream/"+relativeControlAttribute(desc.MediaDescriptions[0])), req.URL) + scheme+"://localhost:8554/teststream/"+desc2.Medias[0].Control), req.URL) var inTH headers.Transport err2 = inTH.Unmarshal(req.Header["Transport"]) diff --git a/client_udp_listener.go b/client_udp_listener.go index 61161fb2..fb0ae2f9 100644 --- a/client_udp_listener.go +++ b/client_udp_listener.go @@ -24,7 +24,7 @@ func randInRange(max int) (int, error) { return int(n.Int64()), nil } -func clientAllocateUDPListenerPair(c *Client) (*clientUDPListener, *clientUDPListener, error) { +func allocateUDPListenerPair(c *Client) (*clientUDPListener, *clientUDPListener, error) { // choose two consecutive ports in range 65535-10000 // RTP port must be even and RTCP port odd for { diff --git a/pkg/base/path.go b/pkg/base/path.go index d6fa6d9f..537adc2c 100644 --- a/pkg/base/path.go +++ b/pkg/base/path.go @@ -5,6 +5,8 @@ import ( ) // PathSplitQuery splits a path from a query. +// +// Deprecated: not useful anymore. func PathSplitQuery(pathAndQuery string) (string, string) { i := strings.Index(pathAndQuery, "?") if i >= 0 { diff --git a/pkg/base/url.go b/pkg/base/url.go index 1205f1f1..5f915453 100644 --- a/pkg/base/url.go +++ b/pkg/base/url.go @@ -75,6 +75,8 @@ func (u *URL) CloneWithoutCredentials() *URL { } // RTSPPathAndQuery returns the path and query of a RTSP URL. +// +// Deprecated: not useful anymore. func (u *URL) RTSPPathAndQuery() (string, bool) { var pathAndQuery string if u.RawPath != "" { diff --git a/server_conn.go b/server_conn.go index 43494321..5a3ed7ad 100644 --- a/server_conn.go +++ b/server_conn.go @@ -24,7 +24,7 @@ func getSessionID(header base.Header) string { return "" } -func serverSideDescription(d *description.Session, contentBase *base.URL) *description.Session { +func serverSideDescription(d *description.Session) *description.Session { out := &description.Session{ Title: d.Title, FECGroups: d.FECGroups, @@ -32,7 +32,7 @@ func serverSideDescription(d *description.Session, contentBase *base.URL) *descr } for i, medi := range d.Medias { - mc := &description.Media{ + out.Medias[i] = &description.Media{ Type: medi.Type, ID: medi.ID, IsBackChannel: medi.IsBackChannel, @@ -41,15 +41,6 @@ func serverSideDescription(d *description.Session, contentBase *base.URL) *descr Control: "trackID=" + strconv.FormatInt(int64(i), 10), Formats: medi.Formats, } - - // always use the absolute URL of the track as control attribute, in order - // to fix compatibility between GStreamer and URLs with queries. - // (when a relative control is used, GStreamer puts it between path and query, - // instead of appending it to the URL). - u, _ := mc.URL(contentBase) - mc.Control = u.String() - - out.Medias[i] = mc } return out @@ -215,16 +206,10 @@ func (sc *ServerConn) handleRequestInner(req *base.Request) (*base.Response, err var path string var query string + switch req.Method { case base.Describe, base.GetParameter, base.SetParameter: - pathAndQuery, ok := req.URL.RTSPPathAndQuery() - if !ok { - return &base.Response{ - StatusCode: base.StatusBadRequest, - }, liberrors.ErrServerInvalidPath{} - } - - path, query = base.PathSplitQuery(pathAndQuery) + path, query = getPathAndQuery(req.URL, false) } switch req.Method { @@ -295,7 +280,7 @@ func (sc *ServerConn) handleRequestInner(req *base.Request) (*base.Response, err } if stream != nil { - byts, _ := serverSideDescription(stream.desc, req.URL).Marshal(multicast) + byts, _ := serverSideDescription(stream.desc).Marshal(multicast) res.Body = byts } } diff --git a/server_multicast_writer.go b/server_multicast_writer.go index 6795aca3..74f19f37 100644 --- a/server_multicast_writer.go +++ b/server_multicast_writer.go @@ -22,7 +22,7 @@ func (h *serverMulticastWriter) initialize() error { return err } - rtpl, rtcpl, err := serverAllocateUDPListenerMulticastPair( + rtpl, rtcpl, err := allocateUDPListenerMulticastPair( h.s.ListenPacket, h.s.WriteTimeout, h.s.MulticastRTPPort, diff --git a/server_play_test.go b/server_play_test.go index aa1d6552..7e95bc58 100644 --- a/server_play_test.go +++ b/server_play_test.go @@ -13,7 +13,6 @@ import ( "github.com/pion/rtcp" "github.com/pion/rtp" - psdp "github.com/pion/sdp/v3" "github.com/stretchr/testify/require" "golang.org/x/net/ipv4" @@ -63,18 +62,13 @@ func multicastCapableIP(t *testing.T) string { return "" } -func relativeControlAttribute(md *psdp.MediaDescription) string { - v, _ := md.Attribute("control") - i := strings.Index(v, "trackID=") - return v[i:] +func mediaURL(t *testing.T, baseURL *base.URL, media *description.Media) *base.URL { + u, err := media.URL(baseURL) + require.NoError(t, err) + return u } -func absoluteControlAttribute(md *psdp.MediaDescription) string { - v, _ := md.Attribute("control") - return v -} - -func doDescribe(t *testing.T, conn *conn.Conn) *sdp.SessionDescription { +func doDescribe(t *testing.T, conn *conn.Conn) *description.Session { res, err := writeReqReadRes(conn, base.Request{ Method: base.Describe, URL: mustParseURL("rtsp://localhost:8554/teststream?param=value"), @@ -88,7 +82,14 @@ func doDescribe(t *testing.T, conn *conn.Conn) *sdp.SessionDescription { var desc sdp.SessionDescription err = desc.Unmarshal(res.Body) require.NoError(t, err) - return &desc + + var desc2 description.Session + err = desc2.Unmarshal(&desc) + require.NoError(t, err) + + desc2.BaseURL = mustParseURL(res.Header["Content-Base"][0]) + + return &desc2 } func doSetup(t *testing.T, conn *conn.Conn, u string, @@ -179,11 +180,17 @@ func TestServerPlayPath(t *testing.T) { "/teststream", }, { - "with query", + "with query, ffmpeg format", "rtsp://localhost:8554/teststream?testing=123[control]", "rtsp://localhost:8554/teststream/", "/teststream", }, + { + "with query, gstreamer format", + "rtsp://localhost:8554/teststream[control]?testing=123", + "rtsp://localhost:8554/teststream/", + "/teststream", + }, { // this is needed to support reading mpegts with ffmpeg "without media id", @@ -204,15 +211,21 @@ func TestServerPlayPath(t *testing.T) { "/test/stream", }, { - "subpath with query", + "subpath with query, ffmpeg format", "rtsp://localhost:8554/test/stream?testing=123[control]", "rtsp://localhost:8554/test/stream", "/test/stream", }, + { + "subpath with query, gstreamer format", + "rtsp://localhost:8554/test/stream[control]?testing=123", + "rtsp://localhost:8554/test/stream", + "/test/stream", + }, { "no slash", "rtsp://localhost:8554[control]", - "rtsp://localhost:8554/", + "rtsp://localhost:8554", "", }, { @@ -279,8 +292,7 @@ func TestServerPlayPath(t *testing.T) { } res, _ := doSetup(t, conn, - strings.ReplaceAll(ca.setupURL, "[control]", "/"+ - relativeControlAttribute(desc.MediaDescriptions[1])), + strings.ReplaceAll(ca.setupURL, "[control]", "/"+desc.Medias[1].Control), th, "") session := readSession(t, res) @@ -356,7 +368,7 @@ func TestServerPlaySetupErrors(t *testing.T) { res, err := writeReqReadRes(conn, base.Request{ Method: base.Setup, - URL: mustParseURL(absoluteControlAttribute(desc.MediaDescriptions[0])), + URL: mediaURL(t, desc.BaseURL, desc.Medias[0]), Header: base.Header{ "CSeq": base.HeaderValue{"2"}, "Transport": th.Marshal(), @@ -374,7 +386,7 @@ func TestServerPlaySetupErrors(t *testing.T) { res, err = writeReqReadRes(conn, base.Request{ Method: base.Setup, - URL: mustParseURL("rtsp://localhost:8554/test12stream/" + relativeControlAttribute(desc.MediaDescriptions[0])), + URL: mustParseURL("rtsp://localhost:8554/test12stream/" + desc.Medias[0].Control), Header: base.Header{ "CSeq": base.HeaderValue{"3"}, "Transport": th.Marshal(), @@ -394,7 +406,7 @@ func TestServerPlaySetupErrors(t *testing.T) { res, err = writeReqReadRes(conn, base.Request{ Method: base.Setup, - URL: mustParseURL(absoluteControlAttribute(desc.MediaDescriptions[0])), + URL: mediaURL(t, desc.BaseURL, desc.Medias[0]), Header: base.Header{ "CSeq": base.HeaderValue{"4"}, "Transport": th.Marshal(), @@ -473,7 +485,7 @@ func TestServerPlaySetupErrorSameUDPPortsAndIP(t *testing.T) { res, err := writeReqReadRes(conn, base.Request{ Method: base.Setup, - URL: mustParseURL(absoluteControlAttribute(desc.MediaDescriptions[0])), + URL: mediaURL(t, desc.BaseURL, desc.Medias[0]), Header: base.Header{ "CSeq": base.HeaderValue{"2"}, "Transport": inTH.Marshal(), @@ -654,7 +666,7 @@ func TestServerPlay(t *testing.T) { inTH.InterleavedIDs = &[2]int{5, 6} // odd value } - res, th := doSetup(t, conn, absoluteControlAttribute(desc.MediaDescriptions[0]), inTH, "") + res, th := doSetup(t, conn, mediaURL(t, desc.BaseURL, desc.Medias[0]).String(), inTH, "") var l1 net.PacketConn var l2 net.PacketConn @@ -916,7 +928,7 @@ func TestServerPlayDecodeErrors(t *testing.T) { inTH.InterleavedIDs = &[2]int{0, 1} } - res, resTH := doSetup(t, conn, absoluteControlAttribute(desc.MediaDescriptions[0]), inTH, "") + res, resTH := doSetup(t, conn, mediaURL(t, desc.BaseURL, desc.Medias[0]).String(), inTH, "") var l1 net.PacketConn var l2 net.PacketConn @@ -1034,7 +1046,7 @@ func TestServerPlayRTCPReport(t *testing.T) { inTH.InterleavedIDs = &[2]int{0, 1} } - res, _ := doSetup(t, conn, absoluteControlAttribute(desc.MediaDescriptions[0]), inTH, "") + res, _ := doSetup(t, conn, mediaURL(t, desc.BaseURL, desc.Medias[0]).String(), inTH, "") var l1 net.PacketConn var l2 net.PacketConn @@ -1228,7 +1240,7 @@ func TestServerPlayTCPResponseBeforeFrames(t *testing.T) { InterleavedIDs: &[2]int{0, 1}, } - res, _ := doSetup(t, conn, absoluteControlAttribute(desc.MediaDescriptions[0]), inTH, "") + res, _ := doSetup(t, conn, mediaURL(t, desc.BaseURL, desc.Medias[0]).String(), inTH, "") session := readSession(t, res) @@ -1285,7 +1297,7 @@ func TestServerPlayPlayPlay(t *testing.T) { ClientPorts: &[2]int{30450, 30451}, } - res, _ := doSetup(t, conn, absoluteControlAttribute(desc.MediaDescriptions[0]), inTH, "") + res, _ := doSetup(t, conn, mediaURL(t, desc.BaseURL, desc.Medias[0]).String(), inTH, "") session := readSession(t, res) @@ -1370,7 +1382,7 @@ func TestServerPlayPlayPausePlay(t *testing.T) { InterleavedIDs: &[2]int{0, 1}, } - res, _ := doSetup(t, conn, absoluteControlAttribute(desc.MediaDescriptions[0]), inTH, "") + res, _ := doSetup(t, conn, mediaURL(t, desc.BaseURL, desc.Medias[0]).String(), inTH, "") session := readSession(t, res) @@ -1452,7 +1464,7 @@ func TestServerPlayPlayPausePause(t *testing.T) { InterleavedIDs: &[2]int{0, 1}, } - res, _ := doSetup(t, conn, absoluteControlAttribute(desc.MediaDescriptions[0]), inTH, "") + res, _ := doSetup(t, conn, mediaURL(t, desc.BaseURL, desc.Medias[0]).String(), inTH, "") session := readSession(t, res) @@ -1542,7 +1554,7 @@ func TestServerPlayTimeout(t *testing.T) { inTH.Protocol = headers.TransportProtocolUDP } - res, _ := doSetup(t, conn, absoluteControlAttribute(desc.MediaDescriptions[0]), inTH, "") + res, _ := doSetup(t, conn, mediaURL(t, desc.BaseURL, desc.Medias[0]).String(), inTH, "") session := readSession(t, res) @@ -1624,7 +1636,7 @@ func TestServerPlayWithoutTeardown(t *testing.T) { inTH.InterleavedIDs = &[2]int{0, 1} } - res, _ := doSetup(t, conn, absoluteControlAttribute(desc.MediaDescriptions[0]), inTH, "") + res, _ := doSetup(t, conn, mediaURL(t, desc.BaseURL, desc.Medias[0]).String(), inTH, "") session := readSession(t, res) @@ -1693,7 +1705,7 @@ func TestServerPlayUDPChangeConn(t *testing.T) { ClientPorts: &[2]int{35466, 35467}, } - res, _ := doSetup(t, conn, absoluteControlAttribute(desc.MediaDescriptions[0]), inTH, "") + res, _ := doSetup(t, conn, mediaURL(t, desc.BaseURL, desc.Medias[0]).String(), inTH, "") session := readSession(t, res) @@ -1774,7 +1786,7 @@ func TestServerPlayPartialMedias(t *testing.T) { InterleavedIDs: &[2]int{4, 5}, } - res, _ := doSetup(t, conn, absoluteControlAttribute(desc.MediaDescriptions[0]), inTH, "") + res, _ := doSetup(t, conn, mediaURL(t, desc.BaseURL, desc.Medias[0]).String(), inTH, "") session := readSession(t, res) @@ -1802,7 +1814,7 @@ func TestServerPlayAdditionalInfos(t *testing.T) { InterleavedIDs: &[2]int{0, 1}, } - res, th := doSetup(t, conn, absoluteControlAttribute(desc.MediaDescriptions[0]), inTH, "") + res, th := doSetup(t, conn, mediaURL(t, desc.BaseURL, desc.Medias[0]).String(), inTH, "") ssrcs := make([]*uint32, 2) ssrcs[0] = th.SSRC @@ -1816,7 +1828,7 @@ func TestServerPlayAdditionalInfos(t *testing.T) { session := readSession(t, res) - _, th = doSetup(t, conn, absoluteControlAttribute(desc.MediaDescriptions[1]), inTH, session) + _, th = doSetup(t, conn, mediaURL(t, desc.BaseURL, desc.Medias[1]).String(), inTH, session) ssrcs[1] = th.SSRC @@ -2016,13 +2028,13 @@ func TestServerPlayNoInterleavedIDs(t *testing.T) { Protocol: headers.TransportProtocolTCP, } - res, th := doSetup(t, conn, absoluteControlAttribute(desc.MediaDescriptions[0]), inTH, "") + res, th := doSetup(t, conn, mediaURL(t, desc.BaseURL, desc.Medias[0]).String(), inTH, "") require.Equal(t, &[2]int{0, 1}, th.InterleavedIDs) session := readSession(t, res) - _, th = doSetup(t, conn, absoluteControlAttribute(desc.MediaDescriptions[1]), inTH, session) + _, th = doSetup(t, conn, mediaURL(t, desc.BaseURL, desc.Medias[1]).String(), inTH, session) require.Equal(t, &[2]int{2, 3}, th.InterleavedIDs) @@ -2097,7 +2109,7 @@ func TestServerPlayBytesSent(t *testing.T) { inTH.InterleavedIDs = &[2]int{0, 1} } - res, _ := doSetup(t, conn, absoluteControlAttribute(desc.MediaDescriptions[0]), inTH, "") + res, _ := doSetup(t, conn, mediaURL(t, desc.BaseURL, desc.Medias[0]).String(), inTH, "") session := readSession(t, res) diff --git a/server_record_test.go b/server_record_test.go index 683f127d..040a842b 100644 --- a/server_record_test.go +++ b/server_record_test.go @@ -48,38 +48,6 @@ func doRecord(t *testing.T, conn *conn.Conn, u string, session string) { require.Equal(t, base.StatusOK, res.StatusCode) } -func invalidURLAnnounceReq(t *testing.T, control string) base.Request { - medi := testH264Media - medi.Control = control - - sout := &sdp.SessionDescription{ - SessionName: psdp.SessionName("Stream"), - Origin: psdp.Origin{ - Username: "-", - NetworkType: "IN", - AddressType: "IP4", - UnicastAddress: "127.0.0.1", - }, - TimeDescriptions: []psdp.TimeDescription{ - {Timing: psdp.Timing{}}, - }, - MediaDescriptions: []*psdp.MediaDescription{medi.Marshal()}, - } - - byts, err := sout.Marshal() - require.NoError(t, err) - - return base.Request{ - Method: base.Announce, - URL: mustParseURL("rtsp://localhost:8554/teststream"), - Header: base.Header{ - "CSeq": base.HeaderValue{"1"}, - "Content-Type": base.HeaderValue{"application/sdp"}, - }, - Body: byts, - } -} - func TestServerRecordErrorAnnounce(t *testing.T) { for _, ca := range []struct { name string @@ -145,16 +113,6 @@ func TestServerRecordErrorAnnounce(t *testing.T) { }, "invalid SDP: media 1 is invalid: clock rate not found", }, - { - "invalid URL 1", - invalidURLAnnounceReq(t, "rtsp:// aaaaa"), - "unable to generate media URL", - }, - { - "invalid URL 3", - invalidURLAnnounceReq(t, "rtsp://host/otherpath"), - "invalid media path: must begin with '/teststream', but is '/otherpath'", - }, } { t.Run(ca.name, func(t *testing.T) { nconnClosed := make(chan struct{}) diff --git a/server_session.go b/server_session.go index 08793061..ad645f8b 100644 --- a/server_session.go +++ b/server_session.go @@ -34,28 +34,53 @@ func stringsReverseIndex(s, substr string) int { return -1 } -func serverParseURLForPlay(u *base.URL) (string, string, string, error) { - pathAndQuery, ok := u.RTSPPathAndQuery() - if !ok { - return "", "", "", liberrors.ErrServerInvalidPath{} - } - - i := stringsReverseIndex(pathAndQuery, "/trackID=") - if i < 0 { - if !strings.HasSuffix(pathAndQuery, "/") { - return "", "", "", liberrors.ErrServerPathNoSlash{} +// used for all methods except SETUP +func getPathAndQuery(u *base.URL, isAnnounce bool) (string, string) { + if !isAnnounce { + // FFmpeg format + if strings.HasSuffix(u.RawQuery, "/") { + return u.Path, u.RawQuery[:len(u.RawQuery)-1] } - path, query := base.PathSplitQuery(pathAndQuery[:len(pathAndQuery)-1]) - return path, query, "", nil + // GStreamer format + if len(u.Path) > 1 && strings.HasSuffix(u.Path, "/") { + return u.Path[:len(u.Path)-1], u.RawQuery + } } - var trackID string - pathAndQuery, trackID = pathAndQuery[:i], pathAndQuery[i+len("/trackID="):] - path, query := base.PathSplitQuery(pathAndQuery) - return path, query, trackID, nil + return u.Path, u.RawQuery } +// used for SETUP when playing +func getPathAndQueryAndTrackID(u *base.URL) (string, string, string, error) { + // FFmpeg format + i := stringsReverseIndex(u.RawQuery, "/trackID=") + if i >= 0 { + path := u.Path + query := u.RawQuery[:i] + trackID := u.RawQuery[i+len("/trackID="):] + return path, query, trackID, nil + } + + // GStreamer format + i = stringsReverseIndex(u.Path, "/trackID=") + if i >= 0 { + path := u.Path[:i] + query := u.RawQuery + trackID := u.Path[i+len("/trackID="):] + return path, query, trackID, nil + } + + // no track ID and a trailing slash. + // this happens when trying to read a MPEG-TS stream with FFmpeg. + if strings.HasSuffix(u.Path[1:], "/") { + return u.Path[:len(u.Path)-1], u.RawQuery, "0", nil + } + + return "", "", "", liberrors.ErrServerPathNoSlash{} +} + +// used for SETUP when recording func findMediaByURL( medias []*description.Media, path string, @@ -520,21 +545,12 @@ func (ss *ServerSession) handleRequestInner(sc *ServerConn, req *base.Request) ( var path string var query string + switch req.Method { - case base.Announce, base.Play, base.Record, base.Pause, base.GetParameter, base.SetParameter: - pathAndQuery, ok := req.URL.RTSPPathAndQuery() - if !ok { - return &base.Response{ - StatusCode: base.StatusBadRequest, - }, liberrors.ErrServerInvalidPath{} - } - - // pathAndQuery can end with a slash due to Content-Base, remove it - if ss.state == ServerSessionStatePrePlay || ss.state == ServerSessionStatePlay { - pathAndQuery = strings.TrimSuffix(pathAndQuery, "/") - } - - path, query = base.PathSplitQuery(pathAndQuery) + case base.Announce: + path, query = getPathAndQuery(req.URL, true) + case base.Pause, base.GetParameter, base.SetParameter, base.Play, base.Record: + path, query = getPathAndQuery(req.URL, false) } switch req.Method { @@ -610,30 +626,6 @@ func (ss *ServerSession) handleRequestInner(sc *ServerConn, req *base.Request) ( }, liberrors.ErrServerSDPInvalid{Err: err} } - for _, medi := range desc.Medias { - var mediURL *base.URL - mediURL, err = medi.URL(req.URL) - if err != nil { - return &base.Response{ - StatusCode: base.StatusBadRequest, - }, fmt.Errorf("unable to generate media URL") - } - - mediPath, ok := mediURL.RTSPPathAndQuery() - if !ok { - return &base.Response{ - StatusCode: base.StatusBadRequest, - }, fmt.Errorf("invalid media URL (%v)", mediURL) - } - - if !strings.HasPrefix(mediPath, path) { - return &base.Response{ - StatusCode: base.StatusBadRequest, - }, fmt.Errorf("invalid media path: must begin with '%s', but is '%s'", - path, mediPath) - } - } - res, err := ss.s.Handler.(ServerHandlerOnAnnounce).OnAnnounce(&ServerHandlerOnAnnounceCtx{ Session: ss, Conn: sc, @@ -682,9 +674,10 @@ func (ss *ServerSession) handleRequestInner(sc *ServerConn, req *base.Request) ( } var trackID string + switch ss.state { case ServerSessionStateInitial, ServerSessionStatePrePlay: // play - path, query, trackID, err = serverParseURLForPlay(req.URL) + path, query, trackID, err = getPathAndQueryAndTrackID(req.URL) if err != nil { return &base.Response{ StatusCode: base.StatusBadRequest, diff --git a/server_test.go b/server_test.go index d88f09d1..9aec0281 100644 --- a/server_test.go +++ b/server_test.go @@ -408,7 +408,7 @@ func TestServerErrorMethodNotImplemented(t *testing.T) { InterleavedIDs: &[2]int{0, 1}, } - res, _ := doSetup(t, conn, absoluteControlAttribute(desc.MediaDescriptions[0]), inTH, "") + res, _ := doSetup(t, conn, mediaURL(t, desc.BaseURL, desc.Medias[0]).String(), inTH, "") session = readSession(t, res) } @@ -422,7 +422,7 @@ func TestServerErrorMethodNotImplemented(t *testing.T) { res, err := writeReqReadRes(conn, base.Request{ Method: base.SetParameter, - URL: mustParseURL(absoluteControlAttribute(desc.MediaDescriptions[0])), + URL: mediaURL(t, desc.BaseURL, desc.Medias[0]), Header: headers, }) require.NoError(t, err) @@ -496,7 +496,7 @@ func TestServerErrorTCPTwoConnOneSession(t *testing.T) { InterleavedIDs: &[2]int{0, 1}, } - res, _ := doSetup(t, conn1, absoluteControlAttribute(desc1.MediaDescriptions[0]), inTH, "") + res, _ := doSetup(t, conn1, mediaURL(t, desc1.BaseURL, desc1.Medias[0]).String(), inTH, "") session := readSession(t, res) @@ -511,7 +511,7 @@ func TestServerErrorTCPTwoConnOneSession(t *testing.T) { res, err = writeReqReadRes(conn2, base.Request{ Method: base.Setup, - URL: mustParseURL(absoluteControlAttribute(desc2.MediaDescriptions[0])), + URL: mediaURL(t, desc2.BaseURL, desc2.Medias[0]), Header: base.Header{ "CSeq": base.HeaderValue{"1"}, "Transport": headers.Transport{ @@ -577,7 +577,7 @@ func TestServerErrorTCPOneConnTwoSessions(t *testing.T) { InterleavedIDs: &[2]int{0, 1}, } - res, _ := doSetup(t, conn, absoluteControlAttribute(desc.MediaDescriptions[0]), inTH, "") + res, _ := doSetup(t, conn, mediaURL(t, desc.BaseURL, desc.Medias[0]).String(), inTH, "") session := readSession(t, res) @@ -585,7 +585,7 @@ func TestServerErrorTCPOneConnTwoSessions(t *testing.T) { res, err = writeReqReadRes(conn, base.Request{ Method: base.Setup, - URL: mustParseURL(absoluteControlAttribute(desc.MediaDescriptions[0])), + URL: mediaURL(t, desc.BaseURL, desc.Medias[0]), Header: base.Header{ "CSeq": base.HeaderValue{"3"}, "Transport": headers.Transport{ @@ -650,7 +650,7 @@ func TestServerSetupMultipleTransports(t *testing.T) { res, err := writeReqReadRes(conn, base.Request{ Method: base.Setup, - URL: mustParseURL(absoluteControlAttribute(desc.MediaDescriptions[0])), + URL: mediaURL(t, desc.BaseURL, desc.Medias[0]), Header: base.Header{ "CSeq": base.HeaderValue{"1"}, "Transport": inTHS.Marshal(), @@ -739,7 +739,7 @@ func TestServerGetSetParameter(t *testing.T) { InterleavedIDs: &[2]int{0, 1}, } - res, _ := doSetup(t, conn, absoluteControlAttribute(desc.MediaDescriptions[0]), inTH, "") + res, _ := doSetup(t, conn, mediaURL(t, desc.BaseURL, desc.Medias[0]).String(), inTH, "") session = readSession(t, res) } @@ -880,7 +880,7 @@ func TestServerSessionClose(t *testing.T) { InterleavedIDs: &[2]int{0, 1}, } - doSetup(t, conn, absoluteControlAttribute(desc.MediaDescriptions[0]), inTH, "") + doSetup(t, conn, mediaURL(t, desc.BaseURL, desc.Medias[0]).String(), inTH, "") session.Close() session.Close() @@ -956,7 +956,7 @@ func TestServerSessionAutoClose(t *testing.T) { res, err := writeReqReadRes(conn, base.Request{ Method: base.Setup, - URL: mustParseURL(absoluteControlAttribute(desc.MediaDescriptions[0])), + URL: mediaURL(t, desc.BaseURL, desc.Medias[0]), Header: base.Header{ "CSeq": base.HeaderValue{"1"}, "Transport": inTH.Marshal(), @@ -1017,7 +1017,7 @@ func TestServerSessionTeardown(t *testing.T) { InterleavedIDs: &[2]int{0, 1}, } - res, _ := doSetup(t, conn, absoluteControlAttribute(desc.MediaDescriptions[0]), inTH, "") + res, _ := doSetup(t, conn, mediaURL(t, desc.BaseURL, desc.Medias[0]).String(), inTH, "") session := readSession(t, res) diff --git a/server_udp_listener.go b/server_udp_listener.go index 61c89f1b..4e333ba6 100644 --- a/server_udp_listener.go +++ b/server_udp_listener.go @@ -25,7 +25,7 @@ func (p *clientAddr) fill(ip net.IP, port int) { } } -func serverAllocateUDPListenerMulticastPair( +func allocateUDPListenerMulticastPair( listenPacket func(network, address string) (net.PacketConn, error), writeTimeout time.Duration, multicastRTPPort int,