HDMI-CEC是HDMI的控制协议,使有HDMI的设备能通过HDMI线缆进行互相控制。CEC是Consumer Electronics Control(消费者电器控制)的缩写。有了HDMI-CEC,电视,蓝光/DVD机,音箱就可以使用一个遥控器操作。同时也使One Touch Play成为可能,比如启动蓝光机就会同时启动电视和音箱。
各个厂商都有自己的HDMI-CEC,具体上层实现方式各不相同,不过都是基于HDMI-CEC的规范。每个厂商都有自己的名字,比如三星的Anynet+, 夏普的Aquos Link,索尼的BRAVIA Link/Sync, LG的SimpLink等
CEC是单线通信,有点像I2C。具体可参照官方规范
现在PC段显卡都有HDMI接口,但是90%的显卡厂商并不支持HDMI-CEC,包括著名的Nvidia和AMD。要在PC上使用CEC的话需要使用如下的USB-CEC适配器。
https://www.pulse-eight.com/p/104/usb-hdmi-cec-adapter
使用了该适配器就可以通过USB端口控制HDMICEC。该软件支持免费媒体管理软件XBMC(最新版叫Kodi)该厂商还提供USB-CEC开源库函数和相应调试软件。
博主购买了该适配器,使用了一下,发现该适配器完美支持XBMC。运行XBMC后可以用电视遥控器上的按钮控制XBMC,暂停播放多媒体文件,利用遥控器的方向键浏览菜单。见下面视频:
height="498" width="510" src="http://player.youku.com/embed/XOTE5NDEwMDQw" frameborder="0" allowfullscreen="">利用官方提供的应用libCECTray还能使CEC支持Windows的媒体中心。在libCECTray的Windows Media Center选项卡里可以自定义媒体中心里电视遥控器和电脑键盘按键的映射关系。XBMC里不能自定义按键映射,因为XBMC是内部支持的。控制媒体中心的情况见下面视频:
官方还提供了一个命令行调试程序cec-client,利用该程序可以检测CEC数据包传输或向CEC发送自定义数据包。下面分析下该调试软件的日志。日志中语句分为error,warning,notice,traffic, debug五种,分别代表错误,警告,提示,数据,调试语句。
每个数据包第一个字节是发出者接受者地址。一个设备分配一个地址,地址1半字节,可以是0到F。F代表所有设备,所以真正有效地址是0到E,所以HDMI-CEC最多支持15个设备。一般来说0设备是主设备电视。软件把CEC适配器模拟成一个recorder(录像机),分配给1地址。如果第一字节是01,就代表是电视发送给1设备(USBCEC适配器)的数据包,如果第一字节是0f,就代表是电视(0)发送给所有设备的广播。
数据包第二字节是命令码,代表了256种可能的命令。具体每个命令的含义可参考官方代码里cectypes.h 里 enum cec_opcode的定义。命令码为空的话代表轮询指令(POLL)
数据包第三字节往后是命令码的数据段,每个命令码数据段格式不同,具体可参照代码或官方HDMI CEC规范。
DEBUG: [ 22] unregistering all CEC clients
DEBUG: [ 26] Broadcast (F): osd name set to 'Broadcast'
DEBUG: [ 33] connection opened, clearing any previous input and waiting for active transmissions to end before starting
DEBUG: [ 47] communication thread started
DEBUG: [ 106] turning controlled mode on
NOTICE: [ 331] connection opened//链接打开
DEBUG: [ 335] processor thread started
DEBUG: [ 335] << Broadcast (F) -> TV (0): POLL
TRAFFIC: [ 342] << f0//发送数据包 f0, 进行轮询
DEBUG: [ 385] setting the line timeout to 3
DEBUG: [ 526] >> POLL sent
DEBUG: [ 530] TV (0): device status changed into 'present'
DEBUG: [ 535] << requesting vendor ID of 'TV' (0)
TRAFFIC: [ 539] << f0:8c//向电视请求厂商ID
TRAFFIC: [ 839] >> 0f:87:00:e0:91 //电视回复,厂商ID是00e091,厂商是LG,可参考cectypes.h中 enum cec_vendor_id
DEBUG: [ 842] >> TV (0) -> Broadcast (F): device vendor id (87)
DEBUG: [ 847] TV (0): vendor = LG (00e091)
DEBUG: [ 851] expected response received (87: device vendor id)
DEBUG: [ 857] replacing the command handler for device 'TV' (0)
DEBUG: [ 862] TV (0): CEC version 1.3a
DEBUG: [ 865] TV (0): menu language set to 'eng'
NOTICE: [ 869] registering new CEC client - v2.2.0
DEBUG: [ 873] detecting logical address for type 'recording device'
DEBUG: [ 879] trying logical address 'Recorder 1'
DEBUG: [ 884] << Recorder 1 (1) -> Recorder 1 (1): POLL
TRAFFIC: [ 888] << 11
TRAFFIC: [ 938] >> 0f:8c
DEBUG: [ 941] >> TV (0) -> Broadcast (F): give device vendor id (8C)
DEBUG: [ 1023] CEC transmission - received response - TRANSMIT_FAILED_ACK
TRAFFIC: [ 1029] << 11
DEBUG: [ 1117] CEC transmission - received response - TRANSMIT_FAILED_ACK
DEBUG: [ 1124] >> POLL not sent
DEBUG: [ 1127] using logical address 'Recorder 1'
DEBUG: [ 1131] Recorder 1 (1): device status changed into 'handled by libCEC'
DEBUG: [ 1136] Recorder 1 (1): power status changed from 'unknown' to 'on'
DEBUG: [ 1142] Recorder 1 (1): vendor = Pulse Eight (001582)
DEBUG: [ 1147] Recorder 1 (1): CEC version 1.4
DEBUG: [ 1151] CEC::CCECClient::AllocateLogicalAddresses - device '0', type 'recording device', LA '1'
DEBUG: [ 1180] setting ackmask to 2
DEBUG: [ 1236] Recorder 1 (1): osd name set to 'CECTester'
DEBUG: [ 1242] Recorder 1 (1): menu language set to 'eng'
DEBUG: [ 1246] CEC::CUSBCECAdapterCommunication::GetPhysicalAddress - trying to get the physical address via ADL
DEBUG: [ 1256] CEC::CUSBCECAdapterCommunication::GetPhysicalAddress - ADL returned physical address 0000
DEBUG: [ 1264] CEC::CUSBCECAdapterCommunication::GetPhysicalAddress - trying to get the physical address via nvidia driver
DEBUG: [ 1274] CEC::CUSBCECAdapterCommunication::GetPhysicalAddress - nvidia driver returned physical address 0000
DEBUG: [ 1281] CEC::CUSBCECAdapterCommunication::GetPhysicalAddress - trying to get the physical address from the OS
DEBUG: [ 1287] CEC::CUSBCECAdapterCommunication::GetPhysicalAddress - OS returned physical address 0000
DEBUG: [ 1292] CEC::CCECClient::SetDevicePhysicalAddress - not setting invalid physical address 0000
NOTICE: [ 1297] setting HDMI port to 1 on device TV (0)
DEBUG: [ 1300] Recorder 1 (1): physical address changed from ffff to 1000
DEBUG: [ 1303] << Recorder 1 (1) -> broadcast (F): physical adddress 1000
TRAFFIC: [ 1306] << 1f:84:10:00:01//录像机广播物理地址1000
DEBUG: [ 1542] using persisted autonomous mode setting: 'enabled'
TRAFFIC: [ 1571] >> 01:8f
DEBUG: [ 1574] >> TV (0) -> Recorder 1 (1): give device power status (8F)
DEBUG: [ 1580] << Recorder 1 (1) -> TV (0): on
TRAFFIC: [ 1583] << 10:90:00
DEBUG: [ 1627] using persisted CEC version setting: '1.4'
DEBUG: [ 1664] using persisted logical address setting: 'Recorder 1'
DEBUG: [ 1759] using persisted device type setting: 'recording device'
DEBUG: [ 1807] using persisted logical address mask setting: '206'
TRAFFIC: [ 1863] >> 01:1a:01
DEBUG: [ 1867] >> TV (0) -> Recorder 1 (1): give deck status (1A)
DEBUG: [ 1872] >> Recorder 1 (1): deck status changed from 'stop' to 'LG other'
DEBUG: [ 1880] << Recorder 1 (1) -> TV (0): deck status 'LG other'
TRAFFIC: [ 1885] << 10:1b:20
DEBUG: [ 1929] using persisted device name setting: 'CECTester'
DEBUG: [ 2020] using persisted physical address setting: '1000'
NOTICE: [ 2026] CEC client registered: libCEC version = 2.2.0, client version = 2.2.0, firmware version = 4, firmware build date: Thu Dec 06 11:15:20 2012 +0000, logical address(es) = Recorder 1 (1) , base device: TV (0), HDMI port number: 1, physical address: 1.0.0.0, host: Windows (x86), features: 'P8 USB' 'P8 USB detect', compiled: Oct 28 2014
DEBUG: [ 2051] Recorder 1 (1): vendor = LG (00e091)
DEBUG: [ 2055] replacing the command handler for device 'Recorder 1' (1)
DEBUG: [ 2060] Recorder 1 (1): CEC version 1.3a
DEBUG: [ 2062] << Recorder 1 (1) -> TV (0): OSD name 'CECTester'
TRAFFIC: [ 2065] << 10:47:43:45:43:54:65:73:74:65:72
DEBUG: [ 2402] << requesting power status of 'TV' (0)
TRAFFIC: [ 2407] << 10:8f
TRAFFIC: [ 2685] >> 01:90:00
DEBUG: [ 2688] >> TV (0) -> Recorder 1 (1): report power status (90)
DEBUG: [ 2693] TV (0): power status changed from 'unknown' to 'on'
DEBUG: [ 2698] expected response received (90: report power status)
TRAFFIC: [ 14015] >> 0f:36
DEBUG: [ 14018] >> TV (0) -> Broadcast (F): standby (36)
NOTICE: [ 14023] resetting SL initialised state
DEBUG: [ 14027] Recorder 1 (1): power status changed from 'on' to 'in transition from standby to on'
DEBUG: [ 14034] TV (0): power status changed from 'on' to 'standby'
TRAFFIC: [ 14102] >> 0f:36
NOTICE: [ 14106] resetting SL initialised state
TRAFFIC: [ 14377] >> 0f:36
NOTICE: [ 14381] resetting SL initialised state
TRAFFIC: [ 14471] >> 0f:36
NOTICE: [ 14475] resetting SL initialised state
TRAFFIC: [ 24969] >> 0f:87:00:e0:91
DEBUG: [ 24971] >> TV (0) -> Broadcast (F): device vendor id (87)
DEBUG: [ 24974] << Recorder 1 (1) -> Broadcast (F): vendor id LG (e091)
TRAFFIC: [ 24977] << 1f:87:00:e0:91
TRAFFIC: [ 38531] >> 0f:87:00:e0:91
DEBUG: [ 38535] >> TV (0) -> Broadcast (F): device vendor id (87)
DEBUG: [ 38540] << Recorder 1 (1) -> Broadcast (F): vendor id LG (e091)
TRAFFIC: [ 38545] << 1f:87:00:e0:91
TRAFFIC: [ 38766] >> 0f:87:00:e0:91
DEBUG: [ 38770] >> TV (0) -> Broadcast (F): device vendor id (87)
DEBUG: [ 38775] << Recorder 1 (1) -> Broadcast (F): vendor id LG (e091)
TRAFFIC: [ 38780] << 1f:87:00:e0:91
TRAFFIC: [ 39036] >> 0f:87:00:e0:91
DEBUG: [ 39040] >> TV (0) -> Broadcast (F): device vendor id (87)
DEBUG: [ 39045] << Recorder 1 (1) -> Broadcast (F): vendor id LG (e091)
TRAFFIC: [ 39051] << 1f:87:00:e0:91
TRAFFIC: [ 39256] >> 01
DEBUG: [ 39259] << POLL: TV (0) -> Recorder 1 (1)
TRAFFIC: [ 39339] >> 01:8c
DEBUG: [ 39342] >> TV (0) -> Recorder 1 (1): give device vendor id (8C)
DEBUG: [ 39348] << Recorder 1 (1) -> TV (0): vendor id LG (e091)
TRAFFIC: [ 39353] << 1f:87:00:e0:91
TRAFFIC: [ 39406] >> 01:89:0b
DEBUG: [ 39409] >> TV (0) -> Recorder 1 (1): vendor command (89)
DEBUG: [ 39414] sending abort with opcode 89 and reason 'invalid operand' to TV
DEBUG: [ 39420] << transmitting abort message
TRAFFIC: [ 39424] << 10:00:89:03
NOTICE: [ 39442] Unmapped code detected. Please send an email to support@pulse-eight.com with the following details, and if you pressed a key, tell us which one you pressed, and we'll add support for this it.
CEC command: >> 01:89:0b
Vendor ID: LG (00e091)
TRAFFIC: [ 39921] >> 01:89:0b
DEBUG: [ 39925] >> TV (0) -> Recorder 1 (1): vendor command (89)
DEBUG: [ 39930] sending abort with opcode 89 and reason 'invalid operand' to TV
DEBUG: [ 39936] << transmitting abort message
TRAFFIC: [ 39940] << 10:00:89:03
TRAFFIC: [ 40374] >> 01:89:01
DEBUG: [ 40377] >> TV (0) -> Recorder 1 (1): vendor command (89)
DEBUG: [ 40382] Recorder 1 (1): power status changed from 'in transition from standby to on' to 'standby'
DEBUG: [ 40390] << Recorder 1 (1) -> TV (0): standby
TRAFFIC: [ 40394] << 10:90:01
TRAFFIC: [ 40429] << 10:89:02:05
NOTICE: [ 40433] SL initialised
TRAFFIC: [ 40748] >> 01:8f
DEBUG: [ 40751] >> TV (0) -> Recorder 1 (1): give device power status (8F)
DEBUG: [ 40757] << Recorder 1 (1) -> TV (0): standby
TRAFFIC: [ 40761] << 10:90:01
DEBUG: [ 40803] Recorder 1 (1): power status changed from 'standby' to 'on'
TRAFFIC: [ 41000] >> 01:46
DEBUG: [ 41004] >> TV (0) -> Recorder 1 (1): give osd name (46)
DEBUG: [ 41009] << Recorder 1 (1) -> TV (0): OSD name 'CECTester'
TRAFFIC: [ 41014] << 10:47:43:45:43:54:65:73:74:65:72
TRAFFIC: [ 41426] >> 01:83
DEBUG: [ 41429] >> TV (0) -> Recorder 1 (1): give physical address (83)
DEBUG: [ 41435] << Recorder 1 (1) -> broadcast (F): physical adddress 1000
TRAFFIC: [ 41440] << 1f:84:10:00:01
TRAFFIC: [ 41701] >> 02
DEBUG: [ 41704] << POLL: TV (0) -> Recorder 2 (2)//电视隔一定时间轮询设备2
TRAFFIC: [ 41802] >> 02
DEBUG: [ 41805] << POLL: TV (0) -> Recorder 2 (2)
TRAFFIC: [ 41846] >> 04
DEBUG: [ 41849] << POLL: TV (0) -> Playback 1 (4) //电视隔一定时间轮询设备4
TRAFFIC: [ 41890] >> 04
DEBUG: [ 41893] << POLL: TV (0) -> Playback 1 (4)
TRAFFIC: [ 41933] >> 05
DEBUG: [ 41936] << POLL: TV (0) -> Audio (5)//电视隔一定时间轮询设备5
TRAFFIC: [ 41940] >> 05
DEBUG: [ 41942] << POLL: TV (0) -> Audio (5)
TRAFFIC: [ 41988] >> 08
DEBUG: [ 41991] << POLL: TV (0) -> Playback 2 (8)//电视隔一定时间轮询设备8
TRAFFIC: [ 42043] >> 08
DEBUG: [ 42046] << POLL: TV (0) -> Playback 2 (8)
TRAFFIC: [ 42098] >> 09
DEBUG: [ 42101] << POLL: TV (0) -> Recorder 3 (9)//电视隔一定时间轮询设备9
TRAFFIC: [ 42151] >> 09
DEBUG: [ 42154] << POLL: TV (0) -> Recorder 3 (9)
TRAFFIC: [ 42195] >> 0a
DEBUG: [ 42197] << POLL: TV (0) -> Tuner 4 (a)//电视隔一定时间轮询设备a
TRAFFIC: [ 42238] >> 0a
DEBUG: [ 42241] << POLL: TV (0) -> Tuner 4 (a)
TRAFFIC: [ 42282] >> 0b
DEBUG: [ 42285] << POLL: TV (0) -> Playback 3 (b)//电视隔一定时间轮询设备b
TRAFFIC: [ 42289] >> 0b
DEBUG: [ 42291] << POLL: TV (0) -> Playback 3 (b)
.
.
.
.
NOTICE: [ 67020] >> source activated: Recorder 1 (1)
TRAFFIC: [ 67098] >> 01:45
DEBUG: [ 67101] >> TV (0) -> Recorder 1 (1): user control release (45)
DEBUG: [ 67107] key released: F2 (red) (72)
TRAFFIC: [ 72096] >> 01:44:72//用户按下遥控器按键72
DEBUG: [ 72100] >> TV (0) -> Recorder 1 (1): user control pressed (44)
DEBUG: [ 72106] key pressed: F2 (red) (72)
TRAFFIC: [ 72261] >> 01:45//用户松开遥控器按键
DEBUG: [ 72265] >> TV (0) -> Recorder 1 (1): user control release (45)
DEBUG: [ 72270] key released: F2 (red) (72)
TRAFFIC: [ 79550] >> 01:44:72
DEBUG: [ 79553] >> TV (0) -> Recorder 1 (1): user control pressed (44)
DEBUG: [ 79559] key pressed: F2 (red) (72)
TRAFFIC: [ 79715] >> 01:45
DEBUG: [ 79718] >> TV (0) -> Recorder 1 (1): user control release (45)
DEBUG: [ 79723] key released: F2 (red) (72)
TRAFFIC: [ 81090] >> 01:44:72
DEBUG: [ 81093] >> TV (0) -> Recorder 1 (1): user control pressed (44)
DEBUG: [ 81098] key pressed: F2 (red) (72)
TRAFFIC: [ 81285] >> 01:45
DEBUG: [ 81288] >> TV (0) -> Recorder 1 (1): user control release (45)
DEBUG: [ 81294] key released: F2 (red) (72)
TRAFFIC: [ 82059] >> 01:44:72
DEBUG: [ 82062] >> TV (0) -> Recorder 1 (1): user control pressed (44)
DEBUG: [ 82068] key pressed: F2 (red) (72)
TRAFFIC: [ 82265] >> 01:45
DEBUG: [ 82268] >> TV (0) -> Recorder 1 (1): user control release (45)
DEBUG: [ 82274] key released: F2 (red) (72)
TRAFFIC: [ 82881] >> 01:44:72
DEBUG: [ 82884] >> TV (0) -> Recorder 1 (1): user control pressed (44)
DEBUG: [ 82889] key pressed: F2 (red) (72)
TRAFFIC: [ 83083] >> 01:45
DEBUG: [ 83086] >> TV (0) -> Recorder 1 (1): user control release (45)
DEBUG: [ 83091] key released: F2 (red) (72)
TRAFFIC: [ 83859] >> 01:44:72
DEBUG: [ 83862] >> TV (0) -> Recorder 1 (1): user control pressed (44)
DEBUG: [ 83868] key pressed: F2 (red) (72)
TRAFFIC: [ 84024] >> 01:45
DEBUG: [ 84027] >> TV (0) -> Recorder 1 (1): user control release (45)
DEBUG: [ 84032] key released: F2 (red) (72)
TRAFFIC: [ 84859] >> 01:44:72
DEBUG: [ 84862] >> TV (0) -> Recorder 1 (1): user control pressed (44)
DEBUG: [ 84868] key pressed: F2 (red) (72)
TRAFFIC: [ 85057] >> 01:45
DEBUG: [ 85060] >> TV (0) -> Recorder 1 (1): user control release (45)
DEBUG: [ 85066] key released: F2 (red) (72)
TRAFFIC: [ 86030] >> 01:44:72
DEBUG: [ 86034] >> TV (0) -> Recorder 1 (1): user control pressed (44)
DEBUG: [ 86039] key pressed: F2 (red) (72)
TRAFFIC: [ 86250] >> 01:45
DEBUG: [ 86253] >> TV (0) -> Recorder 1 (1): user control release (45)
DEBUG: [ 86258] key released: F2 (red) (72)
TRAFFIC: [ 87362] >> 01:44:72
DEBUG: [ 87366] >> TV (0) -> Recorder 1 (1): user control pressed (44)
DEBUG: [ 87371] key pressed: F2 (red) (72)
TRAFFIC: [ 87506] >> 01:45
DEBUG: [ 87508] >> TV (0) -> Recorder 1 (1): user control release (45)
DEBUG: [ 87510] key released: F2 (red) (72)
TRAFFIC: [ 102594] >> 0f:87:00:e0:91
DEBUG: [ 102598] >> TV (0) -> Broadcast (F): device vendor id (87)
DEBUG: [ 102604] << Recorder 1 (1) -> Broadcast (F): vendor id LG (e091)
TRAFFIC: [ 102610] << 1f:87:00:e0:91
参考:
维基百科:http://en.wikipedia.org/wiki/HDMI
HDMI-CEC规范:http://xtreamerdev.googlecode.com/files/CEC_Specs.pdf
QuantumData的CEC白皮书:http://www.quantumdata.com/pdf/CEC_White_Paper.pdf
官方libCEC源码:https://github.com/Pulse-Eight/libcec
转载请注明