Google Cast(Chromecast)浏览器 SDK 学习笔记(一)

前几天因为京东打折,买了个索尼的 SRS-X77 音箱,看说明书说支持 Google Cast,试了试感觉还挺好用,于是研究了一下 Google Cast 的 SDK。

Chromecast、Google Cast 傻傻分不清楚?

Google 在 2013 年推出了一个叫 Chromecast 的硬件,它运行一个精简版的 Chrome OS,用户可以使用手机或者电脑(Chrome 浏览器)来控制它播放网络或者本地的视频、照片等。Google 随之发布了适用于 iOS、Android 和 Chrome 浏览器的 SDK。2015 年,Google 又发布了 Chromecast Audio,它没有 HDMI 接口,只能播放音频。Google 给Chromecast 使用的这套技术命名为 Google Cast。

也就是说, Chromecast 是 Google 推出的硬件产品的名称,Google Cast 指的是是这套通过网络播放媒体技术,比如对应苹果的 AirPlay。除了 Chromecast 系列硬件本身,Android TV 也支持作为 Google Cast 的接收端,此外,索尼、LG 等厂商也制造了一些支持 Google Cast 的音响系统,当然也就包含了我买的索尼 SRS-X 系列。

Google Cast 大致工作原理

发送端 app(sender app)使用 SDK,将需要播放的媒体的信息发送到 Google 的服务器,服务器再通知接收端播放(所以发送端和接收端必须都可以访问 Google 的服务器才行)。接收端运行的是一个浏览器,它会根据发送端的app ID和媒体信息,去载入对应的一个网页这个网页(receiver app)也是由发送端 app 的开发者提供的,的将会负责播放相应的媒体内容。即使接收端时 Chromecast Audio 之类只能播放音频的硬件,这个网页也是会载入并渲染的。

Google Cast 和 DLNA 或者苹果的 AirPlay 不同之处,一是依赖 Google 的服务器,也就是说必须连接到 Internet 才可以用,如果只有一个局域网是不行的。二是前两个的接收端播放器接收端本身提供的,开发者只需要提供要播放的内容就可以,但是 Google Cast 则是需要提供自己的receiver app,这样的好处是开发者可以高度定制(比如可以定制UI,或者加入弹幕、歌词滚动、音乐可视化之类复杂功能),虽然接收端往往运行的并不是Android这样的开放操作系统,但是因为receiver app的本质是网页,所以开发难度并不高。

不过,如果你不需要定制化的receiver app,Google也提供了一套默认的receiver app,拥有最基本的音视频播放的功能。

当然,以上只是根据我对 Google 的文档的理解总结的,如果有什么错误请指出。

Google Cast 一些概念的介绍

  • 发送端(sender)
    可以是Chrome 浏览器(电脑版或者 Android 版)、Android 设备、iOS 设备。

  • 发送端 app(sender app)
    使用了 Google Cast SDK 的 app,可以是 web app(网页)也可以是 Android 或 iOS app。

  • 接收端(receiver)
    支持作为接收端的硬件,如Chromecast、机顶盒、音箱、电视之类。

  • 接收端 app(receiver app)
    接收端上运行的 app,由 sender 指定的 app ID 决定,其本质是网页,接收端上的浏览器将其载入并执行。

  • session
    Sender 首先要跟特定的 receiver 建立 session 才能相互通信。建立 session 对于用户来说就是“设备配对”的过程。

  • media
    Session 建立后,Sender 可以使用 session 的 loadMedia 方法来告诉 receiver 播放媒体。如果 loadMedia 成功,Sender 会获得一个 media 对象。该对象反映了receiver app正在播放的媒体,其中包含了播放状态,播放队列等信息。

使用 SDK 制作一个简单的 sender app

下面我们跟着官方教程,用 Chrome 浏览器的 SDK(Javascript)制作一个简单的 sender app。因为注册 app ID 要交五美元所以我就直接使用默认的 receiver app 了。

引入 SDK

当然第一步就是在页面中引入 SDK:


SDK使用了chrome.cast这个namespace。

初始化:

function onError(error) {
  console.log(error);
}

function onInitSuccess() {
  console.log('API successfully initialized');
}

function initializeCastApi() {
  const appID = chrome.cast.media.DEFAULT_MEDIA_RECEIVER_APP_ID;
  const sessionRequest = new chrome.cast.SessionRequest(applicationID);
  const apiConfig = new chrome.cast.ApiConfig(sessionRequest,
    sessionListener,
    receiverListener);
  chrome.cast.initialize(apiConfig, onInitSuccess, onError);
};

window['__onGCastApiAvailable'] = function(loaded, errorInfo) {
  if (loaded) {
    console.log('API available');
    initializeCastApi();
  } else {
    console.log(errorInfo);
  }
}

我们需要监听__onGCastApiAvailable这个自定义事件,来执行 initializeCastApiinitializeCastApi 需要知道我们的 app ID(如果使用默认的 receiver app 则使用 chrome.cast.media.DEFAULT_MEDIA_RECEIVER_APP_ID 这个常量。sessionListenerreceiverListener 是什么呢?下面说。

receiverListener 就是当receiver的状态发生改变的时候触发的回调函数。Google Cast 使用 mDNS 协议来实现设备发现,当有receiver被发现或者消失的时候,这个函数想会被触发。比如我们定义一个这样的 receiverListener

let receiverIsAvailable = false;
function receiverListener(receiverAvailability) {
  console.log(`Receiver is ${receiverAvailability}`);
  receiverIsAvailable = (receiverAvailability === chrome.cast.ReceiverAvailability.AVAILABLE);
}

一开始我的音箱处于关机状态,刷新页面,控制台显示:

然后我把音箱打开,并连接到网络,此时控制台显示:

可见 receiverListener 的调用是实时的,但是这个函数并不知道有几个 receivers,更不知道 receivers 的具体信息——其唯一参数是一个字符串 unavailable 或者 available,将其与 chrome.cast.ReceiverAvailability.AVAILABLE 常量比较来确定是否available。

sessionListener 是当存在 session 的时候调用的函数。当我们第一次初始化页面的时候,还没有建立 session,所以这个函数并没有被调用,但是如果我们已经建立了 session,那么再次刷新这个页面时,SDK 便会发现已经存在的 session 并调用这个函数。在这个函数中我们可以把 session 存储起来,供以后调用:

let currentSession = null;

function sessionListener(session) {
  currentSession = session;
  console.log('Current session updated');
}

建立 session(设备配对)

function onRequestSessionSuccess(session){
  console.log(session);
  currentSession = session;
  console.log('Current session updated');
}

function requestSession(){
  if(!currentSession){
    chrome.cast.requestSession(onRequestSessionSuccess, onError);
  }
}

设备配对需要客户端主动执行,比如我们可以在页面上放一个按钮,用户按下的时候就执行 requestSession。执行后我们可以看到 Chrome 弹出设备列表,这个列表是 Chrome 浏览器本身提供的:

可以看到我的音箱已经跟 Google Play Music 配对了,不过我们需要它跟目前的页面配对,点击音箱名称,然后点击“投射”,音箱就会跟 Play Music 断开然后跟我们这个页面建立 session。

如果建立 session 成功就会调用 onRequestSessionSuccess,这个函数跟前面说的 sessionListener 是差不多的。

把 session 打印出来,是这样的:

可以看到 session 是由 sender app 和 receiver 决定的,只有我们建立了 session 才能得到具体的 receiver(之前我们只知道 receiver 是否 avilable,不知道 receiver 有哪些),可以知道 receiver 能支持音频还是视频等。当我们再次载入页面的时候,因为 appId 相同,所以初始化阶段就可以触发 sessionListener 我们可以这时就获得 session 而不需要再进行 requestSession 的操作了。注意我的音箱之前跟 Google Play Music 之前有一个 session 但是并没有触发我的页面的 sessionListener,因为 appId 不同。

播放媒体

现在有了 session,我们终于可以命令 receiver 播放媒体了!

let currentMedia = null;

function onMediaDiscovered(how, media) {
  currentMedia = media;
}

function loadMedia(){
  const mediaInfo = new chrome.cast.media.MediaInfo('http://example.com/example.mp3');
  const request = new chrome.cast.media.LoadRequest(mediaInfo);
  session.loadMedia(request,
    onMediaDiscovered.bind(this, 'loadMedia'),
    onError);
}

执行完 loadMedia 不一会,应该就可以听到音箱发出声音了✌️。

返回的 media 对象可以用来控制播放:

currentMedia.pause();
currentMedia.play();
currentMedia.stop();

你可能感兴趣的:(智能电视,chrome,chromecast)