1
votes

I ran the sample custom receiver. I am running it using ngrok but i see in the console that its not connecting to web socket. Any help is appreciated: Here is my receiver code and screenshot

const context = cast.framework.CastReceiverContext.getInstance();
const playerManager = context.getPlayerManager();


const playbackConfig = new cast.framework.PlaybackConfig();
// Customize the license url for playback
playbackConfig.licenseUrl = 'https://wv-keyos.licensekeyserver.com/';
playbackConfig.protectionSystem = cast.framework.ContentProtection.WIDEVINE;
playbackConfig.licenseRequestHandler = requestInfo => {
  requestInfo.withCredentials = true;
  requestInfo.headers = {
    'customdata': '<custom data>'
  };
};


// Update playback config licenseUrl according to provided value in load request.
context.getPlayerManager().setMediaPlaybackInfoHandler((loadRequest, playbackConfig) => {
  if (loadRequest.media.customData && loadRequest.media.customData.licenseUrl) {
    playbackConfig.licenseUrl = loadRequest.media.customData.licenseUrl;
  }
  return playbackConfig;
});


function makeRequest (method, url) {
  return new Promise(function (resolve, reject) {
    var xhr = new XMLHttpRequest();
    xhr.open(method, url);
    xhr.onload = function () {
      if (this.status >= 200 && this.status < 300) {
        resolve(JSON.parse(xhr.response));
      } else {
        reject({
          status: this.status,
          statusText: xhr.statusText
        });
      }
    };
    xhr.onerror = function () {
      reject({
        status: this.status,
        statusText: xhr.statusText
      });
    };
    xhr.send();
  });
}

playerManager.setMessageInterceptor(
  cast.framework.messages.MessageType.LOAD,
  request => {
    castDebugLogger.info('MyAPP.LOG', 'Intercepting LOAD request');

    if (request.media && request.media.entity) {
      request.media.contentId = request.media.entity;
    }

    return new Promise((resolve, reject) => {

      if(request.media.contentType == 'video/mp4') {
        return resolve(request);
      }

      // Fetch content repository by requested contentId
      makeRequest('GET', 'https://tse-summit.firebaseio.com/content.json?orderBy=%22$key%22&equalTo=%22'+ request.media.contentId + '%22')
        .then(function (data) {
          var item = data[request.media.contentId];
          if(!item) {
            // Content could not be found in repository
            castDebugLogger.error('MyAPP.LOG', 'Content not found');
            reject();
          } else {
            // Adjusting request to make requested content playable
            request.media.contentId = item.stream.hls;
            request.media.contentType = 'application/x-mpegurl';
            castDebugLogger.warn('MyAPP.LOG', 'Playable URL:', request.media.contentId);

            // Add metadata
            var metadata = new cast.framework.messages.MovieMediaMetadata();
            metadata.metadataType = cast.framework.messages.MetadataType.MOVIE;
            metadata.title = item.title;
            metadata.subtitle = item.author;

            request.media.metadata = metadata;
            resolve(request);
          }
      });
    });
  });

/** Debug Logger **/
const castDebugLogger = cast.debug.CastDebugLogger.getInstance();

// Enable debug logger and show a warning on receiver
// NOTE: make sure it is disabled on production
castDebugLogger.setEnabled(true);

playerManager.addEventListener(
  cast.framework.events.category.CORE,
  event => {
      castDebugLogger.info('ANALYTICS', 'CORE EVENT:', event);
});

// Set verbosity level for custom tags
castDebugLogger.loggerLevelByTags = {
  'MyAPP.LOG': cast.framework.LoggerLevel.WARNING,
  'ANALYTICS': cast.framework.LoggerLevel.INFO,
};

/** Optimizing for smart displays **/
const playerData = new cast.framework.ui.PlayerData();
const playerDataBinder = new cast.framework.ui.PlayerDataBinder(playerData);
const touchControls = cast.framework.ui.Controls.getInstance();

let browseItems = getBrwoseItems();

function getBrwoseItems() {
  let data = '"video": { \
    "author": "The Blender Project", \
    "description": "Grumpy Bunny is grumpy", \
    "poster": "https://storage.googleapis.com/tse-summit.appspot.com/bbb/poster.png", \
    "prog": "https://storage.googleapis.com/tse-summit.appspot.com/bbb/bbb-prog.mp4", \
    "stream": { \
      "dash": "https://d8dbsji255dut.cloudfront.net/drm-test/4K-Gaming-Sample.mpd", \
      "hls": "https://d8dbsji255dut.cloudfront.net/drm-test/4K-Gaming-Sample.m3u8" \
    }, \
    "title": "Big Buck Bunny" \
  }';


  let browseItems = [];

  for (let key in data) {
    let item = new cast.framework.ui.BrowseItem();
    item.entity = key;
    item.title = data[key].title;
    item.subtitle = data[key].description;
    item.image = new cast.framework.messages.Image(data[key].poster);
    item.imageType = cast.framework.ui.BrowseImageType.MOVIE;
    browseItems.push(item);
  }
  return browseItems;
}

let browseContent = new cast.framework.ui.BrowseContent();
browseContent.title = 'Up Next';
browseContent.items = browseItems;
browseContent.targetAspectRatio =
  cast.framework.ui.BrowseImageAspectRatio.LANDSCAPE_16_TO_9;

playerDataBinder.addEventListener(
  cast.framework.ui.PlayerDataEventType.MEDIA_CHANGED,
  (e) => {
    if (!e.value) return;

    // Clear default buttons and re-assign
    touchControls.clearDefaultSlotAssignments();
    touchControls.assignButton(
      cast.framework.ui.ControlsSlot.SLOT_1,
      cast.framework.ui.ControlsButton.SEEK_BACKWARD_30
    );

    // Media browse
    touchControls.setBrowseContent(browseContent);
  });

// context.start({ touchScreenOptimizedApp: true });

context.start({playbackConfig: playbackConfig});


enter image description here

I have already registered for Google Cast SDK Developer Console and created a unpublished app and added my chrome cast device as well.

1

1 Answers

3
votes

You are seeing these errors because you are loading the receiver through a web browser directly. The usual flow of a cast session is that a "sender" (web browser, iOS device, android device) will initiate a cast session with the hosted receiver, and thereby beginning the socket connection. Right now, you only have a receiver loading, nothing has initiated the session.

One way to test this is to plug in a Chromecast or cast enabled device (most Android TV's have Chromecast built-in too!), and use a valid sender to connect to your receiver.


Google have built an awesome tool to help with Chromecast development, it's a shame it's not publicised more. You can find it here: https://casttool-1287.appspot.com/cactesttool/index.html

If you're wanting to really nail down your Chromecast development skills, I personally recommend that you checkout:

  1. Google Codelabs for Cast, these have some really helpful walkthroughs. https://codelabs.developers.google.com/?cat=Cast
  2. The Google Cast github repo, has some great examples. https://github.com/googlecast

Note: This is by no means a detailed explanation of how cast sessions are actually initiated, some very smart people have done some digging into how Chromecast sessions work, and if you're interested checkout Romain Picard's writeup at https://blog.oakbits.com/google-cast-protocol-overview.html