Meeting audio recorder for macOS
Auto-detects calls in Teams, Zoom & Meet · Records system + mic audio · Uploads to Dropbox
UpM3t is a native macOS menu bar utility that detects active meetings in Microsoft Teams, Zoom, and Google Meet, records high-fidelity audio (system output + microphone), and optionally uploads the recording to a Dropbox folder for transcription services like Fireflies.ai.
Built entirely with Apple frameworks. No Electron, no runtime dependencies, no external libraries.
| Feature | Detail |
|---|---|
| Call detection | Polls running apps every 2 s. Inspects window titles for call keywords (Teams/Zoom) or meet.google.com in browser tabs (Meet). Cross-references microphone activity to reduce false positives. |
| Dual-stream recording | System audio via ScreenCaptureKit + microphone via AVAudioEngine, merged into a single AAC .m4a file (256 kbps, 48 kHz, stereo). |
| Dropbox upload | Uploads finished recordings to /Meet in Dropbox via the content upload API. Fireflies.ai or any service monitoring that folder picks them up automatically. |
| Consent gate | A recording consent notice is displayed before every recording starts — both in the popup and from the menu. |
| Auto-cleanup | Configurable auto-deletion of local audio files after 3, 7, or 15 days. Manual bulk delete available. Logs trim automatically every 30 days. |
| Secure storage | Dropbox access token stored in macOS Keychain (Security.framework), not in UserDefaults. Automatic one-time migration for existing installs. |
| Global hotkey | ⌘⇧R toggles recording from anywhere. |
git clone https://github.com/YOUR_USERNAME/UpM3t.git
cd UpM3t
open UpM3t.xcodeproj # ⌘R to build and run
Or from the command line:
make build # debug
make release # optimized
make clean # remove artifacts
On first use, macOS prompts for:
| Permission | Purpose |
|---|---|
| Microphone | Record the user’s voice |
| Screen & Audio Recording | Capture system audio (remote participants) |
| Notifications | Alert when a meeting is detected |
UpM3t captures audio streams only. Video frames from ScreenCaptureKit are discarded by a dummy handler.
files.content.write, files.content.readRecordings upload to /Meet. The folder is created automatically on first upload.
UpM3t/Sources/
├── App/
│ ├── UpM3tApp.swift SwiftUI @main, menu-bar-only scene
│ ├── AppDelegate.swift Lifecycle, global hotkey (⌘⇧R), notification permission
│ └── AppState.swift Observable state, recording flow, upload, maintenance
├── Models/
│ ├── MeetingApp.swift Platform enum (Teams, Zoom, Meet + browsers)
│ └── RecordingEntry.swift History model, Codable persistence, file operations
├── Services/
│ ├── AudioRecorder.swift SCStream (system) + AVAudioEngine (mic), merge → .m4a
│ ├── DropboxService.swift Upload to /Meet, token validation, folder creation
│ ├── MeetingDetector.swift Window-title polling, mic-state checks, debounced transitions
│ └── MeetingNameResolver.swift Extract meeting names from window titles
├── Views/
│ ├── StatusBarController.swift NSStatusItem, right-click menu, popover, restart/quit
│ ├── PopupRecorderView.swift Call-detected popup with countdown, consent text
│ ├── PreferencesView.swift Tabs: Permissions, Dropbox, General, Logs
│ └── HistoryView.swift Recording list with delete/open/status badges
└── Utilities/
├── Constants.swift Keys, audio config, polling intervals, UI sizing
├── Extensions.swift Date, TimeInterval, String, NSImage helpers
└── KeychainService.swift SecItem wrapper for secure token storage
┌──────────────┐ ┌──────────────────┐ ┌────────────┐ ┌──────────┐
│ SCStream │──▶│ _system.caf │──▶│ │ │ │
│ (system audio)│ │ │ │ AVAsset │──▶│ .m4a │
│ │ └──────────────────┘ │ Export │ │ output │
│ AVAudioEngine │──▶│ _mic.caf │──▶│ Session │ │ │
│ (microphone) │ │ │ │ │ │ │
└──────────────┘ └──────────────────┘ └────────────┘ └──────────┘
Both streams are written to separate .caf files in the native format reported by each source. After recording stops, they are merged into a single .m4a via AVMutableComposition + AVAssetExportSession. If one stream is empty or invalid, the other is exported directly. If the merge fails, the raw file is copied as a fallback.
| Platform | Method |
|---|---|
| Teams | Window title keywords (meeting, call, reunión, sharing, etc.) + significant window count + mic active |
| Zoom | Zoom Meeting / Zoom Webinar in window title, or large window (>500×350) + mic active |
| Meet | Browser window title must contain meet.google.com literally + mic active |
State transitions are debounced: 3 consecutive “not in call” polls (~6 s) required before confirming call end.
| Tab | Options |
|---|---|
| Permissions | View/request Microphone, Screen Recording, Notifications |
| Dropbox | Access token, upload toggle, Test & Save |
| General | Auto-record on call, Launch at login, Auto-delete (Never / 3 / 7 / 15 days), Recordings folder |
| Logs | Activity viewer, Copy All, Clear (auto-cleans every 30 days) |
Left-click opens the recorder popup. Right-click opens the context menu:
| Aspect | Implementation |
|---|---|
| Token storage | Dropbox access token in macOS Keychain via Security.framework. Migrated from UserDefaults on first run. |
| Audio only | SCStreamConfiguration set to 2×2 px video with audio capture. Video frames discarded by DummyVideoOutput. |
| No telemetry | No analytics, no crash reporting, no network calls except Dropbox API when upload is enabled. |
| No account | No sign-up, no login, no server. Fully offline capable. |
| Consent gate | Recording consent notice shown before every recording — popup and menu. |
| Auto-cleanup | Local files auto-deleted after configurable retention period. |
| Open source | Full source code auditable under MIT license. |
The app contacts only content.dropboxapi.com and api.dropboxapi.com, and only when Dropbox upload is enabled and a token is configured. No other outbound connections.
This application acts solely as a technical conduit. The user acknowledges responsibility for the custody of their files on the destination platform (Dropbox) and for ensuring that recorded content does not infringe on the intellectual property or privacy rights of third parties. The application is provided “as is”, without warranties of any kind regarding the integrity of the recordings.
See CONTRIBUTING.md.
See SECURITY.md.