- Introduction to Data
- Track your video performance
- Make API requests
- Setup alerts
- Make your data actionable with metadata
- Track autoplaying videos
- Extend Data with custom metadata
- Track CDN for request metrics
- See how many people are watching
- Build a custom integration
- Understand metric definitions
- Export raw video view data
- Ensure privacy compliance
- Mux Data FAQs
Custom Objective-C integration
This is a guide for building a custom integration with Mux Data in Objective-C.
In this guide:
Mux has a pre-built integration with Apple's AVPlayer
for iOS and tvOS applications; for these players, see here: iOS Integration Guide.
If the player that you use does not expose the AVPlayer
instance directly, swaps between multiple instances during playback, or uses some other playback mechanism completely, a custom integration may be needed.
Important Related Docs
Before proceeding, read the following overview: Building a Custom Integration.
In addition, the source code for Mux's integration with Apple's AVPlayer is open source and can be found in the Mux-Stats-AVPlayer GitHub repository. This project is a good example of how to use the Objective-C core library in building a player integration.
Installing with SwiftPM
- In XCode click "File" > "Swift Packages" > "Add Package Dependency..."
- The package repository URL is
https://github.com/muxinc/stats-sdk-objc.git
- Click
next
. - Since the
MuxCore
follows SemVer, we recommend setting the "Rules" to install the latest version and choosing the option "Up to Next Major".
Installing with CocoaPods
To include the core Objective-C library via CocoaPods, modify your Podfile to use frameworks by including use_frameworks!
and then add the following pod to your Podfile:
pod "Mux-Stats-Core", "~> 3.6"
This will include our current release of the core Objective-C library. There will be no breaking updates within major versions of this library, so you can safely run pod update
.
Since version 3, Mux-Stats-Core
has been updated for Xcode 12 and XCFrameworks bundle type. Carthage has some current issues with Xcode 12, if using Carthage you might want to see the recommended workaround.
Including Manually (not preferred)
If you do not you use CocoaPods and wish to include the library manually, view the XCFramework
directory in the Mux Objective-C Core SDK and dragging the framework into your Xcode project.
There is no need to initialize a player monitor for each player that is being tracked, as this happens automatically when events are emitted for a specific player. For the Objective-C library, the Environment and Viewer-specific data should be emitted to the SDK globally as follows.
MUXSDKEnvironmentData *environmentData = [[MUXSDKEnvironmentData alloc] init]; [environmentData setMuxViewerId:[[[UIDevice currentDevice] identifierForVendor] UUIDString]]; MUXSDKViewerData *viewerData = [[MUXSDKViewerData alloc] init]; NSString *bundleId = [[NSBundle mainBundle] bundleIdentifier]; if (bundleId) { [viewerData setViewerApplicationName:bundleId]; } // Set additional Viewer data as above MUXSDKDataEvent *dataEvent = [[MUXSDKDataEvent alloc] init]; [dataEvent setEnvironmentData:environmentData]; [dataEvent setViewerData:viewerData]; [MUXSDKCore dispatchGlobalDataEvent:dataEvent];
The only field that should be modified within MUXSDKEnvironmentData
is the muxViewerId
, via setMuxViewerId
, which should be a device-specific string. This field is used within the Mux Dashboard as the Viewer ID in the case that a user-specific value is not provided in the metadata, via [MUXSDKCustomerViewerData setViewerUserId:]
.
For MUXSDKViewerData
, the fields that may be provided are the following.
@property (nullable) NSString *viewerApplicationEngine; @property (nullable) NSString *viewerApplicationName; @property (nullable) NSString *viewerApplicationVersion; @property (nullable) NSString *viewerConnectionType; @property (nullable) NSString *viewerDeviceCategory; @property (nullable) NSString *viewerDeviceManufacturer; @property (nullable) NSString *viewerDeviceName; @property (nullable) NSString *viewerOsArchitecture; @property (nullable) NSString *viewerOsFamily; @property (nullable) NSString *viewerOsVersion;
See the AVPlayer integration for example values used.
For the Objective-C core SDK, there are two types of events that should be emitted: data events and playback events. Data events are events that update metadata about the video or view, whereas playback events are those described here: Mux Playback Events.
All events are emitted to a specific Player
, so make sure to include the unique player ID with each event emitted.
Data Events
Data events are emitted via [MUXSDKCore dispatchEvent: forPlayer:]
, and should be emitted when any of the following pieces of metadata change:
MUXSDKVideoData
videoSourceWidth
- width of the video currently being played, in pixelsvideoSourceHeight
- height of the video currently being played, in pixelsvideoSourceIsLive
- whether the video currently being played is live or notvideoSourceDuration
- the duration, in milliseconds, of the video currently being playedvideoSourceAdvertisedBitrate
- the bitrate of the current rendition being played, in bits per second- Anything in
MUXSDKCustomerPlayerData
, as defined here: Metadata - Anything in
MUXSDKCustomerVideoData
, as defined here: Metadata - Anything in
MUXSDKCustomerViewData
, as defined here: Metadata
When any of the above fields change, do the following:
- Create one or more instances of
MUXSDKVideoData
,MUXSDKCustomerPlayerData
,MUXSDKCustomerVideoData
, andMUXSDKCustomerViewData
depending on what changed - Assign all properties with the most recent value via the helper methods to the appropriate instance of data
- Attach these to an instance of
MUXSDKDataEvent
- Emit this
MUXSDKDataEvent
via[MUXSDKCore dispatchEvent: forPlayer:]
For example, when the resolution of the video being played back changes (such as in adaptive streaming), the following should be done:
Playback Events
The Mux Playback Events should be emitted as the events are defined in the referenced document. With regards to naming, the names should align with those in the document, with the following changes: MUXSDK
is appended in front of the name, the name itself should be PascalCased, and Event
is appended at the end. For instance, for playerready, the corresponding event is MUXSDKPlayerReadyEvent
, as defined in MUXSDKPlayerReadyEvent.h
.
With each playback event that is emitted, the following fields within MUXSDKPlayerData
should be included with the latest values:
playerMuxPluginName
- The name of the integration being built, as a stringplayerMuxPluginVersion
- The version of the integration being built, as a stringplayerSoftwareName
- The name of the player software (e.g.AVPlayer
,AVPlayerLayer
, etc)playerSoftwareLanguageCode
- The language code (e.g. en-US) of the player UI localizationplayerWidth
- The width of the player, in pixelsplayerHeight
- The height of the player, in pixelsplayerIsFullscreen
- Boolean of whether the player is currently displayed in full screen or notplayerIsPaused
- Boolean of whether the player is currently paused (i.e. not playing or trying to play)playerPlayheadTime
- The current playhead time of the player, in millisecondsplayerErrorCode
- Error code for the current fatal playback error. Omit this if the player has not encountered an error for this view.playerErrorMessage
- Error message for the current fatal playback error. Omit this if the player has not encountered an error for this view.
For instance, when emitting the MUXSDKPlayerReady
event, it should look like the following:
// Get the player data MUXSDKPlayerData *playerData = [[MUXSDKPlayerData alloc] init]; // Set the player data information [playerData setPlayerMuxPluginName:@"Sample Custom Player"]; // ... repeat the above for all values within `MUXSDKPlayerData` // Emit the event MUXSDKPlayerReadyEvent *event = [[MUXSDKPlayerReadyEvent alloc] init]; [event setPlayerData:playerData]; [MUXSDKCore dispatchEvent:event forPlayer:_playerName];
In addition to the above data fields, for ad and network events there are additional data fields that should be sent. These are documented alongside the events described in Mux Playback Events, and follow similar naming conventions.
In particular:
- Network throughput events should be emitted as
MUXSDKRequestBandwidthEvent
s, with the addition ofMUXSDKBandwidthMetricData
set on the event via[MUXSDKRequestBandwidthEvent setBandwidthMetricData:]
. - Ad events are emitted via a special method,
dispatchAdEvent
, and details can be seen within Mux's IMA integration for AVPlayer
Lastly, for the MUXSDKRenditionChangeEvent
, you should make sure to dispatch a MUXSDKDataEvent
with the latest updated MUXSDKVideoData
immediately before dispatching the MUXSDKRenditionChangeEvent
.
There are multiple steps in setting up and tracking a view correctly. A very simple sequence of events to track a basic playback would look like the following steps:
- Dispatch a global data event with the environment and viewer data
- Dispatch the
MUXSDKViewInitEvent
with the current state of the player and video - Dispatch a
MUXSDKDataEvent
with the updatedMUXSDKCustomerVideoData
andMUXSDKCustomerPlayerData
for the current video view - Dispatch the rest of the Mux Playback Events (e.g.
MUXSDKPlayerReadyEvent
,MUXSDKPlayEvent
,MUXSDKPlayingEvent
,MUXSDKTimeUpdateEvent
, etc), each time with the updated current state of the player
Note: For each Playback Event and MUXSDKViewInitEvent
that is dispatched, the current state of the player and video data (MUXSDKPlayerData
and MUXSDKVideoData
should be attached to the event prior to dispatching the event.
// First, emit the global data event setting up the information about // the player. This will likely only be called once within your application // and does not need to be called for each player that is tracked. MUXSDKDataEvent *dataEvent = [[MUXSDKDataEvent alloc] init]; [dataEvent setEnvironmentData:environmentData]; [dataEvent setViewerData:viewerData]; [MUXSDKCore dispatchGlobalDataEvent:_dataEvent]; // Prepare the view before you emit any other playback events MUXSDKViewInitEvent *event = [[MUXSDKViewInitEvent alloc] init]; [event setPlayerData:playerData]; [MUXSDKCore dispatchEvent:event forPlayer:playerName]; // Dispatch data about the view itself. // Note: customerPlayerData must include your environment key. MUXSDKDataEvent *dataEvent = [[MUXSDKDataEvent alloc] init]; [dataEvent setCustomerPlayerData:customerPlayerData]; [dataEvent setCustomerVideoData:customerVideoData]; [MUXSDKCore dispatchEvent:dataEvent forPlayer:_playerName]; // Emit playback events MUXSDKPlayerReadyEvent *event = [[MUXSDKPlayerReadyEvent alloc] init]; [event setPlayerData:playerData]; [MUXSDKCore dispatchEvent:event forPlayer:_playerName]; // When the player begins to attempt playback MUXSDKPlayEvent *event = [[MUXSDKPlayEvent alloc] init]; [event setPlayerData:playerData]; [MUXSDKCore dispatchEvent:event forPlayer:_playerName]; // When the player actually displays first moving frame MUXSDKPlayingEvent *event = [[MUXSDKPlayingEvent alloc] init]; [event setPlayerData:playerData]; [MUXSDKCore dispatchEvent:event forPlayer:_playerName]; // ... and repeat for all of the playback events
Most of the events are signaled as listed above. However, there are a few cases of events that require additional work.
Changing the Video
In order to change the video within a player, there are a few events that need to be fired in sequence. You can see the implementation of this within mux-stats-sdk-avplayer here. You should do the following:
- Dispatch a
viewend
event - Dispatch a
viewinit
event - Dispatch a
MUXSDKDataEvent
with the new video'sMUXSDKCustomerVideoData
, with thevideoChange
property set toYES
.
[player dispatchViewEnd]; [player dispatchViewInit]; MUXSDKDataEvent *dataEvent = [MUXSDKDataEvent new]; [dataEvent setCustomerVideoData:videoData]; dataEvent.videoChange = YES; [MUXSDKCore dispatchEvent:dataEvent forPlayer:name];
Destroying the Monitor
When you are tearing down the player and want to stop monitoring it, make sure to remove any listeners that you have on the player for sending events to MUXSDKCore
. After this, make sure to call [MUXSDKCore destroyPlayer: _name];
for the name of your player, so that the core library can clean up any monitoring and end the view session.
Current release
v3.6.0
- Add transmission time and round trip time to beacon requests
- Add
player_live_edge_program_time
- Add
player_program_time
Previous Releases
v3.5.0
- Allow overriding of viewer information (application name)
- Add nullability specifiers
- Custom beacon collection domains
v3.4.0
- Adds the
MUXSDKCustomerData
model - Adds support for setting custom dimensions
v3.3.0
- Automatically build statically linked frameworks
- Remove dependency on
UIKit
v3.2.0
- Add Swift PM support
v3.1.0
- Submits a new
mux_embed field
- Fixes bugs with video start-up time for midroll or postroll ads
- Updates ad tracking to be more accurate
- Tracks
view_playing_time
v3.0.3
- No functional changes, just generating a new release on CocoaPods
v3.0.2
- Include linker flags that enable the framework to be built without support for modules.
- Move instance variables out of headers
v3.0.0
This release moves the build process to use XCFramework bundle type. For iOS, there are no changes required to your application code.
If you are using this SDK with TVOS the name of the module has changed (the Tv
suffix is no longer needed):
TVOS before 3.0:
@import MuxCoreTv;
TVOS after 3.0:
@import MuxCore;
v2.4.1
- (bugfix) Works around an issue where a view with no pre-roll ads, but with midroll and/or postroll ads will cause Mux to update the TTFF value erroneously
v3.0.0-beta.0
This release moves the build process to use XCFramework bundle type. For iOS, there are no changes required to your application code.
If you are using this SDK with TVOS the name of the module has changed (the Tv
suffix is no longer needed):
TVOS before 3.0:
@import MuxCoreTv;
TVOS after 3.0:
@import MuxCore;
v2.4.0
- Adds support for
player_remote_played
andview_session_id
. - In addition to existing options that are provided via the
MUXSDKCustomerPlayerData
andMUXSDKCustomerVideoData
objects, there is now support forMUXSDKCustomerViewData
. Theview_session_id
may be set onMUXSDKCustomerViewData
.
v2.3.0
- Update build process for XCode 12 to exclude arm_64 architectures when building for simulator. Before XCode 12, xcodebuild never built arm_64 slices for the simulator. Now, it does (in preparation for Apple silicon). Because arm_64 slices now get built for the simulator,
lipo
errors out, because it can't have the same architecture for two different platforms (it already has arm_64 for the device platform). This is a temporary work around until a later major version release which will use the newXCFramework
hotness - bump iOS deploy target to '9.0' in
podspec
and project build settings for XCode 12 compatibility
v2.2.0
- bugfix: Removes erroneously committed logs from the compiled frameworks
v2.2.1
- bugfix - ignore scaling calculations when player or source width or height dimension is 0
v2.2.0
- Add support for
renditionchange
events - Add support for
orientationchange
events
v2.1.3
- bugfix for request metrics calculation. If we don't have responseStart, fallback to requestStart in order to calculate throughput
v2.1.2
- bugfix - Use monotonically increasing time in Objc client library. Avoids a bug if system time changes during a view.
v2.1.1
- Expose
videoSourceUrl
onMUXSDKCustomerVideoData
. This allows a user to set the videoSourceUrl (along with their other VideoData, in which case any videoSourceUrl that is inferred from the player will be ignored.
v2.1.0
- Fix build process for XCode 11
- Make player_instance_id a full uuid-style string
- Make sure to always send player_instance_id
- Bump Mux API versions for new collectors/processors