Skip to content

Commit

Permalink
Added CCTE-35 support (splice_insert messages)
Browse files Browse the repository at this point in the history
  • Loading branch information
inheb committed Jan 6, 2020
1 parent e5ec178 commit 17dceb8
Show file tree
Hide file tree
Showing 2 changed files with 189 additions and 3 deletions.
60 changes: 58 additions & 2 deletions tsduck-stat/tsduck-stat.go
Expand Up @@ -10,6 +10,7 @@ import (
"regexp"
"strconv"
"io/ioutil"
"io"
)


Expand All @@ -28,6 +29,8 @@ var bitrateAgg1Avg int64 = 0 //average bitrate (interval 1)
var bitrateAgg2Avg int64 = 0 //average bitrate (interval 2)
var missingPackets int64 = 0 //total missing TS packets
var ccErrorSeconds int64 = 0 //total seconds with CC errors
var ccte35oont int64 = 0 //total scte-35 splice_insert messages with out_of_network=true
var ccte35oonf int64 = 0 //total scte-35 splice_insert messages with out_of_network=false


func main() {
Expand All @@ -52,14 +55,17 @@ func main() {
var bitrateAgg2Secs int64 = 0 //seconds for bitrate aggregation 2

mcastGroup := os.Args[1]
args := "--realtime -t -I ip -b 8388608 "+mcastGroup+" -O drop -P continuity -P bitrate_monitor -p 1 -t 1"
//SCTE 35 2019 (section 9.6.1): table_id – This is an 8-bit field. Its value shall be 0xFC
args := "--realtime -t -I ip -b 8388608 "+mcastGroup+" -O drop -P continuity -P tables -f --xml-output - --tid 0xFC -P bitrate_monitor -p 1 -t 1"
cmd := exec.Command("tsp", strings.Split(args, " ")...)

stderr, _ := cmd.StderrPipe()
stdout, _ := cmd.StdoutPipe()
cmd.Start()

//go uptimeThread()
go writeThread(mcastGroup)
go stdoutReader(stdout)

scanner := bufio.NewScanner(stderr)
scanner.Split(bufio.ScanLines)
Expand Down Expand Up @@ -134,6 +140,33 @@ func check(e error) {
}
}

func stdoutReader(stdout io.ReadCloser) {
scanner := bufio.NewScanner(stdout)
scanner.Split(bufio.ScanLines)

//line example: <splice_insert splice_event_id="0x400004F6" splice_event_cancel="false" out_of_network="true" \
// splice_immediate="false" unique_program_id="0x0001" avail_num="0" avails_expected="0" pts_time="5,326,199,179">

regexp1 := regexp.MustCompile(`<splice_insert.*out_of_network="(true|false)"`) //extract out_of_network value [1]

for scanner.Scan() {
//line := scanner.Text()
parts := regexp1.FindStringSubmatch(scanner.Text())
if(len(parts)!=2) {
continue
}
switch parts[1] { //check out_of_network value
case "true":
ccte35oont++
case "false":
ccte35oonf++
default:
continue
}
fmt.Println(parts)
}
}

func writeThread(mcastGroup string) {
start := time.Now() //start time for uptime calculation
var lowBitrateSecsLast int64 = -1
Expand All @@ -142,6 +175,8 @@ func writeThread(mcastGroup string) {
var bitrateAgg2AvgLast int64 = -1
var ccErrorSecondsLast int64 = -1
var missingPacketsLast int64 = -1
var ccte35oontLast int64 = -1
var ccte35oonfLast int64 = -1

var fileMode os.FileMode = 0644

Expand All @@ -159,7 +194,10 @@ func writeThread(mcastGroup string) {
ccErrorSecondsFileTmp := workDir+"/cc_secs_"+mcastGroup+"_tmp"
missingPacketsFile := workDir+"/cc_miss_"+mcastGroup
missingPacketsFileTmp := workDir+"/cc_miss_"+mcastGroup+"_tmp"

ccte35oontFile := workDir+"/ccte35_oont_"+mcastGroup
ccte35oontFileTmp := workDir+"/cct35_oont_"+mcastGroup+"_tmp"
ccte35oonfFile := workDir+"/ccte35_oonf_"+mcastGroup
ccte35oonfFileTmp := workDir+"/cct35_oonf_"+mcastGroup+"_tmp"

for {
uptime := time.Since(start).Nanoseconds()/1e6
Expand All @@ -170,6 +208,24 @@ func writeThread(mcastGroup string) {
err2 := os.Rename(uptimeFileTmp, uptimeFile)
check(err2)

if(ccte35oontLast != ccte35oont) {
ccte35oontWr := ccte35oont
err13 := ioutil.WriteFile(ccte35oontFileTmp, []byte(strconv.FormatInt(ccte35oontWr, 10)), fileMode)
check(err13)
err14 := os.Rename(ccte35oontFileTmp, ccte35oontFile)
check(err14)
ccte35oontLast=ccte35oontWr
}

if(ccte35oonfLast != ccte35oonf) {
ccte35oonfWr := ccte35oonf
err15 := ioutil.WriteFile(ccte35oonfFileTmp, []byte(strconv.FormatInt(ccte35oonfWr, 10)), fileMode)
check(err15)
err16 := os.Rename(ccte35oonfFileTmp, ccte35oonfFile)
check(err16)
ccte35oonfLast=ccte35oonfWr
}

if(ccErrorSecondsLast != ccErrorSeconds) {
ccErrorSecondsWr := ccErrorSeconds
err11 := ioutil.WriteFile(ccErrorSecondsFileTmp, []byte(strconv.FormatInt(ccErrorSecondsWr*1000, 10)), fileMode)
Expand Down
132 changes: 131 additions & 1 deletion zabbix_templates/tsduck_stat_template.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<zabbix_export>
<version>2.0</version>
<date>2020-01-04T17:37:31Z</date>
<date>2020-01-06T13:40:26Z</date>
<groups>
<group>
<name>Templates</name>
Expand Down Expand Up @@ -224,6 +224,92 @@
<valuemap/>
<logtimefmt/>
</item_prototype>
<item_prototype>
<name>CCTE-35 splice_insert oon=false {#MGROUP}</name>
<type>0</type>
<snmp_community/>
<multiplier>0</multiplier>
<snmp_oid/>
<key>vfs.file.contents[/dev/shm/tsduck-stat/ccte35_oonf_{#MGROUP}]</key>
<delay>30</delay>
<history>90</history>
<trends>365</trends>
<status>0</status>
<value_type>3</value_type>
<allowed_hosts/>
<units/>
<delta>2</delta>
<snmpv3_contextname/>
<snmpv3_securityname/>
<snmpv3_securitylevel>0</snmpv3_securitylevel>
<snmpv3_authprotocol>0</snmpv3_authprotocol>
<snmpv3_authpassphrase/>
<snmpv3_privprotocol>0</snmpv3_privprotocol>
<snmpv3_privpassphrase/>
<formula>1</formula>
<delay_flex/>
<params/>
<ipmi_sensor/>
<data_type>0</data_type>
<authtype>0</authtype>
<username/>
<password/>
<publickey/>
<privatekey/>
<port/>
<description>CCTE-35 splice_insert with out_of_network=false</description>
<inventory_link>0</inventory_link>
<applications>
<application>
<name>TSDuck statistics</name>
</application>
</applications>
<valuemap/>
<logtimefmt/>
</item_prototype>
<item_prototype>
<name>CCTE-35 splice_insert oon=true {#MGROUP}</name>
<type>0</type>
<snmp_community/>
<multiplier>0</multiplier>
<snmp_oid/>
<key>vfs.file.contents[/dev/shm/tsduck-stat/ccte35_oont_{#MGROUP}]</key>
<delay>30</delay>
<history>90</history>
<trends>365</trends>
<status>0</status>
<value_type>3</value_type>
<allowed_hosts/>
<units/>
<delta>2</delta>
<snmpv3_contextname/>
<snmpv3_securityname/>
<snmpv3_securitylevel>0</snmpv3_securitylevel>
<snmpv3_authprotocol>0</snmpv3_authprotocol>
<snmpv3_authpassphrase/>
<snmpv3_privprotocol>0</snmpv3_privprotocol>
<snmpv3_privpassphrase/>
<formula>1</formula>
<delay_flex/>
<params/>
<ipmi_sensor/>
<data_type>0</data_type>
<authtype>0</authtype>
<username/>
<password/>
<publickey/>
<privatekey/>
<port/>
<description>CCTE-35 splice_insert with out_of_network=true</description>
<inventory_link>0</inventory_link>
<applications>
<application>
<name>TSDuck statistics</name>
</application>
</applications>
<valuemap/>
<logtimefmt/>
</item_prototype>
<item_prototype>
<name>Seconds with CC misses {#MGROUP} (%)</name>
<type>0</type>
Expand Down Expand Up @@ -518,6 +604,50 @@
</graph_item>
</graph_items>
</graph_prototype>
<graph_prototype>
<name>CCTE-35 splice_inserts of {#MGROUP}</name>
<width>900</width>
<height>200</height>
<yaxismin>0.0000</yaxismin>
<yaxismax>100.0000</yaxismax>
<show_work_period>1</show_work_period>
<show_triggers>0</show_triggers>
<type>0</type>
<show_legend>1</show_legend>
<show_3d>0</show_3d>
<percent_left>0.0000</percent_left>
<percent_right>0.0000</percent_right>
<ymin_type_1>0</ymin_type_1>
<ymax_type_1>0</ymax_type_1>
<ymin_item_1>0</ymin_item_1>
<ymax_item_1>0</ymax_item_1>
<graph_items>
<graph_item>
<sortorder>0</sortorder>
<drawtype>0</drawtype>
<color>00CC00</color>
<yaxisside>0</yaxisside>
<calc_fnc>4</calc_fnc>
<type>0</type>
<item>
<host>Template TSDuck stat</host>
<key>vfs.file.contents[/dev/shm/tsduck-stat/ccte35_oonf_{#MGROUP}]</key>
</item>
</graph_item>
<graph_item>
<sortorder>1</sortorder>
<drawtype>0</drawtype>
<color>0000FF</color>
<yaxisside>0</yaxisside>
<calc_fnc>4</calc_fnc>
<type>0</type>
<item>
<host>Template TSDuck stat</host>
<key>vfs.file.contents[/dev/shm/tsduck-stat/ccte35_oont_{#MGROUP}]</key>
</item>
</graph_item>
</graph_items>
</graph_prototype>
<graph_prototype>
<name>TSP uptime/bitrate info of {#MGROUP}</name>
<width>900</width>
Expand Down

0 comments on commit 17dceb8

Please sign in to comment.