Aug 2, 2017

Introduction to the SHMAVPlayerInterface

Ondřej Macoszek
Ondřej Macoszek
Introduction to the SHMAVPlayerInterface

If you’ve ever worked with AVPlayer you probably encountered a few tricky concepts, namely KVO, CMTime and Media Groups. In this blog post we give some tips and explanations on how best to work with AVPlayer using SHMAVPlayerInterface.

The Challenge of AVPlayer

The typical workflow for AVPlayer requires creating the AVPlayerItem, setting it to AVPlayer and asking the player to start playing with player.play(). Then we usually implement KVO (key-value observing) methods to observe the player’s properties that are interesting to us. Later we might need look into media groups for available subtitles or perhaps seek playback to specific time via CMTime.

Especially when working with KVO, one needs to be careful (for more see useful blog post by Soroush Khanlou). KVO was not built with type safety in mind and unwise usage can lead to crashes. It’s often safer and easier to replace KVO with a different observer pattern. Thus we rarely encounter it in our Showmax app code. Except one place, where Apple requires it - the AVPlayer.

Creating a Friendly Interface

Our SHMAVPlayerInterface library is not a replacement or subclass for AVPlayer. Rather we’ve created a very light and decoupled wrapper around AVPlayer. This way, we’re not obstructing any AVPlayer features. Our helper code can be used seamlessly together with standard AVPlayer features.

The library is split into two parts:

  • SHMAVPlayerInterface class with helper methods offering easier access to information about current state of AVPlayer and AVPlayerItem:
  • Reactive API for AVPlayer and AVPlayerItem replaces the need to implement KVO methods and provides the ability to create Observables for changes in:

Example Code

In the following example we show a simple use case for how to observe playback position in the played asset.

  1. we import SHMAVPlayerInterface so we have available helpers and our reactive API for AVPlayer.
  2. we subscribe to player’s observers to be notified about changes in playback position. After player.play() we will start receiving the notifications.

Note: It is important that you destroy DisposeBag used for observing certain AVPlayer instance before you destroy AVPlayer. In this example we do this with deinit. If this part is missing, a crash will occur.

import AVFoundation
import AVKit
import RxSwift
import SHMAVPlayerInterface

class PlayerManagerExample
    let item: AVPlayerItem
    let player: AVPlayer

    let playerInterface: SHMAVPlayerInterface
    var bag: DisposeBag

    init(url: URL)
        // Create AVPlayer
        item = AVPlayerItem(asset: AVAsset(url: url))
        player = AVPlayer(playerItem: item)

        // Create interface
        playerInterface = SHMAVPlayerInterface(player: player)

        // Setup observers
        // A) for changes in playback position
        player.rx.playbackPosition(updateInterval: 2, updateQueue: nil)
                onNext: { position in


        // B) for status and when status
        player.rx.status(options: [.new])
                onNext: { [weak self] status in

                    guard status == .readyToPlay else { return }


        // Start playing

        bag = DisposeBag() // to cancel reactive subscriptions to AVPlayer

More examples on Github.

Where to get SHMAVPlayerInterface

SHMAVPlayerInterface is available on Cocoapods and Github.

Let us know how it works for you, or if you have any suggestions for improvements.
We welcome your feedback. Contact us at geeks@showmax.com.

Share article via: