Files
audiotee/Sources/AudioTeeCLI/BinaryOutputHandler.swift
sttlab-tech 678557caf7 add microphone capture and stable code signing for TCC persistence
Adds --capture-mic/--mic-output for a second, independently-captured audio
track (mic vs system, written to separate outputs to avoid interleaving
corruption). Embeds Info.plist at link time so the binary carries a stable
CFBundleIdentifier and the usage-description keys TCC requires, and adds
scripts/build-signed.sh + scripts/create-signing-identity.sh so a rebuilt
binary keeps the same signing identity instead of losing granted
permissions on every rebuild.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-09 13:10:08 +02:00

55 lines
1.7 KiB
Swift

import AudioTeeCore
import Foundation
/// CLI-specific output handler that writes raw PCM audio to a file descriptor
/// (stdout by default) and lifecycle messages to stderr via the logger.
///
/// `source` tags every stderr message so a consumer running two tracks at
/// once (e.g. system audio + microphone, each on its own fd) can tell which
/// track a given metadata/lifecycle message belongs to.
class BinaryAudioOutputHandler: AudioOutputHandler {
private let fd: Int32
private let source: String
init(fd: Int32 = STDOUT_FILENO, source: String = "audio") {
self.fd = fd
self.source = source
}
func handleAudioData(_ pointer: UnsafeRawPointer, count: Int) {
var written = 0
while written < count {
let result = write(fd, pointer.advanced(by: written), count - written)
if result >= 0 {
written += result
} else if errno == EINTR {
continue
} else {
break // EPIPE, EIO, etc consumer gone or real error
}
}
}
func handleMetadata(_ metadata: AudioStreamMetadata) {
let taggedMetadata = AudioStreamMetadata(
sampleRate: metadata.sampleRate,
channelsPerFrame: metadata.channelsPerFrame,
bitsPerChannel: metadata.bitsPerChannel,
isFloat: metadata.isFloat,
captureMode: source,
deviceName: metadata.deviceName,
deviceUID: metadata.deviceUID,
encoding: metadata.encoding
)
AudioTeeLogging.logger.writeMessage(.metadata, data: taggedMetadata)
}
func handleStreamStart() {
AudioTeeLogging.logger.writeMessage(.streamStart, data: source)
}
func handleStreamStop() {
AudioTeeLogging.logger.writeMessage(.streamStop, data: source)
}
}