介绍


HDMI-CEC高清晰度多媒体接口的消费类电子控制标准)允许多媒体消费类产品互相之间沟通和交换信息。HDMI-CEC支持多种功能,例如直通遥控、系统音频控制,但是其中最有用的是一键播放。一键播放是指媒体源设备能够打开电视并且让电视自动切换到自己的端口进行播放,这样的话用户就不需要远程控制电视从Chromecast切换到蓝光播放器。

很多厂商已经采用了HDMI-CEC标准,他们的产品能够和其他厂商的产品相互工作。但是由于每一个厂商实现HDMI-CEC标准的方法不同,很多时候这样设备之间不能相互理解,而且这些设备还支持不同的功能。由于这些不同,消费者不能简单的认为两个声称支持CEC的产品互相之间能够兼容。

解决方案


随着Android TIF的引入,HDMI-CEC能够让相互连接的设备能够沟通起来,并且能够最大限度的降低兼容性问题。Android创建了一个系统服务HdmiControlService来解决这个痛点。

提供HdmiControlService作为Android生态的一部分,Android希望实现一下目标:

  • 为所有厂商提供HDMI-CEC的标准实现,这将会减少设备之间的不兼容。在以前,厂商必须开发他们自己的HDMI-CEC,或者使用三方的解决方案。
  • 一个针对目前市场上大量使用的HDMI-CEC设备经过良好测试的Android服务。Android在兼容性问题上已经做过慎重的研究,并且从业界有经验的合作伙伴那儿收集了很多有用的建议。这个CEC服务在标准和修改之间做了很好的平衡,能够和人们已经使用的产品很好的工作在一起。

总体设计


HdmiControlService是和系统的其他部分(例如TIF、Audio服务、电源管理服务等)一起来实现CEC标准。

下图描述了怎样从以前自定义的CEC控制器转换到目前更简单的HDMI-CEC的硬件抽象层。

图 1. HDMI Control Service replacement

实现


下图详细描述了HDMI control service的实现。

图 2. HDMI Control Service details

下面是对于Android HDMI-CEC实现的关键的组成部分:

  • 一个管理类HdmiControlManager向有权限的应用提供API。系统服务例如TV Input Manager服务和Audio服务可以直接使用这个类。
  • 这个服务设计成可用来支持多种类型的逻辑设备。
  • HDMI-CEC通过硬件抽象层来操作硬件,这可以简化设备间在协议和信号机制之间的不同。厂商可以利用已有的硬件抽象层的定义来实现自己的硬件抽象层。

注意: 设备厂商需要将下面一行加入到device.mkPRODUCT_COPY_FILES.

PRODUCT_COPY_FILES +=\ 
frameworks/native/data/etc/android.hardware.hdmi.cec.xml:system/etc/permissions/android.hardware.hdmi.cec.xml
 

对于是HDMI源设备还是接收端设备,为了让HdmiControlService正确工作,设备厂商需要在device.mk中设置ro.hdmi.device_type属性。

 

对于 HDMI源设备,例如 Over the Top (OTT)盒子,设置:

PRODUCT_PROPERTY_OVERRIDES += ro.hdmi.device_type=4

 

对于 HDMI接收端设备,例如电视, 设置:

PRODUCT_PROPERTY_OVERRIDES += ro.hdmi.device_type=0

 

厂商自有的CEC控制器不能和HdmiControlService共存,必须禁止或者删除。但这也带来了如何实现厂商私有命令的需求。厂商私有命令必须通过修改或者扩展这个服务来实现。这个工作应该由设备厂商而不是Android完成。注意任何修改都不能改变标准的命令处理流程,否则这个设备将不是Android兼容的设备。

只有具有SignatureOrSystem权限才能访问HDMI-CEC service。只有系统的组件或者在/system/priv-app下的应用才能访问这个服务。这是为了保护这个服务不被恶意的程序滥用。

Android支持TV/Display(0)和playback device(4)两类命令,这个可以发起一键播放的命令。其他的类型暂时没有支持。

HDMI-CEC 硬件抽象层定义


为了让这个服务正常工作,HDMI-CEC HAL必须来实现Androi定义的接口。他向上层抽象了硬件层次的不同,并且暴露一些基本操作(allocate/read/write)

设备厂商必须支持下面的接口:

TX/RX/Events

  • send_message
  • register_event_callback

Info

  • get_physical_address
  •   get_version
  • get_vendor_id
  • get_port_info

Logical Address

  • add_logical_address
  • clear_logical_address

Status

  • is_connected set_option
  • set_audio_return_channel

下面是HDMI-CEC HAL相关定义的摘要。

 

#ifndef ANDROID_INCLUDE_HARDWARE_HDMI_CEC_H 
#define ANDROID_INCLUDE_HARDWARE_HDMI_CEC_H 
 
...
 
 
/* 
 * HDMI-CEC HAL interface definition. 
 */
 
typedef struct hdmi_cec_device{
 
   
/** 
     * Common methods of the HDMI-CEC device.  This *must* be the first member of 
     * hdmi_cec_device as users of this structure will cast a hw_device_t to hdmi_cec_device 
     * pointer in contexts where it's known the hw_device_t references a hdmi_cec_device. 
     */
 
   
struct hw_device_t common;
 
 
   
/* 
     * (*add_logical_address)() passes the logical address that will be used 
     * in this system. 
     * 
     * HAL may use it to configure the hardware so that the CEC commands addressed 
     * the given logical address can be filtered in. This method can be called 
     * as many times as necessary in order to support multiple logical devices. 
     * addr should be in the range of valid logical addresses for the call 
     * to succeed. 
     * 
     * Returns 0 on success or -errno on error. 
     */
 
   
int (*add_logical_address)(conststruct hdmi_cec_device* dev, cec_logical_address_t addr);
 
 
   
/* 
     * (*clear_logical_address)() tells HAL to reset all the logical addresses. 
     * 
     * It is used when the system doesn't need to process CEC command any more, 
     * hence to tell HAL to stop receiving commands from the CEC bus, and change 
     * the state back to the beginning. 
     */
 
   
void (*clear_logical_address)(conststruct hdmi_cec_device* dev);
 
 
   
/* 
     * (*get_physical_address)() returns the CEC physical address. The 
     * address is written to addr. 
     * 
     * The physical address depends on the topology of the network formed 
     * by connected HDMI devices. It is therefore likely to change if the cable 
     * is plugged off and on again. It is advised to call get_physical_address 
     * to get the updated address when hot plug event takes place. 
     * 
     * Returns 0 on success or -errno on error. 
     */
 
   
int (*get_physical_address)(conststruct hdmi_cec_device* dev, uint16_t* addr);
 
 
   
/* 
     * (*send_message)() transmits HDMI-CEC message to other HDMI device. 
     * 
     * The method should be designed to return in a certain amount of time not 
     * hanging forever, which can happen if CEC signal line is pulled low for 
     * some reason. HAL implementation should take the situation into account 
     * so as not to wait forever for the message to get sent out. 
     * 
     * It should try retransmission at least once as specified in the standard. 
     * 
     * Returns error code. See HDMI_RESULT_SUCCESS, HDMI_RESULT_NACK, and 
     * HDMI_RESULT_BUSY. 
     */
 
   
int (*send_message)(conststruct hdmi_cec_device* dev,const cec_message_t*);
 
 
   
/* 
     * (*register_event_callback)() registers a callback that HDMI-CEC HAL 
     * can later use for incoming CEC messages or internal HDMI events. 
     * When calling from C++, use the argument arg to pass the calling object. 
     * It will be passed back when the callback is invoked so that the context 
     * can be retrieved. 
     */
 
   
void (*register_event_callback)(conststruct hdmi_cec_device* dev, 
            event_callback_t callback
,void* arg);
 
 
   
/* 
     * (*get_version)() returns the CEC version supported by underlying hardware. 
     */
 
   
void (*get_version)(conststruct hdmi_cec_device* dev,int* version);
 
 
   
/* 
     * (*get_vendor_id)() returns the identifier of the vendor. It is 
     * the 24-bit unique company ID obtained from the IEEE Registration 
     * Authority Committee (RAC). 
     */
 
   
void (*get_vendor_id)(conststruct hdmi_cec_device* dev, uint32_t* vendor_id);
 
 
   
/* 
     * (*get_port_info)() returns the hdmi port information of underlying hardware. 
     * info is the list of HDMI port information, and 'total' is the number of 
     * HDMI ports in the system. 
     */
 
   
void (*get_port_info)(conststruct hdmi_cec_device* dev, 
           
struct hdmi_port_info* list[],int* total);
 
 
   
/* 
     * (*set_option)() passes flags controlling the way HDMI-CEC service works down 
     * to HAL implementation. Those flags will be used in case the feature needs 
     * update in HAL itself, firmware or microcontroller. 
     */
 
   
void (*set_option)(conststruct hdmi_cec_device* dev,int flag,int value);
 
 
   
/* 
     * (*set_audio_return_channel)() configures ARC circuit in the hardware logic 
     * to start or stop the feature. Flag can be either 1 to start the feature 
     * or 0 to stop it. 
     * 
     * Returns 0 on success or -errno on error. 
     */
 
   
void (*set_audio_return_channel)(conststruct hdmi_cec_device* dev,int flag);
 
 
   
/* 
     * (*is_connected)() returns the connection status of the specified port. 
     * Returns HDMI_CONNECTED if a device is connected, otherwise HDMI_NOT_CONNECTED. 
     * The HAL should watch for +5V power signal to determine the status. 
     */
 
   
int (*is_connected)(conststruct hdmi_cec_device* dev,int port); 
 
   
/* Reserved for future use to maximum 16 functions. Must be NULL. */ 
   
void* reserved[16-11]; 
} hdmi_cec_device_t; 
 
#endif /* ANDROID_INCLUDE_HARDWARE_HDMI_CEC_H */

 

这个APIHdmiControlService服务能够利用硬件来发送接收HDMI-CEC命令,进行必要的设置,在Android系统处于待机状态时,能够和CEC微处理器通讯。

测试


设备厂商必须对这些HDMI-CEC HAL进行充分的测试来确信这些接口是可以正常工作的。

 

Logo

智屏生态联盟致力于大屏生态发展,利用大屏快应用技术降低开发者开发、发布大屏应用门槛

更多推荐