Overview
The Brightcove SDK offers a plugin to interact with the Google IMA-DAI library for multimedia ads playback in your application, and abstracts the setup and basic interaction with the Google IMA-DAI library so you can focus on requesting video streams.
Cocoapods Implementation
You can use CocoaPods to add the DAI Plugin for Brightcove Player SDK to your project. You can find the latest Brightcove-Player-DAI podspec here. The pod incorporates the correct version of IMA automatically.
CocoaPod podfile snippet:
source 'https://github.com/CocoaPods/Specs'
source 'https://github.com/brightcove/BrightcoveSpecs.git'
platform :ios, '14.0'
use_frameworks!
target 'MyDAIPlayer' do
pod 'Brightcove-Player-DAI'
end
Manual Implementation
To add the DAI Plugin for Brightcove Player SDK to your project manually follow these steps:
- Download the Brightcove Player SDK framework.
- Download the DAI Plugin for Brightcove Player SDK framework.
- Download the Google IMA framework.
- Add the dymnamic framework.
- On the "General" tab of your application target, add the
BrightcovePlayerSDK.framework
orBrightcovePlayerSDK.xcframework
. - From the Brightcove Player SDK download to the list of Frameworks, Libraries, and Embedded Content. The universal Framework and XCFramework are found in the ios/dynamic directory of the download. The Embed setting must be "Embed & Sign".
- On the "General" tab of your application target, add the
- Add the DAI framework.
- On the "General" tab of your application target, add the
BrightcoveDAI.framework
orBrightcoveDAI.xcframework
. - From the DAI Plugin from Brightcove Player SDK download to the list of Frameworks, Libraries, and Embedded Content. The Embed setting must be "Embed & Sign".
- On the "General" tab of your application target, add the
- Add the Google Media Ads framework.
- On the "General" tab of your application target, add the
GoogleInteractiveMediaAds.xcframework
. - From the Google IMA download to the list of Frameworks, Libraries, and Embedded Content. The Embed setting for the XCFrameworks must be "Embed & Sign".
- On the "General" tab of your application target, add the
- On the "Build Settings" tab of your application target, ensure that the "Framework Search Paths" include the paths to the frameworks.
- On the "Build Settings" tab of your application target Ensure that -ObjC has been added to the "Other Linker Flags" build setting.
- For (Universal Framework only).
- On the "Build Phases" tab, add a "Run Script" phase with the command bash
${BUILT_PRODUCTS_DIR}/${FRAMEWORKS_FOLDER_PATH}/BrightcoveDAI.framework/strip-frameworks.sh
. - Check "Run script only when installing". This will remove unneeded architectures from the build, which is important for App Store submission.
- On the "Build Phases" tab, add a "Run Script" phase with the command bash
- For (Apple Silicon only).
- On the "Build Settings" tab of your application target, ensure that arm64 has been added to your "Excluded Architectures" build setting for Any iOS Simulator SDK.
Swift Package Manager Implementation
Add the DAI Plugin for Brightcove Player SDK to your project with Swift Package Manager following these steps:
- add the Core XCFramework.
- Select the "Package Dependencies" tab for your Project
- Click the "+" button
In the "Search or Enter Package URL" field enter:
https://github.com/brightcove/brightcove-player-sdk-ios.git
- When the UI updates click the "Add Package" button
- After Xcode processess the repo you are prompted to "Choose Package Products"
- ensure that your app target is selected and click the "Add Package" button.
Add the DAI package to Swift Package Manager using:
https://github.com/brightcove/brightcove-player-sdk-ios-dai.git
- Download the Google IMA framework.
- Add the Google Media Ads framework.
- On the "General" tab of your application target, add the
GoogleInteractiveMediaAds.xcframework
. - From the Google IMA download to the list of Frameworks, Libraries, and Embedded Content. The Embed setting for the XCFrameworks must be "Embed & Sign".
- On the "General" tab of your application target, add the
- On the "Build Settings" tab of your application target, ensure that the "Framework Search Paths" include the paths to the frameworks.
Quick Start
Create ads rendering settings:
IMASettings *imaSettings = [IMASettings new];
imaSettings.ppid = kViewControllerIMAPublisherID;
imaSettings.language = kViewControllerIMALanguage;
IMAAdsRenderingSettings *adsRenderingSettings = [IMAAdsRenderingSettings new];
adsRenderingSettings.linkOpenerDelegate = self;
adsRenderingSettings.linkOpenerPresentingController = self;
UIView *videoContainerView = <UIView of video container>;
BCOVDAIAdsRequestPolicy
provides methods to specify DAI Streams for VOD and Live. Select the appropriate method to select your ads policy.
BCOVDAIAdsRequestPolicy *adsRequestPolicy = [BCOVDAIAdsRequestPolicy videoPropertiesAdsRequestPolicy];
BCOVPlayerSDKManager *manager = [BCOVPlayerSDKManager sharedManager];
BrightcoveDAI adds some category methods to BCOVPlaybackManager. The first of these is - createDAIPlaybackControllerWithSettings:adsRenderingSettings:adsRequestPolicy:adContainer:viewController:companionSlots:viewStrategy:
. Use this method to create your playback controller.
id<BCOVPlaybackController> controller =
[manager createDAIPlaybackControllerWithSettings:imaSettings
adsRenderingSettings:adsRenderingSettings
adsRequestPolicy:adsRequestPolicy
adContainer:playerView.contentOverlayView
viewController:self
companionSlots:nil
viewStrategy:nil];
controller.delegate = self;
[videoContainerView addSubview:playerView];
NSString *policyKey = <your-policy-key>;
NSString *accountId = <your-account-id>;
NSString *videoID = <your-video-id>;
BCOVPlaybackService *playbackService = [[BCOVPlaybackService alloc] initWithAccountId:accountID
policyKey:policyKey];
NSDictionary *configuration = @{
kBCOVPlaybackServiceConfigurationKeyVideoID:videoID
};
[playbackService findVideoWithConfiguration:configuration
queryParameters:nil
completion:^(BCOVVideo *video,
NSDictionary *jsonResponse,
NSError *error) {
[controller setVideos:@[ video ]];
[controller play];
}];
The complete code is:
IMASettings *imaSettings = [IMASettings new];
imaSettings.ppid = kViewControllerIMAPublisherID;
imaSettings.language = kViewControllerIMALanguage;
IMAAdsRenderingSettings *adsRenderingSettings = [IMAAdsRenderingSettings new];
adsRenderingSettings.linkOpenerDelegate = self;
adsRenderingSettings.linkOpenerPresentingController = self;
UIView *videoContainerView = <UIView of video container>;
BCOVDAIAdsRequestPolicy *adsRequestPolicy = [BCOVDAIAdsRequestPolicy videoPropertiesAdsRequestPolicy];
BCOVPlayerSDKManager *manager = [BCOVPlayerSDKManager sharedManager];
id<BCOVPlaybackController> controller =
[manager createDAIPlaybackControllerWithSettings:imaSettings
adsRenderingSettings:adsRenderingSettings
adsRequestPolicy:adsRequestPolicy
adContainer:playerView.contentOverlayView
viewController:self
companionSlots:nil
viewStrategy:nil];
controller.delegate = self;
[videoContainerView addSubview:playerView];
NSString *policyKey = <your-policy-key>;
NSString *accountId = <your-account-id>;
NSString *videoID = <your-video-id>;
BCOVPlaybackService *playbackService = [[BCOVPlaybackService alloc] initWithAccountId:accountID
policyKey:policyKey];
NSDictionary *configuration = @{
kBCOVPlaybackServiceConfigurationKeyVideoID:videoID
};
[playbackService findVideoWithConfiguration:configuration
queryParameters:nil
completion:^(BCOVVideo *video,
NSDictionary *jsonResponse,
NSError *error) {
[controller setVideos:@[ video ]];
[controller play];
}];
Play and Pause
The Brightcove DAI Plugin implements custom play and pause. Use the play method on the BCOVPlaybackController
or the -[BCOVSessionProviderExtension dai_play]
or -[BCOVSessionProviderExtension dai_pause]
(BCOVSessionProviderExtension), and not the AVPlayer.
Using the Built-In PlayerUI
-
In your
UIViewController
, create aBCOVPUIPlayerView
property called the player view, to contain the playback controls, the video content view, and a special view where DAI can display its ads// PlayerUI's player view @property (nonatomic) BCOVPUIPlayerView *playerView;
Create your player view
Supply a nil playback controller. This player view contains both the video content view and the view that displays playback controls and ad controls. Set up the player view to match the video container from your layout ( videoView ) when it resizes
// Create and configure Control View. BCOVPUIBasicControlView *controlView = [BCOVPUIBasicControlView basicControlViewWithVODLayout]; // Create the player view with a nil playback controller. self.playerView = [[BCOVPUIPlayerView alloc] initWithPlaybackController:nil options:nil controlsView:controlView]; // Add BCOVPUIPlayerView to your video view. [self.videoView addSubview:self.playerView];
Set up the layout for the player view
Do this with Auto Layout or the older Springs & Struts method.
Springs & Struts
self.playerView.frame = self.videoView.bounds; self.playerView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
Auto Layout
self.playerView.translatesAutoresizingMaskIntoConstraints = NO; [NSLayoutConstraint activateConstraints:@[ [self.playerView.topAnchor constraintEqualToAnchor:self.videoView.topAnchor], [self.playerView.rightAnchor constraintEqualToAnchor:self.videoView.rightAnchor], [self.playerView.leftAnchor constraintEqualToAnchor:self.videoView.leftAnchor], [self.playerView.bottomAnchor constraintEqualToAnchor:self.videoView.bottomAnchor], ]];
Create the Content Overlay View
The
contentOverlayView
is a special view used for overlaying views on the main video content.// Create the playback controller. id<BCOVPlaybackController> controller = [manager createDAIPlaybackControllerWithSettings:imaSettings adsRenderingSettings:adsRenderingSettings adsRequestPolicy:adsRequestPolicy adContainer:playerView.contentOverlayView viewController:self companionSlots:nil viewStrategy:nil]; controller.delegate = self; // Assign new playback controller to the player view. // This associates the playerController's session with the PlayerUI. // You can keep this player view around and assign new // playback controllers to it as they are created. self.playerView.playbackController = self.playbackController;
Now, when playing video with ads, you will see the PlayerUI controls while playing video content, plus ad markers on the timeline scrubber.
The playerUI is highly customizable. For more info and sample code, please se Custom Layouts section in the README.md file of the Brightcove Native Player SDK repository
Seek without Ads
Use -[BCOVPlaybackController seekWithoutAds:(CMTime)seekToTime completionHandler:(void (^)(BOOL finished))completion]
to resume playback at a
specific time without forcing the user to watch ads scheduled before seekToTime
.
In preparation for seekWithoutAds:completionHandler:
, disable autoPlay
when setting up the BCOVPlaybackController
.
- (void)playbackController:(NSObject<BCOVPlaybackController>*)controller
playbackSession:(NSObject*)session
didReceiveLifecycleEvent:(BCOVPlaybackSessionLifecycleEvent *)lifecycleEvent
{
if ([kBCOVPlaybackSessionLifecycleEventReady isEqualToString:lifecycleEvent.eventType])
{
// self.resumePlayback is a hypothetical instance variable used here for illustration.
if (self.resumePlayback)
{
__weak typeof(controller) weakController = controller;
// seek without playing ads which are scheduled before the seek time, i.e. resume playback.
[controller seekWithoutAds:CMTimeMake(seekWithoutAdsValue, seekWithoutAdsTimescale)
completionHandler:^(BOOL finished) {
if (!finished)
{
NSLog (@"seekWithoutAds failed to finish");
}
typeof(controller) strongController = weakController;
if (strongController)
{
// fade out the shutter to reveal the player view.
strongController.shutterFadeTime = 0.25;
strongController.shutter = NO;
// turn off seek without ads - especially important if this player is being used with a playlist
self.resumePlayback = NO;
}
}];
}
}
}
Enable the shutter to hide the player view:
NSObject<BCOVPlaybackController> *playbackController;
playbackController = [sdkManager createFWPlaybackControllerWithAdContextPolicy:nil
viewStrategy:nil];
playbackController.delegate = self;
if (self.resumePlayback)
{
// set the shutter fade time to zero to hide the player view immediately.
playbackController.shutterFadeTime = 0.0;
playbackController.shutter = YES;
// disable autoPlay when resuming playback.
playbackController.autoPlay = NO;
}
Customizing Plugin Behavior
You can combine BCOVDAI with another plugin for the Brightcove Player SDK for iOS to create a custom view strategy and supply a custom ads request policy.
Ads Request Policy for VOD and Live
BCOVDAIAdsRequestPolicy
has two factory methods to generate ads request policy; one for VOD and one for Live.
Method for VOD
The method +videoPropertiesAdsRequestPolicy
: returns an ads request policy which looks for the kBCOVDAIVideoPropertiesKeySourceId
and kBCOVDAIVideoPropertiesKeyVideoId
in each BCOVVideo
's properties to determine the DAI Stream.
Method for Live
The method +videoPropertiesAssetKeyAdsRequestPolicy
: returns an ads request policy that checks each BCOVVideo
's properties for the key kBCOVDAIVideoPropertiesKeyAssetKey
to determine the DAI Live Stream.
Add properties to a video
You can add properties to a video by using the update:
method on the BCOVVideo
object. The following example adds the properties needed for VOD:
// Objective-C
- (BCOVVideo *)updateVideo:(BCOVVideo *)video
{
return [video update:^(id<BCOVMutableVideo> mutableVideo)
{
NSDictionary *adProperties = @{
kBCOVDAIVideoPropertiesKeySourceId: kViewControllerGoogleDAISourceId,
kBCOVDAIVideoPropertiesKeyVideoId: kViewControllerGoogleDAIVideoId
};
NSMutableDictionary *propertiesToUpdate = mutableVideo.properties.mutableCopy;
propertiesToUpdate addEntriesFromDictionary:adProperties];
mutableVideo.properties = propertiesToUpdate;
}];
}
// Swift
func updateVideo(_ video: BCOVVideo) -> BCOVVideo {
return update { (mutableVideo: BCOVMutableVideo?) in
guard let mutableVideo = mutableVideo else {
return
}
if var updatedProperties = mutableVideo.properties {
updatedProperties[kBCOVDAIVideoPropertiesKeySourceId] = GoogleDAIConfig.SourceID
updatedProperties[kBCOVDAIVideoPropertiesKeyVideoId] = GoogleDAIConfig.VideoID
mutableVideo.properties = updatedProperties
}
}
}
View Strategy
With a custom view strategy, the ad container view and ad companion slots can be tied with the video content view. This is an example of custom view strategy
BCOVPlaybackControllerViewStrategy customViewStrategy =
^UIView* (UIView *view, id<BCOVPlaybackController< playbackController){
BCOVPlaybackControllerViewStrategy defaultControlsViewStrategy = [playbackManager defaultControlsViewStrategy];
UIView *contentAndDefaultControlsView = defaultControlsViewStrategy(view, playbackController);
[ addSubview:contentAndDefaultControlsView];
return ;
};
Composing Sesion Providers
If you are using more than one plugin to the Brightcove Player SDK for iOS that needs to create a customized playback controller, you must compose a chain of session providers and pass the final session provider to the -[BCOVPlayerSDKManager createPlaybackControllerWithSessionProvider:viewStrategy
:] method.
When composing session providers, the session preloading can be enabled from BCOVBasicSessionProvider
.
Registering Ad Overlays
If you are placing any views over ads while they are playing, it is necceessary to register those views with the IMA SDK. Learn more.
To get the current IMAAdDisplayContainer
object neccessary to register your overlays from the playbackController:playbackSession:didEnterAdSequence:
delegate method of your BCOVPlaybackController
instance. Follow the next example:
- (void)playbackController:(id)controller playbackSession:(id)session
didEnterAdSequence:(BCOVAdSequence *)adSequence
{
NSDictionary *props = session.video.properties;
IMAAdDisplayContainer *adDisplayContainer = props[kBCOVDAIVideoPropertiesKeyAdDisplayContainer];
[adDisplayContainer registerFriendlyObstruction:self.adOverlayView];
}
To unregister the obstructions when the ad sequence is finished, the playbackController:playbackSession:didExitAdSequence:
delegate method of your BCOVPlaybackController
instance. Follow the next example:
- (void)playbackController:(id)controller playbackSession:(id)session
didExitAdSequence:(BCOVAdSequence *)adSequence
{
NSDictionary *props = session.video.properties;
IMAAdDisplayContainer *adDisplayContainer = props[kBCOVIMAVideoPropertiesKeyAdDisplayContainer];
[adDisplayContainer unregisterAllFriendlyObstructions];
}
AirPlay
To use this functionality in your apps set enableBackgroundPlayback
to YES on IMASettings
along with enabling AirPlay on your BCOVPlaybackController
. Learn more.
AVPlayerViewController Support
Displaying Ad UI
To display your own Ad UI during ad playback you can use the playbackController:playbackSession:didReceiveLifecycleEvent:
delegate method. Here is an example:
#pragma mark BCOVPlaybackControllerDelegate
- (void)playbackController:(id)controller
playbackSession:(id)session
didReceiveLifecycleEvent:(BCOVPlaybackSessionLifecycleEvent *)lifecycleEvent
{
...
if ([lifecycleEvent.eventType isEqualToString:kBCOVDAILifecycleEventAdsManagerDidReceiveAdEvent])
{
IMAAdEvent *adEvent = lifecycleEvent.properties[@"adEvent"];
}
switch (adEvent.type)
{
case kIMAAdEvent_STARTED:
[self displayAdUI];
break;
case kIMAAdEvent_COMPLETE:
[self hideAdUI];
break;
default:
break;
}
}
Limitations
- The use of Brightcove VOD Streams are limited.
- DRM is not supported.