【问题标题】:Chromecast custom CAF receiverChromecast 定制 CAF 接收器
【发布时间】:2018-08-07 15:13:15
【问题描述】:

我遇到了新的 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 进入缓冲阶段,但停在那里。永远不会触发带有“加载成功”日志的承诺。

【问题讨论】:

    标签: javascript chromecast google-cast google-cast-sdk caf-receiver-sdk


    【解决方案1】:

    我设法用假的 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);
    

    【讨论】:

    【解决方案2】:

    YouTube iframe 播放器不是为 Cast 接收器而设计的。

    【讨论】:

    • 有没有办法挂钩到 Cast 接收器的状态,以允许更多自定义媒体,使用新的 CAF 接收器框架打开实际自定义 cast 接收器?
    猜你喜欢
    • 2019-01-03
    • 1970-01-01
    • 2020-05-03
    • 2018-08-16
    • 2018-10-29
    • 2020-06-02
    • 2014-10-04
    • 2014-12-25
    相关资源
    最近更新 更多