using System; using System.Linq; using System.Threading; using System.Threading.Tasks; using Jellyfin.Plugin.Enigma2; using MediaBrowser.Controller.MediaEncoding; using MediaBrowser.Model.Entities; public static class BroadcastTrackTests { public static async Task Run(Action check) { const string json="""{"streams":[{"index":0,"id":"0x100","codec_type":"video","codec_name":"h264","width":1920,"height":1080},{"index":2,"id":"0x102","codec_type":"audio","codec_name":"ac3","channels":6,"tags":{"language":"pol","title":"Polski"},"disposition":{"default":1}},{"index":3,"id":"0x103","codec_type":"audio","codec_name":"aac","channels":2,"tags":{"language":"eng","title":"English"}},{"index":5,"id":"0x105","codec_type":"subtitle","codec_name":"dvb_subtitle","tags":{"language":"pol","title":"Napisy"},"disposition":{"forced":1,"hearing_impaired":1},"extradata":"\n00000000: 0001 0001 ....\n"},{"index":6,"id":"0x106","codec_type":"subtitle","codec_name":"dvb_teletext","tags":{"language":"eng"}},{"index":1,"codec_type":"data","codec_name":"bin_data"}]}"""; var parsed=LiveStreamProbe.Parse(json); check(parsed.Count==5&&parsed.Count(s=>s.Type==MediaStreamType.Subtitle)==2,"probe retains both audio languages and broadcast subtitles while excluding data PIDs"); check(parsed[3].Codec=="DVBSUB"&&!parsed[3].IsTextSubtitleStream&&parsed[4].Codec=="DVBTXT","native Jellyfin codec names distinguish DVB bitmap and teletext subtitles"); check(parsed[3].IsForced&&parsed[3].IsHearingImpaired&&parsed[1].IsDefault&&parsed[1].Title=="Polski","language labels and default/forced/hearing-impaired dispositions survive probing"); check(parsed[3] is BroadcastMediaStream {TransportId:261,SubtitleExtraData:var extra}&&extra.SequenceEqual(new byte[]{0,1,0,1}),"probe preserves transport PIDs and DVB page IDs"); var layout=new BroadcastTracks(parsed); check(layout.Output[0].Width==1920&&layout.Output[0].Height==1080&&BroadcastTracks.Fallback().Output[0].Width==null,"native negotiation uses probed channel dimensions, never the status picture dimensions"); check(layout.Output.Select(s=>s.Index).SequenceEqual(Enumerable.Range(0,5))&&layout.Output[2].Language=="eng","explicitly ordered program exposes distinct stable selectable indices"); check(layout.Output[1].Codec=="ac3"&&layout.Output[1].Channels==6&&layout.Output[2].Codec=="aac", "every audio language retains its original codec and surround channels"); check(EncodingHelper.FindIndex(layout.Output,layout.Output[2])==2&&EncodingHelper.GetSubtitleStreamIndexForFfmpeg(new(){MediaStreams=layout.Output},layout.Output[3])==3,"installed Jellyfin resolves alternate audio and subtitle maps without unknown-index auto-selection"); check(layout.MapArguments().Contains("0:i:261")&&!layout.MapArguments().Contains("-sn"),"producer maps broadcast PIDs instead of unstable probe positions and retains subtitles"); var untouched=new BroadcastTracks(parsed,false); check(untouched.Output[1].Codec=="ac3"&&untouched.Output[1].Channels==6,"disabled slates preserve original audio codec and surround channels through remux"); var section=BroadcastSlateProgram.Section(layout);uint crc=0xffffffff; foreach(var value in section){crc^=(uint)value<<24;for(var bit=0;bit<8;bit++)crc=(crc&0x80000000)!=0?(crc<<1)^0x04c11db7:crc<<1;} check(crc==0&§ion.Contains((byte)89)&§ion.Contains((byte)86),"status program map has valid MPEG-TS CRC and DVB/teletext descriptors"); var subtitleClock=new DvbSubtitleVersions(SyntheticBroadcastFixture.Tracks());var cc=0; var wire=SyntheticBroadcastFixture.Packets(SyntheticBroadcastFixture.Bitmap(0),126000,259,ref cc).SelectMany(b=>b).ToArray(); var first=wire.ToArray();subtitleClock.Apply(first,0);var next=wire.ToArray();subtitleClock.Apply(next,1); check(!first.SequenceEqual(next),"DVB pages, objects and display definitions get fresh versions across status/live boundaries"); var retry=wire.ToArray();subtitleClock.Apply(retry,1);check(retry.SequenceEqual(next),"repeated HLS segment requests reuse the same DVB version plan"); var probe=new LiveStreamProbe((_,_)=>Task.FromResult(json));await probe.Get("channel",CancellationToken.None); check(probe.LastKnown("channel")?.Count==5&&probe.LastKnown("other",1)==null&&probe.LastKnown("channel",2)==null,"last-known track catalogue is isolated by source and programme"); } }