Files
mediamtx/internal/forward/srt/dest.go
T

122 lines
2.5 KiB
Go

// Package srt contains the SRT forward destination.
package srt
import (
"bufio"
"context"
"fmt"
"sync"
"time"
srtlib "github.com/datarhei/gosrt"
"github.com/bluenviron/mediamtx/internal/conf"
"github.com/bluenviron/mediamtx/internal/logger"
"github.com/bluenviron/mediamtx/internal/protocols/mpegts"
"github.com/bluenviron/mediamtx/internal/stream"
)
func maxPayloadSize(v int) int {
return ((v - 16) / 188) * 188
}
// Dest is a SRT forward destination.
type Dest struct {
Stream *stream.Stream
Dest string
WriteTimeout conf.Duration
UDPMaxPayloadSize int
Parent logger.Writer
mutex sync.RWMutex
outboundBytesFunc func() uint64
}
// Log implements logger.Writer.
func (d *Dest) Log(level logger.Level, format string, args ...any) {
d.Parent.Log(level, format, args...)
}
// OutboundBytes returns the number of bytes sent by the destination.
func (d *Dest) OutboundBytes() uint64 {
d.mutex.RLock()
defer d.mutex.RUnlock()
if d.outboundBytesFunc == nil {
return 0
}
return d.outboundBytesFunc()
}
// Run runs the destination.
func (d *Dest) Run(ctx context.Context) error {
srtConf := srtlib.DefaultConfig()
address, err := srtConf.UnmarshalURL(d.Dest)
if err != nil {
return err
}
udpMaxPayloadSize := d.UDPMaxPayloadSize
if udpMaxPayloadSize == 0 {
udpMaxPayloadSize = 1472
}
srtConf.PayloadSize = uint32(maxPayloadSize(udpMaxPayloadSize))
err = srtConf.Validate()
if err != nil {
return err
}
terminate := make(chan struct{})
errChan := make(chan error)
go func() {
errChan <- d.runInner(ctx, address, srtConf, terminate)
}()
select {
case err = <-errChan:
return err
case <-ctx.Done():
close(terminate)
<-errChan
return fmt.Errorf("terminated")
}
}
func (d *Dest) runInner(ctx context.Context, address string, srtConf srtlib.Config, terminate <-chan struct{}) error {
conn, err := srtlib.DialWithContext(ctx, "srt", address, srtConf)
if err != nil {
return err
}
defer conn.Close()
d.mutex.Lock()
d.outboundBytesFunc = func() uint64 {
var stats srtlib.Statistics
conn.Stats(&stats)
return stats.Accumulated.ByteSent
}
d.mutex.Unlock()
r := &stream.Reader{Parent: d}
bw := bufio.NewWriterSize(conn, int(srtConf.PayloadSize))
err = mpegts.FromStream(d.Stream.OrigDesc, r, bw, conn, time.Duration(d.WriteTimeout))
if err != nil {
return err
}
d.Stream.AddReader(r)
defer d.Stream.RemoveReader(r)
select {
case readErr := <-r.Error():
return readErr
case <-terminate:
return nil
}
}