In case of a Basic Player, include pod 'KalturaPlayer'
in your Podfile.
In case of an OTT Player, include pod 'KalturaPlayer/OTT'
in your Podfile.
In case of an OVP Player, include pod 'KalturaPlayer/OVP'
in your Podfile.
To use Cocoapods please refer to Cocoapods Guides.
Follow the steps for the required player:
Additional Actions:
Plugins:
Playlist:
In the AppDelegate call setup
on the KalturaBasicPlayer
when the app launches.
For Example:
import KalturaPlayer
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
KalturaBasicPlayer.setup()
return true
}
The setup
will register any of Kaltura's known Plugins if they are added to the project.
import KalturaPlayer
var kalturaBasicPlayer: KalturaBasicPlayer! // Created in the viewDidLoad
override func viewDidLoad() {
super.viewDidLoad()
let playerOptions = PlayerOptions()
kalturaBasicPlayer = KalturaBasicPlayer(options: playerOptions)
}
Check the PlayerOptions
class for more info.
The available options and defaults that can be configured are:
public var preload: Bool = true
public var autoPlay: Bool = true
public var pluginConfig: PluginConfig = PluginConfig(config: [:])
Create a KalturaPlayerView
in the xib or in the code.
@IBOutlet weak var kalturaPlayerView: KalturaPlayerView!
kalturaBasicPlayer.view = kalturaPlayerView
There are two available options:
-
Create a PKMediaEntry and pass it to the
KalturaBasicPlayer
.let contentURL = URL(string: "https://cdnapisec.kaltura.com/p/2215841/sp/221584100/playManifest/entryId/1_vl96wf1o/format/applehttp/protocol/https/a.m3u8") let entryId = "KalturaMedia" let source = PKMediaSource(entryId, contentUrl: contentURL, mediaFormat: .hls) let sources: Array = [source] let mediaEntry = PKMediaEntry(entryId, sources: sources, duration: -1) kalturaBasicPlayer.setMedia(mediaEntry)
-
Use the
setupMediaEntry
function.let contentUrl = URL(string:"https://cdnapisec.kaltura.com/p/2215841/playManifest/entryId/1_w9zx2eti/format/applehttp/protocol/https/a.m3u8") kalturaBasicPlayer.setupMediaEntry(id: "sintel", contentUrl: contentUrl)
Check the function for more available params.
Note: If you want to add a start time for the media, both functions accept a parameter of type MediaOptions
which has a startTime
property which can be set. See MediaOptions
for more information.
- Create a collection of PKMediaEntry:
var mediaEntries: [PKMediaEntry] = []
How to create an individual PKMediaEntry see section 4. Set the Media Entry
-
Populate
mediaEntries
collection with created medias -
Create
PKPlaylist
with this collection and set this playlist to the player
let playlist: PKPlaylist = PKPlaylist(id: nil,
name: "Basic Playlist",
thumbnailUrl: nil,
medias: mediaEntries)
player.setPlaylist(playlist)
// Once all set you can handle playlist here
- Now you have access to player.playlistController. Please check the example of Handeling Playlist Controller
The OTT Player has the Kava Plugin and Phoenix Analytics Plugin embedded, therefore no additional configuration for those plugins are required.
In the AppDelegate call setup
on the KalturaOTTPlayer
when the app launches.
For Example:
import KalturaPlayer
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
KalturaOTTPlayer.setup(partnerId: 3009, serverURL: "https://rest-us.ott.kaltura.com/v4_5/api_v3/", referrer: nil)
return true
}
The setup
will fetch for the configuration needed for the Kava Plugin. As well as register both Kava Plugin and Phoenix Analytics Plugin.
import KalturaPlayer
var kalturaOTTPlayer: KalturaOTTPlayer! // Created in the viewDidLoad
override func viewDidLoad() {
super.viewDidLoad()
let playerOptions = PlayerOptions()
kalturaOTTPlayer = KalturaOTTPlayer(options: playerOptions)
}
Check the PlayerOptions
class for more info.
The available options and defaults that can be configured are:
public var preload: Bool = true
public var autoPlay: Bool = true
public var pluginConfig: PluginConfig = PluginConfig(config: [:])
public var ks: String?
Create a KalturaPlayerView
in the xib or in the code.
@IBOutlet weak var kalturaPlayerView: KalturaPlayerView!
kalturaOTTPlayer.view = kalturaPlayerView
This is the media details that will be passed to the player to load.
let ottMediaOptions = OTTMediaOptions()
Check the OTTMediaOptions
class for more info.
The available options that can be configured are the following:
public var ks: String?
public var assetId: String?
public var assetType: AssetType = .unset
public var assetReferenceType: AssetReferenceType = .unset
public var formats: [String]?
public var fileIds: [String]?
public var playbackContextType: PlaybackContextType = .unset
public var networkProtocol: String?
public var urlType: String?
public var streamerType: String?
public var adapterData: [String: String]?
// MediaOptions
public var startTime: TimeInterval = .nan
Pass the created media options to the loadMedia
function and implement the callback function in order to observe if an error has occurred.
For example:
kalturaOTTPlayer.loadMedia(options: mediaOptions) { [weak self] (error) in
guard let self = self else { return }
if let error = error {
let message = error.localizedDescription
let alert = UIAlertController(title: "Media not loaded", message: message, preferredStyle: UIAlertController.Style.alert)
alert.addAction(UIAlertAction(title: "Ok", style: .cancel, handler: { (alert) in
self.dismiss(animated: true, completion: nil)
}))
self.present(alert, animated: true, completion: nil)
} else {
// If the autoPlay and preload was set to false, prepare will not be called automatically
if videoData.player.autoPlay == false && videoData.player.preload == false {
self.kalturaOTTPlayer.prepare()
}
}
}
- Prepare a collection of
OTTMediaOptions
var mediaOptions: [OTTMediaOptions] = []
mediaOptions.append(OTTMediaOptions().set(assetId: "111111").set(assetReferenceType: .media).set(networkProtocol: "http"))
mediaOptions.append(OTTMediaOptions().set(assetId: "222222").set(assetReferenceType: .media).set(networkProtocol: "http"))
mediaOptions.append(OTTMediaOptions().set(assetId: "333333").set(assetReferenceType: .media).set(networkProtocol: "http"))
- Pass this collection to the player loadPlaylist method:
player.loadPlaylist(options: mediaOptions, callback: { [weak self] error in
guard let self = self else { return }
if let error = error {
print("Loading playlist error: " + error.localizedDescription)
}
// Handle loaded playlist here
})
- Now you have access to player.playlistController. Please check the example of Handeling Playlist Controller
The OVP Player has the Kava Plugin embedded, therefore no additional configuration for the plugin is required.
In the AppDelegate call setup
on the KalturaOVPPlayer
when the app launches.
For Example:
import KalturaPlayer
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
KalturaOVPPlayer.setup(partnerId: 2222401)
return true
}
The setup
will fetch for the configuration needed for the Kava Plugin. As well as register the Kava Plugin.
import KalturaPlayer
var kalturaOVPPlayer: KalturaOVPPlayer! // Created in the viewDidLoad
override func viewDidLoad() {
super.viewDidLoad()
let playerOptions = PlayerOptions()
kalturaOVPPlayer = KalturaOVPPlayer(options: playerOptions)
}
Check the PlayerOptions
class for more info.
The available options and defaults that can be configured are:
public var preload: Bool = true
public var autoPlay: Bool = true
public var pluginConfig: PluginConfig = PluginConfig(config: [:])
public var ks: String?
Create a KalturaPlayerView
in the xib or in the code.
@IBOutlet weak var kalturaPlayerView: KalturaPlayerView!
kalturaOVPPlayer.view = kalturaPlayerView
This is the media details that will be passed to the player to load.
let ovpMediaOptions = OVPMediaOptions()
Check the OVPMediaOptions
class for more info.
The available options that can be configured are the following:
public var ks: String?
public var entryId: String?
public var referenceId: String?
public var uiconfId: NSNumber?
// MediaOptions
public var startTime: TimeInterval = .nan
Pass the created media options to the loadMedia
function and implement the callback function in order to observe if an error has occurred.
For example:
kalturaOVPPlayer.loadMedia(options: mediaOptions) { [weak self] (error) in
guard let self = self else { return }
if let error = error {
let message = error.localizedDescription
let alert = UIAlertController(title: "Media not loaded", message: message, preferredStyle: UIAlertController.Style.alert)
alert.addAction(UIAlertAction(title: "Ok", style: .cancel, handler: { (alert) in
self.dismiss(animated: true, completion: nil)
}))
self.present(alert, animated: true, completion: nil)
} else {
// If the autoPlay and preload was set to false, prepare will not be called automatically
if videoData.player.autoPlay == false && videoData.player.preload == false {
self.kalturaOVPPlayer.prepare()
}
}
}
- Prepare a collection of
OVPMediaOptions
var mediaOptions: [OVPMediaOptions] = []
mediaOptions.append(OVPMediaOptions().set(entryId: "0_aaaa1111"))
mediaOptions.append(OVPMediaOptions().set(entryId: "0_aaaa2222"))
mediaOptions.append(OVPMediaOptions().set(entryId: "0_aaaa3333"))
mediaOptions.append(OVPMediaOptions().set(entryId: "0_aaaa4444"))
mediaOptions.append(OVPMediaOptions().set(entryId: "0_aaaa5555"))
mediaOptions.append(OVPMediaOptions().set(entryId: "0_aaaa6666"))
- Pass this collection to the player loadPlaylist method:
player.loadPlaylist(options: mediaOptions, callback: { [weak self] error in
guard let self = self else { return }
if let error = error {
print("Loading playlist error: " + error.localizedDescription)
}
// Handle loaded playlist here
})
- Now you have access to player.playlistController. Please check the example of Handeling Playlist Controller
- Prepare
OVPPlaylistOptions
and set playlist id:
let playlistOptions = OVPPlaylistOptions()
playlistOptions.playlistId = "0_abcd12345"
- Call loadPlaylistById method in player and pass options:
player.loadPlaylistById(options: playlistOptions) { [weak self] (error) in
guard let self = self else { return }
if let error = error {
print("Loading playlist error: " + error.localizedDescription)
}
// Handle loaded playlist here
}
- Now you have access to player.playlistController. Please check the example of Handeling Playlist Controller
NOTE: In order to receive the events from the beginning, register to them before calling setMedia
in the BasicPlayer or calling loadMedia
in the OTTPlayer or OVPPlayer. In case the player option is set to not auto prepare, registering can be done before calling prepare on the player.
An example for the playback events in order to updated the UI on the button:
kalturaPlayer.addObserver(self, events: [KPPlayerEvent.ended, KPPlayerEvent.play, KPPlayerEvent.playing, KPPlayerEvent.pause]) { [weak self] event in
guard let self = self else { return }
NSLog(event.description)
DispatchQueue.main.async {
switch event {
case is KPPlayerEvent.Ended:
self.playPauseButton.displayState = .replay
case is KPPlayerEvent.Play:
self.playPauseButton.displayState = .pause
case is KPPlayerEvent.Playing:
self.playPauseButton.displayState = .pause
case is KPPlayerEvent.Pause:
self.playPauseButton.displayState = .play
default:
break
}
}
}
An example to update the progress:
kalturaPlayer.addObserver(self, events: [KPPlayerEvent.playheadUpdate]) { [weak self] event in
guard let self = self else { return }
guard let currentTimeNumber = event.currentTime else { return }
DispatchQueue.main.async {
self.mediaProgressSlider.value = Float(currentTimeNumber.doubleValue / self.kalturaPlayer.duration)
}
}
NOTE: Don't forget to perform UI changes on the main thread.
And don't forget to unregister when the view is not displayed.
All available Player events:
- canPlay
- durationChanged
- stopped
- ended
- loadedMetadata
- play
- pause
- playing
- seeking
- seeked
- replay
- tracksAvailable
- textTrackChanged
- audioTrackChanged
- videoTrackChanged
- playbackInfo
- stateChanged
- timedMetadata
- sourceSelected
- loadedTimeRanges
- playheadUpdate
- error
- errorLog
- playbackStalled
This will be done automatically if the player options, autoPlay
or preload
is set to true. Which those are the default values.
In case the autoPlay
and preload
are set to false, prepare
on the player needs to be called manually.
kalturaPlayer.prepare()
This will be done automatically if the player options, autoPlay
is set to true. Which is the default value.
In case the autoPlay
is set to false, play
on the player needs to be called manually.
kalturaPlayer.play()
Play on the player can be called straight after prepare, once it's ready and can play, the playback will start automatically.
Registering to the player event CanPlay
will enable you to know exactly when the play can be performed in case you need it controlled.
When a change media is needed call stop
on the player and call updatePlayerOptions
on the relevant KalturaPlayer with the new/updated PlayerOptions
.
kalturaPlayer.stop()
kalturaPlayer.updatePlayerOptions(playerOptions)
After that follow the steps:
- For the KalturaBasicPlayer from section Set the Media Entry
- For the KalturaOTTPlayer from section Create the OTTMediaOptions
- For the KalturaOVPPlayer from section Create the OVPMediaOptions
Adds the option to download and play local media. The OfflineManager
shared instance is used in order to perform all actions.
Inside your Podfile, for the specific target, add the following:
-
For the KalturaBasicPlayer:
pod 'KalturaPlayer/Offline'
This can replace the
pod 'KalturaPlayer'
-
For the KalturaOTTPlayer:
pod 'KalturaPlayer/Offline_OTT'
This can replace the
pod 'KalturaPlayer/OTT'
-
For the KalturaOVPPlayer:
pod 'KalturaPlayer/Offline_OVP'
This can replace the
pod 'KalturaPlayer/OVP'
Then perform pod update
in the terminal.
See Cocoapods Guide for the difference between pod install and pod update.
Add the KalturaPlayer
to the relevant file if it doesn't already exist.
import KalturaPlayer
NOTE: The setup function on the KalturaPlayer which is called in the AppDelegate, will perform the needed initialization, and will start any media that was downloading before the application was closed.
In the desired class that will take care of the download updates, set it as the OfflineManager's delegate.
Add the following:
OfflineManager.shared.offlineManagerDelegate = self
Note: Don't forget to remove itself.
OfflineManager.shared.offlineManagerDelegate = nil
Set the class to implement it's functions:
extension MediasTableViewController: OfflineManagerDelegate {
func item(id: String, didDownloadData totalBytesDownloaded: Int64, totalBytesEstimated: Int64, completedFraction: Float) {
if let index = self.videos.firstIndex(where: { $0.media.id == id }) {
DispatchQueue.main.async {
guard let cell = self.tableView.cellForRow(at: IndexPath(row: index, section: 0)) as? DownloadMediaTableViewCell else { return }
cell.updateProgress(completedFraction)
}
}
}
func item(id: String, didChangeToState newState: AssetDownloadState, error: Error?) {
if let index = self.videos.firstIndex(where: { $0.media.id == id }) {
if newState == .completed {
// Download is completed, do something.
}
DispatchQueue.main.async {
guard let cell = self.tableView.cellForRow(at: IndexPath(row: index, section: 0)) as? DownloadMediaTableViewCell else { return }
cell.updateDownloadState(newState)
}
}
}
}
In order to update the view once shown with the relevant data regarding the download process, call the getAssetInfo
function. The AssetInfo
will include the required data in order to update the UI.
let assetInfo = OfflineManager.shared.getAssetInfo(assetId: assetId)
The AssetInfo
object includes the following:
public var itemId: String // The asset's id.
public var state: AssetDownloadState // The asset's state. See `AssetDownloadState` for more info.
public var estimatedSize: Int64 // The asset's estimated size.
public var downloadedSize: Int64 // The asset's downloaded size.
public var progress: Float // The asset's progress. A value between 0 and 1.
The AssetDownloadState
represents the asset's download state.
Available Values:
- new
- prepared
- started
- paused
- completed
- failed
- outOfSpace
In order to start downloading a media, a call to prepareAsset
is required.
-
Create an
OfflineSelectionOptions
.For example:
let offlineSelectionOptions = OfflineSelectionOptions() .setMinVideoHeight(300) .setMinVideoBitrate(.avc1, 3_000_000) .setMinVideoBitrate(.hevc, 5_000_000) .setPreferredVideoCodecs([.hevc, .avc1]) .setPreferredAudioCodecs([.ac3, .mp4a]) .setAllTextLanguages() .setAllAudioLanguages()
For a PKMediaEntry download the prepareAsset
function requires two parameters: PKMediaEntry
and OfflineSelectionOptions
.
-
Create a PKMediaEntry
let contentURL = URL(string: "https://cdnapisec.kaltura.com/p/2215841/sp/221584100/playManifest/entryId/1_vl96wf1o/format/applehttp/protocol/https/a.m3u8") let entryId = "KalturaMedia" let source = PKMediaSource(entryId, contentUrl: contentURL, mediaFormat: .hls) let sources: Array = [source] let pkMediaEntry = PKMediaEntry(entryId, sources: sources, duration: -1)
-
Call the
prepareAsset
functionOfflineManager.shared.prepareAsset(mediaEntry: pkMediaEntry, options: offlineSelectionOptions) { (error, assetInfo) in // In case an assetInfo was returned and there is no error, // a call to start the download can be performed. }
For an OTT Media download there is an additional function for the prepareAsset
that requires the following two parameters: OTTMediaOptions
and OfflineSelectionOptions
.
-
Create the
OTTMediaOptions
, follow the Create the OTTMediaOptions section. -
Call the
prepareAsset
functionOfflineManager.shared.prepareAsset(mediaOptions: ottMediaOptions, options: offlineSelectionOptions) { (error, assetInfo, pkMediaEntry) in // In case an assetInfo was returned and there is no error, // a call to start the download can be performed. }
For an OVP Media download there is an additional function for the prepareAsset
that requires the following two parameters: OVPMediaOptions
and OfflineSelectionOptions
.
-
Create the
OVPMediaOptions
, follow the Create the OVPMediaOptions section. -
Call the
prepareAsset
functionOfflineManager.shared.prepareAsset(mediaOptions: ovpMediaOptions, options: offlineSelectionOptions) { (error, assetInfo, pkMediaEntry) in // In case an assetInfo was returned and there is no error, // a call to start the download can be performed. }
In order to start downloading the asset call startAssetDownload
:
try? OfflineManager.shared.startAssetDownload(assetId: id)
An error can be thrown, see the documentation for more information.
In order to pause downloading the asset call pauseAssetDownload
:
try? OfflineManager.shared.pauseAssetDownload(assetId: id)
An error can be thrown, see the documentation for more information.
In order to remove the downloaded asset with all it’s data, call removeAssetDownload
:
try? OfflineManager.shared.removeAssetDownload(assetId: id)
An error can be thrown, see the documentation for more information.
In order to retrieve the local media, call getLocalPlaybackEntry
, if the PKMediaEntry
was retrieved call setMedia
on the relevant KalturaPlayer.
if let localMediaEntry = OfflineManager.shared.getLocalPlaybackEntry(assetId: mediaEntry.id) {
kalturaPlayer.setMedia(localMediaEntry, options: mediaOptions)
}
The player can now be used as usual.
For DRM content, additional actions are need.
- Get the DRM Status. See the
DRMStatus
for more information. - Renew the asset DRM license.
In order to get the DRM status of the asset, call getDRMStatus
:
let drmStatus = OfflineManager.shared.getDRMStatus(assetId: id)
A call to isValid
, on the drmStatus, can determine if the license is still valid and the media can be played, otherwise a call to renewAssetDRMLicense
is needed.
if drmStatus.isValid() == false {
// Renewal is needed.
}
In order to renew the license, a call to renewAssetDRMLicense
is needed.
OfflineManager.shared.renewAssetDRMLicense(mediaEntry: pkMediaEntry) { (error) in
// Decide what to do with the error depending on the error.
}
For OTT there is an additional function that requires the OTTMediaOptions
.
OfflineManager.shared.renewAssetDRMLicense(mediaOptions: ottMediaOptions) { (error) in
// Decide what to do with the error depending on the error.
}
For OVP there is an additional function that requires the OVPMediaOptions
.
OfflineManager.shared.renewAssetDRMLicense(mediaOptions: ovpMediaOptions) { (error) in
// Decide what to do with the error depending on the error.
}
Add Google's IMA (Interactive Media Ads) or IMA DAI (Dynamic Ad Insertion)
Inside your Podfile, for the specific target, add the following:
pod 'PlayKit_IMA'
Then perform pod update
or pod update PlayKit_IMA
in the terminal.
See Cocoapods Guide for the difference between pod install and pod update.
Add the PlayKit_IMA
to the relevant file.
import PlayKit_IMA
-
For IMA:
Create the IMAConfig and set theadTagUrl
or theadsResponse
.
Refer to theIMAConfig
class for all available settings.let imaConfig = IMAConfig() imaConfig.adTagUrl = "https://pubads.g.doubleclick.net/gampad/ads?sz=640x480&iu=/124319096/external/single_ad_samples&ciu_szs=300x250&impl=s&gdfp_req=1&env=vp&output=vast&unviewed_position_start=1&cust_params=deployment%3Ddevsite%26sample_ct%3Dlinear&correlator="
-
For IMA DAI:
Set the required configuration.
Refer to theIMADAIConfig
class for all available settings.
The IMA DAI stream samples can be found in their docs.Sample for a VOD media:
let imaDAIConfig = IMADAIConfig() imaDAIConfig.assetTitle = "Tears of Steel" imaDAIConfig.assetKey = nil imaDAIConfig.contentSourceId = "2528370" imaDAIConfig.videoId = "tears-of-steel" imaDAIConfig.streamType = .vod
Sample for a Live media:
let imaDAIConfig = IMADAIConfig() imaDAIConfig.assetTitle = "Big Buck Bunny" imaDAIConfig.assetKey = "sN_IYUG8STe1ZzhIIE_ksA" imaDAIConfig.contentSourceId = nil imaDAIConfig.videoId = nil imaDAIConfig.streamType = .live
Pass the created config to the PluginConfig
-
For IMA:
let pluginConfig = PluginConfig(config: [IMAPlugin.pluginName : imaConfig])
-
For IMA DAI:
let pluginConfig = PluginConfig(config: [IMADAIPlugin.pluginName : imaDAIConfig])
Set the player options with the plugin config created.
playerOptions.pluginConfig = pluginConfig
Two options to consider:
- The playerOptions is sent upon creating the Kaltura Player, see section Create a KalturaBasicPlayer or Create a KalturaOTTPlayer or Create a KalturaOVPPlayer for the relevant player.
- The playerOptions can be updated upon a change media flow, see section Change Media
In order to receive the events from the beginning, register to them before prepare is performed on the player.
private func registerAdEvents() {
kalturaPlayer.addObserver(self, events: [KPAdEvent.adLoaded, KPAdEvent.adPaused, KPAdEvent.adResumed, KPAdEvent.adStarted, KPAdEvent.adComplete, KPAdEvent.allAdsCompleted]) { [weak self] adEvent in
guard let self = self else { return }
DispatchQueue.main.async {
switch adEvent {
case is KPAdEvent.AdLoaded:
self.adsLoaded = true
case is KPAdEvent.AdPaused:
self.playPauseButton.displayState = .play
case is KPAdEvent.AdResumed:
self.activityIndicator.stopAnimating()
self.playPauseButton.displayState = .pause
case is KPAdEvent.AdStarted:
self.activityIndicator.stopAnimating()
self.playPauseButton.displayState = .pause
self.mediaProgressSlider.isEnabled = false
case is KPAdEvent.AdComplete:
self.mediaProgressSlider.isEnabled = true
case is KPAdEvent.AllAdsCompleted:
self.allAdsCompleted = true
// In case of a post-roll the media has ended
if self.mediaEnded {
self.playPauseButton.displayState = .replay
self.showPlayerControllers(true)
}
default:
break
}
}
}
}
NOTE: Don't forget to perform UI changes on the main thread.
And don't forget to unregister when the view is not displayed.
All available Ad events:
- streamLoaded // DAI
- streamStarted // DAI
- adBreakReady
- adBreakStarted // DAI
- adBreakEnded // DAI
- adPeriodStarted // DAI
- adPeriodEnded // DAI
- allAdsCompleted
- adComplete
- adClicked
- adFirstQuartile
- adLoaded
- adLog
- adMidpoint
- adPaused
- adResumed
- adSkipped
- adStarted
- adTapped
- adThirdQuartile
- adDidProgressToTime
- adDidRequestContentPause /// Ad requested the content to pause (before ad starts playing)
- adDidRequestContentResume /// Ad requested content resume (when finished playing ads or when error occurs and playback needs to continue)
- webOpenerEvent
- adWebOpenerWillOpenExternalBrowser
- adWebOpenerWillOpenInAppBrowser
- adWebOpenerDidOpenInAppBrowser
- adWebOpenerWillCloseInAppBrowser
- adWebOpenerDidCloseInAppBrowser
- adCuePointsUpdate
- adStartedBuffering /// Sent when an ad started buffering
- adPlaybackReady /// Sent when ad finished buffering and ready for playback
- requestTimedOut /// Sent when the ads request timed out.
- adsRequested /// delivered when ads request was sent.
- error /// Sent when an error occurs.
Inside your Podfile, for the specific target, add the following:
pod 'PlayKitYoubora'
Then perform pod update
or pod update PlayKitYoubora
in the terminal.
See Cocoapods Guide for the difference between pod install and pod update.
Add the PlayKitYoubora
to the relevant file.
import PlayKitYoubora
The account code is mandatory, make sure to put the correct one.
See all available params in the YouboraConfig
struct.
let youboraPluginParams: [String: Any] = [
"accountCode": "kalturatest"
]
let analyticsConfig = AnalyticsConfig(params: youboraPluginParams)
Pass the created config to the PluginConfig
let pluginConfig = PluginConfig(config: [YouboraPlugin.pluginName: analyticsConfig])
Set the player options with the plugin config created.
playerOptions.pluginConfig = pluginConfig
Two options to consider:
- The playerOptions is sent upon creating the Kaltura Player, see section Create a KalturaBasicPlayer or Create a KalturaOTTPlayer or Create a KalturaOVPPlayer for the relevant player.
- The playerOptions can be updated upon a change media flow, see section Change Media
NOTE: Currently supporting only OTT and OVP providers.
Inside your Podfile, for the specific target, add the following:
pod 'PlayKitGoogleCast'
Then perform pod update
or pod update PlayKitGoogleCast
in the terminal.
See Cocoapods Guide for the difference between pod install and pod update.
Add the PlayKitGoogleCast
and the GoogleCast
to the relevant file.
import PlayKitGoogleCast
import GoogleCast
In the AppDelegate, need to set up the Application Id.
Recommended to create a manager in order to control all needed actions and setups, see OTTSample and OVPSample.
Setup for example:
// Set your receiver application ID.
let options = GCKCastOptions(discoveryCriteria: GCKDiscoveryCriteria(applicationID: applicationId))
options.physicalVolumeButtonsWillControlDeviceVolume = true
// Following code enables CastConnect
let launchOptions = GCKLaunchOptions()
launchOptions.androidReceiverCompatible = true
options.launchOptions = launchOptions
GCKCastContext.setSharedInstanceWith(options)
GCKCastContext.sharedInstance().useDefaultExpandedMediaControls = true
// Theme the cast button using UIAppearance.
GCKUICastButton.appearance().tintColor = UIColor.gray
setupCastLogging()
GCKCastContext.sharedInstance().sessionManager.add(self)
GCKCastContext.sharedInstance().imagePicker = self
See Google Chrome Cast code-lab for more information.
<key>NSBluetoothAlwaysUsageDescription</key>
<string>${PRODUCT_NAME} uses the bluetooth to discover Cast-enabled devices via the bluetooth.</string>
<key>NSBonjourServices</key>
<array>
<string>_googlecast._tcp</string>
<string>_(applicationID)._googlecast._tcp</string>
</array>
<key>NSLocalNetworkUsageDescription</key>
<string>${PRODUCT_NAME} uses the local network to discover Cast-enabled devices on your WiFi
network.</string>
Add the cast button in the code or the xib.
For example:
castButton = GCKUICastButton(frame: CGRect(x: CGFloat(0),
y: CGFloat(0),
width: CGFloat(24),
height: CGFloat(24)))
castButton.tintColor = UIColor.white
navigationItem.rightBarButtonItem = UIBarButtonItem(customView: castButton)
In order to cast a media the GCKMediaInformation
needs to be created and passed to the remoteMediaClient to be loaded. PlayKitGoogleCast
provides a CAFCastBuilder
which can be set with properties from the nedia and the GCKMediaInformation
will be generated.
Get the media information object and load it:
gckMediaInformation = try getCAFMediaInformation(from: videoData)
if let mediaInformation = gckMediaInformation {
self.load(mediaInformation: mediaInformation, appending: false)
}
Create the media information via the video data:
private func getCAFMediaInformation(from videoData: VideoData) throws -> GCKMediaInformation {
let castBuilder = CAFCastBuilder()
castBuilder.set(contentId: videoData.media.assetId)
castBuilder.set( ...
...
let mediaInformation = try castBuilder.build()
return mediaInformation
}
Load the media:
private func load(mediaInformation:GCKMediaInformation, appending: Bool) -> Void {
guard let remoteMediaClient = GCKCastContext.sharedInstance().sessionManager.currentCastSession?.remoteMediaClient else { return }
let mediaQueueItemBuilder = GCKMediaQueueItemBuilder()
mediaQueueItemBuilder.mediaInformation = mediaInformation
mediaQueueItemBuilder.autoplay = true
mediaQueueItemBuilder.preloadTime = 0
let mediaQueueItem = mediaQueueItemBuilder.build()
if appending {
let request = remoteMediaClient.queueInsert(mediaQueueItem, beforeItemWithID: kGCKMediaQueueInvalidItemID)
request.delegate = self
} else {
let queueDataBuilder = GCKMediaQueueDataBuilder(queueType: .generic)
queueDataBuilder.items = [mediaQueueItem]
queueDataBuilder.repeatMode = remoteMediaClient.mediaStatus?.queueRepeatMode ?? .off
let mediaLoadRequestDataBuilder = GCKMediaLoadRequestDataBuilder()
mediaLoadRequestDataBuilder.mediaInformation = mediaInformation
mediaLoadRequestDataBuilder.queueData = queueDataBuilder.build()
let request = remoteMediaClient.loadMedia(with: mediaLoadRequestDataBuilder.build())
request.delegate = self
}
}
It is similar to Register for Player Events.
NOTE: Don't forget to perform UI changes on the main thread.
And don't forget to unregister when the view is not displayed.
All available Playlists Controller events:
- playlistLoaded
- playlistStarted
- playlistEnded
- playlistCountDownStart
- playlistCountDownEnd
- playlistLoopStateChanged
- playlistAutoContinueStateChanged
- playlistError
- playlistLoadMediaError
- playlistCurrentPlayingItemChanged
if let playlistController = self.player?.playlistController {
// Configure PlaylistController
// Set the playlist controller delegate if you need to manage plugins for each item
// or countdown options for each item.
playlistController.delegate = self
// Also you may set some playlist controller options.
playlistController.preloadTime = 120
playlistController.loop = true
// This is good place to handle UI updates that reuire playlist data.
// Reload your UITableView/UIColloctionView here.
// If needed start playlist playback.
// playNext() will start it from the first item.
self.player?.playlistController?.playNext()
}
Once playlist is loaded in the playlist controller you will have public access to var playlist: PKPlaylist
So basically you have to read playlistController.playlist.medias
collection.
if let playlist = player?.playlistController?.playlist,
let item = playlist.medias?[0] {
print(item.name)
print(item.duration)
}
To provide individual media items dedicated plugin configs or countdown options you have to set PlaylistControllerDelegate.
-
Plugin config implementation is similar to Create the PluginConfig and Pass the PluginConfig to the PlayerOptions.
With the one exeption you can provide own config for the requested media at index (check the example code). -
Every playlist media may have specific
CountdownOptions
it will help you build countdown UI in you App if needed.
With Playlists Controller eventsplaylistCountDownStart
andplaylistCountDownEnd
you can listen for coundown updates.
extension PlaylistViewController: PlaylistControllerDelegate {
func playlistController(_ controller: PlaylistController, updatePluginConfigForMediaItemAtIndex mediaItemIndex: Int) -> Bool {
return true
}
func playlistController(_ controller: PlaylistController, pluginConfigForMediaItemAtIndex mediaItemIndex: Int) -> PluginConfig? {
let youboraPluginParams: [String: Any] = [
"accountCode": "kalturatest",
"contentCustomDimensions": [
"contentCustomDimension1": "Playlist ID: \(controller.playlist.id ?? "empty")",
"contentCustomDimension2": "Playlist Item #: \(mediaItemIndex)",
"contentCustomDimension3": "MediaEntry ID: \(controller.playlist.medias?[mediaItemIndex].id ?? "empty")",
]
]
let analyticsConfig = AnalyticsConfig(params: youboraPluginParams)
let imaConfig = IMAConfig()
imaConfig.alwaysStartWithPreroll = true
imaConfig.adTagUrl = "AD_TAG"
return PluginConfig(config: [IMAPlugin.pluginName: imaConfig,
YouboraPlugin.pluginName: analyticsConfig])
}
func playlistController(_ controller: PlaylistController, enableCountdownForMediaItemAtIndex mediaItemIndex: Int) -> Bool {
return true
}
func playlistController(_ controller: PlaylistController, countdownOptionsForMediaItemAtIndex mediaItemIndex: Int) -> CountdownOptions? {
let countdown = CountdownOptions()
countdown.timeToShow = 240
countdown.duration = 20
return countdown
}
}