CLI tool for recording online meeting audio (mic + system sound)
Project description
Omni Meeting Recorder (omr)
日本語 | English
A Windows CLI tool for recording online meeting audio. Capture both remote participants' voices (system audio) and your own voice (microphone) simultaneously, even when using speakers or headphones.
Features
- System Audio Recording (Loopback): Capture audio output to speakers/headphones
- Microphone Recording: Record microphone input
- Simultaneous Recording: Record both mic and system audio together (default mode)
- Acoustic Echo Cancellation (AEC): Software echo cancellation for speaker use
- Automatic Volume Normalization: Match mic and system audio levels
- MP3 Output: Direct MP3 encoding with configurable bitrate
- No Virtual Audio Cable Required: Direct WASAPI Loopback support
- Live Device Switching: Switch mic/loopback devices during recording via keyboard
- Simple CLI: Start recording with a single command
Documentation
- Concept - Why this tool exists and design principles
- Technical Design - Architecture and implementation details
- Contributing - Development guidelines
Requirements
- Windows 10/11
For source installation only (not needed for portable version):
- Python 3.11 - 3.13 (3.14+ not yet supported due to lameenc dependency)
- uv (recommended) or pip
Installation
Portable Version (Recommended, No Python Required)
Download the pre-built portable version from Releases:
- Download
omr-{version}-windows-x64.zip - Extract to any folder
- Run
omr.exefrom the extracted folder
# Example usage
.\omr.exe --version
.\omr.exe devices
.\omr.exe start -o meeting.mp3
Try Without Installing
If you have uv installed, you can try omr immediately:
uvx --from omni-meeting-recorder omr start
Or install as a global tool:
uv tool install omni-meeting-recorder
omr start
1. Install Python
If Python 3.11+ is not installed:
- Download Windows installer from Python official site
- Run installer with "Add Python to PATH" checked
- Verify in PowerShell:
python --version # Should show Python 3.11.x or higher
2. Install uv (Recommended)
uv is a fast Python package manager.
Run in PowerShell:
# Install uv
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
# Verify installation
uv --version
Or install via pip:
pip install uv
3. Install omr
Option A: Clone from GitHub (for developers)
# Clone repository
git clone https://github.com/dobachi/omni-meeting-recorder.git
cd omni-meeting-recorder
# Install dependencies
uv sync
# Verify installation
uv run omr --version
uv run omr --help
Option B: Install via pip (for users)
# Install from PyPI
pip install omni-meeting-recorder
# Verify installation
omr --version
Usage
omr start
That's it! Press Ctrl+C to stop. Output: recording_YYYYMMDD_HHMMSS.mp3
Quick Start
# List available devices
omr devices
# Record with custom filename
omr start -o meeting.mp3
# Record system audio only
omr start -L -o system.mp3
# Record microphone only
omr start -M -o mic.mp3
# Disable AEC (if using headphones)
omr start --no-aec -o meeting.mp3
# Output as WAV instead of MP3
omr start -f wav -o meeting.wav
# Stereo split mode (left=mic, right=system)
omr start --stereo-split -o meeting.mp3
# Specify device by index
omr start --loopback-device 5 --mic-device 0 -o meeting.mp3
Keyboard Controls During Recording
While recording, you can use these keyboard shortcuts:
| Key | Function |
|---|---|
m |
Enter mic selection mode → press 0-9 to select device |
l |
Enter loopback selection mode → press 0-9 to select device |
0-9 |
Select device by number (in selection mode) |
Esc |
Cancel device selection |
q |
Stop recording (same as Ctrl+C) |
r |
Refresh device list |
Press Ctrl+C or q to stop recording.
Testing Your Setup
Step 1: Check Device List
# If installed with uv
uv run omr devices
# If installed with pip
omr devices
Expected output:
Recording Devices
┏━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━┓
┃ Index ┃ Type ┃ Name ┃ Channels ┃ Sample Rate ┃ Default ┃
┡━━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━┩
│ 0 │ MIC │ Microphone (Realtek Audio) │ 2 │ 44100 Hz │ * │
│ 3 │ LOOP │ Speakers (Realtek Audio) │ 2 │ 48000 Hz │ │
└────────┴──────────┴────────────────────────────────┴────────────┴──────────────┴──────────┘
- MIC: Microphone devices
- LOOP: Loopback devices (can capture system audio)
- *: Default device
Step 2: Test Default Recording (Mic + System)
- Play audio (e.g., YouTube) and speak into the microphone
- Start recording:
uv run omr start -o test.mp3
- Wait a few seconds, then press
Ctrl+Cto stop - Play the generated MP3 to verify both sources are captured
Step 3: Test System Audio Only
uv run omr start -L -o system.mp3
Step 4: Test Microphone Only
uv run omr start -M -o mic.mp3
Commands
omr devices
List available audio devices.
omr devices # Recording devices (mic + loopback)
omr devices --all # All devices (including output)
omr devices --mic # Microphone only
omr devices --loopback # Loopback devices only
omr start
Start recording. By default, records both mic and system audio with AEC enabled.
omr start # Record mic + system (default)
omr start -o meeting.mp3 # Specify output file
omr start -L # Record system audio only (--loopback-only)
omr start -M # Record microphone only (--mic-only)
omr start --no-aec # Disable echo cancellation
omr start --stereo-split # Stereo: left=mic, right=system
omr start -f wav # Output as WAV instead of MP3
omr start -b 192 # MP3 bitrate 192kbps (default: 128)
Options:
| Option | Description |
|---|---|
-o, --output |
Output file path |
-L, --loopback-only |
Record system audio only |
-M, --mic-only |
Record microphone only |
--aec/--no-aec |
Enable/disable echo cancellation (default: enabled) |
--stereo-split/--mix |
Stereo split or mix mode (default: mix) |
-f, --format |
Output format: wav, mp3 (default: mp3, direct streaming) |
-b, --bitrate |
MP3 bitrate in kbps (default: 128) |
--post-convert |
Record to WAV first, then convert to MP3 (legacy mode) |
--keep-wav |
Keep WAV file after MP3 conversion (only with --post-convert) |
--mic-device |
Microphone device index |
--loopback-device |
Loopback device index |
--mic-gain |
Microphone gain multiplier (default: 1.5) |
--loopback-gain |
System audio gain multiplier (default: 1.0) |
omr config
Manage configuration settings. Settings are saved to a config file and used as defaults.
omr config show # Show all settings
omr config show audio.mic_gain # Show specific setting
omr config set audio.mic_gain 2.0 # Set a value
omr config reset # Reset to defaults
omr config path # Show config file path
omr config init # Create config file with defaults
omr config edit # Open config file in editor
Available Settings:
| Key | Description | Default |
|---|---|---|
device.mic |
Default microphone device (name or index) | - |
device.loopback |
Default loopback device (name or index) | - |
audio.mic_gain |
Microphone gain multiplier | 1.5 |
audio.loopback_gain |
System audio gain multiplier | 1.0 |
audio.aec_enabled |
Acoustic Echo Cancellation | true |
audio.stereo_split |
Stereo split mode | false |
audio.mix_ratio |
Mic/system mix ratio (0.0-1.0) | 0.5 |
output.format |
Output format (mp3/wav) | mp3 |
output.bitrate |
MP3 bitrate in kbps | 128 |
output.directory |
Default output directory | - |
Config File Location:
- Windows:
%APPDATA%\omr\config.toml - Linux/macOS:
~/.config/omr/config.toml - Custom: Set
OMR_CONFIGenvironment variable
Example config.toml:
[device]
mic = "Microphone (Realtek Audio)"
loopback = "Speakers (Realtek Audio)"
[audio]
mic_gain = 2.0
loopback_gain = 1.0
aec_enabled = true
stereo_split = false
[output]
format = "mp3"
bitrate = 192
directory = "~/Recordings"
Troubleshooting
"No devices found"
- Check that audio devices are enabled in Windows Sound settings
- Go to "Sound settings" → "Sound Control Panel" and enable disabled devices
Loopback device not showing
- Verify output device (speakers/headphones) is connected and enabled
- Ensure WASAPI-compatible audio driver is installed
Recording file is silent
- Verify system audio is actually playing during recording
- Check you're selecting the correct device with
omr devices --all - Try a different loopback device:
--loopback-device <index>
PyAudioWPatch installation error
PyAudioWPatch only supports Windows. On Linux/macOS, only tests can be run.
# Manually install PyAudioWPatch
pip install PyAudioWPatch
SSL Certificate Errors (Corporate Proxy / Zscaler)
If you're behind a corporate proxy or security tool like Zscaler, you may encounter SSL certificate errors such as:
certificate verify failed: unable to get local issuer certificateSSL: CERTIFICATE_VERIFY_FAILED
Solution 1: Use Native TLS (Recommended)
Set the environment variable to use your system's certificate store:
# PowerShell - temporary (current session only)
$env:UV_NATIVE_TLS = "true"
# PowerShell - permanent (user environment)
[Environment]::SetEnvironmentVariable("UV_NATIVE_TLS", "true", "User")
# Then run uv/uvx commands as usual
uvx --from omni-meeting-recorder omr --help
Solution 2: Specify Certificate File Directly
If your IT department provides a certificate bundle:
$env:SSL_CERT_FILE = "C:\path\to\corporate-ca-bundle.pem"
Solution 3: Use --native-tls Flag
Add the flag to individual commands:
uv --native-tls sync
uv --native-tls run omr start
Reference:
Acoustic Echo Cancellation (AEC)
When recording both mic and system audio while using speakers, the microphone picks up audio from the speakers. This causes echo in the recording.
Solution: AEC is enabled by default and removes this echo using the pyaec library.
# AEC is enabled by default
omr start -o meeting.mp3
# Disable AEC if using headphones (slightly better audio quality)
omr start --no-aec -o meeting.mp3
Note: For best results, use headphones when possible. AEC works well but headphones provide the cleanest audio.
Automatic Volume Normalization
Microphone and system audio often have significantly different volume levels. For example, if mic input is quiet while system audio is loud, the recorded audio will be unbalanced.
Solution: Automatic Gain Control (AGC) is enabled by default, normalizing both audio sources to a target level (~25% of 16-bit peak).
- Continuously measures RMS (Root Mean Square) of both mic and system audio
- Calculates average level from recent audio chunks
- Normalizes both sources to the same target level
- Gain is automatically adjusted within 0.5x to 6.0x range
Development
Setup Development Environment
# Install dependencies (including dev)
uv sync --extra dev
Building Portable Version
Create a standalone Windows executable (no Python required):
# Install build dependencies
uv sync --extra dev --group build
# Build portable version
uv run task build-portable
# Output:
# dist/omr/omr.exe - Standalone executable
# dist/omr-{version}-windows-x64.zip - Distribution ZIP (~15MB)
Build options:
uv run task build-portable --clean # Clean build directories first
uv run task build-portable --no-zip # Skip ZIP creation
Running Checks
Use uv run task to run linting, type checking, and tests:
# Run all checks (lint + typecheck + test)
uv run task check
# Or run individually:
uv run task lint # Run ruff linter
uv run task typecheck # Run mypy type checker
uv run task test # Run pytest
# Other useful commands:
uv run task lint-fix # Auto-fix lint issues
uv run task format # Format code with ruff
uv run task test-cov # Run tests with coverage
Project Structure
omni-meeting-recorder/
├── src/omr/
│ ├── cli/
│ │ ├── main.py # CLI entry point
│ │ └── commands/
│ │ ├── record.py # Recording command
│ │ └── devices.py # Device list
│ ├── core/
│ │ ├── audio_capture.py # Audio capture abstraction
│ │ ├── device_manager.py # Device detection/management
│ │ ├── input_handler.py # Keyboard input handling
│ │ └── mixer.py # Audio mixing/resampling
│ ├── backends/
│ │ └── wasapi.py # Windows WASAPI implementation
│ └── config/
│ └── settings.py # Settings management
├── tests/
├── pyproject.toml
└── README.md
Roadmap
-
Phase 1: MVP
- Device list display
- System audio recording (Loopback)
- Microphone recording
- WAV format output
- Stop with Ctrl+C
-
Phase 2: Simultaneous Recording
- Mic + system audio simultaneous recording
- Stereo split mode (left=mic, right=system)
- Timestamp synchronization
-
Phase 3: Audio Processing
- MP3 output support
- Acoustic Echo Cancellation (AEC)
- Automatic volume normalization
- FLAC output support
-
Phase 4: Distribution
- Portable build support (PyInstaller)
- GitHub Actions automated release build
- Release page with portable ZIP download
-
Phase 5: Stability & UX
- Live device switching via keyboard
- Configuration file support
- Long-duration recording stability
- Device disconnection handling
- Recording status display improvements
- Background recording support
-
Phase 6: Timer Features
- Soft timer (--soft-timer): notification only, recording continues
- Hard timer (--hard-timer): automatic recording stop
- Scheduled recording (--start-at / --end-at)
- Remaining/elapsed time display
- Timer settings in config file
License
MIT License
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file omni_meeting_recorder-0.7.2.tar.gz.
File metadata
- Download URL: omni_meeting_recorder-0.7.2.tar.gz
- Upload date:
- Size: 86.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b7ca47850a94b123ca862bafc3fdabbc7840f467ed606f22deed474166904c8d
|
|
| MD5 |
dbbf7de6d2ab3e34da2ea3c3a5ae82bc
|
|
| BLAKE2b-256 |
2a8f8c3a0766d1e20e7e8fb054da9de9ec7360018ed524daf65a5a004174f4dd
|
Provenance
The following attestation bundles were made for omni_meeting_recorder-0.7.2.tar.gz:
Publisher:
publish.yml on dobachi/omni-meeting-recorder
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
omni_meeting_recorder-0.7.2.tar.gz -
Subject digest:
b7ca47850a94b123ca862bafc3fdabbc7840f467ed606f22deed474166904c8d - Sigstore transparency entry: 883512352
- Sigstore integration time:
-
Permalink:
dobachi/omni-meeting-recorder@369d031cea1de7bff736e6d102750c20ab295973 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/dobachi
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@369d031cea1de7bff736e6d102750c20ab295973 -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file omni_meeting_recorder-0.7.2-py3-none-any.whl.
File metadata
- Download URL: omni_meeting_recorder-0.7.2-py3-none-any.whl
- Upload date:
- Size: 49.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b579ebce75d5931ee1f790aacba0467345bed696e92dfc93859ce30c2e1ff049
|
|
| MD5 |
ed733dffbf1d1c5b214e4dde843c054a
|
|
| BLAKE2b-256 |
f3b4e6b4b4d0a0241d5c88123e37f351decbd0eb3575bd779c3ef1d62c504402
|
Provenance
The following attestation bundles were made for omni_meeting_recorder-0.7.2-py3-none-any.whl:
Publisher:
publish.yml on dobachi/omni-meeting-recorder
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
omni_meeting_recorder-0.7.2-py3-none-any.whl -
Subject digest:
b579ebce75d5931ee1f790aacba0467345bed696e92dfc93859ce30c2e1ff049 - Sigstore transparency entry: 883512415
- Sigstore integration time:
-
Permalink:
dobachi/omni-meeting-recorder@369d031cea1de7bff736e6d102750c20ab295973 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/dobachi
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@369d031cea1de7bff736e6d102750c20ab295973 -
Trigger Event:
workflow_dispatch
-
Statement type: