Skip to main content
The Server struct is the entry point for building an RTSP server with gortsplib. It handles incoming TCP connections, optional UDP transports, multicast distribution, and TLS. You control server behavior by implementing one or more ServerHandler* interfaces and assigning them to Server.Handler.

Server fields

RTSPAddress is the only required field. All other fields are optional.

Transport

FieldTypeDefaultDescription
RTSPAddressstringRequired. TCP address the server listens on (e.g. :8554).
UDPRTPAddressstring""UDP address for receiving/sending RTP packets. Must be set together with UDPRTCPAddress to enable UDP transport.
UDPRTCPAddressstring""UDP address for receiving/sending RTCP packets. Must be set together with UDPRTPAddress.
MulticastIPRangestring""CIDR range of multicast IPs. Must be set together with MulticastRTPPort and MulticastRTCPPort to enable UDP-multicast transport.
MulticastRTPPortint0Port for multicast RTP packets. Must be an even number.
MulticastRTCPPortint0Port for multicast RTCP packets. Must equal MulticastRTPPort + 1.

Timeouts

FieldTypeDefaultDescription
ReadTimeouttime.Duration10sTimeout for read operations on a connection.
WriteTimeouttime.Duration10sTimeout for write operations on a connection.
IdleTimeouttime.Duration60sTimeout for idle connections and sessions with no activity.

Security

FieldTypeDefaultDescription
TLSConfig*tls.ConfignilWhen set, the server accepts only TLS (RTSPS) connections and automatically negotiates SRTP/SRTCP for media encryption.
AuthMethods[]auth.VerifyMethodBasic + Digest MD5Authentication methods accepted by VerifyCredentials. Digest SHA-256 is excluded by default to maintain FFmpeg compatibility.

Tuning

FieldTypeDefaultDescription
UDPReadBufferSizeintOS defaultSize of the UDP read buffer. Increase to reduce packet loss under high load.
WriteQueueSizeint256Size of the outbound packet queue. Must be a power of two.
MaxPacketSizeint1472Maximum size of outbound RTP/RTCP packets. Must not exceed the IPv4/UDP MTU (1472 bytes).
DisableRTCPSenderReportsboolfalseDisable automatic RTCP sender reports.

Handler

FieldTypeDescription
HandlerServerHandlerA value that implements one or more ServerHandler* interfaces. The server calls the corresponding methods when events occur.

Handler pattern

The handler is an ordinary Go struct pointer assigned to Server.Handler. The server checks at runtime which ServerHandler* interfaces the struct implements and calls only those methods. None of the interfaces are required — implement only the callbacks relevant to your use case.
type myHandler struct {
    server *gortsplib.Server
    // ... your fields
}

// Implement only the interfaces you need:
func (h *myHandler) OnConnOpen(ctx *gortsplib.ServerHandlerOnConnOpenCtx)   { /* ... */ }
func (h *myHandler) OnDescribe(ctx *gortsplib.ServerHandlerOnDescribeCtx) (
    *base.Response, *gortsplib.ServerStream, error,
) { /* ... */ }
// ...

func main() {
    h := &myHandler{}
    h.server = &gortsplib.Server{
        Handler:      h,
        RTSPAddress:  ":8554",
    }
    panic(h.server.StartAndWait())
}

Basic server setup

The following example creates a server that accepts a single publisher and relays the stream to any number of readers.
server/main.go
// Package main contains an example.
package main

import (
	"log"
	"sync"

	"github.com/pion/rtp"

	"github.com/bluenviron/gortsplib/v5"
	"github.com/bluenviron/gortsplib/v5/pkg/base"
	"github.com/bluenviron/gortsplib/v5/pkg/description"
	"github.com/bluenviron/gortsplib/v5/pkg/format"
)

type serverHandler struct {
	server    *gortsplib.Server
	mutex     sync.RWMutex
	stream    *gortsplib.ServerStream
	publisher *gortsplib.ServerSession
}

func (sh *serverHandler) OnConnOpen(_ *gortsplib.ServerHandlerOnConnOpenCtx) {
	log.Printf("conn opened")
}

func (sh *serverHandler) OnConnClose(ctx *gortsplib.ServerHandlerOnConnCloseCtx) {
	log.Printf("conn closed (%v)", ctx.Error)
}

func (sh *serverHandler) OnSessionOpen(_ *gortsplib.ServerHandlerOnSessionOpenCtx) {
	log.Printf("session opened")
}

func (sh *serverHandler) OnSessionClose(ctx *gortsplib.ServerHandlerOnSessionCloseCtx) {
	log.Printf("session closed")

	sh.mutex.Lock()
	defer sh.mutex.Unlock()

	if sh.stream != nil && ctx.Session == sh.publisher {
		sh.stream.Close()
		sh.stream = nil
	}
}

func (sh *serverHandler) OnDescribe(
	_ *gortsplib.ServerHandlerOnDescribeCtx,
) (*base.Response, *gortsplib.ServerStream, error) {
	sh.mutex.RLock()
	defer sh.mutex.RUnlock()

	if sh.stream == nil {
		return &base.Response{StatusCode: base.StatusNotFound}, nil, nil
	}
	return &base.Response{StatusCode: base.StatusOK}, sh.stream, nil
}

func (sh *serverHandler) OnAnnounce(ctx *gortsplib.ServerHandlerOnAnnounceCtx) (*base.Response, error) {
	sh.mutex.Lock()
	defer sh.mutex.Unlock()

	if sh.stream != nil {
		sh.stream.Close()
		sh.publisher.Close()
	}

	sh.stream = &gortsplib.ServerStream{
		Server: sh.server,
		Desc:   ctx.Description,
	}
	err := sh.stream.Initialize()
	if err != nil {
		panic(err)
	}
	sh.publisher = ctx.Session

	return &base.Response{StatusCode: base.StatusOK}, nil
}

func (sh *serverHandler) OnSetup(ctx *gortsplib.ServerHandlerOnSetupCtx) (
	*base.Response, *gortsplib.ServerStream, error,
) {
	// SETUP is used by both readers and publishers.
	// In case of publishers, just return StatusOK.
	if ctx.Session.State() == gortsplib.ServerSessionStatePreRecord {
		return &base.Response{StatusCode: base.StatusOK}, nil, nil
	}

	sh.mutex.RLock()
	defer sh.mutex.RUnlock()

	if sh.stream == nil {
		return &base.Response{StatusCode: base.StatusNotFound}, nil, nil
	}

	return &base.Response{StatusCode: base.StatusOK}, sh.stream, nil
}

func (sh *serverHandler) OnPlay(_ *gortsplib.ServerHandlerOnPlayCtx) (*base.Response, error) {
	return &base.Response{StatusCode: base.StatusOK}, nil
}

func (sh *serverHandler) OnRecord(ctx *gortsplib.ServerHandlerOnRecordCtx) (*base.Response, error) {
	ctx.Session.OnPacketRTPAny(func(medi *description.Media, _ format.Format, pkt *rtp.Packet) {
		sh.stream.WritePacketRTP(medi, pkt) //nolint:errcheck
	})
	return &base.Response{StatusCode: base.StatusOK}, nil
}

func main() {
	h := &serverHandler{}
	h.server = &gortsplib.Server{
		Handler:           h,
		RTSPAddress:       ":8554",
		UDPRTPAddress:     ":8000",
		UDPRTCPAddress:    ":8001",
		MulticastIPRange:  "224.1.0.0/16",
		MulticastRTPPort:  8002,
		MulticastRTCPPort: 8003,
	}

	log.Printf("server is ready on %s", h.server.RTSPAddress)
	panic(h.server.StartAndWait())
}

Server lifecycle methods

MethodDescription
Start()Starts listeners and the internal run loop. Returns an error if configuration is invalid.
StartAndWait()Calls Start() then blocks until the server shuts down.
Wait()Blocks until the server shuts down. Returns the fatal error that caused the shutdown.
Close()Signals the server to shut down and waits for all goroutines to exit.
NetListener()Returns the underlying net.Listener for the TCP port.

Next steps

Handling requests

Implement handler callbacks to control how your server responds to DESCRIBE, ANNOUNCE, SETUP, PLAY, and RECORD.

Authentication

Validate publisher and reader credentials using VerifyCredentials.

Security

Enable TLS (RTSPS) and automatic SRTP/SRTCP encryption.