From 35c5c9f077219c7a6b4cf50ede719e785051e839 Mon Sep 17 00:00:00 2001 From: Ingo Oppermann Date: Tue, 25 Oct 2022 14:00:27 +0200 Subject: [PATCH] Add alternative streamid format for SRT The streamid format that starts with #!: is recommended in the SRT specs but it usually causes trouble where you're limited in the use of such characters. Some hardware devices will not accept such streamids. The alternative format is simpler and has the form [resource](,token:[token])?(,mode:[mode])? token and mode are optional. mode can have the values "publish" or "request". If mode is not provided, a value of "request" is assumed. --- srt/srt.go | 58 +++++++++++++++++++++++++++++++++++++++++++++++-- srt/srt_test.go | 22 +++++++++++++++++-- 2 files changed, 76 insertions(+), 4 deletions(-) diff --git a/srt/srt.go b/srt/srt.go index 78c5bbca..73a8ba10 100644 --- a/srt/srt.go +++ b/srt/srt.go @@ -5,6 +5,7 @@ import ( "context" "fmt" "net" + "regexp" "strings" "sync" "time" @@ -365,6 +366,59 @@ type streamInfo struct { func parseStreamId(streamid string) (streamInfo, error) { si := streamInfo{} + if strings.HasPrefix(streamid, "#!:") { + return parseOldStreamId(streamid) + } + + re := regexp.MustCompile(`,(token|mode):(.+)`) + + results := map[string]string{} + + idEnd := -1 + value := streamid + key := "" + + for { + matches := re.FindStringSubmatchIndex(value) + if matches == nil { + break + } + + if idEnd < 0 { + idEnd = matches[2] - 1 + } + + if len(key) != 0 { + results[key] = value[:matches[2]-1] + } + + key = value[matches[2]:matches[3]] + value = value[matches[4]:matches[5]] + + results[key] = value + } + + if idEnd < 0 { + idEnd = len(streamid) + } + + si.resource = streamid[:idEnd] + if token, ok := results["token"]; ok { + si.token = token + } + + if mode, ok := results["mode"]; ok { + si.mode = mode + } else { + si.mode = "request" + } + + return si, nil +} + +func parseOldStreamId(streamid string) (streamInfo, error) { + si := streamInfo{} + if !strings.HasPrefix(streamid, "#!:") { return si, fmt.Errorf("unknown streamid format") } @@ -373,7 +427,7 @@ func parseStreamId(streamid string) (streamInfo, error) { kvs := strings.Split(streamid, ",") - split := func(s, sep string) (string, string, error) { + splitFn := func(s, sep string) (string, string, error) { splitted := strings.SplitN(s, sep, 2) if len(splitted) != 2 { @@ -384,7 +438,7 @@ func parseStreamId(streamid string) (streamInfo, error) { } for _, kv := range kvs { - key, value, err := split(kv, "=") + key, value, err := splitFn(kv, "=") if err != nil { continue } diff --git a/srt/srt_test.go b/srt/srt_test.go index b4b2d843..91ae7ed1 100644 --- a/srt/srt_test.go +++ b/srt/srt_test.go @@ -8,7 +8,25 @@ import ( func TestParseStreamId(t *testing.T) { streamids := map[string]streamInfo{ - "bla": {}, + "bla": {resource: "bla", mode: "request"}, + "bla,mode:publish": {resource: "bla", mode: "publish"}, + "123456789": {resource: "123456789", mode: "request"}, + "bla,token:foobar": {resource: "bla", token: "foobar", mode: "request"}, + "bla,token:foo,bar": {resource: "bla", token: "foo,bar", mode: "request"}, + "123456789,mode:publish,token:foobar": {resource: "123456789", token: "foobar", mode: "publish"}, + "mode:publish": {resource: "mode:publish", mode: "request"}, + } + + for streamid, wantsi := range streamids { + si, err := parseStreamId(streamid) + + require.NoError(t, err) + require.Equal(t, wantsi, si) + } +} + +func TestParseOldStreamId(t *testing.T) { + streamids := map[string]streamInfo{ "#!:": {}, "#!:key=value": {}, "#!:m=publish": {mode: "publish"}, @@ -19,7 +37,7 @@ func TestParseStreamId(t *testing.T) { } for streamid, wantsi := range streamids { - si, _ := parseStreamId(streamid) + si, _ := parseOldStreamId(streamid) require.Equal(t, wantsi, si) }