Ad breaks

The CAF Receiver SDK supports embedding ads within a given media stream.

A break is an interval for playback of one or more ads; each ad is called a break clip. This diagram shows two ad breaks, each with two ads:

CAF Receiver SDK provides two ways to incorporate ad breaks to the receiver: client-side and server-side stitching.

Client-side ad stitching

In client-side stitching, you need to specify the necessary media information for your ad clips by adding a break to the receiver when the media is being loaded. The following snippet is an example of the previous diagram, where third_party is part of your library.

/**
 * @param {!cast.framework.messages.MediaInformation} media
 */
function addBreakToMedia(media) {
  media.breakClips = [
  {
    id: 'bc1',
    title: thirdparty.getBreakClipTitle(),
    contentId: thirdparty.getBreakClipUrl(),
    contentType: thirdparty.getBreakClipContentType(),
    posterUrl: thirdparty.getBreakClipPosterUrl(),
    whenSkippable: 10
  },
  {
    id: 'bc2'
    ...
  },
  {
    id: 'bc3'
    ...
  }];
  media.breaks = [
  {
    id: 'b1',
    breakClipIds: ['bc1', 'bc2'],
    position: thirdparty.getBreakClipPosition()
  },
  {
    id: 'b2',
    breakClipIds: ['bc1', 'bc3'],
    position: thirdparty.getBreakClipPosition()
  }];
}

const context = cast.framework.CastReceiverContext.getInstance();
const castPlayer = context.getPlayerManager();
castPlayer.setMessageInterceptor(
    cast.framework.messages.MessageType.LOAD,
    request => {
      addBreakToMedia(request.media);
      return request;
    });
context.start();

Server-side ad stitching

In server-side stitching, the server is expected to provide a single stream that contains both the primary media and ads. In this case, you are expected to provide the duration of the break clip instead of the URL and content type of the break clip, and set isEmbedded to true.

Note that the isEmbedded boolean is used to identify whether client or server-side stitching should be used. By default, CAF will use client-side stitching if the variable is not provided.

/**
 * @param {!cast.framework.messages.MediaInformation} media
 */
function addBreakToMedia(media) {
  media.breakClips = [
  {
    id: 'bc1',
    title: thirdparty.getBreakClipTitle(1),
    contentId: thirdparty.getBreakClipUrl(1),
    contentType: thirdparty.getBreakClipContentType(1),
    posterUrl: thirdparty.getBreakClipPosterUrl(1),
    duration: thirdparty.getBreakClipDuration(1)
  },
  {
    id: 'bc2'
    ...
  },
  {
    id: 'bc3'
    ...
  }];
  media.breaks = [
  {
    id: 'b1',
    breakClipIds: ['bc1', 'bc2'],
    position: thirdparty.getBreakPosition(1),
    isEmbedded: true
  },
  {
    id: 'b2',
    breakClipIds: ['bc1', 'bc3'],
    position: thirdparty.getBreakPosition(2),
    isEmbedded: true
  }];
}

const context = cast.framework.CastReceiverContext.getInstance();
const castPlayer = context.getPlayerManager();
castPlayer.setMessageInterceptor(
    cast.framework.messages.MessageType.LOAD,
    request => {
      addBreakToMedia(request.media);
      return request;
    });
context.start();

While the ad is playing, the receiver will also send a MediaStatus that contains information about the ad break to the sender, which it can use to render its UI and to block the seek operation.