diff --git a/README.md b/README.md index f570b5f..57b6e79 100644 --- a/README.md +++ b/README.md @@ -1,164 +1,92 @@ -# 🎧 AudioEngine SDK – Advanced Audio Conversion for iOS +# AudioEngine -**AudioEngine SDK** is a lightweight, high-performance iOS framework that brings robust **audio format conversion** capabilities to your appβ€”particularly for formats that Apple does **not support natively**, such as **OGG**, **OGA**, and **MPEG**. +AudioEngine is a small iOS Swift package that presents one request-based API for audio conversion. It routes OGG/OGA input through [`swift-ogg`](https://github.com/element-hq/swift-ogg) and other declared formats through [`SFBAudioEngine`](https://github.com/sbooth/SFBAudioEngine). -Built on top of powerful open-source libraries like **SFBAudioEngine** and **SwiftOgg**, this SDK makes it easy to **convert, encode, and decode** a wide range of audio formats for both playback and processing. +This repository is a focused wrapper and learning project. It does not claim to replace the underlying codec libraries or provide benchmarked performance guarantees. ---- +## What it demonstrates -## πŸš€ Features +- Swift Package Manager library design +- An async, throwing conversion boundary +- A builder that validates required input and creates a default output URL +- Format-specific routing and typed errors +- Dependency-backed audio conversion without exposing dependency APIs to callers -- πŸ”„ **Bidirectional Format Conversion** - - Convert `.m4a`, `.wav` ➝ `.mp3`, `.ogg` - - Convert `.ogg`, `.oga`, `.mpeg` ➝ `.mp3`, `.m4a` +## Requirements -- βš™οΈ **Powered by Proven Libraries** - - 🎧 **SFBAudioEngine**: High-quality encoding and decoding for MP3 and other popular formats - - πŸŒ€ **SwiftOgg**: Native support for Ogg and Oga formats +- iOS 15+ +- Swift 5.7+ +- Xcode 14+ -- πŸ“± **Seamless Integration** - - Optimized for use in any iOS app requiring audio format compatibility - - Straightforward API for converting files with minimal setup +## Installation ---- +In Xcode, select **File β†’ Add Package Dependencies** and enter: -## πŸ“¦ Installation - -### Swift Package Manager (Recommended) - -Add the following to your `Package.swift`: - -```swift -.package(url: "https://github.com/Alenroyfeild/AudioEngine.git", from: "0.0.1") +```text +https://github.com/Alenroyfeild/AudioEngine.git ``` -Or via Xcode: - -1. Go to **File > Add Packages** -2. Enter the repo URL: `https://github.com/Alenroyfeild/AudioEngine.git` -3. Choose your version and target -4. Finish integration - -> βœ… The SDK internally uses `SFBAudioEngine` and `SwiftOgg` for codec support β€” no extra configuration is required. - ---- - -## πŸ“Œ Why Use AudioEngine SDK? - -### ❌ Native iOS Limitations: -- No built-in support for **OGG**, **OGA**, and some **MPEG** formats -- Cannot **encode to MP3** -- `.m4a` (default iOS format) isn’t ideal for cross-platform use - -### βœ… AudioEngine SDK Solves This By: -- Supporting conversion of audio to widely used formats like **MP3** and **OGG** -- Enabling your app to **play, upload, or share** non-native formats -- Offering a clean and modern API to handle audio format needs effortlessly +The repository does not currently publish a tagged semantic version. When adding it, select the `main` branch or pin an exact commit. A tagged release should be preferred once one is available. ---- - -## πŸ” Example Conversion Scenarios - -| Use Case | Conversion Path | -|-----------------------|----------------------------------| -| Playback Support | `.ogg`, `.mpeg` ➝ `.mp3` | -| Upload Compatibility | `.m4a`, `.wav` ➝ `.mp3`, `.ogg` | -| Audio Processing | Any ➝ Target format of choice | - ---- - -## 🧱 Usage - -### Option 1: Manual Request Initialization +## Usage ```swift -let request = AudioConversionRequest( - sourceURL: inputFileURL, - inputFormat: .wav, - outputFormat: .mp3, - outputURL: outputFileURL -) - -try AudioEngine.shared.convert(request) -``` - -### Option 2: Using the Builder Pattern (Recommended) +import AudioEngine -```swift let request = try AudioConversionRequestBuilder() - .setSourceURL(inputFileURL) - .setInputFormat(.ogg) + .setSourceURL(inputURL) + .setInputFormat(.wav) + .setOutputFormat(.mp3) + .setOutputURL(outputURL) .build() -try AudioEngine.shared.convert(request) +let didConvert = try await AudioEngine.convert(request: request) ``` -> ℹ️ **Note:** If the input format is `.ogg` or `.oga`, the output format is automatically set to `.m4a` and cannot be changed. - -### Optional: Set Output Format and Output URL +For OGG/OGA input, the builder fixes the output format to M4A: ```swift let request = try AudioConversionRequestBuilder() - .setSourceURL(inputFileURL) - .setInputFormat(.wav) - .setOutputFormat(.mp3) - .setOutputURL(customOutputURL) + .setSourceURL(oggURL) + .setInputFormat(.ogg) .build() -``` - ---- - -## βš™οΈ Format Handling Rules - -- `.ogg` and `.oga` inputs: - - Output format is **forced to `.m4a`** - - Attempting to override will be ignored -- If `outputURL` is not set: - - A default file will be generated in the same directory, with a `_converted` suffix ---- - -## βœ… Benefits - -- 🧩 **Fills a Native Gap** – Adds support for audio formats missing on iOS -- ⚑ **Fast & Efficient** – Optimized for large audio files -- πŸ§ͺ **Production Ready** – Verified in real-world use cases -- πŸ› οΈ **Extensible** – Easily fits into any audio pipeline - ---- - -## πŸ“‚ Perfect For - -- πŸŽ™οΈ Audio recording or podcast apps -- πŸ“€ Media upload and sharing tools -- πŸŽ›οΈ Custom audio processing utilities -- πŸ“± Any iOS app needing format compatibility - ---- +try await AudioEngine.convert(request: request) +``` -## πŸ” Licensing & Maintenance +When no output URL is supplied, the builder writes beside the source using `_converted.`. -- βœ… Fully approved under licenses compatible with commercial apps -- πŸ”„ Maintained for compatibility with latest iOS versions -- πŸ›‘οΈ Built-in error handling and fallbacks reduce failure risk +## Declared formats and routing ---- +| Input | Requested output | Route | +| --- | --- | --- | +| OGG, OGA | M4A (enforced) | `swift-ogg` | +| M4A, MP3, WAV, MPEG, AMR | Caller-selected declared format | `SFBAudioEngine` | -## πŸ“£ Coming Soon +Actual codec support depends on the underlying libraries and the audio content. A declared enum case is not a guarantee that every codec/container combination will convert successfully; failures are surfaced as `AudioEngineError`. -- πŸ“Š Conversion progress monitoring -- πŸ“ Batch conversion API -- 🎚️ Output quality presets +## Design ---- +```text +AudioConversionRequestBuilder + ↓ validates and supplies defaults +AudioConversionRequest + ↓ +AudioEngine.convert(request:) + β”œβ”€β”€ OGG / OGA β†’ swift-ogg β†’ M4A + └── other input β†’ SFBAudioEngine AudioConverter +``` -## πŸ’¬ Need Help? +## Tests -Open an issue or reach out to the maintainers via GitHub Discussions. +The test target covers request-builder rules that do not require audio fixtures: ---- +```bash +swift test +``` -**AudioEngine SDK** gives you full control over audio formatsβ€”making your app more compatible, more powerful, and future-proof. +End-to-end codec tests with licensed fixture files are still to be added. See this as a transparent limitation, not an implied guarantee. ---- +## License +AudioEngine is available under the [MIT License](LICENSE). Applications must also comply with the licenses of `SFBAudioEngine`, `swift-ogg`, and the codecs they use. diff --git a/Sources/AudioEngine/AudioFormat.swift b/Sources/AudioEngine/AudioFormat.swift index 5faeb28..ed435ea 100644 --- a/Sources/AudioEngine/AudioFormat.swift +++ b/Sources/AudioEngine/AudioFormat.swift @@ -8,7 +8,7 @@ /// Represents supported audio formats for conversion operations. /// /// Each case in `AudioFormat` corresponds to a commonly used audio format that can be used as an input or output in audio conversion processes. -public enum AudioFormat: String, CaseIterable { +public enum AudioFormat: String, CaseIterable, Equatable { /// MPEG-4 Audio format (.m4a) case m4a /// MPEG Layer III Audio format (.mp3) @@ -45,4 +45,3 @@ public enum AudioFormat: String, CaseIterable { } } } - diff --git a/Tests/AudioEngineTests/AudioConversionRequestBuilderTests.swift b/Tests/AudioEngineTests/AudioConversionRequestBuilderTests.swift new file mode 100644 index 0000000..9149b4b --- /dev/null +++ b/Tests/AudioEngineTests/AudioConversionRequestBuilderTests.swift @@ -0,0 +1,43 @@ +import Foundation +import XCTest +@testable import AudioEngine + +final class AudioConversionRequestBuilderTests: XCTestCase { + func testOggInputForcesM4AOutputAndGeneratesDestination() throws { + let source = URL(fileURLWithPath: "/tmp/voice.ogg") + + let request = try AudioConversionRequestBuilder() + .setSourceURL(source) + .setInputFormat(.ogg) + .setOutputFormat(.mp3) + .build() + + XCTAssertEqual(request.inputFormat, .ogg) + XCTAssertEqual(request.outputFormat, .m4a) + XCTAssertEqual(request.outputURL, URL(fileURLWithPath: "/tmp/voice_converted.m4a")) + } + + func testConfiguredOutputIsPreserved() throws { + let source = URL(fileURLWithPath: "/tmp/source.wav") + let destination = URL(fileURLWithPath: "/tmp/export.mp3") + + let request = try AudioConversionRequestBuilder() + .setSourceURL(source) + .setInputFormat(.wav) + .setOutputFormat(.mp3) + .setOutputURL(destination) + .build() + + XCTAssertEqual(request.outputURL, destination) + XCTAssertEqual(request.outputFormat, .mp3) + } + + func testMissingSourceThrows() { + XCTAssertThrowsError( + try AudioConversionRequestBuilder() + .setInputFormat(.wav) + .setOutputFormat(.mp3) + .build() + ) + } +}