summaryrefslogtreecommitdiff
path: root/modules
diff options
context:
space:
mode:
authorCraig Jennings <c@cjennings.net>2025-11-03 14:20:36 -0600
committerCraig Jennings <c@cjennings.net>2025-11-03 14:20:36 -0600
commit9f8aec55033d46ca4f1cd78fbd315444a0c00bc6 (patch)
treeb7b88876d06aaf2846bb535dc7b89285771b979c /modules
parent6624bc48bd9c2c784f41fdf406ec0a73a23adf75 (diff)
feat: Add quick setup for call recording with automatic device pairing
Users needed a faster way to configure audio for call recording. This adds cj/recording-quick-setup-for-calls which automatically groups audio devices by hardware and lets users pick one device for both mic and monitor. Key improvements: - Groups devices by hardware (USB, built-in, Bluetooth) - Normalizes Bluetooth MAC addresses (handles colon/underscore formats) - Shows friendly device names (e.g., "Jabra SPEAK 510 USB") - Automatically pairs mic + monitor from same device - Bound to C-; r c for quick access Perfect for recording video calls where you need to capture both your voice and the remote person's voice through the same audio device. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Diffstat (limited to 'modules')
-rw-r--r--modules/video-audio-recording.el72
1 files changed, 71 insertions, 1 deletions
diff --git a/modules/video-audio-recording.el b/modules/video-audio-recording.el
index bd0a0b22..de770623 100644
--- a/modules/video-audio-recording.el
+++ b/modules/video-audio-recording.el
@@ -149,6 +149,74 @@ Sets cj/recording-mic-device and cj/recording-system-device."
cj/recording-mic-device
cj/recording-system-device))
+(defun cj/recording-group-devices-by-hardware ()
+ "Group audio sources by hardware device.
+Returns alist of (device-name . (mic-source . monitor-source))."
+ (let ((sources (cj/recording-parse-sources))
+ (devices (make-hash-table :test 'equal))
+ (result nil))
+ ;; Group sources by base device name
+ (dolist (source sources)
+ (let* ((device (nth 0 source))
+ (driver (nth 1 source))
+ ;; Extract hardware ID (the unique part that identifies the physical device)
+ (base-name (cond
+ ;; USB devices: extract usb-XXXXX-XX part
+ ((string-match "\\.\\(usb-[^.]+\\-[0-9]+\\)\\." device)
+ (match-string 1 device))
+ ;; Built-in (pci) devices: extract pci-XXXXX part
+ ((string-match "\\.\\(pci-[^.]+\\)\\." device)
+ (match-string 1 device))
+ ;; Bluetooth devices: extract and normalize MAC address
+ ;; (input uses colons, output uses underscores - normalize to colons)
+ ((string-match "bluez_\\(?:input\\|output\\)\\.\\([^.]+\\)" device)
+ (replace-regexp-in-string "_" ":" (match-string 1 device)))
+ (t device)))
+ (is-monitor (string-match-p "\\.monitor$" device))
+ (device-entry (gethash base-name devices)))
+ (unless device-entry
+ (setf device-entry (cons nil nil))
+ (puthash base-name device-entry devices))
+ ;; Store mic or monitor in the pair
+ (if is-monitor
+ (setcdr device-entry device)
+ (setcar device-entry device))))
+
+ ;; Convert hash table to alist with friendly names
+ (maphash (lambda (base-name pair)
+ (when (and (car pair) (cdr pair)) ; Only include if we have both mic and monitor
+ (let ((friendly-name
+ (cond
+ ((string-match-p "usb.*[Jj]abra" base-name) "Jabra SPEAK 510 USB")
+ ((string-match-p "^usb-" base-name) "USB Audio Device")
+ ((string-match-p "^pci-" base-name) "Built-in Laptop Audio")
+ ((string-match-p "^[0-9A-Fa-f:]+$" base-name) "Bluetooth Headset")
+ (t base-name))))
+ (push (cons friendly-name pair) result))))
+ devices)
+ (nreverse result)))
+
+(defun cj/recording-quick-setup-for-calls ()
+ "Quick setup for recording calls/meetings.
+Detects available audio devices and lets you pick one device to use for
+both microphone (your voice) and monitor (remote person + sound effects).
+Perfect for recording video calls, phone calls, or presentations."
+ (interactive)
+ (let* ((grouped-devices (cj/recording-group-devices-by-hardware))
+ (choices (mapcar #'car grouped-devices)))
+ (if (null choices)
+ (user-error "No complete audio devices found (need both mic and monitor)")
+ (let* ((choice (completing-read "Which device are you using for the call? " choices nil t))
+ (device-pair (cdr (assoc choice grouped-devices)))
+ (mic (car device-pair))
+ (monitor (cdr device-pair)))
+ (setq cj/recording-mic-device mic)
+ (setq cj/recording-system-device monitor)
+ (message "Call recording ready! Using: %s\n Mic: %s\n Monitor: %s"
+ choice
+ (file-name-nondirectory mic)
+ (file-name-nondirectory monitor))))))
+
(defun cj/recording-get-devices ()
"Get or auto-detect audio devices.
Returns (mic-device . system-device) or nil on error."
@@ -309,6 +377,7 @@ Otherwise use the default location in `audio-recordings-dir'."
(define-key map (kbd "l") #'cj/recording-adjust-volumes)
(define-key map (kbd "d") #'cj/recording-list-devices)
(define-key map (kbd "s") #'cj/recording-select-devices)
+ (define-key map (kbd "c") #'cj/recording-quick-setup-for-calls)
map)
"Keymap for video/audio recording operations.")
@@ -323,7 +392,8 @@ Otherwise use the default location in `audio-recordings-dir'."
"C-; r A" "stop audio"
"C-; r l" "adjust levels"
"C-; r d" "list devices"
- "C-; r s" "select devices"))
+ "C-; r s" "select devices"
+ "C-; r c" "quick setup for calls"))
(provide 'video-audio-recording)
;;; video-audio-recording.el ends here.