• Welcome to ASR. There are many reviews of audio hardware and expert members to help answer your questions. Click here to have your audio equipment measured for free!

Installation guide: Camilla DSP with Audio Injector Octo 6x8 audio interface

PeteSahat

Member
Joined
Dec 28, 2023
Messages
30
Likes
10
1754351980944.png


Hey everyone!
This is a guide on how to properly set-up the Audio Injector interface with CamillaDSP on an RPi 4 using the JACK Audio API for an ultra low-latency audio system.
Multi-channel audio interfaces for the Raspberry Pi are quite rare, so this guide might be useful for some.
It took me a while to figure out the correct procedure, as the Octo project appears abandoned, and many users reported routing issues and random channel swapping—with no clear solution available.

Raspberry Pi 4 with Audio Injector Octo – Installation Guide

NOTE: This guide shows how to install the Octo audio interface along with CamillaDSP and the JACK Audio API on an RPi 4 without random channel swapping issues. All other audio interfaces of the Pi are disabled in this example. The result is a very low latency audio system.

1. Basic Installation
1.1 Install the Operating System:

Use Raspberry Pi Imager

OS: Raspberry Pi OS Lite (64-bit)

Set up network, SSH, and user account (this guide assumes the username is pi; if using a different username, adjust commands accordingly).

1.2 Update the System:

sudo apt update && sudo apt full-upgrade -y

2. Audio Configuration
2.1 Edit config.txt:

sudo nano /boot/firmware/config.txt

#Edit these entries or add if non-existent:

dtparam=i2c_arm=on
dtparam=i2s=on
dtparam=spi=on
#dtparam=audio=on
dtoverlay=vc4-kms-v3d,noaudio

#at the very bottom of the file add:
dtoverlay=audioinjector-addons

#save and reboot

3. Install JACK Audio Server
3.1 Install JACK with real time permission:

sudo apt install jackd2

3.2 Configure Real-Time Priority:

sudo adduser $USER audio #most likely already added

sudo nano /etc/security/limits.d/audio.conf

#Content looks like:

@audio - rtprio 95
@audio - memlock unlimited
#@audio - nice -19

3.3 Install Development Packages:

sudo apt install -y build-essential git cmake pkg-config libasound2-dev libjack-jackd2-dev libsamplerate0-dev

3.4 Set Up JACK Autostart Service:

sudo nano /etc/systemd/system/jackd.service

#Content:

[Unit]
Description=JACK Audio Daemon
After=alsa-restore.service
Requires=alsa-restore.service

[Service]
User=pi
Environment=JACK_NO_AUDIO_RESERVATION=1
LimitRTPRIO=95
LimitMEMLOCK=infinity
ExecStart=/usr/bin/jackd -P95 -d alsa -d hw:0 -r 48000 -p 128 -n 3
Restart=on-failure

[Install]
WantedBy=multi-user.target

#Enable and start the service:

sudo systemctl enable jackd.service
sudo systemctl start jackd.service
sudo reboot

#Check if Jack is running properly:

sudo systemctl status jackd.service


4. Install CamillaDSP
4.1 Install Rust and Cargo:

curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
#reboot

4.2 Install Dependencies:

sudo apt update
sudo apt install git

4.3 Clone CamillaDSP:

git clone https://github.com/HEnquist/camilladsp.git
cd camilladsp

4.4 Compile with JACK Support:

RUSTFLAGS='-C target-feature=+neon -C target-cpu=native' cargo build --release --features jack-backend,websocket

4.5 Create Service Files:

mkdir -p ~/camilladsp/coeffs ~/camilladsp/configs
sudo wget https://raw.githubusercontent.com/mdsimon2/RPi-CamillaDSP/main/camilladsp.service -O /lib/systemd/system/camilladsp.service

4.6 Adjust ExecStart in Service File and change username:

sudo nano /lib/systemd/system/camilladsp.service

#add your username username

#Change this line to:
ExecStart=/home/pi/camilladsp/target/release/camilladsp -s /home/pi/camilladsp/statefile.yml -w -g-0 -o /home/pi/camilladsp/camilladsp.log -p 1234

4.7 Enable and Start Service:

sudo systemctl enable camilladsp
sudo service camilladsp start

5. Install CamillaDSP GUI
5.1 Install Web Interface:

wget https://github.com/HEnquist/camillagui-backend/releases/download/v3.0.2/bundle_linux_aarch64.tar.gz -O ~/camilladsp/bundle_linux_aarch64.tar.gz
sudo tar -xvf ~/camilladsp/bundle_linux_aarch64.tar.gz -C /opt/

5.2 Set Up GUI Service:

sudo wget https://raw.githubusercontent.com/mdsimon2/RPi-CamillaDSP/main/camillagui.service -O /lib/systemd/system/camillagui.service
sudo nano /lib/systemd/system/camillagui.service # Adjust username if needed

5.3 Enable and Start GUI Service:

sudo systemctl enable camillagui
sudo service camillagui start

5.4 Reboot:

sudo reboot

6. Verification

#Check status:

sudo systemctl status jackd.service
sudo systemctl status camilladsp
sudo systemctl status camillagui

#Web Interface:

http://<yourPI-IP>:5005/gui/index.html

7. Kernel Downgrade (Required, otherwise Octo will not work!)

sudo rpi-update f5c4fc199c8d8423cb427e509563737d1ac21f3c
sudo reboot

8. Camilla setup

In the Camilla webgui under "Devices" > Capture & Playback Devices choose JACK
Chunksize can be reduced for very low latency values - 32 is absolutely safe. Check ExecStart=/usr/bin/jackd -P95 -d alsa -d hw:0 -r 48000 -p 128 -n 3 in ExecStart=/usr/bin/jackd -P95 -d alsa -d hw:0 -r 48000 -p 128 -n 3 for further latency adjustmens. From here it is experimentation.
Create a new config under "Files" and mark it as active (the star button)
On the left hand side click "Apply and save".
You might need to adjust recording levels in alsamixer.

DONE!
 
Hi Pete,
I just wanted to say a big thanks for your posting here.

It helped me a lot. In fact, although I don't yet have an Octo (ordered but not yet arrived), I used this recipe with a 2 channel HiFiberry DAC+ADC for ultra low latency using Jack.

I have a couple of small suggestions for improvement which I'd like to suggest for your consideration. Can we please connect via email? my email is [email protected]

Thanks again.
Mike
 
Hi Mike, you could send me a direct message with you suggestions here on ASR.
 
many users reported routing issues and random channel swapping
The Octo technical design is prone to these issues by principle. Using a GPIO signal to mark start of the multichannel audio frame from a stereo I2S is a brittle hack and cannot work 100% reliably on a non-hard realtime OS.

IMO the way to go is to use a proper multichannel I2S, e.g. RPi5 or another ARM SoC.
 
Using JACK stabilizes the routing and channels aren't being swapped after each restart.

IMO the way to go is to use a proper multichannel I2S, e.g. RPi5 or another ARM SoC.

I will purchase an RPi 5 to see if this improves things.
 
Using JACK stabilizes the routing and channels aren't being swapped after each restart.
Honestly I do not understand how the extra component - the jackd server - can make an improvement of alsa segments. What is your actual chain with jackd?
 
Hi all, I've worked quite a bit with PeteSahat's nice install recipe for Camilla-Jack and Octo.

The install recipe is also applicable to rpi5, but I've been unable to get Octo working on rpi5 (the kernel update doesn't work on the pi5).

On the other hand, the raspiaudio 8in/8out multi i2s device works perfectly on pi5 with low latency and high performance. There are many other benefits once in the Jack domain, including meters, mixers, noise sources, dynamic routing, use of snapcast streaming, and more.

- Mike
 
Honestly I do not understand how the extra component - the jackd server - can make an improvement of alsa segments. What is your actual chain with jackd?
Here's an easy-to-understand AI explanation:

JACK fixes the Audio Injector Octo channel swapping issue because it explicitly manages and locks the channel order, unlike ALSA.
Here’s how it works:
  • The Audio Injector Octo (with PCM1865 ADC and PCM5122 DAC) connects via the Raspberry Pi’s I²S bus.
  • The ALSA driver initializes DMA buffers dynamically. This can cause channels to appear in a different order after reboot or reinitialization — that’s the “channel swapping” problem.
  • JACK uses ALSA as a backend but does not rely on ALSA’s automatic buffer initialization. When JACK starts, it defines the device and reads channels in the order specified in the startup parameters or configuration (e.g. .asoundrc, jackd -d alsa -d hw:AudioInjectorOcto).
  • JACK keeps this mapping fixed throughout runtime. Each channel is given a deterministic port (system:capture_1 … system:capture_8, etc.), so the routing stays constant.
If JACK is started with the same device name and parameters every time, and no other sound system (like PulseAudio or PipeWire) reinitializes the device, the routing remains identical across reboots.

In short:
ALSA alone = dynamic channel assignment → random order.
JACK = fixed channel assignment → stable order, even after reboot.
 
The install recipe is also applicable to rpi5, but I've been unable to get Octo working on rpi5 (the kernel update doesn't work on the pi5).

Do you mean the update process at the beginning before setting up JACK and everything else? Or do you mean the kernel downgrade at the end of the installation process?
If you mean the latter - I'd advise to connect your PI via LAN. As of now, Debian is rolling out Trixie changing some stuff in the background which interrupts the update process when connected wirelessly.
 
Here's an easy-to-understand AI explanation:

JACK fixes the Audio Injector Octo channel swapping issue because it explicitly manages and locks the channel order, unlike ALSA.
Here’s how it works:
  • The Audio Injector Octo (with PCM1865 ADC and PCM5122 DAC) connects via the Raspberry Pi’s I²S bus.
  • The ALSA driver initializes DMA buffers dynamically. This can cause channels to appear in a different order after reboot or reinitialization — that’s the “channel swapping” problem.
  • JACK uses ALSA as a backend but does not rely on ALSA’s automatic buffer initialization. When JACK starts, it defines the device and reads channels in the order specified in the startup parameters or configuration (e.g. .asoundrc, jackd -d alsa -d hw:AudioInjectorOcto).
  • JACK keeps this mapping fixed throughout runtime. Each channel is given a deterministic port (system:capture_1 … system:capture_8, etc.), so the routing stays constant.
If JACK is started with the same device name and parameters every time, and no other sound system (like PulseAudio or PipeWire) reinitializes the device, the routing remains identical across reboots.

In short:
ALSA alone = dynamic channel assignment → random order.
JACK = fixed channel assignment → stable order, even after reboot.
I am sorry but that AI explanation is a typical AI word salat which sounds nice but makes no sense technically. It sounds like the model just chose and ordered words so that it confirms your question. No offense, but IMO a better LLM would be due.

What does a dynamic channel assignment mean? Or dynamical DMA buffer initialization? Alsa always allocates the buffer for the device (in this case the part of RAM which the I2S transmitter reads via DMA) and passes it to the app. How the app stacks the interleaved channels into the buffer (period size) is up to the app.

What the dedicated Octo alsa driver does:

* it quadruples the timing frequency of the I2S interface, so that the interface consumes/transmits the data at four times the rate that the app requested - because the interface outputs only 2 samples at a time, while the app does 8 samples.

*it sends a pulse to the dedicated GPIO when the I2S starts consuming new 8-multiple of the samples: the I2S interface is configured to fire IRQ when it consumes 8-multiple of samples - e.g. 1024 * sample-length bytes. That means at the I2S IRQ handler the driver will push the pulse to the GPIO. That pulse tells the FPGA located on the Octo hat (which demuxes the stereo stream from I2S to the four stereo I2S outputs) that the currently incoming pair is the first one.

As you see this method depends on strict software timing within the Octo driver and authors themselves acknowledge that it's a hack which may not work reliably.

And I wonder how jackd can help with such timing. That's why I asked about details of your chain, where the jackd actually is, how it's configured etc.
 
Last edited:
And I wonder how jackd can help with such timing. That's why I asked about details of your chain, where the jackd actually is, how it's configured etc.

I'm afraid that I cannot give you a better answer. I'm no software engineer nor do I know too much about RPi's hardware architecture. I'm merely a user with some basic knowledge who just got lucky after trying for quite some time.

I run a headless system and installed / set up JACK like described in the first post. That's all I know about it and I'm just happy that it's working and move on.

Right now I try to figure why the Octo doesn't work under kernel 6 and if this problem could be solved "easily". What I've learned so far is that this is much more complicated than I thought.

See here:
https://github.com/raspberrypi/linux/issues/6909
 
Hi all,

Per my comments above, unless you are really determined to use the Octo injector, I suggest moving to the raspiaudio 8in/8out if you need multiple input channels.

This requires a pi5, but the overall performance is much better (including more input channels), and the cost differential is small.

PeteSahat, your install recipe (I haven't tried the script), is still basically applicable. I prefer using the pi desktop os (not the pi light os) so I can use vnc to see/operate the Jack patch diagrams and Jack meters.

If you decide to go this direction and want to work on revising/updating your automation script, I'd be glad to work with you.

On the other hand, if fewer input channels are needed, you can get one of these usb audio devices on Amazon, 2in/6out plus spdif for ~$20

USB 2.0 External Sound Card 6 Channel 5.1 Surround Adapter Audio S/PDIF for PC -Blue

They work fine for crossovers, on both pi4 and pi5 without any kernel mods. The install recipe you described is again applicable.

- Mike
 
sure. all of my work was based on your install recipe, so you're welcome.

(i sent you this info plus more in some dm's, but maybe these didn't make the trip :)

don't forget the 2in-6out device referenced (also has spdif) all of which also work perfectly with camilla and jack

- Mike
 
Sorry if this is slightly off exact topic: I'm wondering whether anyone has been able to get an MCHstreamer working with Camilladsp in Linux? I've been working with it some, I can see the MCHstreamer listed in ALSA's device list as a 10 output device. Butt I can't get Camilla to run with anything involving the MCH configured as its output, it just stalls with errors confuguring channels. The MCH devices listed in Camilla's GUI aren't described the same way as in alsamixer, nor as listed using 'aplay -l', I'm getting pretty frustrated.
 
@Bwaslo: For troubleshooting it's important to know what channel/formats your USB soundcard reports as available. Please post/attach here file /proc/asound/YOUR_USB_CARD_NAME/stream0.

The MCH devices listed in Camilla's GUI aren't described the same way as in alsamixer, nor as listed using 'aplay -l', I'm getting pretty frustrated.
Alsamixer shows alsa controls, it does not talk about channel parameters; aplay - l is just a list of the cards.
 
@Bwaslo: For troubleshooting it's important to know what channel/formats your USB soundcard reports as available. Please post/attach here file /proc/asound/YOUR_USB_CARD_NAME/stream0.
Thanks, I was looking for where that info is stored. Card name is apparently "TosLink". Here is what it shows --

miniDSP MCHStreamer I2S TosLink at usb-0000:00:14.0-3, high speed : USB Audio

Playback:
Status: Running
Interface = 1
Altset = 1
Packet Size = 360
Momentary freq = 48000 Hz (0x6.0000)
Interface 1
Altset 1
Format: S32_LE
Channels: 10
Endpoint: 0x01 (1 OUT) (ASYNC)
Rates: 44100, 48000, 88200, 96000, 176400, 192000
Data packet interval: 125 us
Bits: 24
Channel map: FL FR FC LFE RL RR FLC FRC RC SL
Sync Endpoint: 0x81 (1 IN)
Sync EP Interface: 2
Sync EP Altset: 1
Implicit Feedback Mode: Yes
Interface 1
Altset 2
Format: S32_LE
Channels: 10
Endpoint: 0x01 (1 OUT) (ASYNC)
Rates: 44100, 48000, 88200, 96000, 176400, 192000
Data packet interval: 125 us
Bits: 32
Channel map: FL FR FC LFE RL RR FLC FRC RC SL
Sync Endpoint: 0x81 (1 IN)
Sync EP Interface: 2
Sync EP Altset: 2
Implicit Feedback Mode: Yes

Capture:
Status: Stop
Interface 2
Altset 1
Format: S32_LE
Channels: 10
Endpoint: 0x81 (1 IN) (ASYNC)
Rates: 44100, 48000, 88200, 96000, 176400, 192000
Data packet interval: 125 us
Bits: 24
Channel map: FL FR FC LFE RL RR FLC FRC RC SL
Interface 2
Altset 2
Format: S32_LE
Channels: 10
Endpoint: 0x81 (1 IN) (ASYNC)
Rates: 44100, 48000, 88200, 96000, 176400, 192000
Data packet interval: 125 us
Bits: 32
Channel map: FL FR FC LFE RL RR FLC FRC RC SL
--
Can you show me what the Camilla yml config file should look like for devices then? I'm only needed 6 of the 10 play channels (and two of the capture channels from the Toslink input socket). 96000ksps, 32 or 24 bit
 
Last edited:
The stream0 shows currently the device playback is running 10ch 48kHz S32_LE - that would be accepted by CDSP then. But of course provided the device is not running, to be available for CDSP. Listing processes using the audio devices is 'lsof /dev/snd/*'.

The second playback altsetting is also 10ch/S32_LE, but likely 32bit I2S on output (because altset 1 has 24 significant bits, while altset 2 has 32 significant bits).
 
Back
Top Bottom