Compare commits
11 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 56d0633df0 | |||
| 825e508ecb | |||
| 76d9dc17af | |||
| 8ceb0216a0 | |||
| db41634631 | |||
| 15843b5fe8 | |||
| 4241b484b2 | |||
| 92bf0b96b6 | |||
| 457dff7c01 | |||
| c90e9c4976 | |||
| 649bb01e89 |
@@ -68,9 +68,9 @@ class AudioPlayerTests: XCTestCase {
|
||||
|
||||
func test_AudioPlayer__state__pausing_source__should_be_paused() {
|
||||
let expectation = XCTestExpectation()
|
||||
listener.stateUpdate = { state in
|
||||
listener.stateUpdate = { [weak audioPlayer] state in
|
||||
switch state {
|
||||
case .playing: self.audioPlayer.pause()
|
||||
case .playing: audioPlayer?.pause()
|
||||
case .paused: expectation.fulfill()
|
||||
default: break
|
||||
}
|
||||
@@ -82,11 +82,11 @@ class AudioPlayerTests: XCTestCase {
|
||||
func test_AudioPlayer__state__stopping_source__should_be_idle() {
|
||||
let expectation = XCTestExpectation()
|
||||
var hasBeenPlaying: Bool = false
|
||||
listener.stateUpdate = { state in
|
||||
listener.stateUpdate = { [weak audioPlayer] state in
|
||||
switch state {
|
||||
case .playing:
|
||||
hasBeenPlaying = true
|
||||
self.audioPlayer.stop()
|
||||
audioPlayer?.stop()
|
||||
case .idle:
|
||||
if hasBeenPlaying {
|
||||
expectation.fulfill()
|
||||
@@ -117,22 +117,6 @@ class AudioPlayerTests: XCTestCase {
|
||||
// wait(for: [expectation], timeout: 20.0)
|
||||
// }
|
||||
|
||||
func test_AudioPlayer__currentTime__when_loading_source_with_intial_time__should_be_equal_to_initial_time() {
|
||||
let expectation = XCTestExpectation()
|
||||
let item = DefaultAudioItemInitialTime(audioUrl: LongSource.path, artist: nil, title: nil, albumTitle: nil, sourceType: .file, artwork: nil, initialTime: 4.0)
|
||||
listener.stateUpdate = { state in
|
||||
switch state {
|
||||
case .ready:
|
||||
if self.audioPlayer.currentTime == item.getInitialTime() {
|
||||
expectation.fulfill()
|
||||
}
|
||||
default: break
|
||||
}
|
||||
}
|
||||
try? audioPlayer.load(item: item, playWhenReady: false)
|
||||
wait(for: [expectation], timeout: 20.0)
|
||||
}
|
||||
|
||||
// MARK: - Rate
|
||||
|
||||
func test_AudioPlayer__rate__should_be_0() {
|
||||
@@ -141,10 +125,11 @@ class AudioPlayerTests: XCTestCase {
|
||||
|
||||
func test_AudioPlayer__rate__playing_source__should_be_1() {
|
||||
let expectation = XCTestExpectation()
|
||||
listener.stateUpdate = { state in
|
||||
listener.stateUpdate = { [weak audioPlayer] state in
|
||||
guard let audioPlayer = audioPlayer else { return }
|
||||
switch state {
|
||||
case .playing:
|
||||
if self.audioPlayer.rate == 1.0 {
|
||||
if audioPlayer.rate == 1.0 {
|
||||
expectation.fulfill()
|
||||
}
|
||||
default: break
|
||||
@@ -162,10 +147,11 @@ class AudioPlayerTests: XCTestCase {
|
||||
|
||||
func test_AudioPlayer__currentItem__loading_source__should_not_be_nil() {
|
||||
let expectation = XCTestExpectation()
|
||||
listener.stateUpdate = { state in
|
||||
listener.stateUpdate = { [weak audioPlayer] state in
|
||||
guard let audioPlayer = audioPlayer else { return }
|
||||
switch state {
|
||||
case .ready:
|
||||
if self.audioPlayer.currentItem != nil {
|
||||
if audioPlayer.currentItem != nil {
|
||||
expectation.fulfill()
|
||||
}
|
||||
default: break
|
||||
@@ -191,12 +177,20 @@ class AudioPlayerEventListener {
|
||||
var secondsElapse: ((_ seconds: TimeInterval) -> Void)?
|
||||
var seekCompletion: (() -> Void)?
|
||||
|
||||
weak var audioPlayer: AudioPlayer?
|
||||
|
||||
init(audioPlayer: AudioPlayer) {
|
||||
audioPlayer.event.stateChange.addListener(self, handleDidUpdateState)
|
||||
audioPlayer.event.seek.addListener(self, handleSeek)
|
||||
audioPlayer.event.secondElapse.addListener(self, handleSecondsElapse)
|
||||
}
|
||||
|
||||
deinit {
|
||||
audioPlayer?.event.stateChange.removeListener(self)
|
||||
audioPlayer?.event.seek.removeListener(self)
|
||||
audioPlayer?.event.secondElapse.removeListener(self)
|
||||
}
|
||||
|
||||
func handleDidUpdateState(state: AudioPlayerState) {
|
||||
self.state = state
|
||||
}
|
||||
|
||||
@@ -25,13 +25,13 @@ SwiftAudio is available through [CocoaPods](http://cocoapods.org). To install
|
||||
it, simply add the following line to your Podfile:
|
||||
|
||||
```ruby
|
||||
pod 'SwiftAudio', '~> 0.9.2'
|
||||
pod 'SwiftAudio', '~> 0.9.3'
|
||||
```
|
||||
|
||||
### Carthage
|
||||
SwiftAudio supports [Carthage](https://github.com/Carthage/Carthage). Add this to your Cartfile:
|
||||
```ruby
|
||||
github "jorgenhenrichsen/SwiftAudio" ~> 0.9.2
|
||||
github "jorgenhenrichsen/SwiftAudio" ~> 0.9.3
|
||||
```
|
||||
Then follow the rest of Carthage instructions on [adding a framework](https://github.com/Carthage/Carthage#adding-frameworks-to-an-application).
|
||||
|
||||
@@ -63,18 +63,6 @@ class MyCustomViewController: UIViewController {
|
||||
}
|
||||
```
|
||||
|
||||
If you want to use the [Combine](https://developer.apple.com/documentation/combine) framework for events, each event in the `AudioPlayer` has an `EventPublisher` that can be subscribed to:
|
||||
```swift
|
||||
let audioPlayer = AudioPlayer()
|
||||
audioPlayer.event.stateChange.publisher.subscribe(subscriber: someSubscriber)
|
||||
|
||||
/// Using a Sink
|
||||
audioPlayer.event.stateChange.publisher.sink { state in
|
||||
/// Handle state change here.
|
||||
}
|
||||
```
|
||||
**Important**: This requires iOS version equal to or later than 13.0. If an application needs to support older iOS versions it is recommended to use the regular `Event.addListener(listener:)` method.
|
||||
|
||||
#### QueuedAudioPlayer
|
||||
The `QueuedAudioPlayer` is a subclass of `AudioPlayer` that maintains a queue of audio tracks.
|
||||
```swift
|
||||
|
||||
+1
-1
@@ -8,7 +8,7 @@
|
||||
|
||||
Pod::Spec.new do |s|
|
||||
s.name = 'SwiftAudio'
|
||||
s.version = '0.9.2'
|
||||
s.version = '0.9.3'
|
||||
s.summary = 'Easy audio streaming for iOS'
|
||||
|
||||
# This description is used to generate tags and improve search results.
|
||||
|
||||
@@ -10,20 +10,18 @@ import Foundation
|
||||
|
||||
public struct APError {
|
||||
|
||||
public enum LoadError: Error {
|
||||
enum LoadError: Error {
|
||||
case invalidSourceUrl(String)
|
||||
}
|
||||
|
||||
public enum PlaybackError: Error {
|
||||
enum PlaybackError: Error {
|
||||
case noLoadedItem
|
||||
}
|
||||
|
||||
public enum QueueError: Error {
|
||||
enum QueueError: Error {
|
||||
case noPreviousItem
|
||||
case noNextItem
|
||||
case invalidIndex(index: Int, message: String)
|
||||
}
|
||||
|
||||
public enum EventError: Error {}
|
||||
|
||||
}
|
||||
|
||||
@@ -168,6 +168,8 @@ class AVPlayerWrapper: AVPlayerWrapperProtocol {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
func load(from url: URL, playWhenReady: Bool) {
|
||||
reset(soft: true)
|
||||
_playWhenReady = playWhenReady
|
||||
@@ -176,10 +178,15 @@ class AVPlayerWrapper: AVPlayerWrapperProtocol {
|
||||
recreateAVPlayer()
|
||||
}
|
||||
|
||||
// Set item
|
||||
self._pendingAsset = AVURLAsset(url: url)
|
||||
|
||||
if let pendingAsset = _pendingAsset {
|
||||
pendingAsset.loadValuesAsynchronously(forKeys: [Constants.assetPlayableKey], completionHandler: {
|
||||
pendingAsset.loadValuesAsynchronously(forKeys: [Constants.assetPlayableKey], completionHandler: { [weak self] in
|
||||
|
||||
guard let self = self else {
|
||||
return
|
||||
}
|
||||
|
||||
var error: NSError? = nil
|
||||
let status = pendingAsset.statusOfValue(forKey: Constants.assetPlayableKey, error: &error)
|
||||
|
||||
@@ -201,7 +208,6 @@ class AVPlayerWrapper: AVPlayerWrapperProtocol {
|
||||
break
|
||||
|
||||
case .failed:
|
||||
// print("load asset failed")
|
||||
if isPendingAsset {
|
||||
self.delegate?.AVWrapper(failedWithError: error)
|
||||
self._pendingAsset = nil
|
||||
@@ -209,7 +215,6 @@ class AVPlayerWrapper: AVPlayerWrapperProtocol {
|
||||
break
|
||||
|
||||
case .cancelled:
|
||||
// print("load asset cancelled")
|
||||
break
|
||||
|
||||
default:
|
||||
@@ -233,10 +238,8 @@ class AVPlayerWrapper: AVPlayerWrapperProtocol {
|
||||
playerTimeObserver.unregisterForBoundaryTimeEvents()
|
||||
playerItemNotificationObserver.stopObservingCurrentItem()
|
||||
|
||||
if self._pendingAsset != nil {
|
||||
self._pendingAsset?.cancelLoading()
|
||||
self._pendingAsset = nil
|
||||
}
|
||||
self._pendingAsset?.cancelLoading()
|
||||
self._pendingAsset = nil
|
||||
|
||||
if !soft {
|
||||
avPlayer.replaceCurrentItem(with: nil)
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import Combine
|
||||
|
||||
extension AudioPlayer {
|
||||
|
||||
@@ -70,7 +69,7 @@ extension AudioPlayer {
|
||||
|
||||
class Invoker<EventData> {
|
||||
|
||||
/// Signals false if the listener object is nil. If `false` is signaled, the invoker should not be retained.
|
||||
// Signals false if the listener object is nil
|
||||
let invoke: (EventData) -> Bool
|
||||
weak var listener: AnyObject?
|
||||
|
||||
@@ -115,7 +114,7 @@ extension AudioPlayer {
|
||||
self.invokersSemaphore.signal()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func emit(data: EventData) {
|
||||
eventQueue.async {
|
||||
self.invokersSemaphore.wait()
|
||||
@@ -126,34 +125,6 @@ extension AudioPlayer {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
The publisher for this event. Use this for subscription through the Combine framework.
|
||||
*/
|
||||
@available(iOS 13.0, *)
|
||||
public lazy var publisher: EventPublisher<EventData> = EventPublisher(event: self)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@available(iOS 13.0, *)
|
||||
extension AudioPlayer {
|
||||
|
||||
public class EventPublisher<EventData>: Publisher {
|
||||
|
||||
public typealias Output = EventData
|
||||
public typealias Failure = APError.EventError
|
||||
|
||||
private weak var event: Event<EventData>?
|
||||
|
||||
init(event: Event<EventData>) {
|
||||
self.event = event
|
||||
}
|
||||
|
||||
public func receive<S>(subscriber: S) where S : Subscriber, Failure == S.Failure, Output == S.Input {
|
||||
event?.addListener(self) { (data) in
|
||||
let _ = subscriber.receive(data)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -22,9 +22,15 @@ class AVPlayerItemNotificationObserver {
|
||||
|
||||
private let notificationCenter: NotificationCenter = NotificationCenter.default
|
||||
|
||||
weak var observingItem: AVPlayerItem?
|
||||
private(set) weak var observingItem: AVPlayerItem?
|
||||
weak var delegate: AVPlayerItemNotificationObserverDelegate?
|
||||
|
||||
private(set) var isObserving: Bool = false
|
||||
|
||||
deinit {
|
||||
stopObservingCurrentItem()
|
||||
}
|
||||
|
||||
/**
|
||||
Will start observing notifications from an item.
|
||||
|
||||
@@ -34,6 +40,7 @@ class AVPlayerItemNotificationObserver {
|
||||
func startObserving(item: AVPlayerItem) {
|
||||
stopObservingCurrentItem()
|
||||
observingItem = item
|
||||
isObserving = true
|
||||
notificationCenter.addObserver(self, selector: #selector(itemDidPlayToEndTime), name: NSNotification.Name.AVPlayerItemDidPlayToEndTime, object: item)
|
||||
}
|
||||
|
||||
@@ -41,10 +48,12 @@ class AVPlayerItemNotificationObserver {
|
||||
Stop receiving notifications for the current item.
|
||||
*/
|
||||
func stopObservingCurrentItem() {
|
||||
if let observingItem = observingItem {
|
||||
notificationCenter.removeObserver(self, name: NSNotification.Name.AVPlayerItemDidPlayToEndTime, object: observingItem)
|
||||
guard let observingItem = observingItem, isObserving else {
|
||||
return
|
||||
}
|
||||
observingItem = nil
|
||||
self.notificationCenter.removeObserver(self, name: NSNotification.Name.AVPlayerItemDidPlayToEndTime, object: observingItem)
|
||||
self.observingItem = nil
|
||||
self.isObserving = false
|
||||
}
|
||||
|
||||
@objc private func itemDidPlayToEndTime() {
|
||||
|
||||
@@ -30,37 +30,34 @@ class AVPlayerItemObserver: NSObject {
|
||||
static let loadedTimeRanges = #keyPath(AVPlayerItem.loadedTimeRanges)
|
||||
}
|
||||
|
||||
var isObserving: Bool = false
|
||||
private(set) var isObserving: Bool = false
|
||||
|
||||
weak var observingItem: AVPlayerItem?
|
||||
private(set) weak var observingItem: AVPlayerItem?
|
||||
weak var delegate: AVPlayerItemObserverDelegate?
|
||||
|
||||
deinit {
|
||||
if self.isObserving {
|
||||
stopObservingCurrentItem()
|
||||
}
|
||||
stopObservingCurrentItem()
|
||||
}
|
||||
|
||||
/**
|
||||
Start observing an item. Will remove self as observer from old item.
|
||||
Start observing an item. Will remove self as observer from old item, if any.
|
||||
|
||||
- parameter item: The player item to observe.
|
||||
*/
|
||||
func startObserving(item: AVPlayerItem) {
|
||||
main.async {
|
||||
if self.isObserving {
|
||||
self.stopObservingCurrentItem()
|
||||
}
|
||||
self.isObserving = true
|
||||
self.observingItem = item
|
||||
item.addObserver(self, forKeyPath: AVPlayerItemKeyPath.duration, options: [.new], context: &AVPlayerItemObserver.context)
|
||||
item.addObserver(self, forKeyPath: AVPlayerItemKeyPath.loadedTimeRanges, options: [.new], context: &AVPlayerItemObserver.context)
|
||||
}
|
||||
self.stopObservingCurrentItem()
|
||||
self.isObserving = true
|
||||
self.observingItem = item
|
||||
item.addObserver(self, forKeyPath: AVPlayerItemKeyPath.duration, options: [.new], context: &AVPlayerItemObserver.context)
|
||||
item.addObserver(self, forKeyPath: AVPlayerItemKeyPath.loadedTimeRanges, options: [.new], context: &AVPlayerItemObserver.context)
|
||||
}
|
||||
|
||||
func stopObservingCurrentItem() {
|
||||
observingItem?.removeObserver(self, forKeyPath: AVPlayerItemKeyPath.duration, context: &AVPlayerItemObserver.context)
|
||||
observingItem?.removeObserver(self, forKeyPath: AVPlayerItemKeyPath.loadedTimeRanges, context: &AVPlayerItemObserver.context)
|
||||
guard let observingItem = observingItem, isObserving else {
|
||||
return
|
||||
}
|
||||
observingItem.removeObserver(self, forKeyPath: AVPlayerItemKeyPath.duration, context: &AVPlayerItemObserver.context)
|
||||
observingItem.removeObserver(self, forKeyPath: AVPlayerItemKeyPath.loadedTimeRanges, context: &AVPlayerItemObserver.context)
|
||||
self.isObserving = false
|
||||
self.observingItem = nil
|
||||
}
|
||||
|
||||
@@ -36,10 +36,9 @@ class AVPlayerObserver: NSObject {
|
||||
static let timeControlStatus = #keyPath(AVPlayer.timeControlStatus)
|
||||
}
|
||||
|
||||
|
||||
private let statusChangeOptions: NSKeyValueObservingOptions = [.new, .initial]
|
||||
private let timeControlStatusChangeOptions: NSKeyValueObservingOptions = [.new]
|
||||
var isObserving: Bool = false
|
||||
private(set) var isObserving: Bool = false
|
||||
|
||||
weak var delegate: AVPlayerObserverDelegate?
|
||||
weak var player: AVPlayer? {
|
||||
@@ -66,13 +65,12 @@ class AVPlayerObserver: NSObject {
|
||||
}
|
||||
|
||||
func stopObserving() {
|
||||
guard let player = player, self.isObserving else {
|
||||
guard let player = player, isObserving else {
|
||||
return
|
||||
}
|
||||
player.removeObserver(self, forKeyPath: AVPlayerKeyPath.status, context: &AVPlayerObserver.context)
|
||||
player.removeObserver(self, forKeyPath: AVPlayerKeyPath.timeControlStatus, context: &AVPlayerObserver.context)
|
||||
self.isObserving = false
|
||||
|
||||
}
|
||||
|
||||
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
|
||||
@@ -107,7 +105,6 @@ class AVPlayerObserver: NSObject {
|
||||
}
|
||||
|
||||
private func handleTimeControlStatusChange(_ change: [NSKeyValueChangeKey: Any]?) {
|
||||
|
||||
let status: AVPlayer.TimeControlStatus
|
||||
if let statusNumber = change?[.newKey] as? NSNumber {
|
||||
status = AVPlayer.TimeControlStatus(rawValue: statusNumber.intValue)!
|
||||
|
||||
@@ -10,10 +10,8 @@ import Foundation
|
||||
import AVFoundation
|
||||
|
||||
protocol AVPlayerTimeObserverDelegate: class {
|
||||
|
||||
func audioDidStart()
|
||||
func timeEvent(time: CMTime)
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -50,6 +48,11 @@ class AVPlayerTimeObserver {
|
||||
self.periodicObserverTimeInterval = periodicObserverTimeInterval
|
||||
}
|
||||
|
||||
deinit {
|
||||
unregisterForPeriodicEvents()
|
||||
unregisterForBoundaryTimeEvents()
|
||||
}
|
||||
|
||||
/**
|
||||
Will register for the AVPlayer BoundaryTimeEvents, to trigger start and complete events.
|
||||
*/
|
||||
|
||||
@@ -79,6 +79,30 @@ public struct SkipIntervalCommand: RemoteCommandProtocol {
|
||||
|
||||
}
|
||||
|
||||
public struct FeedbackCommand: RemoteCommandProtocol {
|
||||
|
||||
public static let like = FeedbackCommand(id: "Like", commandKeyPath: \MPRemoteCommandCenter.likeCommand, handlerKeyPath: \RemoteCommandController.handleLikeCommand)
|
||||
|
||||
public static let dislike = FeedbackCommand(id: "Dislike", commandKeyPath: \MPRemoteCommandCenter.dislikeCommand, handlerKeyPath: \RemoteCommandController.handleDislikeCommand)
|
||||
|
||||
public static let bookmark = FeedbackCommand(id: "Bookmark", commandKeyPath: \MPRemoteCommandCenter.bookmarkCommand, handlerKeyPath: \RemoteCommandController.handleBookmarkCommand)
|
||||
|
||||
public typealias Command = MPFeedbackCommand
|
||||
|
||||
public let id: String
|
||||
|
||||
public var commandKeyPath: KeyPath<MPRemoteCommandCenter, MPFeedbackCommand>
|
||||
|
||||
public var handlerKeyPath: KeyPath<RemoteCommandController, RemoteCommandHandler>
|
||||
|
||||
func set(isActive: Bool, localizedTitle: String, localizedShortTitle: String) -> FeedbackCommand {
|
||||
MPRemoteCommandCenter.shared()[keyPath: commandKeyPath].isActive = isActive
|
||||
MPRemoteCommandCenter.shared()[keyPath: commandKeyPath].localizedTitle = localizedTitle
|
||||
MPRemoteCommandCenter.shared()[keyPath: commandKeyPath].localizedShortTitle = localizedShortTitle
|
||||
return self
|
||||
}
|
||||
}
|
||||
|
||||
public enum RemoteCommand {
|
||||
|
||||
case play
|
||||
@@ -99,6 +123,12 @@ public enum RemoteCommand {
|
||||
|
||||
case skipBackward(preferredIntervals: [NSNumber])
|
||||
|
||||
case like(isActive: Bool, localizedTitle: String, localizedShortTitle: String)
|
||||
|
||||
case dislike(isActive: Bool, localizedTitle: String, localizedShortTitle: String)
|
||||
|
||||
case bookmark(isActive: Bool, localizedTitle: String, localizedShortTitle: String)
|
||||
|
||||
/**
|
||||
All values in an array for convenience.
|
||||
Don't use for associated values.
|
||||
@@ -114,6 +144,9 @@ public enum RemoteCommand {
|
||||
.changePlaybackPosition,
|
||||
.skipForward(preferredIntervals: []),
|
||||
.skipBackward(preferredIntervals: []),
|
||||
.like(isActive: false, localizedTitle: "", localizedShortTitle: ""),
|
||||
.dislike(isActive: false, localizedTitle: "", localizedShortTitle: ""),
|
||||
.bookmark(isActive: false, localizedTitle: "", localizedShortTitle: "")
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
@@ -64,6 +64,12 @@ public class RemoteCommandController {
|
||||
case .changePlaybackPosition: self.enableCommand(ChangePlaybackPositionCommand.changePlaybackPosition)
|
||||
case .skipForward(let preferredIntervals): self.enableCommand(SkipIntervalCommand.skipForward.set(preferredIntervals: preferredIntervals))
|
||||
case .skipBackward(let preferredIntervals): self.enableCommand(SkipIntervalCommand.skipBackward.set(preferredIntervals: preferredIntervals))
|
||||
case .like(let isActive, let localizedTitle, let localizedShortTitle):
|
||||
self.enableCommand(FeedbackCommand.like.set(isActive: isActive, localizedTitle: localizedTitle, localizedShortTitle: localizedShortTitle))
|
||||
case .dislike(let isActive, let localizedTitle, let localizedShortTitle):
|
||||
self.enableCommand(FeedbackCommand.dislike.set(isActive: isActive, localizedTitle: localizedTitle, localizedShortTitle: localizedShortTitle))
|
||||
case .bookmark(let isActive, let localizedTitle, let localizedShortTitle):
|
||||
self.enableCommand(FeedbackCommand.bookmark.set(isActive: isActive, localizedTitle: localizedTitle, localizedShortTitle: localizedShortTitle))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,6 +84,9 @@ public class RemoteCommandController {
|
||||
case .changePlaybackPosition: self.disableCommand(ChangePlaybackPositionCommand.changePlaybackPosition)
|
||||
case .skipForward(_): self.disableCommand(SkipIntervalCommand.skipForward)
|
||||
case .skipBackward(_): self.disableCommand(SkipIntervalCommand.skipBackward)
|
||||
case .like(_, _, _): self.disableCommand(FeedbackCommand.like)
|
||||
case .dislike(_, _, _): self.disableCommand(FeedbackCommand.dislike)
|
||||
case .bookmark(_, _, _): self.disableCommand(FeedbackCommand.bookmark)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,6 +101,9 @@ public class RemoteCommandController {
|
||||
public lazy var handleChangePlaybackPositionCommand: RemoteCommandHandler = self.handleChangePlaybackPositionCommandDefault
|
||||
public lazy var handleNextTrackCommand: RemoteCommandHandler = self.handleNextTrackCommandDefault
|
||||
public lazy var handlePreviousTrackCommand: RemoteCommandHandler = self.handlePreviousTrackCommandDefault
|
||||
public lazy var handleLikeCommand: RemoteCommandHandler = self.handleLikeCommandDefault
|
||||
public lazy var handleDislikeCommand: RemoteCommandHandler = self.handleDislikeCommandDefault
|
||||
public lazy var handleBookmarkCommand: RemoteCommandHandler = self.handleBookmarkCommandDefault
|
||||
|
||||
private func handlePlayCommandDefault(event: MPRemoteCommandEvent) -> MPRemoteCommandHandlerStatus {
|
||||
if let audioPlayer = self.audioPlayer {
|
||||
@@ -180,6 +192,18 @@ public class RemoteCommandController {
|
||||
return MPRemoteCommandHandlerStatus.commandFailed
|
||||
}
|
||||
|
||||
private func handleLikeCommandDefault(event: MPRemoteCommandEvent) -> MPRemoteCommandHandlerStatus {
|
||||
return MPRemoteCommandHandlerStatus.success
|
||||
}
|
||||
|
||||
private func handleDislikeCommandDefault(event: MPRemoteCommandEvent) -> MPRemoteCommandHandlerStatus {
|
||||
return MPRemoteCommandHandlerStatus.success
|
||||
}
|
||||
|
||||
private func handleBookmarkCommandDefault(event: MPRemoteCommandEvent) -> MPRemoteCommandHandlerStatus {
|
||||
return MPRemoteCommandHandlerStatus.success
|
||||
}
|
||||
|
||||
private func getRemoteCommandHandlerStatus(forError error: Error) -> MPRemoteCommandHandlerStatus {
|
||||
if let error = error as? APError.LoadError {
|
||||
switch error {
|
||||
|
||||
Reference in New Issue
Block a user