树莓派搭建 Google TV

出处:http://my.oschina.net/funnky/blog/142067


树莓派搭建 Google TV

目录:[ - ]

  • Google TV是啥玩意 ?
  • 搭建我们自己的Google TV
  • 最终效果
  • 步骤
  • 安装软件:
  • 安装Raspbian和NodeJS
  • 安装Chromium和Youtube-dl
  • shell命令及脚本
  • 搭建后台: NodeJS + Express + Socket.io
  • 添加Socket.io
  • 客户端处理Socket通信
  • 在Node服务器上执行Shell命令
  • 添加OMXControl – 可以控制OMXPlayer的Node模块
  • 汇总
  • 搭建前端
  • 总结
  • 树莓派搭建 Google TV_第1张图片

    Google TV是啥玩意 ?

    树莓派搭建 Google TV_第2张图片

    Google TV是支持自选图像、宽带网络、传统电视信号的综合平台,更附带电视节目搜索功能. 谷歌公布了其新版电视的两个版本, 第一个叫做Buddy Box, 由索尼代工的电视盒并且价格昂贵, 第二个是即将发布的集成电视, 将其电视盒内置到电视机内部.

    Google TV界面预览:

    树莓派搭建 Google TV_第3张图片

    开发者: 可以为Google TV开发新的网页应用或者把已有的android应用改为适配大尺寸屏幕, 在谷歌的开发者网站可以看到详细介绍

    搭建我们自己的Google TV

    极客们就是喜欢重复发明轮子, 并且自得其乐. 所以我们使用下列开源技术来搭建我们自己的Google TV:

    硬件:

    • 树莓派

    软件:

    • Raspbian系统 – 为树莓派特殊定制的Debian发行版
    • NodeJs
      • Socket.io – 通过websocket远程连接TV
      • Express – 用来处理一些基本的http请求
      • Omxcontrol – 用来控制树莓派上最棒的视频播放器OMXPlayer
    • Chromium浏览器
    • OMXPlayer
    • Youtube-dl – 一个下载youtube视频的脚本
    • QuoJS – 在手机网页上处理滑动手势
    • HTML5, CSS3, Javascript, 和Moustache模板引擎
    • Youtube API

    最终效果

    树莓派搭建 Google TV_第4张图片

    树莓派TV及其特殊的远程遥控器

     

    步骤

    主要分为4步:

    1. 安装软件
    2. shell命令及脚本
    3. 搭建后台: NodeJS + Express + Socket.io
    4. 搭建前端

    安装软件:

    安装Raspbian和NodeJS

    按照这篇教程在树莓派上安装Raspbian和Node Js

    安装Chromium和Youtube-dl

    安装Chromium浏览器

    1 sudo apt-get install chromium-browser

    为了显示效果更佳我们可以安装使用MC字体

    1 sudo apt-get install ttf-mscorefonts-installer

    安装并升级Youtube下载器

    1 sudo apt-get install youtube-dl
    2  
    3 sudo youtube-dl -U

    注意-1: 现在还无法在树莓派上用Chromium看youtube的视频, 因为在那种情况下视频并未通过GPU渲染, 会巨卡无比. Youtube-dl是不错的替代方案, 先将视频下载下来然后用OMXPlayer播放, 由于用GPU渲染了视频, 所以播放高清视频比较顺畅.

    注意-2: Raspbian上默认就装了OMXPlayer.

    shell命令及脚本

    如果你在用SSH连接树莓派, 你需要先添加个环境变量“DISPLAY=:0.0″, 执行以下命令

    1 export DISPLAY=:0.0

    执行以下命令可列出全部环境变量

    1 env

    在全屏模式下测试Chromium:

    1 chromium --kiosk http://www.google.com

    测试Youtube-dl

    1 youtube-dl youtube_video_url

    你可以给youtube-dl加几个参数, 比如添加“-o youtube ID [dot] the extension”会自动更改下载文件的名称,  “-f /22/18 ”可以强制下载视频的720p版本. 这里有完整的参数格式列表.

    1 youtube-dl  -o "%(id)s.%(ext)s" -f /22/18 youtube_video_url

    下载视频完成后, 用OMXPLayer来播放

    1 omxplayer youtube_video_file

    可以用键盘快捷键来暂停/恢复视频, 更多快捷键说明看这里

    太棒了! 下面就让我们用Node JS来自动化实现上面的整个过程

    搭建后台: NodeJS + Express + Socket.io

    下面是源码的目录结构:

    • public
      • js
      • css
      • images
      • fonts
      • index.html
      • remote.html
    • app.js
    • package.json

    Package.json – npm用来自动安装依赖的JSON文件, 并存储了一些基本信息

    1 { "name": "GoogleTV-rPi",
    2   "version": "0.0.1",
    3   "private": false,
    4   "scripts": { "start": "node app.js" },
    5   "dependencies": { "express": "3.1.1",
    6                     "socket.io":"0.9.14",
    7                     "omxcontrol":"*" }
    8 }

    在创建并修改文件之后, 在应用目录执行下列命令来安装依赖.

    1 npm install

    注意-3: 在安装依赖前会自动创建一个名为node_modules 的文件夹, 如果你使用git, 别忘了要创建一个.gitignore文件并把“ node_modules”写入其中, 在添加git项目时忽略这个文件夹.

    新建一个名为app.js的文件来创建我们的本地HTTP访问服务

    01 var express = require('express')
    02   , app = express() 
    03   , server = require('http').createServer(app)
    04   , path = require('path')
    05 // all environments
    06 app.set('port', process.env.TEST_PORT || 8080);
    07 app.use(express.favicon());
    08 app.use(express.logger('dev')); app.use(express.bodyParser());
    09 app.use(express.methodOverride());
    10 app.use(express.static(path.join(__dirname, 'public')));
    11 //Routes
    12 app.get('/', function (req, res) {
    13   res.sendfile(__dirname + '/public/index.html');
    14 });
    15  
    16 app.get('/remote', function (req, res) {
    17   res.sendfile(__dirname + '/public/remote.html');
    18 });
    19  
    20 server.listen(app.get('port'), function(){
    21   console.log('Express server listening on port ' + app.get('port'));
    22 });

    上面已经配置了本地访问的路径. 现在我们来测试一下搭建是否成功, 在public/目录中创建index.html和remote.html文件, 写入“Hello, World”, 然后执行命令行

    1 node app.js

    1 npm start
    注意-4: 要在   package.json文件中添加:
    1 ...
    2 "scripts": {
    3         "start": "node app.js"
    4     },
    5 ...

    当服务正常启动时会输出"Express server listening on port 8080"
    执行下列命令来测试我们的“Hello, World”页面

    1 node app.js &

    这是在后台启动Node应用的最原始方法, 如果你熟悉node, 你可以用Forever.js这样的模块来自动执行这项简单的任务

    我们的Node应用现在已经在后台启动了, 执行下列命令用chromium在全屏模式下打开我们的Hello, World页面.

    1 chromium --kiosk http://localhost:8080

    添加Socket.io

    我一直都认为WebSocket是现代web的基础, 对于Socket.io我认为其意义重大

    当AJAX刚兴起的时候, 虽然很神往, 但是开发者总被不同浏览器处理异步JavaScript和XML请求时不同的方式所困扰. jQuery提供了统一的一组函数从而解决了这个噩梦. Socket.io对于WebSocket有同样作用, 甚至更多!

    为了在所有浏览器上提供实时连接, Socket.IO会根据运行时选择传输能力最强的方式, 且不需要修改API. 下面是其支持的传输协议:

    1. WebSocket
    2. Adobe® Flash® Socket
    3. AJAX long polling
    4. AJAX multipart streaming
    5. Forever Iframe
    6. JSONP Polling

    把下列内容添加到app.js文件来整合Socket.io:

    1 var express = require('express')
    2   , app = express() 
    3   , server = require('http').createServer(app)
    4   , path = require('path')
    5   , io = require('socket.io').listen(server)
    6   , spawn = require('child_process').spawn

    并添加以下内容降低日志级别:

    1 //Socket.io Config
    2 io.set('log level', 1);

    现在我们的Socket.io就配好了, 但其还没有任何功能, 现在我们要实现如何处理从客户端发到服务端的消息和事件.

    下面是实现服务端功能的方法, 对应的我们还要实现在客户端实现如何处理消息, 这会在下一章介绍.

    1 io.sockets.on('connection', function (socket) {
    2     socket.emit('message', { message: 'welcome to the chat' });
    3     socket.on('send', function (data) {
    4         //Emit to all
    5         io.sockets.emit('message', data);
    6     });
    7 });

    服务端现在会在有新客户端连接后发送消息“message”, 然后等待接收名为“send”的事件来处理数据再回复所有连接的客户端

    在这里我们只有两种类型的客户端: 树莓派的显示器 (屏幕) 和移动Web应用 (远程控制)

    01 var ss; //Socket.io Server
    02 io.sockets.on('connection', function (socket) {
    03     socket.on("screen", function(data){
    04         socket.type = "screen";
    05         //Save the screen socket
    06         ss = socket;
    07         console.log("Screen ready...");
    08     });
    09  
    10     socket.on("remote", function(data){
    11         socket.type = "remote";
    12         console.log("Remote ready...");
    13         if(ss != undefined){
    14             console.log("Synced...");
    15         }
    16     });
    17 )};

    客户端处理Socket通信

    在remote.html和index.html中添加下列内容:

    1 <script src="/socket.io/socket.io.js"> </script>
    2 <script>
    3 //use http://raspberryPi.local if your using Avahi Service 
    4 //or use your RasperryPi IP instead
    5 var socket = io.connect('http://raspberrypi.local:8080');
    6 socket.on('connect', function(data){
    7     socket.emit('screen');
    8 });
    9 </script>

    在Node服务器上执行Shell命令

    Node允许我们新建子进程来运行系统命令, 并监听其输入输出. 还能给命令传递参数, 甚至能把一个命令的执行结果重定向给另一个命令. 

    在NodeJS中执行shell命令的基本方法:

    1 spawn('echo',['foobar']);

    如果需要重定向输出, 我们需要把下列函数加到app.js文件中:

    1 //Run and pipe shell script output 
    2 function run_shell(cmd, args, cb, end) {
    3     var spawn = require('child_process').spawn,
    4         child = spawn(cmd, args),
    5         me = this;
    6     child.stdout.on('data', function (buffer) { cb(me, buffer) });
    7     child.stdout.on('end', end);
    8 }

    添加OMXControl – 可以控制OMXPlayer的Node模块

    我是偶然间在npmjs.org上发现可以控制OMXPlayer的模块!
    把下列内容添加app.js文件中来使用这个模块.

    1 var omx = require('omxcontrol');
    2 //use it with express
    3 app.use(omx());

    这个模块会为我们创建以下访问路径来控制视频的播放:

    1 http://localhost:8080/omx/start/:filename
    2  
    3 http://localhost:8080/omx/pause
    4  
    5 http://localhost:8080/omx/quit

    太TM帅气鸟!

    汇总

    最终的app.js文件

    01 /**
    02  * Module dependencies.
    03  */
    04 var express = require('express')
    05   , app = express() 
    06   , server = require('http').createServer(app)
    07   , path = require('path')
    08   , io = require('socket.io').listen(server)
    09   , spawn = require('child_process').spawn
    10   , omx = require('omxcontrol');
    11 // all environments
    12 app.set('port', process.env.TEST_PORT || 8080);
    13 app.use(express.favicon());
    14 app.use(express.logger('dev'));
    15 app.use(express.bodyParser());
    16 app.use(express.methodOverride());
    17 app.use(express.static(path.join(__dirname, 'public')));
    18 app.use(omx());
    19 //Routes
    20 app.get('/', function (req, res) {
    21     res.sendfile(__dirname + '/public/index.html');
    22 });
    23 app.get('/remote', function (req, res) {
    24     res.sendfile(__dirname + '/public/remote.html');
    25 });
    26 //Socket.io Congfig
    27 io.set('log level', 1);
    28  
    29 server.listen(app.get('port'), function(){
    30     console.log('Express server listening on port ' + app.get('port'));
    31 });
    32 //Run and pipe shell script output 
    33 function run_shell(cmd, args, cb, end) {
    34     var spawn = require('child_process').spawn,
    35         child = spawn(cmd, args),
    36         me = this;
    37     child.stdout.on('data', function (buffer) { cb(me, buffer) });
    38     child.stdout.on('end', end);
    39 }
    40 //Save the Screen Socket in this variable
    41 var ss;
    42

    你可能感兴趣的:(树莓派搭建 Google TV)