8

I'm trying to stream some URLs to my Chromecast through a sender app. They're HLS/m3u8 URLs.

Here's one such example URL: https://qa-apache-php7.dev.kaltura.com/p/1091/sp/109100/playManifest/entryId/0_wifqaipd/protocol/https/format/applehttp/flavorIds/0_h65mfj7f,0_3flmvnwc,0_m131krws,0_5407xm9j/a.m3u8

However they never seem to load on the Chromecast, despite other HLS/m3u8 URLs working (example of an HLS stream that does work).

It's not related to CORS as they indeed have the proper CORS headers.

I notice they have separate audio groups in the root HLS manifest file.

When I hook it up to a custom receiver app, I get the following logs:

enter image description here

The relevant bits being (I think): Neither ID3 nor ADTS header was found at 0 and cast.player.api.ErrorCode.NETWORK/315 (which I believe is a result of the first)

These are perfectly valid/working HLS URLs. They play back in Safari on iOS and desktop perfectly, as well as VLC.

Is there something I need to be doing (either in my sender app or my receiver app) to enable something like the audio tracks? The docs seem to indicate something about that.

I also found this Google issue where a person had a similar issue, but solved it somehow that I can't understand. https://issuetracker.google.com/u/1/issues/112277373

How would I playback this URL on Chromecast properly? Am I to do something in code?

Doug Smith
  • 27,683
  • 54
  • 189
  • 363

2 Answers2

7

This already has a solution here but I will add this answer in case someone looks up the exact error message / code.

The problem lies in the hlsSegmentFormat which is initialized to TS for multiplexed segments but currently defaults to packed audio for HLS with alternate audio tracks.

The solution is to intercept the CAF LOAD request and set the correct segment format:

const context = cast.framework.CastReceiverContext.getInstance();
const playerManager = context.getPlayerManager();
// intercept the LOAD request
playerManager.setMessageInterceptor(cast.framework.messages.MessageType.LOAD, loadRequestData => {
            loadRequestData.media.hlsSegmentFormat = cast.framework.messages.HlsSegmentFormat.TS;
            return loadRequestData;
});
context.start();


Source: Google Cast issue tracker

aergistal
  • 26,033
  • 5
  • 60
  • 82
  • What's the equivalent in JAVA? I need to do this in an app, but I could not find a way to access the player neither set a message interceptor. – raphaelbgr Mar 12 '21 at 18:53
1

For those who manage multiple video sources in various formats and who don't want to arbitrarily force the HLS fragment format to TS, I suggest to track the error and set a flag that force the format at the next retry (by default, the receiver tries 3 times before giving up).

First, have a global flag to enable the HLS segments format override:

setHlsSegmentFormat = false;

Then detect the error:

playerManager.addEventListener(cast.framework.events.EventType.ERROR, 
  event => {
    if (event.detailedErrorCode == cast.framework.events.DetailedErrorCode.HLS_NETWORK_INVALID_SEGMENT) {
      // Failed parsing HLS fragments. Will retry with HLS segments format set to 'TS'
      setHlsSegmentFormat = true;
    }
  }
);

Finally, handle the flag when intercepting the playback request:

playerManager.setMediaPlaybackInfoHandler(
  (loadRequest, playbackConfig) => {
    if (setHlsSegmentFormat) {
      loadRequest.media.hlsSegmentFormat = cast.framework.messages.HlsSegmentFormat.TS;
      // clear the flag to not force the format for subsequent playback requests
      setHlsSegmentFormat = false;
    }
  }
);

The playback will quickly fail the first time and will succeed at the next attempt. The loading time is a bit longer but the HLS segment format is only set when required.

Aurelien
  • 51
  • 4