Video Playback Sample files
VdoCipher Player Sample Code
This sample PlayerUIViewController.swift
file demonstrates minimum APIs of SDK required to support playback. It references some UI elements which should be clear from the naming. This file can be directly run on a fresh Xcode iOS project after connecting the IBOutlet
s and IBAction
s with appropriate UIButton
, UILabel
and UIView
.
For the playback view it uses SDK provide native UIViewController
which will display theme based iOS player controls, on top of the player.
import AVKit
import UIKit
import VdoFramework
class PlayerUIViewController: UIViewController {
@IBOutlet private weak var playVideoBtn: UIButton!
private var asset: VdoAsset?
private var otp = "20160313versIND313dgKrFOzMsDcQQxb85m3eMUGhATPIqHcGbBkVOmWsaX6jF1"
private var playbackInfo = "eyJ2aWRlb0lkIjoiMGViNTVkNWRjMjI2NGY4MGIxOWMwYzI0YmZmYWJmZTMifQ=="
private var videoId = "0eb55d5dc2264f80b19c0c24bffabfe3"
// MARK: - VC life cycle methods
override func viewDidLoad() {
super.viewDidLoad()
// create a delegate for tracking player state (Optional can be skipped)
// VdoCipher.setPlaybackDelegate(delegate: self)
// create a new asset
// VdoAsset.createAsset(videoId: videoId, playerId: "<custom playerId from your account>")
// Optional - to be used if wanted to set custom player config with the player asset on the UI Player.
VdoAsset.createAsset(videoId: videoId) { asset, error in
if let error = error {
// Remove buffering icon (if present) and show error
print(error)
} else {
self.asset = asset // keep this asset reference for your use
print("asset created")
DispatchQueue.main.async {
// enable the UI for playing. remove buffering icon if showing
self.playVideoBtn.isEnabled = true
}
}
}
}
@IBAction func playVideoTapped(_ sender: UIButton) {
let controller = VdoCipher.getVdoPlayerViewController()
// create a delegate for tracking player UI state (Optional can be skipped)
VdoCipher.setUIPlayerDelegate(self)
self.asset?.playOnline(otp: self.otp, playbackInfo: self.playbackInfo)
// to show full screen Video UI Player
presentFullScreen(uiPlayer: controller)
}
// Full screen player
private func presentFullScreen(uiPlayer controller: UIViewController) {
self.present(controller, animated: true, completion: nil)
}
}
Native iOS AVPlayer (AVPlayerViewController) Sample Code
This sample ViewController.swift
file demonstrates minimum APIs of SDK required to support playback with native iOS playback views in an inline playback VideoView
. It references some UI elements which should be clear from the naming. This file can be directly run on a fresh Xcode iOS project after connecting the IBOutlet
s and IBAction
s with appropriate UIButton
, UILabel
and UIView
.
For the playback view it uses iOS framework provided native AVPlayerViewController
which will display iOS native player controls.
class ViewController: UIViewController {
@IBOutlet private weak var playOnlineButton: UIButton!
@IBOutlet private weak var videoView: UIView!
private let playerViewController = AVPlayerViewController()
private var asset: VdoAsset?
private var otp = "20160313versIND313dgKrFOzMsDcQQxb85m3eMUGhATPIqHcGbBkVOmWsaX6jF1"
private var playbackInfo = "eyJ2aWRlb0lkIjoiMGViNTVkNWRjMjI2NGY4MGIxOWMwYzI0YmZmYWJmZTMifQ=="
private var videoId = "0eb55d5dc2264f80b19c0c24bffabfe3"
// MARK: - VC life cycle methods
override func viewDidLoad() {
super.viewDidLoad()
// Setting the AVPlayer controller in a subview
self.playerViewController.view.frame = self.videoView.bounds
self.playerViewController.view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
self.addChild(self.playerViewController)
self.videoView.addSubview(self.playerViewController.view)
self.playerViewController.didMove(toParent: self)
// create a delegate for tracking player state
VdoCipher.setPlaybackDelegate(delegate: self)
// create a new asset
VdoAsset.createAsset(videoId: videoId) { asset, error in
if let error = error {
// Remove buffering icon (if present) and show error
} else {
self.asset = asset // keep this asset reference for your use
DispatchQueue.main.async {
// enable the UI for playing. remove buffering icon if showing
self.playOnlineButton.isEnabled = true
}
}
}
}
@IBAction func playOnline(_ sender: Any) {
guard let asset = asset else {
return print("not ready for playback")
}
asset.playOnline(otp: otp, playbackInfo: playbackInfo)
}
}
// MARK: - AssetPlaybackDelegate methods
extension ViewController: AssetPlaybackDelegate {
func streamPlaybackManager(playerReadyToPlay player: AVPlayer) {
// player is ready to play
player.play()
}
func streamPlaybackManager(playerCurrentItemDidChange player: AVPlayer) {
// player current item has changed, attach it to AVPlayerViewController
playerViewController.player = player
player.play()
}
func streamLoadError(error: VdoError) {
// Error occured while initiating playback
}
}
Custom Video Player Sample Code
This sample CustomPlayerViewController.swift
file demonstrates minimum APIs of SDK required to support playback with customised player view created as per your app's need for playback in iOS. It references some UI elements which should be clear from the naming. This file can be directly run on a fresh Xcode iOS project after connecting the IBOutlet
s and IBAction
s with appropriate UIButton
and UIView
.
For the playback view it uses iOS framework provided native AVPlayerLayer
embedded in a custom videoView
on which you can create and display your customised player controls.
class CustomPlayerViewController: UIViewController, AssetPlaybackDelegate {
@IBOutlet weak var videoView: UIView!
private let playerLayer: AVPlayerLayer = AVPlayerLayer()
private var asset: VdoAsset?
private var otp = "20160313versIND313dgKrFOzMsDcQQxb85m3eMUGhATPIqHcGbBkVOmWsaX6jF1"
private var playbackInfo = "eyJ2aWRlb0lkIjoiMGViNTVkNWRjMjI2NGY4MGIxOWMwYzI0YmZmYWJmZTMifQ=="
private var videoId = "0eb55d5dc2264f80b19c0c24bffabfe3"
// MARK: - VC life cycle methods
override func viewDidLoad() {
super.viewDidLoad()
playerLayer.videoGravity = .resizeAspect
playerLayer.masksToBounds = true
// create a delegate for tracking player state
VdoCipher.setPlaybackDelegate(delegate: self)
// create a new asset
VdoAsset.createAsset(videoId: videoId) { asset, error in
if let error = error {
// Remove buffering icon (if present) and show error
} else {
self.asset = asset // keep this asset reference for your use
DispatchQueue.main.async {
// enable the UI for playing. remove buffering icon if showing
}
}
}
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
playerLayer.frame = videoView.bounds
videoView.layer.addSublayer(playerLayer)
view.layer.layoutSublayers()
view.layer.setNeedsLayout()
view.layer.layoutIfNeeded()
}
@IBAction func playOnline(_ sender: Any) {
guard let asset = asset else {
return print("not ready for playback")
}
asset.playOnline(otp: otp, playbackInfo: playbackInfo)
}
}
// MARK: - AssetPlaybackDelegate methods
extension ViewController {
func streamPlaybackManager(playerReadyToPlay player: AVPlayer) {
// player is ready to play
player.play()
}
func streamPlaybackManager(playerCurrentItemDidChange player: AVPlayer) {
// player current item has changed
playerLayer.player = player
}
func streamLoadError(error: VdoError) {
// Error occured while initiating playback
}
}
Offline Playback & Download Sample Code
This sample ViewController.swift
file demonstrates minimum APIs of SDK required to support playback and download. It references some UI elements which should be clear from the naming.
This file can be directly run on a fresh Xcode iOS project after connecting the IBOutlet
s and IBAction
s with appropriate UIButton
, UILabel
and UIView
.
For the AVPlayer
container, it uses AVPlayerViewController
which will display iOS native player controls.
It contains an offline capable OTP and playbackInfo for demonstration purpose.
import UIKit
import VdoFramework
import AVFoundation
import AVKit
class ViewController: UIViewController, AssetPlaybackDelegate {
@IBOutlet weak var downloadStateLabel: UILabel!
@IBOutlet weak var downloadActionButton: UIButton!
@IBOutlet weak var playOnlineButton: UIButton!
@IBOutlet weak var playOfflineButton: UIButton!
@IBOutlet weak var container: UIView!
fileprivate var playerViewController = AVPlayerViewController()
private var asset: VdoAsset?
private var otp = "20160313versIND313dgKrFOzMsDcQQxb85m3eMUGhATPIqHcGbBkVOmWsaX6jF1"
private var playbackInfo = "eyJ2aWRlb0lkIjoiMGViNTVkNWRjMjI2NGY4MGIxOWMwYzI0YmZmYWJmZTMifQ=="
private var videoId = "0eb55d5dc2264f80b19c0c24bffabfe3"
override func viewDidLoad() {
super.viewDidLoad()
// Setting the AVPlayer controller in a subview
self.playerViewController.view.frame = self.container.bounds
self.playerViewController.view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
self.addChild(self.playerViewController)
self.container.addSubview(self.playerViewController.view)
self.playerViewController.didMove(toParent: self)
// listen to the download events
NotificationCenter.default.addObserver(self, selector: #selector(handleDownloadProgress(_:)), name: .AssetDownloadProgress, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(handleDownloadStateChange(_:)), name: .AssetDownloadStateChanged, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(handleDownloadFailed(_:)), name: .AssetDownloadFailed, object: nil)
// create a delegate for tracking player state
VdoCipher.setPlaybackDelegate(delegate: self)
// create a new asset
VdoAsset.createAsset(videoId: videoId) { asset, error in
if let error = error
{
// Remove buffering icon and show error
}
else
{
self.asset = asset // keep this asset reference for your use
DispatchQueue.main.async {
// enable the UI for playing. remove buffering icon if showing
self.playOnlineButton.isEnabled = true
}
}
}
}
override func viewWillAppear(_ animated: Bool) {
downloadStateLabel.text = "Generating asset..."
playOfflineButton.isEnabled = false
}
private func updateUI(downloadState: VdoAsset.DownloadState?, percentDownload: Double = -1) {
self.playOfflineButton.isEnabled = false
switch downloadState {
case .notDownloaded:
self.downloadStateLabel.text = "not downloaded"
self.downloadActionButton.setTitle("Download", for: .normal)
break;
case .downloaded:
self.downloadStateLabel.text = "downloaded"
self.downloadActionButton.setTitle("Delete", for: .normal)
self.playOfflineButton.isEnabled = true
break;
case .downloading:
self.downloadStateLabel.text = "downloading \(percentDownload)"
self.downloadActionButton.setTitle("Cancel", for: .normal)
break;
case .paused:
self.downloadStateLabel.text = "paused \(percentDownload)"
self.downloadActionButton.setTitle("Cancel", for: .normal)
break;
default:
self.downloadStateLabel.text = "getting download state..."
}
}
// MARK: Notification handlers
@objc func handleDownloadStateChange(_ notification: Notification) {
print("handle download state change")
let notice = notification.userInfo!
guard videoId == notice[VdoAsset.Keys.videoId] as? String else {
return
}
guard let stateRawValue = notice[VdoAsset.Keys.downloadState] as? String,
let newState = VdoAsset.DownloadState(rawValue: (stateRawValue)) else {
return
}
print("state change: \(newState)")
DispatchQueue.main.async {
self.updateUI(downloadState: newState)
}
}
@objc func handleDownloadProgress(_ notification: Notification) {
print("handle download progress")
let notice = notification.userInfo!
guard videoId == notice[VdoAsset.Keys.videoId] as? String else {
return
}
guard let percent = notice[VdoAsset.Keys.percentDownloaded] as? Double else {
return
}
print("progress percent: \(percent)")
DispatchQueue.main.async {
self.updateUI(downloadState: .downloading, percentDownload: percent)
}
}
@objc func handleDownloadFailed(_ notification: Notification) {
print("handle download failed")
let notice = notification.userInfo!
guard let message = notice[VdoAsset.Keys.message] as? String, let code = notice[VdoAsset.Keys.code] else {return}
print("Download Failed with message:\(message) code:\(code)")
DispatchQueue.main.async {
self.updateUI(downloadState: .notDownloaded)
}
}
@IBAction func playOnline(_ sender: Any) {
guard let asset = asset else {
return print("not ready for playback")
}
asset.playOnline(otp: otp, playbackInfo: playbackInfo)
}
@IBAction func playOffline(_ sender: Any) {
guard let asset = asset else {
return print("not ready for offline playback")
}
if asset.downloadState != .downloaded {
return print("not downloaded yet")
}
asset.playOffline()
}
@IBAction func downloadAction(_ sender: Any) {
guard let asset = asset, let button = sender as? UIButton, let buttonText = button.currentTitle else {
return print("not ready for playback or action not defined")
}
print("title is \(String(describing: button.currentTitle))")
print("download action \(buttonText)")
switch buttonText {
case "Delete":
print("downloaded, now can delete")
asset.deleteDownload()
case "Cancel":
print("downloading..., now can cancel")
asset.cancelDownload()
case "Download":
print("download action triggered")
asset.startDownload(otp: otp, playbackInfo: playbackInfo)
default:
print("can't get here")
}
}
}
extension ViewController {
func streamPlaybackManager(playerReadyToPlay player: AVPlayer) {
// player is ready to play
player.play()
}
func streamPlaybackManager(playerCurrentItemDidChange player: AVPlayer) {
// player current item has changed
playerViewController.player = player
}
func streamLoadError(error: VdoError) {
// Error occured while initiating playback
}
}