Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
103 commits
Select commit Hold shift + click to select a range
f48ea34
feat(config): add builder pattern with ::new() and with_* methods
1313 Nov 28, 2025
294411b
docs: use major version only in README examples
1313 Nov 28, 2025
d44b6e2
docs: fix build badge workflow filename
1313 Nov 28, 2025
464eddb
docs: update documentation to use builder pattern API
1313 Nov 28, 2025
c04282b
feat(error): add new error types for macOS 14.0+ stream events
1313 Nov 28, 2025
9caa5ea
feat(config): add new SCStreamConfiguration options for macOS 14.0-15.0
1313 Nov 28, 2025
3f3fe33
feat(filter): add SCContentFilter properties for macOS 14.0-15.2
1313 Nov 28, 2025
21b61bf
feat(content): add SCShareableContentInfo for macOS 14.0+
1313 Nov 28, 2025
7ae1b02
feat(screenshot): add capture_image_in_rect for macOS 15.2+
1313 Nov 28, 2025
28232d6
feat(recording): add SCRecordingOutput features for macOS 15.0+
1313 Nov 28, 2025
aa291c6
feat(picker): add SCContentSharingPicker enhancements for macOS 14.0+
1313 Nov 28, 2025
77ac973
docs: fix clippy doc_markdown warnings and update examples
1313 Nov 28, 2025
a576b84
feat(examples): integrate new macOS 14.0-15.2 features into examples
1313 Nov 28, 2025
0369236
feat(examples): add metal_overlay example with GPU rendering
1313 Nov 28, 2025
2b67450
docs: update README and Cargo.toml for new features
1313 Nov 28, 2025
a635e81
docs(picker): add async API documentation and improve examples
1313 Nov 28, 2025
8aa48ec
feat(delegate): add stream active/inactive callbacks (macOS 15.2+)
1313 Nov 28, 2025
07b672d
feat(config): add CaptureHDRRecordingPreservedSDRHDR10 preset
1313 Nov 28, 2025
0390873
feat(recording): add full video codec and file type arrays
1313 Nov 28, 2025
172c269
fix(picker): remove tokio-dependent async methods
1313 Nov 28, 2025
b74a0a5
feat(async): add AsyncSCContentSharingPicker for non-blocking picker UI
1313 Nov 29, 2025
13182e3
feat(async): add async picker example and tests
1313 Nov 29, 2025
d443c51
feat(screenshot): add macOS 26.0 advanced screenshot APIs
1313 Nov 29, 2025
1cae32d
feat(screenshot): add HDR screenshot example and tests
1313 Nov 29, 2025
d639442
docs: update README with new APIs and feature flags
1313 Nov 29, 2025
44f0d61
ci: add version-specific feature testing per macOS runner
1313 Nov 29, 2025
49cb797
refactor(swift-bridge): standardize API patterns and error handling
1313 Nov 29, 2025
dde6ef3
refactor(api): standardize Rust API patterns and naming
1313 Nov 29, 2025
05c0648
refactor(api): remove deprecated APIs and standardize naming
1313 Nov 29, 2025
ce1c8fe
refactor(cm): standardize CM/CV type method naming
1313 Nov 29, 2025
def27ac
chore: fix clippy warnings in docs and tests
1313 Nov 29, 2025
99f16fb
feat(shareable_content): add missing SDK methods
1313 Nov 29, 2025
7058b27
refactor(api): remove get_ prefix from non-configuration getters
1313 Nov 29, 2025
cd7d736
test: add coverage for missing SDK features
1313 Nov 29, 2025
7975fb9
fix(examples): update recording_output example to use builder pattern
1313 Nov 29, 2025
f341b1d
feat(examples): add real audio waveform and vertical gain meters
1313 Nov 29, 2025
9115f57
fix(examples): use SCShareableContent instead of blocking picker
1313 Nov 29, 2025
3f734cf
refactor(picker): replace blocking API with callback-based API
1313 Nov 29, 2025
2c52eee
refactor(picker): rename async pick() to show() for consistency
1313 Nov 29, 2025
e8c63dc
feat(examples): preserve aspect ratio and center UI panels
1313 Nov 29, 2025
6ba13b6
feat(examples): use SCContentSharingPicker for content selection
1313 Nov 29, 2025
36befc2
fix(picker): activate app and cleanup observer before showing
1313 Nov 29, 2025
9db5060
feat(audio): add audio input device enumeration API
1313 Nov 29, 2025
0e5163f
refactor(example): improve metal_overlay UX with menu navigation
1313 Nov 29, 2025
2f8015b
refactor: improve metal overlay UX and mic device API
1313 Nov 29, 2025
73728eb
feat(picker): add SCPickedSource to identify selected content type
1313 Nov 29, 2025
5634ab3
refactor(example): modularize metal_overlay example
1313 Nov 29, 2025
1896ced
refactor(config): remove get_ prefix from getters
1313 Nov 29, 2025
3cd1cb6
feat(audio): add audio buffer list access
1313 Nov 29, 2025
55a39e3
feat(picker): add show_for_stream methods
1313 Nov 29, 2025
4209884
feat(stream): expose as_ptr for internal use
1313 Nov 29, 2025
ad4e942
fix(audio): correct AudioStreamBasicDescription repr
1313 Nov 29, 2025
3447051
feat(example): enhance metal_overlay with synthwave UI
1313 Nov 29, 2025
28d39b3
feat(example): enable mic-only capture without video source
1313 Nov 29, 2025
f696669
refactor(example): remove unused metal_overlay module files
1313 Nov 29, 2025
4710e04
refactor(example): split metal_overlay into modules
1313 Nov 29, 2025
91a5071
feat(example): add screenshot option to metal_overlay
1313 Nov 29, 2025
498e647
feat(cg): add CGImage::save_png() with auto-open
1313 Nov 29, 2025
7daaffa
feat(example): use macOS 26 screenshot API when available
1313 Nov 29, 2025
b8fa8c5
feat(example): add recording menu option (macOS 15.0+)
1313 Nov 29, 2025
06e50a5
refactor(error): replace specific error variants with SCStreamErrorCode
1313 Nov 30, 2025
47b8bf6
feat(stream): add closure-based delegate builders
1313 Nov 30, 2025
373818d
feat(async): add async screenshot APIs for macOS 15.2/26.0
1313 Nov 30, 2025
1c7f376
feat(screenshot): add SCScreenshotConfiguration content type support
1313 Nov 30, 2025
8af4072
feat(filter): add excluding applications filter variant
1313 Nov 30, 2025
b49d836
feat(config): add capture resolution type support (macOS 14.0+)
1313 Nov 30, 2025
4c4962b
feat(stream): add sync clock and filter stream type
1313 Nov 30, 2025
326c7dc
feat(cm): add CMTime operations and frame status predicates
1313 Nov 30, 2025
068d63e
feat(picker): add presentation mode and single window style
1313 Nov 30, 2025
478d33b
feat(ffi): add FFI bindings for new APIs
1313 Nov 30, 2025
802a181
feat(example): refactor metal_overlay with recording/screenshot modules
1313 Nov 30, 2025
12bb5fa
docs: add copilot instructions and Apple docs download script
1313 Nov 30, 2025
c63f675
refactor: improve code quality and fix memory leaks
1313 Nov 30, 2025
05e0be3
fix(memory): add leak fixes and comprehensive memory tests
1313 Nov 30, 2025
2654956
fix: remove dead code and fix test errors
1313 Nov 30, 2025
58015a4
refactor(examples): extract input handling to separate module
1313 Nov 30, 2025
9b6d526
feat(examples): add missing API coverage examples
1313 Nov 30, 2025
53b852a
docs(examples): update README with new examples
1313 Nov 30, 2025
aa94679
fix(swift): implement stub configuration properties
1313 Nov 30, 2025
1c49bb1
refactor(swift): use public APIs for filter content extraction
1313 Nov 30, 2025
b074f57
fix(swift): implement stub configuration properties
1313 Nov 30, 2025
bf4c352
fix: remove non-existent average_bitrate API
1313 Nov 30, 2025
efa6edf
feat(ffi): add optimized batch retrieval and owned strings
1313 Nov 30, 2025
14fddd3
fix: resolve clippy warnings
1313 Nov 30, 2025
b58a0b9
fix: remove non-existent with_average_bitrate method calls
1313 Nov 30, 2025
1bf2f85
style: fix clippy warnings and format code
1313 Nov 30, 2025
cd14641
docs: add note about running memory tests single-threaded
1313 Nov 30, 2025
8716164
refactor(test): convert leak test to example for better isolation
1313 Nov 30, 2025
9dab484
feat(examples): enhance memory leak test with comprehensive API coverage
1313 Nov 30, 2025
18a0dbe
docs: update references to renamed memory leak example
1313 Nov 30, 2025
2b2c6ef
docs: update documentation to reflect current API
1313 Nov 30, 2025
eabe16e
docs: improve doc comments for audio and block buffer modules
1313 Nov 30, 2025
384474f
fix: guard recording output FFI with compiler version check for macOS 13
1313 Nov 30, 2025
c05fd30
fix: add macOS version availability guards for Swift APIs
1313 Nov 30, 2025
8ce3f06
fix: add SCREENCAPTUREKIT_HAS_MACOS26_SDK guard for macOS 26+ APIs
1313 Nov 30, 2025
34b4f3f
fix: use rawValue comparison for SCStreamOutputType to fix SDK compat…
1313 Nov 30, 2025
9801c37
style: fix formatting in memory leak check example
1313 Nov 30, 2025
c12fab9
fix: add feature gates to example for content_rect, point_pixel_scale…
1313 Nov 30, 2025
c525b0e
fix: add macos_14_0 feature gate to captures_shadows_only tests
1313 Nov 30, 2025
281e72a
ci: add macOS 26 (Tahoe) to build matrix
1313 Nov 30, 2025
6a7f7a8
fix: add macos_13_0 feature gate to synchronization_clock in example
1313 Nov 30, 2025
7bd0c11
docs: update README to match current API
1313 Nov 30, 2025
e87ed1e
chore: release v2.0.0
1313 Nov 30, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
270 changes: 270 additions & 0 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,270 @@
# Copilot Instructions for screencapturekit-rs

This project provides safe, idiomatic Rust bindings for macOS ScreenCaptureKit framework.

## Project Overview

- **Language:** Rust with Swift bridge code
- **Platform:** macOS 12.3+ (with feature flags for newer APIs)
- **Architecture:** FFI bindings via `swift-bridge/` to ScreenCaptureKit

## Key Directories

```
src/ # Rust source code
├── stream/ # SCStream, SCStreamConfiguration, SCContentFilter
├── shareable_content/ # SCShareableContent, SCDisplay, SCWindow
├── cm/ # Core Media types (CMSampleBuffer, CMTime)
├── cg/ # Core Graphics types (CGRect, CGImage)
├── output/ # Frame output handling
├── screenshot_manager/ # SCScreenshotManager (macOS 14.0+)
├── content_sharing_picker/ # SCContentSharingPicker (macOS 14.0+)
├── recording_output/ # SCRecordingOutput (macOS 15.0+)
├── async_api/ # Async wrappers
└── ffi/ # Raw FFI declarations

swift-bridge/ # Swift implementation bridging to ScreenCaptureKit
docs/apple/ # Apple documentation (gitignored, regenerate with scripts/download_apple_docs.py)
```

## Apple ScreenCaptureKit API Reference

**Source this file for complete API signatures:** `docs/apple/API-COMPLETE.md`

To regenerate documentation: `python3 scripts/download_apple_docs.py`

### Core Classes

```swift
// SCStream - Main capture stream
class SCStream
init(filter: SCContentFilter, configuration: SCStreamConfiguration, delegate: SCStreamDelegate?)
func startCapture() async throws
func stopCapture() async throws
func addStreamOutput(_ output: SCStreamOutput, type: SCStreamOutputType, sampleHandlerQueue: DispatchQueue?) throws
func removeStreamOutput(_ output: SCStreamOutput, type: SCStreamOutputType) throws
func updateConfiguration(_ config: SCStreamConfiguration) async throws
func updateContentFilter(_ filter: SCContentFilter) async throws
func addRecordingOutput(_ output: SCRecordingOutput) throws
func removeRecordingOutput(_ output: SCRecordingOutput) throws

// SCStreamConfiguration - Stream settings
class SCStreamConfiguration
var width: Int { get set }
var height: Int { get set }
var pixelFormat: OSType { get set }
var colorSpaceName: CFString { get set }
var showsCursor: Bool { get set }
var capturesAudio: Bool { get set }
var sampleRate: Int { get set }
var channelCount: Int { get set }
var minimumFrameInterval: CMTime { get set }
var queueDepth: Int { get set }
var scalesToFit: Bool { get set }
var sourceRect: CGRect { get set }
var destinationRect: CGRect { get set }
var captureDynamicRange: SCCaptureDynamicRange { get set } // macOS 15.0+
var captureMicrophone: Bool { get set } // macOS 15.0+
var presenterOverlayPrivacyAlertSetting: SCPresenterOverlayAlertSetting { get set }
convenience init(preset: SCStreamConfiguration.Preset)

// SCContentFilter - What to capture
class SCContentFilter
init(desktopIndependentWindow: SCWindow)
init(display: SCDisplay, including: [SCWindow])
init(display: SCDisplay, excludingWindows: [SCWindow])
init(display: SCDisplay, including: [SCRunningApplication], exceptingWindows: [SCWindow])
init(display: SCDisplay, excludingApplications: [SCRunningApplication], exceptingWindows: [SCWindow])
var contentRect: CGRect { get }
var pointPixelScale: Float { get }
var includeMenuBar: Bool { get set }

// SCShareableContent - Query available content
class SCShareableContent
class func getExcludingDesktopWindows(_ excludeDesktop: Bool, onScreenWindowsOnly: Bool) async throws -> SCShareableContent
class func getCurrentProcessShareableContent() async throws -> SCShareableContent // macOS 14.4+
var displays: [SCDisplay] { get }
var windows: [SCWindow] { get }
var applications: [SCRunningApplication] { get }

// SCDisplay
class SCDisplay
var displayID: CGDirectDisplayID { get }
var width: Int { get }
var height: Int { get }
var frame: CGRect { get }

// SCWindow
class SCWindow
var windowID: CGWindowID { get }
var title: String? { get }
var owningApplication: SCRunningApplication? { get }
var frame: CGRect { get }
var isOnScreen: Bool { get }
var windowLayer: Int { get }

// SCRunningApplication
class SCRunningApplication
var bundleIdentifier: String { get }
var applicationName: String { get }
var processID: pid_t { get }
```

### Screenshot API (macOS 14.0+)

```swift
class SCScreenshotManager
class func captureSampleBuffer(contentFilter: SCContentFilter, configuration: SCStreamConfiguration) async throws -> CMSampleBuffer
class func captureImage(contentFilter: SCContentFilter, configuration: SCStreamConfiguration) async throws -> CGImage
class func captureImage(inRect: CGRect) async throws -> CGImage // macOS 15.2+
```

### Recording API (macOS 15.0+)

```swift
class SCRecordingOutput
init(configuration: SCRecordingOutputConfiguration, delegate: SCRecordingOutputDelegate)
var recordedDuration: CMTime { get }
var recordedFileSize: Int { get }

class SCRecordingOutputConfiguration
var outputURL: URL { get set }
var outputFileType: AVFileType { get set }
var videoCodecType: AVVideoCodecType { get set }

protocol SCRecordingOutputDelegate
func recordingOutputDidStartRecording(_ output: SCRecordingOutput)
func recordingOutputDidFinishRecording(_ output: SCRecordingOutput)
func recordingOutput(_ output: SCRecordingOutput, didFailWithError: Error)
```

### Content Picker (macOS 14.0+)

```swift
class SCContentSharingPicker
class var shared: SCContentSharingPicker { get }
var isActive: Bool { get set }
func present()
func present(for stream: SCStream?, using contentStyle: SCShareableContentStyle)
func add(_ observer: SCContentSharingPickerObserver)
func remove(_ observer: SCContentSharingPickerObserver)

protocol SCContentSharingPickerObserver
func contentSharingPicker(_ picker: SCContentSharingPicker, didUpdateWith filter: SCContentFilter, for stream: SCStream?)
func contentSharingPicker(_ picker: SCContentSharingPicker, didCancelFor stream: SCStream?)
func contentSharingPickerStartDidFail(with error: Error)
```

### Protocols

```swift
protocol SCStreamOutput
func stream(_ stream: SCStream, didOutputSampleBuffer: CMSampleBuffer, of type: SCStreamOutputType)

protocol SCStreamDelegate
func stream(_ stream: SCStream, didStopWithError: Error)
func outputEffectDidStart(for stream: SCStream) // Presenter Overlay
func outputEffectDidStop(for stream: SCStream)

enum SCStreamOutputType { case screen, audio, microphone }
enum SCCaptureDynamicRange { case sdr, hdrLocalDisplay, hdrCanonicalDisplay }
enum SCPresenterOverlayAlertSetting { case system, never, always }
```

## Coding Conventions

### Builder Pattern

```rust
// Content filters use .builder() with .build()
let filter = SCContentFilter::builder()
.display(&display)
.exclude_windows(&windows)
.build();

// Configuration uses ::new() with .with_*() chainable methods
let config = SCStreamConfiguration::new()
.with_width(1920)
.with_height(1080)
.with_pixel_format(PixelFormat::BGRA);
```

### Feature Flags

Version-gated APIs require feature flags:

```rust
#[cfg(feature = "macos_15_0")]
pub fn set_capture_dynamic_range(&mut self, range: SCCaptureDynamicRange) -> &mut Self {
// ...
}
```

Feature hierarchy (cumulative):
- `macos_13_0` - Audio capture, sync clock
- `macos_14_0` - Content picker, screenshots
- `macos_14_2` - Menu bar, child windows, presenter overlay
- `macos_14_4` - Current process content
- `macos_15_0` - Recording output, HDR, microphone
- `macos_15_2` - Screenshot in rect
- `macos_26_0` - Advanced screenshot config

### Memory Management

- All CoreFoundation types use RAII with proper retain/release in Drop
- FFI functions that transfer ownership are named `*_create`, `*_copy`
- FFI functions that borrow are named `*_get_*`
- Always pair `*_retain` with `*_release`

### Error Handling

- Use `SCError` for all error types
- Map Swift/ObjC errors to appropriate variants
- Include context in error messages

## Testing

```bash
cargo test # All tests
cargo test --features async # With async
cargo test --all-features # All features
cargo clippy --all-features -- -D warnings # Lint
```

## Updating Apple Documentation

To regenerate the full Apple documentation:

```bash
python3 scripts/download_apple_docs.py
```

This downloads:
1. JSON documentation from Apple's developer docs
2. Converts to markdown for easy reference
3. Extracts Swift sample code from Apple's sample projects
4. WWDC session transcripts with code snippets
5. API-COMPLETE.md with all function signatures

## Common Tasks

### Adding a New API

1. Check `docs/apple/API-COMPLETE.md` for Swift signatures
2. Check `docs/apple/wwdc/` for WWDC session explaining the feature
3. Reference `docs/apple/samples/` for Swift usage patterns
4. Add FFI declaration in `src/ffi/mod.rs`
5. Implement Swift bridge in `swift-bridge/Sources/`
6. Create Rust wrapper with builder pattern
7. Add feature flag if version-specific
8. Add tests and update `CHANGELOG.md`

### Mapping Swift to Rust

| Swift | Rust |
|-------|------|
| `class SCStream` | `struct SCStream { ptr: *const c_void }` |
| `@escaping closure` | `Box<dyn Fn(...) + Send>` |
| `async throws` | `Result<T, SCError>` |
| `Optional<T>` | `Option<T>` |
| `NSError` | `SCError` |
20 changes: 14 additions & 6 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,12 +46,18 @@ jobs:
fail-fast: false
matrix:
include:
- os: macos-13
name: macOS 13 (Ventura) Intel
features: "async,macos_13_0"
- os: macos-14
name: macOS 14 (Sonoma) ARM64
features: "async,macos_14_4"
- os: macos-15
name: macOS 15 (Sequoia) ARM64
- os: macos-13
name: macOS 13 (Ventura) Intel
features: "async,macos_15_2"
- os: macos-26
name: macOS 26 (Tahoe) ARM64
features: "async,macos_26_0"
runs-on: ${{ matrix.os }}
name: Build - ${{ matrix.name }}
steps:
Expand All @@ -68,12 +74,14 @@ jobs:
key: ${{ runner.os }}-${{ matrix.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-${{ matrix.os }}-cargo-
- name: Build
- name: Build (default features)
run: cargo build --verbose
- name: Build with all features
run: cargo build --verbose --all-features
- name: Run tests
- name: Build with version-specific features (${{ matrix.features }})
run: cargo build --verbose --features "${{ matrix.features }}"
- name: Run tests (default features)
run: cargo test --verbose
- name: Run tests with version-specific features
run: cargo test --verbose --features "${{ matrix.features }}"

# ==========================================================================
# Documentation (only on main)
Expand Down
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,11 @@ coverage/
/doc/
/book/

# Downloaded Apple documentation (regenerate with scripts/download_apple_docs.py)
/docs/apple/

# IDE-specific
*.iml
.project
.classpath
.settings/
.github/copilot-instructions.md
Loading
Loading