Files
SwiftAudioEx/SwiftAudio/Classes/Observer/AVPlayerTimeObserver.swift

107 lines
3.2 KiB
Swift

//
// AudioPlayerTimeEventObserver.swift
// SwiftAudio
//
// Created by Jørgen Henrichsen on 09/03/2018.
// Copyright © 2018 Jørgen Henrichsen. All rights reserved.
//
import Foundation
import AVFoundation
protocol AVPlayerTimeObserverDelegate: class {
func audioDidStart()
func timeEvent(time: CMTime)
}
/**
Class for observing time-based events from the AVPlayer
*/
class AVPlayerTimeObserver {
/// The time to use as start boundary time. Cannot be zero.
private static let startBoundaryTime: CMTime = CMTime(value: 1, timescale: 1000)
var boundaryTimeStartObserverToken: Any?
var periodicTimeObserverToken: Any?
weak var player: AVPlayer? {
willSet {
unregisterForBoundaryTimeEvents()
unregisterForPeriodicEvents()
}
}
/// The frequence to receive periodic time events.
/// Setting this to a new value will trigger a re-registering to the periodic events of the player.
var periodicObserverTimeInterval: CMTime {
didSet {
if oldValue != periodicObserverTimeInterval {
registerForPeriodicTimeEvents()
}
}
}
weak var delegate: AVPlayerTimeObserverDelegate?
init(periodicObserverTimeInterval: CMTime) {
self.periodicObserverTimeInterval = periodicObserverTimeInterval
}
deinit {
unregisterForPeriodicEvents()
unregisterForBoundaryTimeEvents()
}
/**
Will register for the AVPlayer BoundaryTimeEvents, to trigger start and complete events.
*/
func registerForBoundaryTimeEvents() {
guard let player = player else {
return
}
unregisterForBoundaryTimeEvents()
let startBoundaryTimes: [NSValue] = [AVPlayerTimeObserver.startBoundaryTime].map({NSValue(time: $0)})
boundaryTimeStartObserverToken = player.addBoundaryTimeObserver(forTimes: startBoundaryTimes, queue: nil, using: { [weak self] in
self?.delegate?.audioDidStart()
})
}
/**
Unregister from the boundary events of the player.
*/
func unregisterForBoundaryTimeEvents() {
guard let player = player, let boundaryTimeStartObserverToken = boundaryTimeStartObserverToken else {
return
}
player.removeTimeObserver(boundaryTimeStartObserverToken)
self.boundaryTimeStartObserverToken = nil
}
/**
Start observing periodic time events.
Will trigger unregisterForPeriodicEvents() first to avoid multiple subscriptions.
*/
func registerForPeriodicTimeEvents() {
guard let player = player else {
return
}
unregisterForPeriodicEvents()
periodicTimeObserverToken = player.addPeriodicTimeObserver(forInterval: periodicObserverTimeInterval, queue: nil, using: { (time) in
self.delegate?.timeEvent(time: time)
})
}
/**
Unregister for periodic events.
*/
func unregisterForPeriodicEvents() {
guard let player = player, let periodicTimeObserverToken = periodicTimeObserverToken else {
return
}
player.removeTimeObserver(periodicTimeObserverToken)
self.periodicTimeObserverToken = nil
}
}