splice_test.go (5846B)
1 package scte35 2 3 import ( 4 "encoding/base64" 5 "fmt" 6 "reflect" 7 "strings" 8 "testing" 9 "time" 10 ) 11 12 func diffInfo(a, b Splice) string { 13 buf := &strings.Builder{} 14 if a.SAPType != b.SAPType { 15 fmt.Fprintln(buf, "SAP type differs") 16 fmt.Fprintf(buf, "< %s\n> %s\n", a.SAPType, b.SAPType) 17 } 18 if a.Cipher != b.Cipher { 19 fmt.Fprintln(buf, "cipher differs") 20 fmt.Fprintf(buf, "< %s\n> %s", a.Cipher, b.Cipher) 21 } 22 if a.PTSAdjustment != b.PTSAdjustment { 23 fmt.Fprintln(buf, "pts adjustment = ", a.PTSAdjustment, b.PTSAdjustment) 24 } 25 if a.CWIndex != b.CWIndex { 26 fmt.Fprintln(buf, "cw index differs") 27 fmt.Fprintf(buf, "< %v\n> %v\n", a.CWIndex, b.CWIndex) 28 } 29 if a.Tier != b.Tier { 30 fmt.Fprintln(buf, "tier differs") 31 fmt.Fprintf(buf, "< %#x\n> %#x\n", a.Tier, b.Tier) 32 } 33 if !reflect.DeepEqual(a.Command, b.Command) { 34 fmt.Fprintln(buf, "command = ", *a.Command, *b.Command) 35 } 36 for i := range a.Descriptors { 37 if !reflect.DeepEqual(a.Descriptors[i], b.Descriptors[i]) { 38 buf.WriteString(diffDescriptors(a.Descriptors[i], b.Descriptors[i])) 39 } 40 } 41 if a.CRC32 != b.CRC32 { 42 fmt.Fprintln(buf, "crc32 = ", a.CRC32, b.CRC32) 43 } 44 return buf.String() 45 } 46 47 func diffDescriptors(a, b SpliceDescriptor) string { 48 buf := &strings.Builder{} 49 if a.Tag() != b.Tag() { 50 fmt.Fprintln(buf, "tag differs") 51 fmt.Fprintln(buf, "<", a.Tag()) 52 fmt.Fprintln(buf, ">", b.Tag()) 53 } 54 if a.ID() != b.ID() { 55 fmt.Fprintln(buf, "id differs") 56 fmt.Fprintf(buf, "< %d\n> %d\n", a.ID(), b.ID()) 57 } 58 if !reflect.DeepEqual(a.Data(), b.Data()) { 59 fmt.Fprintln(buf, "data differs") 60 fmt.Fprintf(buf, "< %v\n> %v\n", a.Data(), b.Data()) 61 } 62 fmt.Fprintf(buf, "< %T %v\n> %T %v\n", a, a, b, b) 63 return buf.String() 64 } 65 66 func TestDecode(t *testing.T) { 67 for _, tt := range samples { 68 t.Run(tt.name, func(t *testing.T) { 69 b, err := base64.StdEncoding.DecodeString(tt.encoded) 70 if err != nil { 71 t.Fatal("decode example splice:", err) 72 } 73 splice, err := Decode(b) 74 if err != nil { 75 t.Fatalf("decode splice: %v", err) 76 } 77 78 // test each possible command 79 if tt.want.Command.TimeSignal != nil { 80 if *tt.want.Command.TimeSignal != *splice.Command.TimeSignal { 81 t.Errorf("want timesig %x, got %x", *tt.want.Command.TimeSignal, *splice.Command.TimeSignal) 82 } 83 } 84 if tt.want.Command.Insert != nil { 85 want := *tt.want.Command.Insert 86 got := *splice.Command.Insert 87 if !reflect.DeepEqual(want, got) { 88 t.Errorf("splice command: want %+v, got %+v", want, got) 89 if *want.SpliceTime != *got.SpliceTime { 90 t.Logf("want splice time %d, got %d", want.SpliceTime, got.SpliceTime) 91 } 92 if want.Duration.Duration != got.Duration.Duration { 93 t.Logf("want break duration %d, got %d", want.Duration.Duration, got.Duration.Duration) 94 } 95 } 96 } 97 98 if !reflect.DeepEqual(tt.want, *splice) { 99 t.Errorf("decode splice splice: want %+v, got %+v", tt.want, *splice) 100 t.Log(diffInfo(tt.want, *splice)) 101 } 102 }) 103 } 104 105 // these messages are from github.com/futzu/SCTE-35_threefive/examples/hls/ 106 inserts := map[string]time.Duration{ 107 "/DAlAAAAAAAAAP/wFAUAAAABf+/+ANgNkv4AFJlwAAEBAQAA5xULLA==": 15 * time.Second, 108 "/DAnAAAAAAAAAP/wBQb+AA27oAARAg9DVUVJAAAAAX+HCQA0AAE0xUZn": 10 * time.Second, 109 "/DAnAAAAAAAAAP/wBQb+AGb/MAARAg9DVUVJAAAAAn+HCQA0AALMua1L": 75 * time.Second, 110 } 111 for s, dur := range inserts { 112 b, err := base64.StdEncoding.DecodeString(s) 113 if err != nil { 114 t.Fatal(err) 115 } 116 splice, err := Decode(b) 117 if err != nil { 118 t.Fatalf("decode splice splice: %v", err) 119 } 120 var got time.Duration 121 switch splice.Command.Type { 122 case TimeSignal: 123 got = time.Duration(*splice.Command.TimeSignal/90000) * time.Second 124 case SpliceInsert: 125 got = time.Duration(splice.Command.Insert.Duration.Duration/90000) * time.Second 126 default: 127 t.Fatalf("no duration test supported for %s", splice.Command.Type) 128 } 129 if got != dur { 130 t.Errorf("want %s, got %s", dur, got) 131 } 132 } 133 } 134 135 func TestEncode(t *testing.T) { 136 for _, tt := range samples { 137 t.Run(tt.name, func(t *testing.T) { 138 b, err := Encode(&tt.want) 139 if err != nil { 140 t.Fatal(err) 141 } 142 bwant, err := base64.StdEncoding.DecodeString(tt.encoded) 143 if err != nil { 144 t.Fatal(err) 145 } 146 // If we're not encrypted, set the CWIndex to be 147 // the same as desired; its value is now undefined 148 // and should be ignored downstream. This lets our 149 // test pass even if our test encoded value has a 150 // different CWIndex set than what we encode. 151 if !tt.want.Encrypted { 152 b[9] = bwant[9] 153 } 154 got := base64.StdEncoding.EncodeToString(b) 155 if tt.encoded != got { 156 // as above, since the undefined CWIndex is encoded differently, 157 // our checksum could be different. 158 // Only error if the value of the message *without* the CRC32 is different. 159 if tt.encoded[:len(tt.encoded)-7] != got[:len(got)-7] { 160 t.Errorf("expected encoded splice differs from calculated") 161 } 162 t.Logf("< %#x", bwant) 163 t.Logf("> %#x", b) 164 } 165 }) 166 } 167 } 168 169 const bitstreamModeKaraoke uint8 = 0b00000111 170 171 func TestAudioDescriptor(t *testing.T) { 172 desc := []AudioChannel{ 173 { 174 ComponentTag: 0xff, // should be 0xff if unused. 175 Language: [3]byte{'e', 'n', 'g'}, // English 176 BitstreamMode: bitstreamModeKaraoke, 177 Count: SixChan, 178 FullService: true, 179 }, 180 } 181 182 want := [6]byte{ 183 0b00010000, // we have a single channel (above), shifted left 4. reserved bits untoggled. 184 0xff, // ComponentTag 185 'e', 'n', 'g', // Language 186 // bit layout is 187 // mode mode mode, count count count count, fullservice 188 0b11111011, // Mode = karaoke, Count = SixChan, FullService = true 189 } 190 191 var got [6]byte 192 marshalled := AudioDescriptor(desc).Data() 193 copy(got[:], marshalled) 194 if got != want { 195 t.Logf("final byte = %#08b, want %#08b", got[5], want[5]) 196 t.Fatalf("Data() = %#08bb, want %#08b", got, want) 197 } 198 }