Skippability

Requesting and displaying skippable ads with the CAF DAI SDK is a bit of a complex task, because it requires identifying whether the combination of senders and receivers in use have the ability to display and interact with a skip button.

The SDK will automatically make best efforts to detect whether the current receiver has the ability to render and interact with a skip button directly. However, the publisher needs to determine whether any of the attached senders can display skippable ads, by toggling the imaRequestData.senderCanSkip attribute.

In all of the samples for the CAF DAI SDK, senderCanSkip is passed directly from the sender, as a part of the media object. This is a purposefully simplified implementation that works well for a single sender, but in real-world applications a CAF receiver may be attached to multiple sender apps, and the sender that queues a media file may no longer be connected when that media object is loaded and the stream request is made.

A more advanced receiver could keep track of which affiliated sender types support skipping, and which do not, and would check at load time to see if any skip-capable senders are currently attached to the receiver.

Example (single-sender):

...

    let getStreamRequest = (request) => {
      const imaRequestData = request.media.customData;
      let streamRequest = null;
      if (imaRequestData.assetKey) {
        // Live stream
        streamRequest = new google.ima.cast.dai.api.LiveStreamRequest();
        streamRequest.assetKey = imaRequestData.assetKey;
      } else if (imaRequestData.contentSourceId) {
        // VOD stream
        streamRequest = new google.ima.cast.dai.api.VODStreamRequest();
        streamRequest.contentSourceId = imaRequestData.contentSourceId;
        streamRequest.videoId = imaRequestData.videoId;
      }
      if (streamRequest && imarequestdata.ApiKey) {
        streamRequest.ApiKey = imarequestdata.ApiKey;
      }
      if (streamRequest && imarequestdata.senderCanSkip) {
        streamRequest.senderCanSkip = imaRequestData.senderCanSkip;
      }
      return streamRequest;
    };
...

Example (multi-sender support):

...

    let getStreamRequest = (request) => {
      const imaRequestData = request.media.customData;
      let streamRequest = null;
      if (imaRequestData.assetKey) {
        // Live stream
        streamRequest = new google.ima.cast.dai.api.LiveStreamRequest();
        streamRequest.assetKey = imaRequestData.assetKey;
      } else if (imaRequestData.contentSourceId) {
        // VOD stream
        streamRequest = new google.ima.cast.dai.api.VODStreamRequest();
        streamRequest.contentSourceId = imaRequestData.contentSourceId;
        streamRequest.videoId = imaRequestData.videoId;
      }
      if (streamRequest && imarequestdata.ApiKey) {
        streamRequest.ApiKey = imarequestdata.ApiKey;
      }

      let senders = castContext.getSenders();
      let senderCanSkip = (sender) => {
        const skippableUserAgents = [
          "iOS CastSDK",
          "Android CastSDK"
        ];
        // trim user agent to just include device
        let userAgent = sender.userAgent.explode(',')[0];
        return skippableUserAgents.includes(userAgent);
      };
      if (streamRequest && senders.some(senderCanSkip)) {
        streamRequest.senderCanSkip = imarequestdata.senderCanSkip;
      }
      return streamRequest;
    };

...

Ultimately, publishers are responsible for their users' experience, and since it is possible for all skippable senders to disconnect between when the stream request is made and when the ad is played, you may want to attach a handler to the STARTED event that will check if an ad is skippable and both the senders and receiver are unable to support skippability. That handler could automatically skip such ads, if they appear. Such an advanced implementation, however, is beyond the scope of CAF DAI support.

By default, if such an edge case occurs, the user is still technically able to initiate a skip, by first connecting a sender that supports skippability and then clicking the skip button that appears.