From c409238ef9a89898da6cae3a37a73e1b5b4ece43 Mon Sep 17 00:00:00 2001 From: dcvz Date: Tue, 5 Mar 2024 09:11:38 +0100 Subject: [PATCH 1/3] Use AS runners --- .github/workflows/validate.yml | 7 ++----- README.md | 35 ++++++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 5 deletions(-) diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml index aadcf53..a3c5701 100644 --- a/.github/workflows/validate.yml +++ b/.github/workflows/validate.yml @@ -9,13 +9,10 @@ concurrency: cancel-in-progress: true jobs: unit-tests: - runs-on: macos-latest + runs-on: blaze/macos-14 strategy: matrix: - destination: - [ - 'platform=iOS Simulator,name=iPhone 12 Pro', - ] + destination: ["platform=iOS Simulator,name=iPhone 15 Pro"] steps: - name: Checkout Repo uses: actions/checkout@v2 diff --git a/README.md b/README.md index 359aba2..3565720 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,8 @@ SwiftAudioEx is an audio player written in Swift, making it simpler to work with audio playback from streams and files. +_[Blaze](https://runblaze.dev) sponsors SwiftAudioEx by providing super fast Apple Silicon based macOS Github Action Runners. Use the discount code `RNTP50` at checkout to get 50% off your first year._ + ## Example To see the audio player in action, run the example project! @@ -16,11 +18,13 @@ XCode project navigator and Build/Run it in a simulator (or on an actual device). ## Requirements + iOS 11.0+ ## Installation ### Swift Package Manager + [Swift Package Manager](https://swift.org/package-manager/) (SwiftPM) is a tool for managing the distribution of Swift code as well as C-family dependency. From Xcode 11, SwiftPM got natively integrated with Xcode. SwiftAudioEx supports SwiftPM from version 0.12.0. To use SwiftPM, you should use Xcode 11 to open your project. Click `File` -> `Swift Packages` -> `Add Package Dependency`, enter [SwiftAudioEx repo's URL](https://github.com/doublesymmetry/SwiftAudio.git). Or you can login Xcode with your GitHub account and just type `SwiftAudioEx` to search. @@ -40,6 +44,7 @@ let package = Package( ``` ### CocoaPods + SwiftAudioEx is available through [CocoaPods](http://cocoapods.org). To install it, simply add the following line to your Podfile: @@ -48,16 +53,21 @@ pod 'SwiftAudioEx', '~> 1.0.0' ``` ### Carthage + SwiftAudioEx supports [Carthage](https://github.com/Carthage/Carthage). Add this to your Cartfile: + ```ruby github "doublesymmetry/SwiftAudioEx" ~> 1.0.0 ``` + Then follow the rest of Carthage instructions on [adding a framework](https://github.com/Carthage/Carthage#adding-frameworks-to-an-application). ## Usage ### AudioPlayer + To get started playing some audio: + ```swift let player = AudioPlayer() let audioItem = DefaultAudioItem(audioUrl: "someUrl", sourceType: .stream) @@ -66,6 +76,7 @@ player.load(item: audioItem, playWhenReady: true) // Load the item and start pla To listen for events in the `AudioPlayer`, subscribe to events found in the `event` property of the `AudioPlayer`. To subscribe to an event: + ```swift class MyCustomViewController: UIViewController { @@ -83,7 +94,9 @@ class MyCustomViewController: UIViewController { ``` #### QueuedAudioPlayer + The `QueuedAudioPlayer` is a subclass of `AudioPlayer` that maintains a queue of audio tracks. + ```swift let player = QueuedAudioPlayer() let audioItem = DefaultAudioItem(audioUrl: "someUrl", sourceType: .stream) @@ -93,7 +106,9 @@ player.add(item: audioItem, playWhenReady: true) // Since this is the first item When a track is done playing, the player will load the next track and update the queue. ##### Navigating the queue + All `AudioItem`s are stored in either `previousItems` or `nextItems`, which refers to items that come prior to the `currentItem` and after, respectively. The queue is navigated with: + ```swift player.next() // Increments the queue, and loads the next item. player.previous() // Decrements the queue, and loads the previous item. @@ -101,13 +116,16 @@ player.jumpToItem(atIndex:) // Jumps to a certain item and loads that item. ``` ##### Manipulating the queue + ```swift player.removeItem(at:) // Remove a specific item from the queue. player.removeUpcomingItems() // Remove all items in nextItems. ``` ### Configuring the AudioPlayer + Current options for configuring the `AudioPlayer`: + - `bufferDuration`: The amount of seconds to be buffered by the player. - `timeEventFrequency`: How often the player should call the delegate with time progress events. - `automaticallyWaitsToMinimizeStalling`: Indicates whether the player should automatically delay playback in order to minimize stalling. @@ -117,10 +135,13 @@ Current options for configuring the `AudioPlayer`: - `audioTimePitchAlgorithm`: This value decides the `AVAudioTimePitchAlgorithm` used for each `AudioItem`. Implement `TimePitching` in your `AudioItem`-subclass to override individually for each `AudioItem`. Options particular to `QueuedAudioPlayer`: + - `repeatMode`: The repeat mode: off, track, queue ### Audio Session + Remember to activate an audio session with an appropriate category for your app. This can be done with `AudioSessionController`: + ```swift try? AudioSessionController.shared.set(category: .playback) //... @@ -133,34 +154,43 @@ try? AudioSessionController.shared.activateSession() App Settings -> Capabilities -> Background Modes -> Check 'Audio, AirPlay, and Picture in Picture'. #### Interruptions + If you are using the `AudioSessionController` for setting up the audio session, you can use it to handle interruptions too. Implement `AudioSessionControllerDelegate` and you will be notified by `handleInterruption(type: AVAudioSessionInterruptionType)`. If you are storing progress for playback time on items when the app quits, it can be a good idea to do it on interruptions as well. To disable interruption notifcations set `isObservingForInterruptions` to `false`. ### Now Playing Info + The `AudioPlayer` can automatically update `nowPlayingInfo` for you. This requires `automaticallyUpdateNowPlayingInfo` to be true (default), and that the `AudioItem` that is passed in return values for the getters. The `AudioPlayer` will update: artist, title, album, artwork, elapsed time, duration and rate. Additional properties for items can be set by accessing the setter of the `nowPlayingInforController`: + ```swift let player = AudioPlayer() player.load(item: someItem) player.nowPlayingInfoController.set(keyValue: NowPlayingInfoProperty.isLiveStream(true)) ``` + The set(keyValue:) and set(keyValues:) accept both `MediaItemProperty` and `NowPlayingInfoProperty`. The info can be forced to reload/update from the `AudioPlayer`. + ```swift audioPlayer.loadNowPlayingMetaValues() audioPlayer.updateNowPlayingPlaybackValues() ``` + The current info can be cleared with: + ```swift audioPlayer.nowPlayingInfoController.clear() ``` ### Remote Commands + To enable remote commands for the player you need to populate the RemoteCommands array for the player: + ```swift audioPlayer.remoteCommands = [ .play, @@ -169,19 +199,24 @@ audioPlayer.remoteCommands = [ .skipBackward(intervals: [30]), ] ``` + These commands will be activated for each `AudioItem`. If you need some audio items to have different commands, implement `RemoteCommandable` in a custom `AudioItem`-subclass. These commands will override the commands found in `AudioPlayer.remoteCommands` so make sure to supply all commands you need for that particular `AudioItem`. #### Custom handlers for remote commands + To supply custom handlers for your remote commands, just override the handlers contained in the player's `RemoteCommandController`: + ```swift let player = QueuedAudioPlayer() player.remoteCommandController.handlePlayCommand = { (event) in // Handle remote command here. } ``` + All available overrides can be found by looking at `RemoteCommandController`. ### Start playback from a certain point in time + Make your `AudioItem`-subclass conform to `InitialTiming` to be able to start playback from a certain time. ## Author From 5e4418aef6446b595b2ad94af98b2a1028aeea3d Mon Sep 17 00:00:00 2001 From: dcvz Date: Tue, 5 Mar 2024 09:21:07 +0100 Subject: [PATCH 2/3] Update workflow to use xcbeautify --- .github/workflows/validate.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml index a3c5701..9e6edf8 100644 --- a/.github/workflows/validate.yml +++ b/.github/workflows/validate.yml @@ -16,8 +16,10 @@ jobs: steps: - name: Checkout Repo uses: actions/checkout@v2 + - name: Set up build tools + run: brew install xcbeautify - name: Run Tests run: |- - xcodebuild test -scheme SwiftAudioEx -destination "${destination}" -enableCodeCoverage YES + set -o pipefail && xcodebuild test -scheme SwiftAudioEx -destination "${destination}" -enableCodeCoverage YES | xcbeautify --renderer github-actions env: destination: ${{ matrix.destination }} From 0ebbf9078dce5ff870f05613fef3496c1acd63ab Mon Sep 17 00:00:00 2001 From: dcvz Date: Tue, 5 Mar 2024 09:32:19 +0100 Subject: [PATCH 3/3] revert using xcbeautify --- .github/workflows/validate.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml index 9e6edf8..a3c5701 100644 --- a/.github/workflows/validate.yml +++ b/.github/workflows/validate.yml @@ -16,10 +16,8 @@ jobs: steps: - name: Checkout Repo uses: actions/checkout@v2 - - name: Set up build tools - run: brew install xcbeautify - name: Run Tests run: |- - set -o pipefail && xcodebuild test -scheme SwiftAudioEx -destination "${destination}" -enableCodeCoverage YES | xcbeautify --renderer github-actions + xcodebuild test -scheme SwiftAudioEx -destination "${destination}" -enableCodeCoverage YES env: destination: ${{ matrix.destination }}