DCR Chromecast iOS SDK

From Engineering Client Portal

Engineering Portal breadcrumbArrow.png Digital breadcrumbArrow.png DCR & DTVR breadcrumbArrow.png DCR Chromecast iOS SDK

1. General Cast architecture


Screen Shot 2018-09-25 at 10.26.22(1).png

See https://developers.google.com/cast/docs/developers

Sender App

is a user-controlled native app that runs on a mobile device (Android, iOS) or a laptop (JS).

Receiver App

is an HTML5/JavaScript application placed at a custom URL that handles communication between the sender app and the Chromecast device.

2. Cast scenarios

2.1 Pure casting scenario

The video is only playing on a Chromecast device.
The sender app should not pass any Nielsen API calls once the pure casting scenario starts. All Nielsen API calls are handled by the receiver app.

Screen Shot 2018-09-25 at 09.35.08.png

2.2 Chromecast mirroring scenario

The video is playing on both the sender and receiver apps.

Screen Shot 2018-09-25 at 09.35.19.png

3.Sender App (iOS) - Nielsen SDK implementation

3.1 General

By adding the below cast-specific API calls alongside the standard implementation of the Nielsen AppSDK into your native application, a sender app can pass appropriate cast-specific metadata.

3.2 API call updateOTT


mAppSdk.updateOTT(JSONObject ottInfo)


Use the updateOTT method to notify the AppSDK whether the remote OTT device (like Google ChromeCast, Roku, Amazon FireTV, etc.) is connected or disconnected (indicated by "ottStatus").

When the OTT device is connected, call updateOTT with "ottStatus": "1" as well as a set of OTT device related parameters in the ottInfo Dictionary.

NSDictionary *ottInfo = @
        {
   @"ottStatus": @"1",
   @"ottType": @"casting",
   @"ottDevice": @"chromecast",
   @"ottDeviceName": @"Google ChromeCast",
   @"ottDeviceID": @"xxxx-xxxx-xxxx",
   @"ottDeviceManufacturer": @"Google",
   @"ottDeviceModel": @"ChromeCast",
   @"ottDeviceVersion": @"1.0.0"
}

When the OTT device is disconnected, call updateOTT with "ottStatus": "0".

NSDictionary *ottInfo = @
{
    @"ottStatus": @"0"
}

Notes:

  • Every time the application is launched or moves to foreground, call updateOTT to report the current OTT status.
  • The application needs to report all the possible OTT types (casting, screen mirroring, and any other types) to App SDK.

3.3 Communicating with the Chromecast Receiver App


SDK cannot communicate directly with the Receiver App running on the Chromecast as it needs access to the Google Casting framework. Alternatively, App SDK requires the application to pass the data to the Receiver App. The application should:

  • Retrieve the Opt-Out status on the device (using getOptOutStatus()) and its Demographic ID (using getDemographicId())
  • Relay the retrieved details / values to the Receiver App, as additional parameters in GCKMediaMetadata payload.
    • Create the metadata information for this purpose, using GCKMediaMetadata.

The two custom parameters to be included in GCKMediaMetadata are

  • kGCKMetadataNlsKeyDeviceID for device ID.
  • kGCKMetadataNlsKeyOptout for Opt-out status (true or false).


Notes :

  • To get more information about Opt Out, please refer to general AppSDK implementation guide: Privacy and Nielsen Opt-Out
  • Result of getOptOutStatus() should be 0 or 1 (true or false)
  • Result of getDemographicId() is an alphanumeric string (ex: a5ff494cce22bda39b29da2509f90f52e4e044587107ba9ca092eb3a1c2eccdf)
  • IMPORTANT: Nielsen Opt Out status is completely dependent on the setting in the sender device (iPhone or iPad) - not any settings in the ChromeCast menus.


Below is a sample code snippet on how the application should retrieve and relay the information from App SDK to Receiver App:

static NSString * const kGCKMetadataNlsKeyDeviceID = @"kGCKMetadataNlsKeyDeviceID";
static NSString * const kGCKMetadataNlsKeyOptout = @"kGCKMetadataNlsKeyOptout";

GCKMediaMetadata *metadata = [[GCKMediaMetadata alloc] init];
NSUInteger channelIndex = [self.appConfig.channels indexOfObject:self.currentChannel] + 1;
[metadata setString:[NSString stringWithFormat:@"Channel %d", channelIndex] forKey:kGCKMetadataKeyTitle];
[metadata setString:self.currentChannel.urlString forKey:kGCKMetadataKeySubtitle];

// custom parameters
[metadata setString:self.nielsenAppApi.demographicId forKey:kGCKMetadataNlsKeyDeviceID];
[metadata setString:(self.nielsenAppApi.optOutStatus) forKey:kGCKMetadataNlsKeyOptout];

[self logConsole:[NSString stringWithFormat:@"Reporting parameters to receiver. %@: %@, %@: %@", kGCKMetadataNlsKeyDeviceID, self.nielsenAppApi.demographicId, kGCKMetadataNlsKeyOptout, (self.nielsenAppApi.optOutStatus)]];

GCKMediaInformation *mediaInformation =
[[GCKMediaInformation alloc] initWithContentID:self.currentChannel.urlString
                                    streamType:GCKMediaStreamTypeUnknown
                                    contentType:@"video/mp4"
                                    metadata:metadata
                                    streamDuration:0
                                    customData:nil];
[self.chromecastControlChannel loadMedia:mediaInformation autoplay:YES playPosition:0];

4. Receiver app (JavaScript) - Nielsen SDK implementation

Once casting starts, the receiver app becomes important as a BSDK instance must be created and the related appropriate API events must be called. Please refer to the Browser SDK guide for more information.

4.1 BSDK init

The BSDK receiver instance gets initialized on load of the Chromecast receiver app.

window.nolSDKInstance = NOLBUNDLE.nlsQ("Pxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxx", "ChromeCastInstance" );

Note: replace "Pxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxx" with your Nielsen provided AppID.

4.2 LoadMetadata

On load of remote player, retrieve content metadata sent by the sender device and pass it using the loadMetadata API call.

var metadata = {
              "assetid" : senderMetadata.assetid,
              "type" : senderMetadata.type,
              "program" : senderMetadata.program,
              "title" : senderMetadata.title,
              "length" : senderMetadata.length,
              "mediaUrl" : senderMetadata.mediaUrl,
              "airdate" : senderMetadata.airdate,
              "isfullepisode" : senderMetadata.isfullepisode,
              "crossId1" : senderMetadata.crossId1,
              "nol_c1" : senderMetadata.nol_c1,
              "nol_c2" : senderMetadata.nol_c2,
              "segB" : senderMetadata.segB,
              "segC" : senderMetadata.segC,
              "adloadtype" : senderMetadata.adloadtype,
              "hasAds" : senderMetadata.hasAds
          };
window.nolSDKInstance.ggPM('loadmetadata', metadata);

Note : refer to specification of Czech MetaData and follow it

4.3 updateOTT

Send the updateOTT event to BSDK receiver instance. The updateOTT event should relay the ottmetadata (kGCKMetadataNlsKeyDeviceID and kGCKMetadataNlsKeyOptout) received from sender app.

sessionId = senderMetadata.kGCKMetadataNlsKeyNUID?senderMetadata.kGCKMetadataNlsKeyNUID:senderMetadata.kGCKMetadataNlsKeyDeviceID;

var contentMetadataObject ={
                        type: "content",
                        ottStatus: "1",
                        ottType: "casting",
                        ottDevice: "chromecast",
                        ottDeviceName: "Google Chromecast",
                        ottDeviceID: sessionId,
                        ottDeviceManufacturer: "Google",
                        ottDeviceModel: "ChromeCastModel",
                        ottDeviceVersion: "1.0.0", 
    kGCKMetadataNlsKeyOptout : (["1",true,1,"true"].indexOf(senderMetadata.kGCKMetadataNlsKeyOptout)>=0)?true:false,
                        kGCKMetadataNlsKeyDeviceID : sessionId
                  };
window.nolSDKInstance.ggPM('updateOTT', contentMetadataObject);

4.4 Rest of API calls

Fire off other API calls based on App/Player state. Refer to the BSDK implementation guide for more information.

// play
window.nolSDKInstance.ggPM('play',Math.round(event.path[0].currentTime));

// setPlayheadPosition
window.nolSDKInstance.ggPM('setPlayheadPosition',Math.round(event.path[0].currentTime));

// pause
window.nolSDKInstance.ggPM('pause',Math.round(event.path[0].currentTime));

// stop
window.nolSDKInstance.ggPM('stop',Math.round(event.path[0].currentTime));

// end
window.nolSDKInstance.ggPM('end',Math.round(event.path[0].currentTime));

4.4 Sample code

Below is a sample code snippet on how the receiver app should retrieve the ottMetadata received from sender apps and relay the information to receiver BSDK instance.

sampleplayer.CastPlayer.prototype.onLoad_ = function(event) {

var senderMetadata = event.data.media.metadata,
	    
sessionId =senderMetadata.kGCKMetadataNlsKeyDeviceID;

  this.cancelDeferredPlay_('new media is loaded');
  this.load(new cast.receiver.MediaManager.LoadInfo( (event.data),  event.senderId));
	var contentMetadata = {
         	      "assetid" : senderMetadata.assetid,
              "type" : senderMetadata.type,
              "program" : senderMetadata.program,
              "title" : senderMetadata.title,
              "length" : senderMetadata.length,
              "mediaUrl" : senderMetadata.mediaUrl,
              "airdate" : senderMetadata.airdate,
              "isfullepisode" : senderMetadata.isfullepisode,
              "crossId1" : senderMetadata.crossId1,
              "nol_c1" : senderMetadata.nol_c1,
              "nol_c2" : senderMetadata.nol_c2,
              "segB" : senderMetadata.segB,
              "segC" : senderMetadata.segC,
              "adloadtype" : senderMetadata.adloadtype,
              "hasAds" : senderMetadata.hasAds
	};

      window.nolSDKInstance.ggPM('loadmetadata', contentMetadata);
	  
	   var ottMetadataObject ={
			ottStatus: "1",
			ottType: "casting",
			ottDevice: "chromecast",
			ottDeviceName: "Google Chromecast",
			ottDeviceID: sessionId,
			ottDeviceManufacturer: "Google",
			ottDeviceModel: "ChromeCastModel",
			ottDeviceVersion: "1.0.0", 
			kGCKMetadataNlsKeyOptout : senderMetadata.kGCKMetadataNlsKeyOptout,
		              kGCKMetadataNlsKeyDeviceID : sessionId	
		  };

window.nolSDKInstance.ggPM('updateOTT', ottMetadataObject);};

5. Summary - Correct squence of API calls

Below is the sequence of API calls sequence from the beginning to the end of casting.

SENDER side :

1) If the video is playing only on the sender app, the standard Nielsen SDK API calls should be invoked.
2) Once a user presses the cast icon and if the video was playing already, call end().
3) Inform the AppSDK about the Chromecast's status (connected or disconnected) by calling updateOTT(config metadata).
4) Retrieve the optOutStatus and demographicId by calling getOptOutStatus() and getDemographicId().
5) Pass the optOutStatus and demographicId into the MediaMetaData object.
6) Start casting (the video should be stopped on the sender device).

RECIEVER side :

Playback has started at ChromeCast device (TV)
7) Retrieve the MediaMetaData sent by the sender device.
8) Instantiate the Browser SDK.
9) Pass metadata by calling loadMetaData().
10) Pass playheads every second by calling setPlayheadPosition().
11) Based on the user's interactions or the playlist state, call stop() (once paused) or end() (once the content or casting has ended).

SENDER side :

Casting has ended and playback continues on the sender device
12) Start a new session by calling play() and loadMetaData().
13) Continue sending API calls as usual.

6. Testing implementation

See https://developers.google.com/cast/docs/debugging
Note: make sure that all your test devices and PC are connected to the same network.
1. Start the iOS/iPad application and play video.
2. Connect the app to Chromecast by pressing the cast button.

Screen Shot 2018-09-25 at 10.15.38.png

3. Launch Chrome browser and access URL chrome://inspect.
4. Under your ChromeCast device, press “inspect”

Screen Shot 2018-09-25 at 10.15.49.png

5. In your browser console, check JS activity - including Nielsen SDK. Note: make sure that the BSDK has DEBUG mode on.

Screen Shot 2018-09-25 at 10.16.02.png

6. In your Network – make sure that outgoing data to Nielsen collection is present.

Screen Shot 2018-09-25 at 10.21.23.png