### Quick Start Installation and Execution Source: https://github.com/makeusabrew/audiotee/blob/main/README.md Clone the repository, navigate to the directory, and run the application using Swift Package Manager. This is a quick way to get started. ```bash git clone git@github.com:makeusabrew/audiotee.git cd audiotee swift run ``` -------------------------------- ### Setup and Start Audio Recording Source: https://context7.com/makeusabrew/audiotee/llms.txt Demonstrates how to set up and start an AudioRecorder instance. Requires a device ID and an AudioOutputHandler. Conversion to a specific sample rate and chunk duration can be configured. ```swift import AudioTeeCore import CoreAudio // Custom output handler to receive audio data class MyAudioHandler: AudioOutputHandler { var audioChunks: [Data] = [] func handleAudioData(_ pointer: UnsafeRawPointer, count: Int) { // Pointer is only valid during this call - copy if needed let data = Data(bytes: pointer, count: count) audioChunks.append(data) print("Received \(count) bytes of audio") } func handleMetadata(_ metadata: AudioStreamMetadata) { print("Format: \(metadata.sampleRate)Hz, \(metadata.channelsPerFrame)ch, \(metadata.bitsPerChannel)-bit") print("Encoding: \(metadata.encoding)") } func handleStreamStart() { print("Stream started") } func handleStreamStop() { print("Stream stopped, total chunks: \(audioChunks.count)") } } // Setup and start recording let handler = MyAudioHandler() do { // deviceID comes from AudioTapManager.getDeviceID() let recorder = try AudioRecorder( deviceID: deviceID, outputHandler: handler, convertToSampleRate: 16000, // nil = use device native rate chunkDuration: 0.2 // Chunk size in seconds ) // Check conversion status print("Is converting: \(recorder.isConverting)") print("Output format: \(recorder.outputFormat.mSampleRate)Hz") try recorder.startRecording() // Recording runs on Core Audio's IO thread // Stop when done: // recorder.stopRecording() } catch AudioTeeError.deviceFormatUnavailable(let deviceID) { print("Could not get format for device: \(deviceID)") } catch { print("Recording setup failed: \(error)") } ``` -------------------------------- ### Initialize AudioTapManager in Swift Source: https://context7.com/makeusabrew/audiotee/llms.txt Set up an audio tap using AudioTapManager with custom configurations. Handles potential errors during setup, such as PID translation or tap creation failures. ```swift import AudioTeeCore // Create tap configuration let config = TapConfiguration( processes: [], // Empty = all processes muteBehavior: .unmuted, // Don't mute captured audio isExclusive: true, // Exclusive mode for "all except" filtering isMono: true // Mono output ) // Initialize and setup the audio tap let tapManager = AudioTapManager() do { try tapManager.setupAudioTap(with: config) // Get the aggregate device ID for recording guard let deviceID = tapManager.getDeviceID() else { print("Failed to get device ID") return } // Use deviceID with AudioRecorder... print("Audio tap ready with device ID: \(deviceID)") } catch AudioTeeError.pidTranslationFailed(let failedPIDs) { print("Could not find processes: \(failedPIDs)") } catch AudioTeeError.tapCreationFailed(let status) { print("Tap creation failed with status: \(status)") } catch { print("Setup failed: \(error)") } ``` -------------------------------- ### Complete Audio Capture and Recording Setup in Swift Source: https://context7.com/makeusabrew/audiotee/llms.txt Sets up AudioTee for system audio capture, including tap configuration, optional sample rate conversion, and recording. Requires an AudioOutputHandler to process audio chunks. Ensure the NSAudioCaptureUsageDescription permission is granted in your application's Info.plist. ```swift import AudioTeeCore import CoreAudio import Foundation class AudioCaptureService { private var tapManager: AudioTapManager? private var recorder: AudioRecorder? private var isRunning = false func startCapture( processIDs: [Int32] = [], excludeProcesses: Bool = true, sampleRate: Double? = 16000, mono: Bool = true, mute: Bool = false, chunkDuration: Double = 0.2, handler: AudioOutputHandler ) throws { // Silence library logs if desired AudioTeeLogging.logger = NullLogger() // Configure tap let config = TapConfiguration( processes: processIDs, muteBehavior: mute ? .muted : .unmuted, isExclusive: excludeProcesses, isMono: mono ) // Setup audio tap tapManager = AudioTapManager() try tapManager?.setupAudioTap(with: config) guard let deviceID = tapManager?.getDeviceID() else { throw AudioTeeError.setupFailed } // Create recorder with optional sample rate conversion recorder = try AudioRecorder( deviceID: deviceID, outputHandler: handler, convertToSampleRate: sampleRate, chunkDuration: chunkDuration ) try recorder?.startRecording() isRunning = true } func stopCapture() { guard isRunning else { return } recorder?.stopRecording() recorder = nil tapManager = nil isRunning = false } } // Usage let handler = MyAudioHandler() // Assume MyAudioHandler conforms to AudioOutputHandler let service = AudioCaptureService() do { // Capture all audio at 16kHz mono for ASR try service.startCapture( sampleRate: 16000, mono: true, handler: handler ) // Run for 10 seconds DispatchQueue.main.asyncAfter(deadline: .now() + 10) { service.stopCapture() exit(0) } RunLoop.main.run() } catch { print("Failed to start capture: \(error)") } ``` -------------------------------- ### Audio Conversion with Sample Rate Source: https://github.com/makeusabrew/audiotee/blob/main/README.md Examples of using the --sample-rate flag. Note that any sample rate conversion results in 16-bit signed integer output, potentially reducing dynamic range. ```bash ./audiotee ``` ```bash ./audiotee --sample-rate 16000 ``` ```bash ./audiotee --sample-rate 44100 ``` -------------------------------- ### Configure AudioTee Logging Source: https://context7.com/makeusabrew/audiotee/llms.txt Set the global logger instance for AudioTeeCore before its initialization. Examples show how to silence logging, use OS Log, or the default stderr logger. ```swift // Configure before using AudioTeeCore AudioTeeLogging.logger = NullLogger() // Silence logging // AudioTeeLogging.logger = OSLogLogger() // Use OS Log // AudioTeeLogging.logger = StderrJSONLogger() // Default CLI behavior ``` -------------------------------- ### Access Audio Stream Metadata Source: https://context7.com/makeusabrew/audiotee/llms.txt The AudioStreamMetadata object, provided via the handleMetadata callback, contains essential format information about the audio stream. It is automatically generated when recording starts. ```swift import AudioTeeCore // Metadata is provided via handleMetadata callback func handleMetadata(_ metadata: AudioStreamMetadata) { print("Sample Rate: \(metadata.sampleRate)") // e.g., 16000.0 print("Channels: \(metadata.channelsPerFrame)") // 1 (mono) or 2 (stereo) print("Bits per Channel: \(metadata.bitsPerChannel)") // 16 or 32 print("Is Float: \(metadata.isFloat)") // true for 32-bit float print("Encoding: \(metadata.encoding)") // "pcm_f32le" or "pcm_s16le" print("Capture Mode: \(metadata.captureMode)") // "audio" print("Device Name: \(metadata.deviceName ?? "N/A")") print("Device UID: \(metadata.deviceUID ?? "N/A")") // Metadata is Codable for easy serialization let encoder = JSONEncoder() encoder.outputFormatting = .prettyPrinted if let json = try? encoder.encode(metadata), let string = String(data: json, encoding: .utf8) { print(string) } } ``` -------------------------------- ### Basic Command Line Usage Source: https://github.com/makeusabrew/audiotee/blob/main/README.md Demonstrates fundamental ways to run AudioTee from the command line, including redirecting output to stdout, a file, or piping to another process. Also shows how to redirect both stdout and stderr. ```bash ./audiotee ``` ```bash ./audiotee > output.pcm ``` ```bash ./audiotee | your_audio_processing_tool ``` ```bash ./audiotee > captured_audio.pcm 2> audiotee.log ``` -------------------------------- ### Build and Run AudioTee CLI Source: https://context7.com/makeusabrew/audiotee/llms.txt Build the project using Swift Package Manager and execute basic capture commands. Redirect stdout for audio data and stderr for logs. ```bash swift build -c release ``` ```bash ./audiotee > output.pcm ``` ```bash ./audiotee --sample-rate 16000 > output.pcm ``` ```bash ./audiotee --stereo > output.pcm ``` ```bash ./audiotee --include-processes 1234 5678 > output.pcm ``` ```bash ./audiotee --exclude-processes 1234 > output.pcm ``` ```bash ./audiotee --mute > output.pcm ``` ```bash ./audiotee --chunk-duration 0.1 > output.pcm ``` ```bash ./audiotee > audio.pcm 2> audiotee.log ``` ```bash ./audiotee --sample-rate 16000 | your_audio_processor ``` ```bash ffplay -f s16le -ar 16000 output.pcm ``` -------------------------------- ### Initialize Audio Buffer Source: https://context7.com/makeusabrew/audiotee/llms.txt Sets up an AudioBuffer for accumulating audio data and delivering fixed-size chunks. The buffer is configured with an audio format and a chunk duration, calculating the required bytes per chunk. ```swift import AudioTeeCore import CoreAudio // Create buffer for 200ms chunks based on audio format let format = AudioStreamBasicDescription( mSampleRate: 48000, mFormatID: kAudioFormatLinearPCM, mFormatFlags: kAudioFormatFlagIsFloat | kAudioFormatFlagIsPacked, mBytesPerPacket: 4, mFramesPerPacket: 1, mBytesPerFrame: 4, mChannelsPerFrame: 1, mBitsPerChannel: 32, mReserved: 0 ) let buffer = AudioBuffer(format: format, chunkDuration: 0.2) print("Bytes per chunk: \(buffer.bytesPerChunk)") // 48000 Hz * 0.2s * 4 bytes = 38,400 bytes per chunk ``` -------------------------------- ### Build Release Version Source: https://github.com/makeusabrew/audiotee/blob/main/README.md Compile the AudioTee application in release mode for optimized performance. Omit '-c release' for a debug build. ```bash swift build -c release ``` -------------------------------- ### Implement File Audio Recording Source: https://context7.com/makeusabrew/audiotee/llms.txt Implement the AudioOutputHandler protocol to write audio data to a file. The file path is determined by the audio stream's sample rate. ```swift import AudioTeeCore import Foundation // Example: Write to file with header tracking class FileAudioHandler: AudioOutputHandler { private var fileHandle: FileHandle? private var totalBytes: Int = 0 func handleAudioData(_ pointer: UnsafeRawPointer, count: Int) { let data = Data(bytes: pointer, count: count) fileHandle?.write(data) totalBytes += count } func handleMetadata(_ metadata: AudioStreamMetadata) { let path = "recording_\(Int(metadata.sampleRate))hz.pcm" FileManager.default.createFile(atPath: path, contents: nil) fileHandle = FileHandle(forWritingAtPath: path) print("Recording to \(path)") } func handleStreamStart() { totalBytes = 0 } func handleStreamStop() { fileHandle?.closeFile() print("Wrote \(totalBytes) bytes") } } ``` -------------------------------- ### View Logs in Real-Time Source: https://github.com/makeusabrew/audiotee/blob/main/README.md Combine audio capture with real-time log viewing by redirecting both stdout and stderr to the same pipeline. This allows monitoring logs while capturing audio. ```bash # View logs in real-time while capturing audio ./audiotee > audio.pcm 2>&1 | grep "AudioTee" ``` -------------------------------- ### Capture System Audio to File Source: https://github.com/makeusabrew/audiotee/blob/main/README.md Redirect the raw PCM audio output to a file for later use. Logs are sent to stderr. ```bash /path/to/audiotee > output.pcm ``` -------------------------------- ### Playback Captured Audio Source: https://github.com/makeusabrew/audiotee/blob/main/README.md Use ffplay to play back the captured PCM audio file. Ensure the format and sample rate match the capture settings. ```bash ffplay -f s16le -ar 16000 output.pcm ``` -------------------------------- ### Run with Specific Sample Rate Source: https://github.com/makeusabrew/audiotee/blob/main/README.md Execute AudioTee and redirect its output to a file, specifying a sample rate of 16000 Hz. This is useful for applications like ASR services that require a specific sample rate. ```bash swift run audiotee --sample-rate 16000 > output.pcm ``` -------------------------------- ### Create Audio Format Converter Source: https://context7.com/makeusabrew/audiotee/llms.txt Initializes an AudioFormatConverter to change the sample rate and bit-depth of audio data. Requires the source audio format. The converter can be configured to target a specific sample rate. ```swift import AudioTeeCore import CoreAudio // Get source format from device (via AudioFormatManager) let sourceFormat = try AudioFormatManager.getDeviceFormat(deviceID: deviceID) // Create converter to 16kHz (also converts to 16-bit signed integers) let converter = try AudioFormatConverter.toSampleRate(16000, from: sourceFormat) // Check formats print("Source: \(converter.sourceFormatDescription.mSampleRate)Hz") print("Target: \(converter.targetFormatDescription.mSampleRate)Hz") // Validate sample rate before creating converter let validRates: [Double] = [8000, 16000, 22050, 24000, 32000, 44100, 48000] if AudioFormatConverter.isValidSampleRate(16000) { print("16kHz is supported") } ``` -------------------------------- ### Define TapConfiguration in Swift Source: https://context7.com/makeusabrew/audiotee/llms.txt Configure the behavior of the audio tap, specifying process inclusion/exclusion, mute settings, and channel mode. ```swift import AudioTeeCore // Capture all system audio in mono let captureAll = TapConfiguration( processes: [], muteBehavior: .unmuted, isExclusive: true, isMono: true ) // Capture only specific processes (by PID) let captureSpecific = TapConfiguration( processes: [1234, 5678], // Process IDs to capture muteBehavior: .unmuted, isExclusive: false, // false = include only these isMono: false // Stereo output ) // Capture all except specific processes, muted let captureExcept = TapConfiguration( processes: [9012], // Process IDs to exclude muteBehavior: .muted, // Mute captured audio isExclusive: true, // true = exclude these isMono: true ) // TapMuteBehavior options: // .unmuted - Captured processes still play through speakers (default) // .muted - Captured processes are silenced on speakers ``` -------------------------------- ### Tap Specific Processes by PID Source: https://github.com/makeusabrew/audiotee/blob/main/README.md Configure AudioTee to capture audio only from specified processes using their Process IDs (PIDs). Including a PID not currently running audio may cause the process to exit. ```bash ./audiotee --include-processes 1234 ``` ```bash ./audiotee --include-processes 1234 5678 9012 ``` -------------------------------- ### Integrate with OS Log Source: https://context7.com/makeusabrew/audiotee/llms.txt Implement the AudioTeeLogger protocol to route log messages to the macOS unified logging system. Requires specifying a subsystem and category. ```swift import AudioTeeCore import os.log // OS Log integration for macOS apps class OSLogLogger: AudioTeeLogger { private let logger = Logger(subsystem: "com.myapp", category: "AudioTee") func debug(_ message: String, context: [String: String]?) { logger.debug("\(message) \(context ?? [:])") } func info(_ message: String, context: [String: String]?) { logger.info("\(message) \(context ?? [:])") } func error(_ message: String, context: [String: String]?) { logger.error("\(message) \(context ?? [:])") } } ``` -------------------------------- ### Implement WebSocket Audio Streaming Source: https://context7.com/makeusabrew/audiotee/llms.txt Implement the AudioOutputHandler protocol to stream audio data over a WebSocket connection. Requires a URL for the WebSocket server. ```swift import AudioTeeCore import Foundation // Example: Stream audio over WebSocket class WebSocketAudioHandler: AudioOutputHandler { private var socket: URLSessionWebSocketTask? private var metadata: AudioStreamMetadata? init(url: URL) { let session = URLSession(configuration: .default) socket = session.webSocketTask(with: url) socket?.resume() } func handleAudioData(_ pointer: UnsafeRawPointer, count: Int) { // Copy data since pointer is only valid during this call let data = Data(bytes: pointer, count: count) let message = URLSessionWebSocketTask.Message.data(data) socket?.send(message) { error in if let error = error { print("Send error: \(error)") } } } func handleMetadata(_ metadata: AudioStreamMetadata) { self.metadata = metadata // Send format info to server let encoder = JSONEncoder() if let data = try? encoder.encode(metadata) { let message = URLSessionWebSocketTask.Message.data(data) socket?.send(message) { _ in } } } func handleStreamStart() { print("Audio stream started") } func handleStreamStop() { socket?.cancel(with: .normalClosure, reason: nil) print("Audio stream stopped") } } ``` -------------------------------- ### Append and Process Audio Chunks Source: https://context7.com/makeusabrew/audiotee/llms.txt Appends incoming audio data to an AudioBuffer and processes complete chunks using a callback. The `processChunks` method provides a pointer to the chunk data, which is valid only during the callback. ```swift // Append data (called from Core Audio IO callback) func audioCallback(data: UnsafeRawPointer, byteCount: Int) { buffer.append(from: data, count: byteCount) // Process complete chunks buffer.processChunks { chunkPointer, chunkSize in // chunkPointer valid only during this callback // Points directly into ring buffer (zero-copy) when contiguous processChunk(chunkPointer, size: chunkSize) } } func processChunk(_ pointer: UnsafeRawPointer, size: Int) { // Send to ASR service, write to file, etc. print("Processing \(size) byte chunk") } ``` -------------------------------- ### Capture Audio and Logs Separately Source: https://github.com/makeusabrew/audiotee/blob/main/README.md Redirect stdout to an audio file and stderr to a log file to separate audio data from logging information. This is useful for debugging and processing. ```bash # Capture audio and logs separately ./audiotee > audio.pcm 2> audiotee.log ``` -------------------------------- ### Implement a Silent Logger Source: https://context7.com/makeusabrew/audiotee/llms.txt Implement the AudioTeeLogger protocol to suppress all log output from AudioTeeCore. Useful for production builds where logging is not desired. ```swift import AudioTeeCore import os.log // Silent logger - suppress all output class NullLogger: AudioTeeLogger { func debug(_ message: String, context: [String: String]?) {} func info(_ message: String, context: [String: String]?) {} func error(_ message: String, context: [String: String]?) {} } ``` -------------------------------- ### Exclude Specific Processes from Tapping Source: https://github.com/makeusabrew/audiotee/blob/main/README.md Use the --exclude-processes flag to prevent AudioTee from capturing audio from specified process IDs. This is useful for avoiding unwanted audio sources. ```bash # Tap everything *except* a specific process (by PID) ./audiotee --exclude-processes 1234 ``` ```bash # Exclude multiple specific processes ./audiotee --exclude-processes 1234 5678 9012 ``` -------------------------------- ### Transform Audio Data with Converter Source: https://context7.com/makeusabrew/audiotee/llms.txt Processes audio data using an AudioFormatConverter. The `transform` method takes a closure that receives the converted audio data. Handles conversion failures by indicating that the original format should be used. ```swift // Transform audio data (typically called from processChunks callback) func processAudio(sourcePointer: UnsafeRawPointer, count: Int) { let success = converter.transform(from: sourcePointer, count: count) { outPtr, outCount in // outPtr is valid only during this callback // Write to file, network, etc. print("Converted: \(count) bytes -> \(outCount) bytes") } if !success { // Conversion failed - could pass through original data print("Conversion failed, using original format") } } ``` -------------------------------- ### Set Custom Chunk Duration Source: https://github.com/makeusabrew/audiotee/blob/main/README.md Configure the duration of audio chunks written to stdout using the --chunk-duration flag. The default is 0.2 seconds, with a maximum of 5.0 seconds. ```bash # Custom chunk duration (default 0.2 seconds, max 5.0) ./audiotee --chunk-duration 0.1 ``` -------------------------------- ### Mute Tapped Processes Source: https://github.com/makeusabrew/audiotee/blob/main/README.md The --mute flag silences the audio output of the processes that AudioTee is currently tapping. This ensures that tapped audio does not play through speakers. ```bash # Mute processes being tapped (so they don't play through speakers) ./audiotee --mute ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.