The following section describes how to accomplish the most common tasks using TritonMobileSdk. The SDK package includes a sample Xcode project that showcases the available features and shows how to integrate the SDK into a streaming application.
Set Your Region
When the SDK loads, it gets its station configuration from our provisioning servers. To speed up the process, we have provisioning servers in several regions including North America, Europe, and Asia. For best results, use the provisioning servers that are closest to your stations.
The default provisioning region is North America; to use one of the other regions, specify it as seen in the example below, where "AP" (Asia) is used.
NSDictionary *settings = @{SettingsStationNameKey : @"MOBILEFM",
SettingsBroadcasterKey : @"Triton Digital",
SettingsMountKey : @"MOBILEFM_AACV2",
SettingsPlayerServicesRegion: @"AP", // AP = Asia | EU = Europe | Omit this configuration option for North America
};
self.tritonPlayer = [[TritonPlayer alloc] initWithDelegate:self andSettings:settings];
...
[self.tritonPlayer play];
Autoplay
For measurement reasons, as well as user experience, the use of auto-play is strongly discouraged. Autoplay is defined as the station/stream playing without any user interaction to initiate the play. If you do implement an autoplay strategy, you need to add the autoplay = 1
value to the SettingsStreamParamsExtraKey
object when calling the play
function on the SDK.
NSDictionary *settings = @{SettingsStationNameKey : @"MOBILEFM",
SettingsBroadcasterKey : @"Triton Digital",
SettingsMountKey : @"MOBILEFM_AACV2",
SettingsEnableLocationTrackingKey : @(YES),
SettingsStreamParamsExtraKey : @{@"autoplay": @"1",
@"age": @"30"}
};
self.tritonPlayer = [[TritonPlayer alloc] initWithDelegate:self andSettings:settings];
...
[self.tritonPlayer play];
Playing a Station
Stream functionality is provided by the TritonPlayer
class. In order to be able to play, you must provide the settings for your station; at a minimum, provide the station and broadcaster's name and the mount. HLS mounts are supported. Contact Triton Digital if you don't have this information. See the API Reference for other available settings.
NSDictionary *settings = @{SettingsStationNameKey : @"MOBILEFM",
SettingsBroadcasterKey : @"Triton Digital",
SettingsMountKey : @"MOBILEFM_AACV2",
SettingsDebouncingKey: @(0.75) // optional debouncing for the Play action, in seconds : default value is 0.2
};
self.tritonPlayer = [[TritonPlayer alloc] initWithDelegate:self andSettings:settings];
...
[self.tritonPlayer play];
Changing Station
When changing stations, you need to provide the settings for the new station. Use the method -updateSettings:
to configure this. It will override the previous settings but will only be effective next time the player stops and plays again.
// Stop previous stream
[self.tritonPlayer stop];
...
// Configure and play the new station
NSDictionary *settings = @{SettingsStationNameKey : @"WMSC_S01",
SettingsBroadcasterKey : @"Triton Digital",
SettingsMountKey : @"WMSC_S01AAC"
};
[self.tritonPlayer updateSettings:settings];
[self.tritonPlayer play];
Alternatively, you can recreate the TritonPlayer every time you change stations, but the procedure above is preferred.
Change Podcast Playback Speed
To change the playback speed of a podcast, use changePlaybackRate
with a float value as the speed argument.
Example:
(void)setPlaybackRate:{
[self.tritonPlayer changePlaybackRate:1.5];
}
...would change the playback to 1.5 times the original speed.
Stream While Muted
You can configure the behaviour of the stream while the player is muted.
SettingsStreamWhileMuted
(Object). Required: No.
Use this object to enable or disable the stream continuing to play when the user mutes the audio. The default is NO.
Options:
NO
- Disabled (stream stops when muted)YES
- Enabled (stream continues when muted, but the user does not hear audio)
Code example:
NSDictionary *settings = @{SettingsStationNameKey : @"MOBILEFM",
SettingsBroadcasterKey : @"Triton Digital",
SettingsMountKey : @"MOBILEFM_AACV2",
SettingsStreamWhileMuted: @(NO) //Steam will be stopped when muted.
};
self.tritonPlayer = [[TritonPlayer alloc] initWithDelegate:self andSettings:settings];
...
[self.tritonPlayer play];
Target Audience for Audio Ads
In order to target your audience for audio ads (and respective companion banners), you must pass targeting parameters to the TritonPlayer's settings. Suppose you want to target males, 30 years old, and provide their location coordinates:
NSDictionary *settings = @{SettingsStationNameKey : @"MOBILEFM",
SettingsBroadcasterKey : @"Triton Digital",
SettingsMountKey : @"MOBILEFM_AACV2",
SettingsEnableLocationTrackingKey : @(YES),
SettingsStreamParamsExtraKey : @{@"gender": @"m",
@"age": @"30"}
};
self.tritonPlayer = [[TritonPlayer alloc] initWithDelegate:self andSettings:settings];
...
[self.tritonPlayer play];
When SettingsEnableLocationTrackingKey
is YES, it will use CLLocationManager
to provide the user's location (See "Location Tracking"). The other parameters (including manual location) are specified in a dictionary in the SettingsStreamParamsExtraKey
. For all available targeting parameters see the Triton Digital Streaming Guide.
You can add DMP Segment headers (as described in the Advertising Technical Specification) for live streaming, podcast, and on-demand by adding the following to the player settings (using examples from Permutive and Adobe DMPs):
SettingsDmpHeadersKey : @{@"permutive": @[@1234,@5679], @"adobe": @[@4321,@8765]},
For example:
NSDictionary *settings = @{SettingsStationNameKey : @"MOBILEFM",
SettingsBroadcasterKey : @"Triton Digital",
SettingsMountKey : @"MOBILEFM_AACV2",
SettingsDmpHeadersKey : @{@"permutive": @[@1234,@5679], @"adobe": @[@4321,@8765]},
SettingsDebouncingKey: @(0.75) // optional debouncing for the Play action, in seconds : default value is 0.2
};
self.tritonPlayer = [[TritonPlayer alloc] initWithDelegate:self andSettings:settings];
...
[self.tritonPlayer play];
Token Authorization (self signed)
In order for re-creation of the tokens on reconnect to work, either of the following parameters are required:
StreamParamExtraAuthorizationSecretKey
StreamParamExtraAuthorizationKeyId
If all of the parameters are filled in, then you don't have to generate the token yourself (although you can if you want to).
// Create the targeting parameters
NSDictionary *targetingParams = @{@"gender": @"m",
@"age": @"30"
};
// Create the authorization token
NSString *token = [TDAuthUtils createJWTTokenWithSecretKey:@"MySecretKey"
andSecretKeyId:@"MySecretKeyId" andRegisteredUser:YES andUserId:@"foo@bar.com" andTargetingParameters:targetingParams];
// Create the player settings.
NSDictionary *settings = @{SettingsStationNameKey : @"BASIC_CONFIG",
SettingsBroadcasterKey : @"Triton Digital",
SettingsMountKey : self.playerViewController.mountName,
SettingsEnableLocationTrackingKey : @(YES),
SettingsStreamParamsExtraKey : @{@"banners": @"300x50,320x50"},
SettingsTtagKey : @[@"mobile:ios", @"triton:sample"],
StreamParamExtraAuthorizationSecretKey: @"4ToEMVkOK1sThhsw",
StreamParamExtraAuthorizationUserId: @"",
StreamParamExtraAuthorizationKeyId: @"DG83J",
StreamParamExtraAuthorizationRegisteredUser: @(YES),
};
[self.tritonPlayer updateSettings:settings];
}
// Create the player.
self.tritonPlayer = [[TritonPlayer alloc] initWithDelegate:self andSettings:settings];
[self.tritonPlayer play];
Receive Stream Metadata (Cue Points)
Once the player is streaming, it is capable of receiving cue points with stream metadata (e.g., current playing song, ad metadata, etc.). To receive cue points, you need to implement TritonPlayerDelegate's -player:didReceiveCuePointEvent:
in the class that will be the TritonPlayer's delegate. CuePointEvent.h
defines all the constants for cue point types and keys for retrieving its information.
@interface ViewController() <TritonPlayerDelegate>
@end
@implementation ViewController
...
- (void)viewDidLoad {
[super viewDidLoad];
...
self.tritonPlayer = [[TritonPlayer alloc] initWithDelegate:self andSettings:settings];
}
...
[self.tritonPlayer play];
...
- (void)player:(TritonPlayer *)player didReceiveCuePointEvent:(CuePointEvent *)cuePointEvent {
// Check if it's an ad or track cue point
if ([cuePointEvent.type isEqualToString:EventTypeAd]) {
// Handle ad information (ex. pass to TDBannerView to render companion banner)
} else if ([cuePointEvent.type isEqualToString:EventTypeTrack]) {
NSString *currentSongTitle = [inNowPlayingEvent.data objectForKey:CommonCueTitleKey];
NSString *currentArtistName = [inNowPlayingEvent.data objectForKey:TrackArtistNameKey];
NSString *currentAlbumName = [inNowPlayingEvent.data objectForKey:TrackAlbumNameKey];
// Do something with track data (update interface, notify user etc.)
}
}
...
@end
Display an In-stream Companion Banner (Sync Banner)
@interface ViewController() <TritonPlayerDelegate>
@property (strong, nonatomic) TDSyncBannerView *adBannerView;
@end
@implementation ViewController
...
- (void)viewDidLoad {
[super viewDidLoad];
...
self.tritonPlayer = [[TritonPlayer alloc] initWithDelegate:self andSettings:settings];
// Create and configure a 320x50 sync banner with a fallback size of 300x50
self.adBannerView = [[TDSyncBannerView alloc] initWithWidth:320 andHeight:50 andFallbackWidth:300 andFallbackHeight:50];
[self.view addSubview:self.adBannerView];
}
...
- (void)player:(TritonPlayer *)player didReceiveCuePointEvent:(CuePointEvent *)cuePointEvent {
if ([cuePointEvent.type isEqualToString:EventTypeAd]) {
[self.adBannerView loadCuePoint:cuePointEvent];
}
...
}
...
Display an Interstitial Ad
Interstitial ads (pre-rolls, mid-rolls) are full-screen ads that are displayed modally in an app. Usually they are displayed at natural app transition points such as before or after playing or changing a radio station.
// Create a TDAdRequestBuilder to build the request string
TDAdRequestURLBuilder *request = [TDAdRequestURLBuilder builderWithHostURL:kRequestUrl];
request.stationId = 12345;
// Create a TDInterstitialAd
self.interstitial = [[TDInterstitialAd alloc] init];
// Create a TDAdLoader to load the ad from the request
self.adLoader = [[TDAdLoader alloc] init];
[self.adLoader loadAdWithBuilder:requestBuilder completionHandler:^(TDAd *loadedAd, NSError *error) {
if (error) {
// Handle error
} else {
// Load the ad into the interstitial
[self.videoInterstitial loadAd:loadedAd];
}
}
];
Once the interstitial is loaded, it must be displayed at the appropriate time. The application must check if the interstitial is loaded before attempting to show it. If -loaded
doesn't return YES, the ad won't be displayed. When showing an interstitial, a view controller must be passed. It will be the presenting view controller of the interstitial.
- (void)playStation {
if ([self.interstitial loaded]) {
[self.interstitial presentFromViewController:self];
}
// Rest of method logic
}
You can add an optional countdown timer to be displayed on an interstitial ad. To do this, enable the CountdownDisplay
property as shown in the video interstitial example below:
// Create a TDAdRequestBuilder to build the request string
TDAdRequestURLBuilder *request = [TDAdRequestURLBuilder builderWithHostURL:kRequestUrl];
request.stationId = 12345;
// Create a TDInterstitialAd
self.videoInterstitial = [[TDInterstitialAd alloc] init];
self.videoInterstitial.enableCountdownDisplay = TRUE;
// Create a TDAdLoader to load the ad from the request
self.adLoader = [[TDAdLoader alloc] init];
[self.adLoader loadAdWithBuilder:requestBuilder completionHandler:^(TDAd *loadedAd, NSError *error) {
if (error) {
// Handle error
} else {
// Load the ad into the interstitial
[self.videoInterstitial loadAd:loadedAd];
}
}
];
You can add DMP Segment headers (as described in the Advertising Technical Specification) to interstitial ads as follows (using examples from Permutive and Adobe DMPs):
requestBuilder.dmpSegments = @{@"permutive": @[@1234,@5679], @"adobe": @[@4321,@8765]}
For example:
// Create a TDAdRequestBuilder to build the request string
TDAdRequestURLBuilder *requestBuilder = [TDAdRequestURLBuilder builderWithHostURL:kRequestUrl];
//Add DMP Segments
requestBuilder.dmpSegments = @{@"permutive": @[@1234,@5679], @"adobe": @[@4321,@8765]};
requestBuilder.stationId = 12345;
// Create a TDInterstitialAd
self.interstitial = [[TDInterstitialAd alloc] init];
// Create a TDAdLoader to load the ad from the request
self.adLoader = [[TDAdLoader alloc] init];
[self.adLoader loadAdWithBuilder:requestBuilder completionHandler:^(TDAd *loadedAd, NSError *error) {
if (error) {
// Handle error
} else {
// Load the ad into the interstitial
[self.videoInterstitial loadAd:loadedAd];
}
}
];
Custom TTags – Player
Custom TTags (e.g., mobile:ford
) can be applied to streaming URLs by adding an array to the settings parameter SettingsTtagKey
.
Custom TTags – Player Example
NSDictionary *settings = @{SettingsStationNameKey : @"MOBILEFM",
SettingsBroadcasterKey : @"Triton Digital",
SettingsTtagKey : @[@"mobile:ios",@"chips:salsa"],
SettingsMountKey : @"MOBILEFM_AACV2"
};
self.tritonPlayer = [[TritonPlayer alloc] initWithDelegate:self andSettings:settings];
...
[self.tritonPlayer play];
Custom TTags – Interstitial Ad
Custom TTags (e.g., mobile: ford
) can be applied to interstitial ad URLs by adding the NSArray TTags on the TDAdRequestURLBuilder
object.
Custom TTags – Interstitial Ad Example
// Create a TDAdRequestBuilder to build the request string
TDAdRequestURLBuilder *request = [TDAdRequestURLBuilder builderWithHostURL:kRequestUrl];
request.stationId = 12345;
request.TTags = @[ "mobile:ios", "cola:diet" ];
// Create a TDInterstitialAd
self.interstitial = [[TDInterstitialAd alloc] init];
// Create a TDAdLoader to load the ad from the request
self.adLoader = [[TDAdLoader alloc] init];
[self.adLoader loadAdWithBuilder:requestBuilder completionHandler:^(TDAd *loadedAd, NSError *error) {
if (error) {
// Handle error
} else {
// Load the ad into the interstitial
[self.videoInterstitial loadAd:loadedAd];
}
}
];
Multi-listener ID
Provides a way to send multiple user or device identifiers, in addition to the main listener ID (lsid
parameter). The latter is still used by Triton for frequency capping, measurement etc., while the other IDs can be provided to third-party demand platforms in order to improve monetization.
The values for StreamParamExtraListenerIdType
are:
ppid
idfa
gaid
app
The value for StreamParamExtraListenerIdValue
can be whatever you decide.
Example:
NSDictionary *settings = @{SettingsStationNameKey : @"BASIC_CONFIG",
SettingsBroadcasterKey : @"Triton Digital",
SettingsMountKey : @"TRITONRADIOMUSIC",
SettingsEnableLocationTrackingKey : @(YES),
SettingsStreamParamsExtraKey : @{@"banners": @"300x50,320x50"},
SettingsTtagKey : @[@"mobile:ios", @"triton:sample"],
StreamParamExtraListenerIdType: @"idfa",
StreamParamExtraListenerIdValue: @"triton-app-id",
};
[self.tritonPlayer updateSettings:settings];
[self.tritonPlayer play];
Low Delay and Adaptive Buffering
When set to -1 / AUTO MODE
the SDK uses a small (two second) buffer window on initial connection, reducing the amount of delay between playback and real-time. (This is useful for sporting events, live contests, etc.)
Because the connection has a small buffer window, if there is network congestion or low bandwidth the buffer will increase by a factor of two if the device cannot maintain proper connection.
When set to a value greater than zero (>0
) the SDK will buffer that many seconds of audio before beginning playback.
Use SettingsLowDelayKey
with an NSNumber object for this feature. Valid values: -1
(AUTO mode), 0
(Disabled), 2
to 60
seconds.
By default the feature is disabled ( 0
).
iOS Low Delay Example
NSNumber *delayValue = [NSNumbernumberWithInt:2];
NSDictionary *settings = @{SettingsStationNameKey : @"MOBILEFM",
SettingsBroadcasterKey : @"Triton Digital",
SettingsLowDelayKey : delayValue,
SettingsMountKey : @"MOBILEFM_AACV2"
};
self.tritonPlayer = [[TritonPlayer alloc] initWithDelegate:self andSettings:settings];
...
[self.tritonPlayer play];
Receiving Now Playing History Information
TDCuePointHistory
is used for accessing Now Playing History information from Triton Servers. It returns a list of CuePointEvents
for a specific mount. It also allows the specification of filters and limiting the maximum number of elements returned.
@property (strong, nonatomic) TDCuePointHistory *cuePointHistory;
...
NSString *mount = @"MOBILEFM_AACV2";
NSInteger maxItems = 20;
NSArray *filter = @[EventTypeTrack, EventTypeAd];
// Request the history list from the server. The result will be a NSArray of CuePointEvent objects.
[self.cuePointHistory requestHistoryForMount:mount withMaximumItems:maxItems eventTypeFilter:filter completionHandler:^(NSArray *historyItems, NSError *error) {
if (error) {
// Handle the error
}
// Process the cue point list. Ex. display them in a UITableView
self.cuePointList = historyItems;
[self.tableView reloadData];
...
}];
Timeshift
For more information about Timeshift Radio, see the Streaming Specification.
To use Timeshift, you need to use a mount that is Timeshift enabled.
NSDictionary *settings = @{SettingsStationNameKey : @"BASIC_CONFIG",
SettingsBroadcasterKey : @"Triton Digital",
SettingsMountKey : TRITONRADIOMUSICAAC_RW,
SettingsEnableLocationTrackingKey : @(YES),
SettingsTtagKey : @[@"mobile:ios", @"triton:sample"],
StreamParamExtraListenerIdType: @"idfa",
StreamParamExtraListenerIdValue: @"triton-app-id",
};
Seek Function (forward or backward):
Add or remove time from the currentPlaybackTime.
To seek forward use a positive NSTimeInterval.
To seek backward use a negative NSTimeInterval.
[self.tritonPlayer seekToTimeInterval:self.tritonPlayer.currentPlaybackTime - 30.0];
Example:
//Seek forward
self.playerViewController.forwardFiredBlock = ^(UIButton *button) {
[self.tritonPlayer seekToTimeInterval:self.tritonPlayer.currentPlaybackTime + 10.0];
};
Seek To Live:
To return to the live stream use seekToLive
. This will stop the Timeshift stream and connect again to the live stream.
[self.tritonPlayer seekToLive]
Get Cloud Stream Info:
To get the cloud stream info, call the getCloudStreamInfo
method and implement the didReceiveCloudStreamInfoEvent
from the TritonPlayerDelegate to receive the callback. Note that for this to work, the Timeshift stream had to play. We are working on a solution that will allow this at any time.
self.playerViewController.getCloudStreamInfoFiredBlock = ^(UIButton *button) {
[self.tritonPlayer getCloudStreamInfo];
};
- (void)player:(TritonPlayer *)player didReceiveCloudStreamInfoEvent:(NSDictionary *)cloudStreamInfoEvent {
NSObject *programs = [cloudStreamInfoEvent valueForKey:@"programs"];
if([programs isKindOfClass:[NSDictionary class]]){
NSObject *properties = [(NSDictionary *)programs valueForKey:@"properties"];
NSString *title = [(NSDictionary *)properties valueForKey:@"program_title"];
dispatch_async(dispatch_get_main_queue(), ^{
self.playerViewController.btnTimeshiftProgram.enabled = YES;
self.playerViewController.btnTimeshiftProgram.hidden = NO;
[self.playerViewController.btnTimeshiftProgram setTitle:title forState:UIControlStateNormal];
self.cloudProgramId = [(NSDictionary *)programs valueForKey:@"program_episode_id"];
});
} else {
dispatch_async(dispatch_get_main_queue(), ^{
self.playerViewController.btnTimeshiftProgram.enabled = NO;
self.playerViewController.btnTimeshiftProgram.hidden = NO;
[self.playerViewController.btnTimeshiftProgram setTitle:@"No Programs" forState:UIControlStateNormal];
});
}
}
Play a Program:
To play a specific program, call playCloudProgram
with the program_episode_id
as the parameter.
self.playerViewController.timeshiftProgramFiredBlock = ^(UIButton *button) {
[self.tritonPlayer playCloudProgram:self.cloudProgramId];
};
Dist Parameter
To use the dist
parameter with Timeshift you need to add both timeshifting parameters:
SettingsStreamParamsExtraKey : @{StreamParamExtraDist:@"the-dist",
StreamParamExtraDistTimeshift:@"timeshift-dist”}
The
StreamParamExtraDist:@"the-dist",
parameter is used when the stream is connected in live mode.The
StreamParamExtraDistTimeshift:@"timeshift-dist”,
parameter is used when the stream is in Timeshift mode.
Below is an example of how to add the parameters:
NSDictionary *settings = @{SettingsStationNameKey : @"MOBILEFM",
SettingsBroadcasterKey : @"Triton Digital",
SettingsMountKey : @"MOBILEFM_AACV2",
SettingsStreamParamsExtraKey : @{
StreamParamExtraDist:@"the-dist",
StreamParamExtraDistTimeshift:@"timeshift-dist"
},
};
self.tritonPlayer = [[TritonPlayer alloc] initWithDelegate:self andSettings:settings];
...
[self.tritonPlayer play];