Skip to content

Commit

Permalink
Merge commit '785e68df381105dee0e75fef1fe18d700f864c66' into FEM-1248-…
Browse files Browse the repository at this point in the history
…Core

* commit '785e68df381105dee0e75fef1fe18d700f864c66':
  add supported version under CC sdk dependency (#143)
  replace raw value to asString (#141)
  Fem 1333 (#140)
  FEM-1318 (#139)
  FEM-1320 (#138)
  Fem 1311 (#136)
  General improvements (#135)

# Conflicts:
#	Classes/Providers/OTT/Services/OTTAssetService.swift
  • Loading branch information
srivkas committed Apr 22, 2017
2 parents 2e769a3 + 785e68d commit a657375
Show file tree
Hide file tree
Showing 26 changed files with 442 additions and 196 deletions.
31 changes: 23 additions & 8 deletions Classes/Managers/AppState/AppStateSubject.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ protocol AppStateSubjectProtocol: class, AppStateProviderDelegate {
/// The app state events provider.
var appStateProvider: AppStateProvider { get }
/// The current app state observers.
var observers: [AppStateObservable] { get set }
var observers: [AppStateObserver] { get set }
/// States whether currently observing.
/// - note: when mocking set initial value to false.
var isObserving: Bool { get set }
Expand Down Expand Up @@ -50,20 +50,23 @@ extension AppStateSubjectProtocol {
/// Adds an observer to inform when state events are posted.
func add(observer: AppStateObservable) {
sync {
cleanObservers()
PKLog.trace("add observer, \(observer)")
// if no observers were available start observing now
if observers.count == 0 && !isObserving {
startObservingAppState()
}
observers.append(observer)
observers.append(AppStateObserver(observer))
}
}

/// Removes an observer to stop being inform when state events are posted.
func remove(observer: AppStateObservable) {
sync {
cleanObservers()
// search for the observer to remove
for i in 0..<observers.count {
if observers[i] === observer {
if observers[i].observer === observer {
let removedObserver = observers.remove(at: i)
PKLog.trace("removed observer, \(removedObserver)")
// if no more observers available stop observing
Expand Down Expand Up @@ -94,10 +97,11 @@ extension AppStateSubjectProtocol {
func appStateEventPosted(name: ObservationName) {
sync {
PKLog.trace("app state event posted with name: \(name.rawValue)")
for observer in self.observers {
let filteredObservations = observer.observations.filter { $0.name == name }
for observation in filteredObservations {
observation.onObserve()
for appStateObserver in self.observers {
if let filteredObservations = appStateObserver.observer?.observations.filter({ $0.name == name }) {
for observation in filteredObservations {
observation.onObserve()
}
}
}
}
Expand All @@ -111,6 +115,10 @@ extension AppStateSubjectProtocol {
objc_sync_exit(lock)
}

/// remove nil observers from our list
private func cleanObservers() {
self.observers = self.observers.filter { $0.observer != nil }
}
}

/************************************************************/
Expand All @@ -135,7 +143,7 @@ final class AppStateSubject: AppStateSubjectProtocol {

let lock: AnyObject = UUID().uuidString as AnyObject

var observers = [AppStateObservable]()
var observers = [AppStateObserver]()
var appStateProvider: AppStateProvider
var isObserving = false
}
Expand All @@ -161,6 +169,13 @@ func == (lhs: NotificationObservation, rhs: NotificationObservation) -> Bool {
return lhs.name.rawValue == rhs.name.rawValue
}

class AppStateObserver: AnyObject {
weak var observer: AppStateObservable?
init(_ observer: AppStateObservable) {
self.observer = observer
}
}

/// A type that provides a set of NotificationObservation to observe.
/// This interface defines the observations we would want in our class, for example a set of [willTerminate, didEnterBackground etc.]
protocol AppStateObservable: AnyObject {
Expand Down
8 changes: 6 additions & 2 deletions Classes/MessageBus.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,15 @@
import Foundation

private struct Observation {
/// the observer of the event
weak var observer: AnyObject?
/// the dispatchQueue to observe the events on.
let observeOn: DispatchQueue
/// the block of code to be performed when event fires.
let block: (PKEvent) -> Void
}

/// `MessageBus` object handles all event message observing and posting
@objc public class MessageBus: NSObject {
private var observations = [String: [Observation]]()
private let lock: AnyObject = UUID().uuidString as AnyObject
Expand All @@ -28,7 +32,7 @@ private struct Observation {

private func add(observer: AnyObject, events: [PKEvent.Type], observeOn dispatchQueue: DispatchQueue = DispatchQueue.main, block: @escaping (PKEvent)->Void) {
sync {
PKLog.debug("Add observer: \(observer) for events: \(events)")
PKLog.debug("Add observer: \(String(describing: observer)) for events: \(String(describing: events))")
events.forEach { (et) in
let typeId = NSStringFromClass(et)
var observationList: [Observation] = observations[typeId] ?? []
Expand All @@ -40,7 +44,7 @@ private struct Observation {

@objc public func removeObserver(_ observer: AnyObject, events: [PKEvent.Type]) {
sync {
PKLog.debug("Remove observer: \(observer) for events: \(events)")
PKLog.debug("Remove observer: \(String(describing: observer)) for events: \(String(describing: events))")
events.forEach { (et) in
let typeId = NSStringFromClass(et)

Expand Down
42 changes: 42 additions & 0 deletions Classes/Network/KalturaPlaybackRequestAdapter.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
//
// KalturaPlaybackRequestAdapter.swift
// Pods
//
// Created by Gal Orlanczyk on 05/04/2017.
//
//

import Foundation

class KalturaPlaybackRequestAdapter: PKRequestParamsAdapter {

private var playSessionId: UUID

init(playSessionId: UUID) {
self.playSessionId = playSessionId
}

public static func setup(player: Player) {
let adapter = KalturaPlaybackRequestAdapter(playSessionId: player.sessionId)
player.settings.set(contentRequestAdapter: adapter)
}

public func adapt(requestParams: PKRequestParams) -> PKRequestParams {
guard requestParams.url.path.contains("/playManifest/") else { return requestParams }
guard var urlComponents = URLComponents(url: requestParams.url, resolvingAgainstBaseURL: false) else { return requestParams }
// add query items to the request
let queryItems = [URLQueryItem(name: "playSessionId", value: self.playSessionId.uuidString), URLQueryItem(name: "clientTag", value: PlayKitManager.clientTag)]
if var urlQueryItems = urlComponents.queryItems {
urlQueryItems += queryItems
urlComponents.queryItems = urlQueryItems
} else {
urlComponents.queryItems = queryItems
}
// create the url
guard let url = urlComponents.url else {
PKLog.debug("failed to create url after appending query items")
return requestParams
}
return PKRequestParams(url: url, headers: requestParams.headers)
}
}
26 changes: 26 additions & 0 deletions Classes/PKRequestParams.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
//
// PKRequestInfo.swift
// Pods
//
// Created by Gal Orlanczyk on 04/04/2017.
//
//

import Foundation

/// `PKRequestParamsDecorator` used for getting updated request info
@objc public protocol PKRequestParamsAdapter {
func adapt(requestParams: PKRequestParams) -> PKRequestParams
}

@objc public class PKRequestParams: NSObject {

public let url: URL
public let headers: [String: String]?

init(url: URL, headers: [String: String]?) {
self.url = url
self.headers = headers
}
}

51 changes: 29 additions & 22 deletions Classes/Player/AVPlayerEngine/AVPlayerEngine.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ class AVPlayerEngine: AVPlayer {

private var avPlayerLayer: AVPlayerLayer!
private var _view: PlayerView!
private var isDestroyed = false

/// Keeps reference on the last timebase rate in order to post events accuratly.
var lastTimebaseRate: Float64 = 0
var lastBitrate: Double = 0
Expand Down Expand Up @@ -158,9 +158,7 @@ class AVPlayerEngine: AVPlayer {
}

deinit {
if !isDestroyed {
self.destroy()
}
PKLog.debug("\(String(describing: type(of: self))), was deinitialized")
}

func stop() {
Expand All @@ -171,31 +169,40 @@ class AVPlayerEngine: AVPlayer {
}

override func pause() {
if self.rate > 0 {
// Playing, so pause.
PKLog.debug("pause player")
super.pause()
// makes sure play/pause call is made on the main thread (calling on background thread has unpredictable behaviours)
DispatchQueue.main.async {
if self.rate > 0 {
// Playing, so pause.
PKLog.debug("pause player")
super.pause()
}
}
}

override func play() {
if self.rate == 0 {
PKLog.debug("play player")
self.post(event: PlayerEvent.Play())
super.play()
// makes sure play/pause call is made on the main thread (calling on background thread has unpredictable behaviours)
DispatchQueue.main.async {
if self.rate == 0 {
PKLog.debug("play player")
self.post(event: PlayerEvent.Play())
super.play()
}
}
}

func destroy() {
PKLog.info("destroy player")
self.removeObservers()
self.avPlayerLayer = nil
self._view = nil
self.onEventBlock = nil
// removes app state observer
AppStateSubject.shared.remove(observer: self)
self.replaceCurrentItem(with: nil)
self.isDestroyed = true
// make sure to call destroy on main thread synchronously.
// this make sure everything will be cleared without any race conditions
DispatchQueue.main.async {
PKLog.info("destroy player")
self.removeObservers()
self.avPlayerLayer = nil
self._view = nil
self.onEventBlock = nil
// removes app state observer
AppStateSubject.shared.remove(observer: self)
self.replaceCurrentItem(with: nil)
}
}

@available(iOS 9.0, *)
Expand All @@ -214,7 +221,7 @@ class AVPlayerEngine: AVPlayer {
}

func post(event: PKEvent) {
PKLog.trace("onEvent:: \(event)")
PKLog.trace("onEvent:: \(String(describing: event))")
onEventBlock?(event)
}

Expand Down
6 changes: 3 additions & 3 deletions Classes/Player/AssetBuilder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ class AssetBuilder {
return nil
}

func build(readyCallback: @escaping (Error?, AVAsset?)->Void) -> Void {
func build(readyCallback: @escaping (Error?, AVAsset?) -> Void) -> Void {

guard let (source, handlerClass) = getPreferredMediaSource() else {
PKLog.error("No playable sources")
Expand All @@ -80,11 +80,11 @@ class AssetBuilder {

protocol AssetHandler {
init()
func buildAsset(mediaSource: MediaSource, readyCallback: @escaping (Error?, AVAsset?)->Void)
func buildAsset(mediaSource: MediaSource, readyCallback: @escaping (Error?, AVAsset?) -> Void)
}

protocol RefreshableAssetHandler: AssetHandler {
func shouldRefreshAsset(mediaSource: MediaSource, refreshCallback: @escaping (Bool)->Void)
func shouldRefreshAsset(mediaSource: MediaSource, refreshCallback: @escaping (Bool) -> Void)
func refreshAsset(mediaSource: MediaSource)
}

Expand Down
8 changes: 4 additions & 4 deletions Classes/Player/DefaultAssetHandler.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@ class DefaultAssetHandler: AssetHandler {

}

func buildAsset(mediaSource: MediaSource, readyCallback: @escaping (Error?, AVAsset?)->Void) {
func buildAsset(mediaSource: MediaSource, readyCallback: @escaping (Error?, AVAsset?) -> Void) {

guard let contentUrl = mediaSource.contentUrl else {
guard let contentUrl = mediaSource.contentUrl, let playbackUrl = mediaSource.playbackUrl else {
PKLog.error("Invalid media: no url")
readyCallback(AssetError.invalidContentUrl(nil), nil)
return
Expand All @@ -46,7 +46,7 @@ class DefaultAssetHandler: AssetHandler {

guard let drmData = mediaSource.drmData?.first else {
PKLog.debug("Creating clear AVURLAsset")
readyCallback(nil, AVURLAsset(url: contentUrl))
readyCallback(nil, AVURLAsset(url: playbackUrl))
return
}

Expand All @@ -63,7 +63,7 @@ class DefaultAssetHandler: AssetHandler {
return
}

let asset = AVURLAsset(url: contentUrl)
let asset = AVURLAsset(url: playbackUrl)

self.assetLoaderDelegate = AssetLoaderDelegate.configureRemotePlay(asset: asset, drmData: fpsData)

Expand Down
Loading

0 comments on commit a657375

Please sign in to comment.