Objective-C SDK Manual

Introduction

Voice Ads allow users to engage with ads using voice commands. While listening to music or a stream, an ad user can speak various voice commands which will be introduced to users within the ad creative. When a user says ‘skip it’, ‘next’, ‘cancel’, ‘not interested’, etc, we stop serving the current ad and play the next one if there is one scheduled.

When a user engages with the ad, we perform the requested action, e.g. open browser, playing a successive audio with ‘more details’, etc.

Actions can be ‘positive’ when users want to ‘know more’ or make a purchase or ‘negative’ when users say ‘no’ or ‘I’m not interested’.

First, you need to add "Privacy - Microphone Usage Description" flag to info.plist in order to prevent future app crashes. Then, use the code below in order to set up the microphone access request.

//
//  ViewController.m
//  AdmanUi
//
//  Created by test name on 12/13/16.
//  Copyright В© 2016 Unisound. All rights reserved.
//

#import <AVFoundation/AVFoundation.h>
#import <UIKit/UIKit.h>

@interface DialogSampleController : UIViewController
@end


@interface DialogSampleController ()
@end

@implementation DialogSampleController

- (void)viewDidLoad {
}


- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
}

- (void) showRequestInfoDialog
{
    if ([[AVAudioSession sharedInstance] recordPermission] == AVAudioSessionRecordPermissionGranted)
        return;
    
    if ([[AVAudioSession sharedInstance] recordPermission] == AVAudioSessionRecordPermissionDenied ||
        [[NSUserDefaults standardUserDefaults] objectForKey:@"admanLastMicroPermissionNotifyDate"] != nil) {
        NSDate *lastNotifyDate = [[NSUserDefaults standardUserDefaults] objectForKey:@"admanLastMicroPermissionNotifyDate"];
        
        NSDateComponents *diff = [[NSCalendar currentCalendar] components:NSCalendarUnitDay fromDate:lastNotifyDate toDate:[NSDate new] options:NSCalendarWrapComponents];
        if ([diff day] <= 6)
            return;
        
        UIAlertController * alert = [UIAlertController
                                     alertControllerWithTitle:@"Microphone disabled."
                                     message:@"If you want to control advertising with your voice and even skip it please enable microphone permission in Settings."
                                     preferredStyle:UIAlertControllerStyleAlert];
        [alert addAction:[UIAlertAction
                          actionWithTitle:@"Ok"
                          style:UIAlertActionStyleDefault
                          handler:nil]];
        
        [self presentViewController:alert animated:NO completion:nil];
        return;
    }
    
    UIAlertController * infoDialog = [UIAlertController
                                      alertControllerWithTitle:@"Do you want to enable Dialogue Ads?"
                                      message:@"Now you can control advertising with your voice and even skip it. Do you want to try Dialogue Advertising?"
                                      preferredStyle:UIAlertControllerStyleAlert];
    
    UIAlertAction* noButton = [UIAlertAction
                               actionWithTitle:@"No"
                               style:UIAlertActionStyleDefault
                               handler:^(UIAlertAction * action) {
                                   NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
                                   NSDate *today = [NSDate new];
                                   
                                   [defaults setObject:today forKey:@"admanLastMicroPermissionNotifyDate"];
                                   [defaults synchronize];
                               }];
    UIAlertAction* yesButton = [UIAlertAction
                                actionWithTitle:@"Yes"
                                style:UIAlertActionStyleDefault
                                handler:^(UIAlertAction * action) {
                                    [[AVAudioSession sharedInstance] requestRecordPermission:^(BOOL permission) {}];
                                }];
    [infoDialog addAction:noButton];
    [infoDialog addAction:yesButton];
    
    [self presentViewController:infoDialog animated:NO completion:nil];
    
}

@end

Implementation

If you are using CocoaPods you should add the following to a podfile:

pod 'Adman'

Then, 'pod update' command should be used to update all the libraries from the podfile, including our SDK and 'pod update Adman' should be used to update our SDK only.

Integration Example

Please find the code example below. (In this example our SDK is used to run an ad every 90 seconds for illustrative purposes, for your app please implement the SDK according to your product logic.):

Please note, that in Demo project you can find in open source version shouldn't be used for integration. The aim of the project is to demonstrate the technology. It shouldn't be inserted to the application in any way.

#import <AVFoundation/AVPlayer.h>
#import <UIKit/UIKit.h>
#import <Adman_framework/Adman.h>
#import <Adman_framework/AdmanUIBase.h>
@interface ViewController : UIViewController<AdmanDelegate>
@end
@interface ViewController ()
@property Adman *adman;
@property AVPlayer *player;
@end
@implementation ViewController
- (void)viewDidLoad {
   [super viewDidLoad];
   // init media player
   _player = [AVPlayer playerWithURL:[NSURL URLWithString:@"https://playlist.pls"]];;
   // init libAdman
   _adman = [Adman sharedManagerWithSiteId:1249 region:AdmanRegionGlobal testMode:false];
   _adman.delegate = self;
}
- (void)viewDidAppear:(BOOL)animated {
   [super viewDidAppear:animated];
   [_player setVolume:1.0];
   // init ads preloading
   [_adman prepareWithType:AdmanTypeAny];
   // start audio playback
   [_player play];
   // play ads each 90 seconds
   [NSTimer timerWithTimeInterval:90 repeats:YES block:^(NSTimer *timer) {
       // report can_show stat event
       [self.adman reportAdEvent:@"can_show"];
       // start ad playback
       if (self.adman.state == AdmanStateReadyForPlayback) {
           AdmanUIBase *admanUI = [[AdmanUIBase alloc] init];
           [admanUI show:self];
           [self.adman play];            
       }
   }];
}
- (void)didReceiveMemoryWarning {
   [super didReceiveMemoryWarning];
}
- (void)admanStateDidChange:(Adman *)sender {
   switch (sender.state) {
       case AdmanStateAdChangedForPlayback:
           break;
       case AdmanStatePlaying:
           break;
       case AdmanStatePlaybackCompleted:
           [_player play];
           [_adman prepareWithType:AdmanTypeAny];
           break;
       case AdmanStateFetchingInfo:
           break;
       case AdmanStateVoiceInteractionStarted:
           break;
       case AdmanStateStopped:
       case AdmanStateVoiceInteractionEnded:
           break;
       case AdmanStateVoiceResponsePlaying:
           break;
       case AdmanStateReadyForPlayback:
           break;
       case AdmanStateError:
       case AdmanStateAdNone:
           [_player play];
           [_adman prepareWithType:AdmanTypeAny];
           break;
       default:
           break;
   }
}

@end

How it work?

Here is a detailed explanation of how our Voice Ads SDK for iOS works:

Ad Request

After importing the library, you need to create a class instance to control the advertisement:

_adman = [Adman sharedManagerWithSiteId:1249 region:AdmanRegionGlobal testMode:false];

In this case, 1249 is a publisher ID. We use 1249 for testing purposes only. The value for region will be different for different publishers. Please ask our representatives for your value. In this manual we are using 'Global' , but for EU server you should use 'AdmanRegionEU' . Please, do not change the server during the initial integration.

To fetch Voice ads from ad server you should use:

[_adman prepareWithType:AdmanTypeVoice];

If you need to work with Voice ads and Audio ads simultaneously you should use:

[_adman prepareWithType:AdmanTypeAny];

If an ad request is completed correctly, the state of Adman object will be changed. This occurs every time the state of Adman object is changed:

- (void)stateDidChange:(Adman *)sender

The above method will be called and you can check it using:

sender.state == AdmanStateReadyForPlayback

Here is the list of possible values:

If there is an ad available for playback, then playback should be started. Before starting the playback, the following method should be called:

[adman reportAdEvent:@"can_show"];

You need to call [adman reportAdEvent:@"can_show"]; in any case when you're supposed to play an ad, even if you haven't received any. The method should be called at any possible ad placement in the app. This is very important and will dramatically affect the revenue. Please, see the example below for reference.

Ad Playback

First of all, advertising audio files and banner (in case of presence of a banner) will be cached. Then our SDK will call statistic pixels in order to report that ad request was made and ad was received successfully. Then, the following method must be used:

AdmanUIBase *admanUI = [[AdmanUIBase alloc] init];
[admanUI show:self];
[self.adman play];

Please note, that DefaultView will automatically start ad playback when autoPlay:true is used. So, no need to use (void)play method to start playback. This view is recommended for the best user experience.

On ad start Adman state will be changed to AdmanStatePlaying and start event will be reported by calling the corresponding statistic pixel and the Teaser audio will be delivered. At the end of Teaser audio, our SDK will activate the device microphone in order to receive a voice response from the listener. The microphone will remain active for 4 seconds. After 3 seconds, the microphone will be disabled and all the recorded material will be sent to Instreamatic recognition server. If the response was shorter than 3 seconds, our voice activity detection technology will handle it, and microphone will be turned off before 3 sec mark.

Depending on the recognition result, our SDK will perform the following actions:

  • Will deliver a second audio component;

  • Will open a link in the browser;

  • Will initiate a phone call;

  • Will deliver an AI response if user wasn’t interested in the ad subject.

In cases when a response wasn’t interpreted in the context of an actual ad, a listener will be asked to repeat the response. A listener will be able to reply once again, and then ad playback will be stopped.

In cases, when voice recognition server sensed silence or unknown noises, AI response will be played and app user will be returned to content.

In case of successful interpretation of a listener response or silence, Adman states will be changed in the following order:

In case of an unsuccessful interpretation of a listener response, Adman states will be changed in the following order:

After the ad, listener should be returned to content and another ad should be requested.

Instance Methods Reference

Please contact us before using any additional methods!

- (void)prepare; 
- (void)prepareWithType:(AdmanType)type;

These methods used to send a request to the ad server to get an ad. If succeed it starts to buffer an audio and caching of companion banner (if exists). Please see below for possible values of 'type'

_______________________________________________________________________________

Please, contact us before using the below methods instead of showDefaultView

Ad playback:

- (void)play;

Ad pause:

- (void)pause;

Ad resume (after the pause):

- (void)resume;

Ad stop:

- (void)stop;

_______________________________________________________________________________

To send data for targeting, the below method can be used

[Adman setSiteVariables:@{@“gender”: “M\F, @“age”: age}]
//or
[Adman setSiteVariables:@{@“gender”: “M\F, @“age_min”: age_min, @“age_max”: age_max}]

This method must be used before prepare.

_______________________________________________________________________________

To get the SDK version, the below method can be used

- (nonnull NSString *) getVersion;

AdmanDelegate Reference

- (void)admanStateDidChange:(nonnull Adman *) sender;

Called when adman state changed.

_______________________________________________________________________________

- (void)phraseRecognized:(nonnull NSString *)phrase;

Handles all the responses from the speech recognition server. The result displays two keys: phrase transcript and target action.

_______________________________________________________________________________

- (void)userPhraseValid:(nonnull NSString *)phrase;

Used when a phrase was recognized successfully and the target action can be performed by SDK.

_______________________________________________________________________________

- (void)userPhraseInvalid:(nonnull NSString *)phrase;

Used when a phrase wasn't interpreted or in cases when SDK got silence instead of a human voice.

_______________________________________________________________________________

- (void)customVoiceIntentHandler;

Handled when there is a specific section for Voice Ads in received VAST-Document.

_______________________________________________________________________________

- (void)bannerTouched:(nullable NSString *) urlToNavigate;

Handled when listener tapped on the banner image.

_______________________________________________________________________________

- (void)viewClosed;

Handled when Default View is closed.

_______________________________________________________________________________

- (void)errorReceived:(nullable NSError *) error;

Handled when SDK got an error from the network or audio player.

_______________________________________________________________________________

- (void)log:(nonnull NSString*)message;

Use this to enable more detailed logging.

How to test the integration?

After the integration, you will be getting unlimited Voice Ads for all your ad requests. Please make sure that the ad is reacting to your commands in the way it's expected. Test for Positive, Negative, and Swear words (if needed), etc.

How to send bug reports?

Please send all the reports by mail to support@instreamatic.com .

In case of unusual behavior (wrong responses, ad skips, etc), please send your idfa along with the incident description. So we will be able to analyze what happened. The good practice is to collect some incidents and send them all in one mail instead of sending them one my one.

In case of a crash, please send the crash log/report to inspect.

Please see our FAQ Page below for frequently asked questions

Why SDK?

Your decision to make Instreamatic Dialogue Ads available on your native mobile apps will provide a highly valuable and unique audio communication capability that makes audio ads “smart”. These ads are driven by Voice AI and allow the listener to respond to various scenarios with voice commands that drive target actions.

The Instreamatic SDK is the most simple and hassle-free way to integrate Dialogue ads to your app. There will be no need for complex coding or fine-tuning, just integrate our SDK by following this short manual and you are ready to go. The whole installation should only take an hour or so for a qualified tech professional and we will support your installation all through the process.

Is it safe?

Yes, our SDK is completely safe for your app and your users. Upon your request, we will share our tech specifications, so you can easily check for yourself that our SDK is completely safe for using it in your apps. You will have the full support from us during the integration process and even afterwards. Our SDK was tested on all Apple devices available in the market, so the possibility of a crash has been eliminated. You can implement in a test environment first to review with your QA team to become absolutely comfortable and again, we will support you through the entire process.

What kind of support can I expect?

Our support team is available by email during business hours on weekdays in most time zones. We also provide detailed installation manuals that provide clear instructions and answer most all questions. We will also answer the questions during the initial integration. Please note, that you should provide all the information regarding the issues during the integration if you need support from our side.

Please see our FAQ Page below for frequently asked questions

What to do if I do not want to use SDK?

You can contact your account manager or support team in order to get tech specifications of the protocol we are using. With our documentation, you will be able to build your own integration, but please keep in mind that you will need to perform some complex coding in order to build the integration. We will still provide support if you decide to take this option.

Feel free to contact our support at support@instreamatic.com

Last updated