fix build error

This commit is contained in:
Nick Payne
2025-07-27 09:55:33 +01:00
parent abaa019bd2
commit 8c3ee0f4e7
2 changed files with 19 additions and 18 deletions
+1 -1
View File
@@ -2,7 +2,7 @@
**⚠️ API Instability Warning: The AudioTee API is incredibly unstable at present and subject to change without notice.** **⚠️ API Instability Warning: The AudioTee API is incredibly unstable at present and subject to change without notice.**
AudioTee captures your Mac's system audio output and writes raw PCM audio data directly to `stdout`. All logging and metadata information is written to `stderr`, allowing for clean redirection of audio data to files or pipes. It uses the [Core Audio taps](https://developer.apple.com/documentation/coreaudio/capturing-system-audio-with-core-audio-taps) API introduced in macOS 14.2 (released in December 2023). You can do whatever you want with this audio - stream it somewhere else, save it to disk, visualise it, etc. AudioTee captures your Mac's system audio output and writes it in PCM encoded chunks to `stdout` at regular intervals. All logging and metadata information is written to `stderr`, allowing for clean redirection of audio data to files or pipes. It uses the [Core Audio taps](https://developer.apple.com/documentation/coreaudio/capturing-system-audio-with-core-audio-taps) API introduced in macOS 14.2 (released in December 2023). You can do whatever you want with this audio - stream it somewhere else, save it to disk, visualise it, etc.
By default, it taps the audio output from **all** running processes. Tap output is forced to `mono` (not yet configurable) and preserves your output device's sample rate (configurable via the `--sample-rate` flag). Only the default output device is currently supported. By default, it taps the audio output from **all** running processes. Tap output is forced to `mono` (not yet configurable) and preserves your output device's sample rate (configurable via the `--sample-rate` flag). Only the default output device is currently supported.
+18 -17
View File
@@ -7,12 +7,12 @@ public class AudioBuffer {
private var readIndex: Int = 0 private var readIndex: Int = 0
private var availableBytes: Int = 0 private var availableBytes: Int = 0
private let maxBufferSize: Int private let maxBufferSize: Int
private let bytesPerChunk: Int private let bytesPerChunk: Int
private let chunkDuration: Double private let chunkDuration: Double
public init(format: AudioStreamBasicDescription, chunkDuration: Double = 0.2) { public init(format: AudioStreamBasicDescription, chunkDuration: Double = 0.2) {
// Pre-calculate chunk parameters // Pre-calculate chunk parameters
let bytesPerFrame = Int(format.mBytesPerFrame) let bytesPerFrame = Int(format.mBytesPerFrame)
let samplesPerChunk = Int(format.mSampleRate * chunkDuration) let samplesPerChunk = Int(format.mSampleRate * chunkDuration)
@@ -22,24 +22,26 @@ public class AudioBuffer {
// Calculate max buffer size to hold ~10 seconds of audio, way more than the maximum we allow // Calculate max buffer size to hold ~10 seconds of audio, way more than the maximum we allow
let bytesPerSecond = Int(format.mSampleRate) * bytesPerFrame let bytesPerSecond = Int(format.mSampleRate) * bytesPerFrame
self.maxBufferSize = bytesPerSecond * 10 self.maxBufferSize = bytesPerSecond * 10
// Pre-allocated ring buffer // Pre-allocated ring buffer
self.buffer = Array(repeating: 0, count: maxBufferSize) self.buffer = Array(repeating: 0, count: maxBufferSize)
} }
public func append(_ data: Data) { public func append(_ data: Data) {
guard availableBytes + data.count <= maxBufferSize else { guard availableBytes + data.count <= maxBufferSize else {
Logger.error("Audio buffer overflow", context: [ Logger.error(
"requested": String(data.count), "Audio buffer overflow",
"available": String(maxBufferSize - availableBytes) context: [
]) "requested": String(data.count),
"available": String(maxBufferSize - availableBytes),
])
return return
} }
data.withUnsafeBytes { bytes in data.withUnsafeBytes { bytes in
let sourceBytes = bytes.bindMemory(to: UInt8.self) let sourceBytes = bytes.bindMemory(to: UInt8.self)
let dataSize = sourceBytes.count let dataSize = sourceBytes.count
// Check if we can copy in one block (no wrap-around) // Check if we can copy in one block (no wrap-around)
if writeIndex + dataSize <= maxBufferSize { if writeIndex + dataSize <= maxBufferSize {
// only one write needed // only one write needed
@@ -49,14 +51,14 @@ public class AudioBuffer {
// two writes needed due to wrap-around // two writes needed due to wrap-around
let firstChunkSize = maxBufferSize - writeIndex let firstChunkSize = maxBufferSize - writeIndex
let secondChunkSize = dataSize - firstChunkSize let secondChunkSize = dataSize - firstChunkSize
buffer.replaceSubrange(writeIndex..<maxBufferSize, with: sourceBytes.prefix(firstChunkSize)) buffer.replaceSubrange(writeIndex..<maxBufferSize, with: sourceBytes.prefix(firstChunkSize))
buffer.replaceSubrange(0..<secondChunkSize, with: sourceBytes.suffix(secondChunkSize)) buffer.replaceSubrange(0..<secondChunkSize, with: sourceBytes.suffix(secondChunkSize))
writeIndex = secondChunkSize writeIndex = secondChunkSize
} }
} }
availableBytes += data.count availableBytes += data.count
} }
@@ -75,7 +77,7 @@ public class AudioBuffer {
guard availableBytes >= bytesPerChunk else { return nil } guard availableBytes >= bytesPerChunk else { return nil }
var chunkData = Data(capacity: bytesPerChunk) var chunkData = Data(capacity: bytesPerChunk)
// Check if we can copy in one block (no wrap-around) // Check if we can copy in one block (no wrap-around)
if readIndex + bytesPerChunk <= maxBufferSize { if readIndex + bytesPerChunk <= maxBufferSize {
// one copy needed // one copy needed
@@ -85,19 +87,18 @@ public class AudioBuffer {
// two copies needed due to wrap-around // two copies needed due to wrap-around
let firstChunkSize = maxBufferSize - readIndex let firstChunkSize = maxBufferSize - readIndex
let secondChunkSize = bytesPerChunk - firstChunkSize let secondChunkSize = bytesPerChunk - firstChunkSize
chunkData.append(contentsOf: buffer[readIndex..<maxBufferSize]) chunkData.append(contentsOf: buffer[readIndex..<maxBufferSize])
chunkData.append(contentsOf: buffer[0..<secondChunkSize]) chunkData.append(contentsOf: buffer[0..<secondChunkSize])
readIndex = secondChunkSize readIndex = secondChunkSize
} }
availableBytes -= bytesPerChunk availableBytes -= bytesPerChunk
let packet = AudioPacket( let packet = AudioPacket(
timestamp: Date(), timestamp: Date(),
duration: chunkDuration, duration: chunkDuration,
peakAmplitude: 0.0,
rawAudioData: chunkData rawAudioData: chunkData
) )