Implementing DAI Plugin for iOS

This topic covers the use of the IMA DAI plugin and how it can be implemented through custom coding.

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.

The recommended way to add the DAI plugin to your project is the Swift Package Manager. CocoaPods is also supported, but is deprecated.

Cocoapods Implementation (deprecated)

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

The SDK and plugin downloads contain dynamic XCFrameworks. The legacy universal framework and its strip-frameworks.sh run script were removed in SDK 7.2.13, so do not add either one.

  1. Download the Brightcove Player SDK for iOS, the DAI plugin, and the Google IMA SDK.
  2. On the General tab of your application target, add BrightcovePlayerSDK.xcframework, BrightcoveDAI.xcframework, and GoogleInteractiveMediaAds.xcframework to Frameworks, Libraries, and Embedded Content.
  3. Set Embed & Sign for all three XCFrameworks.
  4. On the Build Settings tab, ensure that Framework Search Paths include the directories that contain the XCFrameworks. Xcode normally does this when the frameworks are inside the project directory.
  5. Add -ObjC to Other Linker Flags.

Swift Package Manager Implementation

Add the DAI Plugin for Brightcove Player SDK to your project with Swift Package Manager following these steps:

  1. Add the unified Brightcove Swift Package.
    1. Select the "Package Dependencies" tab for your Project
    2. Click the "+" button
    3. In the "Search or Enter Package URL" field enter:

      https://github.com/brightcove/brightcove-player-sdk-ios
    4. When the UI updates click the "Add Package" button
    5. After Xcode processes the repo you are prompted to "Choose Package Products"
    6. Select the BrightcoveDAI product (this automatically includes the Core SDK, so you do not need to add Core separately), ensure that your app target is selected, and click the "Add Package" button.

The Brightcove Swift Package resolves the matching Google IMA SDK automatically; you do not need to add it separately.

Quick Start

Create the player view, the DAI playback controller and the Playback Service request in one view controller. Replace the account, policy key and video ID values with your own.

BCOVDAIAdsRequestPolicy provides methods to specify DAI streams for VOD and live. The example uses videoPropertiesAdsRequestPolicy. BrightcoveDAI adds the createDAIPlaybackControllerWithSettings:adsRenderingSettings:adsRequestPolicy:adContainer:viewController:companionSlots:viewStrategy: method to BCOVPlayerSDKManager.

@import UIKit;
@import BrightcovePlayerSDK;
@import BrightcoveDAI;
@import GoogleInteractiveMediaAds;

@interface DAIViewController : UIViewController <BCOVPlaybackControllerDelegate>
@property (nonatomic, strong) id<BCOVPlaybackController> playbackController;
@property (nonatomic, strong) BCOVPlaybackService *playbackService;
@property (nonatomic, strong) BCOVPUIPlayerView *playerView;
@end

@implementation DAIViewController

- (void)viewDidLoad
{
    [super viewDidLoad];

    BCOVPUIPlayerViewOptions *options = [BCOVPUIPlayerViewOptions new];
    options.presentingViewController = self;
    options.automaticControlTypeSelection = YES;
    self.playerView = [[BCOVPUIPlayerView alloc] initWithPlaybackController:nil
                                                                 options:options
                                                            controlsView:nil];
    self.playerView.frame = self.view.bounds;
    self.playerView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
    [self.view addSubview:self.playerView];

    IMASettings *settings = [IMASettings new];
    IMAAdsRenderingSettings *renderingSettings = [IMAAdsRenderingSettings new];
    BCOVDAIAdsRequestPolicy *policy = [BCOVDAIAdsRequestPolicy videoPropertiesAdsRequestPolicy];

    self.playbackController = [[BCOVPlayerSDKManager sharedManager]
        createDAIPlaybackControllerWithSettings:settings
                           adsRenderingSettings:renderingSettings
                               adsRequestPolicy:policy
                                    adContainer:self.playerView.contentOverlayView
                                 viewController:self
                                 companionSlots:nil
                                   viewStrategy:nil];
    self.playbackController.delegate = self;
    self.playbackController.autoAdvance = YES;
    self.playbackController.autoPlay = YES;
    self.playerView.playbackController = self.playbackController;

    self.playbackService = [[BCOVPlaybackService alloc] initWithAccountId:@"YOUR_ACCOUNT_ID"
                                                                policyKey:@"YOUR_POLICY_KEY"];
    NSDictionary *configuration = @{ BCOVPlaybackService.ConfigurationKeyAssetID: @"YOUR_VIDEO_ID" };
    __weak DAIViewController *weakSelf = self;
    [self.playbackService findVideoWithConfiguration:configuration
                                    queryParameters:nil
                                         completion:^(BCOVVideo *video, id jsonResponse, NSError *error) {
        if (!video) {
            NSLog(@"Error retrieving video: %@", error);
            return;
        }
        [weakSelf.playbackController setVideos:@[video]];
    }];
}

@end

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

  1. In your UIViewController, create a BCOVPUIPlayerView 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;
                    
  2. 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];
                    
  3. Set up the layout for the player view

    Do this with Auto Layout or the older Springs & Struts method.

    1. Springs & Struts

                          self.playerView.frame = self.videoView.bounds;
                          self.playerView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
                              

    2. 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],
                                                                    ]];
                              
  4. 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.playbackController = controller;
                    self.playerView.playbackController = controller;
                        

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, see the Custom Layouts section in the README.md file of the Brightcove Native Player SDK repository.

Seek without Ads

For ordinary seeking, use BCOVPlaybackController's seekToTime:completionHandler: method. The DAI plugin can return playback to an unplayed ad break before continuing to the requested position, so an ordinary seek is not a way to bypass ads.

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:^(BCOVMutableVideo *mutableVideo) {
        NSMutableDictionary *properties = [mutableVideo.properties mutableCopy];
        properties[kBCOVDAIVideoPropertiesKeySourceId] = @"YOUR_DAI_SOURCE_ID";
        properties[kBCOVDAIVideoPropertiesKeyVideoId] = @"YOUR_DAI_VIDEO_ID";
        mutableVideo.properties = properties;
    }];
}
            
        // Swift
func updateVideo(_ video: BCOVVideo) -> BCOVVideo {
    return video.update { mutableVideo in
        var properties = mutableVideo.properties
        properties[kBCOVDAIVideoPropertiesKeySourceId] = "YOUR_DAI_SOURCE_ID"
        properties[kBCOVDAIVideoPropertiesKeyVideoId] = "YOUR_DAI_VIDEO_ID"
        mutableVideo.properties = properties
    }
}
            

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) {
    [self.videoView addSubview:view];
    return self.videoView;
};
                

Composing Session 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 necessary to register those views with the IMA SDK. Learn more.

To get the current IMAAdDisplayContainer object necessary to register your overlays from the playbackController:playbackSession:didEnterAdSequence: delegate method of your BCOVPlaybackController instance. Follow the next example:

        - (void)playbackController:(id<BCOVPlaybackController>)controller playbackSession:(id<BCOVPlaybackSession>)session
        didEnterAdSequence:(BCOVAdSequence *)adSequence
        {
            NSDictionary *props = session.video.properties;
            IMAAdDisplayContainer *adDisplayContainer = props[kBCOVDAIVideoPropertiesKeyAdDisplayContainer];
            IMAFriendlyObstruction *obstruction = [[IMAFriendlyObstruction alloc]
                initWithView:self.adOverlayView
                     purpose:IMAFriendlyObstructionPurposeMediaControls
              detailedReason:@"Custom playback controls"];
            [adDisplayContainer registerFriendlyObstruction:obstruction];
        }
            

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<BCOVPlaybackController>)controller playbackSession:(id<BCOVPlaybackSession>)session
            didExitAdSequence:(BCOVAdSequence *)adSequence
                
            {
                NSDictionary *props = session.video.properties;
                IMAAdDisplayContainer *adDisplayContainer = props[kBCOVDAIVideoPropertiesKeyAdDisplayContainer];
                [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<BCOVPlaybackController>)controller
            playbackSession:(id<BCOVPlaybackSession>)session
            didReceiveLifecycleEvent:(BCOVPlaybackSessionLifecycleEvent *)lifecycleEvent
            {
                if (![lifecycleEvent.eventType isEqualToString:kBCOVDAILifecycleEventAdsManagerDidReceiveAdEvent])
                {
                    return;
                }
                IMAAdEvent *adEvent = lifecycleEvent.properties[kBCOVDAILifecycleEventPropertyKeyAdEvent];
                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.