You can implement your own content resolvers based on the default resolvers.
When TVSDK detects a new opportunity, it iterates through the registered content resolvers looking for one that is capable of resolving that opportunity. The first one that returns true is selected for resolving the opportunity. If no content resolver is capable, then that opportunity is skipped. Because the content resolving process is usually asynchronous, the content resolver is responsible for notifying when the process has completed.
Create a custom AdvertisingFactory
instance and override createContentResolver
.
For example:
new AdvertisingFactory() {
...
@Override
public ContentResolver createContentResolver(MediaPlayerItem item) {
Metadata metadata = _mediaPlayer.getCurrentItem().getResource().getMetadata();
if (metadata != null) {
if (metadata.containsKey(DefaultMetadataKeys.AUDITUDE_METADATA_KEY.getValue())) {
return new AuditudeResolver(getActivity().getApplicationContext());
} else if (metadata.containsKey(DefaultMetadataKeys.JSON_METADATA_KEY.getValue())) {
return new MetadataResolver();
} else if (metadata.containsKey(DefaultMetadataKeys.TIME_RANGES_METADATA_KEY.getValue())) {
return new CustomAdMarkersContentResolver();
} else if (metadata.containsKey(CustomAdResolver.CUSTOM_METADATA_KEY)) {
return new CustomAdResolver();
}
}
return null;
}
...
}
Register the ad client factory to the MediaPlayer
.
For example:
// register the custom advertising factory with media player
advertisingFactory = createCustomAdvertisingFactory();
mediaPlayer.registerAdClientFactory(advertisingFactory);
Pass an AdvertisingMetadata
object to TVSDK as follows:
AdvertisingMetadata
object and MetadataNode
object.AdvertisingMetadata
object to MetadataNode
.MetadataNode result = new MetadataNode();
result.setNode(DefaultMetadataKeys.ADVERTISING_METADATA.getValue(),
advertisingMetadata);
Create a custom ad resolver class that extends the ContentResolver
class.
In the custom ad resolver, override this protected function:
void doResolveAds(Metadata metadata,
PlacementOpportunity placementOpportunity)
Metadata contains your AdvertisingMetada
. Use it for the following TimelineOperation
vector generation.
For each placement opportunity, create a Vector<TimelineOperation>
.
The vector can be empty, but not null.
This sample TimelineOperation
provides a structure for AdBreakPlacement
:
AdBreakPlacement(AdBreak.createAdBreak(
ads, // Vector<Ad>
time, // Ad Break start time. Note: local time on the timeline
duration, // Ad Break duration
tag() // An arbitrary string value that can be attached to
// the AdBreak object.
), placementInformation // Retrieved from PlacementOpportunity
)
After ads are resolved, call one of the following functions:
notifyResolveComplete(Vector<TimelineOperation> proposals)
notifyResolveError(Error error)
For example, if it fails:
Metadata metadata = new MetadataNode();
metadata.setValue("NATIVE_ERROR_CODE", exception.getCause().toString());
error.setMetadata(metadata);
This sample custom ad resolver makes an HTTP request to the ad server and receives a JSON response.
public class CustomAdResolver extends ContentResolver {
...
@Override
protected void doResolveAds(Metadata metadata, PlacementOpportunity placementOpportunity) {
...
if (resolveSuccess == true) {
notifyResolveComplete(Vector<TimelineOperation> proposals);
}
else {
notifyResolveError(Error error);
}
}
...
}
Sample JSON ad server response for a live stream:
{
"response": {
"breaks": [ {
"start": 0,
"ads": [ {
"id": 1001,
"primary_asset": {
"url": "https://venkat-test.s3.amazonaws.com/ads/geico/playlist.m3u8",
"duration": 30000,
"id": "asset1",
"resource_type": ""
},
"companion_assets": {
}
}
] },
{
"start": -1,
"ads": [ {
"id": 1003,
"primary_asset": {
"url": "https://venkat-test.s3.amazonaws.com/ads/priceline/playlist.m3u8",
"duration": 30000,
"id": "asset3",
"resource_type": ""
},
"companion_assets": {
}
} ]
} ]
}
}
Sample JSON ad server response for VOD:
{
"response": {
"breaks": [ {
"start": 0,
"ads": [ {
"id": 1001,
"primary_asset": {
"url": "https://venkat-test.s3.amazonaws.com/ads/geico/playlist.m3u8",
"duration": 30000,
"id": "asset1",
"resource_type": ""
},
"companion_assets": {
}
},
{
"id": 1002,
"primary_asset": {
"url": "https://venkat-test.s3.amazonaws.com/ads/crescent/playlist.m3u8",
"duration": 15000,
"id": "asset2",
"resource_type": ""
},
"companion_assets": {
}
} ]
},
{
"start": 50000,
"ads": [ {
"id": 1003,
"primary_asset": {
"url": "https://venkat-test.s3.amazonaws.com/ads/priceline/playlist.m3u8",
"duration": 30000,
"id": "asset3",
"resource_type": ""
},
"companion_assets": {
}
} ]
},
{
"start": 100000000,
"ads": [ {
"id": 1004,
"primary_asset": {
"url": "https://venkat-test.s3.amazonaws.com/ads/camry/playlist.m3u8",
"duration": 15000,
"id": "asset4",
"resource_type": ""
},
"companion_assets": {
}
} ]
} ]
}
}