Merge branch 'server_rework' into server_rework_dsd

This commit is contained in:
Jakob Ketterl
2019-05-13 17:46:02 +02:00
17 changed files with 1652 additions and 1483 deletions

View File

@ -22,59 +22,44 @@
<html>
<head>
<title>OpenWebRX | Open Source SDR Web App for Everyone!</title>
<script type="text/javascript">
//Global variables
var client_id="%[CLIENT_ID]";
var ws_url="%[WS_URL]";
var rx_photo_height=%[RX_PHOTO_HEIGHT];
var audio_buffering_fill_to=%[AUDIO_BUFSIZE];
var starting_mod="%[START_MOD]";
var starting_offset_frequency = %[START_OFFSET_FREQ];
var waterfall_colors=%[WATERFALL_COLORS];
var waterfall_min_level_default=%[WATERFALL_MIN_LEVEL];
var waterfall_max_level_default=%[WATERFALL_MAX_LEVEL];
var waterfall_auto_level_margin=%[WATERFALL_AUTO_LEVEL_MARGIN];
var server_enable_digimodes=%[DIGIMODES_ENABLE];
var mathbox_waterfall_frequency_resolution=%[MATHBOX_WATERFALL_FRES];
var mathbox_waterfall_history_length=%[MATHBOX_WATERFALL_THIST];
var mathbox_waterfall_colors=%[MATHBOX_WATERFALL_COLORS];
</script>
<script src="sdr.js"></script>
<script src="mathbox-bundle.min.js"></script>
<script src="openwebrx.js"></script>
<script src="jquery-3.2.1.min.js"></script>
<script src="jquery.nanoscroller.js"></script>
<link rel="stylesheet" type="text/css" href="nanoscroller.css" />
<link rel="stylesheet" type="text/css" href="openwebrx.css" />
<script src="static/sdr.js"></script>
<script src="static/mathbox-bundle.min.js"></script>
<script src="static/openwebrx.js"></script>
<script src="static/jquery-3.2.1.min.js"></script>
<script src="static/jquery.nanoscroller.js"></script>
<link rel="stylesheet" type="text/css" href="static/nanoscroller.css" />
<link rel="stylesheet" type="text/css" href="static/openwebrx.css" />
<meta charset="utf-8">
</head>
<body onload="openwebrx_init();">
<div id="webrx-page-container">
<div id="webrx-top-container">
<div id="webrx-top-photo-clip">
<img src="gfx/openwebrx-top-photo.jpg" id="webrx-top-photo"/>
<div id="webrx-rx-photo-title">%[RX_PHOTO_TITLE]</div>
<div id="webrx-rx-photo-desc">%[RX_PHOTO_DESC]</div>
</div>
<div id="webrx-top-bar-background" class="webrx-top-bar-parts"></div>
<div id="webrx-top-bar" class="webrx-top-bar-parts">
<a href="https://sdr.hu/openwebrx" target="_blank"><img src="gfx/openwebrx-top-logo.png" id="webrx-top-logo" /></a>
<a href="http://ha5kfu.sch.bme.hu/" target="_blank"><img src="gfx/openwebrx-ha5kfu-top-logo.png" id="webrx-ha5kfu-top-logo" /></a>
<img id="webrx-rx-avatar-background" src="gfx/openwebrx-avatar-background.png" onclick="toggle_rx_photo();"/>
<img id="webrx-rx-avatar" src="gfx/openwebrx-avatar.png" onclick="toggle_rx_photo();"/>
<div id="webrx-rx-title" onclick="toggle_rx_photo();">%[RX_TITLE]</div>
<div id="webrx-rx-desc" onclick="toggle_rx_photo();">%[RX_LOC] | Loc: %[RX_QRA], ASL: %[RX_ASL] m, <a href="https://www.google.hu/maps/place/%[RX_GPS]" target="_blank" onclick="dont_toggle_rx_photo();">[maps]</a></div>
<div id="openwebrx-rx-details-arrow">
<a id="openwebrx-rx-details-arrow-up" onclick="toggle_rx_photo();"><img src="gfx/openwebrx-rx-details-arrow-up.png" /></a>
<a id="openwebrx-rx-details-arrow-down" onclick="toggle_rx_photo();"><img src="gfx/openwebrx-rx-details-arrow.png" /></a>
<img src="static/gfx/openwebrx-top-photo.jpg" id="webrx-top-photo"/>
<div id="webrx-top-bar" class="webrx-top-bar-parts">
<a href="https://sdr.hu/openwebrx" target="_blank"><img src="static/gfx/openwebrx-top-logo.png" id="webrx-top-logo" /></a>
<a href="http://ha5kfu.sch.bme.hu/" target="_blank"><img src="static/gfx/openwebrx-ha5kfu-top-logo.png" id="webrx-ha5kfu-top-logo" /></a>
<div id="webrx-rx-avatar-background">
<img id="webrx-rx-avatar" src="static/gfx/openwebrx-avatar.png" onclick="toggle_rx_photo();"/>
</div>
<div id="webrx-rx-texts">
<div id="webrx-rx-title" onclick="toggle_rx_photo();"></div>
<div id="webrx-rx-desc" onclick="toggle_rx_photo();"></div>
</div>
<div id="openwebrx-rx-details-arrow">
<a id="openwebrx-rx-details-arrow-up" onclick="toggle_rx_photo();"><img src="static/gfx/openwebrx-rx-details-arrow-up.png" /></a>
<a id="openwebrx-rx-details-arrow-down" onclick="toggle_rx_photo();"><img src="static/gfx/openwebrx-rx-details-arrow.png" /></a>
</div>
<section id="openwebrx-main-buttons">
<ul>
<li onmouseup="toggle_panel('openwebrx-panel-status');"><img src="static/gfx/openwebrx-panel-status.png" /><br/>Status</li>
<li onmouseup="toggle_panel('openwebrx-panel-log');"><img src="static/gfx/openwebrx-panel-log.png" /><br/>Log</li>
<li onmouseup="toggle_panel('openwebrx-panel-receiver');"><img src="static/gfx/openwebrx-panel-receiver.png" /><br/>Receiver</li>
</ul>
</section>
</div>
<section id="openwebrx-main-buttons">
<ul>
<li onmouseup="toggle_panel('openwebrx-panel-status');"><img src="gfx/openwebrx-panel-status.png" /><br/>Status</li>
<li onmouseup="toggle_panel('openwebrx-panel-log');"><img src="gfx/openwebrx-panel-log.png" /><br/>Log</li>
<li onmouseup="toggle_panel('openwebrx-panel-receiver');"><img src="gfx/openwebrx-panel-receiver.png" /><br/>Receiver</li>
</ul>
</section>
<div id="webrx-rx-photo-title"></div>
<div id="webrx-rx-photo-desc"></div>
</div>
</div>
<div id="webrx-main-container">
@ -90,6 +75,10 @@
<div class="openwebrx-panel" id="openwebrx-panel-receiver" data-panel-name="client-params" data-panel-pos="right" data-panel-order="0" data-panel-size="259,115">
<div id="webrx-actual-freq">---.--- MHz</div>
<div id="webrx-mouse-freq">---.--- MHz</div>
<div class="openwebrx-panel-line">
<select id="openwebrx-sdr-profiles-listbox" onchange="sdr_profile_changed();">
</select>
</div>
<div class="openwebrx-panel-line">
<div class="openwebrx-button openwebrx-demodulator-button" id="openwebrx-button-nfm"
onclick="demodulator_analog_replace('nfm');">FM</div>
@ -118,23 +107,23 @@
</select>
</div>
<div class="openwebrx-panel-line">
<div title="Mute on/off" id="openwebrx-mute-off" class="openwebrx-button" onclick="toggleMute();"><img src="gfx/openwebrx-speaker.png" class="openwebrx-sliderbtn-img" id="openwebrx-mute-img"></div>
<div title="Mute on/off" id="openwebrx-mute-off" class="openwebrx-button" onclick="toggleMute();"><img src="static/gfx/openwebrx-speaker.png" class="openwebrx-sliderbtn-img" id="openwebrx-mute-img"></div>
<input title="Volume" id="openwebrx-panel-volume" class="openwebrx-panel-slider" type="range" min="0" max="150" value="50" step="1" onchange="updateVolume()" oninput="updateVolume()">
<div title="Auto-adjust waterfall colors" id="openwebrx-waterfall-colors-auto" class="openwebrx-button" onclick="waterfall_measure_minmax_now=true;"><img src="gfx/openwebrx-waterfall-auto.png" class="openwebrx-sliderbtn-img"></div>
<div title="Auto-adjust waterfall colors" id="openwebrx-waterfall-colors-auto" class="openwebrx-button" onclick="waterfall_measure_minmax_now=true;"><img src="static/gfx/openwebrx-waterfall-auto.png" class="openwebrx-sliderbtn-img"></div>
<input title="Waterfall minimum level" id="openwebrx-waterfall-color-min" class="openwebrx-panel-slider" type="range" min="-200" max="100" value="50" step="1" onchange="updateWaterfallColors(0);" oninput="updateVolume()">
</div>
<div class="openwebrx-panel-line">
<div title="Auto-set squelch level" id="openwebrx-squelch-default" class="openwebrx-button" onclick="setSquelchToAuto()"><img src="gfx/openwebrx-squelch-button.png" class="openwebrx-sliderbtn-img"></div>
<div title="Auto-set squelch level" id="openwebrx-squelch-default" class="openwebrx-button" onclick="setSquelchToAuto()"><img src="static/gfx/openwebrx-squelch-button.png" class="openwebrx-sliderbtn-img"></div>
<input title="Squelch" id="openwebrx-panel-squelch" class="openwebrx-panel-slider" type="range" min="-150" max="0" value="-150" step="1" onchange="updateSquelch()" oninput="updateSquelch()">
<div title="Set waterfall colors to default" id="openwebrx-waterfall-colors-default" class="openwebrx-button" onclick="waterfallColorsDefault()"><img src="gfx/openwebrx-waterfall-default.png" class="openwebrx-sliderbtn-img"></div>
<div title="Set waterfall colors to default" id="openwebrx-waterfall-colors-default" class="openwebrx-button" onclick="waterfallColorsDefault()"><img src="static/gfx/openwebrx-waterfall-default.png" class="openwebrx-sliderbtn-img"></div>
<input title="Waterfall maximum level" id="openwebrx-waterfall-color-max" class="openwebrx-panel-slider" type="range" min="-200" max="100" value="50" step="1" onchange="updateWaterfallColors(1);" oninput="updateVolume()">
</div>
<div class="openwebrx-panel-line">
<div class="openwebrx-button openwebrx-square-button" onclick="zoomInOneStep();" title="Zoom in one step"> <img src="gfx/openwebrx-zoom-in.png" /></div>
<div class="openwebrx-button openwebrx-square-button" onclick="zoomOutOneStep();" title="Zoom out one step"> <img src="gfx/openwebrx-zoom-out.png" /></div>
<div class="openwebrx-button openwebrx-square-button" onclick="zoomInTotal();" title="Zoom in totally"><img src="gfx/openwebrx-zoom-in-total.png" /></div>
<div class="openwebrx-button openwebrx-square-button" onclick="zoomOutTotal();" title="Zoom out totally"><img src="gfx/openwebrx-zoom-out-total.png" /></div>
<div class="openwebrx-button openwebrx-square-button" onclick="mathbox_toggle();" title="Toggle 3D view"><img src="gfx/openwebrx-3d-spectrum.png" /></div>
<div class="openwebrx-button openwebrx-square-button" onclick="zoomInOneStep();" title="Zoom in one step"> <img src="static/gfx/openwebrx-zoom-in.png" /></div>
<div class="openwebrx-button openwebrx-square-button" onclick="zoomOutOneStep();" title="Zoom out one step"> <img src="static/gfx/openwebrx-zoom-out.png" /></div>
<div class="openwebrx-button openwebrx-square-button" onclick="zoomInTotal();" title="Zoom in totally"><img src="static/gfx/openwebrx-zoom-in-total.png" /></div>
<div class="openwebrx-button openwebrx-square-button" onclick="zoomOutTotal();" title="Zoom out totally"><img src="static/gfx/openwebrx-zoom-out-total.png" /></div>
<div class="openwebrx-button openwebrx-square-button" onclick="mathbox_toggle();" title="Toggle 3D view"><img src="static/gfx/openwebrx-3d-spectrum.png" /></div>
<div id="openwebrx-smeter-db">0 dB</div>
</div>
<div class="openwebrx-panel-line">
@ -160,7 +149,7 @@
<div class="openwebrx-progressbar" id="openwebrx-bar-server-cpu"> <span class="openwebrx-progressbar-text">Server CPU [0%]</span><div class="openwebrx-progressbar-bar"></div></div>
<div class="openwebrx-progressbar" id="openwebrx-bar-clients"> <span class="openwebrx-progressbar-text">Clients [1]</span><div class="openwebrx-progressbar-bar"></div></div>
</div>
<div class="openwebrx-panel" data-panel-name="client-under-devel" data-panel-pos="none" data-panel-order="0" data-panel-size="245,55" style="background-color: Red;">
<div class="openwebrx-panel" data-panel-name="client-under-devel" data-panel-pos="left" data-panel-order="0" data-panel-size="245,55" style="background-color: Red;">
<span style="font-size: 15pt; font-weight: bold;">Under construction</span>
<br />We're working on the code right now, so the application might fail.
</div>
@ -182,7 +171,7 @@
</div>
<div id="openwebrx-big-grey" onclick="iosPlayButtonClick();">
<div id="openwebrx-play-button-text">
<img id="openwebrx-play-button" src="gfx/openwebrx-play-button.png" />
<img id="openwebrx-play-button" src="static/gfx/openwebrx-play-button.png" />
<br /><br />Start OpenWebRX
</div>
</div>

View File

@ -155,22 +155,12 @@ input[type=range]:focus::-ms-fill-upper
.webrx-top-bar-parts
{
position: absolute;
top: 0px;
left: 0px;
width:100%;
height:67px;
}
#webrx-top-bar-background
{
background-color: #808080;
opacity: 0.15;
filter:alpha(opacity=15);
}
#webrx-top-bar
{
background: rgba(128, 128, 128, 0.15);
margin:0;
padding:0;
user-select: none;
@ -179,20 +169,23 @@ input[type=range]:focus::-ms-fill-upper
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
overflow: hidden;
position: absolute;
left: 0;
top: 0;
right: 0;
}
#webrx-top-logo
{
position: absolute;
top: 12px;
left: 15px;
padding: 12px;
float: left;
}
#webrx-ha5kfu-top-logo
{
position: absolute;
top: 15px;
right: 15px;
float: right;
padding: 15px;
}
#webrx-top-photo
@ -204,79 +197,37 @@ input[type=range]:focus::-ms-fill-upper
#webrx-rx-avatar-background
{
cursor:pointer;
position: absolute;
left: 285px;
top: 6px;
background-image: url(gfx/openwebrx-avatar-background.png);
background-origin: content-box;
background-repeat: no-repeat;
float: left;
width: 54px;
height: 54px;
padding: 7px;
}
#webrx-rx-avatar
{
cursor:pointer;
position: absolute;
left: 289px;
top: 10px;
width: 46px;
height: 46px;
padding: 4px;
}
#webrx-top-photo-clip
{
min-height: 67px;
max-height: 350px;
overflow: hidden;
position: relative;
}
/*#webrx-bottom-bar
{
position: absolute;
bottom: 0px;
width: 100%;
height: 117px;
background-image:url(gfx/webrx-bottom-bar.png);
}*/
#webrx-page-container
{
min-height:100%;
position:relative;
}
/*#webrx-photo-gradient-left
{
position: absolute;
bottom: 0px;
left: 0px;
background-image:url(gfx/webrx-photo-gradient-corner.png);
width: 59px;
height: 92px;
}
#webrx-photo-gradient-middle
{
position: absolute;
bottom: 0px;
left: 59px;
right: 59px;
height: 92px;
background-image:url(gfx/webrx-photo-gradient-middle.png);
}
#webrx-photo-gradient-right
{
position: absolute;
bottom: 0px;
right: 0px;
background-image:url(gfx/webrx-photo-gradient-corner.png);
width: 59px;
height: 92px;
-webkit-transform:scaleX(-1);
-moz-transform:scaleX(-1);
-ms-transform:scaleX(-1);
-o-transform:scaleX(-1);
transform:scaleX(-1);
}*/
#webrx-rx-photo-title
{
position: absolute;
@ -303,10 +254,17 @@ input[type=range]:focus::-ms-fill-upper
#webrx-rx-photo-desc a
{
/*color: #007df1;*/
color: #5ca8ff;
text-shadow: none;
/*text-shadow: 0px 0px 7px #fff;*/
}
#webrx-rx-texts {
float: left;
padding: 10px;
}
#webrx-rx-texts div {
padding: 3px;
}
#webrx-rx-title
@ -314,9 +272,6 @@ input[type=range]:focus::-ms-fill-upper
white-space:nowrap;
overflow: hidden;
cursor:pointer;
position: absolute;
left: 350px;
top: 13px;
font-family: "DejaVu Sans", Verdana, Geneva, sans-serif;
color: #909090;
font-size: 11pt;
@ -330,15 +285,11 @@ input[type=range]:focus::-ms-fill-upper
cursor:pointer;
font-size: 10pt;
color: #909090;
position: absolute;
left: 350px;
top: 34px;
}
#webrx-rx-desc a
{
color: #909090;
/*text-decoration: none;*/
}
#openwebrx-rx-details-arrow
@ -718,9 +669,7 @@ img.openwebrx-mirror-img
#openwebrx-main-buttons
{
position: absolute;
right: 133px;
top: 3px;
float: right;
margin:0;
color: white;
text-shadow: 0px 0px 4px #000000;
@ -841,10 +790,7 @@ img.openwebrx-mirror-img
transition: width 500ms, left 500ms;
}
#openwebrx-secondary-demod-listbox
{
width: 201px;
height: 27px;
.openwebrx-panel select {
border-radius: 5px;
background-color: #373737;
color: White;
@ -856,16 +802,27 @@ img.openwebrx-mirror-img
border-color: transparent;
border-width: 0px;
-moz-appearance: none;
padding-left:3px;
}
#openwebrx-secondary-demod-listbox option
{
.openwebrx-panel select option {
border-width: 0px;
background-color: #373737;
color: White;
}
#openwebrx-secondary-demod-listbox
{
width: 201px;
height: 27px;
padding-left:3px;
}
#openwebrx-sdr-profiles-listbox {
width: 100%;
font-size: 10pt;
height: 27px;
}
#openwebrx-cursor-blink
{
animation: cursor-blink 1s infinite;

View File

@ -52,6 +52,7 @@ var waterfall_setup_done=0;
var waterfall_queue = [];
var waterfall_timer;
var secondary_fft_size;
var audio_allowed;
/*function fade(something,from,to,time_ms,fps)
{
@ -79,7 +80,9 @@ is_chrome = /Chrome/.test(navigator.userAgent);
function init_rx_photo()
{
e("webrx-top-photo-clip").style.maxHeight=rx_photo_height.toString()+"px";
var clip = e("webrx-top-photo-clip");
rx_photo_height = clip.clientHeight
clip.style.maxHeight=rx_photo_height+"px";
window.setTimeout(function() { animate(e("webrx-rx-photo-title"),"opacity","",1,0,1,500,30); },1000);
window.setTimeout(function() { animate(e("webrx-rx-photo-desc"),"opacity","",1,0,1,500,30); },1500);
window.setTimeout(function() { close_rx_photo() },2500);
@ -133,14 +136,14 @@ function toggleMute()
if (mute) {
mute = false;
e("openwebrx-mute-on").id="openwebrx-mute-off";
e("openwebrx-mute-img").src="gfx/openwebrx-speaker.png";
e("openwebrx-mute-img").src="static/gfx/openwebrx-speaker.png";
e("openwebrx-panel-volume").disabled=false;
e("openwebrx-panel-volume").style.opacity=1.0;
e("openwebrx-panel-volume").value = volumeBeforeMute;
} else {
mute = true;
e("openwebrx-mute-off").id="openwebrx-mute-on";
e("openwebrx-mute-img").src="gfx/openwebrx-speaker-muted.png";
e("openwebrx-mute-img").src="static/gfx/openwebrx-speaker-muted.png";
e("openwebrx-panel-volume").disabled=true;
e("openwebrx-panel-volume").style.opacity=0.5;
volumeBeforeMute = e("openwebrx-panel-volume").value;
@ -160,7 +163,7 @@ function updateSquelch()
{
var sliderValue=parseInt(e("openwebrx-panel-squelch").value);
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)
@ -470,9 +473,13 @@ function demodulator_default_analog(offset_frequency,subtype)
this.doset=function(first_time)
{ //this function sends demodulator parameters to the server
ws.send("SET"+((first_time)?" mod="+this.server_mod:"")+
" low_cut="+this.low_cut.toString()+" high_cut="+this.high_cut.toString()+
" offset_freq="+this.offset_frequency.toString());
params = {
"low_cut": this.low_cut,
"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
@ -1155,169 +1162,140 @@ var COMPRESS_FFT_PAD_N=10; //should be the same as in csdr.c
function on_ws_recv(evt)
{
if(!(evt.data instanceof ArrayBuffer)) { divlog("on_ws_recv(): Not ArrayBuffer received...",1); return; }
//
debug_ws_data_received+=evt.data.byteLength/1000;
first4Chars=getFirstChars(evt.data,4);
first3Chars=first4Chars.slice(0,3);
if(first3Chars=="CLI")
{
var stringData=arrayBufferToString(evt.data);
if(stringData.substring(0,16)=="CLIENT DE SERVER") divlog("Server acknowledged WebSocket connection.");
if (typeof evt.data == 'string') {
// text messages
debug_ws_data_received += evt.data.length / 1000;
}
if(first3Chars=="AUD")
{
var audio_data;
if(audio_compression=="adpcm") audio_data=new Uint8Array(evt.data,4)
else audio_data=new Int16Array(evt.data,4);
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()
}
else if(first3Chars=="FFT")
{
//alert("Yupee! Doing FFT");
//if(first4Chars=="FFTS") console.log("FFTS");
if(fft_compression=="none") waterfall_add_queue(new Float32Array(evt.data,4));
else if(fft_compression="adpcm")
{
fft_codec.reset();
if (evt.data.substr(0, 16) == "CLIENT DE SERVER") {
divlog("Server acknowledged WebSocket connection.");
} else {
try {
json = JSON.parse(evt.data)
switch (json.type) {
case "config":
config = json.value;
window.waterfall_colors = config.waterfall_colors;
window.waterfall_min_level_default = config.waterfall_min_level;
window.waterfall_max_level_default = config.waterfall_max_level;
window.waterfall_auto_level_margin = config.waterfall_auto_level_margin;
waterfallColorsDefault();
window.starting_mod = config.start_mod
window.starting_offset_frequency = config.start_offset_frequency;
window.audio_buffering_fill_to = config.client_audio_buffer_size;
bandwidth = config.samp_rate;
center_freq = config.center_freq + config.lfo_offset;
fft_size = config.fft_size;
fft_fps = config.fft_fps;
audio_compression = config.audio_compression;
divlog( "Audio stream is "+ ((audio_compression=="adpcm")?"compressed":"uncompressed")+"." )
fft_compression = config.fft_compression;
divlog( "FFT stream is "+ ((fft_compression=="adpcm")?"compressed":"uncompressed")+"." )
max_clients_num = config.max_clients;
mathbox_waterfall_colors = config.mathbox_waterfall_colors;
mathbox_waterfall_frequency_resolution = config.mathbox_waterfall_frequency_resolution;
mathbox_waterfall_history_length = config.mathbox_waterfall_history_length;
var waterfall_i16=fft_codec.decode(new Uint8Array(evt.data,4));
var waterfall_f32=new Float32Array(waterfall_i16.length-COMPRESS_FFT_PAD_N);
for(var i=0;i<waterfall_i16.length;i++) waterfall_f32[i]=waterfall_i16[i+COMPRESS_FFT_PAD_N]/100;
if(first4Chars=="FFTS") secondary_demod_waterfall_add_queue(waterfall_f32); //TODO digimodes
else waterfall_add_queue(waterfall_f32);
}
}
else if(first3Chars=="DAT")
{
//secondary_demod_push_binary_data(new Uint8Array(evt.data,4));
secondary_demod_push_data(arrayBufferToString(evt.data).substring(4));
//console.log("DAT");
}
else if(first3Chars=="MSG")
{
/*try
{*/
var stringData=arrayBufferToString(evt.data);
params=stringData.substring(4).split(" ");
for(i=0;i<params.length;i++)
{
param=params[i].split("=");
switch(param[0])
{
case "setup":
waterfall_init();
audio_preinit();
break;
case "bandwidth":
bandwidth=parseInt(param[1]);
break;
case "center_freq":
center_freq=parseInt(param[1]); //there was no ; and it was no problem... why?
break;
case "fft_size":
fft_size=parseInt(param[1]);
break;
case "secondary_fft_size":
secondary_fft_size=parseInt(param[1]);
break;
case "secondary_setup":
if (audio_allowed && !audio_initialized) audio_init();
waterfall_clear();
break;
case "secondary_config":
window.secondary_fft_size = json.value.secondary_fft_size;
window.secondary_bw = json.value.secondary_bw;
window.if_samp_rate = json.value.if_samp_rate;
secondary_demod_init_canvases();
break;
case "if_samp_rate":
if_samp_rate=parseInt(param[1]);
break;
case "secondary_bw":
secondary_bw=parseFloat(param[1]);
break;
case "fft_fps":
fft_fps=parseInt(param[1]);
break;
case "audio_compression":
audio_compression=param[1];
divlog( "Audio stream is "+ ((audio_compression=="adpcm")?"compressed":"uncompressed")+"." )
break;
case "fft_compression":
fft_compression=param[1];
divlog( "FFT stream is "+ ((fft_compression=="adpcm")?"compressed":"uncompressed")+"." )
break;
case "cpu_usage":
var server_cpu_usage=parseInt(param[1]);
progressbar_set(e("openwebrx-bar-server-cpu"),server_cpu_usage/100,"Server CPU ["+param[1]+"%]",server_cpu_usage>85);
break;
case "clients":
var clients_num=parseInt(param[1]);
progressbar_set(e("openwebrx-bar-clients"),clients_num/max_clients_num,"Clients ["+param[1]+"]",clients_num>max_clients_num*0.85);
break;
case "max_clients":
max_clients_num=parseInt(param[1]);
break;
case "s":
smeter_level=parseFloat(param[1]);
setSmeterAbsoluteValue(smeter_level);
break;
}
}
/*}
catch(err)
{
divlog("Received invalid message over WebSocket.");
}*/
} else if (first3Chars=='MET')
{
var stringData=arrayBufferToString(evt.data);
var metaPanels = Array.prototype.filter.call(document.getElementsByClassName('openwebrx-panel'), function(el) {
return el.dataset.panelName == 'metadata';
});
break;
case "receiver_details":
var r = json.value;
e('webrx-rx-title').innerHTML = r.receiver_name;
e('webrx-rx-desc').innerHTML = r.receiver_location + ' | Loc: ' + r.receiver_qra + ', ASL: ' + r.receiver_asl + ' m, <a href="https://www.google.hu/maps/place/' + r.receiver_gps[0] + ',' + r.receiver_gps[1] + '" target="_blank" onclick="dont_toggle_rx_photo();">[maps]</a>';
e('webrx-rx-photo-title').innerHTML = r.photo_title;
e('webrx-rx-photo-desc').innerHTML = r.photo_desc;
break;
case "smeter":
smeter_level = json.value;
setSmeterAbsoluteValue(smeter_level);
break;
case "cpuusage":
var server_cpu_usage = json.value;
progressbar_set(e("openwebrx-bar-server-cpu"),server_cpu_usage/100,"Server CPU [" + server_cpu_usage + "%]",server_cpu_usage>85);
break;
case "clients":
var clients = json.value;
progressbar_set(e("openwebrx-bar-clients"), clients / max_clients_num, "Clients [" + clients + "]", clients > max_clients_num*0.85);
break;
case "profiles":
var listbox = e("openwebrx-sdr-profiles-listbox");
listbox.innerHTML = json.value.map(function(profile){
return '<option value="' + profile.id + '">' + profile.name + "</option>";
}).join("");
break;
default:
console.warn('received message of unknown type: ' + json.type);
}
} catch (e) {
// don't lose exception
console.error(e)
}
}
} else if (evt.data instanceof ArrayBuffer) {
// binary messages
debug_ws_data_received += evt.data.byteLength / 1000;
var meta = {};
stringData.substr(4).split(";").forEach(function(s) {
var item = s.split(":");
meta[item[0]] = item[1];
});
type = new Uint8Array(evt.data, 0, 1)[0]
data = evt.data.slice(1)
var update = function(el) {
el.innerHTML = "";
}
if (meta.protocol) switch (meta.protocol) {
case 'DMR':
if (meta.slot) {
var html = 'Timeslot: ' + meta.slot;
if (meta.type) html += ' Typ: ' + meta.type;
if (meta.source && meta.target) html += ' Source: ' + meta.source + ' Target: ' + meta.target;
update = function(el) {
var slotEl = el.getElementsByClassName('slot-' + meta.slot);
if (!slotEl.length) {
slotEl = document.createElement('div');
slotEl.className = 'slot-' + meta.slot;
el.appendChild(slotEl);
} else {
slotEl = slotEl[0];
}
slotEl.innerHTML = html;
};
switch (type) {
case 1:
// FFT data
if (fft_compression=="none") {
waterfall_add_queue(new Float32Array(data));
} else if (fft_compression == "adpcm") {
fft_codec.reset();
var waterfall_i16=fft_codec.decode(new Uint8Array(data));
var waterfall_f32=new Float32Array(waterfall_i16.length-COMPRESS_FFT_PAD_N);
for(var i=0;i<waterfall_i16.length;i++) waterfall_f32[i]=waterfall_i16[i+COMPRESS_FFT_PAD_N]/100;
waterfall_add_queue(waterfall_f32);
}
break;
case 'YSF':
var strings = [];
if (meta.source) strings.push("Source: " + meta.source);
if (meta.target) strings.push("Destination: " + meta.target);
if (meta.up) strings.push("Up: " + meta.up);
if (meta.down) strings.push("Down: " + meta.down);
var html = strings.join(' ');
update = function(el) {
el.innerHTML = html;
break;
case 2:
// audio data
var audio_data;
if (audio_compression=="adpcm") {
audio_data = new Uint8Array(data);
} else {
audio_data = new Int16Array(data);
}
break;
}
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;
case 3:
// secondary FFT
if (fft_compression == "none") {
secondary_demod_waterfall_add_queue(new Float32Array(data));
} else if (fft_compression == "adpcm") {
fft_codec.reset();
metaPanels.forEach(update);
var waterfall_i16=fft_codec.decode(new Uint8Array(data));
var waterfall_f32=new Float32Array(waterfall_i16.length-COMPRESS_FFT_PAD_N);
for(var i=0;i<waterfall_i16.length;i++) waterfall_f32[i]=waterfall_i16[i+COMPRESS_FFT_PAD_N]/100;
secondary_demod_waterfall_add_queue(waterfall_f32); //TODO digimodes
}
break;
case 4:
// secondary demod
secondary_demod_push_data(arrayBufferToString(data));
break;
default:
console.warn('unknown type of binary message: ' + type)
}
}
}
function add_problem(what)
@ -1630,7 +1608,9 @@ function audio_flush_notused()
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;
@ -1645,7 +1625,7 @@ function parsehash()
if(harr[0]=="mute") toggleMute();
else if(harr[0]=="mod") starting_mod = harr[1];
else if(harr[0]=="sql")
{
{
e("openwebrx-panel-squelch").value=harr[1];
updateSquelch();
}
@ -1680,16 +1660,18 @@ function audio_preinit()
else if(audio_context.sampleRate>44100*4)
audio_buffer_size = 4096 * 4;
audio_rebuffer = new sdrjs.Rebuffer(audio_buffer_size,sdrjs.REBUFFER_FIXED);
audio_last_output_buffer = new Float32Array(audio_buffer_size);
if (!audio_rebuffer) {
audio_rebuffer = new sdrjs.Rebuffer(audio_buffer_size,sdrjs.REBUFFER_FIXED);
audio_last_output_buffer = new Float32Array(audio_buffer_size);
//we send our setup packet
parsehash();
//we send our setup packet
parsehash();
audio_calculate_resampling(audio_context.sampleRate);
audio_resampler = new sdrjs.RationalResamplerFF(audio_client_resampling_factor,1);
ws.send("SET output_rate="+audio_server_output_rate.toString()+" action=start"); //now we'll get AUD packets as well
audio_calculate_resampling(audio_context.sampleRate);
audio_resampler = new sdrjs.RationalResamplerFF(audio_client_resampling_factor,1);
}
ws.send(JSON.stringify({"type":"dspcontrol","action":"start","params":{"output_rate":audio_server_output_rate}}));
}
function audio_init()
@ -1751,7 +1733,10 @@ function on_ws_closed()
audio_node.disconnect();
}
catch (dont_care) {}
divlog("WebSocket has closed unexpectedly. Please reload the page.", 1);
audio_initialized = 0;
divlog("WebSocket has closed unexpectedly. Attempting to reconnect in 5 seconds...", 1);
setTimeout(open_websocket, 5000);
}
function on_ws_error(event)
@ -1763,14 +1748,10 @@ String.prototype.startswith=function(str){ return this.indexOf(str) == 0; }; //h
function open_websocket()
{
//if(ws_url.startswith("ws://localhost:")&&window.location.hostname!="127.0.0.1"&&window.location.hostname!="localhost")
//{
//divlog("Server administrator should set <em>server_hostname</em> correctly, because it is left as <em>\"localhost\"</em>. Now guessing hostname from page URL.",1);
ws_url="ws://"+(window.location.origin.split("://")[1])+"/ws/"; //guess automatically -> now default behaviour
//}
ws_url="ws://"+(window.location.origin.split("://")[1])+"/ws/"; //guess automatically -> now default behaviour
if (!("WebSocket" in window))
divlog("Your browser does not support WebSocket, which is required for WebRX to run. Please upgrade to a HTML5 compatible browser.");
ws = new WebSocket(ws_url+client_id);
ws = new WebSocket(ws_url);
ws.onopen = on_ws_opened;
ws.onmessage = on_ws_recv;
ws.onclose = on_ws_closed;
@ -2023,27 +2004,23 @@ function waterfall_add(data)
waterfall_image.data[base+x*4+i] = ((color>>>0)>>((3-i)*8))&0xff;
}*/
if(mathbox_mode==MATHBOX_MODES.WATERFALL)
{
if (mathbox_mode==MATHBOX_MODES.WATERFALL) {
//Handle mathbox
for(var i=0;i<fft_size;i++) mathbox_data[i+mathbox_data_index*fft_size]=data[i];
mathbox_shift();
}
else
{
//Add line to waterfall image
oneline_image = canvas_context.createImageData(w,1);
for(x=0;x<w;x++)
{
color=waterfall_mkcolor(data[x]);
for(i=0;i<4;i++)
oneline_image.data[x*4+i] = ((color>>>0)>>((3-i)*8))&0xff;
}
} else {
//Add line to waterfall image
oneline_image = canvas_context.createImageData(w,1);
for (x=0;x<w;x++) {
color=waterfall_mkcolor(data[x]);
for(i=0;i<4;i++)
oneline_image.data[x*4+i] = ((color>>>0)>>((3-i)*8))&0xff;
}
//Draw image
canvas_context.putImageData(oneline_image, 0, canvas_actual_line--);
shift_canvases();
if(canvas_actual_line<0) add_canvas();
//Draw image
canvas_context.putImageData(oneline_image, 0, canvas_actual_line--);
shift_canvases();
if(canvas_actual_line<0) add_canvas();
}
@ -2272,7 +2249,7 @@ function openwebrx_init()
//Synchronise volume with slider
updateVolume();
waterfallColorsDefault();
}
function iosPlayButtonClick()
@ -2281,6 +2258,7 @@ function iosPlayButtonClick()
audio_init();
e("openwebrx-big-grey").style.opacity=0;
window.setTimeout(function(){ e("openwebrx-big-grey").style.display="none"; },1100);
audio_allowed = 1;
}
/*
@ -2616,19 +2594,19 @@ function secondary_demod_init()
function secondary_demod_start(subtype)
{
secondary_demod_canvases_initialized = false;
ws.send("SET secondary_mod="+subtype);
secondary_demod = subtype;
ws.send(JSON.stringify({"type":"dspcontrol","params":{"secondary_mod":subtype}}));
secondary_demod = subtype;
}
function secondary_demod_set()
{
ws.send("SET secondary_offset_freq="+secondary_demod_offset_freq.toString());
ws.send(JSON.stringify({"type":"dspcontrol","params":{"secondary_offset_freq":secondary_demod_offset_freq}}));
}
function secondary_demod_stop()
{
ws.send("SET secondary_mod=off");
secondary_demod = false;
ws.send(JSON.stringify({"type":"dspcontrol","params":{"secondary_mod":false}}));
secondary_demod = false;
secondary_demod_waterfall_queue = [];
}
@ -2755,7 +2733,7 @@ function secondary_demod_update_channel_freq_from_event(evt)
{
secondary_demod_waiting_for_set = true;
window.setTimeout(()=>{
ws.send("SET secondary_offset_freq="+Math.floor(secondary_demod_channel_freq));
ws.send(JSON.stringify({"type":"dspcontrol","params":{"secondary_offset_freq":Math.floor(secondary_demod_channel_freq)}}));
//console.log("doneset:", secondary_demod_channel_freq);
secondary_demod_waiting_for_set = false;
}, 50);
@ -2815,3 +2793,8 @@ function secondary_demod_waterfall_set_zoom(low_cut, high_cut)
secondary_demod_canvases.map((x)=>{$(x).css("left",secondary_demod_canvas_left+"px").css("width",secondary_demod_canvas_width+"px");});
secondary_demod_update_channel_freq_from_event();
}
function sdr_profile_changed() {
value = $('#openwebrx-sdr-profiles-listbox').val();
ws.send(JSON.stringify({ type:"selectprofile", params:{ profile:value }}));
}