4
votes

I would like to know how to send video from an m3u8 URL from my iOS app to play on my TV through Google ChromeCast. The playlist contains a bunch of 'ts' URLs. Right now I have:

- (void)deviceManager:(GCKDeviceManager *)deviceManager
didConnectToCastApplication:(GCKApplicationMetadata *)applicationMetadata
                  sessionID:(NSString *)sessionID
        launchedApplication:(BOOL)launchedApp
{

  _gcChannel                   = [[GCKMediaControlChannel alloc] init];
  _gcChannel.delegate          = self;
  [deviceManager    addChannel: _gcChannel];
  GCKMediaMetadata *metadata   = [[GCKMediaMetadata alloc] init];
  NSTimeInterval    startTime  = 0;
  [metadata setString:@"Stream it" forKey:kGCKMetadataKeyTitle];

  GCKMediaInformation *mediaInformation = [[GCKMediaInformation alloc] initWithContentID:URLTOM3U8 streamType:GCKMediaStreamTypeUnknown contentType:@"video/m3u8" metadata:metadata streamDuration:0 customData:nil];

  [_gcChannel loadMedia:mediaInformation autoplay:YES playPosition:startTime];

.htaccess is set to:

<Files "wp-config.php">
    Order allow,deny
    Deny from all
    Header set Access-Control-Allow-Origin "*"
</Files>

When I stream from my iOS device to chromeCast, I see on the TV the www.myURL.com/Cast/mpl.html page, only it is filled out with:

Media Player State: 'underflow true'
Media Host State 'fatal error code = 3'
Media Protocol ' HLS'
.....
License Server URL:
Manifest Credentials: false
Segment Credentials: false
License Credentials: false

My mpl.html comes from https://github.com/googlecast/CastMediaPlayerStreamingDRM and then I copied and pasted from Google's website example: https://google-developers.appspot.com/cast/docs/player?hl=id

<!DOCTYPE html>
<html>
<head>
<META HTTP-EQUIV="CACHE-CONTROL" CONTENT="NO-CACHE">
<META HTTP-EQUIV="PRAGMA" CONTENT="NO-CACHE">
<title>Sample Receiver with Media Player Library for DASH/SS/HLS Streaming with DRMs</title>
<!--
    Cast APIs
-->
<script type="text/javascript" src="//www.gstatic.com/cast/sdk/libs/receiver/2.0.0/cast_receiver.js"></script>
<!--
    Cast Media Library
-->
<script type="text/javascript" src="//www.gstatic.com/cast/sdk/libs/mediaplayer/0.7.0/media_player.js"></script>
<script type="text/javascript" src="mpl.js"></script>

<style>
    body {
        overflow:hidden;
    }
    video {
        height:auto;
        width:100%;
        text-align: center;
        border:0px solid silver;
        display: block;
        vertical-align: middle;
        color: #FFFFFF;
        background-color: #000000;
        font-weight: bold;
        font-family: Verdana, Geneva, sans-serif;
        font-size:40px;
        float:left;
        z-index: 1;
        position:absolute;
    }
    #messages {
        color: #FFFFFF;
        float: left;
        top:10px;
        left:20px;
        margin-left: 5px;
        margin-top:  5px;
        z-index:2;
        position:absolute;
        font-weight: bold;
        font-size: 90%;
        width:95%;
        background-color: rgba(0,0,0,0.5);
        opacity:0.6;
    }

    #messages span {
        font-weight: normal;
    }
</style>
</head>
<body>
<div id="messages">
  <div style="font-size:140%; font-weight:bold; margin-left:0px;" id="title">Sample Receiver with Media Player Library for DASH/SS/HLS Streaming with DRMs</div>
  <div>App State: <span id="applicationState">-</span></div>
  <div>Sender Count: <span id="senderCount">0</span></div>
  <div>Media Element State: <span  id="mediaElementState">-</span></div>
  <div>Volume State: <span  id="volumeMessage">Starting volume, unchanged at 0.5</span></div>
  <hr>
  <div>Cast Receiver Manager Message: <span  id="castReceiverManagerMessage">-</span></div>
  <hr>
  <div>Media Manager Message: <span  id="mediaManagerMessage">-</span></div>
  <hr>
  <div>Message Bus Message: <span  id="messageBusMessage">-</span></div>
  <hr>
  <div style="font-size:110%;font-weight:bold;">Media Player Library: Player - Host - Protocol</div>
  <div>Media Player State: <span id="mediaPlayerState">-</span></div>
  <div>Media Host State: <span id="mediaHostState">-</span></div>
  <div>Media Protocol: <span id="mediaProtocol">-</span></div>
  <div>Stream Count: <span id="streamCount"></span></div>
  <div>Video Stream Index: <span id="videoStreamIndex"></span></div>
  <div>Video Codecs: <span id="streamVideoCodecs"></span></div>
  <div>Video Bitrates: <span id="streamVideoBitrates"></span></div>
  <div>Video Bitrates Index: <span id="videoQualityIndex"></span></div>
  <div>Video Quality Bandwidth: <span id="streamVideoQuality"></span></div>
  <div>Audio Stream Index: <span id="audioStreamIndex"></span></div>
  <div>Audio Codecs: <span id="streamAudioCodecs"></span></div>
  <div>Audio Bitrates: <span id="streamAudioBitrates"></span></div>
  <div>Audio Bitrates Index: <span id="audioQualityIndex"></span></div>
  <div>Audio Quality Bandwidth: <span id="streamAudioQuality"></span></div>
  <div>Captions: <span id="captions"></span></div>
  <div>License Server URL: <span id="licenseUrl"></span></div>
  <div>Manifest Credentials: <span id="manifestCredentials">false</span></div>
  <div>Segment Credentials: <span id="segmentCredentials">false</span></div>
  <div>License Credentials: <span id="licenseCredentials">false</span></div>
</div>
<video id="vid" style="height:95%; width:100%;"></video>


<script type="text/javascript">
window.onload = function() 
{
if (window.location.href.indexOf('Debug=true') != -1) 
{
  cast.receiver.logger.setLevelValue(cast.receiver.LoggerLevel.DEBUG);
  cast.player.api.setLoggerLevel(cast.player.api.LoggerLevel.DEBUG);
}

var mediaElement = document.getElementById('vid');


window.mediaManager = new cast.receiver.MediaManager(mediaElement);

window.defaultOnLoad = mediaManager.onLoad;
mediaManager.onLoad = function (event) 
{
  if (window.player !== null) 
  {
    player.unload();    // Must unload before starting again.
    window.player = null;
  }

if (event.data['media'] && event.data['media']['contentId']) 
{
  console.log('Starting media application');
  var url = event.data['media']['contentId'];

  window.host = new cast.player.api.Host(
    {'mediaElement':mediaElement, 'url':url});
  var ext = url.substring(url.lastIndexOf('.'), url.length);
  var initStart = event.data['media']['currentTime'] || 0;
  var autoplay = event.data['autoplay'] || true;
  var protocol = null;
  mediaElement.autoplay = autoplay;  // Make sure autoplay get's set
  if (url.lastIndexOf('.m3u8') >= 0) 
  {
    // HTTP Live Streaming
    protocol = cast.player.api.CreateHlsStreamingProtocol(host);
  } else if (url.lastIndexOf('.mpd') >= 0) 
  {
    // MPEG-DASH
    protocol = cast.player.api.CreateDashStreamingProtocol(host);
  } else if (url.indexOf('.ism/') >= 0) {
// Smooth Streaming
    protocol = cast.player.api.CreateSmoothStreamingProtocol(host);
  }

  host.onError = function(errorCode) {
    console.log("Fatal Error - "+errorCode);
    if (window.player) {
      window.player.unload();
      window.player = null;
    }
  };
  host.updateSegmentRequestInfo = function(requestInfo) 
  {
    requestInfo.withCredentials = true;
  };
  console.log("we have protocol "+ext);
  if (protocol !== null) 
  {
    console.log("Starting Media Player Library");
    window.player = new cast.player.api.Player(host);
    window.player.load(protocol, initStart);
  }
  else 
  {
    window.defaultOnLoad(event);    // do the default process
  }
}
}
window.player = null;
console.log('Application is ready, starting system');
window.castReceiverManager = cast.receiver.CastReceiverManager.getInstance();
castReceiverManager.start();
};
</script>

</body>
</html>
1
What receiver are you using? What does the receiver log show? Have you setup the CORS?Ali Naddaf
Hi, I'm using a custom receiver. I set the URL in the cast.google.com/publish to www.myURL/Cast/mpl.html. I set CORS by editting .htaccess to Header set Access-Control-Allow-Origin "*". When running from www.myURL/Cast/index.html the log just says 'launching app'. I am also hosted by 'godaddy' on a shared server so i don't know if/when my .htaccess changes would take effect if/when they restart the apache server, per the advice here: enable-cors.org/server_apache.htmluser1709076
The log in myURL.com/Cast/index.html just says "launching app".user1709076

1 Answers

2
votes

Setting streamType to GCKMediaStreamTypeNone and contentType to "video/m3u" worked for me with an HLS-compliant AVC/AAC stream using the default receiver:

GCKMediaInformation *mediaInformation =
      [[GCKMediaInformation alloc] initWithContentID:
              @"https://example.com/path/to/playlist.m3u8"
                                          streamType:GCKMediaStreamTypeNone
                                         contentType:@"video/m3u"
                                            metadata:metadata
                                      streamDuration:0
                                          customData:nil];