diff --git a/client.go b/client.go index cad4ff27..5fa737e9 100644 --- a/client.go +++ b/client.go @@ -9,6 +9,7 @@ package gortsplib import ( "bufio" + "bytes" "context" "crypto/tls" "fmt" @@ -34,7 +35,6 @@ import ( const ( clientReadBufferSize = 4096 - clientWriteBufferSize = 4096 clientUDPKernelReadBufferSize = 0x80000 // same size as gstreamer's rtspsrc ) @@ -200,9 +200,8 @@ type Client struct { ctx context.Context ctxCancel func() state clientState - nconn net.Conn + conn net.Conn br *bufio.Reader - bw *bufio.Writer session string sender *auth.Sender cseq int @@ -213,7 +212,6 @@ type Client struct { tracksByChannel map[int]int lastRange *headers.Range tcpReadBuffer *multibuffer.MultiBuffer - tcpWriteMutex sync.Mutex writeMutex sync.RWMutex // publish writeFrameAllowed bool // publish udpReportTimer *time.Timer @@ -609,10 +607,10 @@ func (c *Client) doClose(isClosing bool) { } } - if c.nconn != nil { + if c.conn != nil { c.connCloserStop() - c.nconn.Close() - c.nconn = nil + c.conn.Close() + c.conn = nil } } @@ -727,7 +725,7 @@ func (c *Client) playRecordStart() { // for some reason, SetReadDeadline() must always be called in the same // goroutine, otherwise Read() freezes. // therefore, we disable the deadline and perform a check with a ticker. - c.nconn.SetReadDeadline(time.Time{}) + c.conn.SetReadDeadline(time.Time{}) // start reader c.readerErr = make(chan error) @@ -768,8 +766,8 @@ func (c *Client) runReader() { } } - frame := base.InterleavedFrame{} - res := base.Response{} + var frame base.InterleavedFrame + var res base.Response for { frame.Payload = c.tcpReadBuffer.Next() @@ -801,7 +799,7 @@ func (c *Client) runReader() { func (c *Client) playRecordStop(isClosing bool) { // stop reader if c.readerErr != nil { - c.nconn.SetReadDeadline(time.Now()) + c.conn.SetReadDeadline(time.Now()) <-c.readerErr } @@ -847,7 +845,7 @@ func (c *Client) connOpen() error { return err } - conn := func() net.Conn { + c.conn = func() net.Conn { if c.scheme == "rtsps" { tlsConfig := c.TLSConfig @@ -863,9 +861,7 @@ func (c *Client) connOpen() error { return nconn }() - c.nconn = nconn - c.br = bufio.NewReaderSize(conn, clientReadBufferSize) - c.bw = bufio.NewWriterSize(conn, clientWriteBufferSize) + c.br = bufio.NewReaderSize(c.conn, clientReadBufferSize) c.connCloserStart() return nil } @@ -877,7 +873,7 @@ func (c *Client) connCloserStart() { defer close(c.connCloserDone) select { case <-c.ctx.Done(): - c.nconn.Close() + c.conn.Close() case <-c.connCloserTerminate: } @@ -893,7 +889,7 @@ func (c *Client) connCloserStop() { } func (c *Client) do(req *base.Request, skipResponse bool) (*base.Response, error) { - if c.nconn == nil { + if c.conn == nil { err := c.connOpen() if err != nil { return nil, err @@ -924,8 +920,11 @@ func (c *Client) do(req *base.Request, skipResponse bool) (*base.Response, error var res base.Response err := func() error { - c.nconn.SetWriteDeadline(time.Now().Add(c.WriteTimeout)) - err := req.Write(c.bw) + var buf bytes.Buffer + req.Write(&buf) + + c.conn.SetWriteDeadline(time.Now().Add(c.WriteTimeout)) + _, err := c.conn.Write(buf.Bytes()) if err != nil { return err } @@ -934,7 +933,7 @@ func (c *Client) do(req *base.Request, skipResponse bool) (*base.Response, error return nil } - c.nconn.SetReadDeadline(time.Now().Add(c.ReadTimeout)) + c.conn.SetReadDeadline(time.Now().Add(c.ReadTimeout)) if c.tcpReadBuffer != nil { // read the response and ignore interleaved frames in between; @@ -1449,8 +1448,8 @@ func (c *Client) doSetup( switch proto { case TransportUDP: - rtpListener.remoteReadIP = c.nconn.RemoteAddr().(*net.TCPAddr).IP - rtpListener.remoteZone = c.nconn.RemoteAddr().(*net.TCPAddr).Zone + rtpListener.remoteReadIP = c.conn.RemoteAddr().(*net.TCPAddr).IP + rtpListener.remoteZone = c.conn.RemoteAddr().(*net.TCPAddr).Zone if thRes.ServerPorts != nil { rtpListener.remotePort = thRes.ServerPorts[0] } @@ -1459,13 +1458,13 @@ func (c *Client) doSetup( cct.udpRTPListener = rtpListener rtpListener.remoteWriteAddr = &net.UDPAddr{ - IP: c.nconn.RemoteAddr().(*net.TCPAddr).IP, + IP: c.conn.RemoteAddr().(*net.TCPAddr).IP, Zone: rtpListener.remoteZone, Port: rtpListener.remotePort, } - rtcpListener.remoteReadIP = c.nconn.RemoteAddr().(*net.TCPAddr).IP - rtcpListener.remoteZone = c.nconn.RemoteAddr().(*net.TCPAddr).Zone + rtcpListener.remoteReadIP = c.conn.RemoteAddr().(*net.TCPAddr).IP + rtcpListener.remoteZone = c.conn.RemoteAddr().(*net.TCPAddr).Zone if thRes.ServerPorts != nil { rtcpListener.remotePort = thRes.ServerPorts[1] } @@ -1474,13 +1473,13 @@ func (c *Client) doSetup( cct.udpRTCPListener = rtcpListener rtcpListener.remoteWriteAddr = &net.UDPAddr{ - IP: c.nconn.RemoteAddr().(*net.TCPAddr).IP, + IP: c.conn.RemoteAddr().(*net.TCPAddr).IP, Zone: rtcpListener.remoteZone, Port: rtcpListener.remotePort, } case TransportUDPMulticast: - rtpListener.remoteReadIP = c.nconn.RemoteAddr().(*net.TCPAddr).IP + rtpListener.remoteReadIP = c.conn.RemoteAddr().(*net.TCPAddr).IP rtpListener.remoteZone = "" rtpListener.remotePort = thRes.Ports[0] rtpListener.trackID = trackID @@ -1493,7 +1492,7 @@ func (c *Client) doSetup( Port: rtpListener.remotePort, } - rtcpListener.remoteReadIP = c.nconn.RemoteAddr().(*net.TCPAddr).IP + rtcpListener.remoteReadIP = c.conn.RemoteAddr().(*net.TCPAddr).IP rtcpListener.remoteZone = "" rtcpListener.remotePort = thRes.Ports[1] rtcpListener.trackID = trackID @@ -1812,6 +1811,8 @@ func (c *Client) runWriter() { } default: // TCP + var buf bytes.Buffer + writeFunc = func(trackID int, isRTP bool, payload []byte) { if isRTP { if c.tracks[trackID].rtcpSender != nil { @@ -1820,19 +1821,17 @@ func (c *Client) runWriter() { f := c.tracks[trackID].tcpRTPFrame f.Payload = payload + f.Write(&buf) - c.tcpWriteMutex.Lock() - c.nconn.SetWriteDeadline(time.Now().Add(c.WriteTimeout)) - f.Write(c.bw) - c.tcpWriteMutex.Unlock() + c.conn.SetWriteDeadline(time.Now().Add(c.WriteTimeout)) + c.conn.Write(buf.Bytes()) } else { f := c.tracks[trackID].tcpRTCPFrame f.Payload = payload + f.Write(&buf) - c.tcpWriteMutex.Lock() - c.nconn.SetWriteDeadline(time.Now().Add(c.WriteTimeout)) - f.Write(c.bw) - c.tcpWriteMutex.Unlock() + c.conn.SetWriteDeadline(time.Now().Add(c.WriteTimeout)) + c.conn.Write(buf.Bytes()) } } } diff --git a/client_publish_test.go b/client_publish_test.go index e6b2c805..fb7dbb0d 100644 --- a/client_publish_test.go +++ b/client_publish_test.go @@ -2,6 +2,7 @@ package gortsplib import ( "bufio" + "bytes" "crypto/tls" "net" "strings" @@ -48,14 +49,15 @@ func TestClientPublishSerial(t *testing.T) { conn, err := l.Accept() require.NoError(t, err) defer conn.Close() - bconn := bufio.NewReadWriter(bufio.NewReader(conn), bufio.NewWriter(conn)) + br := bufio.NewReader(conn) + var bb bytes.Buffer - req, err := readRequest(bconn.Reader) + req, err := readRequest(br) require.NoError(t, err) require.Equal(t, base.Options, req.Method) require.Equal(t, mustParseURL(scheme+"://localhost:8554/teststream"), req.URL) - err = base.Response{ + base.Response{ StatusCode: base.StatusOK, Header: base.Header{ "Public": base.HeaderValue{strings.Join([]string{ @@ -64,20 +66,22 @@ func TestClientPublishSerial(t *testing.T) { string(base.Record), }, ", ")}, }, - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) - req, err = readRequest(bconn.Reader) + req, err = readRequest(br) require.NoError(t, err) require.Equal(t, base.Announce, req.Method) require.Equal(t, mustParseURL(scheme+"://localhost:8554/teststream"), req.URL) - err = base.Response{ + base.Response{ StatusCode: base.StatusOK, - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) - req, err = readRequest(bconn.Reader) + req, err = readRequest(br) require.NoError(t, err) require.Equal(t, base.Setup, req.Method) require.Equal(t, mustParseURL(scheme+"://localhost:8554/teststream/trackID=0"), req.URL) @@ -114,22 +118,24 @@ func TestClientPublishSerial(t *testing.T) { th.InterleavedIDs = inTH.InterleavedIDs } - err = base.Response{ + base.Response{ StatusCode: base.StatusOK, Header: base.Header{ "Transport": th.Write(), }, - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) - req, err = readRequest(bconn.Reader) + req, err = readRequest(br) require.NoError(t, err) require.Equal(t, base.Record, req.Method) require.Equal(t, mustParseURL(scheme+"://localhost:8554/teststream"), req.URL) - err = base.Response{ + base.Response{ StatusCode: base.StatusOK, - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) // client -> server @@ -141,7 +147,7 @@ func TestClientPublishSerial(t *testing.T) { } else { var f base.InterleavedFrame f.Payload = make([]byte, 2048) - err = f.Read(bconn.Reader) + err = f.Read(br) require.NoError(t, err) require.Equal(t, 0, f.Channel) require.Equal(t, []byte{0x01, 0x02, 0x03, 0x04}, f.Payload) @@ -154,21 +160,23 @@ func TestClientPublishSerial(t *testing.T) { Port: th.ClientPorts[1], }) } else { - err = base.InterleavedFrame{ + base.InterleavedFrame{ Channel: 1, Payload: []byte{0x05, 0x06, 0x07, 0x08}, - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) } - req, err = readRequest(bconn.Reader) + req, err = readRequest(br) require.NoError(t, err) require.Equal(t, base.Teardown, req.Method) require.Equal(t, mustParseURL(scheme+"://localhost:8554/teststream"), req.URL) - err = base.Response{ + base.Response{ StatusCode: base.StatusOK, - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) }() @@ -254,13 +262,14 @@ func TestClientPublishParallel(t *testing.T) { conn, err := l.Accept() require.NoError(t, err) defer conn.Close() - bconn := bufio.NewReadWriter(bufio.NewReader(conn), bufio.NewWriter(conn)) + br := bufio.NewReader(conn) + var bb bytes.Buffer - req, err := readRequest(bconn.Reader) + req, err := readRequest(br) require.NoError(t, err) require.Equal(t, base.Options, req.Method) - err = base.Response{ + base.Response{ StatusCode: base.StatusOK, Header: base.Header{ "Public": base.HeaderValue{strings.Join([]string{ @@ -269,19 +278,21 @@ func TestClientPublishParallel(t *testing.T) { string(base.Record), }, ", ")}, }, - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) - req, err = readRequest(bconn.Reader) + req, err = readRequest(br) require.NoError(t, err) require.Equal(t, base.Announce, req.Method) - err = base.Response{ + base.Response{ StatusCode: base.StatusOK, - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) - req, err = readRequest(bconn.Reader) + req, err = readRequest(br) require.NoError(t, err) require.Equal(t, base.Setup, req.Method) @@ -305,30 +316,33 @@ func TestClientPublishParallel(t *testing.T) { th.InterleavedIDs = inTH.InterleavedIDs } - err = base.Response{ + base.Response{ StatusCode: base.StatusOK, Header: base.Header{ "Transport": th.Write(), }, - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) - req, err = readRequest(bconn.Reader) + req, err = readRequest(br) require.NoError(t, err) require.Equal(t, base.Record, req.Method) - err = base.Response{ + base.Response{ StatusCode: base.StatusOK, - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) - req, err = readRequestIgnoreFrames(bconn.Reader) + req, err = readRequestIgnoreFrames(br) require.NoError(t, err) require.Equal(t, base.Teardown, req.Method) - err = base.Response{ + base.Response{ StatusCode: base.StatusOK, - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) }() @@ -397,13 +411,14 @@ func TestClientPublishPauseSerial(t *testing.T) { conn, err := l.Accept() require.NoError(t, err) defer conn.Close() - bconn := bufio.NewReadWriter(bufio.NewReader(conn), bufio.NewWriter(conn)) + br := bufio.NewReader(conn) + var bb bytes.Buffer - req, err := readRequest(bconn.Reader) + req, err := readRequest(br) require.NoError(t, err) require.Equal(t, base.Options, req.Method) - err = base.Response{ + base.Response{ StatusCode: base.StatusOK, Header: base.Header{ "Public": base.HeaderValue{strings.Join([]string{ @@ -413,19 +428,21 @@ func TestClientPublishPauseSerial(t *testing.T) { string(base.Pause), }, ", ")}, }, - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) - req, err = readRequest(bconn.Reader) + req, err = readRequest(br) require.NoError(t, err) require.Equal(t, base.Announce, req.Method) - err = base.Response{ + base.Response{ StatusCode: base.StatusOK, - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) - req, err = readRequest(bconn.Reader) + req, err = readRequest(br) require.NoError(t, err) require.Equal(t, base.Setup, req.Method) @@ -449,48 +466,53 @@ func TestClientPublishPauseSerial(t *testing.T) { th.InterleavedIDs = inTH.InterleavedIDs } - err = base.Response{ + base.Response{ StatusCode: base.StatusOK, Header: base.Header{ "Transport": th.Write(), }, - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) - req, err = readRequest(bconn.Reader) + req, err = readRequest(br) require.NoError(t, err) require.Equal(t, base.Record, req.Method) - err = base.Response{ + base.Response{ StatusCode: base.StatusOK, - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) - req, err = readRequestIgnoreFrames(bconn.Reader) + req, err = readRequestIgnoreFrames(br) require.NoError(t, err) require.Equal(t, base.Pause, req.Method) - err = base.Response{ + base.Response{ StatusCode: base.StatusOK, - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) - req, err = readRequest(bconn.Reader) + req, err = readRequest(br) require.NoError(t, err) require.Equal(t, base.Record, req.Method) - err = base.Response{ + base.Response{ StatusCode: base.StatusOK, - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) - req, err = readRequestIgnoreFrames(bconn.Reader) + req, err = readRequestIgnoreFrames(br) require.NoError(t, err) require.Equal(t, base.Teardown, req.Method) - err = base.Response{ + base.Response{ StatusCode: base.StatusOK, - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) }() @@ -550,13 +572,14 @@ func TestClientPublishPauseParallel(t *testing.T) { conn, err := l.Accept() require.NoError(t, err) defer conn.Close() - bconn := bufio.NewReadWriter(bufio.NewReader(conn), bufio.NewWriter(conn)) + br := bufio.NewReader(conn) + var bb bytes.Buffer - req, err := readRequest(bconn.Reader) + req, err := readRequest(br) require.NoError(t, err) require.Equal(t, base.Options, req.Method) - err = base.Response{ + base.Response{ StatusCode: base.StatusOK, Header: base.Header{ "Public": base.HeaderValue{strings.Join([]string{ @@ -566,19 +589,21 @@ func TestClientPublishPauseParallel(t *testing.T) { string(base.Pause), }, ", ")}, }, - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) - req, err = readRequest(bconn.Reader) + req, err = readRequest(br) require.NoError(t, err) require.Equal(t, base.Announce, req.Method) - err = base.Response{ + base.Response{ StatusCode: base.StatusOK, - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) - req, err = readRequest(bconn.Reader) + req, err = readRequest(br) require.NoError(t, err) require.Equal(t, base.Setup, req.Method) @@ -602,30 +627,33 @@ func TestClientPublishPauseParallel(t *testing.T) { th.InterleavedIDs = inTH.InterleavedIDs } - err = base.Response{ + base.Response{ StatusCode: base.StatusOK, Header: base.Header{ "Transport": th.Write(), }, - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) - req, err = readRequest(bconn.Reader) + req, err = readRequest(br) require.NoError(t, err) require.Equal(t, base.Record, req.Method) - err = base.Response{ + base.Response{ StatusCode: base.StatusOK, - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) - req, err = readRequestIgnoreFrames(bconn.Reader) + req, err = readRequestIgnoreFrames(br) require.NoError(t, err) require.Equal(t, base.Pause, req.Method) - err = base.Response{ + base.Response{ StatusCode: base.StatusOK, - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) }() @@ -689,14 +717,15 @@ func TestClientPublishAutomaticProtocol(t *testing.T) { conn, err := l.Accept() require.NoError(t, err) defer conn.Close() - bconn := bufio.NewReadWriter(bufio.NewReader(conn), bufio.NewWriter(conn)) + br := bufio.NewReader(conn) + var bb bytes.Buffer - req, err := readRequest(bconn.Reader) + req, err := readRequest(br) require.NoError(t, err) require.Equal(t, base.Options, req.Method) require.Equal(t, mustParseURL("rtsp://localhost:8554/teststream"), req.URL) - err = base.Response{ + base.Response{ StatusCode: base.StatusOK, Header: base.Header{ "Public": base.HeaderValue{strings.Join([]string{ @@ -705,29 +734,32 @@ func TestClientPublishAutomaticProtocol(t *testing.T) { string(base.Record), }, ", ")}, }, - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) - req, err = readRequest(bconn.Reader) + req, err = readRequest(br) require.NoError(t, err) require.Equal(t, base.Announce, req.Method) require.Equal(t, mustParseURL("rtsp://localhost:8554/teststream"), req.URL) - err = base.Response{ + base.Response{ StatusCode: base.StatusOK, - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) - req, err = readRequest(bconn.Reader) + req, err = readRequest(br) require.NoError(t, err) require.Equal(t, base.Setup, req.Method) - err = base.Response{ + base.Response{ StatusCode: base.StatusUnsupportedTransport, - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) - req, err = readRequest(bconn.Reader) + req, err = readRequest(br) require.NoError(t, err) require.Equal(t, base.Setup, req.Method) @@ -745,38 +777,41 @@ func TestClientPublishAutomaticProtocol(t *testing.T) { InterleavedIDs: &[2]int{0, 1}, } - err = base.Response{ + base.Response{ StatusCode: base.StatusOK, Header: base.Header{ "Transport": th.Write(), }, - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) - req, err = readRequest(bconn.Reader) + req, err = readRequest(br) require.NoError(t, err) require.Equal(t, base.Record, req.Method) require.Equal(t, mustParseURL("rtsp://localhost:8554/teststream"), req.URL) - err = base.Response{ + base.Response{ StatusCode: base.StatusOK, - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) var f base.InterleavedFrame f.Payload = make([]byte, 2048) - err = f.Read(bconn.Reader) + err = f.Read(br) require.NoError(t, err) require.Equal(t, 0, f.Channel) require.Equal(t, []byte{0x01, 0x02, 0x03, 0x04}, f.Payload) - req, err = readRequest(bconn.Reader) + req, err = readRequest(br) require.NoError(t, err) require.Equal(t, base.Teardown, req.Method) - err = base.Response{ + base.Response{ StatusCode: base.StatusOK, - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) }() @@ -812,13 +847,14 @@ func TestClientPublishRTCPReport(t *testing.T) { conn, err := l.Accept() require.NoError(t, err) defer conn.Close() - bconn := bufio.NewReadWriter(bufio.NewReader(conn), bufio.NewWriter(conn)) + br := bufio.NewReader(conn) + var bb bytes.Buffer - req, err := readRequest(bconn.Reader) + req, err := readRequest(br) require.NoError(t, err) require.Equal(t, base.Options, req.Method) - err = base.Response{ + base.Response{ StatusCode: base.StatusOK, Header: base.Header{ "Public": base.HeaderValue{strings.Join([]string{ @@ -827,19 +863,21 @@ func TestClientPublishRTCPReport(t *testing.T) { string(base.Record), }, ", ")}, }, - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) - req, err = readRequest(bconn.Reader) + req, err = readRequest(br) require.NoError(t, err) require.Equal(t, base.Announce, req.Method) - err = base.Response{ + base.Response{ StatusCode: base.StatusOK, - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) - req, err = readRequest(bconn.Reader) + req, err = readRequest(br) require.NoError(t, err) require.Equal(t, base.Setup, req.Method) @@ -855,7 +893,7 @@ func TestClientPublishRTCPReport(t *testing.T) { require.NoError(t, err) defer l2.Close() - err = base.Response{ + base.Response{ StatusCode: base.StatusOK, Header: base.Header{ "Transport": headers.Transport{ @@ -868,16 +906,18 @@ func TestClientPublishRTCPReport(t *testing.T) { ServerPorts: &[2]int{34556, 34557}, }.Write(), }, - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) - req, err = readRequest(bconn.Reader) + req, err = readRequest(br) require.NoError(t, err) require.Equal(t, base.Record, req.Method) - err = base.Response{ + base.Response{ StatusCode: base.StatusOK, - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) rr := rtcpreceiver.New(nil, 90000) @@ -905,13 +945,15 @@ func TestClientPublishRTCPReport(t *testing.T) { close(reportReceived) - req, err = readRequest(bconn.Reader) + req, err = readRequest(br) require.NoError(t, err) require.Equal(t, base.Teardown, req.Method) base.Response{ StatusCode: base.StatusOK, - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) + require.NoError(t, err) }() c := &Client{ @@ -958,13 +1000,14 @@ func TestClientPublishIgnoreTCPRTPPackets(t *testing.T) { conn, err := l.Accept() require.NoError(t, err) defer conn.Close() - bconn := bufio.NewReadWriter(bufio.NewReader(conn), bufio.NewWriter(conn)) + br := bufio.NewReader(conn) + var bb bytes.Buffer - req, err := readRequest(bconn.Reader) + req, err := readRequest(br) require.NoError(t, err) require.Equal(t, base.Options, req.Method) - err = base.Response{ + base.Response{ StatusCode: base.StatusOK, Header: base.Header{ "Public": base.HeaderValue{strings.Join([]string{ @@ -973,19 +1016,21 @@ func TestClientPublishIgnoreTCPRTPPackets(t *testing.T) { string(base.Record), }, ", ")}, }, - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) - req, err = readRequest(bconn.Reader) + req, err = readRequest(br) require.NoError(t, err) require.Equal(t, base.Announce, req.Method) - err = base.Response{ + base.Response{ StatusCode: base.StatusOK, - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) - req, err = readRequest(bconn.Reader) + req, err = readRequest(br) require.NoError(t, err) require.Equal(t, base.Setup, req.Method) @@ -1002,42 +1047,48 @@ func TestClientPublishIgnoreTCPRTPPackets(t *testing.T) { InterleavedIDs: inTH.InterleavedIDs, } - err = base.Response{ + base.Response{ StatusCode: base.StatusOK, Header: base.Header{ "Transport": th.Write(), }, - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) - req, err = readRequest(bconn.Reader) + req, err = readRequest(br) require.NoError(t, err) require.Equal(t, base.Record, req.Method) - err = base.Response{ + base.Response{ StatusCode: base.StatusOK, - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) - err = base.InterleavedFrame{ + base.InterleavedFrame{ Channel: 0, Payload: []byte{0x01, 0x02, 0x03, 0x04}, - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) - err = base.InterleavedFrame{ + base.InterleavedFrame{ Channel: 1, Payload: []byte{0x05, 0x06, 0x07, 0x08}, - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) - req, err = readRequest(bconn.Reader) + req, err = readRequest(br) require.NoError(t, err) require.Equal(t, base.Teardown, req.Method) base.Response{ StatusCode: base.StatusOK, - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) + require.NoError(t, err) }() rtcpReceived := make(chan struct{}) diff --git a/client_read_test.go b/client_read_test.go index 2de9cd12..2606c288 100644 --- a/client_read_test.go +++ b/client_read_test.go @@ -47,13 +47,14 @@ func TestClientReadTracks(t *testing.T) { conn, err := l.Accept() require.NoError(t, err) defer conn.Close() - bconn := bufio.NewReadWriter(bufio.NewReader(conn), bufio.NewWriter(conn)) + br := bufio.NewReader(conn) + var bb bytes.Buffer - req, err := readRequest(bconn.Reader) + req, err := readRequest(br) require.NoError(t, err) require.Equal(t, base.Options, req.Method) - err = base.Response{ + base.Response{ StatusCode: base.StatusOK, Header: base.Header{ "Public": base.HeaderValue{strings.Join([]string{ @@ -62,28 +63,30 @@ func TestClientReadTracks(t *testing.T) { string(base.Play), }, ", ")}, }, - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) - req, err = readRequest(bconn.Reader) + req, err = readRequest(br) require.NoError(t, err) require.Equal(t, base.Describe, req.Method) require.Equal(t, mustParseURL("rtsp://localhost:8554/teststream"), req.URL) tracks := cloneAndClearTracks(Tracks{track1, track2, track3}) - err = base.Response{ + base.Response{ StatusCode: base.StatusOK, Header: base.Header{ "Content-Type": base.HeaderValue{"application/sdp"}, "Content-Base": base.HeaderValue{"rtsp://localhost:8554/teststream/"}, }, Body: tracks.Write(false), - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) for i := 0; i < 3; i++ { - req, err := readRequest(bconn.Reader) + req, err := readRequest(br) require.NoError(t, err) require.Equal(t, base.Setup, req.Method) require.Equal(t, mustParseURL(fmt.Sprintf("rtsp://localhost:8554/teststream/trackID=%d", i)), req.URL) @@ -102,33 +105,36 @@ func TestClientReadTracks(t *testing.T) { ServerPorts: &[2]int{34556 + i*2, 34557 + i*2}, } - err = base.Response{ + base.Response{ StatusCode: base.StatusOK, Header: base.Header{ "Transport": th.Write(), }, - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) } - req, err = readRequest(bconn.Reader) + req, err = readRequest(br) require.NoError(t, err) require.Equal(t, base.Play, req.Method) require.Equal(t, mustParseURL("rtsp://localhost:8554/teststream/"), req.URL) - err = base.Response{ + base.Response{ StatusCode: base.StatusOK, - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) - req, err = readRequest(bconn.Reader) + req, err = readRequest(br) require.NoError(t, err) require.Equal(t, base.Teardown, req.Method) require.Equal(t, mustParseURL("rtsp://localhost:8554/teststream/"), req.URL) - err = base.Response{ + base.Response{ StatusCode: base.StatusOK, - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) }() @@ -201,14 +207,15 @@ func TestClientRead(t *testing.T) { conn, err := l.Accept() require.NoError(t, err) defer conn.Close() - bconn := bufio.NewReadWriter(bufio.NewReader(conn), bufio.NewWriter(conn)) + br := bufio.NewReader(conn) + var bb bytes.Buffer - req, err := readRequest(bconn.Reader) + req, err := readRequest(br) require.NoError(t, err) require.Equal(t, base.Options, req.Method) require.Equal(t, mustParseURL(scheme+"://"+listenIP+":8554/test/stream?param=value"), req.URL) - err = base.Response{ + base.Response{ StatusCode: base.StatusOK, Header: base.Header{ "Public": base.HeaderValue{strings.Join([]string{ @@ -217,10 +224,11 @@ func TestClientRead(t *testing.T) { string(base.Play), }, ", ")}, }, - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) - req, err = readRequest(bconn.Reader) + req, err = readRequest(br) require.NoError(t, err) require.Equal(t, base.Describe, req.Method) require.Equal(t, mustParseURL(scheme+"://"+listenIP+":8554/test/stream?param=value"), req.URL) @@ -235,17 +243,18 @@ func TestClientRead(t *testing.T) { Value: "trackID=0", }) - err = base.Response{ + base.Response{ StatusCode: base.StatusOK, Header: base.Header{ "Content-Type": base.HeaderValue{"application/sdp"}, "Content-Base": base.HeaderValue{scheme + "://" + listenIP + ":8554/test/stream?param=value/"}, }, Body: Tracks{track}.Write(false), - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) - req, err = readRequest(bconn.Reader) + req, err = readRequest(br) require.NoError(t, err) require.Equal(t, base.Setup, req.Method) require.Equal(t, mustParseURL(scheme+"://"+listenIP+":8554/test/stream?param=value/trackID=0"), req.URL) @@ -318,23 +327,25 @@ func TestClientRead(t *testing.T) { th.InterleavedIDs = &[2]int{0, 1} } - err = base.Response{ + base.Response{ StatusCode: base.StatusOK, Header: base.Header{ "Transport": th.Write(), }, - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) - req, err = readRequest(bconn.Reader) + req, err = readRequest(br) require.NoError(t, err) require.Equal(t, base.Play, req.Method) require.Equal(t, mustParseURL(scheme+"://"+listenIP+":8554/test/stream?param=value/"), req.URL) require.Equal(t, base.HeaderValue{"npt=0-"}, req.Header["Range"]) - err = base.Response{ + base.Response{ StatusCode: base.StatusOK, - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) // server -> client @@ -354,10 +365,11 @@ func TestClientRead(t *testing.T) { }) case "tcp", "tls": - err = base.InterleavedFrame{ + base.InterleavedFrame{ Channel: 0, Payload: []byte{0x01, 0x02, 0x03, 0x04}, - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) } @@ -378,21 +390,22 @@ func TestClientRead(t *testing.T) { case "tcp", "tls": var f base.InterleavedFrame f.Payload = make([]byte, 2048) - err := f.Read(bconn.Reader) + err := f.Read(br) require.NoError(t, err) require.Equal(t, 1, f.Channel) require.Equal(t, []byte{0x05, 0x06, 0x07, 0x08}, f.Payload) close(packetRecv) } - req, err = readRequest(bconn.Reader) + req, err = readRequest(br) require.NoError(t, err) require.Equal(t, base.Teardown, req.Method) require.Equal(t, mustParseURL(scheme+"://"+listenIP+":8554/test/stream?param=value/"), req.URL) - err = base.Response{ + base.Response{ StatusCode: base.StatusOK, - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) }() @@ -459,14 +472,15 @@ func TestClientReadNonStandardFrameSize(t *testing.T) { conn, err := l.Accept() require.NoError(t, err) defer conn.Close() - bconn := bufio.NewReadWriter(bufio.NewReader(conn), bufio.NewWriter(conn)) + br := bufio.NewReader(conn) + var bb bytes.Buffer - req, err := readRequest(bconn.Reader) + req, err := readRequest(br) require.NoError(t, err) require.Equal(t, base.Options, req.Method) require.Equal(t, mustParseURL("rtsp://localhost:8554/teststream"), req.URL) - err = base.Response{ + base.Response{ StatusCode: base.StatusOK, Header: base.Header{ "Public": base.HeaderValue{strings.Join([]string{ @@ -475,10 +489,11 @@ func TestClientReadNonStandardFrameSize(t *testing.T) { string(base.Play), }, ", ")}, }, - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) - req, err = readRequest(bconn.Reader) + req, err = readRequest(br) require.NoError(t, err) require.Equal(t, base.Describe, req.Method) require.Equal(t, mustParseURL("rtsp://localhost:8554/teststream"), req.URL) @@ -493,17 +508,18 @@ func TestClientReadNonStandardFrameSize(t *testing.T) { Value: "trackID=0", }) - err = base.Response{ + base.Response{ StatusCode: base.StatusOK, Header: base.Header{ "Content-Type": base.HeaderValue{"application/sdp"}, "Content-Base": base.HeaderValue{"rtsp://localhost:8554/teststream/"}, }, Body: Tracks{track}.Write(false), - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) - req, err = readRequest(bconn.Reader) + req, err = readRequest(br) require.NoError(t, err) require.Equal(t, base.Setup, req.Method) require.Equal(t, mustParseURL("rtsp://localhost:8554/teststream/trackID=0"), req.URL) @@ -517,29 +533,32 @@ func TestClientReadNonStandardFrameSize(t *testing.T) { InterleavedIDs: &[2]int{0, 1}, } - err = base.Response{ + base.Response{ StatusCode: base.StatusOK, Header: base.Header{ "Transport": th.Write(), }, - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) - req, err = readRequest(bconn.Reader) + req, err = readRequest(br) require.NoError(t, err) require.Equal(t, base.Play, req.Method) require.Equal(t, mustParseURL("rtsp://localhost:8554/teststream/"), req.URL) require.Equal(t, base.HeaderValue{"npt=0-"}, req.Header["Range"]) - err = base.Response{ + base.Response{ StatusCode: base.StatusOK, - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) - err = base.InterleavedFrame{ + base.InterleavedFrame{ Channel: 0, Payload: refPayload, - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) }() @@ -579,9 +598,10 @@ func TestClientReadPartial(t *testing.T) { conn, err := l.Accept() require.NoError(t, err) defer conn.Close() - bconn := bufio.NewReadWriter(bufio.NewReader(conn), bufio.NewWriter(conn)) + br := bufio.NewReader(conn) + var bb bytes.Buffer - req, err := readRequest(bconn.Reader) + req, err := readRequest(br) require.NoError(t, err) require.Equal(t, base.Describe, req.Method) require.Equal(t, mustParseURL("rtsp://"+listenIP+":8554/teststream"), req.URL) @@ -598,17 +618,18 @@ func TestClientReadPartial(t *testing.T) { tracks := cloneAndClearTracks(Tracks{track1, track2}) - err = base.Response{ + base.Response{ StatusCode: base.StatusOK, Header: base.Header{ "Content-Type": base.HeaderValue{"application/sdp"}, "Content-Base": base.HeaderValue{"rtsp://" + listenIP + ":8554/teststream/"}, }, Body: tracks.Write(false), - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) - req, err = readRequest(bconn.Reader) + req, err = readRequest(br) require.NoError(t, err) require.Equal(t, base.Setup, req.Method) require.Equal(t, mustParseURL("rtsp://"+listenIP+":8554/teststream/trackID=1"), req.URL) @@ -627,38 +648,42 @@ func TestClientReadPartial(t *testing.T) { InterleavedIDs: inTH.InterleavedIDs, } - err = base.Response{ + base.Response{ StatusCode: base.StatusOK, Header: base.Header{ "Transport": th.Write(), }, - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) - req, err = readRequest(bconn.Reader) + req, err = readRequest(br) require.NoError(t, err) require.Equal(t, base.Play, req.Method) require.Equal(t, mustParseURL("rtsp://"+listenIP+":8554/teststream/"), req.URL) - err = base.Response{ + base.Response{ StatusCode: base.StatusOK, - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) - err = base.InterleavedFrame{ + base.InterleavedFrame{ Channel: 0, Payload: []byte{0x01, 0x02, 0x03, 0x04}, - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) - req, err = readRequest(bconn.Reader) + req, err = readRequest(br) require.NoError(t, err) require.Equal(t, base.Teardown, req.Method) require.Equal(t, mustParseURL("rtsp://"+listenIP+":8554/teststream/"), req.URL) - err = base.Response{ + base.Response{ StatusCode: base.StatusOK, - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) }() @@ -708,13 +733,14 @@ func TestClientReadNoContentBase(t *testing.T) { conn, err := l.Accept() require.NoError(t, err) defer conn.Close() - bconn := bufio.NewReadWriter(bufio.NewReader(conn), bufio.NewWriter(conn)) + br := bufio.NewReader(conn) + var bb bytes.Buffer - req, err := readRequest(bconn.Reader) + req, err := readRequest(br) require.NoError(t, err) require.Equal(t, base.Options, req.Method) - err = base.Response{ + base.Response{ StatusCode: base.StatusOK, Header: base.Header{ "Public": base.HeaderValue{strings.Join([]string{ @@ -723,10 +749,11 @@ func TestClientReadNoContentBase(t *testing.T) { string(base.Play), }, ", ")}, }, - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) - req, err = readRequest(bconn.Reader) + req, err = readRequest(br) require.NoError(t, err) require.Equal(t, base.Describe, req.Method) require.Equal(t, mustParseURL("rtsp://localhost:8554/teststream"), req.URL) @@ -738,16 +765,17 @@ func TestClientReadNoContentBase(t *testing.T) { tracks := cloneAndClearTracks(Tracks{track}) - err = base.Response{ + base.Response{ StatusCode: base.StatusOK, Header: base.Header{ "Content-Type": base.HeaderValue{"application/sdp"}, }, Body: tracks.Write(false), - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) - req, err = readRequest(bconn.Reader) + req, err = readRequest(br) require.NoError(t, err) require.Equal(t, base.Setup, req.Method) require.Equal(t, mustParseURL("rtsp://localhost:8554/teststream/trackID=0"), req.URL) @@ -766,32 +794,35 @@ func TestClientReadNoContentBase(t *testing.T) { ServerPorts: &[2]int{34556, 34557}, } - err = base.Response{ + base.Response{ StatusCode: base.StatusOK, Header: base.Header{ "Transport": th.Write(), }, - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) - req, err = readRequest(bconn.Reader) + req, err = readRequest(br) require.NoError(t, err) require.Equal(t, base.Play, req.Method) require.Equal(t, mustParseURL("rtsp://localhost:8554/teststream"), req.URL) - err = base.Response{ + base.Response{ StatusCode: base.StatusOK, - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) - req, err = readRequest(bconn.Reader) + req, err = readRequest(br) require.NoError(t, err) require.Equal(t, base.Teardown, req.Method) require.Equal(t, mustParseURL("rtsp://localhost:8554/teststream"), req.URL) - err = base.Response{ + base.Response{ StatusCode: base.StatusOK, - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) }() @@ -824,13 +855,14 @@ func TestClientReadAnyPort(t *testing.T) { conn, err := l.Accept() require.NoError(t, err) defer conn.Close() - bconn := bufio.NewReadWriter(bufio.NewReader(conn), bufio.NewWriter(conn)) + br := bufio.NewReader(conn) + var bb bytes.Buffer - req, err := readRequest(bconn.Reader) + req, err := readRequest(br) require.NoError(t, err) require.Equal(t, base.Options, req.Method) - err = base.Response{ + base.Response{ StatusCode: base.StatusOK, Header: base.Header{ "Public": base.HeaderValue{strings.Join([]string{ @@ -839,10 +871,11 @@ func TestClientReadAnyPort(t *testing.T) { string(base.Play), }, ", ")}, }, - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) - req, err = readRequest(bconn.Reader) + req, err = readRequest(br) require.NoError(t, err) require.Equal(t, base.Describe, req.Method) @@ -853,17 +886,18 @@ func TestClientReadAnyPort(t *testing.T) { tracks := cloneAndClearTracks(Tracks{track}) - err = base.Response{ + base.Response{ StatusCode: base.StatusOK, Header: base.Header{ "Content-Type": base.HeaderValue{"application/sdp"}, "Content-Base": base.HeaderValue{"rtsp://localhost:8554/teststream/"}, }, Body: tracks.Write(false), - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) - req, err = readRequest(bconn.Reader) + req, err = readRequest(br) require.NoError(t, err) require.Equal(t, base.Setup, req.Method) @@ -879,7 +913,7 @@ func TestClientReadAnyPort(t *testing.T) { require.NoError(t, err) defer l1b.Close() - err = base.Response{ + base.Response{ StatusCode: base.StatusOK, Header: base.Header{ "Transport": headers.Transport{ @@ -906,16 +940,18 @@ func TestClientReadAnyPort(t *testing.T) { }(), }.Write(), }, - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) - req, err = readRequest(bconn.Reader) + req, err = readRequest(br) require.NoError(t, err) require.Equal(t, base.Play, req.Method) - err = base.Response{ + base.Response{ StatusCode: base.StatusOK, - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) time.Sleep(500 * time.Millisecond) @@ -977,13 +1013,14 @@ func TestClientReadAutomaticProtocol(t *testing.T) { conn, err := l.Accept() require.NoError(t, err) defer conn.Close() - bconn := bufio.NewReadWriter(bufio.NewReader(conn), bufio.NewWriter(conn)) + br := bufio.NewReader(conn) + var bb bytes.Buffer - req, err := readRequest(bconn.Reader) + req, err := readRequest(br) require.NoError(t, err) require.Equal(t, base.Options, req.Method) - err = base.Response{ + base.Response{ StatusCode: base.StatusOK, Header: base.Header{ "Public": base.HeaderValue{strings.Join([]string{ @@ -992,10 +1029,11 @@ func TestClientReadAutomaticProtocol(t *testing.T) { string(base.Play), }, ", ")}, }, - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) - req, err = readRequest(bconn.Reader) + req, err = readRequest(br) require.NoError(t, err) require.Equal(t, base.Describe, req.Method) @@ -1006,26 +1044,28 @@ func TestClientReadAutomaticProtocol(t *testing.T) { tracks := cloneAndClearTracks(Tracks{track}) - err = base.Response{ + base.Response{ StatusCode: base.StatusOK, Header: base.Header{ "Content-Type": base.HeaderValue{"application/sdp"}, "Content-Base": base.HeaderValue{"rtsp://localhost:8554/teststream/"}, }, Body: tracks.Write(false), - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) - req, err = readRequest(bconn.Reader) + req, err = readRequest(br) require.NoError(t, err) require.Equal(t, base.Setup, req.Method) - err = base.Response{ + base.Response{ StatusCode: base.StatusUnsupportedTransport, - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) - req, err = readRequest(bconn.Reader) + req, err = readRequest(br) require.NoError(t, err) require.Equal(t, base.Setup, req.Method) @@ -1034,7 +1074,7 @@ func TestClientReadAutomaticProtocol(t *testing.T) { require.NoError(t, err) require.Equal(t, headers.TransportProtocolTCP, inTH.Protocol) - err = base.Response{ + base.Response{ StatusCode: base.StatusOK, Header: base.Header{ "Transport": headers.Transport{ @@ -1046,22 +1086,25 @@ func TestClientReadAutomaticProtocol(t *testing.T) { InterleavedIDs: &[2]int{0, 1}, }.Write(), }, - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) - req, err = readRequest(bconn.Reader) + req, err = readRequest(br) require.NoError(t, err) require.Equal(t, base.Play, req.Method) - err = base.Response{ + base.Response{ StatusCode: base.StatusOK, - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) - err = base.InterleavedFrame{ + base.InterleavedFrame{ Channel: 0, Payload: []byte("\x00\x00\x00\x00"), - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) }() @@ -1092,13 +1135,14 @@ func TestClientReadAutomaticProtocol(t *testing.T) { conn, err := l.Accept() require.NoError(t, err) - bconn := bufio.NewReadWriter(bufio.NewReader(conn), bufio.NewWriter(conn)) + br := bufio.NewReader(conn) + var bb bytes.Buffer - req, err := readRequest(bconn.Reader) + req, err := readRequest(br) require.NoError(t, err) require.Equal(t, base.Options, req.Method) - err = base.Response{ + base.Response{ StatusCode: base.StatusOK, Header: base.Header{ "Public": base.HeaderValue{strings.Join([]string{ @@ -1107,24 +1151,26 @@ func TestClientReadAutomaticProtocol(t *testing.T) { string(base.Play), }, ", ")}, }, - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) - req, err = readRequest(bconn.Reader) + req, err = readRequest(br) require.NoError(t, err) require.Equal(t, base.Describe, req.Method) v := auth.NewValidator("myuser", "mypass", nil) - err = base.Response{ + base.Response{ StatusCode: base.StatusUnauthorized, Header: base.Header{ "WWW-Authenticate": v.Header(), }, - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) - req, err = readRequest(bconn.Reader) + req, err = readRequest(br) require.NoError(t, err) require.Equal(t, base.Describe, req.Method) @@ -1138,17 +1184,18 @@ func TestClientReadAutomaticProtocol(t *testing.T) { tracks := cloneAndClearTracks(Tracks{track}) - err = base.Response{ + base.Response{ StatusCode: base.StatusOK, Header: base.Header{ "Content-Type": base.HeaderValue{"application/sdp"}, "Content-Base": base.HeaderValue{"rtsp://localhost:8554/teststream/"}, }, Body: tracks.Write(false), - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) - req, err = readRequest(bconn.Reader) + req, err = readRequest(br) require.NoError(t, err) require.Equal(t, base.Setup, req.Method) require.Equal(t, mustParseURL("rtsp://localhost:8554/teststream/trackID=0"), req.URL) @@ -1167,53 +1214,57 @@ func TestClientReadAutomaticProtocol(t *testing.T) { ClientPorts: inTH.ClientPorts, } - err = base.Response{ + base.Response{ StatusCode: base.StatusOK, Header: base.Header{ "Transport": th.Write(), }, - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) - req, err = readRequest(bconn.Reader) + req, err = readRequest(br) require.NoError(t, err) require.Equal(t, base.Play, req.Method) - err = base.Response{ + base.Response{ StatusCode: base.StatusOK, - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) - req, err = readRequest(bconn.Reader) + req, err = readRequest(br) require.NoError(t, err) require.Equal(t, base.Teardown, req.Method) - err = base.Response{ + base.Response{ StatusCode: base.StatusOK, - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) conn.Close() conn, err = l.Accept() require.NoError(t, err) - bconn = bufio.NewReadWriter(bufio.NewReader(conn), bufio.NewWriter(conn)) + br = bufio.NewReader(conn) - req, err = readRequest(bconn.Reader) + req, err = readRequest(br) require.NoError(t, err) require.Equal(t, base.Setup, req.Method) v = auth.NewValidator("myuser", "mypass", nil) - err = base.Response{ + base.Response{ StatusCode: base.StatusUnauthorized, Header: base.Header{ "WWW-Authenticate": v.Header(), }, - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) - req, err = readRequest(bconn.Reader) + req, err = readRequest(br) require.NoError(t, err) require.Equal(t, base.Setup, req.Method) require.Equal(t, mustParseURL("rtsp://localhost:8554/teststream/trackID=0"), req.URL) @@ -1234,35 +1285,40 @@ func TestClientReadAutomaticProtocol(t *testing.T) { InterleavedIDs: inTH.InterleavedIDs, } - err = base.Response{ + base.Response{ StatusCode: base.StatusOK, Header: base.Header{ "Transport": th.Write(), }, - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) - req, err = readRequest(bconn.Reader) + req, err = readRequest(br) require.NoError(t, err) require.Equal(t, base.Play, req.Method) - err = base.Response{ + base.Response{ StatusCode: base.StatusOK, - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) base.InterleavedFrame{ Channel: 0, Payload: []byte("\x00\x00\x00\x00"), - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) + require.NoError(t, err) - req, err = readRequest(bconn.Reader) + req, err = readRequest(br) require.NoError(t, err) require.Equal(t, base.Teardown, req.Method) - err = base.Response{ + base.Response{ StatusCode: base.StatusOK, - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) conn.Close() @@ -1298,13 +1354,14 @@ func TestClientReadDifferentInterleavedIDs(t *testing.T) { conn, err := l.Accept() require.NoError(t, err) defer conn.Close() - bconn := bufio.NewReadWriter(bufio.NewReader(conn), bufio.NewWriter(conn)) + br := bufio.NewReader(conn) + var bb bytes.Buffer - req, err := readRequest(bconn.Reader) + req, err := readRequest(br) require.NoError(t, err) require.Equal(t, base.Options, req.Method) - err = base.Response{ + base.Response{ StatusCode: base.StatusOK, Header: base.Header{ "Public": base.HeaderValue{strings.Join([]string{ @@ -1313,10 +1370,11 @@ func TestClientReadDifferentInterleavedIDs(t *testing.T) { string(base.Play), }, ", ")}, }, - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) - req, err = readRequest(bconn.Reader) + req, err = readRequest(br) require.NoError(t, err) require.Equal(t, base.Describe, req.Method) require.Equal(t, mustParseURL("rtsp://localhost:8554/teststream"), req.URL) @@ -1328,17 +1386,18 @@ func TestClientReadDifferentInterleavedIDs(t *testing.T) { tracks := cloneAndClearTracks(Tracks{track1}) - err = base.Response{ + base.Response{ StatusCode: base.StatusOK, Header: base.Header{ "Content-Type": base.HeaderValue{"application/sdp"}, "Content-Base": base.HeaderValue{"rtsp://localhost:8554/teststream/"}, }, Body: tracks.Write(false), - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) - req, err = readRequest(bconn.Reader) + req, err = readRequest(br) require.NoError(t, err) require.Equal(t, base.Setup, req.Method) require.Equal(t, mustParseURL("rtsp://localhost:8554/teststream/trackID=0"), req.URL) @@ -1356,38 +1415,42 @@ func TestClientReadDifferentInterleavedIDs(t *testing.T) { InterleavedIDs: &[2]int{2, 3}, } - err = base.Response{ + base.Response{ StatusCode: base.StatusOK, Header: base.Header{ "Transport": th.Write(), }, - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) - req, err = readRequest(bconn.Reader) + req, err = readRequest(br) require.NoError(t, err) require.Equal(t, base.Play, req.Method) require.Equal(t, mustParseURL("rtsp://localhost:8554/teststream/"), req.URL) - err = base.Response{ + base.Response{ StatusCode: base.StatusOK, - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) - err = base.InterleavedFrame{ + base.InterleavedFrame{ Channel: 2, Payload: []byte{0x01, 0x02, 0x03, 0x04}, - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) - req, err = readRequest(bconn.Reader) + req, err = readRequest(br) require.NoError(t, err) require.Equal(t, base.Teardown, req.Method) require.Equal(t, mustParseURL("rtsp://localhost:8554/teststream/"), req.URL) - err = base.Response{ + base.Response{ StatusCode: base.StatusOK, - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) }() @@ -1423,13 +1486,14 @@ func TestClientReadRedirect(t *testing.T) { conn, err := l.Accept() require.NoError(t, err) - bconn := bufio.NewReadWriter(bufio.NewReader(conn), bufio.NewWriter(conn)) + br := bufio.NewReader(conn) + var bb bytes.Buffer - req, err := readRequest(bconn.Reader) + req, err := readRequest(br) require.NoError(t, err) require.Equal(t, base.Options, req.Method) - err = base.Response{ + base.Response{ StatusCode: base.StatusOK, Header: base.Header{ "Public": base.HeaderValue{strings.Join([]string{ @@ -1438,19 +1502,21 @@ func TestClientReadRedirect(t *testing.T) { string(base.Play), }, ", ")}, }, - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) - req, err = readRequest(bconn.Reader) + req, err = readRequest(br) require.NoError(t, err) require.Equal(t, base.Describe, req.Method) - err = base.Response{ + base.Response{ StatusCode: base.StatusMovedPermanently, Header: base.Header{ "Location": base.HeaderValue{"rtsp://localhost:8554/test"}, }, - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) conn.Close() @@ -1458,13 +1524,13 @@ func TestClientReadRedirect(t *testing.T) { conn, err = l.Accept() require.NoError(t, err) defer conn.Close() - bconn = bufio.NewReadWriter(bufio.NewReader(conn), bufio.NewWriter(conn)) + br = bufio.NewReader(conn) - req, err = readRequest(bconn.Reader) + req, err = readRequest(br) require.NoError(t, err) require.Equal(t, base.Options, req.Method) - err = base.Response{ + base.Response{ StatusCode: base.StatusOK, Header: base.Header{ "Public": base.HeaderValue{strings.Join([]string{ @@ -1473,10 +1539,11 @@ func TestClientReadRedirect(t *testing.T) { string(base.Play), }, ", ")}, }, - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) - req, err = readRequest(bconn.Reader) + req, err = readRequest(br) require.NoError(t, err) require.Equal(t, base.Describe, req.Method) @@ -1487,17 +1554,18 @@ func TestClientReadRedirect(t *testing.T) { tracks := cloneAndClearTracks(Tracks{track}) - err = base.Response{ + base.Response{ StatusCode: base.StatusOK, Header: base.Header{ "Content-Type": base.HeaderValue{"application/sdp"}, "Content-Base": base.HeaderValue{"rtsp://localhost:8554/teststream/"}, }, Body: tracks.Write(false), - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) - req, err = readRequest(bconn.Reader) + req, err = readRequest(br) require.NoError(t, err) require.Equal(t, base.Setup, req.Method) @@ -1505,7 +1573,7 @@ func TestClientReadRedirect(t *testing.T) { err = th.Read(req.Header["Transport"]) require.NoError(t, err) - err = base.Response{ + base.Response{ StatusCode: base.StatusOK, Header: base.Header{ "Transport": headers.Transport{ @@ -1518,16 +1586,18 @@ func TestClientReadRedirect(t *testing.T) { ServerPorts: &[2]int{34556, 34557}, }.Write(), }, - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) - req, err = readRequest(bconn.Reader) + req, err = readRequest(br) require.NoError(t, err) require.Equal(t, base.Play, req.Method) - err = base.Response{ + base.Response{ StatusCode: base.StatusOK, - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) time.Sleep(500 * time.Millisecond) @@ -1558,7 +1628,7 @@ func TestClientReadRedirect(t *testing.T) { } func TestClientReadPause(t *testing.T) { - writeFrames := func(inTH *headers.Transport, bconn *bufio.ReadWriter) (chan struct{}, chan struct{}) { + writeFrames := func(inTH *headers.Transport, conn net.Conn, br *bufio.Reader) (chan struct{}, chan struct{}) { writerTerminate := make(chan struct{}) writerDone := make(chan struct{}) @@ -1572,6 +1642,7 @@ func TestClientReadPause(t *testing.T) { require.NoError(t, err) defer l1.Close() } + var bb bytes.Buffer t := time.NewTicker(50 * time.Millisecond) defer t.Stop() @@ -1588,7 +1659,8 @@ func TestClientReadPause(t *testing.T) { base.InterleavedFrame{ Channel: 0, Payload: []byte("\x00\x00\x00\x00"), - }.Write(bconn.Writer) + }.Write(&bb) + conn.Write(bb.Bytes()) } case <-writerTerminate: @@ -1617,13 +1689,14 @@ func TestClientReadPause(t *testing.T) { conn, err := l.Accept() require.NoError(t, err) defer conn.Close() - bconn := bufio.NewReadWriter(bufio.NewReader(conn), bufio.NewWriter(conn)) + br := bufio.NewReader(conn) + var bb bytes.Buffer - req, err := readRequest(bconn.Reader) + req, err := readRequest(br) require.NoError(t, err) require.Equal(t, base.Options, req.Method) - err = base.Response{ + base.Response{ StatusCode: base.StatusOK, Header: base.Header{ "Public": base.HeaderValue{strings.Join([]string{ @@ -1632,10 +1705,11 @@ func TestClientReadPause(t *testing.T) { string(base.Play), }, ", ")}, }, - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) - req, err = readRequest(bconn.Reader) + req, err = readRequest(br) require.NoError(t, err) require.Equal(t, base.Describe, req.Method) @@ -1646,17 +1720,18 @@ func TestClientReadPause(t *testing.T) { tracks := cloneAndClearTracks(Tracks{track}) - err = base.Response{ + base.Response{ StatusCode: base.StatusOK, Header: base.Header{ "Content-Type": base.HeaderValue{"application/sdp"}, "Content-Base": base.HeaderValue{"rtsp://localhost:8554/teststream/"}, }, Body: tracks.Write(false), - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) - req, err = readRequest(bconn.Reader) + req, err = readRequest(br) require.NoError(t, err) require.Equal(t, base.Setup, req.Method) @@ -1680,58 +1755,63 @@ func TestClientReadPause(t *testing.T) { th.InterleavedIDs = inTH.InterleavedIDs } - err = base.Response{ + base.Response{ StatusCode: base.StatusOK, Header: base.Header{ "Transport": th.Write(), }, - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) - req, err = readRequest(bconn.Reader) + req, err = readRequest(br) require.NoError(t, err) require.Equal(t, base.Play, req.Method) - err = base.Response{ + base.Response{ StatusCode: base.StatusOK, - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) - writerTerminate, writerDone := writeFrames(&inTH, bconn) + writerTerminate, writerDone := writeFrames(&inTH, conn, br) - req, err = readRequest(bconn.Reader) + req, err = readRequest(br) require.NoError(t, err) require.Equal(t, base.Pause, req.Method) close(writerTerminate) <-writerDone - err = base.Response{ + base.Response{ StatusCode: base.StatusOK, - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) - req, err = readRequest(bconn.Reader) + req, err = readRequest(br) require.NoError(t, err) require.Equal(t, base.Play, req.Method) - err = base.Response{ + base.Response{ StatusCode: base.StatusOK, - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) - writerTerminate, writerDone = writeFrames(&inTH, bconn) + writerTerminate, writerDone = writeFrames(&inTH, conn, br) - req, err = readRequest(bconn.Reader) + req, err = readRequest(br) require.NoError(t, err) require.Equal(t, base.Teardown, req.Method) close(writerTerminate) <-writerDone - err = base.Response{ + base.Response{ StatusCode: base.StatusOK, - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) }() @@ -1789,13 +1869,14 @@ func TestClientReadRTCPReport(t *testing.T) { conn, err := l.Accept() require.NoError(t, err) defer conn.Close() - bconn := bufio.NewReadWriter(bufio.NewReader(conn), bufio.NewWriter(conn)) + br := bufio.NewReader(conn) + var bb bytes.Buffer - req, err := readRequest(bconn.Reader) + req, err := readRequest(br) require.NoError(t, err) require.Equal(t, base.Options, req.Method) - err = base.Response{ + base.Response{ StatusCode: base.StatusOK, Header: base.Header{ "Public": base.HeaderValue{strings.Join([]string{ @@ -1804,10 +1885,11 @@ func TestClientReadRTCPReport(t *testing.T) { string(base.Play), }, ", ")}, }, - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) - req, err = readRequest(bconn.Reader) + req, err = readRequest(br) require.NoError(t, err) require.Equal(t, base.Describe, req.Method) @@ -1818,17 +1900,18 @@ func TestClientReadRTCPReport(t *testing.T) { tracks := cloneAndClearTracks(Tracks{track}) - err = base.Response{ + base.Response{ StatusCode: base.StatusOK, Header: base.Header{ "Content-Type": base.HeaderValue{"application/sdp"}, "Content-Base": base.HeaderValue{"rtsp://localhost:8554/teststream/"}, }, Body: tracks.Write(false), - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) - req, err = readRequest(bconn.Reader) + req, err = readRequest(br) require.NoError(t, err) require.Equal(t, base.Setup, req.Method) @@ -1844,7 +1927,7 @@ func TestClientReadRTCPReport(t *testing.T) { require.NoError(t, err) defer l2.Close() - err = base.Response{ + base.Response{ StatusCode: base.StatusOK, Header: base.Header{ "Transport": headers.Transport{ @@ -1857,16 +1940,18 @@ func TestClientReadRTCPReport(t *testing.T) { ClientPorts: inTH.ClientPorts, }.Write(), }, - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) - req, err = readRequest(bconn.Reader) + req, err = readRequest(br) require.NoError(t, err) require.Equal(t, base.Play, req.Method) - err = base.Response{ + base.Response{ StatusCode: base.StatusOK, - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) // skip firewall opening @@ -1922,13 +2007,15 @@ func TestClientReadRTCPReport(t *testing.T) { close(reportReceived) - req, err = readRequest(bconn.Reader) + req, err = readRequest(br) require.NoError(t, err) require.Equal(t, base.Teardown, req.Method) base.Response{ StatusCode: base.StatusOK, - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) + require.NoError(t, err) }() c := &Client{ @@ -1961,13 +2048,14 @@ func TestClientReadErrorTimeout(t *testing.T) { conn, err := l.Accept() require.NoError(t, err) defer conn.Close() - bconn := bufio.NewReadWriter(bufio.NewReader(conn), bufio.NewWriter(conn)) + br := bufio.NewReader(conn) + var bb bytes.Buffer - req, err := readRequest(bconn.Reader) + req, err := readRequest(br) require.NoError(t, err) require.Equal(t, base.Options, req.Method) - err = base.Response{ + base.Response{ StatusCode: base.StatusOK, Header: base.Header{ "Public": base.HeaderValue{strings.Join([]string{ @@ -1976,10 +2064,11 @@ func TestClientReadErrorTimeout(t *testing.T) { string(base.Play), }, ", ")}, }, - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) - req, err = readRequest(bconn.Reader) + req, err = readRequest(br) require.NoError(t, err) require.Equal(t, base.Describe, req.Method) @@ -1990,17 +2079,18 @@ func TestClientReadErrorTimeout(t *testing.T) { tracks := cloneAndClearTracks(Tracks{track}) - err = base.Response{ + base.Response{ StatusCode: base.StatusOK, Header: base.Header{ "Content-Type": base.HeaderValue{"application/sdp"}, "Content-Base": base.HeaderValue{"rtsp://localhost:8554/teststream/"}, }, Body: tracks.Write(false), - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) - req, err = readRequest(bconn.Reader) + req, err = readRequest(br) require.NoError(t, err) require.Equal(t, base.Setup, req.Method) @@ -2030,21 +2120,23 @@ func TestClientReadErrorTimeout(t *testing.T) { th.InterleavedIDs = inTH.InterleavedIDs } - err = base.Response{ + base.Response{ StatusCode: base.StatusOK, Header: base.Header{ "Transport": th.Write(), }, - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) - req, err = readRequest(bconn.Reader) + req, err = readRequest(br) require.NoError(t, err) require.Equal(t, base.Play, req.Method) - err = base.Response{ + base.Response{ StatusCode: base.StatusOK, - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) if transport == "udp" || transport == "auto" { @@ -2055,13 +2147,14 @@ func TestClientReadErrorTimeout(t *testing.T) { }) } - req, err = readRequest(bconn.Reader) + req, err = readRequest(br) require.NoError(t, err) require.Equal(t, base.Teardown, req.Method) - err = base.Response{ + base.Response{ StatusCode: base.StatusOK, - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) }() @@ -2111,13 +2204,14 @@ func TestClientReadIgnoreTCPInvalidTrack(t *testing.T) { conn, err := l.Accept() require.NoError(t, err) defer conn.Close() - bconn := bufio.NewReadWriter(bufio.NewReader(conn), bufio.NewWriter(conn)) + br := bufio.NewReader(conn) + var bb bytes.Buffer - req, err := readRequest(bconn.Reader) + req, err := readRequest(br) require.NoError(t, err) require.Equal(t, base.Options, req.Method) - err = base.Response{ + base.Response{ StatusCode: base.StatusOK, Header: base.Header{ "Public": base.HeaderValue{strings.Join([]string{ @@ -2126,10 +2220,11 @@ func TestClientReadIgnoreTCPInvalidTrack(t *testing.T) { string(base.Play), }, ", ")}, }, - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) - req, err = readRequest(bconn.Reader) + req, err = readRequest(br) require.NoError(t, err) require.Equal(t, base.Describe, req.Method) @@ -2140,17 +2235,18 @@ func TestClientReadIgnoreTCPInvalidTrack(t *testing.T) { tracks := cloneAndClearTracks(Tracks{track}) - err = base.Response{ + base.Response{ StatusCode: base.StatusOK, Header: base.Header{ "Content-Type": base.HeaderValue{"application/sdp"}, "Content-Base": base.HeaderValue{"rtsp://localhost:8554/teststream/"}, }, Body: tracks.Write(false), - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) - req, err = readRequest(bconn.Reader) + req, err = readRequest(br) require.NoError(t, err) require.Equal(t, base.Setup, req.Method) @@ -2167,42 +2263,47 @@ func TestClientReadIgnoreTCPInvalidTrack(t *testing.T) { th.Protocol = headers.TransportProtocolTCP th.InterleavedIDs = inTH.InterleavedIDs - err = base.Response{ + base.Response{ StatusCode: base.StatusOK, Header: base.Header{ "Transport": th.Write(), }, - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) - req, err = readRequest(bconn.Reader) + req, err = readRequest(br) require.NoError(t, err) require.Equal(t, base.Play, req.Method) - err = base.Response{ + base.Response{ StatusCode: base.StatusOK, - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) - err = base.InterleavedFrame{ + base.InterleavedFrame{ Channel: 6, Payload: []byte{0x01, 0x02, 0x03, 0x04}, - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) - err = base.InterleavedFrame{ + base.InterleavedFrame{ Channel: 0, Payload: []byte{0x05, 0x06, 0x07, 0x08}, - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) - req, err = readRequest(bconn.Reader) + req, err = readRequest(br) require.NoError(t, err) require.Equal(t, base.Teardown, req.Method) - err = base.Response{ + base.Response{ StatusCode: base.StatusOK, - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) }() @@ -2238,13 +2339,14 @@ func TestClientReadSeek(t *testing.T) { conn, err := l.Accept() require.NoError(t, err) defer conn.Close() - bconn := bufio.NewReadWriter(bufio.NewReader(conn), bufio.NewWriter(conn)) + br := bufio.NewReader(conn) + var bb bytes.Buffer - req, err := readRequest(bconn.Reader) + req, err := readRequest(br) require.NoError(t, err) require.Equal(t, base.Options, req.Method) - err = base.Response{ + base.Response{ StatusCode: base.StatusOK, Header: base.Header{ "Public": base.HeaderValue{strings.Join([]string{ @@ -2253,10 +2355,11 @@ func TestClientReadSeek(t *testing.T) { string(base.Play), }, ", ")}, }, - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) - req, err = readRequest(bconn.Reader) + req, err = readRequest(br) require.NoError(t, err) require.Equal(t, base.Describe, req.Method) @@ -2267,17 +2370,18 @@ func TestClientReadSeek(t *testing.T) { tracks := cloneAndClearTracks(Tracks{track}) - err = base.Response{ + base.Response{ StatusCode: base.StatusOK, Header: base.Header{ "Content-Type": base.HeaderValue{"application/sdp"}, "Content-Base": base.HeaderValue{"rtsp://localhost:8554/teststream/"}, }, Body: tracks.Write(false), - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) - req, err = readRequest(bconn.Reader) + req, err = readRequest(br) require.NoError(t, err) require.Equal(t, base.Setup, req.Method) @@ -2294,15 +2398,16 @@ func TestClientReadSeek(t *testing.T) { InterleavedIDs: inTH.InterleavedIDs, } - err = base.Response{ + base.Response{ StatusCode: base.StatusOK, Header: base.Header{ "Transport": th.Write(), }, - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) - req, err = readRequest(bconn.Reader) + req, err = readRequest(br) require.NoError(t, err) require.Equal(t, base.Play, req.Method) @@ -2315,21 +2420,23 @@ func TestClientReadSeek(t *testing.T) { }, }, ra) - err = base.Response{ + base.Response{ StatusCode: base.StatusOK, - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) - req, err = readRequest(bconn.Reader) + req, err = readRequest(br) require.NoError(t, err) require.Equal(t, base.Pause, req.Method) - err = base.Response{ + base.Response{ StatusCode: base.StatusOK, - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) - req, err = readRequest(bconn.Reader) + req, err = readRequest(br) require.NoError(t, err) require.Equal(t, base.Play, req.Method) @@ -2341,18 +2448,20 @@ func TestClientReadSeek(t *testing.T) { }, }, ra) - err = base.Response{ + base.Response{ StatusCode: base.StatusOK, - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) - req, err = readRequest(bconn.Reader) + req, err = readRequest(br) require.NoError(t, err) require.Equal(t, base.Teardown, req.Method) - err = base.Response{ + base.Response{ StatusCode: base.StatusOK, - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) }() diff --git a/client_test.go b/client_test.go index cc19ea6f..05e25267 100644 --- a/client_test.go +++ b/client_test.go @@ -2,6 +2,7 @@ package gortsplib import ( "bufio" + "bytes" "crypto/tls" "net" "strings" @@ -93,14 +94,15 @@ func TestClientSession(t *testing.T) { conn, err := l.Accept() require.NoError(t, err) - bconn := bufio.NewReadWriter(bufio.NewReader(conn), bufio.NewWriter(conn)) + br := bufio.NewReader(conn) + var bb bytes.Buffer defer conn.Close() - req, err := readRequest(bconn.Reader) + req, err := readRequest(br) require.NoError(t, err) require.Equal(t, base.Options, req.Method) - err = base.Response{ + base.Response{ StatusCode: base.StatusOK, Header: base.Header{ "Public": base.HeaderValue{strings.Join([]string{ @@ -108,10 +110,11 @@ func TestClientSession(t *testing.T) { }, ", ")}, "Session": base.HeaderValue{"123456"}, }, - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) - req, err = readRequest(bconn.Reader) + req, err = readRequest(br) require.NoError(t, err) require.Equal(t, base.Describe, req.Method) @@ -124,14 +127,15 @@ func TestClientSession(t *testing.T) { tracks := cloneAndClearTracks(Tracks{track}) - err = base.Response{ + base.Response{ StatusCode: base.StatusOK, Header: base.Header{ "Content-Type": base.HeaderValue{"application/sdp"}, "Session": base.HeaderValue{"123456"}, }, Body: tracks.Write(false), - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) }() @@ -163,38 +167,41 @@ func TestClientAuth(t *testing.T) { conn, err := l.Accept() require.NoError(t, err) - bconn := bufio.NewReadWriter(bufio.NewReader(conn), bufio.NewWriter(conn)) + br := bufio.NewReader(conn) + var bb bytes.Buffer defer conn.Close() - req, err := readRequest(bconn.Reader) + req, err := readRequest(br) require.NoError(t, err) require.Equal(t, base.Options, req.Method) - err = base.Response{ + base.Response{ StatusCode: base.StatusOK, Header: base.Header{ "Public": base.HeaderValue{strings.Join([]string{ string(base.Describe), }, ", ")}, }, - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) - req, err = readRequest(bconn.Reader) + req, err = readRequest(br) require.NoError(t, err) require.Equal(t, base.Describe, req.Method) v := auth.NewValidator("myuser", "mypass", nil) - err = base.Response{ + base.Response{ StatusCode: base.StatusUnauthorized, Header: base.Header{ "WWW-Authenticate": v.Header(), }, - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) - req, err = readRequest(bconn.Reader) + req, err = readRequest(br) require.NoError(t, err) require.Equal(t, base.Describe, req.Method) @@ -208,13 +215,14 @@ func TestClientAuth(t *testing.T) { tracks := cloneAndClearTracks(Tracks{track}) - err = base.Response{ + base.Response{ StatusCode: base.StatusOK, Header: base.Header{ "Content-Type": base.HeaderValue{"application/sdp"}, }, Body: tracks.Write(false), - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) }() @@ -247,23 +255,25 @@ func TestClientDescribeCharset(t *testing.T) { conn, err := l.Accept() require.NoError(t, err) defer conn.Close() - bconn := bufio.NewReadWriter(bufio.NewReader(conn), bufio.NewWriter(conn)) + br := bufio.NewReader(conn) + var bb bytes.Buffer - req, err := readRequest(bconn.Reader) + req, err := readRequest(br) require.NoError(t, err) require.Equal(t, base.Options, req.Method) - err = base.Response{ + base.Response{ StatusCode: base.StatusOK, Header: base.Header{ "Public": base.HeaderValue{strings.Join([]string{ string(base.Describe), }, ", ")}, }, - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) - req, err = readRequest(bconn.Reader) + req, err = readRequest(br) require.NoError(t, err) require.Equal(t, base.Describe, req.Method) require.Equal(t, mustParseURL("rtsp://localhost:8554/teststream"), req.URL) @@ -273,14 +283,15 @@ func TestClientDescribeCharset(t *testing.T) { }) require.NoError(t, err) - err = base.Response{ + base.Response{ StatusCode: base.StatusOK, Header: base.Header{ "Content-Type": base.HeaderValue{"application/sdp; charset=utf-8"}, "Content-Base": base.HeaderValue{"rtsp://localhost:8554/teststream/"}, }, Body: Tracks{track1}.Write(false), - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) }() @@ -349,9 +360,9 @@ func TestClientCloseDuringRequest(t *testing.T) { conn, err := l.Accept() require.NoError(t, err) defer conn.Close() - bconn := bufio.NewReadWriter(bufio.NewReader(conn), bufio.NewWriter(conn)) + br := bufio.NewReader(conn) - req, err := readRequest(bconn.Reader) + req, err := readRequest(br) require.NoError(t, err) require.Equal(t, base.Options, req.Method) diff --git a/pkg/base/body.go b/pkg/base/body.go index d1abcb1e..33a39bd6 100644 --- a/pkg/base/body.go +++ b/pkg/base/body.go @@ -2,6 +2,7 @@ package base import ( "bufio" + "bytes" "fmt" "io" "strconv" @@ -35,15 +36,10 @@ func (b *body) read(header Header, rb *bufio.Reader) error { return nil } -func (b body) write(bw *bufio.Writer) error { +func (b body) write(bb *bytes.Buffer) { if len(b) == 0 { - return nil + return } - _, err := bw.Write(b) - if err != nil { - return err - } - - return nil + bb.Write(b) } diff --git a/pkg/base/body_test.go b/pkg/base/body_test.go index f31614d1..a4645015 100644 --- a/pkg/base/body_test.go +++ b/pkg/base/body_test.go @@ -3,25 +3,11 @@ package base import ( "bufio" "bytes" - "fmt" "testing" "github.com/stretchr/testify/require" ) -type limitedBuffer struct { - cap int - n int -} - -func (b *limitedBuffer) Write(p []byte) (int, error) { - b.n += len(p) - if b.n > b.cap { - return 0, fmt.Errorf("capacity reached") - } - return len(p), nil -} - var casesBody = []struct { name string h Header @@ -52,19 +38,6 @@ func TestBodyRead(t *testing.T) { } } -func TestBodyWrite(t *testing.T) { - for _, ca := range casesBody { - t.Run(ca.name, func(t *testing.T) { - var buf bytes.Buffer - bw := bufio.NewWriter(&buf) - err := body(ca.byts).write(bw) - require.NoError(t, err) - bw.Flush() - require.Equal(t, ca.byts, buf.Bytes()) - }) - } -} - func TestBodyReadErrors(t *testing.T) { for _, ca := range []struct { name string @@ -105,8 +78,12 @@ func TestBodyReadErrors(t *testing.T) { } } -func TestBodyWriteErrors(t *testing.T) { - bw := bufio.NewWriterSize(&limitedBuffer{cap: 3}, 1) - err := body([]byte("1234")).write(bw) - require.EqualError(t, err, "capacity reached") +func TestBodyWrite(t *testing.T) { + for _, ca := range casesBody { + t.Run(ca.name, func(t *testing.T) { + var buf bytes.Buffer + body(ca.byts).write(&buf) + require.Equal(t, ca.byts, buf.Bytes()) + }) + } } diff --git a/pkg/base/header.go b/pkg/base/header.go index d223a52d..d3b58f23 100644 --- a/pkg/base/header.go +++ b/pkg/base/header.go @@ -2,6 +2,7 @@ package base import ( "bufio" + "bytes" "fmt" "net/http" "sort" @@ -97,7 +98,7 @@ func (h *Header) read(rb *bufio.Reader) error { return nil } -func (h Header) write(wb *bufio.Writer) error { +func (h Header) write(bb *bytes.Buffer) { // sort headers by key // in order to obtain deterministic results keys := make([]string, len(h)) @@ -108,17 +109,9 @@ func (h Header) write(wb *bufio.Writer) error { for _, key := range keys { for _, val := range h[key] { - _, err := wb.Write([]byte(key + ": " + val + "\r\n")) - if err != nil { - return err - } + bb.Write([]byte(key + ": " + val + "\r\n")) } } - _, err := wb.Write([]byte("\r\n")) - if err != nil { - return err - } - - return nil + bb.Write([]byte("\r\n")) } diff --git a/pkg/base/header_test.go b/pkg/base/header_test.go index 214d4445..e8af434c 100644 --- a/pkg/base/header_test.go +++ b/pkg/base/header_test.go @@ -116,19 +116,6 @@ func TestHeaderRead(t *testing.T) { } } -func TestHeaderWrite(t *testing.T) { - for _, ca := range casesHeader { - t.Run(ca.name, func(t *testing.T) { - var buf bytes.Buffer - bw := bufio.NewWriter(&buf) - err := ca.header.write(bw) - require.NoError(t, err) - bw.Flush() - require.Equal(t, ca.enc, buf.Bytes()) - }) - } -} - func TestHeaderReadErrors(t *testing.T) { for _, ca := range []struct { name string @@ -186,26 +173,12 @@ func TestHeaderReadErrors(t *testing.T) { } } -func TestHeaderWriteErrors(t *testing.T) { - for _, ca := range []struct { - name string - cap int - }{ - { - "values", - 3, - }, - { - "final newline", - 12, - }, - } { +func TestHeaderWrite(t *testing.T) { + for _, ca := range casesHeader { t.Run(ca.name, func(t *testing.T) { - bw := bufio.NewWriterSize(&limitedBuffer{cap: ca.cap}, 1) - err := Header{ - "Value": HeaderValue{"key"}, - }.write(bw) - require.EqualError(t, err, "capacity reached") + var buf bytes.Buffer + ca.header.write(&buf) + require.Equal(t, ca.enc, buf.Bytes()) }) } } diff --git a/pkg/base/interleavedframe.go b/pkg/base/interleavedframe.go index 613d4312..55bc175a 100644 --- a/pkg/base/interleavedframe.go +++ b/pkg/base/interleavedframe.go @@ -2,6 +2,7 @@ package base import ( "bufio" + "bytes" "encoding/binary" "fmt" "io" @@ -96,19 +97,13 @@ func (f *InterleavedFrame) Read(br *bufio.Reader) error { } // Write writes an InterleavedFrame into a buffered writer. -func (f InterleavedFrame) Write(bw *bufio.Writer) error { +func (f InterleavedFrame) Write(bb *bytes.Buffer) { + bb.Reset() + buf := []byte{0x24, byte(f.Channel), 0x00, 0x00} binary.BigEndian.PutUint16(buf[2:], uint16(len(f.Payload))) - _, err := bw.Write(buf) - if err != nil { - return err - } + bb.Write(buf) - _, err = bw.Write(f.Payload) - if err != nil { - return err - } - - return bw.Flush() + bb.Write(f.Payload) } diff --git a/pkg/base/interleavedframe_test.go b/pkg/base/interleavedframe_test.go index 86d31ac0..ed887eec 100644 --- a/pkg/base/interleavedframe_test.go +++ b/pkg/base/interleavedframe_test.go @@ -45,19 +45,6 @@ func TestInterleavedFrameRead(t *testing.T) { } } -func TestInterleavedFrameWrite(t *testing.T) { - for _, ca := range casesInterleavedFrame { - t.Run(ca.name, func(t *testing.T) { - var buf bytes.Buffer - bw := bufio.NewWriter(&buf) - err := ca.dec.Write(bw) - require.NoError(t, err) - bw.Flush() - require.Equal(t, ca.enc, buf.Bytes()) - }) - } -} - func TestInterleavedFrameReadErrors(t *testing.T) { for _, ca := range []struct { name string @@ -94,27 +81,12 @@ func TestInterleavedFrameReadErrors(t *testing.T) { } } -func TestInterleavedFrameWriteErrors(t *testing.T) { - for _, ca := range []struct { - name string - cap int - }{ - { - "header", - 3, - }, - { - "content", - 6, - }, - } { +func TestInterleavedFrameWrite(t *testing.T) { + for _, ca := range casesInterleavedFrame { t.Run(ca.name, func(t *testing.T) { - bw := bufio.NewWriterSize(&limitedBuffer{cap: ca.cap}, 1) - err := InterleavedFrame{ - Channel: 3, - Payload: []byte{0x01, 0x02, 0x03, 0x04}, - }.Write(bw) - require.EqualError(t, err, "capacity reached") + var buf bytes.Buffer + ca.dec.Write(&buf) + require.Equal(t, ca.enc, buf.Bytes()) }) } } diff --git a/pkg/base/request.go b/pkg/base/request.go index b998ec59..7739b53e 100644 --- a/pkg/base/request.go +++ b/pkg/base/request.go @@ -121,33 +121,24 @@ func (req *Request) ReadIgnoreFrames(rb *bufio.Reader, buf []byte) error { } // Write writes a request. -func (req Request) Write(bw *bufio.Writer) error { +func (req Request) Write(bb *bytes.Buffer) { + bb.Reset() + urStr := req.URL.CloneWithoutCredentials().String() - _, err := bw.Write([]byte(string(req.Method) + " " + urStr + " " + rtspProtocol10 + "\r\n")) - if err != nil { - return err - } + bb.Write([]byte(string(req.Method) + " " + urStr + " " + rtspProtocol10 + "\r\n")) if len(req.Body) != 0 { req.Header["Content-Length"] = HeaderValue{strconv.FormatInt(int64(len(req.Body)), 10)} } - err = req.Header.write(bw) - if err != nil { - return err - } + req.Header.write(bb) - err = body(req.Body).write(bw) - if err != nil { - return err - } - - return bw.Flush() + body(req.Body).write(bb) } // String implements fmt.Stringer. func (req Request) String() string { - buf := bytes.NewBuffer(nil) - req.Write(bufio.NewWriter(buf)) + var buf bytes.Buffer + req.Write(&buf) return buf.String() } diff --git a/pkg/base/request_test.go b/pkg/base/request_test.go index 41472ef1..32bd6d7b 100644 --- a/pkg/base/request_test.go +++ b/pkg/base/request_test.go @@ -143,19 +143,6 @@ func TestRequestRead(t *testing.T) { } } -func TestRequestWrite(t *testing.T) { - for _, ca := range casesRequest { - t.Run(ca.name, func(t *testing.T) { - var buf bytes.Buffer - bw := bufio.NewWriter(&buf) - err := ca.req.Write(bw) - require.NoError(t, err) - // do NOT call flush(), write() must have already done it - require.Equal(t, ca.byts, buf.Bytes()) - }) - } -} - func TestRequestReadErrors(t *testing.T) { for _, ca := range []struct { name string @@ -231,35 +218,12 @@ func TestRequestReadErrors(t *testing.T) { } } -func TestRequestWriteErrors(t *testing.T) { - for _, ca := range []struct { - name string - cap int - }{ - { - "first line", - 3, - }, - { - "header", - 53, - }, - { - "body", - 80, - }, - } { +func TestRequestWrite(t *testing.T) { + for _, ca := range casesRequest { t.Run(ca.name, func(t *testing.T) { - bw := bufio.NewWriterSize(&limitedBuffer{cap: ca.cap}, 1) - err := Request{ - Method: "ANNOUNCE", - URL: mustParseURL("rtsp://example.com/media.mp4"), - Header: Header{ - "CSeq": HeaderValue{"7"}, - }, - Body: []byte("abc"), - }.Write(bw) - require.EqualError(t, err, "capacity reached") + var buf bytes.Buffer + ca.req.Write(&buf) + require.Equal(t, ca.byts, buf.Bytes()) }) } } diff --git a/pkg/base/response.go b/pkg/base/response.go index 3f15e6b9..8ab7c959 100644 --- a/pkg/base/response.go +++ b/pkg/base/response.go @@ -207,40 +207,31 @@ func (res *Response) ReadIgnoreFrames(rb *bufio.Reader, buf []byte) error { } // Write writes a Response. -func (res Response) Write(bw *bufio.Writer) error { +func (res Response) Write(bb *bytes.Buffer) { + bb.Reset() + if res.StatusMessage == "" { if status, ok := statusMessages[res.StatusCode]; ok { res.StatusMessage = status } } - _, err := bw.Write([]byte(rtspProtocol10 + " " + + bb.Write([]byte(rtspProtocol10 + " " + strconv.FormatInt(int64(res.StatusCode), 10) + " " + res.StatusMessage + "\r\n")) - if err != nil { - return err - } if len(res.Body) != 0 { res.Header["Content-Length"] = HeaderValue{strconv.FormatInt(int64(len(res.Body)), 10)} } - err = res.Header.write(bw) - if err != nil { - return err - } + res.Header.write(bb) - err = body(res.Body).write(bw) - if err != nil { - return err - } - - return bw.Flush() + body(res.Body).write(bb) } // String implements fmt.Stringer. func (res Response) String() string { - buf := bytes.NewBuffer(nil) - res.Write(bufio.NewWriter(buf)) + var buf bytes.Buffer + res.Write(&buf) return buf.String() } diff --git a/pkg/base/response_test.go b/pkg/base/response_test.go index 8ee89125..f868299c 100644 --- a/pkg/base/response_test.go +++ b/pkg/base/response_test.go @@ -105,19 +105,6 @@ func TestResponseRead(t *testing.T) { } } -func TestResponseWrite(t *testing.T) { - for _, c := range casesResponse { - t.Run(c.name, func(t *testing.T) { - var buf bytes.Buffer - bw := bufio.NewWriter(&buf) - err := c.res.Write(bw) - require.NoError(t, err) - // do NOT call flush(), write() must have already done it - require.Equal(t, c.byts, buf.Bytes()) - }) - } -} - func TestResponseReadErrors(t *testing.T) { for _, ca := range []struct { name string @@ -188,35 +175,12 @@ func TestResponseReadErrors(t *testing.T) { } } -func TestResponseWriteErrors(t *testing.T) { - for _, ca := range []struct { - name string - cap int - }{ - { - "first line", - 14, - }, - { - "header", - 21, - }, - { - "body", - 49, - }, - } { - t.Run(ca.name, func(t *testing.T) { - bw := bufio.NewWriterSize(&limitedBuffer{cap: ca.cap}, 1) - err := Response{ - StatusCode: 200, - StatusMessage: "OK", - Header: Header{ - "CSeq": HeaderValue{"2"}, - }, - Body: []byte("abc"), - }.Write(bw) - require.EqualError(t, err, "capacity reached") +func TestResponseWrite(t *testing.T) { + for _, c := range casesResponse { + t.Run(c.name, func(t *testing.T) { + var buf bytes.Buffer + c.res.Write(&buf) + require.Equal(t, c.byts, buf.Bytes()) }) } } @@ -244,9 +208,7 @@ func TestResponseWriteAutoFillStatus(t *testing.T) { ) var buf bytes.Buffer - bw := bufio.NewWriter(&buf) - err := res.Write(bw) - require.NoError(t, err) + res.Write(&buf) require.Equal(t, byts, buf.Bytes()) } diff --git a/server.go b/server.go index dd254f23..7c29e2f6 100644 --- a/server.go +++ b/server.go @@ -17,7 +17,6 @@ import ( const ( serverReadBufferSize = 4096 - serverWriteBufferSize = 4096 serverUDPKernelReadBufferSize = 0x80000 // same as gstreamer's rtspsrc ) diff --git a/server_publish_test.go b/server_publish_test.go index 1501b8ec..20eb40d5 100644 --- a/server_publish_test.go +++ b/server_publish_test.go @@ -171,9 +171,9 @@ func TestServerPublishErrorAnnounce(t *testing.T) { conn, err := net.Dial("tcp", "localhost:8554") require.NoError(t, err) defer conn.Close() - bconn := bufio.NewReadWriter(bufio.NewReader(conn), bufio.NewWriter(conn)) + br := bufio.NewReader(conn) - _, err = writeReqReadRes(bconn, ca.req) + _, err = writeReqReadRes(conn, br, ca.req) require.NoError(t, err) <-connClosed @@ -258,7 +258,7 @@ func TestServerPublishSetupPath(t *testing.T) { conn, err := net.Dial("tcp", "localhost:8554") require.NoError(t, err) defer conn.Close() - bconn := bufio.NewReadWriter(bufio.NewReader(conn), bufio.NewWriter(conn)) + br := bufio.NewReader(conn) track, err := NewTrackH264(96, &TrackConfigH264{ []byte{0x01, 0x02, 0x03, 0x04}, []byte{0x01, 0x02, 0x03, 0x04}, @@ -287,7 +287,7 @@ func TestServerPublishSetupPath(t *testing.T) { byts, _ := sout.Marshal() - res, err := writeReqReadRes(bconn, base.Request{ + res, err := writeReqReadRes(conn, br, base.Request{ Method: base.Announce, URL: mustParseURL("rtsp://localhost:8554/" + ca.path), Header: base.Header{ @@ -312,7 +312,7 @@ func TestServerPublishSetupPath(t *testing.T) { InterleavedIDs: &[2]int{0, 1}, } - res, err = writeReqReadRes(bconn, base.Request{ + res, err = writeReqReadRes(conn, br, base.Request{ Method: base.Setup, URL: mustParseURL(ca.url), Header: base.Header{ @@ -356,7 +356,7 @@ func TestServerPublishErrorSetupDifferentPaths(t *testing.T) { conn, err := net.Dial("tcp", "localhost:8554") require.NoError(t, err) defer conn.Close() - bconn := bufio.NewReadWriter(bufio.NewReader(conn), bufio.NewWriter(conn)) + br := bufio.NewReader(conn) track, err := NewTrackH264(96, &TrackConfigH264{ []byte{0x01, 0x02, 0x03, 0x04}, []byte{0x01, 0x02, 0x03, 0x04}, @@ -371,7 +371,7 @@ func TestServerPublishErrorSetupDifferentPaths(t *testing.T) { }) } - res, err := writeReqReadRes(bconn, base.Request{ + res, err := writeReqReadRes(conn, br, base.Request{ Method: base.Announce, URL: mustParseURL("rtsp://localhost:8554/teststream"), Header: base.Header{ @@ -396,7 +396,7 @@ func TestServerPublishErrorSetupDifferentPaths(t *testing.T) { InterleavedIDs: &[2]int{0, 1}, } - res, err = writeReqReadRes(bconn, base.Request{ + res, err = writeReqReadRes(conn, br, base.Request{ Method: base.Setup, URL: mustParseURL("rtsp://localhost:8554/test2stream/trackID=0"), Header: base.Header{ @@ -441,7 +441,7 @@ func TestServerPublishErrorSetupTrackTwice(t *testing.T) { conn, err := net.Dial("tcp", "localhost:8554") require.NoError(t, err) defer conn.Close() - bconn := bufio.NewReadWriter(bufio.NewReader(conn), bufio.NewWriter(conn)) + br := bufio.NewReader(conn) track, err := NewTrackH264(96, &TrackConfigH264{ []byte{0x01, 0x02, 0x03, 0x04}, []byte{0x01, 0x02, 0x03, 0x04}, @@ -456,7 +456,7 @@ func TestServerPublishErrorSetupTrackTwice(t *testing.T) { }) } - res, err := writeReqReadRes(bconn, base.Request{ + res, err := writeReqReadRes(conn, br, base.Request{ Method: base.Announce, URL: mustParseURL("rtsp://localhost:8554/teststream"), Header: base.Header{ @@ -481,7 +481,7 @@ func TestServerPublishErrorSetupTrackTwice(t *testing.T) { InterleavedIDs: &[2]int{0, 1}, } - res, err = writeReqReadRes(bconn, base.Request{ + res, err = writeReqReadRes(conn, br, base.Request{ Method: base.Setup, URL: mustParseURL("rtsp://localhost:8554/teststream/trackID=0"), Header: base.Header{ @@ -493,7 +493,7 @@ func TestServerPublishErrorSetupTrackTwice(t *testing.T) { require.NoError(t, err) require.Equal(t, base.StatusOK, res.StatusCode) - res, err = writeReqReadRes(bconn, base.Request{ + res, err = writeReqReadRes(conn, br, base.Request{ Method: base.Setup, URL: mustParseURL("rtsp://localhost:8554/teststream/trackID=0"), Header: base.Header{ @@ -543,7 +543,7 @@ func TestServerPublishErrorRecordPartialTracks(t *testing.T) { conn, err := net.Dial("tcp", "localhost:8554") require.NoError(t, err) defer conn.Close() - bconn := bufio.NewReadWriter(bufio.NewReader(conn), bufio.NewWriter(conn)) + br := bufio.NewReader(conn) track1, err := NewTrackH264(96, &TrackConfigH264{ []byte{0x01, 0x02, 0x03, 0x04}, []byte{0x01, 0x02, 0x03, 0x04}, @@ -563,7 +563,7 @@ func TestServerPublishErrorRecordPartialTracks(t *testing.T) { }) } - res, err := writeReqReadRes(bconn, base.Request{ + res, err := writeReqReadRes(conn, br, base.Request{ Method: base.Announce, URL: mustParseURL("rtsp://localhost:8554/teststream"), Header: base.Header{ @@ -588,7 +588,7 @@ func TestServerPublishErrorRecordPartialTracks(t *testing.T) { InterleavedIDs: &[2]int{0, 1}, } - res, err = writeReqReadRes(bconn, base.Request{ + res, err = writeReqReadRes(conn, br, base.Request{ Method: base.Setup, URL: mustParseURL("rtsp://localhost:8554/teststream/trackID=0"), Header: base.Header{ @@ -600,7 +600,7 @@ func TestServerPublishErrorRecordPartialTracks(t *testing.T) { require.NoError(t, err) require.Equal(t, base.StatusOK, res.StatusCode) - res, err = writeReqReadRes(bconn, base.Request{ + res, err = writeReqReadRes(conn, br, base.Request{ Method: base.Record, URL: mustParseURL("rtsp://localhost:8554/teststream"), Header: base.Header{ @@ -684,17 +684,18 @@ func TestServerPublish(t *testing.T) { require.NoError(t, err) defer s.Close() - nconn, err := net.Dial("tcp", "localhost:8554") + conn, err := net.Dial("tcp", "localhost:8554") require.NoError(t, err) - defer nconn.Close() + defer conn.Close() - conn := func() net.Conn { + conn = func() net.Conn { if transport == "tls" { - return tls.Client(nconn, &tls.Config{InsecureSkipVerify: true}) + return tls.Client(conn, &tls.Config{InsecureSkipVerify: true}) } - return nconn + return conn }() - bconn := bufio.NewReadWriter(bufio.NewReader(conn), bufio.NewWriter(conn)) + br := bufio.NewReader(conn) + var bb bytes.Buffer <-connOpened @@ -711,7 +712,7 @@ func TestServerPublish(t *testing.T) { }) } - res, err := writeReqReadRes(bconn, base.Request{ + res, err := writeReqReadRes(conn, br, base.Request{ Method: base.Announce, URL: mustParseURL("rtsp://localhost:8554/teststream"), Header: base.Header{ @@ -755,7 +756,7 @@ func TestServerPublish(t *testing.T) { inTH.InterleavedIDs = &[2]int{0, 1} } - res, err = writeReqReadRes(bconn, base.Request{ + res, err = writeReqReadRes(conn, br, base.Request{ Method: base.Setup, URL: mustParseURL("rtsp://localhost:8554/teststream/trackID=0"), Header: base.Header{ @@ -771,7 +772,7 @@ func TestServerPublish(t *testing.T) { err = th.Read(res.Header["Transport"]) require.NoError(t, err) - res, err = writeReqReadRes(bconn, base.Request{ + res, err = writeReqReadRes(conn, br, base.Request{ Method: base.Record, URL: mustParseURL("rtsp://localhost:8554/teststream"), Header: base.Header{ @@ -798,16 +799,18 @@ func TestServerPublish(t *testing.T) { Port: th.ServerPorts[1], }) } else { - err = base.InterleavedFrame{ + base.InterleavedFrame{ Channel: 0, Payload: []byte{0x01, 0x02, 0x03, 0x04}, - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) - err = base.InterleavedFrame{ + base.InterleavedFrame{ Channel: 1, Payload: []byte{0x05, 0x06, 0x07, 0x08}, - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) } @@ -825,13 +828,13 @@ func TestServerPublish(t *testing.T) { } else { var f base.InterleavedFrame f.Payload = make([]byte, 2048) - err := f.Read(bconn.Reader) + err := f.Read(br) require.NoError(t, err) require.Equal(t, 1, f.Channel) require.Equal(t, []byte{0x09, 0x0A, 0x0B, 0x0C}, f.Payload) } - res, err = writeReqReadRes(bconn, base.Request{ + res, err = writeReqReadRes(conn, br, base.Request{ Method: base.Teardown, URL: mustParseURL("rtsp://localhost:8554/teststream"), Header: base.Header{ @@ -885,10 +888,11 @@ func TestServerPublishNonStandardFrameSize(t *testing.T) { require.NoError(t, err) defer s.Close() - nconn, err := net.Dial("tcp", "localhost:8554") + conn, err := net.Dial("tcp", "localhost:8554") require.NoError(t, err) - defer nconn.Close() - bconn := bufio.NewReadWriter(bufio.NewReader(nconn), bufio.NewWriter(nconn)) + defer conn.Close() + br := bufio.NewReader(conn) + var bb bytes.Buffer track, err := NewTrackH264(96, &TrackConfigH264{ []byte{0x01, 0x02, 0x03, 0x04}, []byte{0x01, 0x02, 0x03, 0x04}, @@ -900,7 +904,7 @@ func TestServerPublishNonStandardFrameSize(t *testing.T) { Value: "trackID=0", }) - res, err := writeReqReadRes(bconn, base.Request{ + res, err := writeReqReadRes(conn, br, base.Request{ Method: base.Announce, URL: mustParseURL("rtsp://localhost:8554/teststream"), Header: base.Header{ @@ -925,7 +929,7 @@ func TestServerPublishNonStandardFrameSize(t *testing.T) { InterleavedIDs: &[2]int{0, 1}, } - res, err = writeReqReadRes(bconn, base.Request{ + res, err = writeReqReadRes(conn, br, base.Request{ Method: base.Setup, URL: mustParseURL("rtsp://localhost:8554/teststream/trackID=0"), Header: base.Header{ @@ -937,7 +941,7 @@ func TestServerPublishNonStandardFrameSize(t *testing.T) { require.NoError(t, err) require.Equal(t, base.StatusOK, res.StatusCode) - res, err = writeReqReadRes(bconn, base.Request{ + res, err = writeReqReadRes(conn, br, base.Request{ Method: base.Record, URL: mustParseURL("rtsp://localhost:8554/teststream"), Header: base.Header{ @@ -948,10 +952,11 @@ func TestServerPublishNonStandardFrameSize(t *testing.T) { require.NoError(t, err) require.Equal(t, base.StatusOK, res.StatusCode) - err = base.InterleavedFrame{ + base.InterleavedFrame{ Channel: 0, Payload: payload, - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) <-frameReceived @@ -991,7 +996,8 @@ func TestServerPublishErrorInvalidProtocol(t *testing.T) { conn, err := net.Dial("tcp", "localhost:8554") require.NoError(t, err) defer conn.Close() - bconn := bufio.NewReadWriter(bufio.NewReader(conn), bufio.NewWriter(conn)) + br := bufio.NewReader(conn) + var bb bytes.Buffer track, err := NewTrackH264(96, &TrackConfigH264{ []byte{0x01, 0x02, 0x03, 0x04}, []byte{0x01, 0x02, 0x03, 0x04}, @@ -1006,7 +1012,7 @@ func TestServerPublishErrorInvalidProtocol(t *testing.T) { }) } - res, err := writeReqReadRes(bconn, base.Request{ + res, err := writeReqReadRes(conn, br, base.Request{ Method: base.Announce, URL: mustParseURL("rtsp://localhost:8554/teststream"), Header: base.Header{ @@ -1031,7 +1037,7 @@ func TestServerPublishErrorInvalidProtocol(t *testing.T) { ClientPorts: &[2]int{35466, 35467}, } - res, err = writeReqReadRes(bconn, base.Request{ + res, err = writeReqReadRes(conn, br, base.Request{ Method: base.Setup, URL: mustParseURL("rtsp://localhost:8554/teststream/trackID=0"), Header: base.Header{ @@ -1047,7 +1053,7 @@ func TestServerPublishErrorInvalidProtocol(t *testing.T) { err = th.Read(res.Header["Transport"]) require.NoError(t, err) - res, err = writeReqReadRes(bconn, base.Request{ + res, err = writeReqReadRes(conn, br, base.Request{ Method: base.Record, URL: mustParseURL("rtsp://localhost:8554/teststream"), Header: base.Header{ @@ -1058,10 +1064,11 @@ func TestServerPublishErrorInvalidProtocol(t *testing.T) { require.NoError(t, err) require.Equal(t, base.StatusOK, res.StatusCode) - err = base.InterleavedFrame{ + base.InterleavedFrame{ Channel: 0, Payload: []byte{0x01, 0x02, 0x03, 0x04}, - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) } @@ -1097,7 +1104,7 @@ func TestServerPublishRTCPReport(t *testing.T) { conn, err := net.Dial("tcp", "localhost:8554") require.NoError(t, err) defer conn.Close() - bconn := bufio.NewReadWriter(bufio.NewReader(conn), bufio.NewWriter(conn)) + br := bufio.NewReader(conn) track, err := NewTrackH264(96, &TrackConfigH264{ []byte{0x01, 0x02, 0x03, 0x04}, []byte{0x01, 0x02, 0x03, 0x04}, @@ -1112,7 +1119,7 @@ func TestServerPublishRTCPReport(t *testing.T) { }) } - res, err := writeReqReadRes(bconn, base.Request{ + res, err := writeReqReadRes(conn, br, base.Request{ Method: base.Announce, URL: mustParseURL("rtsp://localhost:8554/teststream"), Header: base.Header{ @@ -1132,7 +1139,7 @@ func TestServerPublishRTCPReport(t *testing.T) { require.NoError(t, err) defer l2.Close() - res, err = writeReqReadRes(bconn, base.Request{ + res, err = writeReqReadRes(conn, br, base.Request{ Method: base.Setup, URL: mustParseURL("rtsp://localhost:8554/teststream/trackID=0"), Header: base.Header{ @@ -1159,7 +1166,7 @@ func TestServerPublishRTCPReport(t *testing.T) { err = th.Read(res.Header["Transport"]) require.NoError(t, err) - res, err = writeReqReadRes(bconn, base.Request{ + res, err = writeReqReadRes(conn, br, base.Request{ Method: base.Record, URL: mustParseURL("rtsp://localhost:8554/teststream"), Header: base.Header{ @@ -1272,10 +1279,10 @@ func TestServerPublishTimeout(t *testing.T) { require.NoError(t, err) defer s.Close() - nconn, err := net.Dial("tcp", "localhost:8554") + conn, err := net.Dial("tcp", "localhost:8554") require.NoError(t, err) - defer nconn.Close() - bconn := bufio.NewReadWriter(bufio.NewReader(nconn), bufio.NewWriter(nconn)) + defer conn.Close() + br := bufio.NewReader(conn) track, err := NewTrackH264(96, &TrackConfigH264{ []byte{0x01, 0x02, 0x03, 0x04}, []byte{0x01, 0x02, 0x03, 0x04}, @@ -1290,7 +1297,7 @@ func TestServerPublishTimeout(t *testing.T) { }) } - res, err := writeReqReadRes(bconn, base.Request{ + res, err := writeReqReadRes(conn, br, base.Request{ Method: base.Announce, URL: mustParseURL("rtsp://localhost:8554/teststream"), Header: base.Header{ @@ -1321,7 +1328,7 @@ func TestServerPublishTimeout(t *testing.T) { inTH.InterleavedIDs = &[2]int{0, 1} } - res, err = writeReqReadRes(bconn, base.Request{ + res, err = writeReqReadRes(conn, br, base.Request{ Method: base.Setup, URL: mustParseURL("rtsp://localhost:8554/teststream/trackID=0"), Header: base.Header{ @@ -1337,7 +1344,7 @@ func TestServerPublishTimeout(t *testing.T) { err = th.Read(res.Header["Transport"]) require.NoError(t, err) - res, err = writeReqReadRes(bconn, base.Request{ + res, err = writeReqReadRes(conn, br, base.Request{ Method: base.Record, URL: mustParseURL("rtsp://localhost:8554/teststream"), Header: base.Header{ @@ -1403,9 +1410,9 @@ func TestServerPublishWithoutTeardown(t *testing.T) { require.NoError(t, err) defer s.Close() - nconn, err := net.Dial("tcp", "localhost:8554") + conn, err := net.Dial("tcp", "localhost:8554") require.NoError(t, err) - bconn := bufio.NewReadWriter(bufio.NewReader(nconn), bufio.NewWriter(nconn)) + br := bufio.NewReader(conn) track, err := NewTrackH264(96, &TrackConfigH264{ []byte{0x01, 0x02, 0x03, 0x04}, []byte{0x01, 0x02, 0x03, 0x04}, @@ -1420,7 +1427,7 @@ func TestServerPublishWithoutTeardown(t *testing.T) { }) } - res, err := writeReqReadRes(bconn, base.Request{ + res, err := writeReqReadRes(conn, br, base.Request{ Method: base.Announce, URL: mustParseURL("rtsp://localhost:8554/teststream"), Header: base.Header{ @@ -1451,7 +1458,7 @@ func TestServerPublishWithoutTeardown(t *testing.T) { inTH.InterleavedIDs = &[2]int{0, 1} } - res, err = writeReqReadRes(bconn, base.Request{ + res, err = writeReqReadRes(conn, br, base.Request{ Method: base.Setup, URL: mustParseURL("rtsp://localhost:8554/teststream/trackID=0"), Header: base.Header{ @@ -1467,7 +1474,7 @@ func TestServerPublishWithoutTeardown(t *testing.T) { err = th.Read(res.Header["Transport"]) require.NoError(t, err) - res, err = writeReqReadRes(bconn, base.Request{ + res, err = writeReqReadRes(conn, br, base.Request{ Method: base.Record, URL: mustParseURL("rtsp://localhost:8554/teststream"), Header: base.Header{ @@ -1478,7 +1485,7 @@ func TestServerPublishWithoutTeardown(t *testing.T) { require.NoError(t, err) require.Equal(t, base.StatusOK, res.StatusCode) - nconn.Close() + conn.Close() <-sessionClosed <-connClosed @@ -1527,7 +1534,7 @@ func TestServerPublishUDPChangeConn(t *testing.T) { conn, err := net.Dial("tcp", "localhost:8554") require.NoError(t, err) defer conn.Close() - bconn := bufio.NewReadWriter(bufio.NewReader(conn), bufio.NewWriter(conn)) + br := bufio.NewReader(conn) track, err := NewTrackH264(96, &TrackConfigH264{ []byte{0x01, 0x02, 0x03, 0x04}, []byte{0x01, 0x02, 0x03, 0x04}, @@ -1542,7 +1549,7 @@ func TestServerPublishUDPChangeConn(t *testing.T) { }) } - res, err := writeReqReadRes(bconn, base.Request{ + res, err := writeReqReadRes(conn, br, base.Request{ Method: base.Announce, URL: mustParseURL("rtsp://localhost:8554/teststream"), Header: base.Header{ @@ -1567,7 +1574,7 @@ func TestServerPublishUDPChangeConn(t *testing.T) { ClientPorts: &[2]int{35466, 35467}, } - res, err = writeReqReadRes(bconn, base.Request{ + res, err = writeReqReadRes(conn, br, base.Request{ Method: base.Setup, URL: mustParseURL("rtsp://localhost:8554/teststream/trackID=0"), Header: base.Header{ @@ -1579,7 +1586,7 @@ func TestServerPublishUDPChangeConn(t *testing.T) { require.NoError(t, err) require.Equal(t, base.StatusOK, res.StatusCode) - res, err = writeReqReadRes(bconn, base.Request{ + res, err = writeReqReadRes(conn, br, base.Request{ Method: base.Record, URL: mustParseURL("rtsp://localhost:8554/teststream"), Header: base.Header{ @@ -1596,9 +1603,9 @@ func TestServerPublishUDPChangeConn(t *testing.T) { conn, err := net.Dial("tcp", "localhost:8554") require.NoError(t, err) defer conn.Close() - bconn := bufio.NewReadWriter(bufio.NewReader(conn), bufio.NewWriter(conn)) + br := bufio.NewReader(conn) - res, err := writeReqReadRes(bconn, base.Request{ + res, err := writeReqReadRes(conn, br, base.Request{ Method: base.GetParameter, URL: mustParseURL("rtsp://localhost:8554/teststream/"), Header: base.Header{ diff --git a/server_read_test.go b/server_read_test.go index 3c240977..c8e7b2f1 100644 --- a/server_read_test.go +++ b/server_read_test.go @@ -118,7 +118,7 @@ func TestServerReadSetupPath(t *testing.T) { conn, err := net.Dial("tcp", "localhost:8554") require.NoError(t, err) defer conn.Close() - bconn := bufio.NewReadWriter(bufio.NewReader(conn), bufio.NewWriter(conn)) + br := bufio.NewReader(conn) th := &headers.Transport{ Protocol: headers.TransportProtocolTCP, @@ -133,7 +133,7 @@ func TestServerReadSetupPath(t *testing.T) { InterleavedIDs: &[2]int{ca.trackID * 2, (ca.trackID * 2) + 1}, } - res, err := writeReqReadRes(bconn, base.Request{ + res, err := writeReqReadRes(conn, br, base.Request{ Method: base.Setup, URL: mustParseURL(ca.url), Header: base.Header{ @@ -185,7 +185,7 @@ func TestServerReadSetupErrors(t *testing.T) { conn, err := net.Dial("tcp", "localhost:8554") require.NoError(t, err) defer conn.Close() - bconn := bufio.NewReadWriter(bufio.NewReader(conn), bufio.NewWriter(conn)) + br := bufio.NewReader(conn) th := &headers.Transport{ Protocol: headers.TransportProtocolTCP, @@ -201,7 +201,7 @@ func TestServerReadSetupErrors(t *testing.T) { } if ca == "different paths" { - res, err := writeReqReadRes(bconn, base.Request{ + res, err := writeReqReadRes(conn, br, base.Request{ Method: base.Setup, URL: mustParseURL("rtsp://localhost:8554/teststream/trackID=0"), Header: base.Header{ @@ -214,7 +214,7 @@ func TestServerReadSetupErrors(t *testing.T) { th.InterleavedIDs = &[2]int{2, 3} - res, err = writeReqReadRes(bconn, base.Request{ + res, err = writeReqReadRes(conn, br, base.Request{ Method: base.Setup, URL: mustParseURL("rtsp://localhost:8554/test12stream/trackID=1"), Header: base.Header{ @@ -226,7 +226,7 @@ func TestServerReadSetupErrors(t *testing.T) { require.NoError(t, err) require.Equal(t, base.StatusBadRequest, res.StatusCode) } else { - res, err := writeReqReadRes(bconn, base.Request{ + res, err := writeReqReadRes(conn, br, base.Request{ Method: base.Setup, URL: mustParseURL("rtsp://localhost:8554/teststream/trackID=0"), Header: base.Header{ @@ -239,7 +239,7 @@ func TestServerReadSetupErrors(t *testing.T) { th.InterleavedIDs = &[2]int{2, 3} - res, err = writeReqReadRes(bconn, base.Request{ + res, err = writeReqReadRes(conn, br, base.Request{ Method: base.Setup, URL: mustParseURL("rtsp://localhost:8554/teststream/trackID=0"), Header: base.Header{ @@ -351,16 +351,17 @@ func TestServerRead(t *testing.T) { require.NoError(t, err) defer s.Close() - nconn, err := net.Dial("tcp", listenIP+":8554") + conn, err := net.Dial("tcp", listenIP+":8554") require.NoError(t, err) - conn := func() net.Conn { + conn = func() net.Conn { if transport == "tls" { - return tls.Client(nconn, &tls.Config{InsecureSkipVerify: true}) + return tls.Client(conn, &tls.Config{InsecureSkipVerify: true}) } - return nconn + return conn }() - bconn := bufio.NewReadWriter(bufio.NewReader(conn), bufio.NewWriter(conn)) + br := bufio.NewReader(conn) + var bb bytes.Buffer <-connOpened @@ -390,7 +391,7 @@ func TestServerRead(t *testing.T) { inTH.InterleavedIDs = &[2]int{4, 5} } - res, err := writeReqReadRes(bconn, base.Request{ + res, err := writeReqReadRes(conn, br, base.Request{ Method: base.Setup, URL: mustParseURL("rtsp://" + listenIP + ":8554/teststream/trackID=0"), Header: base.Header{ @@ -460,7 +461,7 @@ func TestServerRead(t *testing.T) { <-sessionOpened - res, err = writeReqReadRes(bconn, base.Request{ + res, err = writeReqReadRes(conn, br, base.Request{ Method: base.Play, URL: mustParseURL("rtsp://" + listenIP + ":8554/teststream"), Header: base.Header{ @@ -492,13 +493,13 @@ func TestServerRead(t *testing.T) { } else { var f base.InterleavedFrame f.Payload = make([]byte, 2048) - err := f.Read(bconn.Reader) + err := f.Read(br) require.NoError(t, err) require.Equal(t, 4, f.Channel) require.Equal(t, []byte{0x01, 0x02, 0x03, 0x04}, f.Payload) f.Payload = make([]byte, 2048) - err = f.Read(bconn.Reader) + err = f.Read(br) require.NoError(t, err) require.Equal(t, 5, f.Channel) require.Equal(t, []byte{0x05, 0x06, 0x07, 0x08}, f.Payload) @@ -521,17 +522,18 @@ func TestServerRead(t *testing.T) { <-framesReceived default: - err = base.InterleavedFrame{ + base.InterleavedFrame{ Channel: 5, Payload: []byte{0x01, 0x02, 0x03, 0x04}, - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) <-framesReceived } if transport == "udp" || transport == "multicast" { // ping with OPTIONS - res, err = writeReqReadRes(bconn, base.Request{ + res, err = writeReqReadRes(conn, br, base.Request{ Method: base.Options, URL: mustParseURL("rtsp://" + listenIP + ":8554/teststream"), Header: base.Header{ @@ -543,7 +545,7 @@ func TestServerRead(t *testing.T) { require.Equal(t, base.StatusOK, res.StatusCode) // ping with GET_PARAMETER - res, err = writeReqReadRes(bconn, base.Request{ + res, err = writeReqReadRes(conn, br, base.Request{ Method: base.GetParameter, URL: mustParseURL("rtsp://" + listenIP + ":8554/teststream"), Header: base.Header{ @@ -555,7 +557,7 @@ func TestServerRead(t *testing.T) { require.Equal(t, base.StatusOK, res.StatusCode) } - res, err = writeReqReadRes(bconn, base.Request{ + res, err = writeReqReadRes(conn, br, base.Request{ Method: base.Teardown, URL: mustParseURL("rtsp://" + listenIP + ":8554/teststream"), Header: base.Header{ @@ -568,7 +570,7 @@ func TestServerRead(t *testing.T) { <-sessionClosed - nconn.Close() + conn.Close() <-connClosed }) } @@ -602,12 +604,12 @@ func TestServerReadVLCMulticast(t *testing.T) { require.NoError(t, err) defer s.Close() - nconn, err := net.Dial("tcp", listenIP+":8554") + conn, err := net.Dial("tcp", listenIP+":8554") require.NoError(t, err) - bconn := bufio.NewReadWriter(bufio.NewReader(nconn), bufio.NewWriter(nconn)) - defer nconn.Close() + br := bufio.NewReader(conn) + defer conn.Close() - res, err := writeReqReadRes(bconn, base.Request{ + res, err := writeReqReadRes(conn, br, base.Request{ Method: base.Describe, URL: mustParseURL("rtsp://" + listenIP + ":8554/teststream?vlcmulticast"), Header: base.Header{ @@ -659,9 +661,9 @@ func TestServerReadNonStandardFrameSize(t *testing.T) { require.NoError(t, err) defer s.Close() - nconn, err := net.Dial("tcp", "localhost:8554") + conn, err := net.Dial("tcp", "localhost:8554") require.NoError(t, err) - bconn := bufio.NewReadWriter(bufio.NewReader(nconn), bufio.NewWriter(nconn)) + br := bufio.NewReader(conn) inTH := &headers.Transport{ Mode: func() *headers.TransportMode { @@ -676,7 +678,7 @@ func TestServerReadNonStandardFrameSize(t *testing.T) { InterleavedIDs: &[2]int{0, 1}, } - res, err := writeReqReadRes(bconn, base.Request{ + res, err := writeReqReadRes(conn, br, base.Request{ Method: base.Setup, URL: mustParseURL("rtsp://localhost:8554/teststream/trackID=0"), Header: base.Header{ @@ -687,7 +689,7 @@ func TestServerReadNonStandardFrameSize(t *testing.T) { require.NoError(t, err) require.Equal(t, base.StatusOK, res.StatusCode) - res, err = writeReqReadRes(bconn, base.Request{ + res, err = writeReqReadRes(conn, br, base.Request{ Method: base.Play, URL: mustParseURL("rtsp://localhost:8554/teststream"), Header: base.Header{ @@ -700,7 +702,7 @@ func TestServerReadNonStandardFrameSize(t *testing.T) { var f base.InterleavedFrame f.Payload = make([]byte, 4500) - err = f.Read(bconn.Reader) + err = f.Read(br) require.NoError(t, err) require.Equal(t, 0, f.Channel) require.Equal(t, payload, f.Payload) @@ -764,9 +766,9 @@ func TestServerReadTCPResponseBeforeFrames(t *testing.T) { conn, err := net.Dial("tcp", "localhost:8554") require.NoError(t, err) defer conn.Close() - bconn := bufio.NewReadWriter(bufio.NewReader(conn), bufio.NewWriter(conn)) + br := bufio.NewReader(conn) - res, err := writeReqReadRes(bconn, base.Request{ + res, err := writeReqReadRes(conn, br, base.Request{ Method: base.Setup, URL: mustParseURL("rtsp://localhost:8554/teststream/trackID=0"), Header: base.Header{ @@ -788,7 +790,7 @@ func TestServerReadTCPResponseBeforeFrames(t *testing.T) { require.NoError(t, err) require.Equal(t, base.StatusOK, res.StatusCode) - res, err = writeReqReadRes(bconn, base.Request{ + res, err = writeReqReadRes(conn, br, base.Request{ Method: base.Play, URL: mustParseURL("rtsp://localhost:8554/teststream"), Header: base.Header{ @@ -801,7 +803,7 @@ func TestServerReadTCPResponseBeforeFrames(t *testing.T) { var fr base.InterleavedFrame fr.Payload = make([]byte, 2048) - err = fr.Read(bconn.Reader) + err = fr.Read(br) require.NoError(t, err) } @@ -838,9 +840,9 @@ func TestServerReadPlayPlay(t *testing.T) { conn, err := net.Dial("tcp", "localhost:8554") require.NoError(t, err) defer conn.Close() - bconn := bufio.NewReadWriter(bufio.NewReader(conn), bufio.NewWriter(conn)) + br := bufio.NewReader(conn) - res, err := writeReqReadRes(bconn, base.Request{ + res, err := writeReqReadRes(conn, br, base.Request{ Method: base.Setup, URL: mustParseURL("rtsp://localhost:8554/teststream/trackID=0"), Header: base.Header{ @@ -862,7 +864,7 @@ func TestServerReadPlayPlay(t *testing.T) { require.NoError(t, err) require.Equal(t, base.StatusOK, res.StatusCode) - res, err = writeReqReadRes(bconn, base.Request{ + res, err = writeReqReadRes(conn, br, base.Request{ Method: base.Play, URL: mustParseURL("rtsp://localhost:8554/teststream"), Header: base.Header{ @@ -873,7 +875,7 @@ func TestServerReadPlayPlay(t *testing.T) { require.NoError(t, err) require.Equal(t, base.StatusOK, res.StatusCode) - res, err = writeReqReadRes(bconn, base.Request{ + res, err = writeReqReadRes(conn, br, base.Request{ Method: base.Play, URL: mustParseURL("rtsp://localhost:8554/teststream"), Header: base.Header{ @@ -948,9 +950,9 @@ func TestServerReadPlayPausePlay(t *testing.T) { conn, err := net.Dial("tcp", "localhost:8554") require.NoError(t, err) defer conn.Close() - bconn := bufio.NewReadWriter(bufio.NewReader(conn), bufio.NewWriter(conn)) + br := bufio.NewReader(conn) - res, err := writeReqReadRes(bconn, base.Request{ + res, err := writeReqReadRes(conn, br, base.Request{ Method: base.Setup, URL: mustParseURL("rtsp://localhost:8554/teststream/trackID=0"), Header: base.Header{ @@ -972,7 +974,7 @@ func TestServerReadPlayPausePlay(t *testing.T) { require.NoError(t, err) require.Equal(t, base.StatusOK, res.StatusCode) - res, err = writeReqReadRes(bconn, base.Request{ + res, err = writeReqReadRes(conn, br, base.Request{ Method: base.Play, URL: mustParseURL("rtsp://localhost:8554/teststream"), Header: base.Header{ @@ -983,7 +985,7 @@ func TestServerReadPlayPausePlay(t *testing.T) { require.NoError(t, err) require.Equal(t, base.StatusOK, res.StatusCode) - res, err = writeReqReadRes(bconn, base.Request{ + res, err = writeReqReadRes(conn, br, base.Request{ Method: base.Pause, URL: mustParseURL("rtsp://localhost:8554/teststream"), Header: base.Header{ @@ -994,7 +996,7 @@ func TestServerReadPlayPausePlay(t *testing.T) { require.NoError(t, err) require.Equal(t, base.StatusOK, res.StatusCode) - res, err = writeReqReadRes(bconn, base.Request{ + res, err = writeReqReadRes(conn, br, base.Request{ Method: base.Play, URL: mustParseURL("rtsp://localhost:8554/teststream"), Header: base.Header{ @@ -1065,9 +1067,10 @@ func TestServerReadPlayPausePause(t *testing.T) { conn, err := net.Dial("tcp", "localhost:8554") require.NoError(t, err) defer conn.Close() - bconn := bufio.NewReadWriter(bufio.NewReader(conn), bufio.NewWriter(conn)) + br := bufio.NewReader(conn) + var bb bytes.Buffer - res, err := writeReqReadRes(bconn, base.Request{ + res, err := writeReqReadRes(conn, br, base.Request{ Method: base.Setup, URL: mustParseURL("rtsp://localhost:8554/teststream/trackID=0"), Header: base.Header{ @@ -1089,7 +1092,7 @@ func TestServerReadPlayPausePause(t *testing.T) { require.NoError(t, err) require.Equal(t, base.StatusOK, res.StatusCode) - res, err = writeReqReadRes(bconn, base.Request{ + res, err = writeReqReadRes(conn, br, base.Request{ Method: base.Play, URL: mustParseURL("rtsp://localhost:8554/teststream"), Header: base.Header{ @@ -1100,31 +1103,33 @@ func TestServerReadPlayPausePause(t *testing.T) { require.NoError(t, err) require.Equal(t, base.StatusOK, res.StatusCode) - err = base.Request{ + base.Request{ Method: base.Pause, URL: mustParseURL("rtsp://localhost:8554/teststream"), Header: base.Header{ "CSeq": base.HeaderValue{"2"}, "Session": res.Header["Session"], }, - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) - res, err = readResIgnoreFrames(bconn.Reader) + res, err = readResIgnoreFrames(br) require.NoError(t, err) require.Equal(t, base.StatusOK, res.StatusCode) - err = base.Request{ + base.Request{ Method: base.Pause, URL: mustParseURL("rtsp://localhost:8554/teststream"), Header: base.Header{ "CSeq": base.HeaderValue{"2"}, "Session": res.Header["Session"], }, - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) - res, err = readResIgnoreFrames(bconn.Reader) + res, err = readResIgnoreFrames(br) require.NoError(t, err) require.Equal(t, base.StatusOK, res.StatusCode) } @@ -1176,10 +1181,10 @@ func TestServerReadTimeout(t *testing.T) { require.NoError(t, err) defer s.Close() - nconn, err := net.Dial("tcp", "localhost:8554") + conn, err := net.Dial("tcp", "localhost:8554") require.NoError(t, err) - defer nconn.Close() - bconn := bufio.NewReadWriter(bufio.NewReader(nconn), bufio.NewWriter(nconn)) + defer conn.Close() + br := bufio.NewReader(conn) inTH := &headers.Transport{ Delivery: func() *headers.TransportDelivery { @@ -1195,7 +1200,7 @@ func TestServerReadTimeout(t *testing.T) { inTH.Protocol = headers.TransportProtocolUDP inTH.ClientPorts = &[2]int{35466, 35467} - res, err := writeReqReadRes(bconn, base.Request{ + res, err := writeReqReadRes(conn, br, base.Request{ Method: base.Setup, URL: mustParseURL("rtsp://localhost:8554/teststream/trackID=0"), Header: base.Header{ @@ -1206,7 +1211,7 @@ func TestServerReadTimeout(t *testing.T) { require.NoError(t, err) require.Equal(t, base.StatusOK, res.StatusCode) - res, err = writeReqReadRes(bconn, base.Request{ + res, err = writeReqReadRes(conn, br, base.Request{ Method: base.Play, URL: mustParseURL("rtsp://localhost:8554/teststream"), Header: base.Header{ @@ -1276,10 +1281,10 @@ func TestServerReadWithoutTeardown(t *testing.T) { require.NoError(t, err) defer s.Close() - nconn, err := net.Dial("tcp", "localhost:8554") + conn, err := net.Dial("tcp", "localhost:8554") require.NoError(t, err) - defer nconn.Close() - bconn := bufio.NewReadWriter(bufio.NewReader(nconn), bufio.NewWriter(nconn)) + defer conn.Close() + br := bufio.NewReader(conn) inTH := &headers.Transport{ Delivery: func() *headers.TransportDelivery { @@ -1300,7 +1305,7 @@ func TestServerReadWithoutTeardown(t *testing.T) { inTH.InterleavedIDs = &[2]int{0, 1} } - res, err := writeReqReadRes(bconn, base.Request{ + res, err := writeReqReadRes(conn, br, base.Request{ Method: base.Setup, URL: mustParseURL("rtsp://localhost:8554/teststream/trackID=0"), Header: base.Header{ @@ -1311,7 +1316,7 @@ func TestServerReadWithoutTeardown(t *testing.T) { require.NoError(t, err) require.Equal(t, base.StatusOK, res.StatusCode) - res, err = writeReqReadRes(bconn, base.Request{ + res, err = writeReqReadRes(conn, br, base.Request{ Method: base.Play, URL: mustParseURL("rtsp://localhost:8554/teststream"), Header: base.Header{ @@ -1322,7 +1327,7 @@ func TestServerReadWithoutTeardown(t *testing.T) { require.NoError(t, err) require.Equal(t, base.StatusOK, res.StatusCode) - nconn.Close() + conn.Close() <-sessionClosed <-connClosed @@ -1371,7 +1376,7 @@ func TestServerReadUDPChangeConn(t *testing.T) { conn, err := net.Dial("tcp", "localhost:8554") require.NoError(t, err) defer conn.Close() - bconn := bufio.NewReadWriter(bufio.NewReader(conn), bufio.NewWriter(conn)) + br := bufio.NewReader(conn) inTH := &headers.Transport{ Delivery: func() *headers.TransportDelivery { @@ -1386,7 +1391,7 @@ func TestServerReadUDPChangeConn(t *testing.T) { ClientPorts: &[2]int{35466, 35467}, } - res, err := writeReqReadRes(bconn, base.Request{ + res, err := writeReqReadRes(conn, br, base.Request{ Method: base.Setup, URL: mustParseURL("rtsp://localhost:8554/teststream/trackID=0"), Header: base.Header{ @@ -1397,7 +1402,7 @@ func TestServerReadUDPChangeConn(t *testing.T) { require.NoError(t, err) require.Equal(t, base.StatusOK, res.StatusCode) - res, err = writeReqReadRes(bconn, base.Request{ + res, err = writeReqReadRes(conn, br, base.Request{ Method: base.Play, URL: mustParseURL("rtsp://localhost:8554/teststream"), Header: base.Header{ @@ -1414,9 +1419,9 @@ func TestServerReadUDPChangeConn(t *testing.T) { conn, err := net.Dial("tcp", "localhost:8554") require.NoError(t, err) defer conn.Close() - bconn := bufio.NewReadWriter(bufio.NewReader(conn), bufio.NewWriter(conn)) + br := bufio.NewReader(conn) - res, err := writeReqReadRes(bconn, base.Request{ + res, err := writeReqReadRes(conn, br, base.Request{ Method: base.GetParameter, URL: mustParseURL("rtsp://localhost:8554/teststream/"), Header: base.Header{ @@ -1471,7 +1476,7 @@ func TestServerReadPartialTracks(t *testing.T) { conn, err := net.Dial("tcp", "localhost:8554") require.NoError(t, err) defer conn.Close() - bconn := bufio.NewReadWriter(bufio.NewReader(conn), bufio.NewWriter(conn)) + br := bufio.NewReader(conn) inTH := &headers.Transport{ Delivery: func() *headers.TransportDelivery { @@ -1486,7 +1491,7 @@ func TestServerReadPartialTracks(t *testing.T) { InterleavedIDs: &[2]int{4, 5}, } - res, err := writeReqReadRes(bconn, base.Request{ + res, err := writeReqReadRes(conn, br, base.Request{ Method: base.Setup, URL: mustParseURL("rtsp://localhost:8554/teststream/trackID=1"), Header: base.Header{ @@ -1497,7 +1502,7 @@ func TestServerReadPartialTracks(t *testing.T) { require.NoError(t, err) require.Equal(t, base.StatusOK, res.StatusCode) - res, err = writeReqReadRes(bconn, base.Request{ + res, err = writeReqReadRes(conn, br, base.Request{ Method: base.Play, URL: mustParseURL("rtsp://localhost:8554/teststream"), Header: base.Header{ @@ -1510,7 +1515,7 @@ func TestServerReadPartialTracks(t *testing.T) { var f base.InterleavedFrame f.Payload = make([]byte, 2048) - err = f.Read(bconn.Reader) + err = f.Read(br) require.NoError(t, err) require.Equal(t, 4, f.Channel) require.Equal(t, []byte{0x05, 0x06, 0x07, 0x08}, f.Payload) @@ -1521,7 +1526,7 @@ func TestServerReadAdditionalInfos(t *testing.T) { conn, err := net.Dial("tcp", "localhost:8554") require.NoError(t, err) defer conn.Close() - bconn := bufio.NewReadWriter(bufio.NewReader(conn), bufio.NewWriter(conn)) + br := bufio.NewReader(conn) ssrcs := make([]*uint32, 2) @@ -1538,7 +1543,7 @@ func TestServerReadAdditionalInfos(t *testing.T) { InterleavedIDs: &[2]int{0, 1}, } - res, err := writeReqReadRes(bconn, base.Request{ + res, err := writeReqReadRes(conn, br, base.Request{ Method: base.Setup, URL: mustParseURL("rtsp://localhost:8554/teststream/trackID=0"), Header: base.Header{ @@ -1567,7 +1572,7 @@ func TestServerReadAdditionalInfos(t *testing.T) { InterleavedIDs: &[2]int{2, 3}, } - res, err = writeReqReadRes(bconn, base.Request{ + res, err = writeReqReadRes(conn, br, base.Request{ Method: base.Setup, URL: mustParseURL("rtsp://localhost:8554/teststream/trackID=1"), Header: base.Header{ @@ -1584,7 +1589,7 @@ func TestServerReadAdditionalInfos(t *testing.T) { require.NoError(t, err) ssrcs[1] = th.SSRC - res, err = writeReqReadRes(bconn, base.Request{ + res, err = writeReqReadRes(conn, br, base.Request{ Method: base.Play, URL: mustParseURL("rtsp://localhost:8554/teststream"), Header: base.Header{ @@ -1757,7 +1762,7 @@ func TestServerReadErrorUDPSamePorts(t *testing.T) { conn, err := net.Dial("tcp", "localhost:8554") require.NoError(t, err) defer conn.Close() - bconn := bufio.NewReadWriter(bufio.NewReader(conn), bufio.NewWriter(conn)) + br := bufio.NewReader(conn) inTH := &headers.Transport{ Delivery: func() *headers.TransportDelivery { @@ -1772,7 +1777,7 @@ func TestServerReadErrorUDPSamePorts(t *testing.T) { ClientPorts: &[2]int{35466, 35467}, } - res, err := writeReqReadRes(bconn, base.Request{ + res, err := writeReqReadRes(conn, br, base.Request{ Method: base.Setup, URL: mustParseURL("rtsp://localhost:8554/teststream/trackID=0"), Header: base.Header{ @@ -1783,7 +1788,7 @@ func TestServerReadErrorUDPSamePorts(t *testing.T) { require.NoError(t, err) require.Equal(t, base.StatusOK, res.StatusCode) - res, err = writeReqReadRes(bconn, base.Request{ + res, err = writeReqReadRes(conn, br, base.Request{ Method: base.Play, URL: mustParseURL("rtsp://localhost:8554/teststream"), Header: base.Header{ @@ -1799,7 +1804,7 @@ func TestServerReadErrorUDPSamePorts(t *testing.T) { conn, err := net.Dial("tcp", "localhost:8554") require.NoError(t, err) defer conn.Close() - bconn := bufio.NewReadWriter(bufio.NewReader(conn), bufio.NewWriter(conn)) + br := bufio.NewReader(conn) inTH := &headers.Transport{ Delivery: func() *headers.TransportDelivery { @@ -1814,7 +1819,7 @@ func TestServerReadErrorUDPSamePorts(t *testing.T) { ClientPorts: &[2]int{35466, 35467}, } - res, err := writeReqReadRes(bconn, base.Request{ + res, err := writeReqReadRes(conn, br, base.Request{ Method: base.Setup, URL: mustParseURL("rtsp://localhost:8554/teststream/trackID=0"), Header: base.Header{ diff --git a/server_test.go b/server_test.go index 3b3f07e1..164f9b3e 100644 --- a/server_test.go +++ b/server_test.go @@ -2,6 +2,7 @@ package gortsplib import ( "bufio" + "bytes" "crypto/tls" "fmt" "net" @@ -19,14 +20,18 @@ import ( "github.com/aler9/gortsplib/pkg/headers" ) -func writeReqReadRes(bconn *bufio.ReadWriter, req base.Request) (*base.Response, error) { - err := req.Write(bconn.Writer) +func writeReqReadRes(conn net.Conn, + br *bufio.Reader, + req base.Request) (*base.Response, error) { + var bb bytes.Buffer + req.Write(&bb) + _, err := conn.Write(bb.Bytes()) if err != nil { return nil, err } var res base.Response - err = res.Read(bconn.Reader) + err = res.Read(br) return &res, err } @@ -603,9 +608,9 @@ func TestServerCSeq(t *testing.T) { conn, err := net.Dial("tcp", "localhost:8554") require.NoError(t, err) defer conn.Close() - bconn := bufio.NewReadWriter(bufio.NewReader(conn), bufio.NewWriter(conn)) + br := bufio.NewReader(conn) - res, err := writeReqReadRes(bconn, base.Request{ + res, err := writeReqReadRes(conn, br, base.Request{ Method: base.Options, URL: mustParseURL("rtsp://localhost:8554/"), Header: base.Header{ @@ -637,9 +642,9 @@ func TestServerErrorCSeqMissing(t *testing.T) { conn, err := net.Dial("tcp", "localhost:8554") require.NoError(t, err) defer conn.Close() - bconn := bufio.NewReadWriter(bufio.NewReader(conn), bufio.NewWriter(conn)) + br := bufio.NewReader(conn) - res, err := writeReqReadRes(bconn, base.Request{ + res, err := writeReqReadRes(conn, br, base.Request{ Method: base.Options, URL: mustParseURL("rtsp://localhost:8554/"), Header: base.Header{}, @@ -669,9 +674,9 @@ func TestServerErrorInvalidMethod(t *testing.T) { conn, err := net.Dial("tcp", "localhost:8554") require.NoError(t, err) defer conn.Close() - bconn := bufio.NewReadWriter(bufio.NewReader(conn), bufio.NewWriter(conn)) + br := bufio.NewReader(conn) - res, err := writeReqReadRes(bconn, base.Request{ + res, err := writeReqReadRes(conn, br, base.Request{ Method: "INVALID", URL: mustParseURL("rtsp://localhost:8554/"), Header: base.Header{ @@ -720,9 +725,9 @@ func TestServerErrorTCPTwoConnOneSession(t *testing.T) { conn1, err := net.Dial("tcp", "localhost:8554") require.NoError(t, err) defer conn1.Close() - bconn1 := bufio.NewReadWriter(bufio.NewReader(conn1), bufio.NewWriter(conn1)) + br1 := bufio.NewReader(conn1) - res, err := writeReqReadRes(bconn1, base.Request{ + res, err := writeReqReadRes(conn1, br1, base.Request{ Method: base.Setup, URL: mustParseURL("rtsp://localhost:8554/teststream/trackID=0"), Header: base.Header{ @@ -744,7 +749,7 @@ func TestServerErrorTCPTwoConnOneSession(t *testing.T) { require.NoError(t, err) require.Equal(t, base.StatusOK, res.StatusCode) - res, err = writeReqReadRes(bconn1, base.Request{ + res, err = writeReqReadRes(conn1, br1, base.Request{ Method: base.Play, URL: mustParseURL("rtsp://localhost:8554/teststream"), Header: base.Header{ @@ -758,9 +763,9 @@ func TestServerErrorTCPTwoConnOneSession(t *testing.T) { conn2, err := net.Dial("tcp", "localhost:8554") require.NoError(t, err) defer conn2.Close() - bconn2 := bufio.NewReadWriter(bufio.NewReader(conn2), bufio.NewWriter(conn2)) + br2 := bufio.NewReader(conn2) - res, err = writeReqReadRes(bconn2, base.Request{ + res, err = writeReqReadRes(conn2, br2, base.Request{ Method: base.Setup, URL: mustParseURL("rtsp://localhost:8554/teststream/trackID=0"), Header: base.Header{ @@ -820,9 +825,9 @@ func TestServerErrorTCPOneConnTwoSessions(t *testing.T) { conn, err := net.Dial("tcp", "localhost:8554") require.NoError(t, err) defer conn.Close() - bconn := bufio.NewReadWriter(bufio.NewReader(conn), bufio.NewWriter(conn)) + br := bufio.NewReader(conn) - res, err := writeReqReadRes(bconn, base.Request{ + res, err := writeReqReadRes(conn, br, base.Request{ Method: base.Setup, URL: mustParseURL("rtsp://localhost:8554/teststream/trackID=0"), Header: base.Header{ @@ -844,7 +849,7 @@ func TestServerErrorTCPOneConnTwoSessions(t *testing.T) { require.NoError(t, err) require.Equal(t, base.StatusOK, res.StatusCode) - res, err = writeReqReadRes(bconn, base.Request{ + res, err = writeReqReadRes(conn, br, base.Request{ Method: base.Play, URL: mustParseURL("rtsp://localhost:8554/teststream"), Header: base.Header{ @@ -855,7 +860,7 @@ func TestServerErrorTCPOneConnTwoSessions(t *testing.T) { require.NoError(t, err) require.Equal(t, base.StatusOK, res.StatusCode) - res, err = writeReqReadRes(bconn, base.Request{ + res, err = writeReqReadRes(conn, br, base.Request{ Method: base.Setup, URL: mustParseURL("rtsp://localhost:8554/teststream/trackID=0"), Header: base.Header{ @@ -906,9 +911,9 @@ func TestServerGetSetParameter(t *testing.T) { conn, err := net.Dial("tcp", "localhost:8554") require.NoError(t, err) defer conn.Close() - bconn := bufio.NewReadWriter(bufio.NewReader(conn), bufio.NewWriter(conn)) + br := bufio.NewReader(conn) - res, err := writeReqReadRes(bconn, base.Request{ + res, err := writeReqReadRes(conn, br, base.Request{ Method: base.Options, URL: mustParseURL("rtsp://localhost:8554/teststream"), Header: base.Header{ @@ -918,7 +923,7 @@ func TestServerGetSetParameter(t *testing.T) { require.NoError(t, err) require.Equal(t, base.StatusOK, res.StatusCode) - res, err = writeReqReadRes(bconn, base.Request{ + res, err = writeReqReadRes(conn, br, base.Request{ Method: base.SetParameter, URL: mustParseURL("rtsp://localhost:8554/teststream"), Header: base.Header{ @@ -929,7 +934,7 @@ func TestServerGetSetParameter(t *testing.T) { require.NoError(t, err) require.Equal(t, base.StatusOK, res.StatusCode) - res, err = writeReqReadRes(bconn, base.Request{ + res, err = writeReqReadRes(conn, br, base.Request{ Method: base.GetParameter, URL: mustParseURL("rtsp://localhost:8554/teststream"), Header: base.Header{ @@ -978,9 +983,9 @@ func TestServerErrorInvalidSession(t *testing.T) { conn, err := net.Dial("tcp", "localhost:8554") require.NoError(t, err) defer conn.Close() - bconn := bufio.NewReadWriter(bufio.NewReader(conn), bufio.NewWriter(conn)) + br := bufio.NewReader(conn) - res, err := writeReqReadRes(bconn, base.Request{ + res, err := writeReqReadRes(conn, br, base.Request{ Method: method, URL: mustParseURL("rtsp://localhost:8554/teststream"), Header: base.Header{ @@ -1021,9 +1026,9 @@ func TestServerSessionClose(t *testing.T) { conn, err := net.Dial("tcp", "localhost:8554") require.NoError(t, err) defer conn.Close() - bconn := bufio.NewReadWriter(bufio.NewReader(conn), bufio.NewWriter(conn)) + var bb bytes.Buffer - err = base.Request{ + base.Request{ Method: base.Setup, URL: mustParseURL("rtsp://localhost:8554/teststream/trackID=0"), Header: base.Header{ @@ -1041,7 +1046,8 @@ func TestServerSessionClose(t *testing.T) { InterleavedIDs: &[2]int{0, 1}, }.Write(), }, - }.Write(bconn.Writer) + }.Write(&bb) + _, err = conn.Write(bb.Bytes()) require.NoError(t, err) <-sessionClosed @@ -1077,9 +1083,9 @@ func TestServerSessionAutoClose(t *testing.T) { conn, err := net.Dial("tcp", "localhost:8554") require.NoError(t, err) - bconn := bufio.NewReadWriter(bufio.NewReader(conn), bufio.NewWriter(conn)) + br := bufio.NewReader(conn) - res, err := writeReqReadRes(bconn, base.Request{ + res, err := writeReqReadRes(conn, br, base.Request{ Method: base.Setup, URL: mustParseURL("rtsp://localhost:8554/teststream/trackID=0"), Header: base.Header{ @@ -1158,7 +1164,7 @@ func TestServerErrorInvalidPath(t *testing.T) { conn, err := net.Dial("tcp", "localhost:8554") require.NoError(t, err) defer conn.Close() - bconn := bufio.NewReadWriter(bufio.NewReader(conn), bufio.NewWriter(conn)) + br := bufio.NewReader(conn) sxID := "" @@ -1176,7 +1182,7 @@ func TestServerErrorInvalidPath(t *testing.T) { }) } - res, err := writeReqReadRes(bconn, base.Request{ + res, err := writeReqReadRes(conn, br, base.Request{ Method: base.Announce, URL: mustParseURL("rtsp://localhost:8554/teststream"), Header: base.Header{ @@ -1191,7 +1197,7 @@ func TestServerErrorInvalidPath(t *testing.T) { } if method == base.Play || method == base.Record || method == base.Pause { - res, err := writeReqReadRes(bconn, base.Request{ + res, err := writeReqReadRes(conn, br, base.Request{ Method: base.Setup, URL: mustParseURL("rtsp://localhost:8554/teststream/trackID=0"), Header: base.Header{ @@ -1221,7 +1227,7 @@ func TestServerErrorInvalidPath(t *testing.T) { } if method == base.Pause { - res, err := writeReqReadRes(bconn, base.Request{ + res, err := writeReqReadRes(conn, br, base.Request{ Method: base.Play, URL: mustParseURL("rtsp://localhost:8554/teststream/"), Header: base.Header{ @@ -1233,7 +1239,7 @@ func TestServerErrorInvalidPath(t *testing.T) { require.Equal(t, base.StatusOK, res.StatusCode) } - res, err := writeReqReadRes(bconn, base.Request{ + res, err := writeReqReadRes(conn, br, base.Request{ Method: method, URL: mustParseURL("rtsp://localhost:8554"), Header: base.Header{ diff --git a/serverconn.go b/serverconn.go index 046e94dc..ffedc8bb 100644 --- a/serverconn.go +++ b/serverconn.go @@ -2,12 +2,12 @@ package gortsplib import ( "bufio" + "bytes" "context" "crypto/tls" "net" "net/url" "strings" - "sync" "time" "github.com/aler9/gortsplib/pkg/base" @@ -29,21 +29,20 @@ type readReq struct { // ServerConn is a server-side RTSP connection. type ServerConn struct { - s *Server - nconn net.Conn + s *Server + conn net.Conn - ctx context.Context - ctxCancel func() - remoteAddr *net.TCPAddr // to improve speed - br *bufio.Reader - bw *bufio.Writer - sessions map[string]*ServerSession - tcpFrameEnabled bool - tcpSession *ServerSession - tcpFrameTimeout bool - tcpReadBuffer *multibuffer.MultiBuffer - tcpProcessFunc func(int, bool, []byte) - tcpWriteMutex sync.Mutex + ctx context.Context + ctxCancel func() + remoteAddr *net.TCPAddr + br *bufio.Reader + sessions map[string]*ServerSession + tcpFrameEnabled bool + tcpSession *ServerSession + tcpFrameTimeout bool + tcpReadBuffer *multibuffer.MultiBuffer + tcpProcessFunc func(int, bool, []byte) + tcpWriterRunning bool // in sessionRemove chan *ServerSession @@ -57,12 +56,19 @@ func newServerConn( nconn net.Conn) *ServerConn { ctx, ctxCancel := context.WithCancel(s.ctx) + conn := func() net.Conn { + if s.TLSConfig != nil { + return tls.Server(nconn, s.TLSConfig) + } + return nconn + }() + sc := &ServerConn{ s: s, - nconn: nconn, + conn: conn, ctx: ctx, ctxCancel: ctxCancel, - remoteAddr: nconn.RemoteAddr().(*net.TCPAddr), + remoteAddr: conn.RemoteAddr().(*net.TCPAddr), sessionRemove: make(chan *ServerSession), done: make(chan struct{}), } @@ -81,7 +87,7 @@ func (sc *ServerConn) Close() error { // NetConn returns the underlying net.Conn. func (sc *ServerConn) NetConn() net.Conn { - return sc.nconn + return sc.conn } func (sc *ServerConn) ip() net.IP { @@ -102,15 +108,7 @@ func (sc *ServerConn) run() { }) } - conn := func() net.Conn { - if sc.s.TLSConfig != nil { - return tls.Server(sc.nconn, sc.s.TLSConfig) - } - return sc.nconn - }() - - sc.br = bufio.NewReaderSize(conn, serverReadBufferSize) - sc.bw = bufio.NewWriterSize(conn, serverWriteBufferSize) + sc.br = bufio.NewReaderSize(sc.conn, serverReadBufferSize) sc.sessions = make(map[string]*ServerSession) readRequest := make(chan readReq) @@ -125,7 +123,7 @@ func (sc *ServerConn) run() { for { if sc.tcpFrameEnabled { if sc.tcpFrameTimeout { - sc.nconn.SetReadDeadline(time.Now().Add(sc.s.ReadTimeout)) + sc.conn.SetReadDeadline(time.Now().Add(sc.s.ReadTimeout)) } frame.Payload = sc.tcpReadBuffer.Next() @@ -215,7 +213,7 @@ func (sc *ServerConn) run() { sc.ctxCancel() - sc.nconn.Close() + sc.conn.Close() <-readDone for _, ss := range sc.sessions { @@ -458,8 +456,6 @@ func (sc *ServerConn) handleRequestOuter(req *base.Request) error { h.OnRequest(sc, req) } - sc.tcpWriteMutex.Lock() - res, err := sc.handleRequest(req) if res.Header == nil { @@ -478,10 +474,20 @@ func (sc *ServerConn) handleRequestOuter(req *base.Request) error { h.OnResponse(sc, res) } - sc.nconn.SetWriteDeadline(time.Now().Add(sc.s.WriteTimeout)) - res.Write(sc.bw) + var buf bytes.Buffer + res.Write(&buf) - sc.tcpWriteMutex.Unlock() + sc.conn.SetWriteDeadline(time.Now().Add(sc.s.WriteTimeout)) + sc.conn.Write(buf.Bytes()) + + // start writer after sending the response + if sc.tcpFrameEnabled && !sc.tcpWriterRunning { + sc.tcpWriterRunning = true + select { + case sc.tcpSession.startWriter <- struct{}{}: + case <-sc.tcpSession.ctx.Done(): + } + } return err } diff --git a/serversession.go b/serversession.go index 30dcdc84..38625789 100644 --- a/serversession.go +++ b/serversession.go @@ -1,6 +1,7 @@ package gortsplib import ( + "bytes" "context" "fmt" "net" @@ -183,8 +184,9 @@ type ServerSession struct { writerDone chan struct{} // in - request chan sessionRequestReq - connRemove chan *ServerConn + request chan sessionRequestReq + connRemove chan *ServerConn + startWriter chan struct{} } func newServerSession( @@ -206,6 +208,7 @@ func newServerSession( udpReceiverReportTimer: emptyTimer(), request: make(chan sessionRequestReq), connRemove: make(chan *ServerConn), + startWriter: make(chan struct{}), } s.wg.Add(1) @@ -314,6 +317,15 @@ func (ss *ServerSession) run() { } } + case <-ss.startWriter: + if !ss.writerRunning && (ss.state == ServerSessionStatePublish || + ss.state == ServerSessionStateRead) && + *ss.setuppedTransport == TransportTCP { + ss.writerRunning = true + ss.writerDone = make(chan struct{}) + go ss.runWriter() + } + case <-ss.udpCheckStreamTimer.C: now := time.Now() @@ -876,9 +888,8 @@ func (ss *ServerSession) handleRequest(sc *ServerConn, req *base.Request) (*base ss.tcpConn.tcpProcessFunc = sc.tcpProcessPlay ss.writeBuffer = ringbuffer.New(uint64(ss.s.ReadBufferCount)) - ss.writerRunning = true - ss.writerDone = make(chan struct{}) - go ss.runWriter() + // run writer after sending the response + ss.tcpConn.tcpWriterRunning = false } // add RTP-Info @@ -1010,9 +1021,8 @@ func (ss *ServerSession) handleRequest(sc *ServerConn, req *base.Request) (*base // that are much smaller than RTP packets and are sent at a fixed interval. // decrease RAM consumption by allocating less buffers. ss.writeBuffer = ringbuffer.New(uint64(8)) - ss.writerRunning = true - ss.writerDone = make(chan struct{}) - go ss.runWriter() + // run writer after sending the response + ss.tcpConn.tcpWriterRunning = false } return res, err @@ -1096,7 +1106,7 @@ func (ss *ServerSession) handleRequest(sc *ServerConn, req *base.Request) (*base ss.tcpConn.tcpSession = nil ss.tcpConn.tcpFrameEnabled = false ss.tcpConn.tcpReadBuffer = nil - ss.tcpConn.nconn.SetReadDeadline(time.Time{}) + ss.tcpConn.conn.SetReadDeadline(time.Time{}) ss.tcpConn = nil } } @@ -1158,23 +1168,23 @@ func (ss *ServerSession) runWriter() { } } } else { + var buf bytes.Buffer + writeFunc = func(trackID int, isRTP bool, payload []byte) { if isRTP { f := ss.setuppedTracks[trackID].tcpRTPFrame f.Payload = payload + f.Write(&buf) - ss.tcpConn.tcpWriteMutex.Lock() - ss.tcpConn.nconn.SetWriteDeadline(time.Now().Add(ss.s.WriteTimeout)) - f.Write(ss.tcpConn.bw) - ss.tcpConn.tcpWriteMutex.Unlock() + ss.tcpConn.conn.SetWriteDeadline(time.Now().Add(ss.s.WriteTimeout)) + ss.tcpConn.conn.Write(buf.Bytes()) } else { f := ss.setuppedTracks[trackID].tcpRTCPFrame f.Payload = payload + f.Write(&buf) - ss.tcpConn.tcpWriteMutex.Lock() - ss.tcpConn.nconn.SetWriteDeadline(time.Now().Add(ss.s.WriteTimeout)) - f.Write(ss.tcpConn.bw) - ss.tcpConn.tcpWriteMutex.Unlock() + ss.tcpConn.conn.SetWriteDeadline(time.Now().Add(ss.s.WriteTimeout)) + ss.tcpConn.conn.Write(buf.Bytes()) } } }