Overview
The following points will explain all breaking changes, renamed methods and configuration objects, as well as minimum requirements that need to be fullfilled to migrate and benefit from all the major performance and usability improvements that become available with v3.
V3 of the iOS/tvOS Player SDK marks a new direction where the player itself and the sources it plays back become more decoupled. This allows for sources to have their own lifecycle, emit their own events and offer functionality even when the source is currently not being played back. For more details on how the top-level components fit together in V3, refer to the Player, Source and PlaylistApi documentation.
With this new direction comes the ability to load multiple sources into the player via a PlaylistConfig
. The player will play back one source after another until it reaches the end of the playlist. Sources in the playlist can already preload content before they are being played back, leading to gapless playback across sources without the overhead of unloading and loading a new source like in V2.
Minimum Requirements
Package manager:
v3 SDK will be delivered as pre-compiled XCFramework through
- Swift Package Manager (Swift 5.3+) or
- Cocoapods 1.9+ or
- Carthage 0.37.0+
Supported iOS/tvOS Platforms (Deployment Target):
iOS 14
or highertvOS 14
or higher
Google Cast:
- CAF compatible v3 receiver applications required
Bitmovin Player UI:
- v3.25.x or higher (default and custom versions)
Limitations
-
The initial
3.0.0
version does not support loading live-streams inside a playlist.
As we can't detect the type until we actually start loading the source there won't be an error when loading a live-stream. Doing so will result in unexpected behavior. -
The event transition towards
SourceEvent
s isn't finished yet.
More events will be migrated toSourceEvent
s and emitted on a per-source basis over the next releases. If you plan on directly using the typesPlayerEvent
andSourceEvent
anywhere, be aware that there could be API breaking change in the future when changing the super-type of event classes. Learn More
Renamings
This table lists all naming changes from v2
to v3
with its replacements.
v2 | v3 |
---|---|
*Configuration | *Config |
SourceItem | SourceConfig |
SourceItem.itemTitle | SourceConfig.title |
SourceItem.itemDescription | SourceConfig.sourceDescription |
BMPBitmovinPlayerView | PlayerView |
MediaSourceType | SourceType |
MediaSourceType.HLS | SourceType.hls |
MediaSourceType.DASH | SourceType.dash |
Player.sourceMetadata | Was moved to Source.metadata |
RemoteControlAPI | RemoteControlApi |
UserInterfaceAPI | UserInterfaceApi |
Boolean properties could be accessed without a proper prefix (e.g. .isPlaying was accessible via .playing from ObjC ) | All Boolean properties now have a proper prefix |
BMP prefix when using type/enum from Swift | No more BMP prefixes for types/enums used from Swift |
Removals
This table lists API which was removed in v3 with its replacements (if any).
v2 | v3 |
---|---|
CastConfiguration | RemoteControlConfig |
Player.preload | removed without replacement as this was never implemented properly |
Player.streamType | is now represented through SourceConfig.type |
OfflineContentManager.download(minimumBitrate:) | The minimumBitrate can now be set only via the DownloadConfig |
Player.setup | removed without replacement (Details) |
ConfigurationUpdatedEvent | removed as a configuration can't be updated anymore |
PlayerConfiguration.sourceConfiguration | replaced with new loading workflows (Details) |
Jsonable | removed without replacement as we no longer support loading a web-based PlayerConfig |
Player setup
We no longer expose the concrete implementation for the Player
. Therefore You can no longer create a direct instance from the Player
. From now on the only way to create a player instance is using the PlayerFactory
:
v2
let player = Player(configuration: configuration)
// or
let player = Player() // when no PlayerConfig is needed
v3
let player = PlayerFactory.createPlayer(playerConfig: playerConfig)
// or
let player = PlayerFactory.createPlayer() // when no PlayerConfig is needed
Loading a Source
SourceConfig
The SourceItem
was replaced by SourceConfig
and the old SourceConfiguration
was removed completely. SourceConfig
from now on refers to the old SourceItem
.
As our SourceConfig
was based on the SourceConfig
from the web-player there was the possibility to set up multiple configurations for each streaming technology (HLS, Dash ...). We want to detach from this concept starting with v3. Therefore we deprecated all the legacy types which were used to set up those different sources:
MediaSource
AdaptiveSource
HLSSource
DashSource
ProgressiveSource
The new designated way to create a SourceConfig
is to use the URL
and the type
directly on the SourceConfig
initializer:
v2
let sourceConfig = SourceConfig(hlsSource: HLSSource(url: streamUrl))
v3
let sourceConfig = SourceConfig(url: streamUrl, type: .HLS)
Source
The Source
is, next to the Player
, the new main component in the SDK. See the documentation for more detailed insights.
To create an instance of a Source
a SourceConfig
is needed. The SourceConfig
can then be passed to the SourceFactory
to create a Source
instance.
let source = SourceFactory.createSource(from: sourceConfig)
To load a Source
into the Player
we created a new load method that accepts a Source
:
player.load(source: source)
If you don't need to handle Sources explicitly you can still load a SourceConfig
directly:
// v3
player.load(sourceConfig: sourceConfig)
Event handling
Each Source
can have its own listeners by now. To enable that we split the existing PlayerEvent
s into PlayerEvent
and SourceEvent
.
v2
class PlayerEvent: NSObject { ... }
class SourceLoadedEvent: PlayerEvent { ... }
v3
protocol Event: NSObject { ... }
protocol SourceEvent: Event { ... }
class SourceLoadedEvent: SourceEvent { ... }
We introduce the new Event
protocol as the root type for all events. Each SourceEvent
(e.g. SourceLoadedEvent
) implements the SourceEvent
protocol and each PlayerEvent
(e.g. PlayEvent
) extends the PlayerEvent
super class.
Events which are already SourceEvent
s:
DurationChangedEvent
SourceLoadEvent
SourceLoadedEvent
SourceUnloadEvent
SourceUnloadedEvent
SourceWarningEvent
SourceErrorEvent
Every SourceEvent
emitted from the currently active Source
will be also emitted through the Player
.
This means that SourceEvent
s will be received for the according Source
instance or directly via the Player
for the currently active Source
.
extension PlaybackViewController: PlayerListener {
// Receive the DurationChangedEvent through the player only for the active source
func onDurationChanged(_ event: DurationChangedEvent, player: Player) {
// ...
}
}
extension PlaybackViewController: SourceListener {
// Receive the DurationChangedEvent on the source emitting the event (even if the source is not active)
func onDurationChanged(_ event: DurationChangedEvent, source: Source) {
// ...
}
}
Source Listener
If you want to listen to SourceEvent
and receive them on the actual source (also for non-active Source
s) you can attach a SourceListener
to a Source
:
// v3
source.add(listener: sourceListener)
Sender
To distinguish which source emitted an event we added the sender to the SourceListener
methods. To have a unified API we decided to also add this to the PlayerListener
and to the UserInterfaceListener
:
v2
func onPlay(_ event: PlayEvent) {
// If the same listener handles multiple player instances there is no way to detect which player emitted the event
}
v3
func onPlay(_ event: PlayEvent, player: Player) {
// The player instance which is associated with the emitted event
}
func onSourceLoaded(_ event: SourceLoadedEvent, source: Source) {
// The source instance which is associated with the emitted event
}
DurationChangedEvent
The DurationChangedEvent
is no longer emitted initially when the duration is available the first time. As replacement access the duration when the SourceLoadedEvent
is received.
SourceLoad related events
As the SourceLoaded
and the SourceUnloaded
events will now be emitted per source (and also for non-active sources), we needed to add replacements to ensure old workflows still work as expected.
v2 | v3 |
---|---|
SourceLoadedEvent was emitted when we were about to load a source indicating the player started a source life-cycle | PlayerActiveEvent is emitted when the player received one or more sources and is about to start loading |
SourceUnloadedEvent was emitted after we finished unloading a source indicating the player finished the source life-cycle | PlayerInactiveEvent is emitted when all sources were removed from the player and as no more sources attached |
UI / View
Default Bitmovin Player Web UI
The new v3 iOS SDK isn’t compatible with Bitmovin Player Web UI v2.x
. To use the v3 SDK with a customized Bitmovin Player Web UI you will need to update your Player Web UI version to v3.x
. The recommended version is 3.25.0
and above.
We continue to support Bitmovin Player Web UI v2.x
for use with our v2 iOS SDK only. More details on the Bitmovin Player Web UI can be found here.
Customization
To create a custom UI you no longer need to sub-class PlayerView
, you can just subclass UIView
by now. The PlayerView
should only be used if you want to use any of the UIs we provide.
We added new methods on the Player
protocol to allow registering an AVPlayerLayer
or an AVPlayerViewController
to give more flexibility about where the video should be rendered.
v2
class CustomView: PlayerView {
override init(player: Player, frame: CGRect) {
super.init(player: player, frame: frame)
}
}
v3
Using AVPlayerLayer
.
class CustomView: UIView {
init(player: Player, frame: CGRect) {
super.init(frame: frame)
player.register(playerLayer)
}
var playerLayer: AVPlayerLayer {
layer as! AVPlayerLayer
}
override class var layerClass: AnyClass {
AVPlayerLayer.self
}
}
Using AVPlayerViewController
.
let avPlayerViewController = AVPlayerViewController()
player.register(avPlayerViewController)
Examples
We have updated our iOS Samples GH Repository as well to get you started with our new major version 3 for iOS/tvOS. Check them out!