AudioManager
MicroPythonOS provides a centralized audio service called AudioManager, inspired by Android's architecture. It manages audio playback and recording across different hardware outputs with priority-based audio focus control and a device registry for routing.
Overview
AudioManager provides:
- Priority-based audio focus - Higher priority streams interrupt lower priority ones
- Device registry - Register I2S outputs, PWM buzzers, and microphone inputs
- Session control - Player/Recorder sessions with start/stop/pause/resume
- WAV file support - 8/16/24/32-bit PCM, mono/stereo, auto-upsampling
- WAV recording - 16-bit mono PCM from I2S or ADC microphone
- RTTTL ringtone support - Full Ring Tone Text Transfer Language parser
- Thread-safe - Safe for concurrent access
- Hardware-agnostic - Apps work across all platforms without changes
Supported Audio Devices
- I2S Output: Digital audio output for WAV file playback
- I2S Input: Microphone recording (I2S mic)
- ADC Input: Analog microphone recording via ADC (Fri3d 2026)
- Buzzer: PWM-based tone/ringtone playback
Quick Start
Registering Devices
AudioManager uses a registry of device descriptors instead of direct hardware initialization. Register devices once at startup (typically in your board init file):
from mpos import AudioManager
# I2S speaker
AudioManager.add(
AudioManager.Output(
name="speaker",
kind="i2s",
channels=2,
i2s_pins={"sck": 2, "ws": 47, "sd": 16, "mck": 2},
preferred_sample_rate=44100,
)
)
# I2S microphone
AudioManager.add(
AudioManager.Input(
name="mic",
kind="i2s",
i2s_pins={"sck_in": 17, "ws": 47, "sd_in": 15},
preferred_sample_rate=16000,
)
)
# Buzzer for RTTTL
AudioManager.add(
AudioManager.Output(
name="buzzer",
kind="buzzer",
buzzer_pin=46,
)
)
Playing WAV Files
from mpos import AudioManager
player = AudioManager.player(
file_path="M:/sdcard/music/song.wav",
stream_type=AudioManager.STREAM_MUSIC,
volume=80,
on_complete=lambda msg: print(msg),
)
player.start()
Supported formats: - Encoding: PCM (8/16/24/32-bit) - Channels: Mono or stereo - Sample rate: Any rate (auto-upsampled to ≥8000 Hz)
Playing RTTTL Ringtones
from mpos import AudioManager
rtttl = "Nokia:d=4,o=5,b=225:8e6,8d6,8f#,8g#,8c#6,8b,d,8p,8b,8a,8c#,8e"
player = AudioManager.rtttl_player(
rtttl,
stream_type=AudioManager.STREAM_NOTIFICATION,
)
player.start()
Recording Audio (I2S Mic)
from mpos import AudioManager
recorder = AudioManager.recorder(
file_path="data/my_recording.wav",
duration_ms=10000,
sample_rate=16000,
)
recorder.start()
Recording Audio (ADC Mic)
from mpos import AudioManager
AudioManager.record_wav_adc(
file_path="data/adc_recording.wav",
duration_ms=5000,
sample_rate=16000,
adc_pin=1,
)
Audio Focus Priority
AudioManager implements a 3-tier priority-based audio focus system inspired by Android:
| Stream Type | Priority | Use Case | Behavior |
|---|---|---|---|
| STREAM_ALARM | 2 (Highest) | Alarms, alerts | Interrupts all other streams |
| STREAM_NOTIFICATION | 1 (Medium) | Notifications, UI sounds | Interrupts music, rejected by alarms |
| STREAM_MUSIC | 0 (Lowest) | Music, podcasts | Interrupted by everything |
Priority Rules
- Higher priority interrupts lower priority: ALARM > NOTIFICATION > MUSIC
- Equal priority is rejected: Can't play two alarms simultaneously
- Lower priority is rejected: Can't start music while alarm is playing
Device Routing and Conflicts
AudioManager prevents conflicts by tracking pin usage and sample rates:
- Shared clocks: If two I2S sessions share
ws/sck, they must use the same sample rate. - Conflicts: Starting a new session stops conflicting sessions automatically.
Volume Control
from mpos import AudioManager
AudioManager.set_volume(70)
volume = AudioManager.get_volume()
print(f"Current volume: {volume}")
Volume changes affect active sessions when the stream supports volume adjustment.
API Reference
Device Registration
AudioManager.add(device)
Register a device descriptor.
- Parameters:
device-AudioManager.OutputorAudioManager.Input
AudioManager.get_outputs() / AudioManager.get_inputs()
Return a list of registered devices.
AudioManager.get_default_output() / AudioManager.get_default_input()
Return the default device for playback or recording.
AudioManager.set_default_output(output) / AudioManager.set_default_input(input_device)
Set the default device used when a session does not specify one.
Playback Sessions
AudioManager.player(file_path=None, rtttl=None, stream_type=None, on_complete=None, output=None, sample_rate=None, volume=None)
Create a playback session. For I2S playback use file_path. For RTTTL use rtttl.
- Returns:
Player
AudioManager.rtttl_player(rtttl, **kwargs)
Shortcut for creating an RTTTL player.
AudioManager.get_active_player(stream_type=None, file_path=None)
Return the active Player matching optional filters.
AudioManager.get_active_track(stream_type=None)
Return file path for the active track (if any).
Recording Sessions
AudioManager.recorder(file_path, input=None, sample_rate=None, on_complete=None, duration_ms=None, **adc_config)
Create a recording session. Use an AudioManager.Input descriptor for I2S or ADC input.
- Returns:
Recorder
AudioManager.record_wav_adc(file_path, duration_ms=None, sample_rate=None, adc_pin=None, on_complete=None, **adc_config)
Start an ADC recording session immediately.
Global Control
AudioManager.stop()
Stop all active playback and recording sessions.
AudioManager.set_volume(volume) / AudioManager.get_volume()
Set or get the global volume (0–100).
Player Session Methods
start()/stop()/pause()/resume()is_playing()/is_active()get_progress_percent()/get_progress_ms()/get_duration_ms()
Recorder Session Methods
start()/stop()/pause()/resume()is_recording()/is_active()get_duration_ms()
Hardware Support Matrix
| Board | I2S Output | I2S Mic | ADC Mic | Buzzer | Notes |
|---|---|---|---|---|---|
| Fri3d 2024 Badge | ✅ | ✅ | ❌ | ✅ | Full audio support |
| Fri3d 2026 Badge | ✅ | ❌ | ✅ | ✅ | ADC mic via adc_mic |
| Waveshare ESP32-S3 | ✅ | ❌ | ❌ | ❌ | I2S output only |
| Linux/macOS | ❌ | ✅ (simulated) | ✅ (simulated) | ❌ | Simulated recording for testing |
Troubleshooting
Playback Rejected
Symptom: New playback is rejected or interrupted.
Cause: Higher-priority stream is active or device/pin conflict.
Solution:
1. Use AudioManager.get_active_player() to inspect active streams
2. Stop the active session with AudioManager.stop() if appropriate
3. Use a higher priority stream type
WAV File Not Playing
Requirements: - Encoding: PCM only (not MP3, AAC) - Bit depth: 8, 16, 24, or 32-bit - Channels: Mono or stereo - Sample rate: Any (auto-upsampled to ≥8000 Hz)
See Also
- Creating Apps - Learn how to create MicroPythonOS apps
- WidgetAnimator - Smooth UI animations
- LightsManager - LED control for visual feedback
- SharedPreferences - Store audio preferences