From 0713f57bb46b4780c84db3af2921c01a72edfe24 Mon Sep 17 00:00:00 2001 From: ha7ilm Date: Mon, 17 Aug 2015 20:32:58 +0200 Subject: [PATCH] many fixes and new features like IMA ADPCM compression --- README.md | 8 + config_rtl.py | 44 +- config_webrx.py | 91 +- htdocs/gfx/openwebrx-avatar-background.png | Bin htdocs/gfx/openwebrx-avatar.png | Bin htdocs/gfx/openwebrx-background-cool-blue.png | Bin htdocs/gfx/openwebrx-background-lingrad.png | Bin htdocs/gfx/openwebrx-ha5kfu-top-logo.png | Bin htdocs/gfx/openwebrx-logo-big.png | Bin htdocs/gfx/openwebrx-panel-log.png | Bin 0 -> 1225 bytes htdocs/gfx/openwebrx-panel-receiver.png | Bin 0 -> 1851 bytes htdocs/gfx/openwebrx-panel-status.png | Bin 0 -> 1955 bytes htdocs/gfx/openwebrx-rx-details-arrow-up.png | Bin htdocs/gfx/openwebrx-rx-details-arrow.png | Bin htdocs/gfx/openwebrx-scale-background.png | Bin htdocs/gfx/openwebrx-top-logo.png | Bin htdocs/gfx/openwebrx-top-photo.jpg | Bin htdocs/index.wrx | 51 +- htdocs/openwebrx.css | 132 +- htdocs/openwebrx.js | 379 +- htdocs/retry.html | 94 + htdocs/sdr.js | 11683 ++++++++++++++++ htdocs/upgrade.html | 22 +- openwebrx.py | 237 +- plugins/__init__.py | 0 plugins/dsp/__init__.py | 0 plugins/dsp/csdr/__init__.py | 0 plugins/dsp/csdr/plugin.py | 98 +- rtl_mus.py | 54 +- rxws.py | 23 +- screenshot.png | Bin 1305456 -> 1179530 bytes sdrhu.py | 51 + 32 files changed, 12695 insertions(+), 272 deletions(-) mode change 100755 => 100644 config_rtl.py mode change 100755 => 100644 config_webrx.py mode change 100755 => 100644 htdocs/gfx/openwebrx-avatar-background.png mode change 100755 => 100644 htdocs/gfx/openwebrx-avatar.png mode change 100755 => 100644 htdocs/gfx/openwebrx-background-cool-blue.png mode change 100755 => 100644 htdocs/gfx/openwebrx-background-lingrad.png mode change 100755 => 100644 htdocs/gfx/openwebrx-ha5kfu-top-logo.png mode change 100755 => 100644 htdocs/gfx/openwebrx-logo-big.png create mode 100644 htdocs/gfx/openwebrx-panel-log.png create mode 100644 htdocs/gfx/openwebrx-panel-receiver.png create mode 100644 htdocs/gfx/openwebrx-panel-status.png mode change 100755 => 100644 htdocs/gfx/openwebrx-rx-details-arrow-up.png mode change 100755 => 100644 htdocs/gfx/openwebrx-rx-details-arrow.png mode change 100755 => 100644 htdocs/gfx/openwebrx-scale-background.png mode change 100755 => 100644 htdocs/gfx/openwebrx-top-logo.png mode change 100755 => 100644 htdocs/gfx/openwebrx-top-photo.jpg mode change 100755 => 100644 htdocs/index.wrx mode change 100755 => 100644 htdocs/openwebrx.css mode change 100755 => 100644 htdocs/openwebrx.js create mode 100644 htdocs/retry.html create mode 100644 htdocs/sdr.js mode change 100755 => 100644 plugins/__init__.py mode change 100755 => 100644 plugins/dsp/__init__.py mode change 100755 => 100644 plugins/dsp/csdr/__init__.py create mode 100755 sdrhu.py diff --git a/README.md b/README.md index e08d2d5..3a54613 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,14 @@ It has the following features: - it works in Google Chrome, Chromium (above version 37) and Mozilla Firefox (above version 28), - currently only supports RTL-SDR, but other SDR hardware may be easily added. +**News:** +- My BSc. thesis written on OpenWebRX is available here. +- Several bugs were fixed to improve reliability and stability. +- OpenWebRX now supports compression of audio and waterfall stream, so the required network uplink bandwidth has been decreased from 2 Mbit/s to about 200 kbit/s per client! (Measured with the default settings. It is also dependent on `fft_size`.) +- OpenWebRX now uses sdr.js (*libcsdr* compiled to JavaScript) for some client-side DSP tasks. +- Auto-update capability for sdr.hu added (currently only sdr.hu beta testers can use it). +- License for OpenWebRX is now Affero GPL v3. + ## Setup OpenWebRX currently requires Linux and python 2.7 to run. diff --git a/config_rtl.py b/config_rtl.py old mode 100755 new mode 100644 index c759978..d31d951 --- a/config_rtl.py +++ b/config_rtl.py @@ -1,20 +1,30 @@ ''' -This file is part of RTL Multi-User Server, + This file is part of RTL Multi-User Server, that makes multi-user access to your DVB-T dongle used as an SDR. -Copyright (c) 2013-2014 by Andras Retzler + Copyright (c) 2013-2015 by Andras Retzler -RTL Multi-User Server is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as + published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. -RTL Multi-User Server is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. -You should have received a copy of the GNU General Public License -along with RTL Multi-User Server. If not, see . + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + + ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + + In addition, as a special exception, the copyright holders + state that config_rtl.py and config_webrx.py are not part of the + Corresponding Source defined in GNU AGPL version 3 section 1. + + (It means that you do not have to redistribute config_rtl.py and + config_webrx.py if you make any changes to these two configuration files, + and use them for running your own web service with OpenWebRX.) ''' my_ip='127.0.0.1' # leave blank for listening on all interfaces @@ -70,11 +80,11 @@ Example DSP commands: * Decompress FLAC-coded I/Q data: flac --force-raw-format --decode --endian=little --sign=unsigned - - ''' -watchdog_interval=1.5 +watchdog_interval=0 reconnect_interval=10 ''' If there's no input I/Q data after N seconds, input will be filled with zero samples, -so that GNU Radio won't fail in openwebrx. It may reconnect rtl_tcp_tread. +so that GNU Radio won't fail in OpenWebRX. It may reconnect rtl_tcp_thread. If watchdog_interval is 0, then watchdog thread is not started. ''' @@ -85,3 +95,9 @@ cache_full_behaviour=2 2 = openwebrx: don't care about that client until it wants samples again (gr-osmosdr bug workaround) ''' +rtl_tcp_password=None +''' +This one applies to a special version of rtl_tcp that has authentication. +# You can find more info here: https://github.com/ha7ilm/rtl-sdr +# If it is set to a string (e.g. rtl_tcp_password="changeme"), rtl_mus will try to authenticate against the rtl_tcp server. +''' diff --git a/config_webrx.py b/config_webrx.py old mode 100755 new mode 100644 index 230e349..55f1528 --- a/config_webrx.py +++ b/config_webrx.py @@ -3,36 +3,46 @@ """ config_webrx: configuration options for OpenWebRX -OpenWebRX (c) Copyright 2013-2014 Andras Retzler + This file is part of OpenWebRX, + an open-source SDR receiver software with a web UI. + Copyright (c) 2013-2015 by Andras Retzler -This file is part of OpenWebRX. + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as + published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. - OpenWebRX is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - OpenWebRX is distributed in the hope that it will be useful, + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. + GNU Affero General Public License for more details. - You should have received a copy of the GNU General Public License - along with OpenWebRX. If not, see . + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + + In addition, as a special exception, the copyright holders + state that config_rtl.py and config_webrx.py are not part of the + Corresponding Source defined in GNU AGPL version 3 section 1. + + (It means that you do not have to redistribute config_rtl.py and + config_webrx.py if you make any changes to these two configuration files, + and use them for running your web service with OpenWebRX.) """ -#Server settings +# ==== Server settings ==== web_port=8073 server_hostname="localhost" # If this contains an incorrect value, the web UI may freeze on load (it can't open websocket) +max_clients=20 -#Web GUI configuration +# ==== Web GUI configuration ==== receiver_name="[Callsign]" receiver_location="Budapest, Hungary" receiver_qra="JN97ML" -receiver_asl=182 +receiver_asl=200 receiver_ant="Longwire" receiver_device="RTL-SDR" -receiver_admin="localhost@localhost" +receiver_admin="example@example.com" receiver_gps=(47.000000,19.000000) photo_height=350 photo_title="Panorama of Budapest from Schönherz Zoltán Dormitory" @@ -44,16 +54,57 @@ Antenna: %[RX_ANT]
Website: http://localhost """ -#DSP/RX settings +# ==== sdr.hu listing ==== +# (This feature is only available to sdr.hu beta testers by now.) +# If you want your ham receiver to be listed publicly on sdr.hu, then take the following steps: +# 1. Register at: http://sdr.hu/register +# 2. You will get an unique key by email. Copy it and paste here: +sdrhu_key = "" +# 3. Set this setting to True to enable listing: +sdrhu_public_listing = False + +# ==== DSP/RX settings ==== dsp_plugin="csdr" fft_fps=9 fft_size=4096 samp_rate = 250000 + center_freq = 145525000 rf_gain = 5 +ppm = 0 -start_rtl_thread=True #rtl_sdr is more stable than rtl_tcp... -start_rtl_command="rtl_sdr -s {samp_rate} -f {center_freq} - | nc -vvl 127.0.0.1 -p 8888".format(rf_gain=rf_gain, center_freq=center_freq, samp_rate=samp_rate) -#start_rtl_tcp_command="rtl_tcp -s 250000 -f 145525000 -g 0 -p 8888" -#You can use other SDR hardware as well, but if the command above outputs samples in a format other than [unsigned char], then the dsp plugin has to be slightly modified (at the csdr convert_u8_f part). +audio_compression="adpcm" #valid values: "adpcm", "none" +fft_compression="adpcm" #valid values: "adpcm", "none" +start_rtl_thread=True + +# ==== I/Q sources (uncomment the appropriate) ==== + +# >> RTL-SDR via rtl_sdr + +start_rtl_command="rtl_sdr -s {samp_rate} -f {center_freq} -p {ppm} - | nc -vvl 127.0.0.1 8888".format(rf_gain=rf_gain, center_freq=center_freq, samp_rate=samp_rate, ppm=ppm) +format_conversion="csdr convert_u8_f" + +# >> Sound card SDR (needs ALSA) +#I did not have the chance to properly test it. +#samp_rate = 96000 +#start_rtl_command="arecord -f S16_LE -r {samp_rate} -c2 - | nc -vvl 127.0.0.1 8888".format(samp_rate=samp_rate) +#format_conversion="csdr convert_i16_f | csdr gain_ff 30" + +# >> RTL_SDR via rtl_tcp +#start_rtl_command="rtl_tcp -s {samp_rate} -f {center_freq} -g {rf_gain} -P {ppm} -p 8888".format(rf_gain=rf_gain, center_freq=center_freq, samp_rate=samp_rate, ppm=ppm) +#format_conversion="csdr convert_u8_f" + +# >> /dev/urandom test signal source +#samp_rate = 2400000 +#start_rtl_command="cat /dev/urandom | (pv -qL `python -c 'print int({samp_rate} * 2.2)'` 2>&1) | nc -vvl 127.0.0.1 8888".format(rf_gain=rf_gain, center_freq=center_freq, samp_rate=samp_rate) +#format_conversion="csdr convert_u8_f" + +#You can use other SDR hardware as well, by giving your own command that outputs the I/Q samples... + +shown_center_freq = center_freq #you can change this if you use an upconverter + +client_audio_buffer_size = 4 +#increasing client_audio_buffer_size will: +# - also increase the latency +# - decrease the chance of audio underruns diff --git a/htdocs/gfx/openwebrx-avatar-background.png b/htdocs/gfx/openwebrx-avatar-background.png old mode 100755 new mode 100644 diff --git a/htdocs/gfx/openwebrx-avatar.png b/htdocs/gfx/openwebrx-avatar.png old mode 100755 new mode 100644 diff --git a/htdocs/gfx/openwebrx-background-cool-blue.png b/htdocs/gfx/openwebrx-background-cool-blue.png old mode 100755 new mode 100644 diff --git a/htdocs/gfx/openwebrx-background-lingrad.png b/htdocs/gfx/openwebrx-background-lingrad.png old mode 100755 new mode 100644 diff --git a/htdocs/gfx/openwebrx-ha5kfu-top-logo.png b/htdocs/gfx/openwebrx-ha5kfu-top-logo.png old mode 100755 new mode 100644 diff --git a/htdocs/gfx/openwebrx-logo-big.png b/htdocs/gfx/openwebrx-logo-big.png old mode 100755 new mode 100644 diff --git a/htdocs/gfx/openwebrx-panel-log.png b/htdocs/gfx/openwebrx-panel-log.png new file mode 100644 index 0000000000000000000000000000000000000000..58e6fd5f07311a0fc2bd47fa1d8e09a1d291fa88 GIT binary patch literal 1225 zcmV;)1UCDLP)JNBt;a*zptvgXOf;U37g9<<{-oF)aBVY((Y zopjPYlYoL>D7uH~>iW#9S8v{XWQ;)`5fSBju%Ju^fVgU+1C+k@%#^&p^&tg#DOdt! z2XpS*k8}g$+#3KIfFYs|xJ)nyiUHusxCpKrxlqbpUAPOuQc%Jf{F=bvKq&yR1+{Ql z7E43<0L0GD&g&y1Bd;aT-Wa(Rq%J~%l!d3Sqz`vgD)>vJxcvxVFO0q|#M zXRGV$>z^~m`s?-jqgt)@4Py*N;fyh)lp-l5i{qF9VB_QC3;X-~Z;XwNZ2$<-+S;?N zyujH-0>_t^m)~ZL^)tq9l}e@lAPA%oLMQX`LP2XyN-1hKn*sphIEIw+w;%}a;LLZa z11!-wsNLP&hm}g@6(R}%!1KIn5CoDjW{O%&DaE9eWC4{@c58vup%NL^@&Jg{)zxQ4 zM@QcxqLQ89dET_=dH2!sg`y&34Ep-|J~%u){3@~bm64ypIf+wKQ{}n2xn-QiF88@7 z0Ddn@WsHF_hKw;!h{!O;GA%Ar(cK18zPY)%$T@$Ci2MuY^#gbp1w)2XilQiDCnqP? zRWjvTti6>hD=SY|tJQ~56n!s*2pD6x0E9&JCt8-;P3Fc$z>3I%xmKg0p`i+Z@ZjL! zy-KAL4-XGN;GDmhfZtBWgTjjm0nRxQ(N?3;_#qEi8V&%!IX6NGO+;lP8Y~KuCHFAp z0lVl0hKLY`;YYsje<+0L=5MGiDP?XSW4$bNle#id1OVUn?{m(l(A^(*Ta2;K0Q`7u zU_>-PM0a|DN)+UMFc(-DhM)Sr|F~Bl(^}h*bfy0DJ~k+m6){?_aD$G-1>%sKBSYjxkpq9|g`W|J$Wgp*QV3TB~<{UuUL7KS0WIXYvkC!f?> zQyj-EiXtwhWOf}V#Xi>}a7%W5baeC=TBTb#48v0?C5xh{aPg5=x_mRn5a)bQDRqK$ z!Hdqc+5=Dm;5VDiPqfy5*J`yd0m#ep^CHq(QV`uor#HwEws{f2|yc5o~poYU3uM2ln$t5 zs079ijaI9yRqz^POyYnFo&I)RZKun?+*XvaZK$l?MOLHkCg8NacN=$E-5xkVHwo6h nrdyroz}jEjP%}8Ktmg1PkC6%Fq*um?00000NkvXXu0mjf0Cztd literal 0 HcmV?d00001 diff --git a/htdocs/gfx/openwebrx-panel-receiver.png b/htdocs/gfx/openwebrx-panel-receiver.png new file mode 100644 index 0000000000000000000000000000000000000000..5c80c3b640c3f26776f70c3a6c67d9a525fa5c37 GIT binary patch literal 1851 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 literal 0 HcmV?d00001 diff --git a/htdocs/gfx/openwebrx-rx-details-arrow-up.png b/htdocs/gfx/openwebrx-rx-details-arrow-up.png old mode 100755 new mode 100644 diff --git a/htdocs/gfx/openwebrx-rx-details-arrow.png b/htdocs/gfx/openwebrx-rx-details-arrow.png old mode 100755 new mode 100644 diff --git a/htdocs/gfx/openwebrx-scale-background.png b/htdocs/gfx/openwebrx-scale-background.png old mode 100755 new mode 100644 diff --git a/htdocs/gfx/openwebrx-top-logo.png b/htdocs/gfx/openwebrx-top-logo.png old mode 100755 new mode 100644 diff --git a/htdocs/gfx/openwebrx-top-photo.jpg b/htdocs/gfx/openwebrx-top-photo.jpg old mode 100755 new mode 100644 diff --git a/htdocs/index.wrx b/htdocs/index.wrx old mode 100755 new mode 100644 index 7cf73ba..f9b85db --- a/htdocs/index.wrx +++ b/htdocs/index.wrx @@ -1,31 +1,35 @@ - OpenWebRX | Open Source Web-based SDR for everyone! + OpenWebRX | Open Source SDR Web App for Everyone! + @@ -50,6 +54,13 @@ This file is part of OpenWebRX. +
+
    +

  • Status
  • +

  • Log
  • +

  • Receiver
  • +
+
@@ -61,7 +72,7 @@ This file is part of OpenWebRX.
-
+
---.--- MHz
---.--- MHz
@@ -71,17 +82,23 @@ This file is part of OpenWebRX.
USB
CW
-
-
-
openwebrx.js (beta) client log
+
+
+
OpenWebRX (beta) client log
Author: HA7ILM. Please send me bug reports and suggestions.
- Client status: -
Your client ID is: %[CLIENT_ID]
+
+
Audio buffer [0 ms]
+
Audio output [0 sps]
+
Audio stream [0 kbps]
+
Network speed [0 kbps]
+
Server CPU [0%]
+
Clients [1]
+
Under construction
We're working on the code right now, so the application might fail. diff --git a/htdocs/openwebrx.css b/htdocs/openwebrx.css old mode 100755 new mode 100644 index 15993fc..b3dc9b4 --- a/htdocs/openwebrx.css +++ b/htdocs/openwebrx.css @@ -1,20 +1,22 @@ /* -OpenWebRX (c) Copyright 2013-2014 Andras Retzler -This file is part of OpenWebRX. + This file is part of OpenWebRX, + an open-source SDR receiver software with a web UI. + Copyright (c) 2013-2015 by Andras Retzler - OpenWebRX is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as + published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. - OpenWebRX is distributed in the hope that it will be useful, + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . - You should have received a copy of the GNU General Public License - along with OpenWebRX. If not, see . */ html, body @@ -52,9 +54,14 @@ html, body { margin:0; padding:0; + user-select: none; + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; } - #webrx-top-logo { position: absolute; @@ -65,7 +72,7 @@ html, body #webrx-ha5kfu-top-logo { position: absolute; - top: 19px; + top: 15px; right: 15px; } @@ -177,8 +184,10 @@ html, body #webrx-rx-photo-desc a { + /*color: #007df1;*/ color: #5ca8ff; text-shadow: none; + /*text-shadow: 0px 0px 7px #fff;*/ } #webrx-rx-title @@ -269,6 +278,8 @@ html, body { position: absolute; border-style: none; + image-rendering: crisp-edges; + image-rendering: -webkit-optimize-contrast; } #openwebrx-phantom-canvas @@ -410,6 +421,12 @@ html, body cursor: pointer; background:-webkit-gradient( linear, left top, left bottom, color-stop(0.0 , #373737), color-stop(1, #4F4F4F) ); background:-moz-linear-gradient( center top, #373737 0%, #4F4F4F 100% ); + user-select: none; + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; } .openwebrx-button:hover @@ -431,3 +448,94 @@ html, body margin-bottom: 5px; font-weight: bold; } + +.openwebrx-progressbar +{ + position: relative; + border-radius: 5px; + background-color: #003850; /*#006235;*/ + display: inline-block; + text-align: center; + font-size: 8pt; + font-weight: bold; + text-shadow: 0px 0px 4px #000000; + cursor: default; + user-select: none; + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; +} + +.openwebrx-progressbar-bar +{ + border-radius: 5px; + height: 100%; + width: 100%; +} + +.openwebrx-progressbar-text +{ + position: absolute; + left:0px; + top:4px; + width: inherit; +} + +#openwebrx-panel-status +{ + margin: 0px; + padding: 0px; + background-color:rgba(0, 0, 0, 0); +} + +#openwebrx-panel-status div.openwebrx-progressbar +{ + width: 200px; + height: 20px; +} + +#openwebrx-main-buttons img +{ +} + +#openwebrx-main-buttons ul +{ + display: table; + margin:0; +} + + +#openwebrx-main-buttons ul li +{ + display: table-cell; + padding-left: 5px; + padding-right: 5px; + cursor:pointer; +} + +#openwebrx-main-buttons li:hover +{ + background-color: rgba(255, 255, 255, 0.3); +} + +#openwebrx-main-buttons li:active +{ + background-color: rgba(255, 255, 255, 0.55); +} + + +#openwebrx-main-buttons +{ + position: absolute; + right: 133px; + top: 3px; + margin:0; + color: white; + text-shadow: 0px 0px 4px #000000; + text-align: center; + font-size: 9pt; + font-weight: bold; +} + diff --git a/htdocs/openwebrx.js b/htdocs/openwebrx.js old mode 100755 new mode 100644 index 3947f5d..1deeaf7 --- a/htdocs/openwebrx.js +++ b/htdocs/openwebrx.js @@ -1,21 +1,23 @@ /* -OpenWebRX (c) Copyright 2013-2014 Andras Retzler + This file is part of OpenWebRX, + an open-source SDR receiver software with a web UI. + Copyright (c) 2013-2015 by Andras Retzler -This file is part of OpenWebRX. + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as + published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. - OpenWebRX is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - OpenWebRX is distributed in the hope that it will be useful, + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. + GNU Affero General Public License for more details. - You should have received a copy of the GNU General Public License - along with OpenWebRX. If not, see . + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + +""" */ @@ -43,6 +45,9 @@ var audio_buffer_current_count_debug=0; var audio_buffer_current_size=0; var fft_size; var fft_fps; +var fft_compression="none"; +var fft_codec=new sdrjs.ImaAdpcm(); +var audio_compression="none"; var waterfall_setup_done=0; var waterfall_queue = []; var waterfall_timer; @@ -270,7 +275,7 @@ demodulator.draggable_ranges={none: 0, beginning:1 /*from*/, ending: 2 /*to*/, a // This can be used as a base for basic audio demodulators. // It already supports most basic modulations used for ham radio and commercial services: AM/FM/LSB/USB -demodulator_response_time=100; +demodulator_response_time=50; //in ms; if we don't limit the number of SETs sent to the server, audio will underrun (possibly output buffer is cleared on SETs in GNU Radio function demodulator_default_analog(offset_frequency,subtype) @@ -703,27 +708,21 @@ function mkscale() var text_measured=scale_ctx.measureText(text_to_draw); scale_ctx.textAlign = "center"; //advanced text drawing begins - if(zoom_level==0&&range.start+spacing.smallbw*spacing.ratio>marker_hz) - { //if this is the first overall marker when zoomed out - if(x=scale_min_space_bw_texts) - { //and if we have enough space to draw it correctly without clipping - scale_ctx.textAlign = "left"; - scale_ctx.fillText(text_to_draw, 0, text_h_pos); - } + if( zoom_level==0 && (range.start+spacing.smallbw*spacing.ratio>marker_hz) && (x=scale_min_space_bw_texts) + { //and if we have enough space to draw it correctly without clipping + scale_ctx.textAlign = "left"; + scale_ctx.fillText(text_to_draw, 0, text_h_pos); } } - else if(zoom_level==0&&range.end-spacing.smallbw*spacing.ratiowindow.innerWidth-text_measured.width/2) - { //and if it would be clipped off the screen - if(window.innerWidth-text_measured.width-scale_px_from_freq(marker_hz-spacing.smallbw*spacing.ratio,range)>=scale_min_space_bw_texts) - { //and if we have enough space to draw it correctly without clipping - scale_ctx.textAlign = "right"; - scale_ctx.fillText(text_to_draw, window.innerWidth, text_h_pos); - } - } + else if( zoom_level==0 && (range.end-spacing.smallbw*spacing.ratiowindow.innerWidth-text_measured.width/2) ) + { // if this is the last overall marker when zoomed out... and if it would be clipped off the screen... + if(window.innerWidth-text_measured.width-scale_px_from_freq(marker_hz-spacing.smallbw*spacing.ratio,range)>=scale_min_space_bw_texts) + { //and if we have enough space to draw it correctly without clipping + scale_ctx.textAlign = "right"; + scale_ctx.fillText(text_to_draw, window.innerWidth, text_h_pos); + } } else scale_ctx.fillText(text_to_draw, x, text_h_pos); //draw text normally } @@ -960,11 +959,16 @@ function resize_waterfall_container(check_init) canvas_container.style.height=(window.innerHeight-e("webrx-top-container").clientHeight-e("openwebrx-scale-container").clientHeight).toString()+"px"; } +debug_ws_data_received=0; +max_clients_num=0; + +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; firstChars=getFirstChars(evt.data,3); if(firstChars=="CLI") { @@ -973,7 +977,9 @@ function on_ws_recv(evt) } if(firstChars=="AUD") { - var audio_data=new Int16Array(evt.data,4); + 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; @@ -982,8 +988,15 @@ function on_ws_recv(evt) else if(firstChars=="FFT") { //alert("Yupee! Doing FFT"); - var floatArray = new Float32Array(evt.data,4); - waterfall_add_queue(floatArray); + if(fft_compression=="none") waterfall_add_queue(new Float32Array(evt.data,4)); + else if(fft_compression="adpcm") + { + fft_codec.reset(); + 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;i85); + 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; - } } /*} @@ -1032,17 +1063,33 @@ function add_problem(what) window.setTimeout(function(ps,ns) { ps.removeChild(ns); }, 1000,problems_span,new_span); } +waterfall_measure_minmax=false; +waterfall_measure_minmax_min=1e100; +waterfall_measure_minmax_max=-1e100; + +function waterfall_measure_minmax_do(what) +{ + waterfall_measure_minmax_min=Math.min(waterfall_measure_minmax_min,Math.min.apply(Math,what)); + waterfall_measure_minmax_max=Math.max(waterfall_measure_minmax_max,Math.max.apply(Math,what)); +} + +function waterfall_measure_minmax_print() +{ + console.log("Waterfall | min = "+waterfall_measure_minmax_min.toString()+" dB | max = "+waterfall_measure_minmax_max.toString()+" dB"); +} + function waterfall_add_queue(what) { + if(waterfall_measure_minmax) waterfall_measure_minmax_do(what); waterfall_queue.push(what); } function waterfall_dequeue() { if(waterfall_queue.length) waterfall_add(waterfall_queue.shift()); - if(waterfall_queue.length>Math.max(fft_fps/2,8)) //in case of emergency + if(waterfall_queue.length>Math.max(fft_fps/2,20)) //in case of emergency { - console.log(waterfall_queue.length); + console.log("waterfall queue length:", waterfall_queue.length); add_problem("fft overflow"); while(waterfall_queue.length) waterfall_add(waterfall_queue.shift()); } @@ -1054,10 +1101,20 @@ function on_ws_opened() divlog("WebSocket opened to "+ws_url); } +var was_error=0; + function divlog(what, is_error) { - if(typeof is_error !== undefined && is_error == 1) what=""+what+""; + is_error=!!is_error; + was_error |= is_error; + if(is_error) + { + what=""+what+""; + if(e("openwebrx-panel-log").openwebrxHidden) toggle_panel("openwebrx-panel-log"); //show panel if any error is present + } e("openwebrx-debugdiv").innerHTML+=what+"
"; + var wls=e("openwebrx-log-scroll"); + wls.scrollTop=wls.scrollHeight; //scroll to bottom } var audio_context; @@ -1065,54 +1122,105 @@ var audio_initialized=0; var audio_received = Array(); var audio_buffer_index = 0; -var audio_resampler; +var audio_resampler=new sdrjs.RationalResamplerFF(4,1); +var audio_codec=new sdrjs.ImaAdpcm(); +var audio_compression="unknown"; var audio_node; //var audio_received_sample_rate = 48000; var audio_input_buffer_size; // Optimalise these if audio lags or is choppy: -var audio_buffer_size = 8192;//2048 was choppy -var audio_buffer_maximal_length_sec=1.7; //actual number of samples are calculated from sample rate -var audio_flush_interval_ms=250; //the interval in which audio_flush() is called +var audio_buffer_size = 4096;//2048 was choppy +var audio_buffer_maximal_length_sec=3; //actual number of samples are calculated from sample rate +var audio_buffer_decrease_to_on_overrun_sec=2.2; +var audio_flush_interval_ms=500; //the interval in which audio_flush() is called var audio_prepared_buffers = Array(); +var audio_rebuffer = new sdrjs.Rebuffer(audio_buffer_size,sdrjs.REBUFFER_FIXED); var audio_last_output_buffer = new Float32Array(audio_buffer_size); var audio_last_output_offset = 0; var audio_buffering = false; -var audio_buffering_fill_to=10; //on audio underrun we wait until this n*audio_buffer_size samples are present +//var audio_buffering_fill_to=4; //on audio underrun we wait until this n*audio_buffer_size samples are present + //tnx to the hint from HA3FLT, now we have about half the response time! (original value: 10) + +function gain_ff(gain_value,data) //great! solved clicking! will have to move to sdr.js +{ + for(var i=0;iaudio_buffering_fill_to) audio_buffering=false; +} + + +function audio_prepare_without_resampler(data) +{ + audio_rebuffer.push(sdrjs.ConvertI16_F(data)); + console.log("prepare",data.length,audio_rebuffer.remaining()); + while(audio_rebuffer.remaining()) + { + audio_prepared_buffers.push(audio_rebuffer.take()); + audio_buffer_current_count_debug++; + } + if(audio_buffering && audio_prepared_buffers.length>audio_buffering_fill_to) audio_buffering=false; +} + +function audio_prepare_old(data) { //console.log("audio_prepare :: "+data.length.toString()); //console.log("data.len = "+data.length.toString()); var dopush=function() { + console.log(audio_last_output_buffer); audio_prepared_buffers.push(audio_last_output_buffer); audio_last_output_offset=0; audio_last_output_buffer=new Float32Array(audio_buffer_size); audio_buffer_current_count_debug++; }; + var original_data_length=data.length; + var f32data=new Float32Array(data.length); + for(var i=0;iaudio_buffering_fill_to) audio_buffering=false; } @@ -1127,24 +1235,49 @@ if (!AudioBuffer.prototype.copyToChannel) } function audio_onprocess(e) -{ +{ + //console.log("audio onprocess"); if(audio_buffering) return; - if(audio_prepared_buffers.length==0) { add_problem("audio underrun"); audio_buffering=true; } - else e.outputBuffer.copyToChannel(audio_prepared_buffers.shift(),0); + if(audio_prepared_buffers.length==0) { audio_buffer_progressbar_update(); /*add_problem("audio underrun");*/ audio_buffering=true; } + else { e.outputBuffer.copyToChannel(audio_prepared_buffers.shift(),0); } } +var audio_buffer_progressbar_update_disabled=false; + +var audio_buffer_total_average_level=0; +var audio_buffer_total_average_level_length=0; + +function audio_buffer_progressbar_update() +{ + if(audio_buffer_progressbar_update_disabled) return; + var audio_buffer_value=(audio_prepared_buffers.length*audio_buffer_size)/44100; + audio_buffer_total_average_level_length++; audio_buffer_total_average_level=(audio_buffer_total_average_level*((audio_buffer_total_average_level_length-1)/audio_buffer_total_average_level_length))+(audio_buffer_value/audio_buffer_total_average_level_length); + var overrun=audio_buffer_value>audio_buffer_maximal_length_sec; + var underrun=audio_prepared_buffers.length==0; + var text="buffer"; + if(overrun) text="overrun"; + if(underrun) text="underrun"; + if(overrun||underrun) + { + audio_buffer_progressbar_update_disabled=true; + window.setTimeout(function(){audio_buffer_progressbar_update_disabled=false; audio_buffer_progressbar_update();},1000); + } + progressbar_set(e("openwebrx-bar-audio-buffer"),(underrun)?1:audio_buffer_value/1.5,"Audio "+text+" ["+(audio_buffer_value).toFixed(1)+" s]",overrun||underrun||audio_buffer_value<0.25); +} function audio_flush() { flushed=false; - while(audio_buffer_maximal_length_sec*audio_context.sampleRate