Skip to content

Commit

Permalink
handle conflicts
Browse files Browse the repository at this point in the history
  • Loading branch information
Eliza Sapir committed May 10, 2017
2 parents 511ee0d + bd2eacb commit 884dc12
Show file tree
Hide file tree
Showing 36 changed files with 923 additions and 420 deletions.
31 changes: 17 additions & 14 deletions Addons/GoogleCast/BasicCastBuilder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,11 @@ import GoogleCast

*/
@objc public class BasicCastBuilder: NSObject {

@objc public enum StreamType: Int {
case live
case vod
case unknown
}

enum BasicBuilderDataError: Error {
Expand All @@ -33,23 +35,26 @@ import GoogleCast
@objc public var partnerID: String?
@objc public var uiconfID: String?
@objc public var adTagURL: String?
@objc public private(set) var streamType = GCKMediaStreamType.none
@objc public var metaData: GCKMediaMetadata?

@objc public var streamType = StreamType.unknown {
didSet {
switch streamType {
case .live: self.gckMediaStreamType = .live
case .vod: self.gckMediaStreamType = .buffered
case .unknown: self.gckMediaStreamType = .unknown
}
}
}
private var gckMediaStreamType = GCKMediaStreamType.unknown

/**
Set - stream type
- Parameter contentId: receiver contentId to play ( Entry id, or Asset id )
*/
@discardableResult
@objc public func set(streamType: StreamType) -> Self{

switch streamType {
case .live:
self.streamType = .live
case .vod:
self.streamType = .buffered
}
@nonobjc public func set(streamType: StreamType) -> Self {
self.streamType = streamType
return self
}

Expand All @@ -58,7 +63,7 @@ import GoogleCast
- Parameter contentId: receiver contentId to play ( Entry id, or Asset id )
*/
@discardableResult
@nonobjc public func set(contentId: String?) -> Self{
@nonobjc public func set(contentId: String?) -> Self {

guard contentId != nil,
contentId?.isEmpty == false
Expand Down Expand Up @@ -169,11 +174,9 @@ import GoogleCast
throw BasicCastBuilder.BasicBuilderDataError.missingContentId
}

guard self.streamType != nil else {
guard self.streamType != .unknown else {
throw BasicCastBuilder.BasicBuilderDataError.missingStreamType
}


}


Expand All @@ -185,7 +188,7 @@ import GoogleCast
try self.validate()
let customData = self.customData()
let mediaInfo: GCKMediaInformation = GCKMediaInformation(contentID:self.contentId,
streamType: self.streamType,
streamType: self.gckMediaStreamType,
contentType: "",
metadata: self.metaData,
streamDuration: 0,
Expand Down
30 changes: 13 additions & 17 deletions Addons/GoogleCast/CastAdInfoParser.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,31 +27,29 @@ public class CastAdInfoParser: NSObject, GCKRemoteMediaClientAdInfoParserDelegat
*/
public func remoteMediaClient(_ client: GCKRemoteMediaClient, shouldSetPlayingAdIn mediaStatus: GCKMediaStatus) -> Bool {

guard let customData = mediaStatus.customData as? [String:Any],
let adsInfo = customData["adsInfo"] as? [String:Any],
let metaData : AdsMetadata = AdsMetadata(dict: adsInfo) else {
PKLog.warning("No Ads info from receiver")
return false
guard let customData = mediaStatus.customData as? [String: Any], let adsInfo = customData["adsInfo"] as? [String: Any] else {
PKLog.warning("No Ads info from receiver")
return false
}
let metadata = AdsMetadata(dict: adsInfo)

return metaData.isPlayingAd

return metadata.isPlayingAd
}

/**
A list of playback positions at which the ads occur.
*/
public func remoteMediaClient(_ client: GCKRemoteMediaClient, shouldSetAdBreaksIn mediaStatus: GCKMediaStatus) -> [GCKAdBreakInfo]? {

guard let customData = mediaStatus.customData as? [String:Any],
let adsInfo = customData["adsInfo"] as? [String:Any],
let adsData : AdsMetadata = AdsMetadata(dict: adsInfo),
let adsBreakInfo = adsData.adsBreakInfo else {
PKLog.warning("No Ads info from receiver")
return nil
guard let customData = mediaStatus.customData as? [String: Any], let adsInfo = customData["adsInfo"] as? [String: Any] else {
PKLog.warning("No Ads info from receiver")
return nil
}

let metadata = AdsMetadata(dict: adsInfo)
let adsBreakInfo = metadata.adsBreakInfo ?? []
let adsBreakInfoArray = adsBreakInfo.map({ GCKAdBreakInfo(playbackPosition: TimeInterval($0)) })

return adsBreakInfoArray
}
}
Expand All @@ -71,18 +69,16 @@ private class AdsMetadata: NSObject {

if let isPlaying = dict["isPlayingAd"] as? Bool {
self.isPlayingAd = isPlaying
}else{
} else {
self.isPlayingAd = false
}

if let adBreaksInfo = dict["adsBreakInfo"] as? [NSNumber] {
self.adsBreakInfo = adBreaksInfo.map({ (number:NSNumber) -> Int in
return number.intValue
})
}else{
} else {
self.adsBreakInfo = nil
}


}
}
24 changes: 24 additions & 0 deletions Classes/Backend/OVP/Model/OVPLiveStreamEntry.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
//
// KalturaLiveStreamEntry.swift
// Pods
//
// Created by Gal Orlanczyk on 07/05/2017.
//
//

import Foundation
import SwiftyJSON

class OVPLiveStreamEntry: OVPEntry {

var dvrStatus: Bool?

let dvrStatusKey = "dvrStatus"

required init?(json: Any) {
super.init(json: json)

let jsonObject = JSON(json)
self.dvrStatus = jsonObject[dvrStatusKey].bool
}
}
2 changes: 2 additions & 0 deletions Classes/Backend/OVP/Parsers/OVPObjectMapper.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ class OVPObjectMapper: NSObject {
switch name {
case "KalturaMediaEntry":
return OVPEntry.self
case "KalturaLiveStreamEntry":
return OVPLiveStreamEntry.self
case "KalturaPlaybackContext":
return OVPPlaybackContext.self
case "KalturaAPIException":
Expand Down
2 changes: 1 addition & 1 deletion Classes/Managers/LocalAssetsManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ import AVFoundation
return source
}
} else {
if let source = sources.first(where: {$0.fileExt=="m3u8" && $0.drmData==nil}) {
if let source = sources.first(where: {$0.fileExt=="m3u8" && ($0.drmData == nil || $0.drmData!.isEmpty)}) {
return source
}
}
Expand Down
16 changes: 6 additions & 10 deletions Classes/Network/KalturaPlaybackRequestAdapter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,22 +10,18 @@ import Foundation

class KalturaPlaybackRequestAdapter: PKRequestParamsAdapter {

private var playSessionId: UUID
private var sessionId: String?

init(playSessionId: UUID) {
self.playSessionId = playSessionId
func updateRequestAdapter(withPlayer player: Player) {
self.sessionId = player.sessionId
}

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

public func adapt(requestParams: PKRequestParams) -> PKRequestParams {
func adapt(requestParams: PKRequestParams) -> PKRequestParams {
guard let sessionId = self.sessionId else { return requestParams }
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)]
let queryItems = [URLQueryItem(name: "playSessionId", value: sessionId), URLQueryItem(name: "clientTag", value: PlayKitManager.clientTag)]
if var urlQueryItems = urlComponents.queryItems {
urlQueryItems += queryItems
urlComponents.queryItems = urlQueryItems
Expand Down
10 changes: 5 additions & 5 deletions Classes/PKError.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,23 +18,23 @@ enum PlayerError: PKError {

case failedToLoadAssetFromKeys(rootError: NSError?)
case assetNotPlayable
case failedToPlayToEndTime(rootError: NSError)
case playerItemFailed(rootError: NSError)

static let domain = "com.kaltura.playkit.error.player"

var code: Int {
switch self {
case .failedToLoadAssetFromKeys: return PKErrorCode.failedToLoadAssetFromKeys
case .assetNotPlayable: return PKErrorCode.assetNotPlayable
case .failedToPlayToEndTime: return PKErrorCode.failedToPlayToEndTime
case .playerItemFailed: return PKErrorCode.playerItemFailed
}
}

var errorDescription: String {
switch self {
case .failedToLoadAssetFromKeys: return "Can't use this AVAsset because one of it's keys failed to load"
case .assetNotPlayable: return "Can't use this AVAsset because it isn't playable"
case .failedToPlayToEndTime: return "Item failed to play to its end time"
case .playerItemFailed: return "Player item failed to play"
}
}

Expand All @@ -46,7 +46,7 @@ enum PlayerError: PKError {
}
return [:]
case .assetNotPlayable: return [:]
case .failedToPlayToEndTime(let rootError): return [PKErrorKeys.RootErrorKey: rootError]
case .playerItemFailed(let rootError): return [PKErrorKeys.RootErrorKey: rootError]
}
}
}
Expand Down Expand Up @@ -236,7 +236,7 @@ struct PKErrorKeys {
// PlayerError
@objc(FailedToLoadAssetFromKeys) public static let failedToLoadAssetFromKeys = 7000
@objc(AssetNotPlayable) public static let assetNotPlayable = 7001
@objc(FailedToPlayToEndTime) public static let failedToPlayToEndTime = 7002
@objc(PlayerItemFailed) public static let playerItemFailed = 7002
// PlayerErrorLog
@objc(PlayerItemErrorLogEvent) public static let playerItemErrorLogEvent = 7100
// PKPluginError
Expand Down
1 change: 1 addition & 0 deletions Classes/PKRequestParams.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import Foundation

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

Expand Down
12 changes: 9 additions & 3 deletions Classes/Player/AVPlayerEngine/AVPlayerEngine+AssetLoading.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,15 @@ import AVFoundation

extension AVPlayerEngine {

override func replaceCurrentItem(with item: AVPlayerItem?) {
// when changing asset reset last timebase
self.lastTimebaseRate = 0
// When changing media (loading new asset) we want to reset isFirstReady in order to receive `CanPlay` & `LoadedMetadata` accuratly.
self.isFirstReady = true

super.replaceCurrentItem(with: item)
}

func asynchronouslyLoadURLAsset(_ newAsset: AVAsset) {
/*
Using AVAsset now runs the risk of blocking the current thread (the
Expand Down Expand Up @@ -59,9 +68,6 @@ extension AVPlayerEngine {

return
}

// When changing media (loading new asset) we want to reset isFirstReady in order to receive `CanPlay` & `LoadedMetadata` accuratly.
self.isFirstReady = true

/*
We can play this asset. Create a new `AVPlayerItem` and make
Expand Down
44 changes: 18 additions & 26 deletions Classes/Player/AVPlayerEngine/AVPlayerEngine+Observation.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ extension AVPlayerEngine {
#keyPath(currentItem),
#keyPath(currentItem.playbackLikelyToKeepUp),
#keyPath(currentItem.playbackBufferEmpty),
#keyPath(currentItem.duration),
#keyPath(currentItem.timedMetadata)
]
}
Expand All @@ -36,7 +35,7 @@ extension AVPlayerEngine {
}

NotificationCenter.default.addObserver(self, selector: #selector(self.playerFailed(notification:)), name: .AVPlayerItemFailedToPlayToEndTime, object: self.currentItem)
NotificationCenter.default.addObserver(self, selector: #selector(self.playerPlayedToEnd(notification:)), name: .AVPlayerItemDidPlayToEndTime, object: self.currentItem)
NotificationCenter.default.addObserver(self, selector: #selector(self.playerPlayedToEnd(notification:)), name: .AVPlayerItemDidPlayToEndTime, object: self.currentItem) // TODO: check if fired same as playerItem.status == failed if yes then remove this notificaiton observation.
NotificationCenter.default.addObserver(self, selector: #selector(self.onAccessLogEntryNotification), name: .AVPlayerItemNewAccessLogEntry, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(self.onErrorLogEntryNotification), name: .AVPlayerItemNewErrorLogEntry, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(self.timebaseChanged), name: Notification.Name(kCMTimebaseNotification_EffectiveRateChanged as String), object: self.currentItem?.timebase)
Expand Down Expand Up @@ -67,11 +66,7 @@ extension AVPlayerEngine {
PKLog.debug("event log:\n event log: averageAudioBitrate - \(lastEvent.averageAudioBitrate)\n event log: averageVideoBitrate - \(lastEvent.averageVideoBitrate)\n event log: indicatedAverageBitrate - \(lastEvent.indicatedAverageBitrate)\n event log: indicatedBitrate - \(lastEvent.indicatedBitrate)\n event log: observedBitrate - \(lastEvent.observedBitrate)\n event log: observedMaxBitrate - \(lastEvent.observedMaxBitrate)\n event log: observedMinBitrate - \(lastEvent.observedMinBitrate)\n event log: switchBitrate - \(lastEvent.switchBitrate)")
}

if lastEvent.indicatedBitrate != self.lastBitrate {
self.lastBitrate = lastEvent.indicatedBitrate
PKLog.trace("currentBitrate:: \(self.lastBitrate)")
self.post(event: PlayerEvent.PlaybackParamsUpdated(currentBitrate: self.lastBitrate))
}
self.post(event: PlayerEvent.PlaybackInfo(playbackInfo: PKPlaybackInfo(logEvent: lastEvent)))
}
}

Expand All @@ -87,7 +82,7 @@ extension AVPlayerEngine {
self.currentState = newState

if let error = notification.userInfo?[AVPlayerItemFailedToPlayToEndTimeErrorKey] as? NSError {
self.post(event: PlayerEvent.Error(error: PlayerError.failedToPlayToEndTime(rootError: error)))
self.post(event: PlayerEvent.Error(error: PlayerError.playerItemFailed(rootError: error)))
} else {
self.post(event: PlayerEvent.Error())
}
Expand Down Expand Up @@ -120,24 +115,13 @@ extension AVPlayerEngine {
PKLog.debug("keyPath:: \(keyPath)")

switch keyPath {
case #keyPath(currentItem.playbackLikelyToKeepUp):
self.handleLikelyToKeepUp()
case #keyPath(currentItem.playbackBufferEmpty):
self.handleBufferEmptyChange()
case #keyPath(currentItem.duration):
if let currentItem = self.currentItem {
self.post(event: PlayerEvent.DurationChanged(duration: CMTimeGetSeconds(currentItem.duration)))
}
case #keyPath(rate):
self.handleRate()
case #keyPath(currentItem.status):
self.handleStatusChange()
case #keyPath(currentItem):
self.handleItemChange()
case #keyPath(currentItem.timedMetadata):
self.handleTimedMedia()
default:
super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context)
case #keyPath(currentItem.playbackLikelyToKeepUp): self.handleLikelyToKeepUp()
case #keyPath(currentItem.playbackBufferEmpty): self.handleBufferEmptyChange()
case #keyPath(rate): self.handleRate()
case #keyPath(currentItem.status): self.handleStatusChange()
case #keyPath(currentItem): self.handleItemChange()
case #keyPath(currentItem.timedMetadata): self.handleTimedMedia()
default: super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context)
}
}

Expand Down Expand Up @@ -198,13 +182,21 @@ extension AVPlayerEngine {

if self.isFirstReady {
self.isFirstReady = false
// when player item is readyToPlay for the first time it is safe to assume we have a valid duration.
if let duration = self.currentItem?.duration, duration != kCMTimeIndefinite {
PKLog.debug("duration in seconds: \(CMTimeGetSeconds(duration))")
self.post(event: PlayerEvent.DurationChanged(duration: CMTimeGetSeconds(duration)))
}
self.post(event: PlayerEvent.LoadedMetadata())
self.post(event: PlayerEvent.CanPlay())
}
} else if currentItem?.status == .failed {
let newState = PlayerState.error
self.postStateChange(newState: newState, oldState: self.currentState)
self.currentState = newState
if let error = currentItem?.error as NSError? {
self.post(event: PlayerEvent.Error(error: PlayerError.playerItemFailed(rootError: error)))
}
}
}

Expand Down
Loading

0 comments on commit 884dc12

Please sign in to comment.