This commit is contained in:
aler9
2024-01-15 21:44:37 +01:00
parent 6b0ba5dd64
commit 66e3d79269
4 changed files with 146 additions and 80 deletions

View File

@@ -97,18 +97,26 @@ func (h *Header) unmarshal(br *bufio.Reader) error {
return nil
}
func (h Header) marshalSize() int {
// sort headers by key
// in order to obtain deterministic results
// sort headers by key
// in order to obtain deterministic results
func (h Header) sortedKeys() []string {
keys := make([]string, len(h))
for key := range h {
keys = append(keys, key)
}
sort.Strings(keys)
// some cameras require CSeq to be put before everything else
sort.Slice(keys, func(i, j int) bool {
return keys[i] == "CSeq" || (keys[j] != "CSeq" && keys[i] < keys[j])
})
return keys
}
func (h Header) marshalSize() int {
n := 0
for _, key := range keys {
for _, key := range h.sortedKeys() {
for _, val := range h[key] {
n += len([]byte(key + ": " + val + "\r\n"))
}
@@ -120,17 +128,9 @@ func (h Header) marshalSize() int {
}
func (h Header) marshalTo(buf []byte) int {
// sort headers by key
// in order to obtain deterministic results
keys := make([]string, len(h))
for key := range h {
keys = append(keys, key)
}
sort.Strings(keys)
pos := 0
for _, key := range keys {
for _, key := range h.sortedKeys() {
for _, val := range h[key] {
pos += copy(buf[pos:], []byte(key+": "+val+"\r\n"))
}

View File

@@ -45,60 +45,27 @@ var cases = []struct {
},
},
{
"empty",
[]byte("Testing:\r\n" +
"\r\n"),
[]byte("Testing: \r\n" +
"\r\n"),
Header{
"Testing": HeaderValue{""},
},
},
{
"without space",
[]byte("CSeq:2\r\n" +
"\r\n"),
[]byte("CSeq: 2\r\n" +
"\r\n"),
Header{
"CSeq": HeaderValue{"2"},
},
},
{
"with multiple spaces",
[]byte("CSeq: 2\r\n" +
"\r\n"),
[]byte("CSeq: 2\r\n" +
"\r\n"),
Header{
"CSeq": HeaderValue{"2"},
},
},
{
"normalized keys, standard",
[]byte("content-type: testing\r\n" +
"content-length: value\r\n" +
"\r\n"),
[]byte("Content-Length: value\r\n" +
"Content-Type: testing\r\n" +
"\r\n"),
Header{
"Content-Length": HeaderValue{"value"},
"Content-Type": HeaderValue{"testing"},
},
},
{
"normalized keys, non-standard",
[]byte("www-authenticate: value\r\n" +
"cseq: value\r\n" +
"rtp-info: value\r\n" +
"\r\n"),
"various",
[]byte(
"Testing:\r\n" +
"content-type: testing\r\n" +
"content-length:value\r\n" +
"www-authenticate: value\r\n" +
"cseq: value\r\n" +
"rtp-info: value\r\n" +
"\r\n"),
[]byte("CSeq: value\r\n" +
"Content-Length: value\r\n" +
"Content-Type: testing\r\n" +
"Testing: \r\n" +
"RTP-Info: value\r\n" +
"WWW-Authenticate: value\r\n" +
"\r\n"),
Header{
"Content-Length": HeaderValue{"value"},
"Content-Type": HeaderValue{"testing"},
"CSeq": HeaderValue{"value"},
"Testing": HeaderValue{""},
"RTP-Info": HeaderValue{"value"},
"WWW-Authenticate": HeaderValue{"value"},
},

View File

@@ -114,15 +114,16 @@ func (s *SessionDescription) unmarshalOrigin(value string) error {
var tmp string
tmp, value = value[i+1:], value[:i]
tmp = strings.TrimRight(tmp, " ")
var err error
switch {
case strings.ContainsAny(tmp, "."):
i := strings.Index(tmp, ".")
if i := strings.Index(tmp, "."); i >= 0 {
s.Origin.SessionVersion, err = strconv.ParseUint(tmp[:i], 16, 64)
default:
} else {
s.Origin.SessionVersion, err = strconv.ParseUint(tmp, 10, 64)
}
if err != nil {
return fmt.Errorf("%w `%v`", errSDPInvalidNumericValue, tmp)
}

View File

@@ -227,8 +227,7 @@ var cases = []struct {
Value: "0 1 UDP 2113667327 203.0.113.1 54400 typ host",
},
{
Key: "recvonly",
Value: "",
Key: "recvonly",
},
},
MediaDescriptions: []*psdp.MediaDescription{
@@ -371,8 +370,7 @@ var cases = []struct {
Value: "?ctype=video",
},
{
Key: "recvonly",
Value: "",
Key: "recvonly",
},
},
},
@@ -393,8 +391,7 @@ var cases = []struct {
Value: "?ctype=app106",
},
{
Key: "sendonly",
Value: "",
Key: "sendonly",
},
},
},
@@ -746,8 +743,7 @@ var cases = []struct {
Value: "trackID=1",
},
{
Key: "recvonly",
Value: "",
Key: "recvonly",
},
{
Key: "framerate",
@@ -996,7 +992,6 @@ var cases = []struct {
SessionVersion: 16381778200090839277,
NetworkType: "IN",
AddressType: "IP4",
UnicastAddress: "",
},
SessionName: psdp.SessionName("RTSP Server"),
EmailAddress: func() *psdp.EmailAddress {
@@ -2419,8 +2414,7 @@ var cases = []struct {
"sprop-parameter-sets=Z2QAKKwbGoB4AiflwFuAgICgAAB9AAATiB0MAEr4AAL68F3lxoYAJXwAAX14LvLhQA==,aO48MA==",
},
{
Key: "recvonly",
Value: "",
Key: "recvonly",
},
},
},
@@ -2462,7 +2456,6 @@ var cases = []struct {
AddressType: "IP4",
UnicastAddress: "192.168.1.10",
},
SessionName: "",
Attributes: []psdp.Attribute{
{
Key: "range",
@@ -2857,8 +2850,7 @@ var cases = []struct {
Value: "rtsp://192.168.1.63/defaultPrimary/micCfg0/trackID=9?mtu=1440&streamType=u",
},
{
Key: "recvonly",
Value: "",
Key: "recvonly",
},
},
},
@@ -2916,6 +2908,112 @@ var cases = []struct {
},
},
},
{
"issue mediamtx/2887",
[]byte("v=0\r\n" +
"o=- 57160522 782967157 IN IP4 192.168.1.44\r\n" +
"s=live\r\n" +
"c=IN IP4 0.0.0.0\r\n" +
"t=0 0\r\n" +
"a=control:*\r\n" +
"m=video 0 RTP/AVP 96\r\n" +
"b=AS:2058\r\n" +
"a=rtpmap:96 H264/90000\r\n" +
"a=range:npt=0-\r\n" +
"a=control:rtsp://192.168.1.44:554/video/live00_0\r\n" +
"m=audio 0 RTP/AVP 8\r\n" +
"b=AS:64\r\n" +
"a=rtpmap:8 PCMA/8000\r\n" +
"a=control:rtsp://192.168.1.44:554/audio/live00_0\r\n"),
[]byte("v=0\r\n" +
"o=- 57160522 782967157 IN IP4 192.168.1.44\r\n" +
"s=live\r\n" +
"c=IN IP4 0.0.0.0\r\n" +
"t=0 0\r\n" +
"a=control:*\r\n" +
"m=video 0 RTP/AVP 96\r\n" +
"b=AS:2058\r\n" +
"a=rtpmap:96 H264/90000\r\n" +
"a=range:npt=0-\r\n" +
"a=control:rtsp://192.168.1.44:554/video/live00_0\r\n" +
"m=audio 0 RTP/AVP 8\r\n" +
"b=AS:64\r\n" +
"a=rtpmap:8 PCMA/8000\r\n" +
"a=control:rtsp://192.168.1.44:554/audio/live00_0\r\n"),
SessionDescription{
Origin: psdp.Origin{
Username: "-",
SessionID: 57160522,
SessionVersion: 782967157,
NetworkType: "IN",
AddressType: "IP4",
UnicastAddress: "192.168.1.44",
},
SessionName: "live",
ConnectionInformation: &psdp.ConnectionInformation{
NetworkType: "IN",
AddressType: "IP4",
Address: &psdp.Address{
Address: "0.0.0.0",
},
},
Attributes: []psdp.Attribute{
{
Key: "control",
Value: "*",
},
},
TimeDescriptions: []psdp.TimeDescription{{}},
MediaDescriptions: []*psdp.MediaDescription{
{
MediaName: psdp.MediaName{
Media: "video",
Protos: []string{"RTP", "AVP"},
Formats: []string{"96"},
},
Bandwidth: []psdp.Bandwidth{{
Type: "AS",
Bandwidth: 2058,
}},
Attributes: []psdp.Attribute{
{
Key: "rtpmap",
Value: "96 H264/90000",
},
{
Key: "range",
Value: "npt=0-",
},
{
Key: "control",
Value: "rtsp://192.168.1.44:554/video/live00_0",
},
},
},
{
MediaName: psdp.MediaName{
Media: "audio",
Protos: []string{"RTP", "AVP"},
Formats: []string{"8"},
},
Bandwidth: []psdp.Bandwidth{{
Type: "AS",
Bandwidth: 64,
}},
Attributes: []psdp.Attribute{
{
Key: "rtpmap",
Value: "8 PCMA/8000",
},
{
Key: "control",
Value: "rtsp://192.168.1.44:554/audio/live00_0",
},
},
},
},
},
},
}
func TestUnmarshal(t *testing.T) {