Objective-c Basic example

From Engineering Client Portal

Revision as of 21:09, 1 December 2020 by ColinBrown (talk | contribs) (→‎NielsenInit.m)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)

Engineering Portal / Digital / DCR & DTVR / DCR Video iOS SDK / Objective-c Basic example

iphonescreenshot.png

Objective-C Code Example

NielsenInit.m

//  NielsenInit.m
//  VideoPlayerAppObjC
// This is sample code of a very basic implementation of the Nielsen 'Simplified API'
// This code is for educational purposes only

#import "NielsenInit.h"
#import <NielsenAppApi/NielsenAppApi.h>

@implementation NielsenInit

+ (NielsenAppApi *)createNielsenAppApiWithDelegate:(id<NielsenAppApiDelegate>)delegate
{
    //Initialising the NielsenAppApi class by passing app information which returns the instance of NielsenAppApi.
    
    NSDictionary *appInformation = @{ @"appid": @"PDA7D5EE6-B1B8-4123-9277-2A788BC65XXX",
                                      @"appversion": @"1.0",
                                      @"sfcode": @"dcr",
                                      @"nol_devDebug": @"DEBUG" };
    
    return [[NielsenAppApi alloc] initWithAppInfo:appInformation delegate:delegate];
}


@end

NielsenInit.h

#import <Foundation/Foundation.h>

@class NielsenAppApi;
@protocol NielsenAppApiDelegate;

@interface NielsenInit : NSObject

+ (NielsenAppApi *)createNielsenAppApiWithDelegate:(id<NielsenAppApiDelegate>)delegate;

@end

SDKMethods.m

#import <Foundation/Foundation.h>
#import "SDKMethods.h"


@implementation SDKMethods
NSDictionary *content;

-(void)setContentUrl
{
    //Loading Content URL    
    self.url = [NSURL URLWithString:@"http://www.nielseninternet.com/NielsenConsumer/prog_index.m3u8"];
}

-(void)setAdUrl
{
    //Loading Ad URL    
    self.url = [NSURL URLWithString:@"http://www.nielseninternet.com/NWCC-3002/prog_index.m3u8"];
}

-(void)setDtvrUrl
{
    //Loading DTVR URL    
    self.url = [NSURL URLWithString:@"http://www.nielseninternet.com/VOD/NielsenScienceBehindWhatsNext/prog_index.m3u8"];
}

- (NSDictionary *)loadChannelInfo
{
    //Loading Channel Info.    
    NSString *strUrl = self.url.absoluteString;  
    NSDictionary *channel = @{  @"channelName" : @"ChannelTitle",
                             @"mediaURL": strUrl };   
    return channel;
}

// http://www.nielseninternet.com/NielsenConsumer/prog_index.m3u8
- (NSDictionary *)loadContent
{
    //Loading Content data
        self.url = [NSURL URLWithString:@"http://www.nielseninternet.com/NielsenConsumer/prog_index.m3u8"];   
    NSDictionary *content = @{    @"type":@"content",
                                @"assetid":@"C77664",
                                @"length":@"3600",
                                @"program":@"MyProgram",
                                @"segB":@"CustomSegmentValueB",
                                @"segC":@"segmentC",
                                @"title":@"S2,E3",
                                @"section":@"cloudApi_app",
                                @"airdate":@"20180301 10:00:00",
                                @"isfullepisode":@"y",
                                @"adloadtype":@"2",
                                @"channelName":@"My Channel 1",
                                @"pipMode":@"false" };
    
    return content;
}

- (NSDictionary *)loadPreRollAd
{
    //loading Ad data.   
    self.url = [NSURL URLWithString:@"http://www.nielseninternet.com/NWCC-3002/prog_index.m3u8"];   
    NSDictionary *ad = @{ @"type":@"preroll",
                        @"assetid":@"AD1",
                        @"title":@"ADPreTitle" };    
    return ad;
}

- (NSDictionary *)loadDtvr{
    
    //Loading DTVR data  
    NSDictionary *dtvr = @{ @"adModel":@"1" };  
    return dtvr;
}

@end

SDKMethods.h

#import <Foundation/Foundation.h>

@interface SDKMethods : NSObject

@property(nonatomic, strong) NSURL *url;

- (void)setContentUrl;
- (void)setAdUrl;
- (void)setDtvrUrl;
- (NSDictionary *)loadChannelInfo;
- (NSDictionary *)loadContent;
- (NSDictionary *)loadPreRollAd;
- (NSDictionary *)loadDtvr;

@end

ViewController.m

#import "ViewController.h"
#import "NielsenInit.h"
#import "SDKMethods.h"
#import <MediaPlayer/MediaPlayer.h>
#import <AVKit/AVKit.h>
#import "Constants.h"

#import <NielsenAppApi/NielsenAppApi.h>

NSMutableDictionary *mutableData;
NSDictionary *data;
SDKMethods *sdkMethods;
AVPlayer  *player;
AVPlayerViewController *playerController;
NielsenAppApi *nielsenApi;

int totalVideosPlayed;
id timeObserver;
static void *TimedMetadataObserverContext = &TimedMetadataObserverContext;
NSString *timedMetadataKey = @"currentItem.timedMetadata";
id array;

@interface ViewController()<AVPlayerViewControllerDelegate>

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    //Setting background image
    UIImage *backgroundImage = [UIImage imageNamed:@"bg_image.jpg"];
    UIImageView *backgroundImageView=[[UIImageView alloc]initWithFrame:self.view.frame];
    backgroundImageView.image=backgroundImage;
    [self.view insertSubview:backgroundImageView atIndex:0];
    
    //Mark: In NielsenInit class we are initialising the NielsenEventTracker.
    
    //Getting the instance of NielsenEventTracker
    nielsenApi = [NielsenInit createNielsenAppApiWithDelegate:nil];
    
    //Mark: In SDKMethods class we wrote methods which creates content,Ad objects
    sdkMethods = [[SDKMethods alloc] init];
    
    if(self.videoType == onlyContent){
        //loading video content url
        [sdkMethods setContentUrl];
        
    }else if(self.videoType == dtvrVideo){
        //loading video DTVR url
        [sdkMethods setDtvrUrl];
        
    }else{
        //loading video Ad url
        [sdkMethods setAdUrl];
    }
    
    [self setPlayer];
    
    if(self.videoType != dtvrVideo){
        
        //For DTVR video playHeadPosition is not required
        //For DCR Content,Ad videos only this method will execute.
        [self setPlayHeadPosition];
    }
    
    
    //Setting observer to know the completion of video
    [self setVideoFinishObserver];
    
}


-(void) setPlayer {
    
    //creating player
    player = [AVPlayer playerWithURL:[sdkMethods url]];
    playerController = [[AVPlayerViewController alloc] init];
    playerController.view.frame = CGRectMake(0,100,self.view.frame.size.width, 300);
    playerController.player = player;
    playerController.showsPlaybackControls = YES;
    playerController.delegate = self;
    
    [player play];
    
    if(totalVideosPlayed == 0){
        //For first time sending Channel info to SDK using "play" method.
        [nielsenApi play:([sdkMethods loadChannelInfo])];
    }
    
    if(self.videoType == dtvrVideo){
        
        //loading DTVR metadata
        data = [sdkMethods loadDtvr];
    }else{
        
        //loading video content metadata data
        data = [sdkMethods loadContent];
    }
    //Sending metadata to SDK.
    [nielsenApi loadMetadata:(data)];
    
    if(self.videoType == contentWithOneAd){
        //loading Ad data
        data = [sdkMethods loadPreRollAd];
        [nielsenApi loadMetadata:(data)];
    }
    
    //Adding observer to player to track play,pause and reverse
    [player addObserver:self
             forKeyPath:@"rate"
                options:(NSKeyValueObservingOptionNew)
                context:nil];
    
    //Only for DTVR videos we are tracking iD3 Tags and sends to SDK after extracting.
    if(self.videoType == dtvrVideo){
        
        //Setting observer to track timedMetadata
        [player addObserver:self
                 forKeyPath: timedMetadataKey
                    options: (NSKeyValueObservingOptionNew)
                    context: &TimedMetadataObserverContext];
        
    }
    
    [self addChildViewController:playerController];
    [self.view addSubview:playerController.view];
}

-(void) setPlayHeadPosition {
    
    //Setting play head position
    CMTime timeInterval = CMTimeMakeWithSeconds(1, 1);
    [player addPeriodicTimeObserverForInterval:(timeInterval) queue:dispatch_get_main_queue() usingBlock:^(CMTime time){
        NSTimeInterval seconds = CMTimeGetSeconds(time);
        NSInteger intSec = seconds;
        
        //Sending data dictionary to SDK with updated playHead position.
        [nielsenApi playheadPosition:(intSec)];
    }];
}

- (void) setVideoFinishObserver {
    
    //observer fires on completion of Ad
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(playerDidFinishPlaying:) name:AVPlayerItemDidPlayToEndTimeNotification object:playerController.player.currentItem];
}

//rate 0 = Video Pause or stopped
//rate 1 = Video played or resumed
- (void)observeValueForKeyPath:(NSString *)keyPath
                      ofObject:(id)object
                        change:(NSDictionary *)change
                       context:(void *)context
{
    if(keyPath == timedMetadataKey){
        if(context == &TimedMetadataObserverContext){
            
            id newMetadataArray = [change objectForKey:NSKeyValueChangeNewKey];
            if (newMetadataArray != [NSNull null])
            {
                array = newMetadataArray;
                for (AVMetadataItem *metadataItem in array)
                {
                    //Handling TimedMetadata
                    [self handleTimedMetadata: metadataItem];
                }
            }
            
        }
    }
    
    
    if (object == player && [keyPath isEqualToString:@"rate"]) {
        
        NSNumber * newValue = [change objectForKey:NSKeyValueChangeNewKey];
        int intValue = newValue.intValue;
        if(intValue == 0){
            NSLog(@"playback paused");
            
            //On Video pause calling the "stop" method of SDK.
            [nielsenApi stop];
            
        }else if(intValue == 1){
            NSLog(@"Normal playback");
            
            //On video Resume calling "loadMetada" method of SDK
            [nielsenApi loadMetadata:(data)];
            
        }
    }
}

- (void)viewDidDisappear:(BOOL)animated
{
    ///On moving to other screen calling "stop" method of SDK.
    [nielsenApi stop];
    
    player.rate = 0;
    [player pause];
    
    [super viewDidDisappear:animated];
}

-(void)playerDidFinishPlaying:(NSNotification *) notification {
    
    [player removeObserver:self forKeyPath:@"rate"];
    
    //As 1 video completed playing, incrementing the variable value.
    totalVideosPlayed += 1;
    
    if(self.videoType == onlyContent || totalVideosPlayed == self.totalVideos){
        //When content video completes or total videos finishes, call "end" method.
        [nielsenApi end];
        
    }else if(self.videoType == contentWithOneAd){
        
        //On completion of "AD" call "stop" method.
        [nielsenApi stop];
        
        //After preRoll ad completes, load content video.
        data = [sdkMethods loadContent];
        
    }
    
    //Checking if total videos played or not.
    if(totalVideosPlayed != self.totalVideos){
        
        [self setPlayer];
        [self setPlayHeadPosition];
        
        //Setting observer to know the completion of video
        [self setVideoFinishObserver];
        
    }
}

- (void)dealloc {
    NSLog(@"Remove NotificationCenter dealloc");
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}

- (void)handleTimedMetadata:(AVMetadataItem *)timedMetadata
{
    // We expect the content to contain plists encoded as timed metadata
    // AVPlayer turns these into NSDictionaries
    
    id extraAttributeType = [timedMetadata extraAttributes];
    NSString *extraString = nil;
    if ([extraAttributeType isKindOfClass:[NSDictionary class]])
    {
        extraString = [extraAttributeType valueForKey:@"info"];
    }
    else if ([extraAttributeType isKindOfClass:[NSString class]])
    {
        extraString = extraAttributeType;
    }
    
    NSString *key = [NSString stringWithFormat:@"%@", [timedMetadata key]];
    
    //If tag starts with "www.nielsen.com", then only sending to SDK
    if ([key isEqualToString:@"PRIV"] && [extraString rangeOfString:@"www.nielsen.com"].length > 0)
    {
        
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            [nielsenApi sendID3:extraString];
        });
    }
}

@end

ViewController.h

#import <UIKit/UIKit.h>

@class NielsenAppApi;
@protocol NielsenAppApiDelegate;


@interface ViewController : UIViewController

@property (nonatomic) int videoType;
@property (nonatomic) int totalVideos;

@end

OptOutVC.h

#import <UIKit/UIKit.h>

@class NielsenEventTracker;
@protocol NielsenEventTrackerDelegate;

@interface OptOutVC : UIViewController

@property (nonatomic, weak) NielsenEventTracker *nielsenEventTracker;

@end