Skip to content

Commit

Permalink
test: add more tests for when segments are available for low latency
Browse files Browse the repository at this point in the history
  • Loading branch information
tobbee committed Oct 17, 2023
1 parent b545d2b commit f86e398
Show file tree
Hide file tree
Showing 3 changed files with 159 additions and 15 deletions.
32 changes: 23 additions & 9 deletions cmd/livesim2/app/livempd_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,7 @@ func TestSegmentTimes(t *testing.T) {
}
}

// TestLastAvailableSegment tests that the last available segment is correct including low latency.
func TestLastAvailableSegment(t *testing.T) {
vodFS := os.DirFS("testdata/assets")
tmpDir := t.TempDir()
Expand All @@ -258,6 +259,16 @@ func TestLastAvailableSegment(t *testing.T) {
segTimelineTime: true,
availabilityTimeOffset: 1.5,
availabilityTimeComplete: false,
nowMS: 3_600_501,
wantedSegNr: 1800,
},
{
desc: "Timeline with $Time$ 1hour+1s with chunkdur 0.5",
asset: "WAVE/vectors/cfhd_sets/12.5_25_50/t3/2022-10-17",
mpdName: "stream.mpd",
segTimelineTime: false,
availabilityTimeOffset: 1.5,
availabilityTimeComplete: false,
nowMS: 3_601_000,
wantedSegNr: 1800,
},
Expand Down Expand Up @@ -314,6 +325,8 @@ func TestLastAvailableSegment(t *testing.T) {
cfg := NewResponseConfig()
if tc.segTimelineTime {
cfg.SegTimelineFlag = true
} else {
cfg.SegTimelineNrFlag = true
}
cfg.AvailabilityTimeOffsetS = tc.availabilityTimeOffset
if tc.availabilityTimeOffset > 0 && !tc.availabilityTimeComplete {
Expand All @@ -324,15 +337,16 @@ func TestLastAvailableSegment(t *testing.T) {
wTimes := calcWrapTimes(asset, cfg, tc.nowMS, tsbd)
mpd, err := asset.getVodMPD(tc.mpdName)
require.NoError(t, err)
as := mpd.Periods[0].AdaptationSets[0]
atoMS, err := setOffsetInAdaptationSet(cfg, asset, as)
if tc.wantedErr != "" {
require.EqualError(t, err, tc.wantedErr)
} else {
require.NoError(t, err)
r := as.Representations[0] // Assume that any representation will be fine inside AS
se := asset.generateTimelineEntries(r.Id, wTimes, atoMS)
assert.Equal(t, tc.wantedSegNr, se.lsi.nr)
for _, as := range mpd.Periods[0].AdaptationSets {
atoMS, err := setOffsetInAdaptationSet(cfg, asset, as)
if tc.wantedErr != "" {
require.EqualError(t, err, tc.wantedErr)
} else {
require.NoError(t, err)
r := as.Representations[0] // Assume that any representation will be fine inside AS
se := asset.generateTimelineEntries(r.Id, wTimes, atoMS)
assert.Equal(t, tc.wantedSegNr, se.lsi.nr)
}
}
})
}
Expand Down
6 changes: 0 additions & 6 deletions cmd/livesim2/app/livesegment.go
Original file line number Diff line number Diff line change
Expand Up @@ -139,9 +139,6 @@ func findSegMetaFromTime(a *asset, rep *RepData, time uint64, cfg *ResponseConfi

// Check interval validity
segAvailTimeS := float64(int(seg.EndTime)+wrapTime+mediaRef) / float64(rep.MediaTimescale)
if !cfg.AvailabilityTimeCompleteFlag {
segAvailTimeS -= cfg.AvailabilityTimeOffsetS
}
nowS := float64(nowMS) * 0.001
err := CheckTimeValidity(segAvailTimeS, nowS, float64(*cfg.TimeShiftBufferDepthS), cfg.getAvailabilityTimeOffsetS())
if err != nil {
Expand Down Expand Up @@ -238,9 +235,6 @@ func findSegMetaFromNr(a *asset, rep *RepData, nr uint32, cfg *ResponseConfig, n

// Check interval validity
segAvailTimeS := float64(int(seg.EndTime)+wrapTime+mediaRef) / float64(rep.MediaTimescale)
if !cfg.AvailabilityTimeCompleteFlag {
segAvailTimeS -= cfg.AvailabilityTimeOffsetS
}
nowS := float64(nowMS) * 0.001
err := CheckTimeValidity(segAvailTimeS, nowS, float64(*cfg.TimeShiftBufferDepthS), cfg.getAvailabilityTimeOffsetS())
if err != nil {
Expand Down
136 changes: 136 additions & 0 deletions cmd/livesim2/app/livesegment_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -422,3 +422,139 @@ func TestStartNumber(t *testing.T) {

}
}

func TestLLSegmentAvailability(t *testing.T) {
vodFS := os.DirFS("testdata/assets")
am := newAssetMgr(vodFS, "", false)
err := am.discoverAssets()
require.NoError(t, err)
err = logging.InitSlog("error", "discard")
require.NoError(t, err)

cases := []struct {
asset string
media string
nowMS int
startNr int
mpdType string
requestMedia int
expectedNr int
expectedDecodeTime int
expectedErr string
}{
{
asset: "testpic_2s",
media: "V300/$NrOrTime$.m4s",
nowMS: 50_000,
mpdType: "Number",
requestMedia: 25,
expectedErr: "too early",
},
{
asset: "testpic_2s",
media: "V300/$NrOrTime$.m4s",
nowMS: 50_500,
mpdType: "Number",
requestMedia: 25,
expectedNr: 25,
expectedDecodeTime: 50 * 90000,
expectedErr: "",
},
{
asset: "testpic_2s",
media: "V300/$NrOrTime$.m4s",
nowMS: 50_500,
mpdType: "TimelineNumber",
requestMedia: 25,
expectedNr: 25,
expectedDecodeTime: 50 * 90000,
expectedErr: "",
},
{
asset: "testpic_2s",
media: "V300/$NrOrTime$.m4s",
nowMS: 50_500,
mpdType: "TimelineTime",
requestMedia: 4_500_000,
expectedNr: 25,
expectedDecodeTime: 50 * 90000,
expectedErr: "",
},
{
asset: "testpic_2s",
media: "V300/$NrOrTime$.m4s",
nowMS: 50_500,
startNr: 1,
mpdType: "Number",
requestMedia: 26,
expectedNr: 26,
expectedDecodeTime: 50 * 90000,
expectedErr: "",
},
{
asset: "testpic_2s",
media: "V300/$NrOrTime$.m4s",
nowMS: 50_500,
startNr: 1,
mpdType: "Number",
requestMedia: 27,
expectedErr: "too early",
},
{
asset: "testpic_2s",
media: "V300/$NrOrTime$.m4s",
nowMS: 50_500,
mpdType: "TimelineNumber",
startNr: 1,
requestMedia: 26,
expectedNr: 26,
expectedDecodeTime: 50 * 90000,
expectedErr: "",
},
{
asset: "testpic_2s",
media: "V300/$NrOrTime$.m4s",
nowMS: 50_500,
mpdType: "TimelineTime",
startNr: 1,
requestMedia: 4_500_000,
expectedNr: 26,
expectedDecodeTime: 50 * 90000,
expectedErr: "",
},
}
for _, tc := range cases {
asset, ok := am.findAsset(tc.asset)
require.True(t, ok)
require.NoError(t, err)
cfg := NewResponseConfig()
cfg.AvailabilityTimeCompleteFlag = false
cfg.AvailabilityTimeOffsetS = 1.5
switch tc.mpdType {
case "TimelineTime":
cfg.SegTimelineFlag = true
case "TimelineNumber":
cfg.SegTimelineNrFlag = true
case "Number":
// Nothing
default:
require.Fail(t, "unknown mpdType")
}
if tc.startNr != 0 {
cfg.StartNr = Ptr(tc.startNr)
}
media := strings.Replace(tc.media, "$NrOrTime$", fmt.Sprintf("%d", (tc.requestMedia)), 1)
so, err := genLiveSegment(vodFS, asset, cfg, media, tc.nowMS)
if tc.expectedErr != "" {
require.Error(t, err)
require.Contains(t, err.Error(), tc.expectedErr)
continue
}
require.NoError(t, err)
moof := so.seg.Fragments[0].Moof
seqNr := moof.Mfhd.SequenceNumber
require.Equal(t, tc.expectedNr, int(seqNr), "response segment sequence number")
decodeTime := moof.Traf.Tfdt.BaseMediaDecodeTime()
require.Equal(t, tc.expectedDecodeTime, int(decodeTime), "response segment decode time")
}
}

0 comments on commit f86e398

Please sign in to comment.