HDMI-CEC(高清晰度多媒体接口的消费类电子控制标准)允许多媒体消费类产品互相之间沟通和交换信息。HDMI-CEC支持多种功能,例如直通遥控、系统音频控制,但是其中最有用的是一键播放。一键播放是指媒体源设备能够打开电视并且让电视自动切换到自己的端口进行播放,这样的话用户就不需要远程控制电视从Chromecast切换到蓝光播放器。
很多厂商已经采用了HDMI-CEC标准,他们的产品能够和其他厂商的产品相互工作。但是由于每一个厂商实现HDMI-CEC标准的方法不同,很多时候这样设备之间不能相互理解,而且这些设备还支持不同的功能。由于这些不同,消费者不能简单的认为两个声称支持CEC的产品互相之间能够兼容。
随着Android TIF的引入,HDMI-CEC能够让相互连接的设备能够沟通起来,并且能够最大限度的降低兼容性问题。Android创建了一个系统服务HdmiControlService来解决这个痛点。
提供HdmiControlService作为Android生态的一部分,Android希望实现一下目标:
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服务可以直接使用这个类。
注意: 设备厂商需要将下面一行加入到device.mk的
PRODUCT_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 HAL必须来实现Androi定义的接口。他向上层抽象了硬件层次的不同,并且暴露一些基本操作(allocate/read/write等)
设备厂商必须支持下面的接口:
send_message
register_event_callback
get_physical_address
get_version
get_vendor_id
get_port_info
add_logical_address
clear_logical_address
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 */
这个API让HdmiControlService
服务能够利用硬件来发送接收HDMI-CEC命令,进行必要的设置,在Android系统处于待机状态时,能够和CEC微处理器通讯。
设备厂商必须对这些HDMI-CEC HAL进行充分的测试来确信这些接口是可以正常工作的。
参考:http://blog.csdn.net/alpha_harrison/article/details/42424487