Go to file
2023-06-15 16:37:08 +09:30
data Added some sample audio tracks to always be available 2023-06-13 20:09:10 +09:30
docs last attempt 2023-05-23 10:27:17 +09:30
examples Adding LICENSE for SoapySDR example code 2023-05-11 13:21:52 +09:30
scripts Merge pull request #1 from 9130_dummy_audio into main 2023-06-15 12:49:11 +09:30
.gitignore Project cleanup 2023-05-10 17:03:49 +09:30
fileradio.py Ran everything through the 'black' formatter 2023-06-15 15:16:24 +09:30
filters.py Ran everything through the 'black' formatter 2023-06-15 15:16:24 +09:30
fm_demod.py Ran everything through the 'black' formatter 2023-06-15 15:16:24 +09:30
formats.py Ran everything through the 'black' formatter 2023-06-15 15:16:24 +09:30
mediamtx.yml Added RTSP streams report to API 2023-06-13 18:52:51 +09:30
microservice.py add todos and initial route changes 2023-06-15 16:37:08 +09:30
radio.py Ran everything through the 'black' formatter 2023-06-15 15:16:24 +09:30
README.md Updated setup script to be cleaner 2023-05-26 10:50:44 +09:30
requirements.apt Fix incorrect directory locations after build. Add timer to setup script 2023-05-26 11:03:01 +09:30
requirements.pip Updated pip package requirements 2023-06-14 11:52:30 +09:30
samplerates.py Ran everything through the 'black' formatter 2023-06-15 15:16:24 +09:30
sdrplay_sample Unified byte format mappings 2023-05-15 12:52:05 +09:30
setup.sh Updated setup script 2023-06-13 17:20:58 +09:30
soapyhelpers.py Ran everything through the 'black' formatter 2023-06-15 15:16:24 +09:30
streamer.py Ran everything through the 'black' formatter 2023-06-15 15:16:24 +09:30
tuuube.py Ran everything through the 'black' formatter 2023-06-15 15:16:24 +09:30

SDRPlay RSP1A demo code

This repository is a demo - it isn't a fully fleshed out system and isn't intended to be. Things might break. It also makes use of some 3rd-party code that we don't have a commercial licence for, so legally this can only be used for demonstration purposes, and only interally.

Getting started

  • Use a debian-based 64-bit system (x86). No way around it; this project is not cross-platform until some efforts gets put into making it that way.
  • Install the SDRPlay device driver & install the project dependencies.
    • ./setup.sh
    • Follow the prompts, there is some audience participation getting the driver installed.
    • Beyond that it should be mostly unattended. SoapySDR & plugins will be installed in the system directories.
  • Run the demos. The demo code is provided by SoapySDR and required minimal modification.
    • cd ./examples/
    • C++ demo: make && ./Example
    • Python demo: ./example.py

Using the radio

The project is currently structured as several independent scripts that pipe raw data to one another. It was easier to integrate everything this way, rather than trying to manage it all as one monolithic program.

nooelec/NESDR Smart

The NESDR Smart is a good starting place as it has a command line utility already, rtl_sdr. This is available as the system package rtl-sdr, which should be automatically installed by the ./setup script.

SDRPlay radio

The script ./sdrplay_sample was built to mimic the interface provided by rtl_sdr, and is nearly a slot in replacement but for the SDRPlay hardware. It is used for producing raw I/Q samples from the radio device, which (assuming you tune to a frequency where an FM radio station is available) can be piped into the FM demodulator fm_demod.py, which itself outputs raw PCM audio.

To capture raw IQ samples from the device, follow the below example (omitting the comments).

# FM broadcasting is in the VHF Band II space - in Australia this is 87.5 MHz to 108 MHz.
# You can specify the frequency as either a plain integer (87500000) or using a suffix:
station="87.5M"

# You'll want to replace that number with an actual radio station.

./sdrplay_sample \
  -v \                # Enable verbose output.
  -d sdrplay \        # Connect to first radio of sdrplay driver;
  --format CS16 \     # Sample format of complex signed 16-bit int;
  -f ${station} \     # Tune to FM station frequency;
  -s 384k \           # Sampling rate 384 kHz;
  -n 4M \             # Collect 4 million samples (~10 seconds);
  -o output.iq        # Save IQ samples to file.

# To find the formats, frequencies, sampling rates etc that are supported by the
# radio device, run:
./sdrplay_sample -v --list-devices

To demodulate the received IQ samples into raw PCM audio, do:

./fm_demod.py \
  -f CS16 \           # Sample format must match IQ samples;
  -s 384k \           # Sampling rate must match IQ samples;
  -d 32k \            # Output rate - see notes.
  < test.iq \         # IQ sample input file,
  > test.raw          # Write PCM to file.

# The output rate is a bit finicky as it needs to satisfy multiple requirements.
# - must be an integer divisor of the sampling rate;
# - must be a supported input format for the system sound card.
#
# A good ratio to aim for is for sampling-rate / output-rate = 10. This might not
# always be possible, but near enough will work. Higher and you're wasting samples
# and too low you will face audio problems.

Finally, to play the PCM file through the system audio out, use the sox utility. Most of the parameters are required to be fixed values, so only the modifiable ones are explained.

sox \
  -t raw \
  -r 32000 \          # Sample rate (must match demodulator output rate)
  -b 16 \
  -c 2 \
  -L \
  -e signed-integer \
  test.raw \          # Input audio file
  -d                  # Output to default audio device

To run the whole chain in realtime without using intermediary files, tuning to a radio station frequency, demodulating the IQ samples to PCM and rendering to the system audio sink, run the following:

./sdrplay_sample -d sdrplay --format CS16 -f ${station} -s 384k -o - | \
  ./fm_demod.py -f CS16 -s 384k -d 32k | \
  sox -t raw -r 32000 -b 16 -c 2 -L -e signed-integer - -d

There's an outstanding bug where running live causes a buffer under-run in alsa - still working on that.

Running the microservice

A detailed description of the 'microservice' architecture is available here. To be able to access the microservice outside of localhost you may need to open up some ports. Some of the architecture is currently dependent on stuff running on my local network as well - anything from Reverse Proxy doesn't exist in this project and so won't be available if run elsewhere.

Running the microservice is simple. With no arguments:

./microservice.py

You should get some log output about how this isn't safe to run in production - good thing it isn't being run in production. Ignore most of the garbage, but you'll also be able to see REST client hits and the response codes in the terminal output.

The REST API will present itself at http://localhost:5000, but there is also Swagger UI available at http://localhost:5000/apidocs. Documentation on the endpoints and how to interact with the radio is presented there.

Once a radio stream is started, use any RTSP capable client (VLC is recommended) to connect to the stream at rtsp://localhost:8554/radio/[radio]/stream. You'll need to replace [radio] with the name of the radio for which you have started the stream.

For more detail on interacting with the microservice, see the system state flow diagram in the /docs folder.