Skip to content

Commit

Permalink
feat: add support for utc_head
Browse files Browse the repository at this point in the history
  • Loading branch information
tobbee committed Aug 22, 2023
1 parent e8d0472 commit 823217c
Show file tree
Hide file tree
Showing 8 changed files with 37 additions and 35 deletions.
3 changes: 2 additions & 1 deletion cmd/livesim2/app/configurl.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ type UTCTimingMethod string

const (
UtcTimingDirect UTCTimingMethod = "direct"
UtcTimingHead UTCTimingMethod = "head" // Note, not supported
UtcTimingHead UTCTimingMethod = "head"
UtcTimingNtp UTCTimingMethod = "ntp"
UtcTimingSntp UTCTimingMethod = "sntp"
UtcTimingHttpXSDate UTCTimingMethod = "httpxsdate"
Expand All @@ -42,6 +42,7 @@ const (
UtcTimingSntpServer = "time.kfki.hu"
UtcTimingHttpServer = "http://time.akamai.com/?iso"
UtcTimingHttpServerMS = "http://time.akamai.com/?isoms"
UtcTimingHeadAsset = "/static/time.txt"
)

type ResponseConfig struct {
Expand Down
19 changes: 3 additions & 16 deletions cmd/livesim2/app/configurl_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,18 +20,18 @@ func TestProcessURLCfg(t *testing.T) {
err string
}{
{
url: "/livesim2/utc_direct-ntp-sntp-httpxsdate-httpiso/asset/x.mpd",
url: "/livesim2/utc_direct-ntp-sntp-httpxsdate-httpiso-head/asset/x.mpd",
nowMS: 0,
contentPart: "asset/x.mpd",
wantedCfg: &ResponseConfig{
URLParts: []string{"", "livesim2", "utc_direct-ntp-sntp-httpxsdate-httpiso", "asset", "x.mpd"},
URLParts: []string{"", "livesim2", "utc_direct-ntp-sntp-httpxsdate-httpiso-head", "asset", "x.mpd"},
URLContentIdx: 3,
StartTimeS: 0,
TimeShiftBufferDepthS: Ptr(defaultTimeShiftBufferDepthS),
StartNr: Ptr(0),
AvailabilityTimeCompleteFlag: true,
TimeSubsDurMS: defaultTimeSubsDurMS,
UTCTimingMethods: []UTCTimingMethod{"direct", "ntp", "sntp", "httpxsdate", "httpiso"},
UTCTimingMethods: []UTCTimingMethod{"direct", "ntp", "sntp", "httpxsdate", "httpiso", "head"},
},
err: "",
},
Expand All @@ -48,19 +48,6 @@ func TestProcessURLCfg(t *testing.T) {
},
err: `key="utc", val="unknown" is not a valid UTC timing method`,
},
{
url: "/livesim/utc_head/asset.mpd",
nowMS: 0,
contentPart: "asset.mpd",
wantedCfg: &ResponseConfig{
StartTimeS: 0,
TimeShiftBufferDepthS: Ptr(defaultTimeShiftBufferDepthS),
StartNr: Ptr(0),
AvailabilityTimeCompleteFlag: true,
TimeSubsDurMS: defaultTimeSubsDurMS,
},
err: `key="utc", val="head", UTC timing method "head" not supported`,
},
{
url: "/livesim2/utc_none/asset.mpd",
nowMS: 0,
Expand Down
15 changes: 12 additions & 3 deletions cmd/livesim2/app/handler_livesim.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ func (s *Server) livesimHandlerFunc(w http.ResponseWriter, r *http.Request) {
http.Error(w, msg, http.StatusInternalServerError)
return
}
fullHost := getSchemeAndHost(r)

var nowMS int // Set from query string or from wall-clock
q := r.URL.Query()
Expand Down Expand Up @@ -80,7 +81,7 @@ func (s *Server) livesimHandlerFunc(w http.ResponseWriter, r *http.Request) {
_, mpdName := path.Split(contentPart)
cfg.SetScheme(s.Cfg.Scheme, r)
cfg.SetHost(s.Cfg.Host, r)
err := writeLiveMPD(log, w, cfg, a, mpdName, nowMS)
err := writeLiveMPD(log, w, cfg, a, mpdName, fullHost, nowMS)
if err != nil {
// TODO. Add more granular errors like 404 not found
msg := fmt.Sprintf("liveMPD: %s", err)
Expand Down Expand Up @@ -112,10 +113,18 @@ func (s *Server) livesimHandlerFunc(w http.ResponseWriter, r *http.Request) {
}
}

func writeLiveMPD(log *zerolog.Logger, w http.ResponseWriter, cfg *ResponseConfig, a *asset, mpdName string, nowMS int) error {
func getSchemeAndHost(r *http.Request) string {
scheme := "http"
if r.TLS != nil {
scheme = "https"
}
return fmt.Sprintf("%s://%s", scheme, r.Host)
}

func writeLiveMPD(log *zerolog.Logger, w http.ResponseWriter, cfg *ResponseConfig, a *asset, mpdName, host string, nowMS int) error {
work := make([]byte, 0, 1024)
buf := bytes.NewBuffer(work)
lMPD, err := LiveMPD(a, mpdName, cfg, nowMS)
lMPD, err := LiveMPD(a, mpdName, cfg, host, nowMS)
if err != nil {
return fmt.Errorf("convertToLive: %w", err)
}
Expand Down
11 changes: 8 additions & 3 deletions cmd/livesim2/app/livempd.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ func calcWrapTimes(a *asset, cfg *ResponseConfig, nowMS int, tsbd m.Duration) wr
}

// LiveMPD generates a dynamic configured MPD for a VoD asset.
func LiveMPD(a *asset, mpdName string, cfg *ResponseConfig, nowMS int) (*m.MPD, error) {
func LiveMPD(a *asset, mpdName string, cfg *ResponseConfig, host string, nowMS int) (*m.MPD, error) {
mpd, err := a.getVodMPD(mpdName)
if err != nil {
return nil, err
Expand Down Expand Up @@ -90,7 +90,7 @@ func LiveMPD(a *asset, mpdName string, cfg *ResponseConfig, nowMS int) (*m.MPD,
}
}

addUTCTimings(mpd, cfg)
addUTCTimings(mpd, cfg, host)

afterStop := false
endTimeMS := nowMS
Expand Down Expand Up @@ -525,7 +525,7 @@ func lastSegAvailTimeS(cfg *ResponseConfig, lsi lastSegInfo) float64 {
}

// addUTCTimings adds the UTCTiming elements to the MPD.
func addUTCTimings(mpd *m.MPD, cfg *ResponseConfig) {
func addUTCTimings(mpd *m.MPD, cfg *ResponseConfig, host string) {
if len(cfg.UTCTimingMethods) == 0 {
// default if none is set. Use HTTP with ms precision.
mpd.UTCTimings = []*m.DescriptorType{
Expand Down Expand Up @@ -564,6 +564,11 @@ func addUTCTimings(mpd *m.MPD, cfg *ResponseConfig) {
SchemeIdUri: "urn:mpeg:dash:utc:http-iso:2014",
Value: UtcTimingHttpServerMS,
}
case UtcTimingHead:
ut = &m.DescriptorType{
SchemeIdUri: "urn:mpeg:dash:utc:http-head:2014",
Value: fmt.Sprintf("%s%s", host, UtcTimingHeadAsset),
}
case UtcTimingNone:
cfg.UTCTimingMethods = nil
return // no UTCTiming elements
Expand Down
18 changes: 9 additions & 9 deletions cmd/livesim2/app/livempd_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ func TestLiveMPD(t *testing.T) {
cfg := NewResponseConfig()
nowMS := 100_000
// Number template
liveMPD, err := LiveMPD(asset, tc.mpdName, cfg, nowMS)
liveMPD, err := LiveMPD(asset, tc.mpdName, cfg, "", nowMS)
assert.NoError(t, err)
assert.Equal(t, "dynamic", *liveMPD.Type)
assert.Equal(t, m.DateTime("1970-01-01T00:00:00Z"), liveMPD.AvailabilityStartTime)
Expand All @@ -83,7 +83,7 @@ func TestLiveMPD(t *testing.T) {
}
// SegmentTimeline with $Time$
cfg.SegTimelineFlag = true
liveMPD, err = LiveMPD(asset, tc.mpdName, cfg, nowMS)
liveMPD, err = LiveMPD(asset, tc.mpdName, cfg, "", nowMS)
assert.NoError(t, err)
assert.Equal(t, "dynamic", *liveMPD.Type)
assert.Equal(t, m.DateTime("1970-01-01T00:00:00Z"), liveMPD.AvailabilityStartTime)
Expand Down Expand Up @@ -133,7 +133,7 @@ func TestLiveMPDWithTimeSubs(t *testing.T) {
cfg.TimeSubsStpp = []string{"en", "sv"}
nowMS := 100_000
// Number template
liveMPD, err := LiveMPD(asset, tc.mpdName, cfg, nowMS)
liveMPD, err := LiveMPD(asset, tc.mpdName, cfg, "", nowMS)
assert.NoError(t, err)
assert.Equal(t, "dynamic", *liveMPD.Type)
aSets := liveMPD.Periods[0].AdaptationSets
Expand Down Expand Up @@ -208,7 +208,7 @@ func TestSegmentTimes(t *testing.T) {
}
for nowS := tc.startTimeS; nowS < tc.endTimeS; nowS++ {
nowMS := nowS * 1000
liveMPD, err := LiveMPD(asset, tc.mpdName, cfg, nowMS)
liveMPD, err := LiveMPD(asset, tc.mpdName, cfg, "", nowMS)
wantedStartNr := (nowS - 62) / 2 // Sliding window of 60s + one segment
assert.NoError(t, err)
for _, as := range liveMPD.Periods[0].AdaptationSets {
Expand Down Expand Up @@ -460,7 +460,7 @@ func TestPublishTime(t *testing.T) {
}
err := verifyAndFillConfig(cfg, tc.nowMS)
require.NoError(t, err)
liveMPD, err := LiveMPD(asset, tc.mpdName, cfg, tc.nowMS)
liveMPD, err := LiveMPD(asset, tc.mpdName, cfg, "", tc.nowMS)
assert.NoError(t, err)
assert.Equal(t, m.ConvertToDateTimeS(int64(tc.availabilityStartTime)), liveMPD.AvailabilityStartTime)
assert.Equal(t, m.DateTime(tc.wantedPublishTime), liveMPD.PublishTime)
Expand Down Expand Up @@ -532,7 +532,7 @@ func TestNormalAvailabilityTimeOffset(t *testing.T) {
cfg.SegTimelineFlag = tc.segTimelineTime
sc := strConvAccErr{}
cfg.AvailabilityTimeOffsetS = sc.AtofInf("ato", tc.ato)
liveMPD, err := LiveMPD(asset, tc.mpdName, cfg, tc.nowMS)
liveMPD, err := LiveMPD(asset, tc.mpdName, cfg, "", tc.nowMS)
if tc.wantedErr != "" {
assert.EqualError(t, err, tc.wantedErr)
return
Expand Down Expand Up @@ -602,7 +602,7 @@ func TestUTCTiming(t *testing.T) {
}
err := verifyAndFillConfig(cfg, tc.nowMS)
require.NoError(t, err)
liveMPD, err := LiveMPD(asset, tc.mpdName, cfg, tc.nowMS)
liveMPD, err := LiveMPD(asset, tc.mpdName, cfg, "", tc.nowMS)
assert.NoError(t, err)
assert.Equal(t, m.DateTime(tc.wantedPublishTime), liveMPD.PublishTime)
assert.Equal(t, tc.wantedUTCTimings, len(liveMPD.UTCTimings))
Expand Down Expand Up @@ -700,7 +700,7 @@ func TestMultiPeriod(t *testing.T) {
default: // $Number$
// no flag
}
liveMPD, err := LiveMPD(asset, tc.mpdName, cfg, tc.nowMS)
liveMPD, err := LiveMPD(asset, tc.mpdName, cfg, "", tc.nowMS)
if tc.wantedErr != "" {
assert.EqualError(t, err, tc.wantedErr)
return
Expand Down Expand Up @@ -754,7 +754,7 @@ func TestRelStartStopTimeIntoLocation(t *testing.T) {
asset, ok := am.findAsset(contentPart)
require.True(t, ok)
_, mpdName := path.Split(contentPart)
liveMPD, err := LiveMPD(asset, mpdName, cfg, c.nowMS)
liveMPD, err := LiveMPD(asset, mpdName, cfg, "", c.nowMS)
require.NoError(t, err)
require.Equal(t, c.wantedLocation, string(liveMPD.Location[0]), "the right location element is not inserted")
}
Expand Down
1 change: 1 addition & 0 deletions cmd/livesim2/app/routes.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ func (s *Server) Routes(ctx context.Context) error {
s.Router.MethodFunc("GET", "/config", s.configHandlerFunc)
s.Router.MethodFunc("GET", "/assets", s.assetsHandlerFunc)
s.Router.MethodFunc("GET", "/static/*", s.embeddedStaticHandlerFunc)
s.Router.MethodFunc("HEAD", "/static/*", s.embeddedStaticHandlerFunc)
// LiveRouter is mounted at /livesim2
s.LiveRouter.MethodFunc("GET", "/*", s.livesimHandlerFunc)
s.LiveRouter.MethodFunc("HEAD", "/*", s.livesimHandlerFunc)
Expand Down
1 change: 1 addition & 0 deletions cmd/livesim2/app/static/time.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Used for UTCTiming in head mode.
4 changes: 1 addition & 3 deletions cmd/livesim2/app/strconv.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,10 +80,8 @@ func (s *strConvAccErr) SplitUTCTimings(key, val string) []UTCTimingMethod {
utcVal := UTCTimingMethod(val)
switch utcVal {
case UtcTimingDirect, UtcTimingNtp, UtcTimingSntp, UtcTimingHttpXSDate, UtcTimingHttpISO,
UtcTimingNone:
UtcTimingNone, UtcTimingHead:
utcTimingMethods[i] = utcVal
case UtcTimingHead:
s.err = fmt.Errorf("key=%q, val=%q, UTC timing method %q not supported", key, val, UtcTimingHead)
default:
s.err = fmt.Errorf("key=%q, val=%q is not a valid UTC timing method", key, val)
}
Expand Down

0 comments on commit 823217c

Please sign in to comment.