android 上的 HDMI CEC
HDMI CEC on android
我在 this android 加密狗上访问 HDMI CEC 时遇到问题。
我正在尝试打开电视并更改电视的输入源,但我无法做到。
AndroidAPI接近
我正在运行安装系统应用程序,我已经解决了
<uses-permission android:name="android.permission.HDMI_CEC" />
于 AndroidManifest.xml。
我正在通过反射访问 HDMI 服务,因为我无法直接访问它,即使是系统应用程序。
public class HdmiHelper {
public HdmiHelper(Context context) {
init(context);
}
public void init(Context context) {
try {
//Interface Callback Proxy
Class<?> hotplugEventListenerClass = Class.forName("android.hardware.hdmi.HdmiControlManager$HotplugEventListener");
Class<?> vendorCommandListenerClass = Class.forName("android.hardware.hdmi.HdmiControlManager$VendorCommandListener");
Class<?> oneTouchPlayCallbackClass = Class.forName("android.hardware.hdmi.HdmiPlaybackClient$OneTouchPlayCallback");
Class<?> displayStatusCallbackClass = Class.forName("android.hardware.hdmi.HdmiPlaybackClient$DisplayStatusCallback");
Object interfaceOneTouchPlaybackCallback = Proxy.newProxyInstance(oneTouchPlayCallbackClass.getClassLoader(),
new Class<?>[]{ oneTouchPlayCallbackClass } , new callbackProxyListener() );
Object interfaceHotplugEventCallback = Proxy.newProxyInstance(hotplugEventListenerClass.getClassLoader(),
new Class<?>[]{ hotplugEventListenerClass } , new callbackProxyListener() );
Object interfaceDisplayStatusCallbackClass = Proxy.newProxyInstance(displayStatusCallbackClass.getClassLoader(),
new Class<?>[]{ displayStatusCallbackClass } , new callbackProxyListener() );
Method m = context.getClass().getMethod("getSystemService", String.class);
Object obj_HdmiControlManager = m.invoke(context, (Object) "hdmi_control");
Log.d("HdmiHelper", "obj: " + obj_HdmiControlManager + " | " + obj_HdmiControlManager.getClass());
for( Method method : obj_HdmiControlManager.getClass().getMethods()) {
Log.d("HdmiHelper", " method: " + method.getName() );
}
Method method_addHotplugEventListener = obj_HdmiControlManager.getClass().getMethod("addHotplugEventListener", hotplugEventListenerClass);
method_addHotplugEventListener.invoke(obj_HdmiControlManager, interfaceHotplugEventCallback);
Method m2 = obj_HdmiControlManager.getClass().getMethod("getPlaybackClient");
Object obj_HdmiPlaybackClient = m2.invoke( obj_HdmiControlManager );
Log.d("HdmiHelper", "obj_HdmiPlaybackClient: " + obj_HdmiPlaybackClient + " | " + obj_HdmiPlaybackClient.getClass());
Method method_oneTouchPlay = obj_HdmiPlaybackClient.getClass().getMethod("oneTouchPlay", oneTouchPlayCallbackClass);
method_oneTouchPlay.invoke( obj_HdmiPlaybackClient, interfaceOneTouchPlaybackCallback);
Method method_queryDisplayStatus = obj_HdmiPlaybackClient.getClass().getMethod("queryDisplayStatus", displayStatusCallbackClass);
method_queryDisplayStatus.invoke( obj_HdmiPlaybackClient, interfaceDisplayStatusCallbackClass);
Method method_getActiveSource = obj_HdmiPlaybackClient.getClass().getMethod("getActiveSource");
Log.d("HdmiHelper", "getActiveSource: " + method_getActiveSource.invoke(obj_HdmiPlaybackClient));
}catch (Exception e) {
e.printStackTrace();
}
}
public class callbackProxyListener implements java.lang.reflect.InvocationHandler {
public callbackProxyListener() {
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
Log.d("HdmiHelper", "Start method " + method.getName() + " | " + proxy.getClass() + " | " + method.getDeclaringClass() );
if ( args != null ) {
// Prints the method being invoked
for (int i = 0; i != args.length; i++) {
Log.d("HdmiHelper", " - Arg(" + i + "): " + args[i].toString());
}
}
if (method.getName().equals("onReceived")) {
if (args.length == 1) {
onReceived(args[0]);
}else
if (args.length == 3) {
onReceived( (int) args[0], BytesUtil.toByteArray( args[1] ), (boolean) args[2] );
}
}else
if (method.getName().equals("onComplete")) {
onComplete( (int) args[0] );
}else
if (method.getName().equals("toString")) {
return this.toString();
}else {
return method.invoke(this, args);
}
}catch (Exception e) {
e.printStackTrace();
}
return null;
}
void onComplete(int result) {
Log.d("HdmiHelper", "onComplete: " + result);
}
void onReceived(Object event) {
Class eventClass = event.getClass();
Log.d("HdmiHelper", "onReceived(1): " + event.toString() + " | " + eventClass);
try {
Method method_getPort = eventClass.getMethod("getPort");
Method method_isConnected = eventClass.getMethod("isConnected");
Method method_describeContents = eventClass.getMethod("describeContents");
Log.d("HdmiHelper", " - " + method_getPort.invoke(event) + " | " + method_isConnected.invoke(event) + " | " + method_describeContents.invoke(event) );
}catch (Exception e) {
e.printStackTrace();
}
}
void onReceived(int srcAddress, byte[] params, boolean hasVendorId) {
Log.d("HdmiHelper", "onReceived(3): " + srcAddress + " | " + params + " | " + hasVendorId);
}
}
记录答案:
D/HdmiHelper: obj: android.hardware.hdmi.HdmiControlManager@7bca63c | class android.hardware.hdmi.HdmiControlManager
D/HdmiHelper: obj_HdmiPlaybackClient: android.hardware.hdmi.HdmiPlaybackClient@6345d1a | class android.hardware.hdmi.HdmiPlaybackClient
D/HdmiHelper: Start method onReceived | class $Proxy2 | interface android.hardware.hdmi.HdmiControlManager$HotplugEventListener
D/HdmiHelper: onReceived(1): android.hardware.hdmi.HdmiHotplugEvent@4c5c04b | class android.hardware.hdmi.HdmiHotplugEvent
D/HdmiHelper: - 1 | true | 0
- 问题一:
我收到了 true: 这意味着电视上的内容是真实的。如果电视关闭,我会收到假消息。这似乎有效。
虽然,我希望每次更改电视状态时都能收到回调,但这并没有发生。有什么想法吗?
- 问题二:
继续 OneTouchPlayCallback 的日志:
D/HdmiHelper: Start method onComplete | class $Proxy1 | interface android.hardware.hdmi.HdmiPlaybackClient$OneTouchPlayCallback
D/HdmiHelper: onComplete: 2
调查 class HdmiPlaybackClient.java if everything went good the answer would be 0 (@param result the result of the operation. {@link HdmiControlManager#RESULT_SUCCESS . You can find this variable in HdmiControlManager.java class}。相反,我收到 2,我认为是 RESULT_SOURCE_NOT_AVAILABLE.
知道为什么吗?
- 问题三
现在继续 DisplayStatusCallback 的日志:
D/HdmiHelper: Start method onComplete | class $Proxy3 | interface android.hardware.hdmi.HdmiPlaybackClient$DisplayStatusCallback
D/HdmiHelper: onComplete: 2
根据这个回调的定义:
/**
* Listener used by the client to get display device status.
*/
public interface DisplayStatusCallback {
/**
* Called when display device status is reported.
*
* @param status display device status. It should be one of the following values.
* <ul>
* <li>{@link HdmiControlManager#POWER_STATUS_ON}
* <li>{@link HdmiControlManager#POWER_STATUS_STANDBY}
* <li>{@link HdmiControlManager#POWER_STATUS_TRANSIENT_TO_ON}
* <li>{@link HdmiControlManager#POWER_STATUS_TRANSIENT_TO_STANDBY}
* <li>{@link HdmiControlManager#POWER_STATUS_UNKNOWN}
* </ul>
*/
public void onComplete(int status);
}
查看 HdmiControlManager,我收到 2,这意味着:
public static final int POWER_STATUS_TRANSIENT_TO_ON = 2;
这是一个 st运行ge 结果,因为事实并非如此。
- 继续查看日志以获取信息:
回答:
getActiveSource 为空
我还测试了这段调用 getTvClient() 方法的代码:
Method method_getTvClient = obj_HdmiControlManager.getClass().getMethod("getTvClient");
Object obj_HdmiTvClient = method_getTvClient.invoke( obj_HdmiControlManager );
Log.d("HdmiHelper", "obj_HdmiTvClient: " + obj_HdmiTvClient);
结果为空。
我也尝试了在 CEC-O-MATIC website 之后发送供应商命令的方法,但我无法成功。如果您对此有任何说明,请给我一些指导,我会测试它。
LibCEC 方法:
由于这个 post,我能够将 libcec 交叉编译为 android。但是 libcec 总是回答我 "command 'PING' was not acked by the controller".
我已将标志 -DHAVE_EXYNOS_API=1 和 -DHAVE_AOCEC_API=1 添加到 libcec。
系统信息
设备/dev/cec已入驻:
q8723bs:/ # ls -l /dev/cec
crw-rw-rw- 1 root root 218, 0 2017-12-19 16:33 /dev/cec
我在/sys/class/cec上也能找到:
q8723bs:/ # ls -laht /sys/class/cec/
total 0
-r--r--r-- 1 root root 4.0K 2017-12-19 16:45 arc_port
lrwxrwxrwx 1 root root 0 2017-12-19 16:45 cec -> ../../devices/aocec/cec
-r--r--r-- 1 root root 4.0K 2017-12-19 16:45 cec_version
--w------- 1 root root 4.0K 2017-12-19 16:45 cmd
-rw-rw-r-- 1 root root 4.0K 2017-12-19 16:45 dbg_en
-rw-rw-r-- 1 root root 4.0K 2017-12-19 16:45 device_type
-r--r--r-- 1 root root 4.0K 2017-12-19 16:45 dump_reg
-rw-rw-r-- 1 root root 4.0K 2017-12-19 16:45 fun_cfg
-rw-rw-r-- 1 root root 4.0K 2017-12-19 16:45 menu_language
-r--r--r-- 1 root root 4.0K 2017-12-19 16:45 osd_name
-rw-rw-r-- 1 root root 4.0K 2017-12-19 16:45 physical_addr
-r--r--r-- 1 root root 4.0K 2017-12-19 16:45 pin_status
-r--r--r-- 1 root root 4.0K 2017-12-19 16:45 port_num
-rw-rw-r-- 1 root root 4.0K 2017-12-19 16:45 port_seq
-r--r--r-- 1 root root 4.0K 2017-12-19 16:45 port_status
-rw-rw-r-- 1 root root 4.0K 2017-12-19 16:45 vendor_id
-r--r--r-- 1 root root 4.0K 2017-12-19 16:45 wake_up
但是当我 运行 cec-client 时,我收到了这个答案:
q8723bs:/ # id
uid=0(root) gid=0(root) groups=0(root) context=u:r:toolbox:s0
q8723bs:/ # cec-client -s /dev/cec
opening a connection to the CEC adapter...
DEBUG: [ 1] Broadcast (F): osd name set to 'Broadcast'
DEBUG: [ 2] connection opened, clearing any previous input and waiting for active transmissions to end before starting
DEBUG: [ 396] communication thread started
DEBUG: [ 1396] command 'PING' was not acked by the controller
请注意,我还有设备 /dev/input/event2 是只读的 cec_input:
q8723bs:/ # ls -l /dev/input/event2
crw-rw---- 1 root input 13, 66 2017-12-19 16:33 /dev/input/event2
q8723bs:/ # ls /sys/devices/virtual/input/input2/
capabilities/ event2/ id/ modalias name phys power/ properties subsystem/ uevent uniq
q8723bs:/ # cat /sys/devices/virtual/input/input2/name
cec_input
我尝试在 /dev/input/event2 上 运行 它,但显然它不起作用,因为它无法打开连接:
q8723bs:/ # cec-client /dev/input/event2
No device type given. Using 'recording device'
CEC Parser created - libCEC version 4.0.2
opening a connection to the CEC adapter...
DEBUG: [ 1] Broadcast (F): osd name set to 'Broadcast'
ERROR: [ 3335] error opening serial port '/dev/input/event2': Couldn't lock the serial port
ERROR: [ 3335] could not open a connection (try 1)
总结:
在这两种情况下,我都无法获得打开或更改电视输入源的命令。任何方向都会非常有帮助。提前致谢。
注意:我能够在同一台电视上使用 libcec 和 raspberry pi 完成它
因此,在围绕这个问题进行了大量工作之后,我发现,为了在 android 中启用 CEC 控制,您需要 运行 在 shell 上执行此命令:
settings put global hdmi_control_enabled 1
#if you want, you can also enable this self-explanatory command
settings put global hdmi_control_auto_wakeup_enabled 1
#and this
settings put global hdmi_control_auto_device_off_enabled 1
此后android自动开始使用cec,开机后,比如改变电视的输入源and/or打开电视
现在,关于开发者控制:
我明白了,当我调用方法时:
Method m2 = obj_HdmiControlManager.getClass().getMethod("getPlaybackClient");
我基本上可以访问加密狗本身(不是电视)的 CEC。
尽管如此,当我 运行 方法时,我仍然继续收到 null:
Method method_getTvClient = obj_HdmiControlManager.getClass().getMethod("getTvClient");
我的猜测是这是一种正常行为,因为加密狗本身是 playback 类型而不是 TV 类型。
所以我尝试使用函数 sendVendorCommand 但我不知道如何使用它。关于这个主题,我找不到任何 documentation/examples 可以帮助我的东西。
所以我决定直接通过 OS 级别并且成功了。具体来说,在这个加密狗中,您有 /sys/class/cec 两个重要文件:
。 cmd(发送cec命令)
例如(作为根 @ android shell )
#turn on tv
echo 0x40 0x04 > /sys/class/cec/cmd
#change input source to HDMI 1
echo 0x4F 0x82 0x10 0x00 > /sys/class/cec/cmd
。 dump_reg(读取cec的输出)
使用this站点检查其他命令的代码
就是这样!我更愿意通过 android 框架执行这些命令,但至少,这是可行的。
我在 this android 加密狗上访问 HDMI CEC 时遇到问题。
我正在尝试打开电视并更改电视的输入源,但我无法做到。
AndroidAPI接近
我正在运行安装系统应用程序,我已经解决了
<uses-permission android:name="android.permission.HDMI_CEC" />
于 AndroidManifest.xml。
我正在通过反射访问 HDMI 服务,因为我无法直接访问它,即使是系统应用程序。
public class HdmiHelper {
public HdmiHelper(Context context) {
init(context);
}
public void init(Context context) {
try {
//Interface Callback Proxy
Class<?> hotplugEventListenerClass = Class.forName("android.hardware.hdmi.HdmiControlManager$HotplugEventListener");
Class<?> vendorCommandListenerClass = Class.forName("android.hardware.hdmi.HdmiControlManager$VendorCommandListener");
Class<?> oneTouchPlayCallbackClass = Class.forName("android.hardware.hdmi.HdmiPlaybackClient$OneTouchPlayCallback");
Class<?> displayStatusCallbackClass = Class.forName("android.hardware.hdmi.HdmiPlaybackClient$DisplayStatusCallback");
Object interfaceOneTouchPlaybackCallback = Proxy.newProxyInstance(oneTouchPlayCallbackClass.getClassLoader(),
new Class<?>[]{ oneTouchPlayCallbackClass } , new callbackProxyListener() );
Object interfaceHotplugEventCallback = Proxy.newProxyInstance(hotplugEventListenerClass.getClassLoader(),
new Class<?>[]{ hotplugEventListenerClass } , new callbackProxyListener() );
Object interfaceDisplayStatusCallbackClass = Proxy.newProxyInstance(displayStatusCallbackClass.getClassLoader(),
new Class<?>[]{ displayStatusCallbackClass } , new callbackProxyListener() );
Method m = context.getClass().getMethod("getSystemService", String.class);
Object obj_HdmiControlManager = m.invoke(context, (Object) "hdmi_control");
Log.d("HdmiHelper", "obj: " + obj_HdmiControlManager + " | " + obj_HdmiControlManager.getClass());
for( Method method : obj_HdmiControlManager.getClass().getMethods()) {
Log.d("HdmiHelper", " method: " + method.getName() );
}
Method method_addHotplugEventListener = obj_HdmiControlManager.getClass().getMethod("addHotplugEventListener", hotplugEventListenerClass);
method_addHotplugEventListener.invoke(obj_HdmiControlManager, interfaceHotplugEventCallback);
Method m2 = obj_HdmiControlManager.getClass().getMethod("getPlaybackClient");
Object obj_HdmiPlaybackClient = m2.invoke( obj_HdmiControlManager );
Log.d("HdmiHelper", "obj_HdmiPlaybackClient: " + obj_HdmiPlaybackClient + " | " + obj_HdmiPlaybackClient.getClass());
Method method_oneTouchPlay = obj_HdmiPlaybackClient.getClass().getMethod("oneTouchPlay", oneTouchPlayCallbackClass);
method_oneTouchPlay.invoke( obj_HdmiPlaybackClient, interfaceOneTouchPlaybackCallback);
Method method_queryDisplayStatus = obj_HdmiPlaybackClient.getClass().getMethod("queryDisplayStatus", displayStatusCallbackClass);
method_queryDisplayStatus.invoke( obj_HdmiPlaybackClient, interfaceDisplayStatusCallbackClass);
Method method_getActiveSource = obj_HdmiPlaybackClient.getClass().getMethod("getActiveSource");
Log.d("HdmiHelper", "getActiveSource: " + method_getActiveSource.invoke(obj_HdmiPlaybackClient));
}catch (Exception e) {
e.printStackTrace();
}
}
public class callbackProxyListener implements java.lang.reflect.InvocationHandler {
public callbackProxyListener() {
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
Log.d("HdmiHelper", "Start method " + method.getName() + " | " + proxy.getClass() + " | " + method.getDeclaringClass() );
if ( args != null ) {
// Prints the method being invoked
for (int i = 0; i != args.length; i++) {
Log.d("HdmiHelper", " - Arg(" + i + "): " + args[i].toString());
}
}
if (method.getName().equals("onReceived")) {
if (args.length == 1) {
onReceived(args[0]);
}else
if (args.length == 3) {
onReceived( (int) args[0], BytesUtil.toByteArray( args[1] ), (boolean) args[2] );
}
}else
if (method.getName().equals("onComplete")) {
onComplete( (int) args[0] );
}else
if (method.getName().equals("toString")) {
return this.toString();
}else {
return method.invoke(this, args);
}
}catch (Exception e) {
e.printStackTrace();
}
return null;
}
void onComplete(int result) {
Log.d("HdmiHelper", "onComplete: " + result);
}
void onReceived(Object event) {
Class eventClass = event.getClass();
Log.d("HdmiHelper", "onReceived(1): " + event.toString() + " | " + eventClass);
try {
Method method_getPort = eventClass.getMethod("getPort");
Method method_isConnected = eventClass.getMethod("isConnected");
Method method_describeContents = eventClass.getMethod("describeContents");
Log.d("HdmiHelper", " - " + method_getPort.invoke(event) + " | " + method_isConnected.invoke(event) + " | " + method_describeContents.invoke(event) );
}catch (Exception e) {
e.printStackTrace();
}
}
void onReceived(int srcAddress, byte[] params, boolean hasVendorId) {
Log.d("HdmiHelper", "onReceived(3): " + srcAddress + " | " + params + " | " + hasVendorId);
}
}
记录答案:
D/HdmiHelper: obj: android.hardware.hdmi.HdmiControlManager@7bca63c | class android.hardware.hdmi.HdmiControlManager
D/HdmiHelper: obj_HdmiPlaybackClient: android.hardware.hdmi.HdmiPlaybackClient@6345d1a | class android.hardware.hdmi.HdmiPlaybackClient
D/HdmiHelper: Start method onReceived | class $Proxy2 | interface android.hardware.hdmi.HdmiControlManager$HotplugEventListener
D/HdmiHelper: onReceived(1): android.hardware.hdmi.HdmiHotplugEvent@4c5c04b | class android.hardware.hdmi.HdmiHotplugEvent
D/HdmiHelper: - 1 | true | 0
- 问题一:
我收到了 true: 这意味着电视上的内容是真实的。如果电视关闭,我会收到假消息。这似乎有效。
虽然,我希望每次更改电视状态时都能收到回调,但这并没有发生。有什么想法吗?
- 问题二:
继续 OneTouchPlayCallback 的日志:
D/HdmiHelper: Start method onComplete | class $Proxy1 | interface android.hardware.hdmi.HdmiPlaybackClient$OneTouchPlayCallback
D/HdmiHelper: onComplete: 2
调查 class HdmiPlaybackClient.java if everything went good the answer would be 0 (@param result the result of the operation. {@link HdmiControlManager#RESULT_SUCCESS . You can find this variable in HdmiControlManager.java class}。相反,我收到 2,我认为是 RESULT_SOURCE_NOT_AVAILABLE.
知道为什么吗?
- 问题三
现在继续 DisplayStatusCallback 的日志:
D/HdmiHelper: Start method onComplete | class $Proxy3 | interface android.hardware.hdmi.HdmiPlaybackClient$DisplayStatusCallback
D/HdmiHelper: onComplete: 2
根据这个回调的定义:
/**
* Listener used by the client to get display device status.
*/
public interface DisplayStatusCallback {
/**
* Called when display device status is reported.
*
* @param status display device status. It should be one of the following values.
* <ul>
* <li>{@link HdmiControlManager#POWER_STATUS_ON}
* <li>{@link HdmiControlManager#POWER_STATUS_STANDBY}
* <li>{@link HdmiControlManager#POWER_STATUS_TRANSIENT_TO_ON}
* <li>{@link HdmiControlManager#POWER_STATUS_TRANSIENT_TO_STANDBY}
* <li>{@link HdmiControlManager#POWER_STATUS_UNKNOWN}
* </ul>
*/
public void onComplete(int status);
}
查看 HdmiControlManager,我收到 2,这意味着:
public static final int POWER_STATUS_TRANSIENT_TO_ON = 2;
这是一个 st运行ge 结果,因为事实并非如此。
- 继续查看日志以获取信息:
回答:
getActiveSource 为空
我还测试了这段调用 getTvClient() 方法的代码:
Method method_getTvClient = obj_HdmiControlManager.getClass().getMethod("getTvClient");
Object obj_HdmiTvClient = method_getTvClient.invoke( obj_HdmiControlManager );
Log.d("HdmiHelper", "obj_HdmiTvClient: " + obj_HdmiTvClient);
结果为空。
我也尝试了在 CEC-O-MATIC website 之后发送供应商命令的方法,但我无法成功。如果您对此有任何说明,请给我一些指导,我会测试它。
LibCEC 方法:
由于这个 post,我能够将 libcec 交叉编译为 android。但是 libcec 总是回答我 "command 'PING' was not acked by the controller".
我已将标志 -DHAVE_EXYNOS_API=1 和 -DHAVE_AOCEC_API=1 添加到 libcec。
系统信息
设备/dev/cec已入驻:
q8723bs:/ # ls -l /dev/cec
crw-rw-rw- 1 root root 218, 0 2017-12-19 16:33 /dev/cec
我在/sys/class/cec上也能找到:
q8723bs:/ # ls -laht /sys/class/cec/
total 0
-r--r--r-- 1 root root 4.0K 2017-12-19 16:45 arc_port
lrwxrwxrwx 1 root root 0 2017-12-19 16:45 cec -> ../../devices/aocec/cec
-r--r--r-- 1 root root 4.0K 2017-12-19 16:45 cec_version
--w------- 1 root root 4.0K 2017-12-19 16:45 cmd
-rw-rw-r-- 1 root root 4.0K 2017-12-19 16:45 dbg_en
-rw-rw-r-- 1 root root 4.0K 2017-12-19 16:45 device_type
-r--r--r-- 1 root root 4.0K 2017-12-19 16:45 dump_reg
-rw-rw-r-- 1 root root 4.0K 2017-12-19 16:45 fun_cfg
-rw-rw-r-- 1 root root 4.0K 2017-12-19 16:45 menu_language
-r--r--r-- 1 root root 4.0K 2017-12-19 16:45 osd_name
-rw-rw-r-- 1 root root 4.0K 2017-12-19 16:45 physical_addr
-r--r--r-- 1 root root 4.0K 2017-12-19 16:45 pin_status
-r--r--r-- 1 root root 4.0K 2017-12-19 16:45 port_num
-rw-rw-r-- 1 root root 4.0K 2017-12-19 16:45 port_seq
-r--r--r-- 1 root root 4.0K 2017-12-19 16:45 port_status
-rw-rw-r-- 1 root root 4.0K 2017-12-19 16:45 vendor_id
-r--r--r-- 1 root root 4.0K 2017-12-19 16:45 wake_up
但是当我 运行 cec-client 时,我收到了这个答案:
q8723bs:/ # id
uid=0(root) gid=0(root) groups=0(root) context=u:r:toolbox:s0
q8723bs:/ # cec-client -s /dev/cec
opening a connection to the CEC adapter...
DEBUG: [ 1] Broadcast (F): osd name set to 'Broadcast'
DEBUG: [ 2] connection opened, clearing any previous input and waiting for active transmissions to end before starting
DEBUG: [ 396] communication thread started
DEBUG: [ 1396] command 'PING' was not acked by the controller
请注意,我还有设备 /dev/input/event2 是只读的 cec_input:
q8723bs:/ # ls -l /dev/input/event2
crw-rw---- 1 root input 13, 66 2017-12-19 16:33 /dev/input/event2
q8723bs:/ # ls /sys/devices/virtual/input/input2/
capabilities/ event2/ id/ modalias name phys power/ properties subsystem/ uevent uniq
q8723bs:/ # cat /sys/devices/virtual/input/input2/name
cec_input
我尝试在 /dev/input/event2 上 运行 它,但显然它不起作用,因为它无法打开连接:
q8723bs:/ # cec-client /dev/input/event2
No device type given. Using 'recording device'
CEC Parser created - libCEC version 4.0.2
opening a connection to the CEC adapter...
DEBUG: [ 1] Broadcast (F): osd name set to 'Broadcast'
ERROR: [ 3335] error opening serial port '/dev/input/event2': Couldn't lock the serial port
ERROR: [ 3335] could not open a connection (try 1)
总结:
在这两种情况下,我都无法获得打开或更改电视输入源的命令。任何方向都会非常有帮助。提前致谢。
注意:我能够在同一台电视上使用 libcec 和 raspberry pi 完成它
因此,在围绕这个问题进行了大量工作之后,我发现,为了在 android 中启用 CEC 控制,您需要 运行 在 shell 上执行此命令:
settings put global hdmi_control_enabled 1
#if you want, you can also enable this self-explanatory command
settings put global hdmi_control_auto_wakeup_enabled 1
#and this
settings put global hdmi_control_auto_device_off_enabled 1
此后android自动开始使用cec,开机后,比如改变电视的输入源and/or打开电视
现在,关于开发者控制:
我明白了,当我调用方法时:
Method m2 = obj_HdmiControlManager.getClass().getMethod("getPlaybackClient");
我基本上可以访问加密狗本身(不是电视)的 CEC。
尽管如此,当我 运行 方法时,我仍然继续收到 null:
Method method_getTvClient = obj_HdmiControlManager.getClass().getMethod("getTvClient");
我的猜测是这是一种正常行为,因为加密狗本身是 playback 类型而不是 TV 类型。
所以我尝试使用函数 sendVendorCommand 但我不知道如何使用它。关于这个主题,我找不到任何 documentation/examples 可以帮助我的东西。
所以我决定直接通过 OS 级别并且成功了。具体来说,在这个加密狗中,您有 /sys/class/cec 两个重要文件:
。 cmd(发送cec命令)
例如(作为根 @ android shell )
#turn on tv
echo 0x40 0x04 > /sys/class/cec/cmd
#change input source to HDMI 1
echo 0x4F 0x82 0x10 0x00 > /sys/class/cec/cmd
。 dump_reg(读取cec的输出)
使用this站点检查其他命令的代码
就是这样!我更愿意通过 android 框架执行这些命令,但至少,这是可行的。