get the audio going as well

This commit is contained in:
Jakob Ketterl 2019-05-04 23:11:13 +02:00
parent 6ec21e6716
commit f05afc4b0a
4 changed files with 109 additions and 32 deletions

View File

@ -161,7 +161,7 @@ function updateSquelch()
{ {
var sliderValue=parseInt(e("openwebrx-panel-squelch").value); var sliderValue=parseInt(e("openwebrx-panel-squelch").value);
var outputValue=(sliderValue==parseInt(e("openwebrx-panel-squelch").min))?0:getLinearSmeterValue(sliderValue); var outputValue=(sliderValue==parseInt(e("openwebrx-panel-squelch").min))?0:getLinearSmeterValue(sliderValue);
ws.send("SET squelch_level="+outputValue.toString()); ws.send(JSON.stringify({"type":"dspcontrol","params":{"squelch_level":outputValue}}));
} }
function updateWaterfallColors(which) function updateWaterfallColors(which)
@ -461,9 +461,13 @@ function demodulator_default_analog(offset_frequency,subtype)
this.doset=function(first_time) this.doset=function(first_time)
{ //this function sends demodulator parameters to the server { //this function sends demodulator parameters to the server
ws.send("SET"+((first_time)?" mod="+this.server_mod:"")+ params = {
" low_cut="+this.low_cut.toString()+" high_cut="+this.high_cut.toString()+ "low_cut": this.low_cut,
" offset_freq="+this.offset_frequency.toString()); "high_cut": this.high_cut,
"offset_freq": this.offset_frequency
};
if (first_time) params.mod = this.server_mod;
ws.send(JSON.stringify({"type":"dspcontrol","params":params}));
} }
this.doset(true); //we set parameters on object creation this.doset(true); //we set parameters on object creation
@ -1164,6 +1168,7 @@ function on_ws_recv(evt)
window.starting_mod = config.start_mod window.starting_mod = config.start_mod
window.starting_offset_frequency = config.start_offset_frequency; window.starting_offset_frequency = config.start_offset_frequency;
window.audio_buffering_fill_to = config.client_audio_buffer_size;
bandwidth = config.samp_rate; bandwidth = config.samp_rate;
center_freq = config.shown_center_freq; center_freq = config.shown_center_freq;
fft_size = config.fft_size; fft_size = config.fft_size;
@ -1191,6 +1196,7 @@ function on_ws_recv(evt)
switch (type) { switch (type) {
case 1: case 1:
// FFT data
if (fft_compression=="none") { if (fft_compression=="none") {
waterfall_add_queue(new Float32Array(data)); waterfall_add_queue(new Float32Array(data));
} else if (fft_compression == "adpcm") { } else if (fft_compression == "adpcm") {
@ -1202,6 +1208,19 @@ function on_ws_recv(evt)
waterfall_add_queue(waterfall_f32); waterfall_add_queue(waterfall_f32);
} }
break; break;
case 2:
// audio data
var audio_data;
if (audio_compression=="adpcm") {
audio_data = new Uint8Array(data);
} else {
audio_data = new Int16Array(data);
}
audio_prepare(audio_data);
audio_buffer_current_size_debug += audio_data.length;
audio_buffer_all_size_debug += audio_data.length;
if (!(ios||is_chrome) && (audio_initialized==0 && audio_prepared_buffers.length>audio_buffering_fill_to)) audio_init()
break;
default: default:
console.warn('unknown type of binary message: ' + type) console.warn('unknown type of binary message: ' + type)
} }
@ -1619,7 +1638,9 @@ function audio_flush_notused()
function webrx_set_param(what, value) function webrx_set_param(what, value)
{ {
ws.send("SET "+what+"="+value.toString()); params = {};
params[what] = value;
ws.send(JSON.stringify({"type":"dspcontrol","params":params}));
} }
var starting_mute = false; var starting_mute = false;
@ -1678,7 +1699,7 @@ function audio_preinit()
audio_calculate_resampling(audio_context.sampleRate); audio_calculate_resampling(audio_context.sampleRate);
audio_resampler = new sdrjs.RationalResamplerFF(audio_client_resampling_factor,1); audio_resampler = new sdrjs.RationalResamplerFF(audio_client_resampling_factor,1);
ws.send(JSON.stringify({"type":"start","params":{"output_rate":audio_server_output_rate}})) ws.send(JSON.stringify({"type":"dspcontrol","action":"start","params":{"output_rate":audio_server_output_rate}}));
} }
function audio_init() function audio_init()

View File

@ -1,8 +1,7 @@
import mimetypes import mimetypes
from owrx.websocket import WebSocketConnection from owrx.websocket import WebSocketConnection
from owrx.config import PropertyManager from owrx.config import PropertyManager
from owrx.source import SpectrumThread from owrx.source import SpectrumThread, DspThread
import csdr
import json import json
class Controller(object): class Controller(object):
@ -52,6 +51,8 @@ class SpectrumForwarder(object):
self.conn = conn self.conn = conn
def write_spectrum_data(self, data): def write_spectrum_data(self, data):
self.conn.send(bytes([0x01]) + data) self.conn.send(bytes([0x01]) + data)
def write_dsp_data(self, data):
self.conn.send(bytes([0x02]) + data)
class WebSocketMessageHandler(object): class WebSocketMessageHandler(object):
def __init__(self): def __init__(self):
@ -64,7 +65,7 @@ class WebSocketMessageHandler(object):
for key in ["waterfall_colors", "waterfall_min_level", "waterfall_max_level", "waterfall_auto_level_margin", for key in ["waterfall_colors", "waterfall_min_level", "waterfall_max_level", "waterfall_auto_level_margin",
"shown_center_freq", "samp_rate", "fft_size", "fft_fps", "audio_compression", "fft_compression", "shown_center_freq", "samp_rate", "fft_size", "fft_fps", "audio_compression", "fft_compression",
"max_clients", "start_mod"]: "max_clients", "start_mod", "client_audio_buffer_size"]:
config[key] = pm.getPropertyValue(key) config[key] = pm.getPropertyValue(key)
@ -73,29 +74,30 @@ class WebSocketMessageHandler(object):
conn.send({"type":"config","value":config}) conn.send({"type":"config","value":config})
print("client connection intitialized") print("client connection intitialized")
dsp = self.dsp = csdr.dsp()
dsp_initialized=False
dsp.set_audio_compression(pm.getPropertyValue("audio_compression"))
dsp.set_fft_compression(pm.getPropertyValue("fft_compression")) #used by secondary chains
dsp.set_format_conversion(pm.getPropertyValue("format_conversion"))
dsp.set_offset_freq(0)
dsp.set_bpf(-4000,4000)
dsp.set_secondary_fft_size(pm.getPropertyValue("digimodes_fft_size"))
dsp.nc_port=pm.getPropertyValue("iq_server_port")
dsp.csdr_dynamic_bufsize = pm.getPropertyValue("csdr_dynamic_bufsize")
dsp.csdr_print_bufsizes = pm.getPropertyValue("csdr_print_bufsizes")
dsp.csdr_through = pm.getPropertyValue("csdr_through")
do_secondary_demod=False
self.forwarder = SpectrumForwarder(conn) self.forwarder = SpectrumForwarder(conn)
SpectrumThread.getSharedInstance().add_client(self.forwarder) SpectrumThread.getSharedInstance().add_client(self.forwarder)
self.dsp = DspThread(self.forwarder)
else: else:
try: try:
message = json.loads(message) message = json.loads(message)
if message["type"] == "start": if message["type"] == "dspcontrol":
self.dsp.set_samp_rate(message["params"]["output_rate"]) if "params" in message:
self.dsp.start() params = message["params"]
for key in params:
methodname = "set_" + key
if hasattr(self.dsp, methodname):
method = getattr(self.dsp, methodname)
if callable(method):
method(params[key])
else:
print("method {0} is not callable".format(methodname))
else:
print("dsp has no method {0}".format(methodname))
if "action" in message and message["action"] == "start":
self.dsp.start()
except json.JSONDecodeError: except json.JSONDecodeError:
print("message is not json: {0}".format(message)) print("message is not json: {0}".format(message))
@ -105,6 +107,8 @@ class WebSocketMessageHandler(object):
def handleClose(self, conn): def handleClose(self, conn):
if self.forwarder: if self.forwarder:
SpectrumThread.getSharedInstance().remove_client(self.forwarder) SpectrumThread.getSharedInstance().remove_client(self.forwarder)
if self.dsp:
self.dsp.stop()
class WebSocketController(Controller): class WebSocketController(Controller):
def handle_request(self): def handle_request(self):

View File

@ -98,4 +98,58 @@ class SpectrumThread(threading.Thread):
def shutdown(self): def shutdown(self):
print("shutting down spectrum thread") print("shutting down spectrum thread")
SpectrumThread.sharedInstance = None SpectrumThread.sharedInstance = None
self.doRun = False self.doRun = False
class DspThread(threading.Thread):
def __init__(self, handler):
self.doRun = True
self.handler = handler
pm = PropertyManager.getSharedInstance()
self.dsp = csdr.dsp()
#dsp_initialized=False
self.dsp.set_audio_compression(pm.getPropertyValue("audio_compression"))
self.dsp.set_fft_compression(pm.getPropertyValue("fft_compression")) #used by secondary chains
self.dsp.set_format_conversion(pm.getPropertyValue("format_conversion"))
self.dsp.set_offset_freq(0)
self.dsp.set_bpf(-4000,4000)
self.dsp.set_secondary_fft_size(pm.getPropertyValue("digimodes_fft_size"))
self.dsp.nc_port=pm.getPropertyValue("iq_server_port")
self.dsp.csdr_dynamic_bufsize = pm.getPropertyValue("csdr_dynamic_bufsize")
self.dsp.csdr_print_bufsizes = pm.getPropertyValue("csdr_print_bufsizes")
self.dsp.csdr_through = pm.getPropertyValue("csdr_through")
self.dsp.set_samp_rate(pm.getPropertyValue("samp_rate"))
#do_secondary_demod=False
super().__init__()
def run(self):
self.dsp.start()
while (self.doRun):
data = self.dsp.read(256)
self.handler.write_dsp_data(data)
def stop(self):
self.doRun = False
def set_output_rate(self, samp_rate):
self.dsp.set_output_rate(samp_rate)
def set_low_cut(self, cut):
bpf = self.dsp.get_bpf()
bpf[0] = cut
self.dsp.set_bpf(*bpf)
def set_high_cut(self, cut):
bpf = self.dsp.get_bpf()
bpf[1] = cut
self.dsp.set_bpf(*bpf)
def set_offset_freq(self, freq):
self.dsp.set_offset_freq(freq)
def set_mod(self, mod):
if (self.dsp.get_demodulator() == mod): return
self.dsp.stop()
self.dsp.set_demodulator(mod)
self.dsp.start()

View File

@ -20,7 +20,7 @@ class WebSocketConnection(object):
def get_header(self, size, opcode): def get_header(self, size, opcode):
ws_first_byte = 0b10000000 | (opcode & 0x0F) ws_first_byte = 0b10000000 | (opcode & 0x0F)
if(size>125): if (size > 125):
return bytes([ws_first_byte, 126, (size>>8) & 0xff, size & 0xff]) return bytes([ws_first_byte, 126, (size>>8) & 0xff, size & 0xff])
else: else:
# 256 bytes binary message in a single unmasked frame # 256 bytes binary message in a single unmasked frame
@ -34,14 +34,12 @@ class WebSocketConnection(object):
# string-type messages are sent as text frames # string-type messages are sent as text frames
if (type(data) == str): if (type(data) == str):
header = self.get_header(len(data), 1) header = self.get_header(len(data), 1)
self.handler.wfile.write(header) self.handler.wfile.write(header + data.encode('utf-8'))
self.handler.wfile.write(data.encode('utf-8'))
self.handler.wfile.flush() self.handler.wfile.flush()
# anything else as binary # anything else as binary
else: else:
header = self.get_header(len(data), 2) header = self.get_header(len(data), 2)
self.handler.wfile.write(header) self.handler.wfile.write(header + data)
self.handler.wfile.write(data)
self.handler.wfile.flush() self.handler.wfile.flush()
def read_loop(self): def read_loop(self):