Template

Template:iOS Airplay

From Engineering Client Portal

AirPlay

To implement OTT measurement, report OTT changes to the SDK using public API interface: updateOTT

In order to detect AirPlay and mirroring changes we use AVAudioSessionPortDescription properties that are different on different iOS versions. We found that on iOS versions 8 - 10 AVAudioSessionPortDescription has the following values:
AirPlay: type = AirPlay; name = Apple TV 4K; UID = DC:56:E7:53:72:85-airplay
Mirroring: type = AirPlay; name = Apple TV 4K; UID = DC:56:E7:53:72:85-screen

For iOS 11+ some parameters like name and UID have different values:
AirPlay: type = AirPlay; name = AirPlay; UID = 0eb63aae-5915-45f1-b0f7-0102a0e50d53
Mirroring: type = AirPlay; name = Apple TV 4K; UID = 4335E8A9-1C0A-4251-9000-28CA5FA2F3CF-192731714653291-screen

The following code snipped is suggested for AirPlay / mirroring detection on iOS devices.

Swift

nielsenSdk.updateOTT(currentStatus)

Subscribe to AVAudioSessionRouteChangeNotification

NotificationCenter.default.addObserver(self, selector: #selector(handleRouteChanged(_:)), name: NSNotification.Name.AVAudioSessionRouteChange, object: nil)

Handle AVAudioSessionRouteChangeNotification and prepare OTT dictionary:

func handleRouteChanged(_ notification: Notification) {
var currentStatus: [String: String] = ["ottStatus": "0"]

let session = AVAudioSession.sharedInstance()
let currentRoute = session.currentRoute
for outputPort in currentRoute.outputs {
if outputPort.portType == AVAudioSessionPortAirPlay {
currentStatus["ottStatus"] = "1"
currentStatus["ottDeviceModel"] = outputPort.portName
currentStatus["ottDeviceID"] = outputPort.uid

if outputPort.portName == "AirPlay" {
currentStatus["ottDevice"] = "airplay"
currentStatus["ottType"] = "airplay"
}
else {
if outputPort.portName.contains("Apple TV") {
currentStatus["ottDevice"] = "appleTV"
}
else {
currentStatus["ottDevice"] = "other"
}

if outputPort.uid.hasSuffix("airplay") {
currentStatus["ottType"] = "airplay"
}
else if outputPort.uid.hasSuffix("screen") {
currentStatus["ottType"] = "mirroring"
}
else {
currentStatus["ottType"] = "other"
}
}
}
}

// report OTT status update to Nielsen SDK
self.reportOTTUpdate(currentStatus)
}

Report OTT update to the Nielsen SDK

func reportOTTUpdate(_ ottDict: [String: String]) {
if let nielsenSdk = self.nielsenAppApi {
nielsenSdk.updateOTT(currentStatus)
}
}

Objective C

 (void)updateOTT:(id)ottInfo;

Subscribe to AVAudioSessionRouteChangeNotification

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleRouteChanged:) name:AVAudioSessionRouteChangeNotification object:nil];

Handle AVAudioSessionRouteChangeNotification and prepare OTT dictionary:

- (void)handleRouteChanged:(NSNotification *)notification
{
NSMutableDictionary *ottDict = [NSMutableDictionary dictionaryWithDictionary: @{@"ottStatus": @"0"}];

AVAudioSession *audioSession = [AVAudioSession sharedInstance];
AVAudioSessionRouteDescription *currentRoute = audioSession.currentRoute;
for (AVAudioSessionPortDescription *outputPort in currentRoute.outputs) {
if ([outputPort.portType isEqualToString:AVAudioSessionPortAirPlay]) {
ottDict[@"ottStatus"] = @"1";
ottDict[@"ottDeviceModel"] = outputPort.portName;
ottDict[@"ottDeviceID"] = outputPort.UID;

if ([outputPort.portName isEqualToString:@"AirPlay"]) {
ottDict[@"ottDevice"] = @"airplay";
ottDict[@"ottType"] = @"airplay";
}
else {
if ([outputPort.portName containsString:@"Apple TV"]) {
ottDict[@"ottDevice"] = @"appleTV";
}
else {
ottDict[@"ottDevice"] = @"other";
}

if ([outputPort.UID hasSuffix:@"airplay"]) {
ottDict[@"ottType"] = @"airplay";
}
else if ([outputPort.UID hasSuffix:@"screen"]) {
ottDict[@"ottType"] = @"mirroring";
}
else {
ottDict[@"ottType"] = @"other";
}
}
}
}

// report OTT status update to Nielsen SDK
[self reportOTTWithDict:ottDict];
}

Report OTT update to the Nielsen SDK

- (void)reportOTTWithDict:(NSDictionary *)ottDict
{
[self.nielsenSDK updateOTT:ottDict];
}