Skip to content

Meta layer for Camel Audio, a Raspberry Pi–based Hi-Res audio player.

License

Notifications You must be signed in to change notification settings

pcjustin/meta-camelpi

Repository files navigation

meta-camelpi

Camel Logo

A Yocto/OpenEmbedded BSP layer for building Camel Audio, a high-resolution audio streaming platform.

Note: This project was previously known as Auris and has been rebranded to Camel Audio.

Overview

Camel Audio is a dedicated music platform designed to deliver pristine high-resolution audio playback through USB DAC (Digital-to-Analog Converter) devices. The platform provides a web-based interface for managing and streaming your music collection from multiple sources.

Features

  • High-Resolution Audio Support: Native playback of Hi-Res audio formats through USB DAC
  • RAM Boot System: Entire OS runs from RAM (initramfs), no rootfs partition needed
    • Minimal SD card writes for extended lifespan
    • Fast boot and shutdown
    • Optimized for audio-focused workloads
  • AirPlay Support: Stream audio from iOS, macOS, and iTunes via Shairport Sync with automatic switching
  • UPnP Renderer: Act as UPnP/DLNA audio renderer to receive audio streams from UPnP control points
  • NetworkAudio (NAA) Support: HQPlayer endpoint for high-quality network audio streaming
  • Multiple Audio Sources:
    • AirPlay (from iOS/macOS devices)
    • UPnP/DLNA media servers
    • Roon Ready (RoonBridge endpoint)
    • NetworkAudio (NAA) endpoint for HQPlayer
  • Bit-Perfect Audio: Direct hardware access with no sample rate conversion, replaygain disabled
    • Memory locking prevents audio interruption from memory swapping
    • Optimized buffer management for low-latency playback
  • Real-Time Audio Scheduling: Dynamic CPU scheduling with FIFO priorities
    • sysctl tuning reduces memory swapping and optimizes filesystem caching
    • mpd-camel (Backend): FIFO priority 80 (ALSA audio control - critical path)
    • upmpdcli (UPnP Renderer): FIFO priority 75 (primary playback - depends on mpd)
    • RoonBridge (Roon Endpoint): FIFO priority 75 (Roon audio streaming)
    • Shairport Sync (AirPlay): FIFO priority 70 (independent ALSA access)
  • Web-Based Control: Intuitive web interface for music library management and playback control
  • Optimized for Audio: Minimal Linux image focused on audio performance
  • Raspberry Pi Ready: Built and optimized for Raspberry Pi 5 hardware

Image

The layer provides camelpi-image, a custom Linux image for Camel Audio based on core-image-minimal with high-resolution audio streaming capabilities.

Image Architecture

  • RAM Boot System: Entire OS runs from RAM via initramfs (mounted on /dev/ram0)
  • Single Boot Partition: No separate rootfs partition, minimizes SD card usage
  • Kernel with Embedded Initramfs: Kernel built with embedded camelpi-initramfs-image
  • WIC Image Format: Pre-partitioned .wic.bz2 format for easy SD card deployment
  • Audio-Optimized: Minimal rootfs focused on audio performance

Architecture

System Architecture Diagram

┌──────────────────────────────────┐
│     Network Audio Sources        │
│  ┌──────────────┐  ┌──────────┐ │
│  │ UPnP Server  │  │ AirPlay  │ │
│  │  (Primary)   │  │          │ │
│  └──────┬───────┘  └──────┬───┘ │
└─────────┼──────────────────┼─────┘
          │                  │
    ┌─────▼─────────────┐    │
    │ upmpdcli (UPnP)   │    │
    │ FIFO: 75          │    │
    │ (Primary playback)│    │
    └────────┬──────────┘    │
             │                │     ┌──────────────────┐
             │                │     │ Shairport-sync   │
             │                └────▶│ FIFO: 70         │
             │                      │ (AirPlay)        │
             │                      │ Direct ALSA      │
    ┌────────▼─────────────────┐    └────────┬─────────┘
    │   mpd-camel (Backend)    │             │
    │   FIFO: 80 (Critical)    │             │
    │   ALSA Control & Output  │             │
    └────────┬─────────────────┘             │
             │                                │
    ┌────────┴────────────────────────────────┴──┐
    │            USB DAC Audio Output             │
    │         (Bit-Perfect, No Resampling)        │
    └──────────────────────────────────────────────┘

CPU Scheduler (scx_bpfland):
    Primary Domain: CPU 3 (Audio)
    Overflow Domain: CPU 0-2 (System Services)

    FIFO Priority Hierarchy:
    80: mpd-camel ────────── Critical ALSA Control
    75: upmpdcli ─────────── Depends on mpd-camel
    75: RoonBridge ──────── Roon audio streaming
    75: NetworkAudio (NAA) ─ HQPlayer network endpoint
    70: Shairport-sync ───── Independent ALSA
    Normal: Other Services

Interrupt Handling: CPU 0-2 (irqaffinity=0-2)

For a detailed explanation of the architecture and design principles, see meta-camelpi: HiFi Music Streaming Platform

Audio Signal Flow

UPnP Playback (Primary):

UPnP Server → upmpdcli (control) → mpd-camel (ALSA) → USB DAC

Roon Playback:

Roon Core → RoonBridge (FIFO 75) → mpd-camel (ALSA) → USB DAC

NetworkAudio/HQPlayer Playback:

HQPlayer → networkaudiod (NAA) (FIFO 75) → USB DAC

AirPlay Playback (Independent):

AirPlay Source → Shairport-sync (direct) → USB DAC

Multiple sources share the same USB DAC with independent signal paths to avoid conflicts. Priority scheduling ensures mpd-camel maintains control of the critical ALSA interface.

Real-Time Scheduling Strategy

  • mpd-camel (FIFO 80): Highest priority, controls critical ALSA interface
  • upmpdcli (FIFO 75): Secondary priority, depends on mpd-camel for audio output
  • RoonBridge (FIFO 75): Roon Labs network audio endpoint, same priority as upmpdcli
  • NetworkAudio/NAA (FIFO 75): HQPlayer network endpoint, same priority as upmpdcli and RoonBridge
  • Shairport-sync (FIFO 70): Independent ALSA access, lower priority
  • System Services: Normal priority, dynamically scheduled by scx_bpfland

Priority inversion is avoided because mpd-camel (critical path) has highest priority among audio applications.

Prerequisites

Recommended Build Environment

Ubuntu 24.04 LTS is the recommended operating system for building this layer. Other Linux distributions may work but are not officially tested.

Required Dependencies

Before building this layer, ensure your build host has the following dependencies installed:

# Ubuntu/Debian
sudo apt-get install bzip2 chrpath diffstat g++ gawk gcc make libc-bin

# Fedora/RHEL
sudo dnf install bzip2 chrpath diffstat gcc gcc-c++ gawk make rpcgen util-linux

Required packages:

  • bzip2 - Compression utility and algorithm support (includes bunzip2)
  • chrpath - Change rpath/runpath for binaries
  • diffstat - Generates histogram of changes in source files
  • g++ - C++ compiler (for building native tools)
  • gawk - GNU awk text processing
  • gcc - C compiler (essential for kernel and recipe compilation)
  • make - Build automation tool
  • libc-bin - C library utilities (includes rpcgen on Ubuntu/Debian)

Dependencies

This layer depends on:

URI: https://git.openembedded.org/bitbake
    branch: master
    revision: HEAD

URI: https://git.openembedded.org/openembedded-core
    branch: master
    revision: HEAD

URI: https://git.yoctoproject.org/meta-yocto
    branch: master
    revision: HEAD

URI: https://git.yoctoproject.org/meta-raspberrypi
    branch: master
    revision: HEAD

URI: https://git.openembedded.org/meta-openembedded
    branch: master
    revision: HEAD
    layers: meta-oe, meta-python, meta-multimedia

Quick Start

1. Create Sources Directory and Clone Repositories

First, create a sources directory for all Yocto/OpenEmbedded repositories:

# Create sources directory
mkdir -p ~/camelpi/sources
cd ~/camelpi/sources

Then clone all necessary repositories in the following order:

# Clone Yocto/OpenEmbedded core components
git clone https://git.openembedded.org/bitbake
git clone https://git.openembedded.org/openembedded-core

# Clone Yocto project metadata layers
git clone https://git.yoctoproject.org/meta-yocto
git clone https://git.yoctoproject.org/meta-raspberrypi

# Clone additional metadata layer
git clone https://git.openembedded.org/meta-openembedded

# Clone this Camel Audio BSP layer
git clone <meta-camelpi-repository>

# IMPORTANT: Switch to master branch for these layers
cd openembedded-core && git checkout master && cd ..
cd meta-yocto && git checkout master && cd ..
cd meta-openembedded && git checkout master && cd ..
cd meta-camelpi && git checkout master && cd ..

Required repositories:

  • bitbake - Build engine for Yocto/OpenEmbedded
  • openembedded-core - Core metadata and base recipes
  • meta-yocto - Yocto-specific metadata layer
  • meta-raspberrypi - Raspberry Pi hardware support layer
  • meta-openembedded - Additional recipes for multimedia, Python, and system tools
  • meta-camelpi - Camel Audio BSP layer (this repository)

2. Initialize Build Environment

source openembedded-core/oe-init-build-env camel-build

3. Add Layers to Build Configuration

Use bitbake-layers command to add all required layers:

bitbake-layers add-layer ../sources/meta-raspberrypi/
bitbake-layers add-layer ../sources/meta-openembedded/meta-oe
bitbake-layers add-layer ../sources/meta-openembedded/meta-python
bitbake-layers add-layer ../sources/meta-openembedded/meta-multimedia
bitbake-layers add-layer ../sources/meta-camelpi/

Layers being added:

  • meta-raspberrypi - Raspberry Pi hardware support
  • meta-openembedded/meta-oe - OpenEmbedded core recipes
  • meta-openembedded/meta-python - Python support recipes
  • meta-openembedded/meta-multimedia - Multimedia recipes
  • meta-camelpi - Camel Audio BSP layer

4. Configure Build Settings

Add the required settings to conf/local.conf using echo:

echo 'MACHINE = "raspberrypi5"' >> conf/local.conf
echo 'LICENSE_FLAGS_ACCEPTED = "synaptics-killswitch"' >> conf/local.conf

Or add them all at once:

cat >> conf/local.conf << 'EOF'

MACHINE = "raspberrypi5"
LICENSE_FLAGS_ACCEPTED = "synaptics-killswitch"
EOF

Optional: Enable SSH login for remote access and debugging:

echo 'EXTRA_IMAGE_FEATURES:append = " ssh-server-dropbear allow-empty-password empty-root-password allow-root-login"' >> conf/local.conf

5. Build the Image

bitbake camelpi-image

6. Deploy to SD Card

Use bmaptool to copy the generated .wic.bz2 file to your SD card:

bmaptool copy tmp/deploy/images/raspberrypi5/camelpi-image-raspberrypi5.wic.bz2 /dev/sdX

Replace /dev/sdX with your actual SD card device (e.g., /dev/sdb).

7. Boot Your Raspberry Pi

Insert the SD card into your Raspberry Pi 5 and power it on.

Hardware Requirements

Minimum Requirements

  • Raspberry Pi 5
  • 16GB+ microSD card
  • USB DAC device (primary) OR HiFiBerry Digi+ Pro (fallback)
  • Network connection (Ethernet or WiFi)

Recommended Requirements

  • Raspberry Pi 5 (8GB RAM)
  • 32GB+ microSD card (Class 10/UHS-1 or better)
  • High-quality USB DAC (primary audio output)
  • Optional: HiFiBerry Digi+ Pro for S/PDIF fallback
  • Gigabit Ethernet connection

Usage

Using AirPlay

Stream audio directly from your iOS, macOS, or iTunes device:

  1. Ensure the device is on the same network as the Camel Audio system
  2. On your Apple device, open the AirPlay menu:
    • iOS/iPadOS: Control Center → Music playback card → AirPlay icon
    • macOS: Click the volume icon in the menu bar → AirPlay
    • iTunes: Click the AirPlay icon in the lower right
  3. Select "Camel Audio" from the available AirPlay devices
  4. Start playing audio - it will stream directly to the USB DAC

Note: When AirPlay is active, MPD and UPnP services are automatically paused. They will resume when you disconnect from AirPlay.

Connecting USB DAC

  1. Connect USB DAC to Raspberry Pi
  2. Device automatically detects and configures DAC as the primary audio output

Supported Audio Formats

  • FLAC (up to 24-bit/192kHz)
  • WAV (PCM)
  • AIFF
  • ALAC (Apple Lossless)
  • DSD (DSF/DFF)
  • MP3, AAC (for compatibility)

Development

Initramfs RAM Boot

The system boots from initramfs (initial RAM filesystem) for optimized audio performance:

Configuration

  • Initramfs Image: camelpi-initramfs-image - custom minimal rootfs with audio packages
  • Kernel Bundling: Initramfs is embedded directly in kernel via INITRAMFS_IMAGE_BUNDLE = "1"
  • Root Filesystem: Mounted as /dev/ram0 at boot time
  • Kernel Parameters: root=/dev/ram0 in cmdline.txt
  • Configuration Files:
    • conf/layer.conf - Initramfs image and bundling settings
    • wic/sdimage-camelpi-initramfs.wks - Single partition WIC template
    • recipes-kernel/linux/linux-raspberrypi_%.bbappend - Kernel config files

Benefits

  • Reduced SD card wear (all writes to RAM)
  • Fast boot/shutdown cycles
  • Consistent audio performance without I/O interference

Supported Audio Devices

Primary: USB DAC (Recommended)

  • Any USB Audio Class compliant DAC
  • Automatically detected as ALSA card 0 when connected
  • Supports up to 192kHz/24-bit audio (device dependent)
  • Recommended for best audio quality

Fallback: HiFiBerry Digi+ Pro

  • S/PDIF digital audio output (RCA coaxial connector)
  • Requires GPIO connection to 40-pin header
  • Automatically used when USB DAC is not detected
  • Becomes ALSA card 0 when USB DAC is absent
  • Supports up to 192kHz/24-bit audio via S/PDIF

Device Priority: USB DAC takes priority when both are connected due to kernel USB enumeration order.

Audio Device Verification

To check which audio device is currently active:

# View detection log at boot time
cat /var/log/audio-detect.log

# List all audio cards and PCM devices
aplay -l

# Test audio output (if speaker-test is installed)
speaker-test -D default -c 2 -t wav

Named ALSA devices are available for explicit selection:

# Play through USB DAC explicitly
aplay -D usb_dac /path/to/audio.wav

# Play through HiFiBerry explicitly
aplay -D hifiberry /path/to/audio.wav

USB DAC Audio Configuration

Hardware Setup

  • USB DAC automatically detected as primary audio device
  • ALSA interface available at /proc/asound
  • Bluetooth and WiFi disabled to minimize interference

Configuration

  • Device Tree Overlays and Parameters:

    • dtoverlay=vc4-kms-v3d,noaudio - HDMI output with audio disabled
    • dtparam=audio=off - Disable PWM audio (analog output)
    • dtoverlay=disable-bt-pi5 - Disable Bluetooth
    • dtoverlay=disable-wifi-pi5 - Disable WiFi
    • dtoverlay=hifiberry-digi-pro - Enable HiFiBerry Digi+ Pro S/PDIF output (includes I2S configuration)
    • dtparam=spi=off - Disable SPI interface (unused)
    • Located in: recipes-bsp/bootfiles/rpi-config_git.bbappend

    Note (Pi 5): dtparam=i2s=on does not work on Raspberry Pi 5. The hifiberry-digi-pro overlay includes all necessary I2S configuration.

    Audio Output Configuration Rationale:

    • HDMI audio disabled via noaudio (HDMI video still available)
    • PWM audio disabled via audio=off (analog output not used)
    • I2C kept enabled (required for HiFiBerry WM8804 codec control via I2C bus)
    • I2S enabled implicitly via hifiberry-digi-pro overlay (no separate I2S overlay needed on Pi 5)
    • Only USB DAC (primary) and HiFiBerry Digi+ Pro (fallback) are active
  • CPU Performance Tuning (boot-time configuration):

    • force_turbo=1 - Enable turbo boost for consistent CPU performance
    • arm_freq=1500 - Set CPU frequency to 1500MHz for stable audio processing
    • Located in: recipes-bsp/bootfiles/rpi-config_git.bbappend
  • Kernel Audio Support:

    • CONFIG_SND_USB_AUDIO=y - USB Audio driver (built-in for priority)
      • Located in: recipes-kernel/linux/files/usb-audio.cfg
    • HiFiBerry Digi+ Pro Support (fallback):
      • CONFIG_SND_BCM2835=m - BCM2835 ALSA driver (module)
      • CONFIG_SND_SOC_HIFIBERRY_DIGI=m - HiFiBerry Digi+ Pro driver (module)
      • CONFIG_SND_SOC_WM8804=m - WM8804 codec driver (module)
      • CONFIG_SND_SOC_WM8804_I2C=m - WM8804 I2C interface (module)
      • Located in: recipes-kernel/linux/files/i2s-audio.cfg
    • Modules loaded dynamically when HiFiBerry device tree overlay is active

System Performance Tuning

The Camel Audio platform implements several performance optimizations:

System Startup Order

The services are carefully configured to avoid circular dependencies:

Boot → sysinit → irq-affinity → sound.target → audio-detect
             ↓
         network-online → scx-bpfland → upmpdcli → mpd-camel
                                              ↓
                                      shairport-sync

Service Dependencies:

  • irq-affinity: Starts after sysinit.target

    • Configures IRQ affinity to protect CPU 3 from interrupts
    • Binds all IRQs to CPUs 0-2
    • Runs before all audio services
    • Log file: /var/log/irq-affinity.log
  • audio-detect: Starts after sound.target, before audio services

    • Detects available audio hardware (USB DAC or HiFiBerry Digi+ Pro)
    • Logs detection results to /var/log/audio-detect.log
    • Provides visibility into device priority at boot time
    • Runs before mpd-camel, upmpdcli, and shairport-sync
  • scx-bpfland: Starts after network-online.target (not multi-user.target)

    • Provides dynamic CPU scheduling via BPF
    • Must start early to manage system load
  • mpd-camel: Started as a dependency of upmpdcli

    • FIFO priority 80 (critical audio control)
    • Configured with WantedBy=upmpdcli.service
    • Depends on scx-bpfland.service and audio-detect.service
  • upmpdcli: Starts with multi-user.target

    • Automatically pulls in mpd-camel via Wants=mpd-camel.service
    • FIFO priority 75 (primary playback)
    • Depends on mpd-camel.service
  • networkaudiod: Starts with multi-user.target

    • FIFO priority 75 (NetworkAudio/HQPlayer endpoint)
    • Provides network audio endpoint for HQPlayer streaming
    • Depends on network-online.target

This ordering ensures:

  1. Early system initialization (irq-affinity protects CPU 3 first)
  2. Audio hardware detection before audio services start
  3. CPU scheduler runs before audio services to manage task distribution
  4. Audio services respect the critical path (mpd-camel highest priority)
  5. Avoids circular dependencies between services

CPU Isolation & Scheduling

  • sched_ext Scheduler (scx_bpfland):
    • Dynamic BPF-based scheduler for intelligent task distribution
    • Primary domain: CPU 3 (--primary-domain 0x8)
    • CPU 3 prioritized for audio applications (mpd-camel, upmpdcli, shairport-sync)
    • System services dynamically scheduled by scx_bpfland
    • Automatically balances load: high-priority audio tasks on CPU 3, others overflow to CPUs 0-2
    • Located in: recipes-kernel/scx/files/scx-bpfland.service
  • Interrupt Affinity: irqaffinity=0-2
    • Keeps interrupts on CPUs 0-2
    • Protects CPU 3 from interrupt latency
    • Monitored via irq-affinity.service which logs critical interrupts:
      • USB audio (USB DAC)
      • I2S audio (HiFiBerry Digi+ Pro)
      • I2C control (WM8804 codec configuration)
      • DMA, timer, and system interrupts
    • Log file: /var/log/irq-affinity.log
    • Located in: recipes-bsp/bootfiles/rpi-cmdline.bbappend and recipes-core/systemd/irq-affinity/irq-affinity.sh

Real-Time Process Scheduling

  • mpd-camel: FIFO priority 80 - Music Player Daemon (critical ALSA control point)
  • upmpdcli: FIFO priority 75 - UPnP/DLNA renderer (primary playback method, depends on mpd)
  • Shairport Sync: FIFO priority 70 - AirPlay audio receiver (independent ALSA access)
  • CPU scheduling: Dynamically managed by scx_bpfland based on FIFO priorities and system load
  • Priority inversion prevention: Critical path (mpd-camel) has highest priority

CPU Performance Optimization

  • Turbo Boost: Enabled at boot time for consistent CPU performance
  • Fixed CPU Frequency: Set to 1500MHz to minimize frequency scaling latency
  • Scheduler Tick Frequency: 1000Hz kernel timer (4x more precise than default 250Hz)
    • Provides improved scheduling precision for real-time audio processing
    • Better handling of ultra-low buffer sizes in audio applications
    • Configured via CONFIG_HZ_1000=y in scheduler.cfg
  • Configuration applied via boot-time parameters in rpi-config_git.bbappend and kernel configuration files

ALSA & Audio Buffer Configuration

  • Direct Hardware Access: Using ALSA type hw for bit-perfect audio without sample rate conversion
  • Mixer Disabled: No resampling or signal processing for transparent audio reproduction
  • Bit-Perfect Playback: replaygain "off" ensures strict bit-perfect audio playback without any gain processing
  • MPD Buffer Optimization: buffer_size "8192" provides low-latency playback with excellent stability
    • Tested across 44.1kHz - 192kHz sample rates
    • Balances responsiveness with system load handling
  • Zero-Copy Buffer Management: Minimizes data copying overhead for real-time audio
  • Located in:
    • ALSA config: recipes-multimedia/alsa/alsa-config/asound.conf
    • MPD config: recipes-multimedia/mpd/files/mpd-camel.conf

Memory Management

  • Memory Locking: MemoryLocking=true and LimitMEMLOCK=infinity in mpd-camel.service
    • Prevents audio interruption from memory swapping
    • Keeps critical audio data in physical RAM
    • Configured in: recipes-multimedia/mpd/files/mpd-camel.service

System Tuning Parameters (sysctl)

  • Swap Reduction: vm.swappiness=10 reduces memory swapping to prevent audio latency
  • Cache Optimization: vm.vfs_cache_pressure=50 optimizes filesystem caching for consistent performance
  • Configured via sysctl-tuning recipe
  • Located in: recipes-core/sysctl-tuning/files/99-audio-tuning.conf

Adding Custom Recipes

Place custom recipes in appropriate subdirectories:

meta-camelpi/
├── recipes-camelpi/
│   ├── audio-player/
│   ├── web-interface/
│   └── source-handlers/
├── recipes-core/
│   └── images/
└── conf/

Contributing

Contributions are welcome! Please follow these guidelines:

  • Use clear commit messages
  • Test builds before submitting
  • Document new features
  • Follow Yocto/OE coding standards

License

This layer is licensed under the MIT License. See COPYING.MIT for details.

Support

For issues and feature requests, please use the issue tracker.

Roadmap

  • RAM boot support (initramfs-based system)
  • Roon Ready support (RoonBridge endpoint)
  • Spotify Connect integration
  • Tidal/Qobuz streaming support
  • Multi-room audio synchronization
  • DSP effects and equalizer
  • Bluetooth audio output
  • Mobile app control
  • Gapless playback
  • Playlist management
  • Album art display

Acknowledgments

Built with:

About

Meta layer for Camel Audio, a Raspberry Pi–based Hi-Res audio player.

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors