public override Tuple <PlayoutBuilderState, List <PlayoutItem> > Schedule( PlayoutBuilderState playoutBuilderState, Dictionary <CollectionKey, IMediaCollectionEnumerator> collectionEnumerators, ProgramScheduleItem scheduleItem, ProgramScheduleItem nextScheduleItem, DateTimeOffset hardStop) => throw new NotSupportedException();
public void Should_Have_Gap_With_No_Tail_No_Fallback() { Collection collectionOne = TwoItemCollection(1, 2, TimeSpan.FromHours(1)); var scheduleItem = new ProgramScheduleItemOne { Id = 1, Index = 1, Collection = collectionOne, CollectionId = collectionOne.Id, StartTime = null, PlaybackOrder = PlaybackOrder.Chronological, TailFiller = null, FallbackFiller = null }; var scheduleItemsEnumerator = new OrderedScheduleItemsEnumerator( new List <ProgramScheduleItem> { scheduleItem }, new CollectionEnumeratorState()); var enumerator = new ChronologicalMediaCollectionEnumerator( collectionOne.MediaItems, new CollectionEnumeratorState()); PlayoutBuilderState startState = StartState(scheduleItemsEnumerator); var scheduler = new PlayoutModeSchedulerOne(new Mock <ILogger>().Object); (PlayoutBuilderState playoutBuilderState, List <PlayoutItem> playoutItems) = scheduler.Schedule( startState, CollectionEnumerators(scheduleItem, enumerator), scheduleItem, NextScheduleItem, HardStop(scheduleItemsEnumerator)); playoutBuilderState.CurrentTime.Should().Be(startState.CurrentTime.AddHours(1)); playoutItems.Last().FinishOffset.Should().Be(playoutBuilderState.CurrentTime); playoutBuilderState.NextGuideGroup.Should().Be(2); playoutBuilderState.DurationFinish.IsNone.Should().BeTrue(); playoutBuilderState.InFlood.Should().BeFalse(); playoutBuilderState.MultipleRemaining.IsNone.Should().BeTrue(); playoutBuilderState.InDurationFiller.Should().BeFalse(); playoutBuilderState.ScheduleItemsEnumerator.State.Index.Should().Be(0); enumerator.State.Index.Should().Be(1); playoutItems.Count.Should().Be(1); playoutItems[0].MediaItemId.Should().Be(1); playoutItems[0].StartOffset.Should().Be(startState.CurrentTime); playoutItems[0].GuideGroup.Should().Be(1); playoutItems[0].FillerKind.Should().Be(FillerKind.None); }
public void Should_Not_Crash_Mid_Roll_One_Chapter() { Collection collectionOne = TwoItemCollection(1, 2, TimeSpan.FromHours(1)); var scheduleItem = new ProgramScheduleItemOne { Id = 1, Index = 1, Collection = collectionOne, CollectionId = collectionOne.Id, StartTime = null, PlaybackOrder = PlaybackOrder.Chronological, TailFiller = null, FallbackFiller = null, MidRollFiller = new FillerPreset { FillerKind = FillerKind.MidRoll, FillerMode = FillerMode.Pad, PadToNearestMinute = 15 } }; var scheduleItemsEnumerator = new OrderedScheduleItemsEnumerator( new List <ProgramScheduleItem> { scheduleItem }, new CollectionEnumeratorState()); var enumerator = new ChronologicalMediaCollectionEnumerator( collectionOne.MediaItems, new CollectionEnumeratorState()); PlayoutBuilderState startState = StartState(scheduleItemsEnumerator); Dictionary <CollectionKey, IMediaCollectionEnumerator> enumerators = CollectionEnumerators( scheduleItem, enumerator); // too lazy to make another enumerator for the filler that we don't want enumerators.Add(CollectionKey.ForFillerPreset(scheduleItem.MidRollFiller), enumerator); List <PlayoutItem> playoutItems = Scheduler() .AddFiller( startState, enumerators, scheduleItem, new PlayoutItem(), new List <MediaChapter> { new() });
public void Should_Compare_Time_As_Local_Time() { var enumerator = new Mock <IScheduleItemsEnumerator>(); var state = new PlayoutBuilderState( enumerator.Object, None, None, false, false, 0, DateTime.Today.AddHours(6).ToUniversalTime()); var scheduleItem = new ProgramScheduleItemOne { StartTime = TimeSpan.FromHours(6) }; DateTimeOffset result = PlayoutModeSchedulerBase <ProgramScheduleItem> .GetStartTimeAfter(state, scheduleItem); result.Should().Be(DateTime.Today.AddHours(6)); }
public void Should_Not_Crash_Mid_Roll_Zero_Chapters() { Collection collectionOne = TwoItemCollection(1, 2, TimeSpan.FromHours(1)); var scheduleItem = new ProgramScheduleItemOne { MidRollFiller = new FillerPreset { FillerKind = FillerKind.MidRoll, FillerMode = FillerMode.Pad, PadToNearestMinute = 15 } }; var scheduleItemsEnumerator = new OrderedScheduleItemsEnumerator( new List <ProgramScheduleItem> { scheduleItem }, new CollectionEnumeratorState()); var enumerator = new ChronologicalMediaCollectionEnumerator( collectionOne.MediaItems, new CollectionEnumeratorState()); PlayoutBuilderState startState = StartState(scheduleItemsEnumerator); List <PlayoutItem> playoutItems = Scheduler() .AddFiller( startState, CollectionEnumerators(scheduleItem, enumerator), scheduleItem, new PlayoutItem(), new List <MediaChapter>()); playoutItems.Count.Should().Be(1); }
public void Should_Have_No_Gap_With_Exact_Post_Roll_Pad_With_Chapters() { Collection collectionOne = TwoItemCollection(1, 2, new TimeSpan(2, 45, 0), 2); Collection collectionTwo = TwoItemCollection(3, 4, TimeSpan.FromMinutes(5)); Collection collectionThree = TwoItemCollection(5, 6, TimeSpan.FromMinutes(1)); var scheduleItem = new ProgramScheduleItemOne { Id = 1, Index = 1, Collection = collectionOne, CollectionId = collectionOne.Id, StartTime = null, PlaybackOrder = PlaybackOrder.Chronological, PostRollFiller = new FillerPreset { FillerKind = FillerKind.PostRoll, FillerMode = FillerMode.Pad, PadToNearestMinute = 30, Collection = collectionTwo, CollectionId = collectionTwo.Id }, FallbackFiller = new FillerPreset { FillerKind = FillerKind.Fallback, Collection = collectionThree, CollectionId = collectionThree.Id } }; var scheduleItemsEnumerator = new OrderedScheduleItemsEnumerator( new List <ProgramScheduleItem> { scheduleItem }, new CollectionEnumeratorState()); var enumerator1 = new ChronologicalMediaCollectionEnumerator( collectionOne.MediaItems, new CollectionEnumeratorState()); var enumerator2 = new ChronologicalMediaCollectionEnumerator( collectionTwo.MediaItems, new CollectionEnumeratorState()); var enumerator3 = new ChronologicalMediaCollectionEnumerator( collectionThree.MediaItems, new CollectionEnumeratorState()); PlayoutBuilderState startState = StartState(scheduleItemsEnumerator); var scheduler = new PlayoutModeSchedulerOne(new Mock <ILogger>().Object); (PlayoutBuilderState playoutBuilderState, List <PlayoutItem> playoutItems) = scheduler.Schedule( startState, CollectionEnumerators( scheduleItem, enumerator1, scheduleItem.PostRollFiller, enumerator2, scheduleItem.FallbackFiller, enumerator3), scheduleItem, NextScheduleItem, HardStop(scheduleItemsEnumerator)); playoutBuilderState.CurrentTime.Should().Be(startState.CurrentTime.AddHours(3)); playoutItems.Last().FinishOffset.Should().Be(playoutBuilderState.CurrentTime); playoutBuilderState.NextGuideGroup.Should().Be(2); playoutBuilderState.DurationFinish.IsNone.Should().BeTrue(); playoutBuilderState.InFlood.Should().BeFalse(); playoutBuilderState.MultipleRemaining.IsNone.Should().BeTrue(); playoutBuilderState.InDurationFiller.Should().BeFalse(); playoutBuilderState.ScheduleItemsEnumerator.State.Index.Should().Be(0); enumerator1.State.Index.Should().Be(1); enumerator2.State.Index.Should().Be(1); enumerator3.State.Index.Should().Be(0); playoutItems.Count.Should().Be(4); playoutItems[0].MediaItemId.Should().Be(1); playoutItems[0].StartOffset.Should().Be(startState.CurrentTime); playoutItems[0].GuideGroup.Should().Be(1); playoutItems[0].FillerKind.Should().Be(FillerKind.None); playoutItems[1].MediaItemId.Should().Be(3); playoutItems[1].StartOffset.Should().Be(startState.CurrentTime.Add(new TimeSpan(2, 45, 0))); playoutItems[1].GuideGroup.Should().Be(1); playoutItems[1].FillerKind.Should().Be(FillerKind.PostRoll); playoutItems[2].MediaItemId.Should().Be(4); playoutItems[2].StartOffset.Should().Be(startState.CurrentTime.Add(new TimeSpan(2, 50, 0))); playoutItems[2].GuideGroup.Should().Be(1); playoutItems[2].FillerKind.Should().Be(FillerKind.PostRoll); playoutItems[3].MediaItemId.Should().Be(3); playoutItems[3].StartOffset.Should().Be(startState.CurrentTime.Add(new TimeSpan(2, 55, 0))); playoutItems[3].GuideGroup.Should().Be(1); playoutItems[3].FillerKind.Should().Be(FillerKind.PostRoll); }
public override Tuple <PlayoutBuilderState, List <PlayoutItem> > Schedule( PlayoutBuilderState playoutBuilderState, Dictionary <CollectionKey, IMediaCollectionEnumerator> collectionEnumerators, ProgramScheduleItemOne scheduleItem, ProgramScheduleItem nextScheduleItem, DateTimeOffset hardStop) { IMediaCollectionEnumerator contentEnumerator = collectionEnumerators[CollectionKey.ForScheduleItem(scheduleItem)]; foreach (MediaItem mediaItem in contentEnumerator.Current) { // find when we should start this item, based on the current time DateTimeOffset itemStartTime = GetStartTimeAfter( playoutBuilderState, scheduleItem); TimeSpan itemDuration = DurationForMediaItem(mediaItem); List <MediaChapter> itemChapters = ChaptersForMediaItem(mediaItem); var playoutItem = new PlayoutItem { MediaItemId = mediaItem.Id, Start = itemStartTime.UtcDateTime, Finish = itemStartTime.UtcDateTime + itemDuration, InPoint = TimeSpan.Zero, OutPoint = itemDuration, GuideGroup = playoutBuilderState.NextGuideGroup, FillerKind = scheduleItem.GuideMode == GuideMode.Filler ? FillerKind.Tail : FillerKind.None, WatermarkId = scheduleItem.WatermarkId, PreferredAudioLanguageCode = scheduleItem.PreferredAudioLanguageCode, PreferredSubtitleLanguageCode = scheduleItem.PreferredSubtitleLanguageCode, SubtitleMode = scheduleItem.SubtitleMode }; DateTimeOffset itemEndTimeWithFiller = CalculateEndTimeWithFiller( collectionEnumerators, scheduleItem, itemStartTime, itemDuration, itemChapters); List <PlayoutItem> playoutItems = AddFiller( playoutBuilderState, collectionEnumerators, scheduleItem, playoutItem, itemChapters); PlayoutBuilderState nextState = playoutBuilderState with { CurrentTime = itemEndTimeWithFiller }; nextState.ScheduleItemsEnumerator.MoveNext(); contentEnumerator.MoveNext(); // LogScheduledItem(scheduleItem, mediaItem, itemStartTime); // only play one item from collection, so always advance to the next item // _logger.LogDebug( // "Advancing to next schedule item after playout mode {PlayoutMode}", // "One"); DateTimeOffset nextItemStart = GetStartTimeAfter(nextState, nextScheduleItem); if (scheduleItem.TailFiller != null) { (nextState, playoutItems) = AddTailFiller( nextState, collectionEnumerators, scheduleItem, playoutItems, nextItemStart); } if (scheduleItem.FallbackFiller != null) { (nextState, playoutItems) = AddFallbackFiller( nextState, collectionEnumerators, scheduleItem, playoutItems, nextItemStart); } nextState = nextState with { NextGuideGroup = nextState.IncrementGuideGroup }; return(Tuple(nextState, playoutItems)); } return(Tuple(playoutBuilderState, new List <PlayoutItem>())); } }
public override Tuple <PlayoutBuilderState, List <PlayoutItem> > Schedule( PlayoutBuilderState playoutBuilderState, Dictionary <CollectionKey, IMediaCollectionEnumerator> collectionEnumerators, ProgramScheduleItemFlood scheduleItem, ProgramScheduleItem nextScheduleItem, DateTimeOffset hardStop) { var playoutItems = new List <PlayoutItem>(); PlayoutBuilderState nextState = playoutBuilderState; var willFinishInTime = true; IMediaCollectionEnumerator contentEnumerator = collectionEnumerators[CollectionKey.ForScheduleItem(scheduleItem)]; ProgramScheduleItem peekScheduleItem = nextScheduleItem; while (contentEnumerator.Current.IsSome && nextState.CurrentTime < hardStop && willFinishInTime) { MediaItem mediaItem = contentEnumerator.Current.ValueUnsafe(); // find when we should start this item, based on the current time DateTimeOffset itemStartTime = GetStartTimeAfter(nextState, scheduleItem); TimeSpan itemDuration = DurationForMediaItem(mediaItem); List <MediaChapter> itemChapters = ChaptersForMediaItem(mediaItem); var playoutItem = new PlayoutItem { MediaItemId = mediaItem.Id, Start = itemStartTime.UtcDateTime, Finish = itemStartTime.UtcDateTime + itemDuration, InPoint = TimeSpan.Zero, OutPoint = itemDuration, GuideGroup = nextState.NextGuideGroup, FillerKind = scheduleItem.GuideMode == GuideMode.Filler ? FillerKind.Tail : FillerKind.None, WatermarkId = scheduleItem.WatermarkId, PreferredAudioLanguageCode = scheduleItem.PreferredAudioLanguageCode, PreferredSubtitleLanguageCode = scheduleItem.PreferredSubtitleLanguageCode, SubtitleMode = scheduleItem.SubtitleMode }; DateTimeOffset peekScheduleItemStart = peekScheduleItem.StartType == StartType.Fixed ? GetStartTimeAfter(nextState with { InFlood = false }, peekScheduleItem) : DateTimeOffset.MaxValue; DateTimeOffset itemEndTimeWithFiller = CalculateEndTimeWithFiller( collectionEnumerators, scheduleItem, itemStartTime, itemDuration, itemChapters); // if the next schedule item is supposed to start during this item, // don't schedule this item and just move on willFinishInTime = peekScheduleItemStart < itemStartTime || peekScheduleItemStart >= itemEndTimeWithFiller; if (willFinishInTime) { playoutItems.AddRange( AddFiller(nextState, collectionEnumerators, scheduleItem, playoutItem, itemChapters)); // LogScheduledItem(scheduleItem, mediaItem, itemStartTime); DateTimeOffset actualEndTime = playoutItems.Max(p => p.FinishOffset); if (Math.Abs((itemEndTimeWithFiller - actualEndTime).TotalSeconds) > 1) { _logger.LogWarning( "Filler prediction failure: predicted {PredictedDuration} doesn't match actual {ActualDuration}", itemEndTimeWithFiller, actualEndTime); // _logger.LogWarning("Playout items: {@PlayoutItems}", playoutItems); } nextState = nextState with { CurrentTime = itemEndTimeWithFiller, InFlood = true, NextGuideGroup = nextState.IncrementGuideGroup }; contentEnumerator.MoveNext(); } } // _logger.LogDebug( // "Advancing to next schedule item after playout mode {PlayoutMode}", // "Flood"); nextState = nextState with { InFlood = nextState.CurrentTime >= hardStop, NextGuideGroup = nextState.DecrementGuideGroup }; nextState.ScheduleItemsEnumerator.MoveNext(); ProgramScheduleItem peekItem = nextScheduleItem; DateTimeOffset peekItemStart = GetStartTimeAfter(nextState, peekItem); if (scheduleItem.TailFiller != null) { (nextState, playoutItems) = AddTailFiller( nextState, collectionEnumerators, scheduleItem, playoutItems, peekItemStart); } if (scheduleItem.FallbackFiller != null) { (nextState, playoutItems) = AddFallbackFiller( nextState, collectionEnumerators, scheduleItem, playoutItems, peekItemStart); } nextState = nextState with { NextGuideGroup = nextState.IncrementGuideGroup }; return(Tuple(nextState, playoutItems)); } }
public override Tuple <PlayoutBuilderState, List <PlayoutItem> > Schedule( PlayoutBuilderState playoutBuilderState, Dictionary <CollectionKey, IMediaCollectionEnumerator> collectionEnumerators, ProgramScheduleItemDuration scheduleItem, ProgramScheduleItem nextScheduleItem, DateTimeOffset hardStop) { var playoutItems = new List <PlayoutItem>(); PlayoutBuilderState nextState = playoutBuilderState; var willFinishInTime = true; Option <DateTimeOffset> durationUntil = None; IMediaCollectionEnumerator contentEnumerator = collectionEnumerators[CollectionKey.ForScheduleItem(scheduleItem)]; while (contentEnumerator.Current.IsSome && nextState.CurrentTime < hardStop && willFinishInTime) { MediaItem mediaItem = contentEnumerator.Current.ValueUnsafe(); // find when we should start this item, based on the current time DateTimeOffset itemStartTime = GetStartTimeAfter(nextState, scheduleItem); // remember when we need to finish this duration item if (nextState.DurationFinish.IsNone) { nextState = nextState with { DurationFinish = itemStartTime + scheduleItem.PlayoutDuration }; durationUntil = nextState.DurationFinish; } TimeSpan itemDuration = DurationForMediaItem(mediaItem); List <MediaChapter> itemChapters = ChaptersForMediaItem(mediaItem); if (itemDuration > scheduleItem.PlayoutDuration) { _logger.LogWarning( "Skipping playout item {Title} with duration {Duration} that is longer than schedule item duration {PlayoutDuration}", PlayoutBuilder.DisplayTitle(mediaItem), itemDuration, scheduleItem.PlayoutDuration); contentEnumerator.MoveNext(); continue; } var playoutItem = new PlayoutItem { MediaItemId = mediaItem.Id, Start = itemStartTime.UtcDateTime, Finish = itemStartTime.UtcDateTime + itemDuration, InPoint = TimeSpan.Zero, OutPoint = itemDuration, GuideGroup = nextState.NextGuideGroup, FillerKind = scheduleItem.GuideMode == GuideMode.Filler ? FillerKind.Tail : FillerKind.None, CustomTitle = scheduleItem.CustomTitle, WatermarkId = scheduleItem.WatermarkId, PreferredAudioLanguageCode = scheduleItem.PreferredAudioLanguageCode, PreferredSubtitleLanguageCode = scheduleItem.PreferredSubtitleLanguageCode, SubtitleMode = scheduleItem.SubtitleMode }; durationUntil.Do(du => playoutItem.GuideFinish = du.UtcDateTime); DateTimeOffset durationFinish = nextState.DurationFinish.IfNone(SystemTime.MaxValueUtc); DateTimeOffset itemEndTimeWithFiller = CalculateEndTimeWithFiller( collectionEnumerators, scheduleItem, itemStartTime, itemDuration, itemChapters); willFinishInTime = itemStartTime > durationFinish || itemEndTimeWithFiller <= durationFinish; if (willFinishInTime) { // LogScheduledItem(scheduleItem, mediaItem, itemStartTime); playoutItems.AddRange( AddFiller(nextState, collectionEnumerators, scheduleItem, playoutItem, itemChapters)); nextState = nextState with { CurrentTime = itemEndTimeWithFiller, // only bump guide group if we don't have a custom title NextGuideGroup = string.IsNullOrWhiteSpace(scheduleItem.CustomTitle) ? nextState.IncrementGuideGroup : nextState.NextGuideGroup }; contentEnumerator.MoveNext(); } else { TimeSpan durationBlock = itemEndTimeWithFiller - itemStartTime; if (itemEndTimeWithFiller - itemStartTime > scheduleItem.PlayoutDuration) { _logger.LogWarning( "Unable to schedule duration block of {DurationBlock} which is longer than the configured playout duration {PlayoutDuration}", durationBlock, scheduleItem.PlayoutDuration); } nextState = nextState with { DurationFinish = None }; nextState.ScheduleItemsEnumerator.MoveNext(); } } // this is needed when the duration finish exactly matches the hard stop if (nextState.DurationFinish.IsSome && nextState.CurrentTime == nextState.DurationFinish) { nextState = nextState with { DurationFinish = None }; nextState.ScheduleItemsEnumerator.MoveNext(); } if (playoutItems.Select(pi => pi.GuideGroup).Distinct().Count() != 1) { nextState = nextState with { NextGuideGroup = nextState.DecrementGuideGroup }; } foreach (DateTimeOffset nextItemStart in durationUntil) { switch (scheduleItem.TailMode) { case TailMode.Filler: if (scheduleItem.TailFiller != null) { (nextState, playoutItems) = AddTailFiller( nextState, collectionEnumerators, scheduleItem, playoutItems, nextItemStart); } if (scheduleItem.FallbackFiller != null) { (nextState, playoutItems) = AddFallbackFiller( nextState, collectionEnumerators, scheduleItem, playoutItems, nextItemStart); } nextState = nextState with { CurrentTime = nextItemStart }; break; case TailMode.Offline: if (scheduleItem.FallbackFiller != null) { (nextState, playoutItems) = AddFallbackFiller( nextState, collectionEnumerators, scheduleItem, playoutItems, nextItemStart); } nextState = nextState with { CurrentTime = nextItemStart }; break; } } // clear guide finish on all but the last item var all = playoutItems.Filter(pi => pi.FillerKind == FillerKind.None).ToList(); PlayoutItem last = all.OrderBy(pi => pi.FinishOffset).LastOrDefault(); foreach (PlayoutItem item in all.Filter(pi => pi != last)) { item.GuideFinish = null; } nextState = nextState with { NextGuideGroup = nextState.IncrementGuideGroup }; return(Tuple(nextState, playoutItems)); } }
public void Should_Not_Have_Gap_Duration_Tail_Mode_Filler_With_Fallback() { Collection collectionOne = TwoItemCollection(1, 2, TimeSpan.FromMinutes(55)); Collection collectionTwo = TwoItemCollection(3, 4, TimeSpan.FromMinutes(4)); Collection collectionThree = TwoItemCollection(5, 6, TimeSpan.FromMinutes(1)); var scheduleItem = new ProgramScheduleItemDuration { Id = 1, Index = 1, Collection = collectionOne, CollectionId = collectionOne.Id, StartTime = null, PlayoutDuration = TimeSpan.FromHours(3), TailMode = TailMode.Filler, PlaybackOrder = PlaybackOrder.Chronological, TailFiller = new FillerPreset { FillerKind = FillerKind.Tail, Collection = collectionTwo, CollectionId = collectionTwo.Id }, FallbackFiller = new FillerPreset { FillerKind = FillerKind.Fallback, Collection = collectionThree, CollectionId = collectionThree.Id } }; var scheduleItemsEnumerator = new OrderedScheduleItemsEnumerator( new List <ProgramScheduleItem> { scheduleItem }, new CollectionEnumeratorState()); var enumerator1 = new ChronologicalMediaCollectionEnumerator( collectionOne.MediaItems, new CollectionEnumeratorState()); var enumerator2 = new ChronologicalMediaCollectionEnumerator( collectionTwo.MediaItems, new CollectionEnumeratorState()); var enumerator3 = new ChronologicalMediaCollectionEnumerator( collectionThree.MediaItems, new CollectionEnumeratorState()); PlayoutBuilderState startState = StartState(scheduleItemsEnumerator); var scheduler = new PlayoutModeSchedulerDuration(new Mock <ILogger>().Object); (PlayoutBuilderState playoutBuilderState, List <PlayoutItem> playoutItems) = scheduler.Schedule( startState, CollectionEnumerators( scheduleItem, enumerator1, scheduleItem.TailFiller, enumerator2, scheduleItem.FallbackFiller, enumerator3), scheduleItem, NextScheduleItem, HardStop(scheduleItemsEnumerator)); playoutBuilderState.CurrentTime.Should().Be(startState.CurrentTime.AddHours(3)); playoutItems.Last().FinishOffset.Should().Be(playoutBuilderState.CurrentTime); playoutBuilderState.NextGuideGroup.Should().Be(4); playoutBuilderState.DurationFinish.IsNone.Should().BeTrue(); playoutBuilderState.InFlood.Should().BeFalse(); playoutBuilderState.MultipleRemaining.IsNone.Should().BeTrue(); playoutBuilderState.InDurationFiller.Should().BeFalse(); playoutBuilderState.ScheduleItemsEnumerator.State.Index.Should().Be(0); enumerator1.State.Index.Should().Be(1); enumerator2.State.Index.Should().Be(1); enumerator3.State.Index.Should().Be(1); playoutItems.Count.Should().Be(7); playoutItems[0].MediaItemId.Should().Be(1); playoutItems[0].StartOffset.Should().Be(startState.CurrentTime); playoutItems[0].GuideGroup.Should().Be(1); playoutItems[0].FillerKind.Should().Be(FillerKind.None); playoutItems[0].GuideFinish.HasValue.Should().BeFalse(); playoutItems[1].MediaItemId.Should().Be(2); playoutItems[1].StartOffset.Should().Be(startState.CurrentTime.AddMinutes(55)); playoutItems[1].GuideGroup.Should().Be(2); playoutItems[1].FillerKind.Should().Be(FillerKind.None); playoutItems[1].GuideFinish.HasValue.Should().BeFalse(); playoutItems[2].MediaItemId.Should().Be(1); playoutItems[2].StartOffset.Should().Be(startState.CurrentTime.Add(new TimeSpan(1, 50, 0))); playoutItems[2].GuideGroup.Should().Be(3); playoutItems[2].FillerKind.Should().Be(FillerKind.None); playoutItems[2].GuideFinish.HasValue.Should().BeTrue(); playoutItems[3].MediaItemId.Should().Be(3); playoutItems[3].StartOffset.Should().Be(startState.CurrentTime.Add(new TimeSpan(2, 45, 0))); playoutItems[3].GuideGroup.Should().Be(3); playoutItems[3].FillerKind.Should().Be(FillerKind.Tail); playoutItems[3].GuideFinish.HasValue.Should().BeFalse(); playoutItems[4].MediaItemId.Should().Be(4); playoutItems[4].StartOffset.Should().Be(startState.CurrentTime.Add(new TimeSpan(2, 49, 0))); playoutItems[4].GuideGroup.Should().Be(3); playoutItems[4].FillerKind.Should().Be(FillerKind.Tail); playoutItems[4].GuideFinish.HasValue.Should().BeFalse(); playoutItems[5].MediaItemId.Should().Be(3); playoutItems[5].StartOffset.Should().Be(startState.CurrentTime.Add(new TimeSpan(2, 53, 0))); playoutItems[5].GuideGroup.Should().Be(3); playoutItems[5].FillerKind.Should().Be(FillerKind.Tail); playoutItems[5].GuideFinish.HasValue.Should().BeFalse(); playoutItems[6].MediaItemId.Should().Be(5); playoutItems[6].StartOffset.Should().Be(startState.CurrentTime.Add(new TimeSpan(2, 57, 0))); playoutItems[6].GuideGroup.Should().Be(3); playoutItems[6].FillerKind.Should().Be(FillerKind.Fallback); playoutItems[6].GuideFinish.HasValue.Should().BeFalse(); }
public void Should_Fill_Exact_Duration_CustomTitle() { Collection collectionOne = TwoItemCollection(1, 2, TimeSpan.FromHours(1)); var scheduleItem = new ProgramScheduleItemDuration { Id = 1, Index = 1, Collection = collectionOne, CollectionId = collectionOne.Id, StartTime = null, PlayoutDuration = TimeSpan.FromHours(3), TailMode = TailMode.None, PlaybackOrder = PlaybackOrder.Chronological, CustomTitle = "Custom Title" }; var scheduleItemsEnumerator = new OrderedScheduleItemsEnumerator( new List <ProgramScheduleItem> { scheduleItem }, new CollectionEnumeratorState()); var enumerator = new ChronologicalMediaCollectionEnumerator( collectionOne.MediaItems, new CollectionEnumeratorState()); PlayoutBuilderState startState = StartState(scheduleItemsEnumerator); var scheduler = new PlayoutModeSchedulerDuration(new Mock <ILogger>().Object); (PlayoutBuilderState playoutBuilderState, List <PlayoutItem> playoutItems) = scheduler.Schedule( startState, CollectionEnumerators(scheduleItem, enumerator), scheduleItem, NextScheduleItem, HardStop(scheduleItemsEnumerator)); playoutBuilderState.CurrentTime.Should().Be(startState.CurrentTime.AddHours(3)); playoutItems.Last().FinishOffset.Should().Be(playoutBuilderState.CurrentTime); playoutBuilderState.NextGuideGroup.Should().Be(2); playoutBuilderState.DurationFinish.IsNone.Should().BeTrue(); playoutBuilderState.InFlood.Should().BeFalse(); playoutBuilderState.MultipleRemaining.IsNone.Should().BeTrue(); playoutBuilderState.InDurationFiller.Should().BeFalse(); playoutBuilderState.ScheduleItemsEnumerator.State.Index.Should().Be(0); enumerator.State.Index.Should().Be(1); playoutItems.Count.Should().Be(3); playoutItems[0].MediaItemId.Should().Be(1); playoutItems[0].StartOffset.Should().Be(startState.CurrentTime); playoutItems[0].GuideGroup.Should().Be(1); playoutItems[0].FillerKind.Should().Be(FillerKind.None); playoutItems[0].GuideFinish.HasValue.Should().BeFalse(); playoutItems[0].CustomTitle.Should().Be("Custom Title"); playoutItems[1].MediaItemId.Should().Be(2); playoutItems[1].StartOffset.Should().Be(startState.CurrentTime.AddHours(1)); playoutItems[1].GuideGroup.Should().Be(1); playoutItems[1].FillerKind.Should().Be(FillerKind.None); playoutItems[1].GuideFinish.HasValue.Should().BeFalse(); playoutItems[1].CustomTitle.Should().Be("Custom Title"); playoutItems[2].MediaItemId.Should().Be(1); playoutItems[2].StartOffset.Should().Be(startState.CurrentTime.AddHours(2)); playoutItems[2].GuideGroup.Should().Be(1); playoutItems[2].FillerKind.Should().Be(FillerKind.None); playoutItems[2].GuideFinish.HasValue.Should().BeTrue(); playoutItems[2].CustomTitle.Should().Be("Custom Title"); }
public void Should_Have_Gap_Duration_Tail_Mode_Offline_No_Fallback() { Collection collectionOne = TwoItemCollection(1, 2, TimeSpan.FromMinutes(55)); var scheduleItem = new ProgramScheduleItemDuration { Id = 1, Index = 1, Collection = collectionOne, CollectionId = collectionOne.Id, StartTime = null, PlayoutDuration = TimeSpan.FromHours(3), TailMode = TailMode.Offline, PlaybackOrder = PlaybackOrder.Chronological }; var scheduleItemsEnumerator = new OrderedScheduleItemsEnumerator( new List <ProgramScheduleItem> { scheduleItem }, new CollectionEnumeratorState()); var enumerator = new ChronologicalMediaCollectionEnumerator( collectionOne.MediaItems, new CollectionEnumeratorState()); PlayoutBuilderState startState = StartState(scheduleItemsEnumerator); var scheduler = new PlayoutModeSchedulerDuration(new Mock <ILogger>().Object); (PlayoutBuilderState playoutBuilderState, List <PlayoutItem> playoutItems) = scheduler.Schedule( startState, CollectionEnumerators(scheduleItem, enumerator), scheduleItem, NextScheduleItem, HardStop(scheduleItemsEnumerator)); // duration block should end after exact duration, with gap playoutBuilderState.CurrentTime.Should().Be(startState.CurrentTime.AddHours(3)); playoutItems.Last().FinishOffset.Should().Be(startState.CurrentTime.Add(new TimeSpan(2, 45, 0))); playoutBuilderState.NextGuideGroup.Should().Be(4); playoutBuilderState.DurationFinish.IsNone.Should().BeTrue(); playoutBuilderState.InFlood.Should().BeFalse(); playoutBuilderState.MultipleRemaining.IsNone.Should().BeTrue(); playoutBuilderState.InDurationFiller.Should().BeFalse(); playoutBuilderState.ScheduleItemsEnumerator.State.Index.Should().Be(0); enumerator.State.Index.Should().Be(1); playoutItems.Count.Should().Be(3); playoutItems[0].MediaItemId.Should().Be(1); playoutItems[0].StartOffset.Should().Be(startState.CurrentTime); playoutItems[0].GuideGroup.Should().Be(1); playoutItems[0].FillerKind.Should().Be(FillerKind.None); playoutItems[0].GuideFinish.HasValue.Should().BeFalse(); playoutItems[1].MediaItemId.Should().Be(2); playoutItems[1].StartOffset.Should().Be(startState.CurrentTime.AddMinutes(55)); playoutItems[1].GuideGroup.Should().Be(2); playoutItems[1].FillerKind.Should().Be(FillerKind.None); playoutItems[1].GuideFinish.HasValue.Should().BeFalse(); playoutItems[2].MediaItemId.Should().Be(1); playoutItems[2].StartOffset.Should().Be(startState.CurrentTime.Add(new TimeSpan(1, 50, 0))); playoutItems[2].GuideGroup.Should().Be(3); playoutItems[2].FillerKind.Should().Be(FillerKind.None); playoutItems[2].GuideFinish.HasValue.Should().BeTrue(); }
public void Should_Not_Have_Gap_With_Unused_Tail_And_Unused_Fallback() { Collection collectionOne = TwoItemCollection(1, 2, TimeSpan.FromHours(1)); Collection collectionTwo = TwoItemCollection(3, 4, TimeSpan.FromMinutes(4)); Collection collectionThree = TwoItemCollection(5, 6, TimeSpan.FromMinutes(1)); var scheduleItem = new ProgramScheduleItemMultiple { Id = 1, Index = 1, Collection = collectionOne, CollectionId = collectionOne.Id, StartTime = null, PlaybackOrder = PlaybackOrder.Chronological, TailFiller = new FillerPreset { FillerKind = FillerKind.Tail, Collection = collectionTwo, CollectionId = collectionTwo.Id }, FallbackFiller = new FillerPreset { FillerKind = FillerKind.Fallback, Collection = collectionThree, CollectionId = collectionThree.Id }, Count = 3 }; var scheduleItemsEnumerator = new OrderedScheduleItemsEnumerator( new List <ProgramScheduleItem> { scheduleItem }, new CollectionEnumeratorState()); var enumerator1 = new ChronologicalMediaCollectionEnumerator( collectionOne.MediaItems, new CollectionEnumeratorState()); var enumerator2 = new ChronologicalMediaCollectionEnumerator( collectionTwo.MediaItems, new CollectionEnumeratorState()); var enumerator3 = new ChronologicalMediaCollectionEnumerator( collectionThree.MediaItems, new CollectionEnumeratorState()); var collectionMediaItems = new Dictionary <CollectionKey, List <MediaItem> > { { CollectionKey.ForScheduleItem(scheduleItem), collectionOne.MediaItems }, { CollectionKey.ForFillerPreset(scheduleItem.TailFiller), collectionTwo.MediaItems }, { CollectionKey.ForFillerPreset(scheduleItem.FallbackFiller), collectionThree.MediaItems } }.ToMap(); PlayoutBuilderState startState = StartState(scheduleItemsEnumerator); var scheduler = new PlayoutModeSchedulerMultiple(collectionMediaItems, new Mock <ILogger>().Object); (PlayoutBuilderState playoutBuilderState, List <PlayoutItem> playoutItems) = scheduler.Schedule( startState, CollectionEnumerators( scheduleItem, enumerator1, scheduleItem.TailFiller, enumerator2, scheduleItem.FallbackFiller, enumerator3), scheduleItem, NextScheduleItem, HardStop(scheduleItemsEnumerator)); playoutBuilderState.CurrentTime.Should().Be(startState.CurrentTime.AddHours(3)); playoutItems.Last().FinishOffset.Should().Be(playoutBuilderState.CurrentTime); playoutBuilderState.NextGuideGroup.Should().Be(4); playoutBuilderState.DurationFinish.IsNone.Should().BeTrue(); playoutBuilderState.InFlood.Should().BeFalse(); playoutBuilderState.MultipleRemaining.IsNone.Should().BeTrue(); playoutBuilderState.InDurationFiller.Should().BeFalse(); playoutBuilderState.ScheduleItemsEnumerator.State.Index.Should().Be(0); enumerator1.State.Index.Should().Be(1); enumerator2.State.Index.Should().Be(0); enumerator3.State.Index.Should().Be(0); playoutItems.Count.Should().Be(3); playoutItems[0].MediaItemId.Should().Be(1); playoutItems[0].StartOffset.Should().Be(startState.CurrentTime); playoutItems[0].GuideGroup.Should().Be(1); playoutItems[0].FillerKind.Should().Be(FillerKind.None); playoutItems[1].MediaItemId.Should().Be(2); playoutItems[1].StartOffset.Should().Be(startState.CurrentTime.AddHours(1)); playoutItems[1].GuideGroup.Should().Be(2); playoutItems[1].FillerKind.Should().Be(FillerKind.None); playoutItems[2].MediaItemId.Should().Be(1); playoutItems[2].StartOffset.Should().Be(startState.CurrentTime.AddHours(2)); playoutItems[2].GuideGroup.Should().Be(3); playoutItems[2].FillerKind.Should().Be(FillerKind.None); }
public void Should_Fill_Exactly_To_Next_Schedule_Item() { Collection collectionOne = TwoItemCollection(1, 2, TimeSpan.FromHours(1)); var scheduleItem = new ProgramScheduleItemMultiple { Id = 1, Index = 1, CollectionType = ProgramScheduleItemCollectionType.Collection, Collection = collectionOne, CollectionId = collectionOne.Id, StartTime = null, PlaybackOrder = PlaybackOrder.Chronological, TailFiller = null, FallbackFiller = null, Count = 3 }; var scheduleItemsEnumerator = new OrderedScheduleItemsEnumerator( new List <ProgramScheduleItem> { scheduleItem }, new CollectionEnumeratorState()); var enumerator = new ChronologicalMediaCollectionEnumerator( collectionOne.MediaItems, new CollectionEnumeratorState()); var collectionMediaItems = new Dictionary <CollectionKey, List <MediaItem> > { { CollectionKey.ForScheduleItem(scheduleItem), collectionOne.MediaItems } }.ToMap(); PlayoutBuilderState startState = StartState(scheduleItemsEnumerator); var scheduler = new PlayoutModeSchedulerMultiple(collectionMediaItems, new Mock <ILogger>().Object); (PlayoutBuilderState playoutBuilderState, List <PlayoutItem> playoutItems) = scheduler.Schedule( startState, CollectionEnumerators(scheduleItem, enumerator), scheduleItem, NextScheduleItem, HardStop(scheduleItemsEnumerator)); playoutBuilderState.CurrentTime.Should().Be(startState.CurrentTime.AddHours(3)); playoutItems.Last().FinishOffset.Should().Be(playoutBuilderState.CurrentTime); playoutBuilderState.NextGuideGroup.Should().Be(4); playoutBuilderState.DurationFinish.IsNone.Should().BeTrue(); playoutBuilderState.InFlood.Should().BeFalse(); playoutBuilderState.MultipleRemaining.IsNone.Should().BeTrue(); playoutBuilderState.InDurationFiller.Should().BeFalse(); playoutBuilderState.ScheduleItemsEnumerator.State.Index.Should().Be(0); enumerator.State.Index.Should().Be(1); playoutItems.Count.Should().Be(3); playoutItems[0].MediaItemId.Should().Be(1); playoutItems[0].StartOffset.Should().Be(startState.CurrentTime); playoutItems[0].GuideGroup.Should().Be(1); playoutItems[0].FillerKind.Should().Be(FillerKind.None); playoutItems[1].MediaItemId.Should().Be(2); playoutItems[1].StartOffset.Should().Be(startState.CurrentTime.AddHours(1)); playoutItems[1].GuideGroup.Should().Be(2); playoutItems[1].FillerKind.Should().Be(FillerKind.None); playoutItems[2].MediaItemId.Should().Be(1); playoutItems[2].StartOffset.Should().Be(startState.CurrentTime.AddHours(2)); playoutItems[2].GuideGroup.Should().Be(3); playoutItems[2].FillerKind.Should().Be(FillerKind.None); }
public void Should_Fill_Exactly_To_Next_Schedule_Item_Flood() { Collection collectionOne = TwoItemCollection(1, 2, TimeSpan.FromHours(1)); var scheduleItem = new ProgramScheduleItemFlood { Id = 1, Index = 1, Collection = collectionOne, CollectionId = collectionOne.Id, StartTime = null, PlaybackOrder = PlaybackOrder.Chronological, TailFiller = null, FallbackFiller = null }; var enumerator = new ChronologicalMediaCollectionEnumerator( collectionOne.MediaItems, new CollectionEnumeratorState()); var sortedScheduleItems = new List <ProgramScheduleItem> { scheduleItem, // this caused trouble with the peek logic and the IsFlood flag new ProgramScheduleItemFlood { StartTime = TimeSpan.FromHours(3) } }; var scheduleItemsEnumerator = new OrderedScheduleItemsEnumerator( sortedScheduleItems, new CollectionEnumeratorState()); PlayoutBuilderState startState = StartState(scheduleItemsEnumerator); var scheduler = new PlayoutModeSchedulerFlood(new Mock <ILogger>().Object); (PlayoutBuilderState playoutBuilderState, List <PlayoutItem> playoutItems) = scheduler.Schedule( startState, CollectionEnumerators(scheduleItem, enumerator), scheduleItem, NextScheduleItem, HardStop(scheduleItemsEnumerator)); playoutBuilderState.CurrentTime.Should().Be(startState.CurrentTime.AddHours(3)); playoutItems.Last().FinishOffset.Should().Be(playoutBuilderState.CurrentTime); playoutBuilderState.NextGuideGroup.Should().Be(4); playoutBuilderState.DurationFinish.IsNone.Should().BeTrue(); playoutBuilderState.InFlood.Should().BeFalse(); playoutBuilderState.MultipleRemaining.IsNone.Should().BeTrue(); playoutBuilderState.InDurationFiller.Should().BeFalse(); playoutBuilderState.ScheduleItemsEnumerator.State.Index.Should().Be(1); enumerator.State.Index.Should().Be(1); playoutItems.Count.Should().Be(3); playoutItems[0].MediaItemId.Should().Be(1); playoutItems[0].StartOffset.Should().Be(startState.CurrentTime); playoutItems[0].GuideGroup.Should().Be(1); playoutItems[0].FillerKind.Should().Be(FillerKind.None); playoutItems[1].MediaItemId.Should().Be(2); playoutItems[1].StartOffset.Should().Be(startState.CurrentTime.AddHours(1)); playoutItems[1].GuideGroup.Should().Be(2); playoutItems[1].FillerKind.Should().Be(FillerKind.None); playoutItems[2].MediaItemId.Should().Be(1); playoutItems[2].StartOffset.Should().Be(startState.CurrentTime.AddHours(2)); playoutItems[2].GuideGroup.Should().Be(3); playoutItems[2].FillerKind.Should().Be(FillerKind.None); }
public void Should_Fill_Exactly_To_Next_Schedule_Item_With_Post_Roll_Multiple_One() { Collection collectionOne = TwoItemCollection(1, 2, TimeSpan.FromMinutes(55)); Collection collectionTwo = TwoItemCollection(3, 4, TimeSpan.FromMinutes(5)); var scheduleItem = new ProgramScheduleItemFlood { Id = 1, Index = 1, Collection = collectionOne, CollectionId = collectionOne.Id, StartTime = null, PlaybackOrder = PlaybackOrder.Chronological, PostRollFiller = new FillerPreset { FillerKind = FillerKind.PostRoll, FillerMode = FillerMode.Count, Count = 1, Collection = collectionTwo, CollectionId = collectionTwo.Id }, TailFiller = null, FallbackFiller = null }; var enumerator1 = new ChronologicalMediaCollectionEnumerator( collectionOne.MediaItems, new CollectionEnumeratorState()); var enumerator2 = new ChronologicalMediaCollectionEnumerator( collectionTwo.MediaItems, new CollectionEnumeratorState()); var sortedScheduleItems = new List <ProgramScheduleItem> { scheduleItem, NextScheduleItem }; var scheduleItemsEnumerator = new OrderedScheduleItemsEnumerator( sortedScheduleItems, new CollectionEnumeratorState()); PlayoutBuilderState startState = StartState(scheduleItemsEnumerator); var scheduler = new PlayoutModeSchedulerFlood(new Mock <ILogger>().Object); (PlayoutBuilderState playoutBuilderState, List <PlayoutItem> playoutItems) = scheduler.Schedule( startState, CollectionEnumerators(scheduleItem, enumerator1, scheduleItem.PostRollFiller, enumerator2), scheduleItem, NextScheduleItem, HardStop(scheduleItemsEnumerator)); playoutBuilderState.CurrentTime.Should().Be(startState.CurrentTime.AddHours(3)); playoutItems.Last().FinishOffset.Should().Be(playoutBuilderState.CurrentTime); playoutBuilderState.NextGuideGroup.Should().Be(4); playoutBuilderState.DurationFinish.IsNone.Should().BeTrue(); playoutBuilderState.InFlood.Should().BeFalse(); playoutBuilderState.MultipleRemaining.IsNone.Should().BeTrue(); playoutBuilderState.InDurationFiller.Should().BeFalse(); playoutBuilderState.ScheduleItemsEnumerator.State.Index.Should().Be(1); enumerator1.State.Index.Should().Be(1); enumerator2.State.Index.Should().Be(1); playoutItems.Count.Should().Be(6); playoutItems[0].MediaItemId.Should().Be(1); playoutItems[0].StartOffset.Should().Be(startState.CurrentTime); playoutItems[0].GuideGroup.Should().Be(1); playoutItems[0].FillerKind.Should().Be(FillerKind.None); playoutItems[1].MediaItemId.Should().Be(3); playoutItems[1].StartOffset.Should().Be(startState.CurrentTime.AddMinutes(55)); playoutItems[1].GuideGroup.Should().Be(1); playoutItems[1].FillerKind.Should().Be(FillerKind.PostRoll); playoutItems[2].MediaItemId.Should().Be(2); playoutItems[2].StartOffset.Should().Be(startState.CurrentTime.AddHours(1)); playoutItems[2].GuideGroup.Should().Be(2); playoutItems[2].FillerKind.Should().Be(FillerKind.None); playoutItems[3].MediaItemId.Should().Be(4); playoutItems[3].StartOffset.Should().Be(startState.CurrentTime.Add(new TimeSpan(1, 55, 0))); playoutItems[3].GuideGroup.Should().Be(2); playoutItems[3].FillerKind.Should().Be(FillerKind.PostRoll); playoutItems[4].MediaItemId.Should().Be(1); playoutItems[4].StartOffset.Should().Be(startState.CurrentTime.AddHours(2)); playoutItems[4].GuideGroup.Should().Be(3); playoutItems[4].FillerKind.Should().Be(FillerKind.None); playoutItems[5].MediaItemId.Should().Be(3); playoutItems[5].StartOffset.Should().Be(startState.CurrentTime.Add(new TimeSpan(2, 55, 0))); playoutItems[5].GuideGroup.Should().Be(3); playoutItems[5].FillerKind.Should().Be(FillerKind.PostRoll); }