Raspberry Pi

CUE Audio Transmitter service for Raspberry Pi

This module provides ability to broadcast CUE triggers with BLE advertise data from Raspberry Pi device using low level access to audio stream and Bluetooth device.

Setup

Flash Raspbian OS

Download ISO image from official Raspberry PI site: https://www.raspberrypi.org/downloads/raspbian/

Note: Raspbian Buster with desktop or Raspbian Buster Lite are recommended, but any should work

Installation guide can be found here

Or find complete image here. Install it using the instructions here, or the balenaEtcher desktop app.

Python installation

This module runs within Python. First thing is to make sure Python3 is installed:

sudo apt update
sudo apt install python3

CUEEngine native library

Install CUE engine python wrapper packages within instructions here

Audio and Bluetooth dependencies

Install dependencies for audio and Bluetooth usage:

sudo apt install libcairo2-dev
sudo apt install python3-pyaudio
sudo apt install libgirepository1.0-dev
sudo apt install libasound-dev

Source code import

Load source code (e.g., CUE-Bluetooth/Python/transmitter) onto rpi. You can do this with:

scp ./transmitter.zip pi@raspberrypi:/home/pi/transmitter.zip

After source code is in place run next command to install python dependencies:

pip3 install -r requirements.txt

Execution

The simplest way to run a service is to launch it within Python directly:

python3 transmitter.py --logfile=logs.log

Installation

There is a script to install CUE transmitter service to work as Linux service:

source ./intall.sh -k test_api_key

At time this code is executed the service will be created pointing to transmitter.py at the folder script launched from. Service will boot automatically on a system start next time.

To finish the setup you may need to set API key by adding environment variable:

export CUE_AUDIO_API_KEY=test_api_key

Package details

transmitter.py

Entry point of service.

  • launches audio input stream
  • feeds audio into engine and listens for trigger callback
  • passes trigger to BLE advertisement and stops within timeout
Environment variables
  • CUE_AUDIO_API_KEY used to set CUE api key for a system wide service
Parameters
  • --api-key or -k: Engine API key
  • --timeout or -t: Advertising timeout in seconds
  • --device or -d: Audio input device name
  • --channels or -ch Audio input channels amount: 1 - mono, 2 - stereo, 6 - full 6 channel audio
  • --samplerate or -s Audio input signal sampling frequency
  • --blocksize or -p Audio input block size
  • --logfile or -l Log output file path

audio_input.py

Abstract AudioInput class. Used to be source of audio input stream to engine.

sound_device_audio_input.py

Implementation of AudioInput class based on SoundDevice library.

engine.py

CUE engine library wrapper. Used to listen byte array input from AudioInput, analyze and callback with trigger.

ble_device.py

Wrapper over DBus to work with Bluetooth LE device. Consumes Advertisement object to broadcast method to start BLE advertisement.

ble_advertisement.py

DBus wrapper over BLE advertisement object. Should be extended to apply needed parameters.

trigger_advertisement.py

CUE trigger advertisement implementation. Receives the trigger and advertises it as binary payload.

Logs

Logs are written to a file set by --logfile option or to /var/log/cur-transmitter.log by default.

Service commands

Status

sudo systemctl status cue-transmitter returns the current service status with system logs (not transmitter ones)

Stop

sudo systemctl stop cue-transmitter stops the service until reboot. In is useful to test different settings.

Restart all services

sudo systemctl daemon-reload used to restart all services.

Confirming BLE Extender is active

Useful commands:
sudo hciconfig Shows all BLE devices. With extender, there should be two.
sudo hciconfig hci0 down. Cancels default/root BLE and will use extender.

Without dongle:

pi@raspberrypi:~/CUE-Bluetooth-feature-python_transmitter/Python/transmitter $ sudo hciconfig
hci1:	Type: Primary  Bus: UART
	BD Address: B8:27:EB:A8:7B:49  ACL MTU: 1021:8  SCO MTU: 64:1
	UP RUNNING
	RX bytes:780 acl:0 sco:0 events:51 errors:0
	TX bytes:2994 acl:0 sco:0 commands:51 errors:0
With dongle:
pi@raspberrypi:~/CUE-Bluetooth-feature-python_transmitter/Python/transmitter $ sudo hciconfig
hci0:	Type: Primary  Bus: USB
	BD Address: 00:1A:7D:DA:71:06  ACL MTU: 310:10  SCO MTU: 64:8
	UP RUNNING
	RX bytes:628 acl:0 sco:0 events:39 errors:0
	TX bytes:1198 acl:0 sco:0 commands:39 errors:0
hci1:	Type: Primary  Bus: UART
	BD Address: B8:27:EB:A8:7B:49  ACL MTU: 1021:8  SCO MTU: 64:1
	UP RUNNING
	RX bytes:780 acl:0 sco:0 events:51 errors:0
	TX bytes:2994 acl:0 sco:0 commands:51 errors:0
2:59

Running transmitter.py without dongle and playing a trigger I see:

Trigger heard: 140.305.308
Adapter: /org/bluez/hci1
Mac address: B8:27:EB:A8:7B:49

Running:

sudo hciconfig hci0 down
python3 transmitter.py

Then I see:

Trigger heard: 129.131.220
Adapter: /org/bluez/hci0
Mac address: 00:1A:7D:DA:71:06

So the mac address does change to that of the BLE extender, showing the BLE extender is being utilized.

Making recordings

Simply run:

arecord --device=hw:1,0 --format S16_LE --rate 48000 -c1 myfile.wav

If recording on HiFiBerry, see devices using arecord -l. You may need to use this instead (this may change according to the results of arecord -l):

arecord --device=hw:0,0 --format S16_LE --rate 48000 -c1 test.wav

You will likely need to run sudo systemctl stop cue-transmitter first so you avoid this error: arecord: main:828: audio open error: Device or resource busy. Afterwards, you can run sudo systemctl restart cue-transmitter to restart the service.

Download files from RPi using scp [email protected]:/home/pi/myfile.wav /Users/Home/Downloads/myfile.wav

HiFiBerry

To get the DAC+ ADC working, you must modify /boot/config.txt to include:

# Enable audio (loads snd_bcm2835)
dtoverlay=hifiberry-dacplusadcpro

An example config is:

pi@raspberrypi:~ $ cat /boot/config.txt
# For more options and information see
# http://rpf.io/configtxt
# Some settings may impact device functionality. See link above for details

# uncomment if you get no picture on HDMI for a default "safe" mode
#hdmi_safe=1

# uncomment this if your display has a black border of unused pixels visible
# and your display can output without overscan
disable_overscan=1

# uncomment the following to adjust overscan. Use positive numbers if console
# goes off screen, and negative if there is too much border
#overscan_left=16
#overscan_right=16
#overscan_top=16
#overscan_bottom=16

# uncomment to force a console size. By default it will be display's size minus
# overscan.
#framebuffer_width=1280
#framebuffer_height=720

# uncomment if hdmi display is not detected and composite is being output
#hdmi_force_hotplug=1

# uncomment to force a specific HDMI mode (this will force VGA)
#hdmi_group=1
#hdmi_mode=1

# uncomment to force a HDMI mode rather than DVI. This can make audio work in
# DMT (computer monitor) modes
#hdmi_drive=2

# uncomment to increase signal to HDMI, if you have interference, blanking, or
# no display
#config_hdmi_boost=4

# uncomment for composite PAL
#sdtv_mode=2

#uncomment to overclock the arm. 700 MHz is the default.
#arm_freq=800

# Uncomment some or all of these to enable the optional hardware interfaces
#dtparam=i2c_arm=on
#dtparam=i2s=on
#dtparam=spi=on

# Uncomment this to enable infrared communication.
#dtoverlay=gpio-ir,gpio_pin=17
#dtoverlay=gpio-ir-tx,gpio_pin=18

# Additional overlays and parameters are documented /boot/overlays/README

# Enable audio (loads snd_bcm2835)
#dtparam=audio=on
dtoverlay=hifiberry-dacplusadcpro

[pi4]
# Enable DRM VC4 V3D driver on top of the dispmanx display stack
dtoverlay=vc4-fkms-v3d
max_framebuffers=2

[all]
#dtoverlay=vc4-fkms-v3d

Troubleshooting

If encountering an Message: 'Unexpected error:', make sure that, before starting the service again (e.g., via sudo python3 transmitter.py --api-key=<apiKey>), you first run sudo systemctl stop cue-transmitter.service.