Application collectors
Bitmovin Media Player
For the iOS / tvOS Collector
The Bitmovin Media Player Extension is a configuration option for the iOS / tvOS Collector by Datazoom that makes the following additional data points automatically collectable in real time.
Integration Instructions
Description
The DzBitmovinPlayerAdapter project offers a set of utilities and functionality to facilitate seamless integration with Bitmovin Player implementations. It provides common code and abstraction layers to streamline the integration of Datazoom's tracking capabilities into Bitmovin Player-powered applications.
Installation
To use the DzBitmovinPlayerAdapter project in your application, include the following dependency in your project's Gradle file:
The preferred way of installing Collector is via the Swift Package Manager.
Swift package manager
12Add Swift Package Dependency - navigate to File → Add Packages3Paste the repository URL: https://gitlab.com/datazoom/apple/libraries-release/apple_dz_bitmovin_player_adapter4For Rules, select Branch (with branch set to main) and click Add Package.5On the confirmation dialog click Add Package, again.Note: Instead of downloading the full git history of DzBitmovinPlayerAdapter and building it from source, this repo just contains a pointer to the precompiled XCFramework included in the latest DzBitmovinPlayerAdapter release.
Cocoapods
Add the 'DzBitmovinPlayerAdapter' pod in the podfile
1source 'https://gitlab.com/datazoom/pod-specs.git'2pod 'DzBitmovinPlayerAdapter'Usage
To integrate the DzBitmovinPlayerAdapter project into your project:
Initialize DzBitmovinPlayerAdapter by providing your Datazoom configuration id and configuring necessary settings.
Initialization
1 let configBuilder = Config.Builder(configurationId: configId)2 configBuilder.logLevel(logLevel: .verbose)3 configBuilder.isProduction(isProduction: isProduction)4 5 Datazoom.shared.doInit(config: configBuilder.build())⚠️ Important: Always set
isProduction = trueunless directed by Datazoom.
Create Context
If you want to track events from your Bitmovin Player, you need to create a context and assign your player to it so that the SDK can track events and metadata from your specified player.
1/**2 * Creates a player context. A player context is used to embed the player with Datazoom and is responsible for player-specific events.3 * - Parameters:4 * - player: The Player(Bitmovin) instance.5 * - eventSpace: The event space to be used to create the player context. This parameter is optional. If not provided, a default event space will be created.6 * - Returns: The DzAdapter.7 * @see <a href="https://help.datazoom.io/">Datazoom Help</a>8 */9func createContext(10 player: Player,11 eventSpace: BaseContext = Datazoom.shared.createBaseContext()12) -> DzAdapterExample
1Datazoom.shared.createContext(player: bitmovinPlayer)Custom Metadata - Context
Context custom metadata is used to attach metadata, which is a Dictionary of your choice, to each event sent from the given context you created using the Datazoom object. For more information, please refer to the Datazoom documentation on custom metadata.
API looks like
1/**2 * Sends metadata to Context.3 *4 * - Parameters:5 - metadata: a Dictionary that will be attached to each event being sent from SDK, for more information on this topic, please visit our6 * documentation.7 */8func setMetadata(metadata: <String, Any>)Example
1yourPlayerContext.setMetadata(2 [3 "property": "custom property",4 "property2": "custom property2",5 ]6)You can also retrieve your current metadata by calling the following API:
1/**2 * Returns the metadata that is being sent with each event in given context.3 *4 * @return The metadata that is being sent with each event in given context.5 */6func getMetadata() -> <String, Any>Example
1yourPlayerContext.getMetadata()Player width and height
We have the ability to gather player width and height and track if there any change in the dimensions. We expect you to invoke context/adapter following function with a UIView sending the superview of the Bitmovin Player.
1func setPlayerView(playerView: UIView)Example
1yourPlayerContext.setPlayerView(playerView: yourVideoPlayerView)Fullscreen
We have the ability to send Fullscreen/Exit Fullscreen events. We expect you to invoke context/adapter following function with a boolean sending Fullscreen state.
1func sendFullScreenEvent(isFullScreen: Bool)Example
1yourPlayerContext.sendFullScreenEvent(isFullScreen = {isFullScreen})Custom Events - Context
To send events in the context scope, you can use the following method, with each parameter explained below.
1/**2 * Sends an event to given context.3 *4 * - Parameters:5 * - name: The name of the event.6 * - payload: a Dictionary that will be attached to each event being sent from given context, for more information on this topic, please visit our documentation.7 */8func generateEvent(name: String, payload: <String, Any>)Example
1yourPlayerContext.generateEvent(2 name = "login",3 eventMap =4 [5 "property": "custom property",6 "property2": "custom property2",7 ]8)Custom Events - Global
To send events in the global scope, you can use the following method, with each parameter explained below.
1/**2 * Sends an event to Datazoom.3 *4 * - Parameters:5 * - name: The name of the event.6 * - payload: a Dictionary that will be attached to each event being sent from SDK, for more information on this topic, please visit our documentation.7 */8fun generateEvent(name: String, payload: <String, Any>)Example
1Datazoom.shared.generateEvent(2 name = "login",3 eventMap =4 [5 "property": "custom property",6 "property2": "custom property2",7 ]8)Custom Metadata - Global
Global metadata is used to attach metadata, which is a HashMap of your choice, to each event sent from any context you created using the Datazoom object. For more information, please refer to the Datazoom documentation on custom metadata.
API looks like
1/**2 * Sends metadata to Datazoom.3 * 4 * - Parameters:5 * - metadata: a Dictionary that will be attached to each event being sent from SDK, for more information on this topic, please visit our6 * documentation.7 */8fun setMetadata(metadata: <String, Any>)Example
1Datazoom.shared.setMetadata(2 [3 "property": "custom property",4 "property2": "custom property2",5 ]6)Get all player context
Datazoom supports having multiple contexts. You can create multiple contexts and Datazoom will keep track of all created contexts and give ability to get them if you need them anytime of your app lifecycle.
API looks like
1/**2 * Returns a list of all player contexts.3 *4 * @return A list of all player contexts. You can retrieve list of all player contexts at anytime in player lifecycle.5 */6fun playerContexts() -> [DzAdapter]Example
1Datazoom.shared.playerContexts()Destroy Context
If you want to destroy a context, there are multiple ways to do it. Ideally, you should ask the Datazoom object to destroy the context by either providing your context ID or the context/adapter itself.
1/**2 * Removes a player context.3 *4 * @param adapter The adapter to be used to remove the context.5 */6fun removeContext(adapter: DzAdapter)or
1/**2 * Removes a player context.3 *4 * @param id The id of the player context to be removed. its the same id returned by5 * @sample createContext(adapter: DzAdapter): String6 */7fun removeContext(id: String)Please make sure that once the context is removed from Datazoom, you do not use it for communication because it will no longer be able to communicate with the server, and you might miss critical events.
Example
1 Datazoom.shared.removeContext("contextId")or
1 Datazoom.shared.removeContext(context)The appropriate place to destroy the context could be the deinit lifecycle method of the ViewController.
1deinit {2 Datazoom.shared.removeContext(adapter: context)3 }Listening SDK events
1 Datazoom.shared.sdkEvents.watch { event in2 guard let eventDescription = event?.description as? String else { return }3 if eventDescription.contains("SdkInit") {4 // SDK initialized5 } else if eventDescription.contains("SdkError") {6 // SDK error 7 } else if eventDescription.contains("AdapterCreated") {8 // Adapter created 9 }10}Supported Client Events
SdkInit
The "SdkInit" event signals the successful initialization of the SDK and the receipt of the API key used during initialization. Upon receiving this event, users can confidently proceed with utilizing the SDK's functionalities, knowing that the SDK is ready for use with the provided API key. Ensure to handle this event appropriately in your application code to synchronize operations requiring the SDK's readiness.
SdkError
The "SdkError" event is triggered when an error occurs during the operation of the SDK. This event provides crucial information about the nature of the error, such as error codes or descriptive messages, allowing developers to identify and handle errors effectively within their applications.
AdapterCreated
The "AdapterCreated" event signifies the successful creation of an adapter within the SDK. This event provides notification to developers that the adapter, responsible for interfacing with external systems or components, is ready for use. Utilize this event to synchronize operations dependent on the availability of the adapter within your application code.
Objective-C Integration
Our XCFramework is written in Swift, which means it cannot be consumed directly in Objective-C projects. To overcome this, you need to create a Swift wrapper that exposes the required APIs in an Objective-C-compatible way.
We’ve already provided a Sample Project demonstrating this approach. Below is a step-by-step guide.
Why a Wrapper is Needed
Objective-C cannot directly recognize Swift-only features or certain language constructs. The solution is to write a thin Swift wrapper layer, where you mark the methods with @objc and make them available to Objective-C using the auto-generated Swift bridging header (
Creating a Wrapper
Create a Swift file, for example DatazoomWrapper.swift, inside your project:
1import Foundation2import AVKit3import DzBitmovinPlayerAdapter4import DzBase56@objc public class DatazoomWrapper: NSObject {78 @objc9 @MainActor static let sharedInstance = DatazoomWrapper()10 private override init() {}11 12 private var dzAdapter: DzAdapter? = nil1314 @objc15 func initializeDZ(configId: String, isProduction: Bool) {16 let configBuilder = Config.Builder(configurationId: configId)17 configBuilder.logLevel(logLevel: .verbose)18 configBuilder.isProduction(isProduction: isProduction)19 Datazoom.shared.doInit(config: configBuilder.build())20 }21 22 @objc23 func setupDataZoomAdapter(player: Player, videoUrl: String, videoPlayerView: UIView) {24 dzAdapter = Datazoom.shared.createContext(player: player)25 }26 27 @objc28 func destroyDzAdapter() {29 guard let dzAdapter else { return}30 Datazoom.shared.removeContext(adapter: dzAdapter)31 }32}Key points:
The wrapper class must inherit from NSObject.
Methods and properties you want visible in Objective-C must be marked @objc.
Make sure the wrapper itself is marked public if used from another module.
Consuming from Objective-C
Once the wrapper is in place, Xcode generates a bridging header named:
1<ProjectName>-Swift.hYou can import this in your Objective-C files:
1#import "<YourProjectName>-Swift.h"23@implementation AppDelegate45- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {6 [[DatazoomWrapper sharedInstance] initializeDZWithConfigId:@"Enter your config id" isProduction: NO];7 ////8 //// some code9}1011@endStep-by-Step Summary
Add the Datazoom dependencies to your project.
Create a Swift wrapper file.
Ensure Defines Module = YES in Build Settings.
Import
Call into the wrapper just like any Objective-C class.
Sample Project
For a working example, check out our Objective-C Integration Sample. It demonstrates:
How the wrapper is written.
How it’s imported into Objective-C.
How methods are called end-to-end.
Issues
If you encounter any issues or have suggestions for improvements, please open an issue on the GitHub repository.
Ad Frameworks Extensions
If your iOS / tvOS application has a media player with an ad framework, Datazoom’s iOS / tvOS Collector with a Bitmovin Media Player can be extended with the following ad framework extensions.
Supported Data Points
Events
Discrete occurrences driven by user interactions or system actions
Metadata
Attributes
Video
User
Fluxdata
Metrics measuring changing parameters over time
-
Buffer Duration (Content Session)
-
Buffer Length
-
Content Buffer Duration (Content Session)
-
Content Buffer Start Recency (Content Session)
-
Content Media Request Count (App Session)
-
Content Media Request Recency (Content Session)
-
Content Pause Duration (Content Session)
-
Content Playback Duration (Content Session)
-
Content Playback Start Count (App Session)
-
Content Playback Start Recency (Content Session)
-
Content Session Start Timestamp
-
Content Stall Duration (Content Session)
-
Content Stall Start Recency (Content Session)
-
Heartbeat Recency (Content Session)
-
Pause Duration (Content Session)
-
Pause Recency (Content Session)
-
Playback Duration (Content Session)
-
Playback Rate
-
Player State
-
Playhead Position
-
Rendition Change Recency (Content Session)
-
Rendition Height
-
Rendition Name
-
Rendition Video Bitrate
-
Rendition Width
-
Seek Start Recency (Content Session)
-
Stall Count (Content Session)
-
Stall Duration (Content Session)
-
Stall Start Recency (Content Session)
-
Subtitle Track
- Volume