From 43e9546192668e2ac16b54921c3e6796e8826d3b Mon Sep 17 00:00:00 2001 From: schneider Date: Thu, 16 Jul 2020 17:24:27 +0200 Subject: [PATCH] feat(vod): Add tools to cluster, parse and play VOD calls --- check-sample-vod | 1 + play-iridium-vod | 5 ++ vod-cluster.py | 54 ++++++++++++++++++ vod-stitcher.py | 140 +++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 200 insertions(+) create mode 100755 check-sample-vod create mode 100755 play-iridium-vod create mode 100755 vod-cluster.py create mode 100755 vod-stitcher.py diff --git a/check-sample-vod b/check-sample-vod new file mode 100755 index 0000000..c5b3121 --- /dev/null +++ b/check-sample-vod @@ -0,0 +1 @@ +vod-stitcher.py $1 /tmp/voice.dfs && ir77_ambe_decode /tmp/voice.dfs /tmp/voice.wav diff --git a/play-iridium-vod b/play-iridium-vod new file mode 100755 index 0000000..6a22f6b --- /dev/null +++ b/play-iridium-vod @@ -0,0 +1,5 @@ +#!/bin/sh +vod-stitcher.py $1 /tmp/voice.dfs +ir77_ambe_decode /tmp/voice.dfs /tmp/voice.wav +ambe -w /tmp/voice.dfs +mplayer /tmp/voice.wav diff --git a/vod-cluster.py b/vod-cluster.py new file mode 100755 index 0000000..27c7084 --- /dev/null +++ b/vod-cluster.py @@ -0,0 +1,54 @@ +#!/usr/bin/python +# vim: set ts=4 sw=4 tw=0 et fenc=utf8 pm=: + +import sys +import os + +class Frame: + def __init__(self, f, f_alt, ts, line): + self.f = f + self.ts = ts + self.line = line + self.f_alt = f_alt + +calls = [] + +for line in open(sys.argv[1]): + if 'VOD: ' in line: + sl = line.split() + ts = int(sl[2])/1000. # seconds + f = int(sl[3])/1000. # kHz + frame = Frame(f, 0, ts, line) + + for call in calls: + last_frame = call[-1] + + # VOD calls span three adjacent channels. We need to be quite + # generous with our frequency window to capture them while looking + # at single frames + + # If the last frame is not more than 140 kHz and 20 seconds "away" + if abs(last_frame.f - frame.f < 140) and abs(last_frame.ts - frame.ts) < 20: + call.append(frame) + # First call that matches wins + break + else: + # If no matching call is available create a new one + calls.insert(0,[frame]) + +call_id = 0 +for call in calls[::-1]: + if abs(call[0].ts - call[-1].ts) < 1: + continue + + samples = [frame.line for frame in call] + + filename = "call-%04d.parsed" % call_id + open(filename, "w").writelines(samples) + + is_voice = os.system('check-sample-vod ' + filename) == 0 + + if not is_voice: + os.system('mv ' + filename + ' fail-%d.parsed' % call_id) + call_id += 1 + diff --git a/vod-stitcher.py b/vod-stitcher.py new file mode 100755 index 0000000..a53bc0f --- /dev/null +++ b/vod-stitcher.py @@ -0,0 +1,140 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# vim: set ts=4 sw=4 tw=0 et pm=: +import fileinput +import sys + +""" +VOC: i-1443338945.6543-t1 033399141 1625872817 81% 0.027 179 L:no LCW(0,001111,100000000000000000000 E1) 01111001000100010010010011011011011001111 011000010000100001110101111011110010010111011001010001011101010001100000000110010100000110111110010101110101001111010100111001000110100110001110110 1010101010010010001000001110011000001001001010011110011100110100111110001101110010110101010110011101011100011101011000000000 descr_extra: + +""" + +def chunks(l, n): + """ Yield successive n-sized chunks from l. + """ + for i in xrange(0, len(l), n): + yield l[i:i+n] + +from itertools import izip +def grouped(iterable, n): + "s -> (s0,s1,s2,...sn-1), (sn,sn+1,sn+2,...s2n-1), ..." + return izip(*[iter(iterable)]*n) + +def turn_symbols(byte): + out = 0 + if byte & 0x01: + out |= 0x02 + if byte & 0x02: + out |= 0x01 + if byte & 0x04: + out |= 0x08 + if byte & 0x08: + out |= 0x04 + + if byte & 0x10: + out |= 0x20 + if byte & 0x20: + out |= 0x10 + if byte & 0x40: + out |= 0x80 + if byte & 0x80: + out |= 0x40 + + return out + +infile = sys.argv[1] +outfile = open(sys.argv[2], 'wb') + +data = '' + +a_seq = None +a_data = '' + +b_seq = None +b_data = '' + +c_data=bytearray([0]*10) + +ts_old = 0 + +for line in fileinput.input(infile): + line = line.split() + if line[0] == 'VOD:': + if int(line[6]) < 179: + continue + ts = int(line[2]) + data = line[10] + content=bytearray() + for pos in xrange(1,len(data),3): + byte=int(data[pos:pos+2],16) + byte=int('{:08b}'.format(byte)[::-1], 2) + #byte=int('{:08b}'.format(byte)[::], 2) + content.append(byte) + hdr='{:08b}'.format(content[0]) + hdr=hdr[::-1] + content=content[1:] +# print data + print hdr, + print "".join("%02x"%x for x in content), + + if hdr.startswith("11000") or hdr.startswith("10000") or hdr.startswith("01000"): + print "A1", + #if a_data!='': + # outfile.write(a_data) + # outfile.write(c_data) + a_seq = hdr[5:8] + a_data = content[0:29] + a_ts = ts + + if hdr.startswith("00001"): + print "B1", + b_seq = hdr[5:8] + b_data = content[20:30] + b_ts = ts + + if hdr.startswith("00010"): + print "B2", + b_seq = hdr[5:8] + b_data = content[10:20] + b_ts = ts + + if hdr.startswith("00100"): + print "B3", + b_seq = hdr[5:8] + b_data = content[0:10] + b_ts = ts + + print "> ",a_seq,b_seq, +# print "|", "".join("%x"%x for x in a_data),"[%02d]"%len(a_data), +# print " ", "".join("%x"%x for x in b_data),"[%02d]"%len(b_data) + if a_seq and b_seq and a_seq == b_seq and abs(a_ts - b_ts) < 3*90: + #print "out!" + data = a_data + b_data + + print 'XXX: ','.'.join([c.encode('hex') for c in str(data)]) + #outfile.write(data) + + #if data[0] == 0xc0: + #if not (data[0] == 0x03 and data[1] == 0xc0): + if (data[0] == 0x03 and data[1] == 0xc0): + #print int(a_seq, 2), a_ts - ts_old, '.'.join([c.encode('hex') for c in str(data)]) + print a_ts - ts_old, '.'.join([c.encode('hex') for c in str(data)]) + #outfile.write(data) + + content=bytearray() + for c in str(data): + byte=int('{:08b}'.format(ord(c))[::], 2) + #byte=turn_symbols(int('{:08b}'.format(ord(c))[::], 2)) + content.append(byte) + + outfile.write(str(content)) + + ts_old = a_ts + a_data='' + b_data='' + a_seq = None + b_seq = None + + + print "" +