-
Notifications
You must be signed in to change notification settings - Fork 2
/
ZelloCalls.py
140 lines (118 loc) · 5 KB
/
ZelloCalls.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
import pyaudio
import math
import struct
import wave
import time
import os
import _thread
import subprocess
import datetime
from Crypto.PublicKey import RSA
from Crypto.Signature import pkcs1_15
from Crypto.Hash import SHA256
from threading import Thread
import etc.config as config
from lib.zello_handler import ZelloSend
import base64
import json
import asyncio
Threshold = config.vox_volume_threshold
SHORT_NORMALIZE = (1.0 / 32768.0)
chunk = 1024
FORMAT = pyaudio.paInt16
CHANNELS = 1
RATE = 16000
swidth = 2
TIMEOUT_LENGTH = config.vox_delay
RECORDING_LENGTH_THRESHOLD = config.vox_length_threshold
f_name_directory = config.record_path + "/" + config.channel.replace(" ", "")
loop = asyncio.get_event_loop()
class Recorder:
@staticmethod
def rms(frame):
count = len(frame) / swidth
format = "%dh" % (count)
shorts = struct.unpack(format, frame)
sum_squares = 0.0
for sample in shorts:
n = sample * SHORT_NORMALIZE
sum_squares += n * n
rms = math.pow(sum_squares / count, 0.5)
return rms * 1000
def __init__(self):
self.p = pyaudio.PyAudio()
self.stream = self.p.open(format=FORMAT,
channels=CHANNELS,
rate=RATE,
input=True,
output=True,
frames_per_buffer=chunk)
def record(self):
print('Noise detected, recording beginning')
rec = []
rec_start = time.time()
current = time.time()
end = time.time() + TIMEOUT_LENGTH
while current <= end:
data = self.stream.read(chunk)
if self.rms(data) >= Threshold:
end = time.time() + TIMEOUT_LENGTH
current = time.time()
rec.append(data)
rec_length = time.time() - rec_start
config.token = self.create_token()
rec_thread = Thread(target=self.write, args=(rec_length, b''.join(rec)))
rec_thread.daemon = True
rec_thread.start()
print('Returning to listening')
def write(self, rec_length, recording):
if rec_length > RECORDING_LENGTH_THRESHOLD:
x = datetime.datetime.now()
if not os.path.exists(f_name_directory):
os.mkdir(f_name_directory)
if not os.path.exists(f_name_directory + "/" + str(x.year)):
os.mkdir(f_name_directory + "/" + str(x.year))
if not os.path.exists(f_name_directory + "/" + str(x.year) + "/" + str(x.month)):
os.mkdir(f_name_directory + "/" + str(x.year) + "/" + str(x.month))
if not os.path.exists(f_name_directory + "/" + str(x.year) + "/" + str(x.month) + "/" + str(x.day)):
os.mkdir(f_name_directory + "/" + str(x.year) + "/" + str(x.month) + "/" + str(x.day))
file_path = f_name_directory + "/" + str(x.year) + "/" + str(x.month) + "/" + str(x.day)
file_name = str(x.hour) + str(x.minute) + "_" + str(x.second)
wf = wave.open(file_path + "/" + file_name + ".wav", 'wb')
wf.setnchannels(CHANNELS)
wf.setsampwidth(self.p.get_sample_size(FORMAT))
wf.setframerate(RATE)
wf.writeframes(recording)
wf.close()
print('Written to file: {}'.format(file_path + "/" + file_name))
subprocess.call(
"opusenc " + file_path + "/" + file_name + ".wav" + " " + file_path + "/" + file_name + ".opus",
shell=True, stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT)
if os.path.exists(file_path + "/" + file_name + ".wav"):
os.remove(file_path + "/" + file_name + ".wav")
print("Sending To Zello")
ZelloSend(config, file_path + "/" + file_name + ".opus").zello_init_upload(loop)
else:
print("Recording too short not saving.")
def listen(self):
print('Listening beginning')
while True:
input = self.stream.read(chunk)
rms_val = self.rms(input)
if rms_val > Threshold:
self.record()
def create_token(self):
key = RSA.import_key(config.private_key)
# Create a Zello-specific JWT. Can't use PyJWT because Zello doesn't support url safe base64 encoding in the JWT.
header = {"typ": "JWT", "alg": "RS256"}
payload = {"iss": config.issuer, "exp": round(time.time() + 60)}
signer = pkcs1_15.new(key)
json_header = json.dumps(header, separators=(",", ":"), cls=None).encode("utf-8")
json_payload = json.dumps(payload, separators=(",", ":"), cls=None).encode("utf-8")
h = SHA256.new(base64.standard_b64encode(json_header) + b"." + base64.standard_b64encode(json_payload))
signature = signer.sign(h)
token = (base64.standard_b64encode(json_header) + b"." + base64.standard_b64encode(
json_payload) + b"." + base64.standard_b64encode(signature))
return token
a = Recorder()
a.listen()