mirror of
https://github.com/aler9/gortsplib
synced 2025-10-05 15:16:51 +08:00
add RTP-Info header
This commit is contained in:
@@ -79,7 +79,7 @@ func findValue(v0 string) (string, string, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReadAuth parses an Authenticate or a WWW-Authenticate header.
|
// ReadAuth decodes an Authenticate or a WWW-Authenticate header.
|
||||||
func ReadAuth(v base.HeaderValue) (*Auth, error) {
|
func ReadAuth(v base.HeaderValue) (*Auth, error) {
|
||||||
if len(v) == 0 {
|
if len(v) == 0 {
|
||||||
return nil, fmt.Errorf("value not provided")
|
return nil, fmt.Errorf("value not provided")
|
||||||
@@ -89,7 +89,7 @@ func ReadAuth(v base.HeaderValue) (*Auth, error) {
|
|||||||
return nil, fmt.Errorf("value provided multiple times (%v)", v)
|
return nil, fmt.Errorf("value provided multiple times (%v)", v)
|
||||||
}
|
}
|
||||||
|
|
||||||
ha := &Auth{}
|
h := &Auth{}
|
||||||
|
|
||||||
v0 := v[0]
|
v0 := v[0]
|
||||||
|
|
||||||
@@ -100,10 +100,10 @@ func ReadAuth(v base.HeaderValue) (*Auth, error) {
|
|||||||
|
|
||||||
switch v0[:i] {
|
switch v0[:i] {
|
||||||
case "Basic":
|
case "Basic":
|
||||||
ha.Method = AuthBasic
|
h.Method = AuthBasic
|
||||||
|
|
||||||
case "Digest":
|
case "Digest":
|
||||||
ha.Method = AuthDigest
|
h.Method = AuthDigest
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("invalid method (%s)", v0[:i])
|
return nil, fmt.Errorf("invalid method (%s)", v0[:i])
|
||||||
@@ -127,28 +127,28 @@ func ReadAuth(v base.HeaderValue) (*Auth, error) {
|
|||||||
|
|
||||||
switch key {
|
switch key {
|
||||||
case "username":
|
case "username":
|
||||||
ha.Username = &val
|
h.Username = &val
|
||||||
|
|
||||||
case "realm":
|
case "realm":
|
||||||
ha.Realm = &val
|
h.Realm = &val
|
||||||
|
|
||||||
case "nonce":
|
case "nonce":
|
||||||
ha.Nonce = &val
|
h.Nonce = &val
|
||||||
|
|
||||||
case "uri":
|
case "uri":
|
||||||
ha.URI = &val
|
h.URI = &val
|
||||||
|
|
||||||
case "response":
|
case "response":
|
||||||
ha.Response = &val
|
h.Response = &val
|
||||||
|
|
||||||
case "opaque":
|
case "opaque":
|
||||||
ha.Opaque = &val
|
h.Opaque = &val
|
||||||
|
|
||||||
case "stale":
|
case "stale":
|
||||||
ha.Stale = &val
|
h.Stale = &val
|
||||||
|
|
||||||
case "algorithm":
|
case "algorithm":
|
||||||
ha.Algorithm = &val
|
h.Algorithm = &val
|
||||||
|
|
||||||
// ignore non-standard keys
|
// ignore non-standard keys
|
||||||
}
|
}
|
||||||
@@ -164,14 +164,14 @@ func ReadAuth(v base.HeaderValue) (*Auth, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ha, nil
|
return h, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write encodes an Authenticate or a WWW-Authenticate header.
|
// Write encodes an Authenticate or a WWW-Authenticate header.
|
||||||
func (ha Auth) Write() base.HeaderValue {
|
func (h Auth) Write() base.HeaderValue {
|
||||||
ret := ""
|
ret := ""
|
||||||
|
|
||||||
switch ha.Method {
|
switch h.Method {
|
||||||
case AuthBasic:
|
case AuthBasic:
|
||||||
ret += "Basic"
|
ret += "Basic"
|
||||||
|
|
||||||
@@ -181,41 +181,41 @@ func (ha Auth) Write() base.HeaderValue {
|
|||||||
|
|
||||||
ret += " "
|
ret += " "
|
||||||
|
|
||||||
var vals []string
|
var rets []string
|
||||||
|
|
||||||
if ha.Username != nil {
|
if h.Username != nil {
|
||||||
vals = append(vals, "username=\""+*ha.Username+"\"")
|
rets = append(rets, "username=\""+*h.Username+"\"")
|
||||||
}
|
}
|
||||||
|
|
||||||
if ha.Realm != nil {
|
if h.Realm != nil {
|
||||||
vals = append(vals, "realm=\""+*ha.Realm+"\"")
|
rets = append(rets, "realm=\""+*h.Realm+"\"")
|
||||||
}
|
}
|
||||||
|
|
||||||
if ha.Nonce != nil {
|
if h.Nonce != nil {
|
||||||
vals = append(vals, "nonce=\""+*ha.Nonce+"\"")
|
rets = append(rets, "nonce=\""+*h.Nonce+"\"")
|
||||||
}
|
}
|
||||||
|
|
||||||
if ha.URI != nil {
|
if h.URI != nil {
|
||||||
vals = append(vals, "uri=\""+*ha.URI+"\"")
|
rets = append(rets, "uri=\""+*h.URI+"\"")
|
||||||
}
|
}
|
||||||
|
|
||||||
if ha.Response != nil {
|
if h.Response != nil {
|
||||||
vals = append(vals, "response=\""+*ha.Response+"\"")
|
rets = append(rets, "response=\""+*h.Response+"\"")
|
||||||
}
|
}
|
||||||
|
|
||||||
if ha.Opaque != nil {
|
if h.Opaque != nil {
|
||||||
vals = append(vals, "opaque=\""+*ha.Opaque+"\"")
|
rets = append(rets, "opaque=\""+*h.Opaque+"\"")
|
||||||
}
|
}
|
||||||
|
|
||||||
if ha.Stale != nil {
|
if h.Stale != nil {
|
||||||
vals = append(vals, "stale=\""+*ha.Stale+"\"")
|
rets = append(rets, "stale=\""+*h.Stale+"\"")
|
||||||
}
|
}
|
||||||
|
|
||||||
if ha.Algorithm != nil {
|
if h.Algorithm != nil {
|
||||||
vals = append(vals, "algorithm=\""+*ha.Algorithm+"\"")
|
rets = append(rets, "algorithm=\""+*h.Algorithm+"\"")
|
||||||
}
|
}
|
||||||
|
|
||||||
ret += strings.Join(vals, ", ")
|
ret += strings.Join(rets, ", ")
|
||||||
|
|
||||||
return base.HeaderValue{ret}
|
return base.HeaderValue{ret}
|
||||||
}
|
}
|
||||||
|
87
pkg/headers/rtpinfo.go
Normal file
87
pkg/headers/rtpinfo.go
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
package headers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/aler9/gortsplib/pkg/base"
|
||||||
|
)
|
||||||
|
|
||||||
|
// RTPInfoEntry is an entry of an RTP-Info header.
|
||||||
|
type RTPInfoEntry struct {
|
||||||
|
URL *base.URL
|
||||||
|
SequenceNumber uint16
|
||||||
|
RTPTime uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
// RTPInfo is a RTP-Info header.
|
||||||
|
type RTPInfo []RTPInfoEntry
|
||||||
|
|
||||||
|
// ReadRTPInfo decodes a RTP-Info header.
|
||||||
|
func ReadRTPInfo(v base.HeaderValue) (*RTPInfo, error) {
|
||||||
|
if len(v) == 0 {
|
||||||
|
return nil, fmt.Errorf("value not provided")
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(v) > 1 {
|
||||||
|
return nil, fmt.Errorf("value provided multiple times (%v)", v)
|
||||||
|
}
|
||||||
|
|
||||||
|
h := &RTPInfo{}
|
||||||
|
|
||||||
|
for _, tmp := range strings.Split(v[0], ",") {
|
||||||
|
e := RTPInfoEntry{}
|
||||||
|
|
||||||
|
for _, kv := range strings.Split(tmp, ";") {
|
||||||
|
tmp := strings.SplitN(kv, "=", 2)
|
||||||
|
if len(tmp) != 2 {
|
||||||
|
return nil, fmt.Errorf("unable to parse key-value (%v)", kv)
|
||||||
|
}
|
||||||
|
|
||||||
|
k, v := tmp[0], tmp[1]
|
||||||
|
switch k {
|
||||||
|
case "url":
|
||||||
|
vu, err := base.ParseURL(v)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
e.URL = vu
|
||||||
|
|
||||||
|
case "seq":
|
||||||
|
vi, err := strconv.ParseUint(v, 10, 16)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
e.SequenceNumber = uint16(vi)
|
||||||
|
|
||||||
|
case "rtptime":
|
||||||
|
vi, err := strconv.ParseUint(v, 10, 32)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
e.RTPTime = uint32(vi)
|
||||||
|
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("invalid key: %v", k)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*h = append(*h, e)
|
||||||
|
}
|
||||||
|
|
||||||
|
return h, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write encodes a RTP-Info header.
|
||||||
|
func (h RTPInfo) Write() base.HeaderValue {
|
||||||
|
var rets []string
|
||||||
|
|
||||||
|
for _, e := range h {
|
||||||
|
rets = append(rets, "url="+e.URL.String()+
|
||||||
|
";seq="+strconv.FormatUint(uint64(e.SequenceNumber), 10)+
|
||||||
|
";rtptime="+strconv.FormatUint(uint64(e.RTPTime), 10))
|
||||||
|
}
|
||||||
|
|
||||||
|
return base.HeaderValue{strings.Join(rets, ",")}
|
||||||
|
}
|
65
pkg/headers/rtpinfo_test.go
Normal file
65
pkg/headers/rtpinfo_test.go
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
package headers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
|
"github.com/aler9/gortsplib/pkg/base"
|
||||||
|
)
|
||||||
|
|
||||||
|
var casesRTPInfo = []struct {
|
||||||
|
name string
|
||||||
|
vin base.HeaderValue
|
||||||
|
vout base.HeaderValue
|
||||||
|
h *RTPInfo
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
"single value",
|
||||||
|
base.HeaderValue{`url=rtsp://127.0.0.1/test.mkv/track1;seq=35243;rtptime=717574556`},
|
||||||
|
base.HeaderValue{`url=rtsp://127.0.0.1/test.mkv/track1;seq=35243;rtptime=717574556`},
|
||||||
|
&RTPInfo{
|
||||||
|
{
|
||||||
|
URL: base.MustParseURL("rtsp://127.0.0.1/test.mkv/track1"),
|
||||||
|
SequenceNumber: 35243,
|
||||||
|
RTPTime: 717574556,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"multiple value",
|
||||||
|
base.HeaderValue{`url=rtsp://127.0.0.1/test.mkv/track1;seq=35243;rtptime=717574556,url=rtsp://127.0.0.1/test.mkv/track2;seq=13655;rtptime=2848846950`},
|
||||||
|
base.HeaderValue{`url=rtsp://127.0.0.1/test.mkv/track1;seq=35243;rtptime=717574556,url=rtsp://127.0.0.1/test.mkv/track2;seq=13655;rtptime=2848846950`},
|
||||||
|
&RTPInfo{
|
||||||
|
{
|
||||||
|
URL: base.MustParseURL("rtsp://127.0.0.1/test.mkv/track1"),
|
||||||
|
SequenceNumber: 35243,
|
||||||
|
RTPTime: 717574556,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
URL: base.MustParseURL("rtsp://127.0.0.1/test.mkv/track2"),
|
||||||
|
SequenceNumber: 13655,
|
||||||
|
RTPTime: 2848846950,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRTPInfoRead(t *testing.T) {
|
||||||
|
for _, c := range casesRTPInfo {
|
||||||
|
t.Run(c.name, func(t *testing.T) {
|
||||||
|
req, err := ReadRTPInfo(c.vin)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, c.h, req)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRTPInfoWrite(t *testing.T) {
|
||||||
|
for _, c := range casesRTPInfo {
|
||||||
|
t.Run(c.name, func(t *testing.T) {
|
||||||
|
req := c.h.Write()
|
||||||
|
require.Equal(t, c.vout, req)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
@@ -17,7 +17,7 @@ type Session struct {
|
|||||||
Timeout *uint
|
Timeout *uint
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReadSession parses a Session header.
|
// ReadSession decodes a Session header.
|
||||||
func ReadSession(v base.HeaderValue) (*Session, error) {
|
func ReadSession(v base.HeaderValue) (*Session, error) {
|
||||||
if len(v) == 0 {
|
if len(v) == 0 {
|
||||||
return nil, fmt.Errorf("value not provided")
|
return nil, fmt.Errorf("value not provided")
|
||||||
@@ -32,20 +32,20 @@ func ReadSession(v base.HeaderValue) (*Session, error) {
|
|||||||
return nil, fmt.Errorf("invalid value (%v)", v)
|
return nil, fmt.Errorf("invalid value (%v)", v)
|
||||||
}
|
}
|
||||||
|
|
||||||
hs := &Session{}
|
h := &Session{}
|
||||||
|
|
||||||
hs.Session = parts[0]
|
h.Session = parts[0]
|
||||||
|
|
||||||
for _, part := range parts[1:] {
|
for _, part := range parts[1:] {
|
||||||
// remove leading spaces
|
// remove leading spaces
|
||||||
part = strings.TrimLeft(part, " ")
|
part = strings.TrimLeft(part, " ")
|
||||||
|
|
||||||
keyval := strings.Split(part, "=")
|
kv := strings.Split(part, "=")
|
||||||
if len(keyval) != 2 {
|
if len(kv) != 2 {
|
||||||
return nil, fmt.Errorf("invalid value")
|
return nil, fmt.Errorf("invalid value")
|
||||||
}
|
}
|
||||||
|
|
||||||
key, strValue := keyval[0], keyval[1]
|
key, strValue := kv[0], kv[1]
|
||||||
if key != "timeout" {
|
if key != "timeout" {
|
||||||
return nil, fmt.Errorf("invalid key '%s'", key)
|
return nil, fmt.Errorf("invalid key '%s'", key)
|
||||||
}
|
}
|
||||||
@@ -56,19 +56,19 @@ func ReadSession(v base.HeaderValue) (*Session, error) {
|
|||||||
}
|
}
|
||||||
uiv := uint(iv)
|
uiv := uint(iv)
|
||||||
|
|
||||||
hs.Timeout = &uiv
|
h.Timeout = &uiv
|
||||||
}
|
}
|
||||||
|
|
||||||
return hs, nil
|
return h, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write encodes a Session header
|
// Write encodes a Session header.
|
||||||
func (hs Session) Write() base.HeaderValue {
|
func (h Session) Write() base.HeaderValue {
|
||||||
val := hs.Session
|
ret := h.Session
|
||||||
|
|
||||||
if hs.Timeout != nil {
|
if h.Timeout != nil {
|
||||||
val += ";timeout=" + strconv.FormatUint(uint64(*hs.Timeout), 10)
|
ret += ";timeout=" + strconv.FormatUint(uint64(*h.Timeout), 10)
|
||||||
}
|
}
|
||||||
|
|
||||||
return base.HeaderValue{val}
|
return base.HeaderValue{ret}
|
||||||
}
|
}
|
||||||
|
@@ -20,8 +20,8 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// String implements fmt.Stringer.
|
// String implements fmt.Stringer.
|
||||||
func (sm TransportMode) String() string {
|
func (tm TransportMode) String() string {
|
||||||
switch sm {
|
switch tm {
|
||||||
case TransportModePlay:
|
case TransportModePlay:
|
||||||
return "play"
|
return "play"
|
||||||
|
|
||||||
@@ -89,7 +89,7 @@ func parsePorts(val string) (*[2]int, error) {
|
|||||||
return &[2]int{0, 0}, fmt.Errorf("invalid ports (%v)", val)
|
return &[2]int{0, 0}, fmt.Errorf("invalid ports (%v)", val)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReadTransport parses a Transport header.
|
// ReadTransport decodes a Transport header.
|
||||||
func ReadTransport(v base.HeaderValue) (*Transport, error) {
|
func ReadTransport(v base.HeaderValue) (*Transport, error) {
|
||||||
if len(v) == 0 {
|
if len(v) == 0 {
|
||||||
return nil, fmt.Errorf("value not provided")
|
return nil, fmt.Errorf("value not provided")
|
||||||
@@ -99,7 +99,7 @@ func ReadTransport(v base.HeaderValue) (*Transport, error) {
|
|||||||
return nil, fmt.Errorf("value provided multiple times (%v)", v)
|
return nil, fmt.Errorf("value provided multiple times (%v)", v)
|
||||||
}
|
}
|
||||||
|
|
||||||
ht := &Transport{}
|
h := &Transport{}
|
||||||
|
|
||||||
parts := strings.Split(v[0], ";")
|
parts := strings.Split(v[0], ";")
|
||||||
if len(parts) == 0 {
|
if len(parts) == 0 {
|
||||||
@@ -108,10 +108,10 @@ func ReadTransport(v base.HeaderValue) (*Transport, error) {
|
|||||||
|
|
||||||
switch parts[0] {
|
switch parts[0] {
|
||||||
case "RTP/AVP", "RTP/AVP/UDP":
|
case "RTP/AVP", "RTP/AVP/UDP":
|
||||||
ht.Protocol = base.StreamProtocolUDP
|
h.Protocol = base.StreamProtocolUDP
|
||||||
|
|
||||||
case "RTP/AVP/TCP":
|
case "RTP/AVP/TCP":
|
||||||
ht.Protocol = base.StreamProtocolTCP
|
h.Protocol = base.StreamProtocolTCP
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("invalid protocol (%v)", v)
|
return nil, fmt.Errorf("invalid protocol (%v)", v)
|
||||||
@@ -121,12 +121,12 @@ func ReadTransport(v base.HeaderValue) (*Transport, error) {
|
|||||||
switch parts[0] {
|
switch parts[0] {
|
||||||
case "unicast":
|
case "unicast":
|
||||||
v := base.StreamDeliveryUnicast
|
v := base.StreamDeliveryUnicast
|
||||||
ht.Delivery = &v
|
h.Delivery = &v
|
||||||
parts = parts[1:]
|
parts = parts[1:]
|
||||||
|
|
||||||
case "multicast":
|
case "multicast":
|
||||||
v := base.StreamDeliveryMulticast
|
v := base.StreamDeliveryMulticast
|
||||||
ht.Delivery = &v
|
h.Delivery = &v
|
||||||
parts = parts[1:]
|
parts = parts[1:]
|
||||||
|
|
||||||
// cast is optional, do not return any error
|
// cast is optional, do not return any error
|
||||||
@@ -135,7 +135,7 @@ func ReadTransport(v base.HeaderValue) (*Transport, error) {
|
|||||||
for _, t := range parts {
|
for _, t := range parts {
|
||||||
if strings.HasPrefix(t, "destination=") {
|
if strings.HasPrefix(t, "destination=") {
|
||||||
v := t[len("destination="):]
|
v := t[len("destination="):]
|
||||||
ht.Destination = &v
|
h.Destination = &v
|
||||||
|
|
||||||
} else if strings.HasPrefix(t, "ttl=") {
|
} else if strings.HasPrefix(t, "ttl=") {
|
||||||
v, err := strconv.ParseUint(t[len("ttl="):], 10, 64)
|
v, err := strconv.ParseUint(t[len("ttl="):], 10, 64)
|
||||||
@@ -143,35 +143,35 @@ func ReadTransport(v base.HeaderValue) (*Transport, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
vu := uint(v)
|
vu := uint(v)
|
||||||
ht.TTL = &vu
|
h.TTL = &vu
|
||||||
|
|
||||||
} else if strings.HasPrefix(t, "port=") {
|
} else if strings.HasPrefix(t, "port=") {
|
||||||
ports, err := parsePorts(t[len("port="):])
|
ports, err := parsePorts(t[len("port="):])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
ht.Ports = ports
|
h.Ports = ports
|
||||||
|
|
||||||
} else if strings.HasPrefix(t, "client_port=") {
|
} else if strings.HasPrefix(t, "client_port=") {
|
||||||
ports, err := parsePorts(t[len("client_port="):])
|
ports, err := parsePorts(t[len("client_port="):])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
ht.ClientPorts = ports
|
h.ClientPorts = ports
|
||||||
|
|
||||||
} else if strings.HasPrefix(t, "server_port=") {
|
} else if strings.HasPrefix(t, "server_port=") {
|
||||||
ports, err := parsePorts(t[len("server_port="):])
|
ports, err := parsePorts(t[len("server_port="):])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
ht.ServerPorts = ports
|
h.ServerPorts = ports
|
||||||
|
|
||||||
} else if strings.HasPrefix(t, "interleaved=") {
|
} else if strings.HasPrefix(t, "interleaved=") {
|
||||||
ports, err := parsePorts(t[len("interleaved="):])
|
ports, err := parsePorts(t[len("interleaved="):])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
ht.InterleavedIds = ports
|
h.InterleavedIds = ports
|
||||||
|
|
||||||
} else if strings.HasPrefix(t, "mode=") {
|
} else if strings.HasPrefix(t, "mode=") {
|
||||||
str := strings.ToLower(t[len("mode="):])
|
str := strings.ToLower(t[len("mode="):])
|
||||||
@@ -181,13 +181,13 @@ func ReadTransport(v base.HeaderValue) (*Transport, error) {
|
|||||||
switch str {
|
switch str {
|
||||||
case "play":
|
case "play":
|
||||||
v := TransportModePlay
|
v := TransportModePlay
|
||||||
ht.Mode = &v
|
h.Mode = &v
|
||||||
|
|
||||||
// receive is an old alias for record, used by ffmpeg with the
|
// receive is an old alias for record, used by ffmpeg with the
|
||||||
// -listen flag, and by Darwin Streaming Server
|
// -listen flag, and by Darwin Streaming Server
|
||||||
case "record", "receive":
|
case "record", "receive":
|
||||||
v := TransportModeRecord
|
v := TransportModeRecord
|
||||||
ht.Mode = &v
|
h.Mode = &v
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("invalid transport mode: '%s'", str)
|
return nil, fmt.Errorf("invalid transport mode: '%s'", str)
|
||||||
@@ -197,49 +197,49 @@ func ReadTransport(v base.HeaderValue) (*Transport, error) {
|
|||||||
// ignore non-standard keys
|
// ignore non-standard keys
|
||||||
}
|
}
|
||||||
|
|
||||||
return ht, nil
|
return h, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write encodes a Transport header
|
// Write encodes a Transport header
|
||||||
func (ht Transport) Write() base.HeaderValue {
|
func (h Transport) Write() base.HeaderValue {
|
||||||
var vals []string
|
var rets []string
|
||||||
|
|
||||||
if ht.Protocol == base.StreamProtocolUDP {
|
if h.Protocol == base.StreamProtocolUDP {
|
||||||
vals = append(vals, "RTP/AVP")
|
rets = append(rets, "RTP/AVP")
|
||||||
} else {
|
} else {
|
||||||
vals = append(vals, "RTP/AVP/TCP")
|
rets = append(rets, "RTP/AVP/TCP")
|
||||||
}
|
}
|
||||||
|
|
||||||
if ht.Delivery != nil {
|
if h.Delivery != nil {
|
||||||
if *ht.Delivery == base.StreamDeliveryUnicast {
|
if *h.Delivery == base.StreamDeliveryUnicast {
|
||||||
vals = append(vals, "unicast")
|
rets = append(rets, "unicast")
|
||||||
} else {
|
} else {
|
||||||
vals = append(vals, "multicast")
|
rets = append(rets, "multicast")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ht.ClientPorts != nil {
|
if h.ClientPorts != nil {
|
||||||
ports := *ht.ClientPorts
|
ports := *h.ClientPorts
|
||||||
vals = append(vals, "client_port="+strconv.FormatInt(int64(ports[0]), 10)+"-"+strconv.FormatInt(int64(ports[1]), 10))
|
rets = append(rets, "client_port="+strconv.FormatInt(int64(ports[0]), 10)+"-"+strconv.FormatInt(int64(ports[1]), 10))
|
||||||
}
|
}
|
||||||
|
|
||||||
if ht.ServerPorts != nil {
|
if h.ServerPorts != nil {
|
||||||
ports := *ht.ServerPorts
|
ports := *h.ServerPorts
|
||||||
vals = append(vals, "server_port="+strconv.FormatInt(int64(ports[0]), 10)+"-"+strconv.FormatInt(int64(ports[1]), 10))
|
rets = append(rets, "server_port="+strconv.FormatInt(int64(ports[0]), 10)+"-"+strconv.FormatInt(int64(ports[1]), 10))
|
||||||
}
|
}
|
||||||
|
|
||||||
if ht.InterleavedIds != nil {
|
if h.InterleavedIds != nil {
|
||||||
ports := *ht.InterleavedIds
|
ports := *h.InterleavedIds
|
||||||
vals = append(vals, "interleaved="+strconv.FormatInt(int64(ports[0]), 10)+"-"+strconv.FormatInt(int64(ports[1]), 10))
|
rets = append(rets, "interleaved="+strconv.FormatInt(int64(ports[0]), 10)+"-"+strconv.FormatInt(int64(ports[1]), 10))
|
||||||
}
|
}
|
||||||
|
|
||||||
if ht.Mode != nil {
|
if h.Mode != nil {
|
||||||
if *ht.Mode == TransportModePlay {
|
if *h.Mode == TransportModePlay {
|
||||||
vals = append(vals, "mode=play")
|
rets = append(rets, "mode=play")
|
||||||
} else {
|
} else {
|
||||||
vals = append(vals, "mode=record")
|
rets = append(rets, "mode=record")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return base.HeaderValue{strings.Join(vals, ";")}
|
return base.HeaderValue{strings.Join(rets, ";")}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user