Last active
May 12, 2021 15:28
-
-
Save junpluse/ee6d031654dd07c39fc7d8fbab80d6ed to your computer and use it in GitHub Desktop.
AVQueuePlayer.repeatMode = .All
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// AVPlayer+Repeat.swift | |
// | |
// Created by Jun Tanaka on 4/1/16. | |
// Copyright © 2016 eje Inc. All rights reserved. | |
// | |
import AVFoundation | |
private final class RepeatManager: NSObject { | |
weak var player: AVPlayer? | |
var mode: AVPlayer.RepeatMode = .None | |
init(player: AVPlayer) { | |
self.player = player | |
super.init() | |
startObservingCurrentItem(of: player) | |
if let playerItem = player.currentItem { | |
startObservingNotifications(of: playerItem) | |
} | |
} | |
deinit { | |
guard let player = player else { | |
return | |
} | |
stopObservingCurrentItem(of: player) | |
if let playerItem = player.currentItem { | |
stopObservingNotifications(of: playerItem) | |
} | |
} | |
func startObservingCurrentItem(of player: AVPlayer) { | |
player.addObserver(self, forKeyPath: "currentItem", options: [.Old, .New], context: nil) | |
} | |
func stopObservingCurrentItem(of player: AVPlayer) { | |
player.removeObserver(self, forKeyPath: "currentItem") | |
} | |
func startObservingNotifications(of playerItem: AVPlayerItem) { | |
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(RepeatManager.observe(AVPlayerItemDidPlayToEndTimeNotification:)), name: AVPlayerItemDidPlayToEndTimeNotification, object: playerItem) | |
} | |
func stopObservingNotifications(of playerItem: AVPlayerItem) { | |
NSNotificationCenter.defaultCenter().removeObserver(self, name: AVPlayerItemDidPlayToEndTimeNotification, object: playerItem) | |
} | |
@objc func observe(AVPlayerItemDidPlayToEndTimeNotification notification: NSNotification) { | |
guard let player = player, let currentItem = player.currentItem where currentItem == (notification.object as? AVPlayerItem) else { | |
return | |
} | |
switch (mode, player) { | |
case (.All, let queuePlayer as AVQueuePlayer): | |
queuePlayer.advanceToNextItem() | |
currentItem.seekToTime(kCMTimeZero) | |
queuePlayer.insertItem(currentItem, afterItem: nil) | |
case (.One, _), (.All, _): | |
currentItem.seekToTime(kCMTimeZero) | |
default: | |
break | |
} | |
} | |
override func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer<Void>) { | |
if (object as? AVPlayer) == player && keyPath == "currentItem" { | |
if let oldItem = change?[NSKeyValueChangeOldKey] as? AVPlayerItem { | |
stopObservingNotifications(of: oldItem) | |
} | |
if let newItem = change?[NSKeyValueChangeNewKey] as? AVPlayerItem { | |
startObservingNotifications(of: newItem) | |
} | |
} | |
} | |
} | |
public extension AVPlayer { | |
private struct CustomProperties { | |
static var repeatManager: RepeatManager? = nil | |
} | |
private var repeatManager: RepeatManager? { | |
get { | |
return objc_getAssociatedObject(self, &CustomProperties.repeatManager) as? RepeatManager | |
} | |
set(value) { | |
objc_setAssociatedObject(self, &CustomProperties.repeatManager, value, .OBJC_ASSOCIATION_RETAIN) | |
} | |
} | |
enum RepeatMode { | |
case None | |
case One | |
case All // for AVQueuePlayer | |
} | |
var repeatMode: RepeatMode { | |
get { | |
return repeatManager?.mode ?? .None | |
} | |
set(mode) { | |
if repeatManager == nil { | |
repeatManager = RepeatManager(player: self) | |
} | |
repeatManager?.mode = mode | |
switch mode { | |
case .One: | |
actionAtItemEnd = .None | |
case _ where isKindOfClass(AVQueuePlayer.self): | |
actionAtItemEnd = .Advance | |
case .All: | |
actionAtItemEnd = .None | |
default: | |
actionAtItemEnd = .Pause | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment