streaming

Media streaming and broadcast systems in Go
Log | Files | Refs | README | LICENSE

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 }