Repository: bluenviron/gortsplib
Pull request #226 (2023-04-06 21:34:30)

use normalized trackID in place of mediaUUID
This is needed to support clients like the Grandstream GXV3500.

Fixes https://github.com/bluenviron/gortsplib/issues/190

codecov-commenter: ## [Codecov](https://codecov.io/gh/bluenviron/gortsplib/pull/226?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None) Report
> Merging [#226](https://codecov.io/gh/bluenviron/gortsplib/pull/226?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None) (5452b14) into [main](https://codecov.io/gh/bluenviron/gortsplib/commit/2fbba142cc41772001dd02b9d6109a1c992cafd6?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None) (2fbba14) will **decrease** coverage by `0.02%`.
> The diff coverage is `86.11%`.

> :exclamation: Current head 5452b14 differs from pull request most recent head 44a32a3. Consider uploading reports for the commit 44a32a3 to get more accurate results

:mega: This organization is not using Codecov’s [GitHub App Integration](https://github.com/apps/codecov). We recommend you install it so Codecov can continue to function properly for your repositories. [Learn more](https://about.codecov.io/blog/codecov-is-updating-its-github-integration/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None)

```diff
@@            Coverage Diff             @@
##             main     #226      +/-   ##
==========================================
- Coverage   85.68%   85.66%   -0.02%     
==========================================
  Files          81       81              
  Lines        8711     8720       +9     
==========================================
+ Hits         7464     7470       +6     
  Misses        968      968              
- Partials      279      282       +3     
```


| [Impacted Files](https://codecov.io/gh/bluenviron/gortsplib/pull/226?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None) | Coverage Δ | |
|---|---|---|
| [pkg/media/medias.go](https://codecov.io/gh/bluenviron/gortsplib/pull/226?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None#diff-cGtnL21lZGlhL21lZGlhcy5nbw==) | `91.83% <ø> (+6.93%)` | :arrow_up: |
| [server\_session.go](https://codecov.io/gh/bluenviron/gortsplib/pull/226?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None#diff-c2VydmVyX3Nlc3Npb24uZ28=) | `76.75% <75.00%> (-0.42%)` | :arrow_down: |
| [client.go](https://codecov.io/gh/bluenviron/gortsplib/pull/226?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None#diff-Y2xpZW50Lmdv) | `73.88% <100.00%> (+0.09%)` | :arrow_up: |
| [server\_conn.go](https://codecov.io/gh/bluenviron/gortsplib/pull/226?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None#diff-c2VydmVyX2Nvbm4uZ28=) | `90.79% <100.00%> (+0.06%)` | :arrow_up: |
| [server\_stream.go](https://codecov.io/gh/bluenviron/gortsplib/pull/226?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None#diff-c2VydmVyX3N0cmVhbS5nbw==) | `83.87% <100.00%> (ø)` | |
| [server\_stream\_media.go](https://codecov.io/gh/bluenviron/gortsplib/pull/226?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None#diff-c2VydmVyX3N0cmVhbV9tZWRpYS5nbw==) | `82.85% <100.00%> (ø)` | |

... and [1 file with indirect coverage changes](https://codecov.io/gh/bluenviron/gortsplib/pull/226/indirect-changes?src=pr&el=tree-more&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None)

:mega: We’re building smart automated test selection to slash your CI/CD build times. [Learn more](https://about.codecov.io/iterative-testing/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None)


Patch:
diff --git a/client.go b/client.go
index 215f00fd..cd55623d 100644
--- a/client.go
+++ b/client.go
@@ -70,6 +70,12 @@ func findBaseURL(sd *sdp.SessionDescription, res *base.Response, u *url.URL) (*u
 	return u, nil
 }
 
+func resetMediaControls(ms media.Medias) {
+	for i, media := range ms {
+		media.Control = "trackID=" + strconv.FormatInt(int64(i), 10)
+	}
+}
+
 type clientState int
 
 const (
@@ -1118,7 +1124,7 @@ func (c *Client) doAnnounce(u *url.URL, medias media.Medias) (*base.Response, er
 		return nil, err
 	}
 
-	medias.SetControls()
+	resetMediaControls(medias)
 
 	byts, err := medias.Marshal(false).Marshal()
 	if err != nil {
diff --git a/go.mod b/go.mod
index ba5c09d5..0e383eef 100644
--- a/go.mod
+++ b/go.mod
@@ -10,7 +10,7 @@ require (
 	github.com/pion/rtp v0.0.0-20230107162714-c3ea6851e25b
 	github.com/pion/sdp/v3 v3.0.6
 	github.com/stretchr/testify v1.8.2
-	golang.org/x/net v0.8.0
+	golang.org/x/net v0.9.0
 )
 
 require (
@@ -18,6 +18,6 @@ require (
 	github.com/davecgh/go-spew v1.1.1 // indirect
 	github.com/pion/randutil v0.1.0 // indirect
 	github.com/pmezard/go-difflib v1.0.0 // indirect
-	golang.org/x/sys v0.6.0 // indirect
+	golang.org/x/sys v0.7.0 // indirect
 	gopkg.in/yaml.v3 v3.0.1 // indirect
 )
diff --git a/go.sum b/go.sum
index 0de66cca..824ddd38 100644
--- a/go.sum
+++ b/go.sum
@@ -28,10 +28,10 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
 github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
 github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
 github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
-golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ=
-golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
-golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ=
-golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/net v0.9.0 h1:aWJ/m6xSmxWBx+V0XRHTlrYrPG56jKsLdTFmsSsCzOM=
+golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
+golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU=
+golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
diff --git a/pkg/media/medias.go b/pkg/media/medias.go
index 5cdc88fd..a8a59ae6 100644
--- a/pkg/media/medias.go
+++ b/pkg/media/medias.go
@@ -3,7 +3,6 @@ package media
 import (
 	"fmt"
 
-	"github.com/google/uuid"
 	psdp "github.com/pion/sdp/v3"
 
 	"github.com/bluenviron/gortsplib/v3/pkg/sdp"
@@ -64,13 +63,6 @@ func (ms Medias) Marshal(multicast bool) *sdp.SessionDescription {
 	return sout
 }
 
-// SetControls sets the control attribute of all medias in the list.
-func (ms Medias) SetControls() {
-	for _, media := range ms {
-		media.Control = "mediaUUID=" + uuid.New().String()
-	}
-}
-
 // FindFormat finds a certain format among all the formats in all the medias.
 // If the format is found, it is inserted into forma, and its media is returned.
 func (ms Medias) FindFormat(forma interface{}) *Media {
diff --git a/server_conn.go b/server_conn.go
index d4514e4a..5cd7dc0f 100644
--- a/server_conn.go
+++ b/server_conn.go
@@ -6,6 +6,7 @@ import (
 	"errors"
 	"net"
 	gourl "net/url"
+	"strconv"
 	"strings"
 	"sync/atomic"
 	"time"
@@ -36,12 +37,15 @@ func mediasForSDP(
 			Type: medi.Type,
 			// Direction: skipped for the moment
 			Formats: medi.Formats,
-			Control: "mediaUUID=" + streamMedias[medi].uuid.String(),
+			// we have to use trackID=number in order to support clients
+			// like the Grandstream GXV3500.
+			Control: "trackID=" + strconv.FormatInt(int64(i), 10),
 		}
 
 		// always use the absolute URL of the track as control attribute, in order
-		// to support GStreamer's rtspsrc. When a relative control is used, GStreamer
-		// puts it between path and query, instead of appending it to the URL.
+		// 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()
 
diff --git a/server_session.go b/server_session.go
index 13db162e..cf40ec40 100644
--- a/server_session.go
+++ b/server_session.go
@@ -4,6 +4,7 @@ import (
 	"context"
 	"fmt"
 	"net"
+	"strconv"
 	"strings"
 	"sync/atomic"
 	"time"
@@ -35,7 +36,7 @@ func serverParseURLForPlay(u *url.URL) (string, string, string, error) {
 		return "", "", "", liberrors.ErrServerInvalidPath{}
 	}
 
-	i := stringsReverseIndex(pathAndQuery, "/mediaUUID=")
+	i := stringsReverseIndex(pathAndQuery, "/trackID=")
 	if i < 0 {
 		if !strings.HasSuffix(pathAndQuery, "/") {
 			return "", "", "", fmt.Errorf("path of a SETUP request must end with a slash. " +
@@ -47,10 +48,10 @@ func serverParseURLForPlay(u *url.URL) (string, string, string, error) {
 		return path, query, "", nil
 	}
 
-	var mediaUUID string
-	pathAndQuery, mediaUUID = pathAndQuery[:i], pathAndQuery[i+len("/mediaUUID="):]
+	var trackID string
+	pathAndQuery, trackID = pathAndQuery[:i], pathAndQuery[i+len("/trackID="):]
 	path, query := url.PathSplitQuery(pathAndQuery)
-	return path, query, mediaUUID, nil
+	return path, query, trackID, nil
 }
 
 func findMediaByURL(medias media.Medias, baseURL *url.URL, u *url.URL) *media.Media {
@@ -64,17 +65,22 @@ func findMediaByURL(medias media.Medias, baseURL *url.URL, u *url.URL) *media.Me
 	return nil
 }
 
-func findMediaByUUID(st *ServerStream, uuid string) *media.Media {
-	if uuid == "" {
+func findMediaByTrackID(st *ServerStream, trackID string) *media.Media {
+	if trackID == "" {
 		return st.medias[0]
 	}
 
-	for _, sm := range st.streamMedias {
-		if sm.uuid.String() == uuid {
-			return sm.media
-		}
+	tmp, err := strconv.ParseInt(trackID, 10, 64)
+	if err != nil {
+		return nil
 	}
-	return nil
+	id := int(tmp)
+
+	if len(st.medias) <= id {
+		return nil
+	}
+
+	return st.medias[id]
 }
 
 func findFirstSupportedTransportHeader(s *Server, tsh headers.Transports) *headers.Transport {
@@ -634,11 +640,11 @@ func (ss *ServerSession) handleRequest(sc *ServerConn, req *base.Request) (*base
 
 		var path string
 		var query string
-		var mediaUUID string
+		var trackID string
 		switch ss.state {
 		case ServerSessionStateInitial, ServerSessionStatePrePlay: // play
 			var err error
-			path, query, mediaUUID, err = serverParseURLForPlay(req.URL)
+			path, query, trackID, err = serverParseURLForPlay(req.URL)
 			if err != nil {
 				return &base.Response{
 					StatusCode: base.StatusBadRequest,
@@ -720,7 +726,7 @@ func (ss *ServerSession) handleRequest(sc *ServerConn, req *base.Request) (*base
 		var medi *media.Media
 		switch ss.state {
 		case ServerSessionStateInitial, ServerSessionStatePrePlay: // play
-			medi = findMediaByUUID(stream, mediaUUID)
+			medi = findMediaByTrackID(stream, trackID)
 		default: // record
 			baseURL := &url.URL{
 				Scheme:   req.URL.Scheme,
@@ -921,7 +927,8 @@ func (ss *ServerSession) handleRequest(sc *ServerConn, req *base.Request) (*base
 				entry.URL = (&url.URL{
 					Scheme: req.URL.Scheme,
 					Host:   req.URL.Host,
-					Path:   *ss.setuppedPath + "/mediaUUID=" + ss.setuppedStream.streamMedias[sm.media].uuid.String(),
+					Path: *ss.setuppedPath + "/trackID=" +
+						strconv.FormatInt(int64(ss.setuppedStream.streamMedias[sm.media].trackID), 10),
 				}).String()
 				ri = append(ri, entry)
 			}
diff --git a/server_stream.go b/server_stream.go
index 98d09f3d..199a4e50 100644
--- a/server_stream.go
+++ b/server_stream.go
@@ -38,8 +38,8 @@ func NewServerStream(medias media.Medias) *ServerStream {
 	}
 
 	st.streamMedias = make(map[*media.Media]*serverStreamMedia, len(medias))
-	for _, medi := range medias {
-		st.streamMedias[medi] = newServerStreamMedia(st, medi)
+	for i, medi := range medias {
+		st.streamMedias[medi] = newServerStreamMedia(st, medi, i)
 	}
 
 	return st
diff --git a/server_stream_media.go b/server_stream_media.go
index 33fef74b..177148de 100644
--- a/server_stream_media.go
+++ b/server_stream_media.go
@@ -3,7 +3,6 @@ package gortsplib
 import (
 	"time"
 
-	"github.com/google/uuid"
 	"github.com/pion/rtcp"
 	"github.com/pion/rtp"
 
@@ -12,16 +11,16 @@ import (
 )
 
 type serverStreamMedia struct {
-	uuid            uuid.UUID
+	trackID         int
 	media           *media.Media
 	formats         map[uint8]*serverStreamFormat
 	multicastWriter *serverMulticastWriter
 }
 
-func newServerStreamMedia(st *ServerStream, medi *media.Media) *serverStreamMedia {
+func newServerStreamMedia(st *ServerStream, medi *media.Media, trackID int) *serverStreamMedia {
 	sm := &serverStreamMedia{
-		uuid:  uuid.New(),
-		media: medi,
+		trackID: trackID,
+		media:   medi,
 	}
 
 	sm.formats = make(map[uint8]*serverStreamFormat)


Test patch:
diff --git a/client_play_test.go b/client_play_test.go
index 6fe2efda..1fcd6814 100644
--- a/client_play_test.go
+++ b/client_play_test.go
@@ -139,7 +139,7 @@ func TestClientPlayFormats(t *testing.T) {
 		require.Equal(t, mustParseURL("rtsp://localhost:8554/teststream"), req.URL)
 
 		medias := media.Medias{media1, media2, media3}
-		medias.SetControls()
+		resetMediaControls(medias)
 
 		err = conn.WriteResponse(&base.Response{
 			StatusCode: base.StatusOK,
@@ -284,7 +284,7 @@ func TestClientPlay(t *testing.T) {
 						Formats: []formats.Format{forma},
 					},
 				}
-				medias.SetControls()
+				resetMediaControls(medias)
 
 				err = conn.WriteResponse(&base.Response{
 					StatusCode: base.StatusOK,
@@ -558,7 +558,7 @@ func TestClientPlayPartial(t *testing.T) {
 				Formats: []formats.Format{forma},
 			},
 		}
-		medias.SetControls()
+		resetMediaControls(medias)
 
 		err = conn.WriteResponse(&base.Response{
 			StatusCode: base.StatusOK,
@@ -701,7 +701,7 @@ func TestClientPlayContentBase(t *testing.T) {
 				require.Equal(t, mustParseURL("rtsp://localhost:8554/teststream"), req.URL)
 
 				medias := media.Medias{testH264Media}
-				medias.SetControls()
+				resetMediaControls(medias)
 
 				switch ca {
 				case "absent":
@@ -831,7 +831,7 @@ func TestClientPlayAnyPort(t *testing.T) {
 				require.Equal(t, base.Describe, req.Method)
 
 				medias := media.Medias{testH264Media}
-				medias.SetControls()
+				resetMediaControls(medias)
 
 				err = conn.WriteResponse(&base.Response{
 					StatusCode: base.StatusOK,
@@ -985,7 +985,7 @@ func TestClientPlayAutomaticProtocol(t *testing.T) {
 			require.Equal(t, base.Describe, req.Method)
 
 			medias := media.Medias{testH264Media}
-			medias.SetControls()
+			resetMediaControls(medias)
 
 			err = conn.WriteResponse(&base.Response{
 				StatusCode: base.StatusOK,
@@ -1078,7 +1078,7 @@ func TestClientPlayAutomaticProtocol(t *testing.T) {
 			defer close(serverDone)
 
 			medias := media.Medias{testH264Media}
-			medias.SetControls()
+			resetMediaControls(medias)
 
 			func() {
 				nconn, err := l.Accept()
@@ -1258,7 +1258,7 @@ func TestClientPlayAutomaticProtocol(t *testing.T) {
 			defer close(serverDone)
 
 			medias := media.Medias{testH264Media}
-			medias.SetControls()
+			resetMediaControls(medias)
 
 			func() {
 				nconn, err := l.Accept()
@@ -1524,7 +1524,7 @@ func TestClientPlayDifferentInterleavedIDs(t *testing.T) {
 		require.Equal(t, mustParseURL("rtsp://localhost:8554/teststream"), req.URL)
 
 		medias := media.Medias{testH264Media}
-		medias.SetControls()
+		resetMediaControls(medias)
 
 		err = conn.WriteResponse(&base.Response{
 			StatusCode: base.StatusOK,
@@ -1719,7 +1719,7 @@ func TestClientPlayRedirect(t *testing.T) {
 					}
 
 					medias := media.Medias{testH264Media}
-					medias.SetControls()
+					resetMediaControls(medias)
 
 					err = conn.WriteResponse(&base.Response{
 						StatusCode: base.StatusOK,
@@ -1880,7 +1880,7 @@ func TestClientPlayPause(t *testing.T) {
 				require.Equal(t, base.Describe, req.Method)
 
 				medias := media.Medias{testH264Media}
-				medias.SetControls()
+				resetMediaControls(medias)
 
 				err = conn.WriteResponse(&base.Response{
 					StatusCode: base.StatusOK,
@@ -2048,7 +2048,7 @@ func TestClientPlayRTCPReport(t *testing.T) {
 		require.Equal(t, base.Describe, req.Method)
 
 		medias := media.Medias{testH264Media}
-		medias.SetControls()
+		resetMediaControls(medias)
 
 		err = conn.WriteResponse(&base.Response{
 			StatusCode: base.StatusOK,
@@ -2226,7 +2226,7 @@ func TestClientPlayErrorTimeout(t *testing.T) {
 				require.Equal(t, base.Describe, req.Method)
 
 				medias := media.Medias{testH264Media}
-				medias.SetControls()
+				resetMediaControls(medias)
 
 				err = conn.WriteResponse(&base.Response{
 					StatusCode: base.StatusOK,
@@ -2372,7 +2372,7 @@ func TestClientPlayIgnoreTCPInvalidMedia(t *testing.T) {
 		require.Equal(t, base.Describe, req.Method)
 
 		medias := media.Medias{testH264Media}
-		medias.SetControls()
+		resetMediaControls(medias)
 
 		err = conn.WriteResponse(&base.Response{
 			StatusCode: base.StatusOK,
@@ -2495,7 +2495,7 @@ func TestClientPlaySeek(t *testing.T) {
 		require.Equal(t, base.Describe, req.Method)
 
 		medias := media.Medias{testH264Media}
-		medias.SetControls()
+		resetMediaControls(medias)
 
 		err = conn.WriteResponse(&base.Response{
 			StatusCode: base.StatusOK,
@@ -2659,7 +2659,7 @@ func TestClientPlayKeepaliveFromSession(t *testing.T) {
 		require.Equal(t, base.Describe, req.Method)
 
 		medias := media.Medias{testH264Media}
-		medias.SetControls()
+		resetMediaControls(medias)
 
 		err = conn.WriteResponse(&base.Response{
 			StatusCode: base.StatusOK,
@@ -2782,7 +2782,7 @@ func TestClientPlayDifferentSource(t *testing.T) {
 		require.Equal(t, mustParseURL("rtsp://localhost:8554/test/stream?param=value"), req.URL)
 
 		medias := media.Medias{testH264Media}
-		medias.SetControls()
+		resetMediaControls(medias)
 
 		err = conn.WriteResponse(&base.Response{
 			StatusCode: base.StatusOK,
@@ -2935,7 +2935,7 @@ func TestClientPlayDecodeErrors(t *testing.T) {
 						RTPMap:     "private/90000",
 					}},
 				}}
-				medias.SetControls()
+				resetMediaControls(medias)
 
 				err = conn.WriteResponse(&base.Response{
 					StatusCode: base.StatusOK,
diff --git a/client_test.go b/client_test.go
index b2043331..a8143fbf 100644
--- a/client_test.go
+++ b/client_test.go
@@ -106,7 +106,7 @@ func TestClientSession(t *testing.T) {
 		require.Equal(t, base.HeaderValue{"123456"}, req.Header["Session"])
 
 		medias := media.Medias{testH264Media}
-		medias.SetControls()
+		resetMediaControls(medias)
 
 		err = conn.WriteResponse(&base.Response{
 			StatusCode: base.StatusOK,
@@ -183,7 +183,7 @@ func TestClientAuth(t *testing.T) {
 		require.NoError(t, err)
 
 		medias := media.Medias{testH264Media}
-		medias.SetControls()
+		resetMediaControls(medias)
 
 		err = conn.WriteResponse(&base.Response{
 			StatusCode: base.StatusOK,
diff --git a/server_play_test.go b/server_play_test.go
index b38ba774..932e60c1 100644
--- a/server_play_test.go
+++ b/server_play_test.go
@@ -54,7 +54,7 @@ func multicastCapableIP(t *testing.T) string {
 
 func relativeControlAttribute(md *psdp.MediaDescription) string {
 	v, _ := md.Attribute("control")
-	i := strings.Index(v, "mediaUUID=")
+	i := strings.Index(v, "trackID=")
 	return v[i:]
 }
 
@@ -2186,7 +2186,7 @@ func TestServerPlayAdditionalInfos(t *testing.T) {
 	})
 
 	rtpInfo, ssrcs := getInfos()
-	require.True(t, strings.HasPrefix(mustParseURL((*rtpInfo)[0].URL).Path, "/teststream/mediaUUID="))
+	require.True(t, strings.HasPrefix(mustParseURL((*rtpInfo)[0].URL).Path, "/teststream/trackID="))
 	require.Equal(t, &headers.RTPInfo{
 		&headers.RTPInfoEntry{
 			URL: (&url.URL{
@@ -2221,7 +2221,7 @@ func TestServerPlayAdditionalInfos(t *testing.T) {
 	})
 
 	rtpInfo, ssrcs = getInfos()
-	require.True(t, strings.HasPrefix(mustParseURL((*rtpInfo)[0].URL).Path, "/teststream/mediaUUID="))
+	require.True(t, strings.HasPrefix(mustParseURL((*rtpInfo)[0].URL).Path, "/teststream/trackID="))
 	require.Equal(t, &headers.RTPInfo{
 		&headers.RTPInfoEntry{
 			URL: (&url.URL{
diff --git a/server_record_test.go b/server_record_test.go
index 9fdd99aa..434bf94c 100644
--- a/server_record_test.go
+++ b/server_record_test.go
@@ -337,7 +337,7 @@ func TestServerRecordErrorSetupMediaTwice(t *testing.T) {
 	conn := conn.NewConn(nconn)
 
 	medias := media.Medias{testH264Media}
-	medias.SetControls()
+	resetMediaControls(medias)
 
 	res, err := writeReqReadRes(conn, base.Request{
 		Method: base.Announce,
@@ -457,7 +457,7 @@ func TestServerRecordErrorRecordPartialMedias(t *testing.T) {
 			Formats: []formats.Format{forma},
 		},
 	}
-	medias.SetControls()
+	resetMediaControls(medias)
 
 	res, err := writeReqReadRes(conn, base.Request{
 		Method: base.Announce,
@@ -630,7 +630,7 @@ func TestServerRecord(t *testing.T) {
 					}},
 				},
 			}
-			medias.SetControls()
+			resetMediaControls(medias)
 
 			res, err := writeReqReadRes(conn, base.Request{
 				Method: base.Announce,
@@ -834,7 +834,7 @@ func TestServerRecordErrorInvalidProtocol(t *testing.T) {
 	conn := conn.NewConn(nconn)
 
 	medias := media.Medias{testH264Media}
-	medias.SetControls()
+	resetMediaControls(medias)
 
 	res, err := writeReqReadRes(conn, base.Request{
 		Method: base.Announce,
@@ -935,7 +935,7 @@ func TestServerRecordRTCPReport(t *testing.T) {
 	conn := conn.NewConn(nconn)
 
 	medias := media.Medias{testH264Media}
-	medias.SetControls()
+	resetMediaControls(medias)
 
 	res, err := writeReqReadRes(conn, base.Request{
 		Method: base.Announce,
@@ -1110,7 +1110,7 @@ func TestServerRecordTimeout(t *testing.T) {
 			conn := conn.NewConn(nconn)
 
 			medias := media.Medias{testH264Media}
-			medias.SetControls()
+			resetMediaControls(medias)
 
 			res, err := writeReqReadRes(conn, base.Request{
 				Method: base.Announce,
@@ -1233,7 +1233,7 @@ func TestServerRecordWithoutTeardown(t *testing.T) {
 			conn := conn.NewConn(nconn)
 
 			medias := media.Medias{testH264Media}
-			medias.SetControls()
+			resetMediaControls(medias)
 
 			res, err := writeReqReadRes(conn, base.Request{
 				Method: base.Announce,
@@ -1346,7 +1346,7 @@ func TestServerRecordUDPChangeConn(t *testing.T) {
 		conn := conn.NewConn(nconn)
 
 		medias := media.Medias{testH264Media}
-		medias.SetControls()
+		resetMediaControls(medias)
 
 		res, err := writeReqReadRes(conn, base.Request{
 			Method: base.Announce,
@@ -1504,7 +1504,7 @@ func TestServerRecordDecodeErrors(t *testing.T) {
 					RTPMap:     "private/90000",
 				}},
 			}}
-			medias.SetControls()
+			resetMediaControls(medias)
 
 			res, err := writeReqReadRes(conn, base.Request{
 				Method: base.Announce,