Repository: bluenviron/gortsplib
Pull request #728 (2025-03-23 14:47:47)

make ServerStream return an error if initialized before Server (#719)

codecov[bot]: ## [Codecov](https://app.codecov.io/gh/bluenviron/gortsplib/pull/728?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=bluenviron) Report
Attention: Patch coverage is `62.50000%` with `3 lines` in your changes missing coverage. Please review.
> Project coverage is 82.14%. Comparing base [(`fa94080`)](https://app.codecov.io/gh/bluenviron/gortsplib/commit/fa94080e84a863236942237cfe73b4bfaa5b1bf3?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=bluenviron) to head [(`3073264`)](https://app.codecov.io/gh/bluenviron/gortsplib/commit/30732641f1c20e0f0d50bf810d397f879d00d277?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=bluenviron).

| [Files with missing lines](https://app.codecov.io/gh/bluenviron/gortsplib/pull/728?dropdown=coverage&src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=bluenviron) | Patch % | Lines |
|---|---|---|
| [server\_stream.go](https://app.codecov.io/gh/bluenviron/gortsplib/pull/728?src=pr&el=tree&filepath=server_stream.go&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=bluenviron#diff-c2VydmVyX3N0cmVhbS5nbw==) | 62.50% | [3 Missing :warning: ](https://app.codecov.io/gh/bluenviron/gortsplib/pull/728?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=bluenviron) |

<details><summary>Additional details and impacted files</summary>


```diff
@@            Coverage Diff             @@
##             main     #728      +/-   ##
==========================================
- Coverage   82.15%   82.14%   -0.01%     
==========================================
  Files         121      121              
  Lines       12533    12539       +6     
==========================================
+ Hits        10296    10300       +4     
- Misses       1823     1825       +2     
  Partials      414      414              
```

</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/bluenviron/gortsplib/pull/728?dropdown=coverage&src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=bluenviron).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=bluenviron).

<details><summary> :rocket: New features to boost your workflow: </summary>

- :snowflake: [Test Analytics](https://docs.codecov.com/docs/test-analytics): Detect flaky tests, report on failures, and find test suite problems.
</details>

Patch:
diff --git a/examples/proxy/server.go b/examples/proxy/server.go
index 32334fb6..d7ee5235 100644
--- a/examples/proxy/server.go
+++ b/examples/proxy/server.go
@@ -102,7 +102,10 @@ func (s *server) setStreamReady(desc *description.Session) *gortsplib.ServerStre
 		Server: s.s,
 		Desc:   desc,
 	}
-	s.stream.Initialize()
+	err := s.stream.Initialize()
+	if err != nil {
+		panic(err)
+	}
 	return s.stream
 }
 
diff --git a/examples/server-auth/main.go b/examples/server-auth/main.go
index fb1b4b33..b15901c9 100644
--- a/examples/server-auth/main.go
+++ b/examples/server-auth/main.go
@@ -121,7 +121,10 @@ func (sh *serverHandler) OnAnnounce(ctx *gortsplib.ServerHandlerOnAnnounceCtx) (
 		Server: sh.s,
 		Desc:   ctx.Description,
 	}
-	sh.stream.Initialize()
+	err := sh.stream.Initialize()
+	if err != nil {
+		panic(err)
+	}
 	sh.publisher = ctx.Session
 
 	return &base.Response{
diff --git a/examples/server-tls/main.go b/examples/server-tls/main.go
index cb62d501..751f1d83 100644
--- a/examples/server-tls/main.go
+++ b/examples/server-tls/main.go
@@ -93,7 +93,10 @@ func (sh *serverHandler) OnAnnounce(ctx *gortsplib.ServerHandlerOnAnnounceCtx) (
 		Server: sh.s,
 		Desc:   ctx.Description,
 	}
-	sh.stream.Initialize()
+	err := sh.stream.Initialize()
+	if err != nil {
+		panic(err)
+	}
 	sh.publisher = ctx.Session
 
 	return &base.Response{
diff --git a/examples/server/main.go b/examples/server/main.go
index 270edfdc..2ecca102 100644
--- a/examples/server/main.go
+++ b/examples/server/main.go
@@ -92,7 +92,10 @@ func (sh *serverHandler) OnAnnounce(ctx *gortsplib.ServerHandlerOnAnnounceCtx) (
 		Server: sh.s,
 		Desc:   ctx.Description,
 	}
-	sh.stream.Initialize()
+	err := sh.stream.Initialize()
+	if err != nil {
+		panic(err)
+	}
 	sh.publisher = ctx.Session
 
 	return &base.Response{
diff --git a/server_stream.go b/server_stream.go
index b10c43f0..574d112d 100644
--- a/server_stream.go
+++ b/server_stream.go
@@ -1,6 +1,7 @@
 package gortsplib
 
 import (
+	"fmt"
 	"sync"
 	"sync/atomic"
 	"time"
@@ -32,7 +33,10 @@ func NewServerStream(s *Server, desc *description.Session) *ServerStream {
 		Server: s,
 		Desc:   desc,
 	}
-	st.Initialize()
+	err := st.Initialize()
+	if err != nil {
+		panic(err)
+	}
 	return st
 }
 
@@ -54,7 +58,11 @@ type ServerStream struct {
 }
 
 // Initialize initializes a ServerStream.
-func (st *ServerStream) Initialize() {
+func (st *ServerStream) Initialize() error {
+	if st.Server == nil || st.Server.sessions == nil {
+		return fmt.Errorf("server not present or not initialized")
+	}
+
 	st.readers = make(map[*ServerSession]struct{})
 	st.activeUnicastReaders = make(map[*ServerSession]struct{})
 
@@ -68,6 +76,8 @@ func (st *ServerStream) Initialize() {
 		sm.initialize()
 		st.medias[medi] = sm
 	}
+
+	return nil
 }
 
 // Close closes a ServerStream.


Test patch:
diff --git a/internal/highleveltests/server_test.go b/internal/highleveltests/server_test.go
index 9507e29a..0980230f 100644
--- a/internal/highleveltests/server_test.go
+++ b/internal/highleveltests/server_test.go
@@ -332,7 +332,8 @@ func TestServerRecordRead(t *testing.T) {
 							Server: s,
 							Desc:   ctx.Description,
 						}
-						stream.Initialize()
+						err := stream.Initialize()
+						require.NoError(t, err)
 						publisher = ctx.Session
 
 						return &base.Response{
diff --git a/server_play_test.go b/server_play_test.go
index 108844c8..e87ba4d0 100644
--- a/server_play_test.go
+++ b/server_play_test.go
@@ -302,7 +302,8 @@ func TestServerPlayPath(t *testing.T) {
 					},
 				},
 			}
-			stream.Initialize()
+			err = stream.Initialize()
+			require.NoError(t, err)
 			defer stream.Close()
 
 			nconn, err := net.Dial("tcp", "localhost:8554")
@@ -388,7 +389,8 @@ func TestServerPlaySetupErrors(t *testing.T) {
 				Server: s,
 				Desc:   &description.Session{Medias: []*description.Media{testH264Media}},
 			}
-			stream.Initialize()
+			err = stream.Initialize()
+			require.NoError(t, err)
 
 			if ca == "closed stream" {
 				stream.Close()
@@ -560,7 +562,8 @@ func TestServerPlaySetupErrorSameUDPPortsAndIP(t *testing.T) {
 		Server: s,
 		Desc:   &description.Session{Medias: []*description.Media{testH264Media}},
 	}
-	stream.Initialize()
+	err = stream.Initialize()
+	require.NoError(t, err)
 	defer stream.Close()
 
 	for i := 0; i < 2; i++ {
@@ -740,7 +743,8 @@ func TestServerPlay(t *testing.T) {
 				Server: s,
 				Desc:   &description.Session{Medias: []*description.Media{testH264Media}},
 			}
-			stream.Initialize()
+			err = stream.Initialize()
+			require.NoError(t, err)
 			defer stream.Close()
 
 			nconn, err := net.Dial("tcp", listenIP+":8554")
@@ -1038,7 +1042,8 @@ func TestServerPlaySocketError(t *testing.T) {
 				Server: s,
 				Desc:   &description.Session{Medias: []*description.Media{testH264Media}},
 			}
-			stream.Initialize()
+			err = stream.Initialize()
+			require.NoError(t, err)
 
 			func() {
 				nconn, err := net.Dial("tcp", listenIP+":8554")
@@ -1208,7 +1213,8 @@ func TestServerPlayDecodeErrors(t *testing.T) {
 				Server: s,
 				Desc:   &description.Session{Medias: []*description.Media{testH264Media}},
 			}
-			stream.Initialize()
+			err = stream.Initialize()
+			require.NoError(t, err)
 			defer stream.Close()
 
 			nconn, err := net.Dial("tcp", "localhost:8554")
@@ -1330,7 +1336,8 @@ func TestServerPlayRTCPReport(t *testing.T) {
 				Server: s,
 				Desc:   &description.Session{Medias: []*description.Media{testH264Media}},
 			}
-			stream.Initialize()
+			err = stream.Initialize()
+			require.NoError(t, err)
 			defer stream.Close()
 
 			nconn, err := net.Dial("tcp", "localhost:8554")
@@ -1453,7 +1460,8 @@ func TestServerPlayVLCMulticast(t *testing.T) {
 		Server: s,
 		Desc:   &description.Session{Medias: []*description.Media{testH264Media}},
 	}
-	stream.Initialize()
+	err = stream.Initialize()
+	require.NoError(t, err)
 	defer stream.Close()
 
 	nconn, err := net.Dial("tcp", listenIP+":8554")
@@ -1538,7 +1546,8 @@ func TestServerPlayTCPResponseBeforeFrames(t *testing.T) {
 		Server: s,
 		Desc:   &description.Session{Medias: []*description.Media{testH264Media}},
 	}
-	stream.Initialize()
+	err = stream.Initialize()
+	require.NoError(t, err)
 	defer stream.Close()
 
 	nconn, err := net.Dial("tcp", "localhost:8554")
@@ -1629,7 +1638,8 @@ func TestServerPlayPause(t *testing.T) {
 		Server: s,
 		Desc:   &description.Session{Medias: []*description.Media{testH264Media}},
 	}
-	stream.Initialize()
+	err = stream.Initialize()
+	require.NoError(t, err)
 	defer stream.Close()
 
 	nconn, err := net.Dial("tcp", "localhost:8554")
@@ -1726,7 +1736,8 @@ func TestServerPlayPlayPausePausePlay(t *testing.T) {
 				Server: s,
 				Desc:   &description.Session{Medias: []*description.Media{testH264Media}},
 			}
-			stream.Initialize()
+			err = stream.Initialize()
+			require.NoError(t, err)
 			defer stream.Close()
 
 			nconn, err := net.Dial("tcp", "localhost:8554")
@@ -1813,7 +1824,8 @@ func TestServerPlayTimeout(t *testing.T) {
 				Server: s,
 				Desc:   &description.Session{Medias: []*description.Media{testH264Media}},
 			}
-			stream.Initialize()
+			err = stream.Initialize()
+			require.NoError(t, err)
 			defer stream.Close()
 
 			nconn, err := net.Dial("tcp", "localhost:8554")
@@ -1903,7 +1915,8 @@ func TestServerPlayWithoutTeardown(t *testing.T) {
 				Server: s,
 				Desc:   &description.Session{Medias: []*description.Media{testH264Media}},
 			}
-			stream.Initialize()
+			err = stream.Initialize()
+			require.NoError(t, err)
 			defer stream.Close()
 
 			nconn, err := net.Dial("tcp", "localhost:8554")
@@ -1979,7 +1992,8 @@ func TestServerPlayUDPChangeConn(t *testing.T) {
 		Server: s,
 		Desc:   &description.Session{Medias: []*description.Media{testH264Media}},
 	}
-	stream.Initialize()
+	err = stream.Initialize()
+	require.NoError(t, err)
 	defer stream.Close()
 
 	sxID := ""
@@ -2067,7 +2081,8 @@ func TestServerPlayPartialMedias(t *testing.T) {
 		Server: s,
 		Desc:   &description.Session{Medias: []*description.Media{testH264Media, testH264Media}},
 	}
-	stream.Initialize()
+	err = stream.Initialize()
+	require.NoError(t, err)
 	defer stream.Close()
 
 	nconn, err := net.Dial("tcp", "localhost:8554")
@@ -2188,7 +2203,8 @@ func TestServerPlayAdditionalInfos(t *testing.T) {
 			},
 		},
 	}
-	stream.Initialize()
+	err = stream.Initialize()
+	require.NoError(t, err)
 	defer stream.Close()
 
 	err = stream.WritePacketRTP(stream.Description().Medias[0], &rtp.Packet{
@@ -2318,7 +2334,8 @@ func TestServerPlayNoInterleavedIDs(t *testing.T) {
 			},
 		},
 	}
-	stream.Initialize()
+	err = stream.Initialize()
+	require.NoError(t, err)
 	defer stream.Close()
 
 	nconn, err := net.Dial("tcp", "localhost:8554")
@@ -2392,7 +2409,8 @@ func TestServerPlayStreamStats(t *testing.T) {
 		Server: s,
 		Desc:   &description.Session{Medias: []*description.Media{testH264Media}},
 	}
-	stream.Initialize()
+	err = stream.Initialize()
+	require.NoError(t, err)
 	defer stream.Close()
 
 	for _, transport := range []string{"tcp", "multicast"} {
diff --git a/server_record_test.go b/server_record_test.go
index 800ffb68..e1dc813d 100644
--- a/server_record_test.go
+++ b/server_record_test.go
@@ -297,7 +297,8 @@ func TestServerRecordPath(t *testing.T) {
 							Server: s,
 							Desc:   ctx.Description,
 						}
-						stream.Initialize()
+						err := stream.Initialize()
+						require.NoError(t, err)
 						defer stream.Close()
 
 						return &base.Response{
diff --git a/server_test.go b/server_test.go
index f3045194..4e2a8916 100644
--- a/server_test.go
+++ b/server_test.go
@@ -392,7 +392,8 @@ func TestServerErrorMethodNotImplemented(t *testing.T) {
 				Server: s,
 				Desc:   &description.Session{Medias: []*description.Media{testH264Media}},
 			}
-			stream.Initialize()
+			err = stream.Initialize()
+			require.NoError(t, err)
 			defer stream.Close()
 
 			h.stream = stream
@@ -489,7 +490,8 @@ func TestServerErrorTCPTwoConnOneSession(t *testing.T) {
 		Server: s,
 		Desc:   &description.Session{Medias: []*description.Media{testH264Media}},
 	}
-	stream.Initialize()
+	err = stream.Initialize()
+	require.NoError(t, err)
 	defer stream.Close()
 
 	nconn1, err := net.Dial("tcp", "localhost:8554")
@@ -574,7 +576,8 @@ func TestServerErrorTCPOneConnTwoSessions(t *testing.T) {
 		Server: s,
 		Desc:   &description.Session{Medias: []*description.Media{testH264Media}},
 	}
-	stream.Initialize()
+	err = stream.Initialize()
+	require.NoError(t, err)
 	defer stream.Close()
 
 	nconn, err := net.Dial("tcp", "localhost:8554")
@@ -641,7 +644,8 @@ func TestServerSetupMultipleTransports(t *testing.T) {
 		Server: s,
 		Desc:   &description.Session{Medias: []*description.Media{testH264Media}},
 	}
-	stream.Initialize()
+	err = stream.Initialize()
+	require.NoError(t, err)
 	defer stream.Close()
 
 	nconn, err := net.Dial("tcp", "localhost:8554")
@@ -741,7 +745,8 @@ func TestServerGetSetParameter(t *testing.T) {
 				Server: s,
 				Desc:   &description.Session{Medias: []*description.Media{testH264Media}},
 			}
-			stream.Initialize()
+			err = stream.Initialize()
+			require.NoError(t, err)
 			defer stream.Close()
 
 			nconn, err := net.Dial("tcp", "localhost:8554")
@@ -854,6 +859,146 @@ func TestServerErrorInvalidSession(t *testing.T) {
 	}
 }
 
+func TestServerAuth(t *testing.T) {
+	for _, method := range []string{"all", "basic", "digest_md5", "digest_sha256"} {
+		t.Run(method, func(t *testing.T) {
+			s := &Server{
+				Handler: &testServerHandler{
+					onAnnounce: func(ctx *ServerHandlerOnAnnounceCtx) (*base.Response, error) {
+						ok := ctx.Conn.VerifyCredentials(ctx.Request, "myuser", "mypass")
+						if !ok {
+							return &base.Response{
+								StatusCode: base.StatusUnauthorized,
+							}, liberrors.ErrServerAuth{}
+						}
+
+						return &base.Response{
+							StatusCode: base.StatusOK,
+						}, nil
+					},
+				},
+				RTSPAddress: "localhost:8554",
+				AuthMethods: func() []auth.VerifyMethod {
+					switch method {
+					case "basic":
+						return []auth.VerifyMethod{auth.VerifyMethodBasic}
+
+					case "digest_md5":
+						return []auth.VerifyMethod{auth.VerifyMethodDigestMD5}
+
+					case "digest_sha256":
+						return []auth.VerifyMethod{auth.VerifyMethodDigestSHA256}
+					}
+					return nil
+				}(),
+			}
+
+			err := s.Start()
+			require.NoError(t, err)
+			defer s.Close()
+
+			nconn, err := net.Dial("tcp", "localhost:8554")
+			require.NoError(t, err)
+			defer nconn.Close()
+			conn := conn.NewConn(nconn)
+
+			medias := []*description.Media{testH264Media}
+
+			req := 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: mediasToSDP(medias),
+			}
+
+			res, err := writeReqReadRes(conn, req)
+			require.NoError(t, err)
+			require.Equal(t, base.StatusUnauthorized, res.StatusCode)
+
+			sender := &auth.Sender{
+				WWWAuth: res.Header["WWW-Authenticate"],
+				User:    "myuser",
+				Pass:    "mypass",
+			}
+			err = sender.Initialize()
+			require.NoError(t, err)
+
+			sender.AddAuthorization(&req)
+			res, err = writeReqReadRes(conn, req)
+			require.NoError(t, err)
+			require.Equal(t, base.StatusOK, res.StatusCode)
+		})
+	}
+}
+
+func TestServerAuthFail(t *testing.T) {
+	s := &Server{
+		Handler: &testServerHandler{
+			onConnClose: func(ctx *ServerHandlerOnConnCloseCtx) {
+				require.EqualError(t, ctx.Error, "authentication error")
+			},
+			onAnnounce: func(ctx *ServerHandlerOnAnnounceCtx) (*base.Response, error) {
+				ok := ctx.Conn.VerifyCredentials(ctx.Request, "myuser2", "mypass2")
+				if !ok {
+					return &base.Response{
+						StatusCode: http.StatusUnauthorized,
+					}, liberrors.ErrServerAuth{}
+				}
+
+				return &base.Response{
+					StatusCode: base.StatusOK,
+				}, nil
+			},
+		},
+		RTSPAddress: "localhost:8554",
+	}
+
+	err := s.Start()
+	require.NoError(t, err)
+	defer s.Close()
+
+	nconn, err := net.Dial("tcp", "localhost:8554")
+	require.NoError(t, err)
+	defer nconn.Close()
+	conn := conn.NewConn(nconn)
+
+	medias := []*description.Media{testH264Media}
+
+	req := 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: mediasToSDP(medias),
+	}
+
+	res, err := writeReqReadRes(conn, req)
+	require.NoError(t, err)
+	require.Equal(t, base.StatusUnauthorized, res.StatusCode)
+
+	sender := &auth.Sender{
+		WWWAuth: res.Header["WWW-Authenticate"],
+		User:    "myuser",
+		Pass:    "mypass",
+	}
+	err = sender.Initialize()
+	require.NoError(t, err)
+
+	sender.AddAuthorization(&req)
+
+	res, err = writeReqReadRes(conn, req)
+	require.NoError(t, err)
+	require.Equal(t, base.StatusUnauthorized, res.StatusCode)
+
+	_, err = writeReqReadRes(conn, req)
+	require.Error(t, err)
+}
+
 func TestServerSessionClose(t *testing.T) {
 	var stream *ServerStream
 	var session *ServerSession
@@ -889,7 +1034,8 @@ func TestServerSessionClose(t *testing.T) {
 		Server: s,
 		Desc:   &description.Session{Medias: []*description.Media{testH264Media}},
 	}
-	stream.Initialize()
+	err = stream.Initialize()
+	require.NoError(t, err)
 	defer stream.Close()
 
 	nconn, err := net.Dial("tcp", "localhost:8554")
@@ -968,7 +1114,8 @@ func TestServerSessionAutoClose(t *testing.T) {
 				Server: s,
 				Desc:   &description.Session{Medias: []*description.Media{testH264Media}},
 			}
-			stream.Initialize()
+			err = stream.Initialize()
+			require.NoError(t, err)
 			defer stream.Close()
 
 			nconn, err := net.Dial("tcp", "localhost:8554")
@@ -1034,7 +1181,8 @@ func TestServerSessionTeardown(t *testing.T) {
 		Server: s,
 		Desc:   &description.Session{Medias: []*description.Media{testH264Media}},
 	}
-	stream.Initialize()
+	err = stream.Initialize()
+	require.NoError(t, err)
 	defer stream.Close()
 
 	nconn, err := net.Dial("tcp", "localhost:8554")
@@ -1068,142 +1216,10 @@ func TestServerSessionTeardown(t *testing.T) {
 	require.Equal(t, base.StatusOK, res.StatusCode)
 }
 
-func TestServerAuth(t *testing.T) {
-	for _, method := range []string{"all", "basic", "digest_md5", "digest_sha256"} {
-		t.Run(method, func(t *testing.T) {
-			s := &Server{
-				Handler: &testServerHandler{
-					onAnnounce: func(ctx *ServerHandlerOnAnnounceCtx) (*base.Response, error) {
-						ok := ctx.Conn.VerifyCredentials(ctx.Request, "myuser", "mypass")
-						if !ok {
-							return &base.Response{
-								StatusCode: base.StatusUnauthorized,
-							}, liberrors.ErrServerAuth{}
-						}
-
-						return &base.Response{
-							StatusCode: base.StatusOK,
-						}, nil
-					},
-				},
-				RTSPAddress: "localhost:8554",
-				AuthMethods: func() []auth.VerifyMethod {
-					switch method {
-					case "basic":
-						return []auth.VerifyMethod{auth.VerifyMethodBasic}
-
-					case "digest_md5":
-						return []auth.VerifyMethod{auth.VerifyMethodDigestMD5}
-
-					case "digest_sha256":
-						return []auth.VerifyMethod{auth.VerifyMethodDigestSHA256}
-					}
-					return nil
-				}(),
-			}
-
-			err := s.Start()
-			require.NoError(t, err)
-			defer s.Close()
-
-			nconn, err := net.Dial("tcp", "localhost:8554")
-			require.NoError(t, err)
-			defer nconn.Close()
-			conn := conn.NewConn(nconn)
-
-			medias := []*description.Media{testH264Media}
-
-			req := 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: mediasToSDP(medias),
-			}
-
-			res, err := writeReqReadRes(conn, req)
-			require.NoError(t, err)
-			require.Equal(t, base.StatusUnauthorized, res.StatusCode)
-
-			sender := &auth.Sender{
-				WWWAuth: res.Header["WWW-Authenticate"],
-				User:    "myuser",
-				Pass:    "mypass",
-			}
-			err = sender.Initialize()
-			require.NoError(t, err)
-
-			sender.AddAuthorization(&req)
-			res, err = writeReqReadRes(conn, req)
-			require.NoError(t, err)
-			require.Equal(t, base.StatusOK, res.StatusCode)
-		})
-	}
-}
-
-func TestServerAuthFail(t *testing.T) {
-	s := &Server{
-		Handler: &testServerHandler{
-			onConnClose: func(ctx *ServerHandlerOnConnCloseCtx) {
-				require.EqualError(t, ctx.Error, "authentication error")
-			},
-			onAnnounce: func(ctx *ServerHandlerOnAnnounceCtx) (*base.Response, error) {
-				ok := ctx.Conn.VerifyCredentials(ctx.Request, "myuser2", "mypass2")
-				if !ok {
-					return &base.Response{
-						StatusCode: http.StatusUnauthorized,
-					}, liberrors.ErrServerAuth{}
-				}
-
-				return &base.Response{
-					StatusCode: base.StatusOK,
-				}, nil
-			},
-		},
-		RTSPAddress: "localhost:8554",
-	}
-
-	err := s.Start()
-	require.NoError(t, err)
-	defer s.Close()
+func TestServerStreamErrorNoServer(t *testing.T) {
+	s := &Server{}
 
-	nconn, err := net.Dial("tcp", "localhost:8554")
-	require.NoError(t, err)
-	defer nconn.Close()
-	conn := conn.NewConn(nconn)
-
-	medias := []*description.Media{testH264Media}
-
-	req := 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: mediasToSDP(medias),
-	}
-
-	res, err := writeReqReadRes(conn, req)
-	require.NoError(t, err)
-	require.Equal(t, base.StatusUnauthorized, res.StatusCode)
-
-	sender := &auth.Sender{
-		WWWAuth: res.Header["WWW-Authenticate"],
-		User:    "myuser",
-		Pass:    "mypass",
-	}
-	err = sender.Initialize()
-	require.NoError(t, err)
-
-	sender.AddAuthorization(&req)
-
-	res, err = writeReqReadRes(conn, req)
-	require.NoError(t, err)
-	require.Equal(t, base.StatusUnauthorized, res.StatusCode)
-
-	_, err = writeReqReadRes(conn, req)
+	stream := &ServerStream{Server: s}
+	err := stream.Initialize()
 	require.Error(t, err)
 }