To record audio with Raspberry Pi, you must bypass the board's lack of an onboard analog-to-digital converter (ADC). The 3.5mm jack is strictly an audio output. For embedded, headless, or low-latency applications, the definitive hardware choice is wiring an I2S MEMS microphone directly to the GPIO header. This avoids USB polling overhead, eliminates analog noise floors, and draws minimal current.

This guide targets the Raspberry Pi 5 (4GB) running Pi OS Bookworm (64-bit, Lite). We will use the Adafruit SPH0645LM4H I2S MEMS breakout, configure the ALSA sound subsystem, and write a robust Python script to capture WAV files.

The Hardware Decision: How to Get Audio INTO a Pi

Before wiring anything, you must choose your input topology. Here is the decision framework for Pi audio input:

MethodHardware ExampleLatency & QualityBest Use Case
USB Analog Sound CardSabrent USB External Adapter ($8)High latency, prone to USB bus noise and ground loops.Quick desktop prototyping where GPIO is unavailable.
USB Digital MicrophoneBlue Snowball or Mini USB Mic ($15-$50)Medium latency, good quality, but bulky and requires USB hub power.Desktop voice assistants, Pi 4/5 desktop setups.
I2S MEMS BreakoutAdafruit SPH0645LM4H ($8.50)Lowest latency, digital noise immunity, tiny footprint.Headless embedded builds, battery-powered IoT, custom HATs.
Decision Path Termination: If your project is a headless sensor node, a battery-powered wildlife recorder, or requires strict timing, choose the I2S MEMS (SPH0645LM4H). If you just need a quick desktop dictation mic and have a free USB port, buy a generic USB mini-mic and skip the GPIO wiring.

Parts List & Pin Mapping

The SPH0645LM4H is a 24-bit I2S microphone. It requires three shared I2S lines and power. Note that I2S on the Raspberry Pi uses dedicated hardware pins (PCM), not arbitrary GPIOs.

Bill of Materials (2026 Pricing)

ComponentExact Variant / Part NumberEst. Cost
Compute BoardRaspberry Pi 5 (4GB RAM)$60.00
MicrophoneAdafruit I2S MEMS Breakout (PID: 3421 / SPH0645LM4H)$8.50
WiringSilicone jumper wires (Female-to-Female, 26 AWG)$6.00
Storage32GB microSD (SanDisk Extreme Pro A2)$9.00

GPIO Pin Mapping (BCM Numbering)

MEMS Breakout PinRaspberry Pi 5 GPIO (BCM)Physical Pin #Function
VIN3V31 or 17Power (3.3V logic)
GNDGND6, 9, etc.Common Ground
BCLK (Bit Clock)GPIO 18 (PCM_CLK)12I2S Clock Signal
DOUT (Data Out)GPIO 20 (PCM_DIN)38I2S Data from Mic
LRCL (Word Select)GPIO 19 (PCM_FS)35Left/Right Channel Sync
SELLeave Unconnected (or tie to GND)N/ATie to GND for Left channel, 3V3 for Right

OS Configuration: Enabling the I2S Bus

In Pi OS Bookworm, the boot partition path changed. Older tutorials tell you to edit /boot/config.txt, which will fail or be ignored on modern Pi OS. You must edit the firmware config.

  1. Open the configuration file: sudo nano /boot/firmware/config.txt
  2. Find the line #dtparam=i2s=on and uncomment it (remove the #). If it doesn't exist, add it to the bottom.
  3. Add the I2S memory-mapped overlay at the very bottom of the file:
    dtoverlay=i2s-mmap
  4. Save and exit (Ctrl+O, Enter, Ctrl+X).
  5. Reboot the Pi: sudo reboot

After rebooting, verify the kernel loaded the I2S driver by checking ALSA recording devices:

arecord -l

You should see output similar to card 1: sndrpii2scard [snd_rpi_i2s_card], device 0: .... Note the card and device numbers.

Python Recording Script (Sounddevice + Wave)

We use the sounddevice library rather than pyaudio because it handles PortAudio bindings much more cleanly on 64-bit ARM architectures without requiring manual C-compilation of the PortAudio source tree.

Install the required system dependencies and Python packages:

sudo apt update
sudo apt install libportaudio2
pip3 install sounddevice numpy --break-system-packages

Note: Use a virtual environment (python3 -m venv audio_env) in production to avoid the --break-system-packages flag, which is required here only for global Pi OS Bookworm pip installs.

Complete Recording Script

import sounddevice as sd
import numpy as np
import wave
import sys
import time

# TARGET BOARD: Raspberry Pi 5 (4GB) / Pi OS Bookworm 64-bit
# HARDWARE: Adafruit SPH0645LM4H I2S MEMS Breakout
# I2S PINS: BCLK=GPIO18, DOUT=GPIO20, LRCL=GPIO19

# Configuration
DEVICE_INDEX = 1      # Verify via `python3 -m sounddevice`. Usually 1 if HDMI is 0.
CHANNELS = 1          # CRITICAL: SPH0645 is strictly MONO. Do not set to 2.
SAMPLE_RATE = 44100   # Standard CD quality
DURATION_SEC = 5.0    # Recording length
OUTPUT_FILE = 'i2s_capture.wav'

def record_audio():
    print(f'Initializing I2S capture on Device {DEVICE_INDEX}...')
    
    # Calculate total frames
    total_frames = int(DURATION_SEC * SAMPLE_RATE)
    
    try:
        print(f'Recording {DURATION_SEC} seconds... Speak now.')
        
        # Capture audio into a numpy array
        audio_data = sd.rec(
            frames=total_frames,
            samplerate=SAMPLE_RATE,
            channels=CHANNELS,
            dtype='int16',
            device=DEVICE_INDEX,
            blocking=True
        )
        
        print('Capture complete. Writing to WAV file...')
        
        # Write to WAV
        with wave.open(OUTPUT_FILE, 'w') as wf:
            wf.setnchannels(CHANNELS)
            wf.setsampwidth(2)  # 16-bit audio = 2 bytes per sample
            wf.setframerate(SAMPLE_RATE)
            wf.writeframes(audio_data.tobytes())
            
        print(f'Successfully saved to {OUTPUT_FILE}')
        
    except sd.PortAudioError as e:
        print(f'[FATAL] PortAudio Error: {e}')
        print('Check `arecord -l` and ensure CHANNELS matches hardware (Mono=1).')
        sys.exit(1)
    except Exception as e:
        print(f'[FATAL] Unexpected Error: {e}')
        sys.exit(1)

if __name__ == '__main__':
    # Print available devices for debugging before attempting capture
    print('--- Available Audio Devices ---')
    print(sd.query_devices())
    print('-------------------------------')
    record_audio()

Debugging: 'Invalid number of channels' and ALSA Errors

When working with I2S on Linux, ALSA (Advanced Linux Sound Architecture) errors are notoriously cryptic. Here is the exact error string you will encounter if your channel configuration mismatches the hardware:

Exact Error String:
sounddevice.PortAudioError: Error opening InputStream: Invalid number of channels [PaErrorCode -9998]

Ranked Causes and Fixes

  1. Cause 1: Channel Count Mismatch (Most Likely). The SPH0645LM4H is a single-channel (mono) MEMS sensor. If your Python script requests channels=2 (stereo), PortAudio will ask ALSA for a stereo stream from a mono hardware device, triggering -9998. Fix: Ensure CHANNELS = 1 in the script.
  2. Cause 2: Wrong Device Index. The Pi 5 routes HDMI audio as Device 0. If your I2S mic is Device 1, but your script targets Device 0, it will fail to open a recording stream on an output-only device. Fix: Run python3 -m sounddevice to find the exact index of the snd_rpi_i2s_card and update DEVICE_INDEX.
  3. Cause 3: PipeWire Interference. If you are running the Desktop version of Pi OS instead of Lite, PipeWire may have hijacked the ALSA device. Fix: Stop PipeWire (systemctl --user stop pipewire) or switch to Pi OS Lite for embedded deployments.

The First 3 Things to Check When Audio Fails

If you get no sound or ALSA throws a No such file or directory error regarding confmisc.c, run this diagnostic triage:

  1. Verify the Overlay: Run cat /boot/firmware/config.txt | grep i2s. Ensure dtparam=i2s=on is uncommented and dtoverlay=i2s-mmap is present.
  2. Verify ALSA Recognition: Run arecord -l. If the I2S card does not appear, the kernel failed to probe the driver. Check your physical wiring, specifically GPIO 18 (Clock).
  3. Verify Hardware Format: Run arecord -D hw:1,0 -f S32_LE -r 44100 -c 1 test.wav. This bypasses Python and tests the raw ALSA driver. If this works but Python fails, your issue is strictly in the PortAudio Python bindings.

Extending and Simplifying the Build

How to Simplify (The Desktop Route)

If you realize I2S configuration is overkill for your needs, simplify the build by purchasing a generic USB 2.0 Mini Microphone (usually based on the C-Media CM108 chipset, ~$10). Plug it into a USB port, change DEVICE_INDEX to the USB mic's index, and delete the dtoverlay lines from config.txt. You sacrifice latency and introduce USB bus noise, but you gain plug-and-play simplicity.

How to Extend (Push-to-Talk & Edge AI)

To turn this into an embedded voice-command node:

  • Add a GPIO Trigger: Wire a momentary push-button to GPIO 21 with a 10k pull-down resistor. Use the gpiozero library to detect the button press, replacing the fixed DURATION_SEC with a loop that records until the button is released.
  • Edge Inference: Pipe the captured numpy array directly into a local Vosk offline speech recognition model instead of writing to a WAV file. This allows the Pi to process wake-words entirely offline, which is critical for privacy-focused IoT devices.

For embedded audio capture on the Raspberry Pi, hardwiring an I2S MEMS microphone remains the most robust, lowest-noise architecture available. By locking down the ALSA configuration in Bookworm and strictly enforcing mono channel parameters in Python, you eliminate the driver-level ambiguities that plague most Pi audio projects.