mirror of
https://github.com/jketterl/openwebrx.git
synced 2026-02-27 10:04:20 +01:00
Merge c11ff91f3d into 640c5b0b3e
This commit is contained in:
commit
bb9554c90e
33
Dockerfile.hotfix
Normal file
33
Dockerfile.hotfix
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
# Stage 1: Build dablin from source
|
||||
FROM debian:bookworm-slim AS builder
|
||||
|
||||
RUN apt-get update && apt-get install -y \
|
||||
git cmake make g++ \
|
||||
pkg-config libncurses-dev libsdl2-dev \
|
||||
libfaad-dev libmpg123-dev libfftw3-dev \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
RUN git clone https://github.com/Opendigitalradio/dablin.git /src/dablin
|
||||
WORKDIR /src/dablin
|
||||
RUN mkdir build && cd build && cmake .. && make
|
||||
|
||||
# Stage 2: Final image (based on openwebrx base to ensure compatibility or full?)
|
||||
# Using jketterl/openwebrx:latest as base
|
||||
FROM jketterl/openwebrx:latest
|
||||
|
||||
# Install sox and runtime deps for dablin
|
||||
# libfaad2 is required. libmpg123-0 is likely required for new dablin.
|
||||
RUN apt-get update && apt-get install -y sox ffmpeg mbuffer libfaad2 libmpg123-0 libsdl2-2.0-0 && rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Copy new dablin binary
|
||||
COPY --from=builder /src/dablin/build/src/dablin /usr/local/bin/dablin
|
||||
|
||||
# Patch files (PR #419: DAB+ sample rate fix via ffmpeg resampling)
|
||||
COPY owrx/dab/dablin.py /opt/openwebrx/owrx/dab/dablin.py
|
||||
COPY csdr/chain/dablin.py /opt/openwebrx/csdr/chain/dablin.py
|
||||
|
||||
# Frontend: defensive JS so /compiled/receiver.js works when DOM elements are missing (e.g. template/load order)
|
||||
COPY htdocs/openwebrx.js /opt/openwebrx/htdocs/openwebrx.js
|
||||
|
||||
# Bytecode compile
|
||||
RUN python3 -m py_compile /opt/openwebrx/owrx/dab/dablin.py /opt/openwebrx/csdr/chain/dablin.py
|
||||
30
README-FORK.md
Normal file
30
README-FORK.md
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
# dom-robinson/openwebrx fork – DAB+ sample rate fix
|
||||
|
||||
This is a clone of [dom-robinson/openwebrx](https://github.com/dom-robinson/openwebrx) with branch **feature/dab-audio-fix** containing improvements over upstream [jketterl/openwebrx PR #419](https://github.com/jketterl/openwebrx/pull/419): **Fix DAB+ audio sample rate issues using ffmpeg resampling**.
|
||||
|
||||
## What’s in this branch
|
||||
|
||||
- **owrx/dab/dablin.py** – DAB+ audio fix with **automatic handling of all sample rates (24/32/48 kHz)** and mono/stereo:
|
||||
- **Default (WAV path):** `dablin -w` so ffmpeg reads sample rate and channel count from the WAV header; resample to 48 kHz stereo. All DAB+ services play at correct speed without configuration.
|
||||
- **Fallback (PCM path):** Set `OPENWEBRX_DAB_USE_WAV=0` and optionally `OPENWEBRX_DAB_INPUT_RATE=24000|32000|48000` if WAV causes issues. Optional `OPENWEBRX_DAB_CAPTURE_RAW=1` tees raw PCM to `/tmp/dablin_capture.raw` for analysis.
|
||||
- **Critical fix:** Treat dablin output as **stereo** (`-ac 2`) when using PCM; using mono caused consistently slow playback.
|
||||
- **docker/scripts/install-dependencies.sh** – Add `sox` to static packages.
|
||||
- **Dockerfile.hotfix** – Optional image that builds dablin from source and applies the dablin.py patch.
|
||||
|
||||
## Environment variables (optional)
|
||||
|
||||
| Variable | Default | Description |
|
||||
|----------|---------|-------------|
|
||||
| `OPENWEBRX_DAB_USE_WAV` | `1` | Use dablin WAV output so rate/channels are automatic. Set `0` to use PCM path with fixed rate. |
|
||||
| `OPENWEBRX_DAB_INPUT_RATE` | `32000` | Only when `OPENWEBRX_DAB_USE_WAV=0`: input rate 24000, 32000, or 48000. |
|
||||
| `OPENWEBRX_DAB_CAPTURE_RAW` | unset | Set to `1` to tee raw PCM to `/tmp/dablin_capture.raw` (PCM path only, for analysis). |
|
||||
|
||||
## Push this branch to the fork
|
||||
|
||||
From this directory, with GitHub auth set up:
|
||||
|
||||
```bash
|
||||
git push -u origin feature/dab-audio-fix
|
||||
```
|
||||
|
||||
After pushing, the fork on GitHub will list the branch and you can open or update a PR to jketterl/openwebrx, or build images from it.
|
||||
|
|
@ -21,7 +21,7 @@ function cmakebuild() {
|
|||
|
||||
cd /tmp
|
||||
|
||||
STATIC_PACKAGES="libfftw3-single3 libfftw3-double3 python3 python3-setuptools python3-paho-mqtt netcat-openbsd libsndfile1 liblapack3 libusb-1.0-0 libqt5core5a libreadline8 libgfortran5 libgomp1 libasound2 libudev1 ca-certificates libpulse0 libfaad2 libopus0 libboost-program-options1.74.0 libboost-log1.74.0 libcurl4 libncurses6 libliquid1 libconfig++9v5"
|
||||
STATIC_PACKAGES="libfftw3-single3 libfftw3-double3 python3 python3-setuptools python3-paho-mqtt netcat-openbsd libsndfile1 liblapack3 libusb-1.0-0 libqt5core5a libreadline8 libgfortran5 libgomp1 libasound2 libudev1 ca-certificates libpulse0 libfaad2 libopus0 libboost-program-options1.74.0 libboost-log1.74.0 libcurl4 libncurses6 libliquid1 libconfig++9v5 sox"
|
||||
BUILD_PACKAGES="wget git libsndfile1-dev libfftw3-dev cmake make gcc g++ liblapack-dev texinfo gfortran libusb-1.0-0-dev qtbase5-dev qtmultimedia5-dev qttools5-dev libqt5serialport5-dev qttools5-dev-tools asciidoctor asciidoc libasound2-dev libudev-dev libhamlib-dev patch xsltproc qt5-qmake libfaad-dev libopus-dev libboost-dev libboost-program-options-dev libboost-log-dev libboost-regex-dev libpulse-dev libcurl4-openssl-dev libncurses-dev xz-utils libliquid-dev libconfig++-dev autoconf automake"
|
||||
apt-get update
|
||||
apt-get -y install auto-apt-proxy
|
||||
|
|
|
|||
|
|
@ -242,13 +242,15 @@ var scale_canvas;
|
|||
|
||||
function scale_setup() {
|
||||
scale_canvas = $("#openwebrx-scale-canvas")[0];
|
||||
if (!scale_canvas) return;
|
||||
scale_ctx = scale_canvas.getContext("2d");
|
||||
if (!scale_ctx) return;
|
||||
scale_canvas.addEventListener("mousedown", scale_canvas_mousedown, false);
|
||||
scale_canvas.addEventListener("mousemove", scale_canvas_mousemove, false);
|
||||
scale_canvas.addEventListener("mouseup", scale_canvas_mouseup, false);
|
||||
resize_scale();
|
||||
var frequency_container = $("#openwebrx-frequency-container");
|
||||
frequency_container.on("mousemove", frequency_container_mousemove, false);
|
||||
if (frequency_container.length) frequency_container.on("mousemove", frequency_container_mousemove, false);
|
||||
}
|
||||
|
||||
var scale_canvas_drag_params = {
|
||||
|
|
@ -704,7 +706,7 @@ var COMPRESS_FFT_PAD_N = 10; //should be the same as in csdr.c
|
|||
function on_ws_recv(evt) {
|
||||
if (typeof evt.data === 'string') {
|
||||
// text messages
|
||||
networkSpeedMeasurement.add(evt.data.length);
|
||||
if (networkSpeedMeasurement) networkSpeedMeasurement.add(evt.data.length);
|
||||
|
||||
if (evt.data.substr(0, 16) === "CLIENT DE SERVER") {
|
||||
params = Object.fromEntries(
|
||||
|
|
@ -901,7 +903,7 @@ function on_ws_recv(evt) {
|
|||
}
|
||||
} else if (evt.data instanceof ArrayBuffer) {
|
||||
// binary messages
|
||||
networkSpeedMeasurement.add(evt.data.byteLength);
|
||||
if (networkSpeedMeasurement) networkSpeedMeasurement.add(evt.data.byteLength);
|
||||
|
||||
var type = new Uint8Array(evt.data, 0, 1)[0];
|
||||
var data = evt.data.slice(1);
|
||||
|
|
@ -999,10 +1001,14 @@ function divlog(what, is_error) {
|
|||
what = "<span class=\"webrx-error\">" + what + "</span>";
|
||||
toggle_panel("openwebrx-panel-log", true); //show panel if any error is present
|
||||
}
|
||||
$('#openwebrx-debugdiv')[0].innerHTML += what + "<br />";
|
||||
var logEl = $('#openwebrx-debugdiv')[0];
|
||||
if (logEl) logEl.innerHTML += what + "<br />";
|
||||
else if (typeof console !== "undefined") console.log("[OpenWebRX] " + (is_error ? "Error: " : "") + what);
|
||||
var nano = $('.nano');
|
||||
nano.nanoScroller();
|
||||
nano.nanoScroller({scroll: 'bottom'});
|
||||
if (nano.length) {
|
||||
nano.nanoScroller();
|
||||
nano.nanoScroller({scroll: 'bottom'});
|
||||
}
|
||||
}
|
||||
|
||||
var volumeBeforeMute = 100.0;
|
||||
|
|
@ -1109,6 +1115,7 @@ var canvas_container;
|
|||
var canvas_actual_line = -1;
|
||||
|
||||
function add_canvas() {
|
||||
if (!canvas_container) return;
|
||||
var new_canvas = document.createElement("canvas");
|
||||
new_canvas.width = fft_size;
|
||||
new_canvas.height = canvas_default_height;
|
||||
|
|
@ -1128,6 +1135,7 @@ function add_canvas() {
|
|||
|
||||
function init_canvas_container() {
|
||||
canvas_container = $("#webrx-canvas-container")[0];
|
||||
if (!canvas_container) return;
|
||||
canvas_container.addEventListener("mouseleave", canvas_container_mouseleave, false);
|
||||
canvas_container.addEventListener("mousemove", canvas_mousemove, false);
|
||||
canvas_container.addEventListener("mouseup", canvas_mouseup, false);
|
||||
|
|
@ -1157,6 +1165,7 @@ function resize_canvases() {
|
|||
|
||||
function waterfall_init() {
|
||||
init_canvas_container();
|
||||
if (!canvas_container) return;
|
||||
resize_canvases();
|
||||
scale_setup();
|
||||
waterfall_setup_done = 1;
|
||||
|
|
@ -1164,6 +1173,9 @@ function waterfall_init() {
|
|||
|
||||
function waterfall_add(data) {
|
||||
if (!waterfall_setup_done) return;
|
||||
// create new canvas if the current one is full (or there isn't one) – must run before canvas_context check
|
||||
if (canvas_actual_line <= 0) add_canvas();
|
||||
if (!canvas_context) return;
|
||||
var w = fft_size;
|
||||
|
||||
if (waterfall_measure_minmax_now) {
|
||||
|
|
@ -1178,9 +1190,6 @@ function waterfall_add(data) {
|
|||
waterfallColorsContinuous(level);
|
||||
}
|
||||
|
||||
// create new canvas if the current one is full (or there isn't one)
|
||||
if (canvas_actual_line <= 0) add_canvas();
|
||||
|
||||
//Add line to waterfall image
|
||||
var oneline_image = canvas_context.createImageData(w, 1);
|
||||
for (var x = 0; x < w; x++) {
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
import os
|
||||
from pycsdr.modules import ExecModule
|
||||
from pycsdr.types import Format
|
||||
|
||||
|
|
@ -12,7 +13,30 @@ class DablinModule(ExecModule):
|
|||
)
|
||||
|
||||
def _buildArgs(self):
|
||||
return ["dablin", "-p", "-s", "{:#06x}".format(self.serviceId)]
|
||||
# Two paths:
|
||||
# 1) WAV (default): dablin -w so ffmpeg reads rate and channels from header → 24/32/48 kHz and mono/stereo all work.
|
||||
# 2) PCM: set OPENWEBRX_DAB_USE_WAV=0 and OPENWEBRX_DAB_INPUT_RATE=24000|32000|48000 if WAV causes issues.
|
||||
# Optional: OPENWEBRX_DAB_CAPTURE_RAW=1 tees raw PCM to /tmp/dablin_capture.raw (PCM path only).
|
||||
use_wav = os.environ.get("OPENWEBRX_DAB_USE_WAV", "1") != "0"
|
||||
if use_wav:
|
||||
dab_cmd = (
|
||||
"dablin -w -s {:#06x} | mbuffer -q -m 4M | "
|
||||
"ffmpeg -v error -probesize 4096 -analyzeduration 0 -f wav -i pipe:0 "
|
||||
"-af aresample=48000 -f f32le -ar 48000 -ac 2 pipe:1"
|
||||
).format(self.serviceId)
|
||||
else:
|
||||
rate = int(os.environ.get("OPENWEBRX_DAB_INPUT_RATE", "32000"))
|
||||
if rate not in (24000, 32000, 48000):
|
||||
rate = 32000
|
||||
dab_cmd = "echo {} > /tmp/dablin_rate.txt 2>/dev/null; dablin -p -s {:#06x}".format(rate, self.serviceId)
|
||||
if os.environ.get("OPENWEBRX_DAB_CAPTURE_RAW"):
|
||||
dab_cmd += " | tee >(dd of=/tmp/dablin_capture.raw bs=1M count=5 2>/dev/null)"
|
||||
dab_cmd += (
|
||||
" | mbuffer -q -m 4M | "
|
||||
"ffmpeg -v error -f s16le -ar {} -ac 2 -i pipe:0 "
|
||||
"-af aresample=48000 -f f32le -ar 48000 -ac 2 pipe:1"
|
||||
).format(rate)
|
||||
return ["bash", "-c", dab_cmd]
|
||||
|
||||
def setDabServiceId(self, serviceId: int) -> None:
|
||||
self.serviceId = serviceId
|
||||
|
|
|
|||
Loading…
Reference in a new issue