首页 \ 问答 \ 使用Google Cast - 媒体播放器库创建自定义接收器(Creating a custom receiver with the Google Cast - Media Player Library)

使用Google Cast - 媒体播放器库创建自定义接收器(Creating a custom receiver with the Google Cast - Media Player Library)

我想为我的自定义接收器实现媒体播放器功能。 在谷歌开发者网站上,我找到了实现发件人样式媒体接收器应用程序的描述。

我做了这个样本,它工作正常。 我可以将Google云端硬盘上托管的MP3文件投射到我的chromecast设备上。

现在,我已经实现了一个自定义接收器(参见附件),该接收器应该能够播放指向m3u8文件的URL。 为此,我正在使用Google建议的媒体播放器库。

<body>
<div>
<p id='text'> </p>
<video id='vid'> </video>
</div>
<script type="text/javascript" src="https://www.gstatic.com/cast/sdk/libs/receiver/2.0.0/cast_receiver.js"></script>
<script type="text/javascript" src="https://www.gstatic.com/cast/sdk/libs/mediaplayer/1.0.0/media_player.js"></script>



<script type="text/javascript">
// If you set ?Debug=true in the URL, such as a different App ID in the
// developer console, include debugging information.
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);
}

console.log("mediaElement set");
var mediaElement = document.getElementById('vid');

// Create the media manager. This will handle all media messages by default.
window.mediaManager = new cast.receiver.MediaManager(mediaElement);

// Remember the default value for the Receiver onLoad, so this sample can Play
// non-adaptive media as well.
window.defaultOnLoad = mediaManager.onLoad;

mediaManager.onLoad = function (event) {
    // The Media Player Library requires that you call player unload between
    // different invocations.
    if (window.player !== null) {
        player.unload();    // Must unload before starting again.
        window.player = null;
    }
    // This trivial parser is by no means best practice, it shows how to access
    // event data, and uses the a string search of the suffix, rather than looking
    // at the MIME type which would be better.  In practice, you will know what
    // content you are serving while writing your player.


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


    var t = document.getElementById('text');
    t.innerHTML = event.data['media'];
    console.log("EventData: "+event.data);
    console.log("EventData-Media: "+event.data['media']);
    console.log("EventData-ContendID: "+event.data['media']['contentId']);

    var url = event.data['media']['contentId'];
    console.log("URL: "+url);

    // Create the Host - much of your interaction with the library uses the Host and
    // methods you provide to it.
    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

    protocol = cast.player.api.CreateHlsStreamingProtocol(host);

    host.onError = function(errorCode) {
      console.log("Fatal Error - "+errorCode);
      if (window.player) {
        window.player.unload();
        window.player = null;
      }
    };
    // If you need cookies, then set withCredentials = true also set any header
    // information you need.  If you don't need them, there can be some unexpected
    // effects by setting this value.
    //      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>

我已经想通了,可以使用Media Player Library转换.m3u8,.ism和.mpd文件。 所以我创建了一个如下的m3u8文件,将其托管到Google云端硬盘,并尝试将其投射到我的自定义接收器。

#EXTM3U
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=173952
https://www.googledrive.com/host/0B1x31lLRAxTMRndtNkhSWVdGLVE

但它不起作用。 我使用Goolge Cast Developer Console来调试自定义接收器。 通过排除

window.player.load(protocol, initStart);

命令,我在控制台上收到致命错误。

我认为问题在于自定义接收器代码,因为谷歌文档中的发件人应用程序与样式化的媒体接收器一起工作正常。

是否有人知道此问题或在自定义接收器代码上看到一些问题? 有谁知道如何调试风格的媒体播放器? 如果我能看到哪些消息与样式化的媒体播放器交换会更容易,但如果我激活调试我看不到交换的消息。


I would like to implement media player functionality to my custom receiver. On the google developer website, I found a description to implement a sender and a styled media receiver application.

I have done this sample, and it works fine. I can cast a MP3 file hosted on Google Drive to my chromecast device.

Now, I have implemented a custom receiver (see attachment) which should be able to play an URL refered to a m3u8 file. For this, I am using the Media Player Library as suggested from Google.

<body>
<div>
<p id='text'> </p>
<video id='vid'> </video>
</div>
<script type="text/javascript" src="https://www.gstatic.com/cast/sdk/libs/receiver/2.0.0/cast_receiver.js"></script>
<script type="text/javascript" src="https://www.gstatic.com/cast/sdk/libs/mediaplayer/1.0.0/media_player.js"></script>



<script type="text/javascript">
// If you set ?Debug=true in the URL, such as a different App ID in the
// developer console, include debugging information.
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);
}

console.log("mediaElement set");
var mediaElement = document.getElementById('vid');

// Create the media manager. This will handle all media messages by default.
window.mediaManager = new cast.receiver.MediaManager(mediaElement);

// Remember the default value for the Receiver onLoad, so this sample can Play
// non-adaptive media as well.
window.defaultOnLoad = mediaManager.onLoad;

mediaManager.onLoad = function (event) {
    // The Media Player Library requires that you call player unload between
    // different invocations.
    if (window.player !== null) {
        player.unload();    // Must unload before starting again.
        window.player = null;
    }
    // This trivial parser is by no means best practice, it shows how to access
    // event data, and uses the a string search of the suffix, rather than looking
    // at the MIME type which would be better.  In practice, you will know what
    // content you are serving while writing your player.


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


    var t = document.getElementById('text');
    t.innerHTML = event.data['media'];
    console.log("EventData: "+event.data);
    console.log("EventData-Media: "+event.data['media']);
    console.log("EventData-ContendID: "+event.data['media']['contentId']);

    var url = event.data['media']['contentId'];
    console.log("URL: "+url);

    // Create the Host - much of your interaction with the library uses the Host and
    // methods you provide to it.
    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

    protocol = cast.player.api.CreateHlsStreamingProtocol(host);

    host.onError = function(errorCode) {
      console.log("Fatal Error - "+errorCode);
      if (window.player) {
        window.player.unload();
        window.player = null;
      }
    };
    // If you need cookies, then set withCredentials = true also set any header
    // information you need.  If you don't need them, there can be some unexpected
    // effects by setting this value.
    //      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>

I've figured out, that it's just possible to cast .m3u8, .ism and .mpd files with the Media Player Library. So I created a m3u8 file as follows, host it to Google Drive, and tried to cast it to my custom receiver.

#EXTM3U
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=173952
https://www.googledrive.com/host/0B1x31lLRAxTMRndtNkhSWVdGLVE

But it doesn't works. I used the Goolge Cast Developer Console to debug the custom receiver. By exceuting the

window.player.load(protocol, initStart);

command, I get an FATAL ERROR on the console.

I think the problem is on the custom receiver code because the sender application from the google documentation works fine with the styled media receiver.

Is there anyone who know this problem or see some issue on the custom receiver code? Has anyone a idea how I could debug the styled media player? It would be much easier if I could see which messages are exchanged with the styled media player but if I activate the debugging I can´t see the exchanged messages.


原文:https://stackoverflow.com/questions/26911309
更新时间:2022-10-16 12:10

最满意答案

我认为问题出在Pair方法中。 当你这样做:

this.rates.get(new Pair(from, to));

您正在创建Pair的新实例,这与您在addRate方法中放入地图的addRate

如果您希望代码正常工作,您必须使用Pair类的相同实例或在Pair类上正确实现equalshashCode方法。

以下是对HashMap内部工作的深入了解以及为使其工作所需做的工作: https//stackoverflow.com/a/6493946/2266098


I think the problem is in the Pair method. When you do this:

this.rates.get(new Pair(from, to));

you are creating a new instance of Pair, which is not the same as the one you've put into the map in the addRate method.

If you want the code to work correctly, you either have to use the same instance of Pair class or correctly implement equals and hashCode method on Pair class.

Here's a bit deeper insight into the inner working on HashMap and what you have to do to make it work: https://stackoverflow.com/a/6493946/2266098

相关问答

更多
  • 正在比较的字符串可能包含空格,换行符,换行符。 正如我们之前所怀疑的那样,你的输入文件train.txt尾随空格,导致地图查找失败。 除此之外,您的Java代码还有许多冗余代码块。 我把它清理干净了。 这是您修改后的代码: import java.io.*; import java.util.*; public class ExampleClass1 { public static void main(String[] args) throws IOException { Scann ...
  • 我认为问题出在Pair方法中。 当你这样做: this.rates.get(new Pair(from, to)); 您正在创建Pair的新实例,这与您在addRate方法中放入地图的addRate 。 如果您希望代码正常工作,您必须使用Pair类的相同实例或在Pair类上正确实现equals和hashCode方法。 以下是对HashMap内部工作的深入了解以及为使其工作所需做的工作: https : //stackoverflow.com/a/6493946/2266098 I think the pro ...
  • false表示哈希表不包含提供的密钥。 需要另一种方式来表明您提供了无效密钥。 您总是可以将HashTable.Contains包装在另一个执行null检查(或捕获异常)的方法中,并在这种情况下返回false 。 false means that the hash table doesn't contain the key supplied. There needs to be another way of indicating that you've supplied an invalid key. Yo ...
  • “id”和“name”在JSON对象内部,对着“rikeard”键。 所以你需要进行如下更改: JSONParser parser = new JSONParser(); try { Object obj = parser.parse(datJ); JSONObject jsonObject = (JSONObject) obj; JSONObject rikeardObject = (JSONObject) obj.get("rikeard"); String name = ...
  • 您的代码中有许多错误。 我在第一次阅读时看到的最明显的是: 在map的实现中比较字符串与equals not == 在将其放入地图之前,请勿在名称末尾添加空格 我对您的代码的主要建议是学习开发单元测试并编写代码。 在这种情况下,你应该有一些测试表明HashEntry在HashTable中使用它之前会做你期望的事情,在你继续从文件中读取值并将它们放在地图中之前,还应该对它进行彻底的测试。 或者,如果您使用模拟,则可以以相反的顺序执行此操作。 但是试着在最后进行测试会让人更难以知道出了什么问题。 学习构建单元测 ...
  • 我认为问题是,如果sometimesPopulated alwaysPopulated值中的任何一个为空或者alwaysPopulated值中的任何一个为空,则从compareTo返回1。 请记住, compareTo可以被认为是返回减法运算的值而你的不是传递的。 (a - b)即使在a = = b时也可以==(b - a)。 如果aKey sometimesPopulated aKey不是空白而本地sometimesPopulated aKey是空白的,我会返回-1。 如果它们是相同的那么我会对alway ...
  • 如果您使用的是EntityFrameworkCore,则必须使用eager-loading。 在LocationAppService覆盖此方法: protected override IQueryable CreateFilteredQuery(LocationGetAllInput input) { return Repository.GetAllIncluding(x => x.LocationManager); } If you are using EntityFrame ...
  • 最简单的方法是使用-notcontains每个哈希表所具有的两组密钥之一的补码: function Process-Roles { param( [hashtable]$MasterRoles, [hashtable]$SlaveRoles ) # Complement to slave roles (those ONLY in $MasterRoles) $MasterRoles.Keys |Where-Object { $SlaveRol ...
  • 您尚未初始化您的Hashtable : - static Hashtable callfunc; // Reference points to null 当put()的参数都不为null时 您应该使用允许1 null key HashMap ,以避免在使用带有null key put时获取NPE ,该方法在Hashtable情况下抛出NPE ,因为它不允许使用null keys, or value 。 因此,将您的声明更改为: - static Hashtable
  • 尝试 for (String key : table.values()) { System.out.println("Keyvalues " + key.toString()); String value = key.toString(); myStringArray =ArrayUtils.addAll(myStringArray, value); } 要么 int cnt=0; for (String key : table.values()) { S ...

相关文章

更多

最新问答

更多
  • 获取MVC 4使用的DisplayMode后缀(Get the DisplayMode Suffix being used by MVC 4)
  • 如何通过引用返回对象?(How is returning an object by reference possible?)
  • 矩阵如何存储在内存中?(How are matrices stored in memory?)
  • 每个请求的Java新会话?(Java New Session For Each Request?)
  • css:浮动div中重叠的标题h1(css: overlapping headlines h1 in floated divs)
  • 无论图像如何,Caffe预测同一类(Caffe predicts same class regardless of image)
  • xcode语法颜色编码解释?(xcode syntax color coding explained?)
  • 在Access 2010 Runtime中使用Office 2000校对工具(Use Office 2000 proofing tools in Access 2010 Runtime)
  • 从单独的Web主机将图像传输到服务器上(Getting images onto server from separate web host)
  • 从旧版本复制文件并保留它们(旧/新版本)(Copy a file from old revision and keep both of them (old / new revision))
  • 西安哪有PLC可控制编程的培训
  • 在Entity Framework中选择基类(Select base class in Entity Framework)
  • 在Android中出现错误“数据集和渲染器应该不为null,并且应该具有相同数量的系列”(Error “Dataset and renderer should be not null and should have the same number of series” in Android)
  • 电脑二级VF有什么用
  • Datamapper Ruby如何添加Hook方法(Datamapper Ruby How to add Hook Method)
  • 金华英语角.
  • 手机软件如何制作
  • 用于Android webview中图像保存的上下文菜单(Context Menu for Image Saving in an Android webview)
  • 注意:未定义的偏移量:PHP(Notice: Undefined offset: PHP)
  • 如何读R中的大数据集[复制](How to read large dataset in R [duplicate])
  • Unity 5 Heighmap与地形宽度/地形长度的分辨率关系?(Unity 5 Heighmap Resolution relationship to terrain width / terrain length?)
  • 如何通知PipedOutputStream线程写入最后一个字节的PipedInputStream线程?(How to notify PipedInputStream thread that PipedOutputStream thread has written last byte?)
  • python的访问器方法有哪些
  • DeviceNetworkInformation:哪个是哪个?(DeviceNetworkInformation: Which is which?)
  • 在Ruby中对组合进行排序(Sorting a combination in Ruby)
  • 网站开发的流程?
  • 使用Zend Framework 2中的JOIN sql检索数据(Retrieve data using JOIN sql in Zend Framework 2)
  • 条带格式类型格式模式编号无法正常工作(Stripes format type format pattern number not working properly)
  • 透明度错误IE11(Transparency bug IE11)
  • linux的基本操作命令。。。