diff --git a/Package.swift b/Package.swift index 9906ed2..a9a878a 100644 --- a/Package.swift +++ b/Package.swift @@ -8,7 +8,37 @@ let package = Package( platforms: [ .macOS("14.2") ], + products: [ + // Library that can be imported by other packages + .library( + name: "AudioTeeCore", + targets: ["AudioTeeCore"] + ), + // CLI executable + .executable( + name: "audiotee", + targets: ["AudioTeeCLI"] + ) + ], targets: [ - .executableTarget(name: "audiotee") + // Core library with all business logic + .target( + name: "AudioTeeCore", + path: "Sources/AudioTeeCore" + ), + + // CLI executable that uses the library + .executableTarget( + name: "AudioTeeCLI", + dependencies: ["AudioTeeCore"], + path: "Sources/AudioTeeCLI" + ), + + // Tests for the library + .testTarget( + name: "AudioTeeCoreTests", + dependencies: ["AudioTeeCore"], + path: "Tests/AudioTeeCoreTests" + ) ] -) +) \ No newline at end of file diff --git a/Sources/CLI/ArgumentParser.swift b/Sources/AudioTeeCLI/ArgumentParser.swift similarity index 100% rename from Sources/CLI/ArgumentParser.swift rename to Sources/AudioTeeCLI/ArgumentParser.swift diff --git a/Sources/CLI/AudioTee.swift b/Sources/AudioTeeCLI/AudioTee.swift similarity index 99% rename from Sources/CLI/AudioTee.swift rename to Sources/AudioTeeCLI/AudioTee.swift index ae3a73f..12b5b63 100644 --- a/Sources/CLI/AudioTee.swift +++ b/Sources/AudioTeeCLI/AudioTee.swift @@ -1,3 +1,4 @@ +import AudioTeeCore import CoreAudio import Foundation diff --git a/Sources/main.swift b/Sources/AudioTeeCLI/main.swift similarity index 73% rename from Sources/main.swift rename to Sources/AudioTeeCLI/main.swift index 4f1427f..d035603 100644 --- a/Sources/main.swift +++ b/Sources/AudioTeeCLI/main.swift @@ -1,3 +1,4 @@ +import AudioTeeCore import AudioToolbox import Foundation diff --git a/Sources/Core/AudioBuffer.swift b/Sources/AudioTeeCore/Core/AudioBuffer.swift similarity index 100% rename from Sources/Core/AudioBuffer.swift rename to Sources/AudioTeeCore/Core/AudioBuffer.swift diff --git a/Sources/Core/AudioFormatConverter.swift b/Sources/AudioTeeCore/Core/AudioFormatConverter.swift similarity index 100% rename from Sources/Core/AudioFormatConverter.swift rename to Sources/AudioTeeCore/Core/AudioFormatConverter.swift diff --git a/Sources/Core/AudioFormatManager.swift b/Sources/AudioTeeCore/Core/AudioFormatManager.swift similarity index 100% rename from Sources/Core/AudioFormatManager.swift rename to Sources/AudioTeeCore/Core/AudioFormatManager.swift diff --git a/Sources/Core/AudioPacket.swift b/Sources/AudioTeeCore/Core/AudioPacket.swift similarity index 100% rename from Sources/Core/AudioPacket.swift rename to Sources/AudioTeeCore/Core/AudioPacket.swift diff --git a/Sources/Core/AudioRecorder.swift b/Sources/AudioTeeCore/Core/AudioRecorder.swift similarity index 98% rename from Sources/Core/AudioRecorder.swift rename to Sources/AudioTeeCore/Core/AudioRecorder.swift index c093178..9a7aecd 100644 --- a/Sources/Core/AudioRecorder.swift +++ b/Sources/AudioTeeCore/Core/AudioRecorder.swift @@ -10,7 +10,7 @@ public class AudioRecorder { private var outputHandler: AudioOutputHandler private var converter: AudioFormatConverter? - init( + public init( deviceID: AudioObjectID, outputHandler: AudioOutputHandler, convertToSampleRate: Double? = nil, chunkDuration: Double = 0.2 ) { @@ -51,7 +51,7 @@ public class AudioRecorder { } } - func startRecording() { + public func startRecording() { Logger.debug("Starting audio recording") // Log format info and send metadata for final format @@ -112,7 +112,7 @@ public class AudioRecorder { return noErr } - func stopRecording() { + public func stopRecording() { processAudioBuffer() outputHandler.handleStreamStop() cleanupIOProc() diff --git a/Sources/Core/AudioStreamMetadata.swift b/Sources/AudioTeeCore/Core/AudioStreamMetadata.swift similarity index 100% rename from Sources/Core/AudioStreamMetadata.swift rename to Sources/AudioTeeCore/Core/AudioStreamMetadata.swift diff --git a/Sources/Core/AudioTapManager.swift b/Sources/AudioTeeCore/Core/AudioTapManager.swift similarity index 96% rename from Sources/Core/AudioTapManager.swift rename to Sources/AudioTeeCore/Core/AudioTapManager.swift index 893473f..9594531 100644 --- a/Sources/Core/AudioTapManager.swift +++ b/Sources/AudioTeeCore/Core/AudioTapManager.swift @@ -3,10 +3,12 @@ import AudioToolbox import CoreAudio import Foundation -class AudioTapManager { +public class AudioTapManager { private var tapID: AudioObjectID? private var deviceID: AudioObjectID? + public init() {} + deinit { Logger.debug("Cleaning up audio tap manager") @@ -22,7 +24,7 @@ class AudioTapManager { } /// Sets up the audio tap and aggregate device - func setupAudioTap(with config: TapConfiguration) throws { + public func setupAudioTap(with config: TapConfiguration) throws { Logger.debug("Setting up audio tap manager") tapID = try createSystemAudioTap(with: config) @@ -38,7 +40,7 @@ class AudioTapManager { } /// Returns the aggregate device ID for recording - func getDeviceID() -> AudioObjectID? { + public func getDeviceID() -> AudioObjectID? { return deviceID } diff --git a/Sources/Core/AudioTeeErrors.swift b/Sources/AudioTeeCore/Core/AudioTeeErrors.swift similarity index 100% rename from Sources/Core/AudioTeeErrors.swift rename to Sources/AudioTeeCore/Core/AudioTeeErrors.swift diff --git a/Sources/CLI/TapConfiguration.swift b/Sources/AudioTeeCore/Core/TapConfiguration.swift similarity index 100% rename from Sources/CLI/TapConfiguration.swift rename to Sources/AudioTeeCore/Core/TapConfiguration.swift diff --git a/Sources/CLI/TapMuteBehavior.swift b/Sources/AudioTeeCore/Core/TapMuteBehavior.swift similarity index 100% rename from Sources/CLI/TapMuteBehavior.swift rename to Sources/AudioTeeCore/Core/TapMuteBehavior.swift diff --git a/Sources/Output/AudioOutputProtocol.swift b/Sources/AudioTeeCore/Output/AudioOutputProtocol.swift similarity index 100% rename from Sources/Output/AudioOutputProtocol.swift rename to Sources/AudioTeeCore/Output/AudioOutputProtocol.swift diff --git a/Sources/Output/Handlers/BinaryOutputHandler.swift b/Sources/AudioTeeCore/Output/BinaryOutputHandler.swift similarity index 96% rename from Sources/Output/Handlers/BinaryOutputHandler.swift rename to Sources/AudioTeeCore/Output/BinaryOutputHandler.swift index a932353..883a75b 100644 --- a/Sources/Output/Handlers/BinaryOutputHandler.swift +++ b/Sources/AudioTeeCore/Output/BinaryOutputHandler.swift @@ -1,6 +1,8 @@ import Foundation public class BinaryAudioOutputHandler: AudioOutputHandler { + public init() {} + public func handleAudioPacket(_ packet: AudioPacket) { // TODO: should we use a DispatchQueue instead of writing directly? // Write raw binary audio data directly to stdout diff --git a/Sources/Output/MessageType.swift b/Sources/AudioTeeCore/Output/MessageType.swift similarity index 100% rename from Sources/Output/MessageType.swift rename to Sources/AudioTeeCore/Output/MessageType.swift diff --git a/Sources/Utils/Logger.swift b/Sources/AudioTeeCore/Utils/Logger.swift similarity index 100% rename from Sources/Utils/Logger.swift rename to Sources/AudioTeeCore/Utils/Logger.swift diff --git a/Sources/Utils/Utils.swift b/Sources/AudioTeeCore/Utils/Utils.swift similarity index 100% rename from Sources/Utils/Utils.swift rename to Sources/AudioTeeCore/Utils/Utils.swift diff --git a/Tests/AudioTeeCoreTests/AudioPacketTests.swift b/Tests/AudioTeeCoreTests/AudioPacketTests.swift new file mode 100644 index 0000000..35898ac --- /dev/null +++ b/Tests/AudioTeeCoreTests/AudioPacketTests.swift @@ -0,0 +1,30 @@ +import XCTest +@testable import AudioTeeCore + +final class AudioPacketTests: XCTestCase { + func testPacketCreation() { + let timestamp = Date() + let duration = 1.0 + let data = Data([0x01, 0x02, 0x03, 0x04]) + + let packet = AudioPacket( + timestamp: timestamp, + duration: duration, + data: data + ) + + XCTAssertEqual(packet.timestamp, timestamp) + XCTAssertEqual(packet.duration, duration) + XCTAssertEqual(packet.data, data) + } + + func testPacketDataSize() { + let packet = AudioPacket( + timestamp: Date(), + duration: 0.5, + data: Data(repeating: 0xFF, count: 1024) + ) + + XCTAssertEqual(packet.data.count, 1024) + } +} \ No newline at end of file