2023-07-30 20:34:35 +00:00
|
|
|
// Package stream contains the Stream object.
|
|
|
|
package stream
|
2021-08-10 16:34:10 +00:00
|
|
|
|
|
|
|
import (
|
2023-08-26 16:54:28 +00:00
|
|
|
"sync"
|
2023-09-16 15:27:07 +00:00
|
|
|
"sync/atomic"
|
2023-05-14 12:18:03 +00:00
|
|
|
"time"
|
|
|
|
|
2023-08-26 16:54:28 +00:00
|
|
|
"github.com/bluenviron/gortsplib/v4"
|
|
|
|
"github.com/bluenviron/gortsplib/v4/pkg/description"
|
|
|
|
"github.com/bluenviron/gortsplib/v4/pkg/format"
|
2023-05-14 12:18:03 +00:00
|
|
|
"github.com/pion/rtp"
|
2023-01-05 11:54:00 +00:00
|
|
|
|
2023-08-30 09:24:14 +00:00
|
|
|
"github.com/bluenviron/mediamtx/internal/asyncwriter"
|
2023-07-30 20:34:35 +00:00
|
|
|
"github.com/bluenviron/mediamtx/internal/logger"
|
2023-08-25 16:11:02 +00:00
|
|
|
"github.com/bluenviron/mediamtx/internal/unit"
|
2021-08-10 16:34:10 +00:00
|
|
|
)
|
|
|
|
|
2024-02-16 22:27:27 +00:00
|
|
|
// ReadFunc is the callback passed to AddReader().
|
|
|
|
type ReadFunc func(unit.Unit) error
|
2023-08-30 09:24:14 +00:00
|
|
|
|
2023-07-30 20:34:35 +00:00
|
|
|
// Stream is a media stream.
|
2023-08-30 09:24:14 +00:00
|
|
|
// It stores tracks, readers and allows to write data to readers.
|
2023-07-30 20:34:35 +00:00
|
|
|
type Stream struct {
|
2023-09-16 15:27:07 +00:00
|
|
|
desc *description.Session
|
2023-05-04 18:16:41 +00:00
|
|
|
|
2023-09-16 15:27:07 +00:00
|
|
|
bytesReceived *uint64
|
2023-11-08 10:20:16 +00:00
|
|
|
bytesSent *uint64
|
2023-09-16 15:27:07 +00:00
|
|
|
smedias map[*description.Media]*streamMedia
|
|
|
|
mutex sync.RWMutex
|
|
|
|
rtspStream *gortsplib.ServerStream
|
|
|
|
rtspsStream *gortsplib.ServerStream
|
2021-08-10 16:34:10 +00:00
|
|
|
}
|
|
|
|
|
2023-07-30 20:34:35 +00:00
|
|
|
// New allocates a Stream.
|
|
|
|
func New(
|
2023-03-31 09:53:49 +00:00
|
|
|
udpMaxPayloadSize int,
|
2023-08-26 16:54:28 +00:00
|
|
|
desc *description.Session,
|
2022-11-11 10:59:52 +00:00
|
|
|
generateRTPPackets bool,
|
2023-08-26 21:34:39 +00:00
|
|
|
decodeErrLogger logger.Writer,
|
2023-07-30 20:34:35 +00:00
|
|
|
) (*Stream, error) {
|
|
|
|
s := &Stream{
|
2023-08-26 16:54:28 +00:00
|
|
|
desc: desc,
|
2023-09-16 15:27:07 +00:00
|
|
|
bytesReceived: new(uint64),
|
2023-11-08 10:20:16 +00:00
|
|
|
bytesSent: new(uint64),
|
2021-08-10 16:34:10 +00:00
|
|
|
}
|
2022-08-14 11:01:06 +00:00
|
|
|
|
2023-08-26 16:54:28 +00:00
|
|
|
s.smedias = make(map[*description.Media]*streamMedia)
|
2022-08-14 11:01:06 +00:00
|
|
|
|
2023-08-26 16:54:28 +00:00
|
|
|
for _, media := range desc.Medias {
|
2022-08-14 11:01:06 +00:00
|
|
|
var err error
|
2023-08-26 21:34:39 +00:00
|
|
|
s.smedias[media], err = newStreamMedia(udpMaxPayloadSize, media, generateRTPPackets, decodeErrLogger)
|
2022-08-14 11:01:06 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return s, nil
|
2021-08-10 16:34:10 +00:00
|
|
|
}
|
|
|
|
|
2023-07-30 20:34:35 +00:00
|
|
|
// Close closes all resources of the stream.
|
|
|
|
func (s *Stream) Close() {
|
2023-08-26 16:54:28 +00:00
|
|
|
if s.rtspStream != nil {
|
|
|
|
s.rtspStream.Close()
|
|
|
|
}
|
|
|
|
if s.rtspsStream != nil {
|
|
|
|
s.rtspsStream.Close()
|
|
|
|
}
|
2021-08-10 16:34:10 +00:00
|
|
|
}
|
|
|
|
|
2023-08-30 09:24:14 +00:00
|
|
|
// Desc returns the description of the stream.
|
2023-08-26 16:54:28 +00:00
|
|
|
func (s *Stream) Desc() *description.Session {
|
|
|
|
return s.desc
|
2021-08-10 16:34:10 +00:00
|
|
|
}
|
|
|
|
|
2023-09-16 15:27:07 +00:00
|
|
|
// BytesReceived returns received bytes.
|
|
|
|
func (s *Stream) BytesReceived() uint64 {
|
|
|
|
return atomic.LoadUint64(s.bytesReceived)
|
|
|
|
}
|
|
|
|
|
2023-11-08 10:20:16 +00:00
|
|
|
// BytesSent returns sent bytes.
|
|
|
|
func (s *Stream) BytesSent() uint64 {
|
|
|
|
s.mutex.RLock()
|
|
|
|
defer s.mutex.RUnlock()
|
|
|
|
|
|
|
|
bytesSent := atomic.LoadUint64(s.bytesSent)
|
|
|
|
if s.rtspStream != nil {
|
|
|
|
bytesSent += s.rtspStream.BytesSent()
|
|
|
|
}
|
|
|
|
if s.rtspsStream != nil {
|
|
|
|
bytesSent += s.rtspsStream.BytesSent()
|
|
|
|
}
|
|
|
|
return bytesSent
|
|
|
|
}
|
|
|
|
|
2023-07-30 20:34:35 +00:00
|
|
|
// RTSPStream returns the RTSP stream.
|
2023-08-26 16:54:28 +00:00
|
|
|
func (s *Stream) RTSPStream(server *gortsplib.Server) *gortsplib.ServerStream {
|
|
|
|
s.mutex.Lock()
|
|
|
|
defer s.mutex.Unlock()
|
|
|
|
|
|
|
|
if s.rtspStream == nil {
|
|
|
|
s.rtspStream = gortsplib.NewServerStream(server, s.desc)
|
|
|
|
}
|
2023-07-30 20:34:35 +00:00
|
|
|
return s.rtspStream
|
|
|
|
}
|
|
|
|
|
2023-08-26 16:54:28 +00:00
|
|
|
// RTSPSStream returns the RTSPS stream.
|
|
|
|
func (s *Stream) RTSPSStream(server *gortsplib.Server) *gortsplib.ServerStream {
|
|
|
|
s.mutex.Lock()
|
|
|
|
defer s.mutex.Unlock()
|
|
|
|
|
|
|
|
if s.rtspsStream == nil {
|
|
|
|
s.rtspsStream = gortsplib.NewServerStream(server, s.desc)
|
|
|
|
}
|
|
|
|
return s.rtspsStream
|
|
|
|
}
|
|
|
|
|
2023-07-30 20:34:35 +00:00
|
|
|
// AddReader adds a reader.
|
2024-02-16 22:27:27 +00:00
|
|
|
func (s *Stream) AddReader(r *asyncwriter.Writer, medi *description.Media, forma format.Format, cb ReadFunc) {
|
2023-08-26 16:54:28 +00:00
|
|
|
s.mutex.Lock()
|
|
|
|
defer s.mutex.Unlock()
|
|
|
|
|
2022-12-13 19:54:17 +00:00
|
|
|
sm := s.smedias[medi]
|
|
|
|
sf := sm.formats[forma]
|
2023-07-30 20:34:35 +00:00
|
|
|
sf.addReader(r, cb)
|
2021-08-10 16:34:10 +00:00
|
|
|
}
|
|
|
|
|
2023-07-30 20:34:35 +00:00
|
|
|
// RemoveReader removes a reader.
|
2023-08-30 09:24:14 +00:00
|
|
|
func (s *Stream) RemoveReader(r *asyncwriter.Writer) {
|
2023-08-26 16:54:28 +00:00
|
|
|
s.mutex.Lock()
|
|
|
|
defer s.mutex.Unlock()
|
|
|
|
|
2022-12-13 19:54:17 +00:00
|
|
|
for _, sm := range s.smedias {
|
|
|
|
for _, sf := range sm.formats {
|
2023-07-30 20:34:35 +00:00
|
|
|
sf.removeReader(r)
|
2022-12-13 19:54:17 +00:00
|
|
|
}
|
2021-08-10 16:34:10 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-01-15 11:08:14 +00:00
|
|
|
// FormatsForReader returns all formats that a reader is reading.
|
|
|
|
func (s *Stream) FormatsForReader(r *asyncwriter.Writer) []format.Format {
|
2023-10-14 20:52:10 +00:00
|
|
|
s.mutex.Lock()
|
|
|
|
defer s.mutex.Unlock()
|
|
|
|
|
2024-01-15 11:08:14 +00:00
|
|
|
var formats []format.Format
|
2023-10-14 20:52:10 +00:00
|
|
|
|
2024-01-15 11:08:14 +00:00
|
|
|
for _, sm := range s.smedias {
|
|
|
|
for forma, sf := range sm.formats {
|
2023-10-14 20:52:10 +00:00
|
|
|
if _, ok := sf.readers[r]; ok {
|
2024-01-15 11:08:14 +00:00
|
|
|
formats = append(formats, forma)
|
2023-10-14 20:52:10 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-01-15 11:08:14 +00:00
|
|
|
return formats
|
2023-10-14 20:52:10 +00:00
|
|
|
}
|
|
|
|
|
2023-07-30 20:34:35 +00:00
|
|
|
// WriteUnit writes a Unit.
|
2023-08-30 09:24:14 +00:00
|
|
|
func (s *Stream) WriteUnit(medi *description.Media, forma format.Format, u unit.Unit) {
|
2022-12-13 19:54:17 +00:00
|
|
|
sm := s.smedias[medi]
|
|
|
|
sf := sm.formats[forma]
|
2023-08-26 16:54:28 +00:00
|
|
|
|
|
|
|
s.mutex.RLock()
|
|
|
|
defer s.mutex.RUnlock()
|
|
|
|
|
2023-08-30 09:24:14 +00:00
|
|
|
sf.writeUnit(s, medi, u)
|
2021-11-12 21:29:56 +00:00
|
|
|
}
|
2023-05-14 12:18:03 +00:00
|
|
|
|
2023-07-30 20:34:35 +00:00
|
|
|
// WriteRTPPacket writes a RTP packet.
|
2023-08-26 16:54:28 +00:00
|
|
|
func (s *Stream) WriteRTPPacket(
|
|
|
|
medi *description.Media,
|
|
|
|
forma format.Format,
|
|
|
|
pkt *rtp.Packet,
|
|
|
|
ntp time.Time,
|
|
|
|
pts time.Duration,
|
|
|
|
) {
|
2023-05-14 12:18:03 +00:00
|
|
|
sm := s.smedias[medi]
|
|
|
|
sf := sm.formats[forma]
|
2023-08-26 16:54:28 +00:00
|
|
|
|
|
|
|
s.mutex.RLock()
|
|
|
|
defer s.mutex.RUnlock()
|
|
|
|
|
|
|
|
sf.writeRTPPacket(s, medi, pkt, ntp, pts)
|
2023-05-14 12:18:03 +00:00
|
|
|
}
|