Skip to content

Conversation

wobondar
Copy link

Description

Feature: System-Wide Audio Recording Option

Adds the ability to record System audio from all applications, not just a specific one.

Q: Why is this required in the first place?
A: Often, I ran meetings and, for example, do "show and tell" at the same time during the meeting from multiple audio sources(apps), so i wanted Recap to record all system audio.

How it works

  • The "All Apps" option appears at the top of the app selection dropdown
  • When selected, it uses SystemWideTap with Core Audio's global tap APIs
  • System-wide capture uses CATapDescription(stereoGlobalTapButExcludeProcesses: []) with exclusive: true
  • All existing functionality for specific apps continues to work unchanged

Demo for screenshots below

  1. I began watching youtube video about "Volvo armoured cars" :)
  2. Somewhere in the middle said, "and this project will be assigned to Andrew"
  3. After Transcribing and Summarizing i've got expected behaviour, that it picked up details from both sources, mentioning me: "... the Armoured XC90 Plug-in Hybrid will be assigned to Andrew."

Important bits

  • Requires the same audio permissions as current process-specific capture
  • Maintains existing recording pipeline
  • No breaking changes to existing functionality
  • Does not introduce extra dependencies

Type of Change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Documentation update
  • Test improvement

Testing

  • Unit tests pass locally
  • New tests have been added for new functionality
  • Existing tests have been updated if needed

Checklist

  • I have performed a self-review of my own code
  • I have commented my code where necessary (following the no-comments rule)
  • My changes generate no new warnings
  • Any dependent changes have been merged and published

Screenshots (if applicable)

Default view

001_default_view

App selector

002_app_selector

Selected "All Apps"

003_all_apps_selected_view

Recording

004_recording

Summary Transcribing

005_summary_transcribing

Summarizing

006_summarizing

Final Summary

007_final_summary

Additional Notes

Everything I've already explained above.

@rawandahmad698
Copy link
Collaborator

Great work. Will review soon!

@wobondar
Copy link
Author

@rawandahmad698 @dennisimoo, is there a chance that it can be merged?

@rawandahmad698
Copy link
Collaborator

@wobondar yes. Sorry. I have been really busy. Will review certainly

Copy link
Contributor

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR introduces a system-wide audio recording feature that allows capturing audio from all applications simultaneously, rather than just a specific application. This addresses use cases where users need to record multiple audio sources during meetings or presentations.

  • Adds "All Apps" option to the app selection dropdown using a special ID of -1
  • Implements SystemWideTap and SystemWideTapRecorder classes using Core Audio's global tap APIs
  • Updates the recording pipeline to handle both process-specific and system-wide audio capture

Reviewed Changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
AppSelectionViewModel.swift Prepends "All Apps" option to available apps list
AppSelectionDropdown.swift Adds dedicated UI row for system-wide recording option
RecordingConfiguration.swift Updates application name handling for system-wide mode
RecordingSessionManager.swift Implements branching logic for system-wide vs process-specific recording
AudioRecordingCoordinator.swift Extends coordinator to support both tap types with unified interface
SelectableApp.swift Adds system-wide app representation with special ID -1
AudioProcess.swift Adds commented placeholders for future system case
SystemWideTap.swift New implementation of system-wide audio capture using Core Audio APIs
ProcessTap.swift Adds protocol conformance for unified tap interface
AudioTapType.swift New protocol definitions for audio tap abstraction

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

try tap.invalidate()
} catch {
logger.error("Stop failed: \(error, privacy: .public)")
}
Copy link
Preview

Copilot AI Aug 20, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The tap property is computed and calls invalidate() on the SystemWideTap instance, but invalidate() doesn't throw. This try is unnecessary and the method signature should be updated.

Suggested change
}
logger.debug(#function)
guard isRecording else { return }
currentFile = nil
isRecording = false
tap.invalidate()

Copilot uses AI. Check for mistakes.

if let systemWideTap = systemWideTap {
await MainActor.run {
systemWideTap.activate()
}
Copy link
Preview

Copilot AI Aug 20, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The systemWideTap.activate() is called twice - once at line 33 and again at line 59. This redundant activation could cause issues or unexpected behavior.

Suggested change
}

Copilot uses AI. Check for mistakes.

@@ -7,19 +7,44 @@ struct SelectableApp: Identifiable, Hashable {
let icon: NSImage
let isMeetingApp: Bool
let isAudioActive: Bool
private let originalAudioProcess: AudioProcess
let isSystemWide: Bool
Copy link
Preview

Copilot AI Aug 20, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] The isSystemWide property is redundant since it can be derived from checking if id == -1. Consider removing this property and using a computed property instead.

Suggested change
let isSystemWide: Bool

Copilot uses AI. Check for mistakes.

self.originalAudioProcess = audioProcess
}

private init(systemWide: Bool) {
Copy link
Preview

Copilot AI Aug 20, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The systemWide parameter in this initializer is always true when called. Consider removing the parameter and making this a parameterless private initializer.

Suggested change
private init(systemWide: Bool) {
private init() {

Copilot uses AI. Check for mistakes.

@ObservationIgnored
private(set) var tapStreamDescription: AudioStreamBasicDescription?
@ObservationIgnored
private var invalidationHandler: InvalidationHandler?
Copy link
Preview

Copilot AI Aug 20, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] Multiple @ObservationIgnored annotations could be grouped together for better readability, or consider using a single comment explaining why these properties are ignored.

Suggested change
private var invalidationHandler: InvalidationHandler?
// The following properties are ignored for observation because they are internal implementation details
// and do not affect the observable state of the SystemWideTap object.
@ObservationIgnored private var processTapID: AudioObjectID = .unknown
@ObservationIgnored private var aggregateDeviceID = AudioObjectID.unknown
@ObservationIgnored private var deviceProcID: AudioDeviceIOProcID?
@ObservationIgnored private(set) var tapStreamDescription: AudioStreamBasicDescription?
@ObservationIgnored private var invalidationHandler: InvalidationHandler?

Copilot uses AI. Check for mistakes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants