mirror of
https://github.com/datarhei/core.git
synced 2025-10-06 00:17:07 +08:00
743 lines
18 KiB
Go
743 lines
18 KiB
Go
package srt
|
|
|
|
import (
|
|
"fmt"
|
|
"net/url"
|
|
"strconv"
|
|
"time"
|
|
)
|
|
|
|
const (
|
|
UDP_HEADER_SIZE = 28
|
|
SRT_HEADER_SIZE = 16
|
|
MIN_MSS_SIZE = 76
|
|
MAX_MSS_SIZE = 1500
|
|
MIN_PAYLOAD_SIZE = MIN_MSS_SIZE - UDP_HEADER_SIZE - SRT_HEADER_SIZE
|
|
MAX_PAYLOAD_SIZE = MAX_MSS_SIZE - UDP_HEADER_SIZE - SRT_HEADER_SIZE
|
|
MIN_PASSPHRASE_SIZE = 10
|
|
MAX_PASSPHRASE_SIZE = 79
|
|
MAX_STREAMID_SIZE = 512
|
|
SRT_VERSION = 0x010401
|
|
)
|
|
|
|
// Config is the configuration for a SRT connection
|
|
type Config struct {
|
|
// Type of congestion control. 'live' or 'file'
|
|
// SRTO_CONGESTION
|
|
Congestion string
|
|
|
|
// Connection timeout.
|
|
// SRTO_CONNTIMEO
|
|
ConnectionTimeout time.Duration
|
|
|
|
// Enable drift tracer.
|
|
// SRTO_DRIFTTRACER
|
|
DriftTracer bool
|
|
|
|
// Reject connection if parties set different passphrase.
|
|
// SRTO_ENFORCEDENCRYPTION
|
|
EnforcedEncryption bool
|
|
|
|
// Flow control window size. Packets.
|
|
// SRTO_FC
|
|
FC uint32
|
|
|
|
// Accept group connections.
|
|
// SRTO_GROUPCONNECT
|
|
GroupConnect bool
|
|
|
|
// Group stability timeout.
|
|
// SRTO_GROUPSTABTIMEO
|
|
GroupStabilityTimeout time.Duration
|
|
|
|
// Input bandwidth. Bytes.
|
|
// SRTO_INPUTBW
|
|
InputBW int64
|
|
|
|
// IP socket type of service
|
|
// SRTO_IPTOS
|
|
IPTOS int
|
|
|
|
// Defines IP socket "time to live" option.
|
|
// SRTO_IPTTL
|
|
IPTTL int
|
|
|
|
// Allow only IPv6.
|
|
// SRTO_IPV6ONLY
|
|
IPv6Only int
|
|
|
|
// Duration of Stream Encryption key switchover. Packets.
|
|
// SRTO_KMPREANNOUNCE
|
|
KMPreAnnounce uint64
|
|
|
|
// Stream encryption key refresh rate. Packets.
|
|
// SRTO_KMREFRESHRATE
|
|
KMRefreshRate uint64
|
|
|
|
// Defines the maximum accepted transmission latency.
|
|
// SRTO_LATENCY
|
|
Latency time.Duration
|
|
|
|
// Packet reorder tolerance.
|
|
// SRTO_LOSSMAXTTL
|
|
LossMaxTTL uint32
|
|
|
|
// Bandwidth limit in bytes/s.
|
|
// SRTO_MAXBW
|
|
MaxBW int64
|
|
|
|
// Enable SRT message mode.
|
|
// SRTO_MESSAGEAPI
|
|
MessageAPI bool
|
|
|
|
// Minimum input bandwidth
|
|
// This option is effective only if both SRTO_MAXBW and SRTO_INPUTBW are set to 0. It controls the minimum allowed value of the input bitrate estimate.
|
|
// SRTO_MININPUTBW
|
|
MinInputBW int64
|
|
|
|
// Minimum SRT library version of a peer.
|
|
// SRTO_MINVERSION
|
|
MinVersion uint32
|
|
|
|
// MTU size
|
|
// SRTO_MSS
|
|
MSS uint32
|
|
|
|
// Enable periodic NAK reports
|
|
// SRTO_NAKREPORT
|
|
NAKReport bool
|
|
|
|
// Limit bandwidth overhead, percents
|
|
// SRTO_OHEADBW
|
|
OverheadBW int64
|
|
|
|
// Set up the packet filter.
|
|
// SRTO_PACKETFILTER
|
|
PacketFilter string
|
|
|
|
// Password for the encrypted transmission.
|
|
// SRTO_PASSPHRASE
|
|
Passphrase string
|
|
|
|
// Maximum payload size. Bytes.
|
|
// SRTO_PAYLOADSIZE
|
|
PayloadSize uint32
|
|
|
|
// Crypto key length in bytes.
|
|
// SRTO_PBKEYLEN
|
|
PBKeylen int
|
|
|
|
// Peer idle timeout.
|
|
// SRTO_PEERIDLETIMEO
|
|
PeerIdleTimeout time.Duration
|
|
|
|
// Minimum receiver latency to be requested by sender.
|
|
// SRTO_PEERLATENCY
|
|
PeerLatency time.Duration
|
|
|
|
// Receiver buffer size. Bytes.
|
|
// SRTO_RCVBUF
|
|
ReceiverBufferSize uint32
|
|
|
|
// Receiver-side latency.
|
|
// SRTO_RCVLATENCY
|
|
ReceiverLatency time.Duration
|
|
|
|
// Sender buffer size. Bytes.
|
|
// SRTO_SNDBUF
|
|
SendBufferSize uint32
|
|
|
|
// Sender's delay before dropping packets.
|
|
// SRTO_SNDDROPDELAY
|
|
SendDropDelay time.Duration
|
|
|
|
// Stream ID (settable in caller mode only, visible on the listener peer)
|
|
// SRTO_STREAMID
|
|
StreamId string
|
|
|
|
// Drop too late packets.
|
|
// SRTO_TLPKTDROP
|
|
TooLatePacketDrop bool
|
|
|
|
// Transmission type. 'live' or 'file'.
|
|
// SRTO_TRANSTYPE
|
|
TransmissionType string
|
|
|
|
// Timestamp-based packet delivery mode.
|
|
// SRTO_TSBPDMODE
|
|
TSBPDMode bool
|
|
|
|
// An implementation of the Logger interface
|
|
Logger Logger
|
|
}
|
|
|
|
// DefaultConfig is the default configuration for a SRT connection
|
|
// if no individual configuration has been provided.
|
|
var defaultConfig Config = Config{
|
|
Congestion: "live",
|
|
ConnectionTimeout: 3 * time.Second,
|
|
DriftTracer: true,
|
|
EnforcedEncryption: true,
|
|
FC: 25600,
|
|
GroupConnect: false,
|
|
GroupStabilityTimeout: 0,
|
|
InputBW: 0,
|
|
IPTOS: 0,
|
|
IPTTL: 0,
|
|
IPv6Only: -1,
|
|
KMPreAnnounce: 1 << 12,
|
|
KMRefreshRate: 1 << 24,
|
|
Latency: -1,
|
|
LossMaxTTL: 0,
|
|
MaxBW: -1,
|
|
MessageAPI: false,
|
|
MinVersion: SRT_VERSION,
|
|
MSS: MAX_MSS_SIZE,
|
|
NAKReport: true,
|
|
OverheadBW: 25,
|
|
PacketFilter: "",
|
|
Passphrase: "",
|
|
PayloadSize: MAX_PAYLOAD_SIZE,
|
|
PBKeylen: 16,
|
|
PeerIdleTimeout: 2 * time.Second,
|
|
PeerLatency: 120 * time.Millisecond,
|
|
ReceiverBufferSize: 0,
|
|
ReceiverLatency: 120 * time.Millisecond,
|
|
SendBufferSize: 0,
|
|
SendDropDelay: 1 * time.Second,
|
|
StreamId: "",
|
|
TooLatePacketDrop: true,
|
|
TransmissionType: "live",
|
|
TSBPDMode: true,
|
|
}
|
|
|
|
// DefaultConfig returns the default configuration for Dial and Listen.
|
|
func DefaultConfig() Config {
|
|
return defaultConfig
|
|
}
|
|
|
|
// UnmarshalURL takes a SRT URL and parses out the configuration. A SRT URL is
|
|
// srt://[host]:[port]?[key1]=[value1]&[key2]=[value2]...
|
|
func (c *Config) UnmarshalURL(addr string) (string, error) {
|
|
u, err := url.Parse(addr)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
if u.Scheme != "srt" {
|
|
return "", fmt.Errorf("the URL doesn't seem to be an srt:// URL")
|
|
}
|
|
|
|
return u.Host, c.UnmarshalQuery(u.RawQuery)
|
|
}
|
|
|
|
// UnmarshalQuery parses a query string and interprets it as a configuration
|
|
// for a SRT connection. The key in each key/value pair corresponds to the
|
|
// respective field in the Config type, but with only lower case letters. Bool
|
|
// values can be represented as "true"/"false", "on"/"off", "yes"/"no", or "0"/"1".
|
|
func (c *Config) UnmarshalQuery(query string) error {
|
|
v, err := url.ParseQuery(query)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// https://github.com/Haivision/srt/blob/master/docs/apps/srt-live-transmit.md
|
|
|
|
if s := v.Get("congestion"); len(s) != 0 {
|
|
c.Congestion = s
|
|
}
|
|
|
|
if s := v.Get("conntimeo"); len(s) != 0 {
|
|
if d, err := strconv.Atoi(s); err == nil {
|
|
c.ConnectionTimeout = time.Duration(d) * time.Millisecond
|
|
}
|
|
}
|
|
|
|
if s := v.Get("drifttracer"); len(s) != 0 {
|
|
switch s {
|
|
case "yes", "on", "true", "1":
|
|
c.DriftTracer = true
|
|
case "no", "off", "false", "0":
|
|
c.DriftTracer = false
|
|
}
|
|
}
|
|
|
|
if s := v.Get("enforcedencryption"); len(s) != 0 {
|
|
switch s {
|
|
case "yes", "on", "true", "1":
|
|
c.EnforcedEncryption = true
|
|
case "no", "off", "false", "0":
|
|
c.EnforcedEncryption = false
|
|
}
|
|
}
|
|
|
|
if s := v.Get("fc"); len(s) != 0 {
|
|
if d, err := strconv.ParseUint(s, 10, 32); err == nil {
|
|
c.FC = uint32(d)
|
|
}
|
|
}
|
|
|
|
if s := v.Get("groupconnect"); len(s) != 0 {
|
|
switch s {
|
|
case "yes", "on", "true", "1":
|
|
c.GroupConnect = true
|
|
case "no", "off", "false", "0":
|
|
c.GroupConnect = false
|
|
}
|
|
}
|
|
|
|
if s := v.Get("groupstabtimeo"); len(s) != 0 {
|
|
if d, err := strconv.Atoi(s); err == nil {
|
|
c.GroupStabilityTimeout = time.Duration(d) * time.Millisecond
|
|
}
|
|
}
|
|
|
|
if s := v.Get("inputbw"); len(s) != 0 {
|
|
if d, err := strconv.ParseInt(s, 10, 64); err == nil {
|
|
c.InputBW = d
|
|
}
|
|
}
|
|
|
|
if s := v.Get("iptos"); len(s) != 0 {
|
|
if d, err := strconv.Atoi(s); err == nil {
|
|
c.IPTOS = d
|
|
}
|
|
}
|
|
|
|
if s := v.Get("ipttl"); len(s) != 0 {
|
|
if d, err := strconv.Atoi(s); err == nil {
|
|
c.IPTTL = d
|
|
}
|
|
}
|
|
|
|
if s := v.Get("ipv6only"); len(s) != 0 {
|
|
if d, err := strconv.Atoi(s); err == nil {
|
|
c.IPv6Only = d
|
|
}
|
|
}
|
|
|
|
if s := v.Get("kmpreannounce"); len(s) != 0 {
|
|
if d, err := strconv.ParseUint(s, 10, 64); err == nil {
|
|
c.KMPreAnnounce = d
|
|
}
|
|
}
|
|
|
|
if s := v.Get("kmrefreshrate"); len(s) != 0 {
|
|
if d, err := strconv.ParseUint(s, 10, 64); err == nil {
|
|
c.KMRefreshRate = d
|
|
}
|
|
}
|
|
|
|
if s := v.Get("latency"); len(s) != 0 {
|
|
if d, err := strconv.Atoi(s); err == nil {
|
|
c.Latency = time.Duration(d) * time.Millisecond
|
|
}
|
|
}
|
|
|
|
if s := v.Get("lossmaxttl"); len(s) != 0 {
|
|
if d, err := strconv.ParseUint(s, 10, 32); err == nil {
|
|
c.LossMaxTTL = uint32(d)
|
|
}
|
|
}
|
|
|
|
if s := v.Get("maxbw"); len(s) != 0 {
|
|
if d, err := strconv.ParseInt(s, 10, 64); err == nil {
|
|
c.MaxBW = d
|
|
}
|
|
}
|
|
|
|
if s := v.Get("mininputbw"); len(s) != 0 {
|
|
if d, err := strconv.ParseInt(s, 10, 64); err == nil {
|
|
c.MinInputBW = d
|
|
}
|
|
}
|
|
|
|
if s := v.Get("messageapi"); len(s) != 0 {
|
|
switch s {
|
|
case "yes", "on", "true", "1":
|
|
c.MessageAPI = true
|
|
case "no", "off", "false", "0":
|
|
c.MessageAPI = false
|
|
}
|
|
}
|
|
|
|
// minversion is ignored
|
|
|
|
if s := v.Get("mss"); len(s) != 0 {
|
|
if d, err := strconv.ParseUint(s, 10, 32); err == nil {
|
|
c.MSS = uint32(d)
|
|
}
|
|
}
|
|
|
|
if s := v.Get("nakreport"); len(s) != 0 {
|
|
switch s {
|
|
case "yes", "on", "true", "1":
|
|
c.NAKReport = true
|
|
case "no", "off", "false", "0":
|
|
c.NAKReport = false
|
|
}
|
|
}
|
|
|
|
if s := v.Get("oheadbw"); len(s) != 0 {
|
|
if d, err := strconv.ParseInt(s, 10, 64); err == nil {
|
|
c.OverheadBW = d
|
|
}
|
|
}
|
|
|
|
if s := v.Get("packetfilter"); len(s) != 0 {
|
|
c.PacketFilter = s
|
|
}
|
|
|
|
if s := v.Get("passphrase"); len(s) != 0 {
|
|
c.Passphrase = s
|
|
}
|
|
|
|
if s := v.Get("payloadsize"); len(s) != 0 {
|
|
if d, err := strconv.ParseUint(s, 10, 32); err == nil {
|
|
c.PayloadSize = uint32(d)
|
|
}
|
|
}
|
|
|
|
if s := v.Get("pbkeylen"); len(s) != 0 {
|
|
if d, err := strconv.Atoi(s); err == nil {
|
|
c.PBKeylen = d
|
|
}
|
|
}
|
|
|
|
if s := v.Get("peeridletimeo"); len(s) != 0 {
|
|
if d, err := strconv.Atoi(s); err == nil {
|
|
c.PeerIdleTimeout = time.Duration(d) * time.Millisecond
|
|
}
|
|
}
|
|
|
|
if s := v.Get("peerlatency"); len(s) != 0 {
|
|
if d, err := strconv.Atoi(s); err == nil {
|
|
c.PeerLatency = time.Duration(d) * time.Millisecond
|
|
}
|
|
}
|
|
|
|
if s := v.Get("rcvbuf"); len(s) != 0 {
|
|
if d, err := strconv.ParseUint(s, 10, 32); err == nil {
|
|
c.ReceiverBufferSize = uint32(d)
|
|
}
|
|
}
|
|
|
|
if s := v.Get("rcvlatency"); len(s) != 0 {
|
|
if d, err := strconv.Atoi(s); err == nil {
|
|
c.ReceiverLatency = time.Duration(d) * time.Millisecond
|
|
}
|
|
}
|
|
|
|
// retransmitalgo not implemented (there's only one)
|
|
|
|
if s := v.Get("sndbuf"); len(s) != 0 {
|
|
if d, err := strconv.ParseUint(s, 10, 32); err == nil {
|
|
c.SendBufferSize = uint32(d)
|
|
}
|
|
}
|
|
|
|
if s := v.Get("snddropdelay"); len(s) != 0 {
|
|
if d, err := strconv.Atoi(s); err == nil {
|
|
c.SendDropDelay = time.Duration(d) * time.Millisecond
|
|
}
|
|
}
|
|
|
|
if s := v.Get("streamid"); len(s) != 0 {
|
|
c.StreamId = s
|
|
}
|
|
|
|
if s := v.Get("tlpktdrop"); len(s) != 0 {
|
|
switch s {
|
|
case "yes", "on", "true", "1":
|
|
c.TooLatePacketDrop = true
|
|
case "no", "off", "false", "0":
|
|
c.TooLatePacketDrop = false
|
|
}
|
|
}
|
|
|
|
if s := v.Get("transtype"); len(s) != 0 {
|
|
c.TransmissionType = s
|
|
}
|
|
|
|
if s := v.Get("tsbpdmode"); len(s) != 0 {
|
|
switch s {
|
|
case "yes", "on", "true", "1":
|
|
c.TSBPDMode = true
|
|
case "no", "off", "false", "0":
|
|
c.TSBPDMode = false
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// MarshalURL returns the SRT URL for this config and the given host and port.
|
|
func (c *Config) MarshalURL(host string, port uint) string {
|
|
return "srt://" + host + ":" + strconv.FormatUint(uint64(port), 10) + "?" + c.MarshalQuery()
|
|
}
|
|
|
|
// MarshalQuery returns the corresponding query string for a configuration.
|
|
func (c *Config) MarshalQuery() string {
|
|
q := url.Values{}
|
|
|
|
if c.Congestion != defaultConfig.Congestion {
|
|
q.Set("congestion", c.Congestion)
|
|
}
|
|
|
|
if c.ConnectionTimeout != defaultConfig.ConnectionTimeout {
|
|
q.Set("conntimeo", strconv.FormatInt(c.ConnectionTimeout.Milliseconds(), 10))
|
|
}
|
|
|
|
if c.DriftTracer != defaultConfig.DriftTracer {
|
|
q.Set("drifttracer", strconv.FormatBool(c.DriftTracer))
|
|
}
|
|
|
|
if c.EnforcedEncryption != defaultConfig.EnforcedEncryption {
|
|
q.Set("enforcedencryption", strconv.FormatBool(c.EnforcedEncryption))
|
|
}
|
|
|
|
if c.FC != defaultConfig.FC {
|
|
q.Set("fc", strconv.FormatUint(uint64(c.FC), 10))
|
|
}
|
|
|
|
if c.GroupConnect != defaultConfig.GroupConnect {
|
|
q.Set("groupconnect", strconv.FormatBool(c.GroupConnect))
|
|
}
|
|
|
|
if c.GroupStabilityTimeout != defaultConfig.GroupStabilityTimeout {
|
|
q.Set("groupstabtimeo", strconv.FormatInt(c.GroupStabilityTimeout.Milliseconds(), 10))
|
|
}
|
|
|
|
if c.InputBW != defaultConfig.InputBW {
|
|
q.Set("inputbw", strconv.FormatInt(c.InputBW, 10))
|
|
}
|
|
|
|
if c.IPTOS != defaultConfig.IPTOS {
|
|
q.Set("iptos", strconv.FormatInt(int64(c.IPTOS), 10))
|
|
}
|
|
|
|
if c.IPTTL != defaultConfig.IPTTL {
|
|
q.Set("ipttl", strconv.FormatInt(int64(c.IPTTL), 10))
|
|
}
|
|
|
|
if c.IPv6Only != defaultConfig.IPv6Only {
|
|
q.Set("ipv6only", strconv.FormatInt(int64(c.IPv6Only), 10))
|
|
}
|
|
|
|
if len(c.Passphrase) != 0 {
|
|
if c.KMPreAnnounce != defaultConfig.KMPreAnnounce {
|
|
q.Set("kmpreannounce", strconv.FormatUint(c.KMPreAnnounce, 10))
|
|
}
|
|
|
|
if c.KMRefreshRate != defaultConfig.KMRefreshRate {
|
|
q.Set("kmrefreshrate", strconv.FormatUint(c.KMRefreshRate, 10))
|
|
}
|
|
}
|
|
|
|
if c.Latency != defaultConfig.Latency {
|
|
q.Set("latency", strconv.FormatInt(c.Latency.Milliseconds(), 10))
|
|
}
|
|
|
|
if c.LossMaxTTL != defaultConfig.LossMaxTTL {
|
|
q.Set("lossmaxttl", strconv.FormatInt(int64(c.LossMaxTTL), 10))
|
|
}
|
|
|
|
if c.MaxBW != defaultConfig.MaxBW {
|
|
q.Set("maxbw", strconv.FormatInt(c.MaxBW, 10))
|
|
}
|
|
|
|
if c.MinInputBW != defaultConfig.InputBW {
|
|
q.Set("mininputbw", strconv.FormatInt(c.MinInputBW, 10))
|
|
}
|
|
|
|
if c.MessageAPI != defaultConfig.MessageAPI {
|
|
q.Set("messageapi", strconv.FormatBool(c.MessageAPI))
|
|
}
|
|
|
|
if c.MSS != defaultConfig.MSS {
|
|
q.Set("mss", strconv.FormatUint(uint64(c.MSS), 10))
|
|
}
|
|
|
|
if c.NAKReport != defaultConfig.NAKReport {
|
|
q.Set("nakreport", strconv.FormatBool(c.NAKReport))
|
|
}
|
|
|
|
if c.OverheadBW != defaultConfig.OverheadBW {
|
|
q.Set("oheadbw", strconv.FormatInt(c.OverheadBW, 10))
|
|
}
|
|
|
|
if c.PacketFilter != defaultConfig.PacketFilter {
|
|
q.Set("packetfilter", c.PacketFilter)
|
|
}
|
|
|
|
if len(c.Passphrase) != 0 {
|
|
q.Set("passphrase", c.Passphrase)
|
|
}
|
|
|
|
if c.PayloadSize != defaultConfig.PayloadSize {
|
|
q.Set("payloadsize", strconv.FormatUint(uint64(c.PayloadSize), 10))
|
|
}
|
|
|
|
if c.PBKeylen != defaultConfig.PBKeylen {
|
|
q.Set("pbkeylen", strconv.FormatInt(int64(c.PBKeylen), 10))
|
|
}
|
|
|
|
if c.PeerIdleTimeout != defaultConfig.PeerIdleTimeout {
|
|
q.Set("peeridletimeo", strconv.FormatInt(c.PeerIdleTimeout.Milliseconds(), 10))
|
|
}
|
|
|
|
if c.PeerLatency != defaultConfig.PeerLatency {
|
|
q.Set("peerlatency", strconv.FormatInt(c.PeerLatency.Milliseconds(), 10))
|
|
}
|
|
|
|
if c.ReceiverBufferSize != defaultConfig.ReceiverBufferSize {
|
|
q.Set("rcvbuf", strconv.FormatInt(int64(c.ReceiverBufferSize), 10))
|
|
}
|
|
|
|
if c.ReceiverLatency != defaultConfig.ReceiverLatency {
|
|
q.Set("rcvlatency", strconv.FormatInt(c.ReceiverLatency.Milliseconds(), 10))
|
|
}
|
|
|
|
if c.SendBufferSize != defaultConfig.SendBufferSize {
|
|
q.Set("sndbuf", strconv.FormatInt(int64(c.SendBufferSize), 10))
|
|
}
|
|
|
|
if c.SendDropDelay != defaultConfig.SendDropDelay {
|
|
q.Set("snddropdelay", strconv.FormatInt(c.SendDropDelay.Milliseconds(), 10))
|
|
}
|
|
|
|
if len(c.StreamId) != 0 {
|
|
q.Set("streamid", c.StreamId)
|
|
}
|
|
|
|
if c.TooLatePacketDrop != defaultConfig.TooLatePacketDrop {
|
|
q.Set("tlpktdrop", strconv.FormatBool(c.TooLatePacketDrop))
|
|
}
|
|
|
|
if c.TransmissionType != defaultConfig.TransmissionType {
|
|
q.Set("transtype", c.TransmissionType)
|
|
}
|
|
|
|
if c.TSBPDMode != defaultConfig.TSBPDMode {
|
|
q.Set("tsbpdmode", strconv.FormatBool(c.TSBPDMode))
|
|
}
|
|
|
|
return q.Encode()
|
|
}
|
|
|
|
// Validate validates a configuration or returns an error if a field
|
|
// has an invalid value.
|
|
func (c Config) Validate() error {
|
|
if c.TransmissionType != "live" {
|
|
return fmt.Errorf("config: TransmissionType must be 'live'")
|
|
}
|
|
|
|
c.Congestion = "live"
|
|
c.NAKReport = true
|
|
c.TooLatePacketDrop = true
|
|
c.TSBPDMode = true
|
|
|
|
if c.Congestion != "live" {
|
|
return fmt.Errorf("config: Congestion mode must be 'live'")
|
|
}
|
|
|
|
if c.ConnectionTimeout <= 0 {
|
|
return fmt.Errorf("config: ConnectionTimeout must be greater than 0")
|
|
}
|
|
|
|
if c.GroupConnect {
|
|
return fmt.Errorf("config: GroupConnect is not supported")
|
|
}
|
|
|
|
if c.IPTOS > 0 && c.IPTOS > 255 {
|
|
return fmt.Errorf("config: IPTOS must be lower than 255")
|
|
}
|
|
|
|
if c.IPTTL > 0 && c.IPTTL > 255 {
|
|
return fmt.Errorf("config: IPTTL must be between 1 and 255")
|
|
}
|
|
|
|
if c.IPv6Only > 0 {
|
|
return fmt.Errorf("config: IPv6Only is not supported")
|
|
}
|
|
|
|
if c.KMRefreshRate != 0 {
|
|
if c.KMPreAnnounce < 1 || c.KMPreAnnounce > c.KMRefreshRate/2 {
|
|
return fmt.Errorf("config: KMPreAnnounce must be greater than 1 and smaller than KMRefreshRate/2")
|
|
}
|
|
}
|
|
|
|
if c.Latency >= 0 {
|
|
c.PeerLatency = c.Latency
|
|
c.ReceiverLatency = c.Latency
|
|
}
|
|
|
|
if c.MinVersion != SRT_VERSION {
|
|
return fmt.Errorf("config: MinVersion must be %#06x", SRT_VERSION)
|
|
}
|
|
|
|
if c.MSS < MIN_MSS_SIZE || c.MSS > MAX_MSS_SIZE {
|
|
return fmt.Errorf("config: MSS must be between %d and %d (both inclusive)", MIN_MSS_SIZE, MAX_MSS_SIZE)
|
|
}
|
|
|
|
if !c.NAKReport {
|
|
return fmt.Errorf("config: NAKReport must be enabled")
|
|
}
|
|
|
|
if c.OverheadBW < 10 || c.OverheadBW > 100 {
|
|
return fmt.Errorf("config: OverheadBW must be between 10 and 100")
|
|
}
|
|
|
|
if len(c.PacketFilter) != 0 {
|
|
return fmt.Errorf("config: PacketFilter are not supported")
|
|
}
|
|
|
|
if len(c.Passphrase) != 0 {
|
|
if len(c.Passphrase) < MIN_PASSPHRASE_SIZE || len(c.Passphrase) > MAX_PASSPHRASE_SIZE {
|
|
return fmt.Errorf("config: Passphrase must be between %d and %d bytes long", MIN_PASSPHRASE_SIZE, MAX_PASSPHRASE_SIZE)
|
|
}
|
|
}
|
|
|
|
if c.PayloadSize < MIN_PAYLOAD_SIZE || c.PayloadSize > MAX_PAYLOAD_SIZE {
|
|
return fmt.Errorf("config: PayloadSize must be between %d and %d (both inclusive)", MIN_PAYLOAD_SIZE, MAX_PAYLOAD_SIZE)
|
|
}
|
|
|
|
if c.PayloadSize > c.MSS-uint32(SRT_HEADER_SIZE+UDP_HEADER_SIZE) {
|
|
return fmt.Errorf("config: PayloadSize must not be larger than %d (MSS - %d)", c.MSS-uint32(SRT_HEADER_SIZE+UDP_HEADER_SIZE), SRT_HEADER_SIZE-UDP_HEADER_SIZE)
|
|
}
|
|
|
|
if c.PBKeylen != 16 && c.PBKeylen != 24 && c.PBKeylen != 32 {
|
|
return fmt.Errorf("config: PBKeylen must be 16, 24, or 32 bytes")
|
|
}
|
|
|
|
if c.PeerLatency < 0 {
|
|
return fmt.Errorf("config: PeerLatency must be greater than 0")
|
|
}
|
|
|
|
if c.ReceiverLatency < 0 {
|
|
return fmt.Errorf("config: ReceiverLatency must be greater than 0")
|
|
}
|
|
|
|
if c.SendDropDelay < 0 {
|
|
return fmt.Errorf("config: SendDropDelay must be greater than 0")
|
|
}
|
|
|
|
if len(c.StreamId) > MAX_STREAMID_SIZE {
|
|
return fmt.Errorf("config: StreamId must be shorter than or equal to %d bytes", MAX_STREAMID_SIZE)
|
|
}
|
|
|
|
if !c.TooLatePacketDrop {
|
|
return fmt.Errorf("config: TooLatePacketDrop must be enabled")
|
|
}
|
|
|
|
if c.TransmissionType != "live" {
|
|
return fmt.Errorf("config: TransmissionType must be 'live'")
|
|
}
|
|
|
|
if !c.TSBPDMode {
|
|
return fmt.Errorf("config: TSBPDMode must be enabled")
|
|
}
|
|
|
|
return nil
|
|
}
|