Skip to main content

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 IBOutlets and IBActions 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 IBOutlets and IBActions 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 IBOutlets and IBActions 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 IBOutlets and IBActions 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
}
}