摘要:本文从苏州台4K转播车系统项目实际应用出发,通过采购带Android系统的19寸长条屏显示器,基于Android系统框架及SDK定向开发,实现了多台19寸长条屏显示器集中控制管理、NTP授时、倒计时设、多种显示方案实时切换的功能,目前该时钟系统已经在苏州台4K转播车上顺利投入使用,通过IP化的管理和授时方式,提高了时间显示精度,满足了多样化的4K节目制作需求。
关键字:Android;NTP;倒计时控制;19寸长条屏显示器;Socket服务。
一、 概述
在传统转播车和演播室时钟授时及显示使用方案上,目前国内主要用的是朗威和青岛的时钟显示产品,主要原理是通过GPS授时,将接收下来的时间转换成LTC时间码,再通过分配器发送给各个时钟显示单元及倒计时控制器,时钟显示主要通过LED数码管显示。
传统时钟授时及显示方案,需要增加一堆硬件投入,使用时间长以后,会出现各类硬件损坏或失灵情况,届时只能重新购买。
在进入4K IP制作以后,转播车系统内主要使用的是PTP+BB的同步方案,同时同步机自带NTP服务,可以通过网络获得更精确的时间。因此,为了降低硬件维护成本及难度、获取更精确的时钟,我台决定通过自主开始,实现通过NTP授时的时钟显示方案。
二、硬件方案选择及系统架构
2.1、19寸长条屏显示器介绍
19寸长条显示器通过采购第三方的现有解决方案,显示器如下图所示,采用窄边框设计,分辨率1920*360,最高亮度为500cd/m²,对比度为600/1,带1个RJ45的网口,1根外部WIFI天线,1路红外输入,不带VGA或HDMI输入,显示器内部集成了定制的Android 6.0系统,可以通过外接键鼠或者红外遥控器,对显示界面进行操作。
值得一提的是,19寸长条屏显示器的Android系统,采用的是手机和平板端的Android进行的定制,修改了分辨率和布局显示,因此在相应Android程序的开始时,需选择手机或者平板端的开发框架。
2.2、时钟授时系统框架
转播车内时钟授时及显示的框架如下图所示,主同步机通过GPS授时,生成PTP、BB、LTC、WCLK、NTP等同步信号,4K转播车内的备同步机、交换机、IP设备通过PTP来锁同步;同时主同步机作为NTP服务器,19寸长条时钟显示器作为NTP客户端,共同接入控制交换机;每台时钟显示器对外开放接口,倒计时控制软件可通过这些接口,去单独设置每台时钟显示器的倒计时、栏目名、初始化显示界面等配置信息。
相比于传统的转播车时钟授时及显示系统,新的时钟显示系统,去除了时钟主机、时码分配、倒计时控制硬件等硬件,每台时钟显示器可进行分布式管控,在操作和显示上更具灵活性,同时通过NTP服务从同步机上获取时钟信息,精度更高、更稳定。
三、Android端开发设计方案
Android端使用Android Studio进行开发,Android Studio是用于开发Android应用的官方集成开发环境,以IntelliJ IDEA为基础构建而成;得益于官方的支持,Android Studio除了提供强大的代码编译器和开发着工具,还提供了更多提高Android应用构建效率的功能,如快速且功能丰富的模拟器、统一的开发环境、基于Gradle的灵活构建系统、大量的测试工具和框架等,开发者不需要从头开始搭建,就可以快速的构建自己的Android应用程序。
3.1、Android端时钟显示程序框架
程序框架图如下图所示:
1. Android应用程序在获取各类权限和SDK以后,进入MainActivity主进程;
2. MainActivity下进入初始化事件onCreate,读取时钟显示器本地存储中的”countdownTime.json”和”app.config”,两个文件都为自定义,其中第一个表示倒计时及NTP服务配置的文件,内部存有栏目名、开始时间、结束时间、NTP服务器地址等信息,第二个表示时钟程序初始化后的界面显示和Socket服务地址;
3. 打开SocketService端口监听服务,时钟显示器作为服务端,PC倒计时控制程序作为客户端,当两边建立连接以后,倒计时控制器发送”countdownTime.json”配置文件给时钟显示器,时钟显示器对比本地和接收到的”countdownTime.json”配置文件,当文件内容不一样时,覆盖掉本地的配置文件,并启用新的倒计时配置;
4. 初始化NTP服务,更新NTP服务器的IP地址,并从NTP服务端获取时间;
5. 新建一个定时器的线程,每隔200ms去获取以下本地的”countdownTime.json”配置文件,并更新时钟显示界面;
6. 时钟显示器支持外部红外遥控,当按下外部红外遥控器按钮以后,触发程序中“onKeyDown“事件,程序根据按下去按钮的类型,如”前进“、”后退“,再比对现有的显示界面,来切换不同的时钟显示界面,当切换到新的显示界面后,将新界面中的”startPoint“保存到本地”app.config“文件中,这样下次重启时钟显示程序时,会根据”startPonit”自动进入上次保存的显示界面。
3.2、Android端的环境搭建
3.2.1、build.gradle文件的构建
1. 时钟显示器的Android版本为6.0版本,Android版本自上而下兼容,考虑今后的兼容性和扩展性,此次开发的此次开发的Android SDK,选用了Android 10.0(Q)的版本,API等级为29,在程序构建配置项“build.gradle”中配置如下。
2. 在bulid.gradle中添加本地和第三方库,具体如下图所示,其中主要用到的库有:
'com.google.code.gson:gson:2.8.6'为google提供的json读写库;
'org.greenrobot:eventbus:3.0.0'为greenrobot的多线程处理库;
"io.reactivex.rxjava2:rxandroid:2.0.2"为线程之间通信需要的库;
project(path: ':library')包含了本地工程文件中,library下面的所有库,其中主要用到NTP服务的是第三方库“TrueTime.java“。
3.1.2、AndroidManifest文件的构建
在AndroidManifest.xml里面,对应用程序所要用到的权限、组件、服务信息做一些规范,如其中主要用到的规范有:
1.uses-permission”下加入允许内部存储的读写、开机自动启动程序的权限;
2.读写权限除了在AndroidManifest里面进行全局设置以外,还需要在初始化启动Activity进程时,打开页面对应存储的读写权限(新版本Android系统出于对系统文件的保护考虑),具体代码如下;
3. 在“application-receiver“下打开接收开机自动启动的广播类” .BootBroadcastReceiver“;
4.在“application-service“下打开通信端口的服务类”.SocketService“;
5. 在“application-activity“下,规定程数启动时启动的Activitey页面,已经页面的方向,默认我们启动程序时是进入”MainActivity“并横屏显示。
3.2、NTP授时设计
获取NTP时间的SDK已经导入到项目的“library“库中,调用SDK的接口通过”TrueTime“接口去实现,NTP授时的部分代码如下:
1. 通过异步的方式初始化NTP时间,包括通过”.build”建立TrueTime对象,”withNtpHost(ntpHost)”设置NTP服务端IP地址,“.withConnectionTimeout(3_1428)“设置连接服务的事件,”initialize()“初始化NTP服务的连接,并同时钟显示器步本地时钟;
2.通过Timer类定时器,每隔200ms去获取NTP时间以及倒计时并更新显示页面,具体程序如下图,其中“getCountdownData“为获取本地倒计时配置及NTP服务器地址,”updateTime(dataList)“是将获取到的倒计时信息,更新并显示给程序页面。
3.3、Socket服务
Scoket服务是通过Android线程启动的TCP端口连接服务,主要用于连接Android时钟显示器和倒计时控制软件,SocketService线程启动在Android主程序中,通过Intent方法实现,传递参数为IP地址和端口号,默认TCP端口号“5000“,如下图;
SocketService继承于Service服务类,然后通过重写“onStartCommand“、”run“、”onDestroy“三个方法:
“onStartCommand“用于获取主线程传递的参数、读取本地配置文件以及初始化TCP接口三个功能,其中TCP接口的TCP接口初始化为服务端,当每次有客户端连接请求时,就会新建一个线程,单独处理客户端的连接及通信请求;
“run”用于循环接收倒计时控制客户端发来的数据,并将这些数据保存到本地“countdownTime.json”配置文件中;
“onDestroy”用于在SocketService服务断开以后,释放之前对应的socket连接资源。
3.4、开机自动启动
Android端时钟显示器的程序,要求每次开机自动启动,并且显示上一次关机的画面。在Android系统启动时,会发送一个字符串系统广播,广播内容为“action.BOOT_COMPLETED”,所有只要在程序的“BroadcastReceiver”中接收到该消息,并创建启用相应的Activity,就能实现Android程序的开机自启动。
实现程序开机自启动的具体方法如下:
1.新建一个BootBroadcasReceiver的类,继承于BroadcastReceiver,重写onReceive方法,实现启动程序中MainActivity主进程,代码如下图;
2.在AndroidManifest中打开程序开机自启的权限,另外指定“BootBroadcasReceiver”接收广播“action.BOOT_COMPLETED”后自动触发执行内部OnReceive方法。
3.5、显示界面设计及切换
1. 时钟显示方案是通过在一个MainActivity进程中,显示四个布局方案,分别为:
“activity_main”主显示方案,页面进入锚点startPoint为0,该页面主要包含栏目名、日期、正计时时间、倒计时时间的显示;
“activity_countdown”倒计时显示方案,页面进入锚点startPoint为1,该页面主要包含倒计时时钟显示;
“activity_countup”倒计时显示方案,页面进入锚点startPoint为2,该页面主要包含正计时时钟显示;
“activity_details”倒计时显示方案,页面进入锚点startPoint为3,该页面主要包含一些提醒信息说明,各个时钟显示方案如下如所示。
2.为了模仿LED字体显示的效果,时钟显示程序从网上下载了第三方LED字体库文件“digital-7.ttf”,放入工程文件中“src/main/assets”目录下,之后通过重写”TextView”文本框方法,重新生成一个“DigitalTextView”的带LED字体显示效果的文本框,“DigitalTextView”文本框在页面设计使用时,跟”TextView”文本框一致,重写方法如下。
3.时钟显示界面切换逻辑:
在程序初始化的时候,会读取本地存储“app.confiig”中的startPoint值,该值为进入对应的显示方案的锚点;
当使用外置红外遥控器对程序进行操作时,如“向前翻页”,则startPoint在原来值的基础上加1,如果startPoint已经是最大值3,则重新回到0开始,反之如“向后翻页”,则strartPoint在原来的基础上减1,不断循环;
当startPoint锚点修改以后,会记录到本地存储“app.config”中,程序每次刷新时间,都会重新读取“app.config”中startPoint的值,并通过对应的值显示显示界面;
程序每次重启不会初始化内部存储中的配置文件,因此通过次方法,可以保证时钟显示程序每次开启,都会显示上一次开机时的显示画面。
4.“countdownTime.json”文件内容如下图所示,采用json文件格式。
节点“data”表示一个栏目倒计时设计数组,可放入多个倒计时栏目,其中“pgmTime”为栏目开始时间,”Length”为栏目结束时间,“Column”为栏目名,时钟显示程序中,会根据NTP服务器读取到的时间,跟“data”节点下的倒计时栏目进行比对,选择最接近开播开始或者结束的栏目,做对应倒计时及栏目名的显示。
节点“ntpHost”表示NTP服务器的地址,当设定好该地址后,会跟时钟显示程序中现有的NTP服务器地址进行比对,如果NTP服务器地址不一致,则会把新地址传送给“initTrueTime”类,并重新初始化NTP服务。
四、时钟集中控制端的设计方案
4.1、Windows环境及界面设计
时钟显示系统的倒计时控制,通过远端Windows窗体应用程序,去发现并连接局域网内的每台时钟显示器,然后统一发送倒计时控制信息。
Windows窗体应用程序基于.NET Framework 4.6框架进行开发,程序命名为“时钟倒计时设置器”,程序界面如下图所示,左侧“扫描”按钮按下后,下方会显示局域网中所有的时钟显示器,并自动建立连接;“NTP服务设置”下方,可设置NTP服务器的地址;“倒计时设置”下方,可设置栏目开始时间,结束时间及栏目名等信息;NTP的服务器地址、倒计时设置下的栏目信息,都可以通过“保存配置”按钮保存到本地,供下次打开程序读取,也可以直接发送给时钟显示器列表内的所有时钟显示器。
4.2、局域网内时钟显示器的发现和接入
当按下“时钟倒计时设置器”程序中的“扫描按钮时,触发“”scanBtn_Click”按钮控制事件,如下图所示:
1.首先程序会清空所有跟在程序内的TCP端口连接;
2.获取“App.config“文件中的配置信息,如扫描的开始和截止地址、扫描的端口号,对这些地址做差值,从而得到总的需要扫描的地址数量;
3.遍历扫描这些地址和端口号,并尝试进行连接,当和时钟显示器端建立连接成功后,返回时钟显示器端的IP地址和socket对象;
4.每个时钟显示器端的连接和通信,都开通一个单独的线程,并同步实时更新显示到“时钟倒计时设置器“界面中。
4.3、栏目名、倒计时信息的读取、保存和发送
程序初始化时,会从本地配置文件中读取之前保存的配置信息并显示,本地配置文件名和格式与Android端时钟显示器上的一样,都为“countdownTime.json“;
在程序里面,可以对“countdownTime.json“读取出的倒计时信息和NTP服务器地址进行修改,修改完成后,点保存配置,触发”saveBtn_Click“按钮事件,该事件主要用于覆盖之前读取的“countdownTime.json“文件;
当在程序中点击“发送配置”按钮,触发“sendBtn_Click”按钮事件,将目前程序界面上的内容,以json文件数据流的格式,发送给“时钟显示”列表里的所有时钟显示器,时钟显示器端程序收到数据流以后,更新显示并自动覆盖掉原先的时钟显示器端的”countdownTime.json”配置文件,发送倒计时配置信息的主要程序如下图所示。
五、总结
转播车时钟系统的设计与应用,满足了我台现有4K IP转播车上时钟授时和显示的应用,不同的操作工位,可以显示不同的时钟监看方案,同时基于IP化的统一配置管理,使得在时钟显示器的配置上更加简单方便。
基于Android框架而设计的时钟系统,在未来复杂的4K制作环节中,更具有灵活性和多样性,我们随时可以根据不同的需求来修改程序,增加新的功能,如把天气信息、温度湿度信息、早中晚的界面显示颜色、时钟倒计时蜂鸣器报警等,这些功能也将在今后的实际应用中,慢慢完善并加入。