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:
| Method | Hardware Example | Latency & Quality | Best Use Case |
|---|---|---|---|
| USB Analog Sound Card | Sabrent USB External Adapter ($8) | High latency, prone to USB bus noise and ground loops. | Quick desktop prototyping where GPIO is unavailable. |
| USB Digital Microphone | Blue 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 Breakout | Adafruit SPH0645LM4H ($8.50) | Lowest latency, digital noise immunity, tiny footprint. | Headless embedded builds, battery-powered IoT, custom HATs. |
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)
| Component | Exact Variant / Part Number | Est. Cost |
|---|---|---|
| Compute Board | Raspberry Pi 5 (4GB RAM) | $60.00 |
| Microphone | Adafruit I2S MEMS Breakout (PID: 3421 / SPH0645LM4H) | $8.50 |
| Wiring | Silicone jumper wires (Female-to-Female, 26 AWG) | $6.00 |
| Storage | 32GB microSD (SanDisk Extreme Pro A2) | $9.00 |
GPIO Pin Mapping (BCM Numbering)
| MEMS Breakout Pin | Raspberry Pi 5 GPIO (BCM) | Physical Pin # | Function |
|---|---|---|---|
| VIN | 3V3 | 1 or 17 | Power (3.3V logic) |
| GND | GND | 6, 9, etc. | Common Ground |
| BCLK (Bit Clock) | GPIO 18 (PCM_CLK) | 12 | I2S Clock Signal |
| DOUT (Data Out) | GPIO 20 (PCM_DIN) | 38 | I2S Data from Mic |
| LRCL (Word Select) | GPIO 19 (PCM_FS) | 35 | Left/Right Channel Sync |
| SEL | Leave Unconnected (or tie to GND) | N/A | Tie 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.
- Open the configuration file:
sudo nano /boot/firmware/config.txt - Find the line
#dtparam=i2s=onand uncomment it (remove the#). If it doesn't exist, add it to the bottom. - Add the I2S memory-mapped overlay at the very bottom of the file:
dtoverlay=i2s-mmap - Save and exit (Ctrl+O, Enter, Ctrl+X).
- 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:
sounddevice.PortAudioError: Error opening InputStream: Invalid number of channels [PaErrorCode -9998]
Ranked Causes and Fixes
- 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: EnsureCHANNELS = 1in the script. - 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 sounddeviceto find the exact index of thesnd_rpi_i2s_cardand updateDEVICE_INDEX. - 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:
- Verify the Overlay: Run
cat /boot/firmware/config.txt | grep i2s. Ensuredtparam=i2s=onis uncommented anddtoverlay=i2s-mmapis present. - 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). - 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
gpiozerolibrary to detect the button press, replacing the fixedDURATION_SECwith a loop that records until the button is released. - Edge Inference: Pipe the captured
numpyarray 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.






