UpM3t

UpM3t

UpM3t

Meeting audio recorder for macOS
Auto-detects calls in Teams, Zoom & Meet · Records system + mic audio · Uploads to Dropbox

macOS 13+ Swift 5.9 Zero deps MIT


Overview

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.

Core Capabilities

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.

Getting Started

Requirements

Build

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

Permissions

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.

Dropbox Setup (optional)

  1. Create an app at dropbox.com/developers/apps
  2. Enable scopes: files.content.write, files.content.read
  3. Generate an access token under Settings
  4. Paste it in Preferences → Dropbox → Test & Save

Recordings upload to /Meet. The folder is created automatically on first upload.


Architecture

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

Recording Pipeline

┌──────────────┐   ┌──────────────────┐   ┌────────────┐   ┌──────────┐
│ 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.

Call Detection Strategy

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.


Configuration

Preferences (right-click → Preferences)

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:


Security & Privacy

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.

Network Access

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.


Contributing

See CONTRIBUTING.md.

Security Policy

See SECURITY.md.

License

MIT