zero-alloc audio pipeline: pointer-based IO from ring buffer to stdout

Replace Data/AudioPacket allocations with raw pointer callbacks through
the entire audio pipeline. Ring buffer hands out direct pointers (or
linearizes into a pre-allocated scratch buffer on wrap-around), converter
accepts/emits pointers via its cached buffers, and output handler writes
to stdout via write(2) with EINTR handling.

Remove AudioPacket (dead code), --flush flag (no-op with raw write(2)).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Nick Payne
2026-03-07 07:14:16 +00:00
parent 65c2d58c82
commit a1eb465142
9 changed files with 122 additions and 174 deletions
+1 -6
View File
@@ -9,7 +9,6 @@ struct AudioTee {
var stereo: Bool = false
var sampleRate: Double?
var chunkDuration: Double = 0.2
var flush: Bool = false
init() {}
@@ -33,7 +32,6 @@ struct AudioTee {
audiotee --include-processes 1234 5678 9012 # Tap only these processes
audiotee --exclude-processes 1234 5678 # Tap everything except these
audiotee --mute # Mute processes being tapped
audiotee --flush # Flush stdout after each chunk
"""
)
@@ -45,8 +43,6 @@ struct AudioTee {
name: "exclude-processes", help: "Process IDs to exclude (space-separated)")
parser.addFlag(name: "mute", help: "Mute processes being tapped")
parser.addFlag(name: "stereo", help: "Records in stereo")
parser.addFlag(
name: "flush", help: "Flush stdout after each audio chunk (reduces latency when piping)")
parser.addOption(
name: "sample-rate",
help: "Target sample rate (8000, 16000, 22050, 24000, 32000, 44100, 48000)")
@@ -64,7 +60,6 @@ struct AudioTee {
audioTee.excludeProcesses = try parser.getArrayValue("exclude-processes", as: Int32.self)
audioTee.mute = parser.getFlag("mute")
audioTee.stereo = parser.getFlag("stereo")
audioTee.flush = parser.getFlag("flush")
audioTee.sampleRate = try parser.getOptionalValue("sample-rate", as: Double.self)
audioTee.chunkDuration = try parser.getValue("chunk-duration", as: Double.self)
@@ -142,7 +137,7 @@ struct AudioTee {
throw ExitCode.failure
}
let outputHandler = BinaryAudioOutputHandler(flushAfterWrite: flush)
let outputHandler = BinaryAudioOutputHandler()
let recorder = try AudioRecorder(
deviceID: deviceID, outputHandler: outputHandler, convertToSampleRate: sampleRate,
chunkDuration: chunkDuration)