- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我在使用新的 CAF 接收器时遇到问题,无法将 YouTube iframe 播放器注册为播放器,但它正在播放。连接到接收器5分钟后,连接断开,因为它认为播放器空闲。
这是发件人代码
var metadata = new chrome.cast.media.GenericMediaMetadata();
metadata.title = "Foo - Bar";
metadata.image = 'https://img.youtube.com/vi/IXNrHusLXoM/mqdefault.jpg';
metadata.images = ['https://img.youtube.com/vi/IXNrHusLXoM/mqdefault.jpg'];
var mediaInfo = new chrome.cast.media.MediaInfo();
mediaInfo.contentType = "video/*";
mediaInfo.contentId ="IXNrHusLXoM";
mediaInfo.duration = 300;
var request = new chrome.cast.media.LoadRequest();
request.media = mediaInfo;
request.customData = customData;
request.metadata = metadata;
castSession.loadMedia(request).then(
function() {
console.log('Load succeed');
},
function(errorCode) {
console.log('Error code: ' + errorCode);
});
接收器代码可以在这里找到:https://github.com/zoff-music/zoff-chromecast-receiver/blob/feature/v3/receiver.js
有没有办法让新的 CAF 接收器挂接到 YouTube iframe 播放器,或者“手动”调度 LOADED、BUFFERING、PLAYING、PAUSED、STOPPED 事件,以便接收器不会与发送器断开连接?
编辑:使用上面的代码,PlayerState 到达 BUFFERING 阶段,但停在那里。带有日志“Load success”的 promise 永远不会被触发。
最佳答案
我设法用假的 mediaEelement 欺骗了接收者。可以看到代码in pastebin
const context = cast.framework.CastReceiverContext.getInstance();
const playerManager = context.getPlayerManager();
var yt_events = {};
var pause_request = false;
var yt_player;
var yt_video_fake = {
removeAttribute: function(attr) {
},
setAttribute: function(attr, val) {
},
getCurrentTimeSec: function() { return yt_player && yt_player.getCurrentTime ? yt_player.getCurrentTime() : 0; },
getDurationSec: function() { return yt_player ? yt_player.getDuration() : 0; },
getVolume: function() {
if(!yt_player || !yt_player.getVolume) {
return 0;
}
var volume = new cast.framework.messages.Volume();
volume.level = yt_player.getVolume() / 100;
volume.muted = yt_player.isMuted() ? true : false;
return volume;
},
setVolume: function(vol) { yt_player && yt_player.setVolume(vol.level * 100); },
getState: function() {
if(!yt_player || !yt_player.getPlayerState) {
return 'IDLE';
}
var state = yt_player.getPlayerState();
var _state;
if(pause_request) {
pause_request = false;
state = YT.PlayerState.PAUSED;
}
switch(state) {
default: case YT.PlayerState.UNSTARTED:
_state = 'IDLE';
break;
case YT.PlayerState.PLAYING:
_state = 'PLAYING';
break;
case YT.PlayerState.PAUSED:
_state = 'PAUSED';
break;
case YT.PlayerState.BUFFERING:
_state = 'BUFFERING';
break;
case YT.PlayerState.ENDED:
_state = 'ENDED';
break;
}
return _state;
},
addEventListener: function(e, func) { },
load: function() {},
play: function() { yt_player && yt_player.playVideo(); },
pause: function() { if(yt_player && yt_player.pauseVideo) {pause_request = true; yt_player.pauseVideo(); }},
seek: function(timeTo) { yt_player && yt_player.seekTo(timeTo, true);},
reset: function() {
if(yt_player) {
try { yt_player.destroy && yt_player.destroy(); } catch(e) {
//console.trace(e);
};
delete yt_player;
}
},
registerErrorCallback: function(func) { yt_events['error'] = func; },
registerEndedCallback: function(func) { yt_events['ended'] = func; },
registerLoadCallback: function(func) { yt_events['load'] = func; },
unregisterErrorCallback: function () { delete yt_events['error'] },
unregisterEndedCallback: function () { delete yt_events['ended']},
unregisterLoadCallback: function () { delete yt_events['load']}
};
Object.defineProperty(yt_video_fake, 'currentTime', {
val1: null,
get: function() { return yt_player && yt_player.getCurrentTime ? yt_player.getCurrentTime() : this.val1; },
set: function(newValue) {
yt_player && yt_player.seekTo(newValue, true);
this.val1 = newValue;
},
enumerable : true,
configurable : true
});
Object.defineProperty(yt_video_fake, 'volume', {
val1: null,
get: function() { var vol = this.getVolume(); if(vol) return vol['level']; return 1; },
set: function(newValue) {
yt_player && yt_player.setVolume && yt_player.setVolume(newValue * 100);
this.val1 = newValue;
},
enumerable : true,
configurable : true
});
Object.defineProperty(yt_video_fake, 'duration', {
val1: null,
get: function() { return this.getDurationSec(); },
set: function() {},
enumerable : true,
configurable : true
});
function YoutubePlayMedia(videoid) {
var yt_container = $('#yt_container');
if(!yt_container.length) {
yt_container = $('<div id="yt_container" style="position:absolute;top:0;left:0;width:100%;height:100%;"></div>');
$('body').append(yt_container);
}
yt_container.html('<iframe id="youtube_container" style="width:100%;height:100%;" frameborder="0" allowfullscreen="1" allow="autoplay; encrypted-media" title="YouTube video player" src="//www.youtube.com/embed/' + videoid +'?autoplay=1&enablejsapi=1&modestbranding=1&controls=0&fs=0&iv_load_policy=3&rel=0&cc_load_policy=1&cc_lang_pref=bg"></iframe>');
yt_player = new YT.Player('youtube_container', {
events: {
'onReady': function(e) {
yt_player.is_loaded = true;
yt_player.playVideo();
},
'onStateChange': function(e) {
switch(e.data) {
case YT.PlayerState.PLAYING:
if(yt_player.is_loaded) {
if(yt_events['load']) {
yt_events['load']();
}
}
break;
case YT.PlayerState.ENDED:
//yt_events['ended'] && yt_events['ended'](e);
break;
}
},
'onError': function(e) {
//yt_events['error'] && yt_events['error'](e);
}
}
});
}
function YoutubeLoadMedia(url) {
current_media_type = 'Youtube';
window.onYouTubeIframeAPIReady = function() {
window.youtube_loaded = true;
YoutubePlayMedia(url);
}
if(!window.youtube_script) {
window.youtube_script = document.createElement('script');
window.youtube_script.src = "https://www.youtube.com/iframe_api";
var firstScriptTag = document.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(window.youtube_script, firstScriptTag);
} else {
// Вече имаме api направо действаме
YoutubePlayMedia(url);
}
}
playerManager.setMessageInterceptor(
cast.framework.messages.MessageType.LOAD,
loadRequestData => {
if (loadRequestData.media && loadRequestData.media.contentId) {
YoutubeLoadMedia(loadRequestData.media.contentId);
playerManager.setMediaElement(yt_video_fake);
return false;
}
return loadRequestData;
}
);
const options = new cast.framework.CastReceiverOptions();
options.disableIdleTimeout = true;
context.start(options);
关于javascript - Chromecast 定制 CAF 接收器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49017723/
我想知道 Chromecast 支持哪些网络技术。我知道没有提到的完整列表 here但我实际上想要支持的列表和 performant特点。 它与普通的 Web 开发有什么不同? 是否有硬件加速、Web
我创建了一个 Android 发送器应用程序。它似乎不起作用,我想知道发生了什么,但我无法访问 http://RECEIVER-IP-ADDRESS:9222 。我已注册我的 chromecast 设
我已填写 Google 表单,以便将我的设备列入白名单,并已获得 AppID。 我已按照此处概述的步骤尝试调试设备,但没有成功: https://developers.google.com/cast/
我的自定义 Chromecast 接收器最初是在开发人员控制台中关闭“列表详细信息”的情况下发布的,因此它不会显示在 http://chromecast.com/apps 上。 .现在,我希望它被列出
我想启动 Chromecast 应用程序,但不使用 chrome 扩展程序或 iOS 或 Android。从命令行执行此操作。 我注意到您可以向 chromecast 发送 POST,它会启动一个应用
此 article解释“支持 Chromecast 的网站”的好处: Higher quality: Chromecast-enabled sites can serve high quality c
很高兴终于有时间尝试在我的 chromecast 上进行开发,但唉……似乎甚至无法开始。 我填写了白名单请求,收到了周五确认的电子邮件(正好 catch 周末!),然后我开始查看样本,并根据我发现的一
我尝试使用以下工作正常的代码将元数据从发送方发送到接收方。 const mediaInfo = new chrome.cast.media.MediaInfo(url, type); /* -----
我想制作 Chromecast 设备运行的接收器应用程序的屏幕截图。 我需要让它在设备上运行才能同时显示视频和应用程序。 有没有办法做到这一点 ? 最佳答案 Ali Naddaf 的回答在技术上是正确
有没有办法选择您自己的图像来自定义 Chromecast 屏幕保护程序? 或者我可以编写一个接收器应用程序来替换屏幕保护程序吗? 最佳答案 屏幕保护程序实际上是一个网页 ( https://clien
我正在尝试创建一个设备,让我可以指定 youtube 视频,以便从任意客户端通过 chromecast 播放。就我而言,客户端是在 Arduino 上运行的 CURL。 我很早就撞墙了。我看到 SDK
目前,您可以使用 Google 智能助理控制您的 chromecast 屏幕,例如询问 Google Home“OK Google,在客厅屏幕上显示来自 YouTube 的关于食物的视频”。但是你可以
我将 chromecast 支持集成到我的 Android 应用程序中。已发布(将状态更改为已发布)。然后我改为"is"部分 LISTING DETAILS Allow users to discov
有什么方法可以使用标准(桌面)Java 连接到 ChromeCast。我正在寻找一种自动化测试的方法,并希望我们的 CC:s 能够自动播放视频。 到目前为止我已经找到了这个项目: https://gi
我正在尝试使用 chrome 测试一些 chromecast 示例,但在我的 APP-ID 的可用接收器列表中看不到 chromecast。 这是我的情况, 我的 chromecast 设备已列入白名
文档说 Chromecast 使用的是“缩小版”的 Chrome 浏览器。是否有受支持的 HTML5 标记和受支持的 JavaScript DOM 操作的列表? 我喜欢用 HTML5 为 Chrome
使用 Host.processMetadata() 获取视频流中的 ID3 标签。它说这是一个 Uint8Array 但我不知道如何正确解码它。我在用: new TextDecoder("utf-8"
在播放音乐时,我尝试了几种不同的 css 动画来在屏幕上上下移动大图像。我没有发现任何导致平滑过渡的速度、距离转换等变化。 最佳答案 如果您查看 Chromecast Chrome 调试器的“时间轴”
我查看了 git 上的 chromecast 示例并查看了较旧的 v7 mediarouter examples其中包括“播放或排队”行为。从 chromecast 接口(interface)不清楚,
我在 Chrome Incognito 中运行 Chromecast 发件人时出错,或者如果未安装 Chromecast 扩展程序: Failed to load resource: net::ERR
我是一名优秀的程序员,十分优秀!