Skip to main content

pysdrweb

Project to create a web interface to RTL-SDR tooling.

FM Radio Receiver

The first focus of the project is to make a simple, web-based FM Radio receiver that can be controlled entirely through a web browser. By visiting the main page, the user can listen in on an (FM) radio station using any compatible RTL-SDR dongle and change the frequency, as desired.

This receiver is backed by some driver, which implements the set of calls necessary to run the radio, i.e. calls to generate a raw PCM data stream that is then encoded on the fly. Usually, this driver is simply the RTL-SDR program: rtl_fm, which the server searches for by default. (Other driver types are planned for the future, but are not yet implemented.)

By default, python supports some (usually uncompressed) formats out of the box:

  • WAV: Raw format used in CDs and other media.

If soundfile is also present (and installed correctly), then this can also encode into more formats:

  • FLAC: Free Lossless Audio Codec, supported by most browsers with some possible compression.
  • OGG: Container format, supported by browsers. This format usually compresses fairly well, especially compared to more raw formats. (The list isn't exhaustive, but the goal is to support more browsers, not as many formats. The code should be easy enough to add more formats, however, if that is ever really needed.)

If lameenc is also present, then this can also encode into still more formats like:

  • MP3: Enough said.

Currently, this server appears to work on Firefox and Chrome. With HLS, Safari should also be supported, though this will require the app to stall for a bit to build up the appropriate HLS buffering.

Goal

The goal of this server is to support multiple formats and multiple clients simultaneously, without straining too many system resources; the hope is that this server is low-key enough to run on weaker hardware (yes, even with python).

Running the Server

Currently, the server requires rtl_fm to be installed and a valid RTL-SDR device to be plugged in.

The simplest way to run the server is:

pysdrweb_server -p 8080 -f 107.3M

This runs the server on port 8080 and listens (initially) on 107.3 FM.

If rtl_fm is not on the path, that can be passed in with:

pysdrweb_server -p 8080 -f 107.3M -m ${RTL_FM_PATH}

For the full set of options, it is easier to configure the server with a configuration file. A sample configuration file is shown below:

#
# Sample 'native' driver configuration file.
# 
---
port: 9000
# Uncomment to require auth to change the frequency.
# auth:
#   type: basic
#   # This indicates whether 'readonly' (GET) requests require auth or not.
#   ignore_on_read: true
#   # Each user is denoted by: <user>: <password>
#   users:
#     admin: admin

# Starting (FM) channel/frequency to listen on startup.
default_frequency: 107.3M
# Driver settings.
driver:
  # Path to rtl_fm, if not on the path of the server.
  rtl_fm: /usr/local/bin/rtl_fm
  # Optional.
  kb_buffer_size: 128

# HLS Streaming Options
#
# Uncomment below to enable HLS with various options. HLS is a protocol
# that handles streams of media by splitting it into 'chunks', and serving
# those chunks as static files. The client will piece these chunks together
# into a continuous stream; the chunks are advertised to the client as an
# "HLS Playlist", a special file (with .m3u8 extension) that points to each
# chunk.
#
# NOTE: HLS is currently needed to support Safari/iOS browsers.
#
# Uncomment to enable HLS:
hls:
  enabled: true
  # Number of chunks (distinct audio files) to store.
  chunk_count: 6
  # The length of each individual chunk.
  seconds_per_chunk: 10
  # The format of the chunk. If unspecified, this will be a sensible default.
  # format: flac

Then, to run the server:

sdrfm_server -c config.yml

This permits adding authentication as well.

Server REST API

Currently, the server supports a REST API that the main page invokes to render. The main calls are described below:

Method Route Description
GET /api/frequency Returns the current frequency the server is listening on.
POST /api/frequency Change the frequency the server is listening on.
GET /api/procinfo Returns any (stderr) logging for the current driver.
GET /api/radio/audio.<ext> Fetch the audio streamed from the radio.

Audio Route (More Detail)

Much of this server relies on /api/radio/audio.<ext> to function since this is the route that actually serves the audio file. This route uses the given <ext> extension to determine the format to stream in. The route also accepts an optional timeout parameter, telling the server how long to listen for (in seconds). If not passed, the server will continue streaming indefinitely.

To download 10 seconds of the audio in WAV format (assuming the server is running locally on port 8080) call:

curl http://localhost:8080/api/radio/audio.wav?timeout=10 > audio.wav

If a format is not supported, the response will indicate as such.

Authentication

By default, the requests are not authenticated. If configured, however, the requests can all require authentication using "HTTP Basic"-style authentication. When making a request, the browser will prompt for the username/password combination.

Other authentication may be added later.

How It Works

For simplicity, the RTL-SDR tooling includes rtl_fm, which streams FM audio data as raw, mono, 16-bit (2 byte) PCM data at some configurable frequency. For example, the following shell pipeline streams the frequency 107.3M to an MP3 file:

# Listen on 107.3 FM, sampling at 48kHz
rtl_fm -f 107.3M -M fm -s 48000 | \
sox -traw -r48000 -es -b16 -c1 -V1 - -tmp3 - > output.mp3

The sox command is used to convert raw PCM data into framed MP3 data. (It is possible to use ffmpeg in a similar vain as well). The quality is quite bad; we need to sample more quickly then resample down to a lower frequency:

# Sample at 200k, then resample down to 48k.
# Passing '-A fast' denotes the way to perform the resample.
rtl_fm -f 107.3M -M fm -s 200k -r 48k -A fast | \
sox -traw -r48k -es -b16 -c1 -V1 - -tmp3 - > output.mp3

This command can be run remotely and played (once) in the browser using:

# Like above, but pipes the output to port 8080.
rtl_fm -f 107.3M -M fm -s 200k -r 48k -A fast | \
sox -traw -r48k -es -b16 -c1 -V1 - -tmp3 - | \
socat -u - TCP-LISTEN:8080

This pipeline is cool, but has some obvious problems. In particular, the pipeline ends as soon as the browser stops listening for any more input. Also, only one browser/client can listen at a time. (Also, some browsers might not support this for some formats...) Once finished, the command must be executed again. Changing the frequency also requires rerunning or otherwise changing the command.

To address these issues, pysdrweb will buffer the PCM output from whatever source (currently rtl_fm) and encode it on the fly, which permits multiple clients and formats. This also permits changing the frequency more easily.

Future

A few low-hanging fruit features to consider adding:

  • Scan for available channels.
  • More sophisticated UI (Theming and Features)

Metadata

Release files for pysdrweb 0.4.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for pysdrweb 0.4.1
File Size Uploaded Provenance Actions
pysdrweb-0.4.1.tar.gz 28.3 kB Without provenance Details for pysdrweb-0.4.1.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for pysdrweb 0.4.1
File Interpreter ABI Platform Actions
pysdrweb-0.4.1-py3-none-any.whl Python 3 none any Details for pysdrweb-0.4.1-py3-none-any.whl

Total release size: 62.4 kB

Release files / pysdrweb-0.4.1.tar.gz

Download URL pysdrweb-0.4.1.tar.gz
Size 28.3 kB
Tags Source
SHA-256 checksum
How to use checksums
3f13ef70ff82db684f51e4e73cf4048df3c977c747e433b35bf18aa9406ab13f
BLAKE2b-256 checksum
How to use checksums
9e48a8ce88d14d4dff71872a3db8082988dce533d7cd6599172d106681c9f137
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via poetry/1.8.2 CPython/3.12.2 Darwin/23.5.0

Release files / pysdrweb-0.4.1-py3-none-any.whl

Download URL pysdrweb-0.4.1-py3-none-any.whl
Size 34.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
91efd6b986a57ff7119af6eb136deb6fad9eff2e5754d6a0612db8ba01f9aab1
BLAKE2b-256 checksum
How to use checksums
98ec0c91184d1b88db98a54b9580f71ce677d5080ead2eb29f97b5ae9ed69c24
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via poetry/1.8.2 CPython/3.12.2 Darwin/23.5.0

Security for pysdrweb 0.4.1

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page