Use generated Java bindings for CEC HAL

Replace usage of JNI methods with Java bindings.

Bug: 150290661
Test: run cts -m CtsServicesHostTestCases
Test: adb shell dumpsys hdmi_control
Change-Id: I43c72ab6cc203da1d935bd51fc0fd11b930255ce
This commit is contained in:
Shraddha Basantwani
2020-03-24 18:16:28 +05:30
parent bf7cb1ca91
commit 2f0e16a8e6
4 changed files with 230 additions and 84 deletions

View File

@@ -26,7 +26,6 @@ java_library_static {
"services.net", "services.net",
"android.hardware.light-V2.0-java", "android.hardware.light-V2.0-java",
"android.hardware.power-V1.0-java", "android.hardware.power-V1.0-java",
"android.hardware.tv.cec-V1.0-java",
"android.hardware.vibrator-java", "android.hardware.vibrator-java",
"android.net.ipsec.ike.stubs.module_libs_api", "android.net.ipsec.ike.stubs.module_libs_api",
"app-compat-annotations", "app-compat-annotations",
@@ -46,6 +45,7 @@ java_library_static {
"android.hardware.health-V2.0-java", "android.hardware.health-V2.0-java",
"android.hardware.health-V2.1-java", "android.hardware.health-V2.1-java",
"android.hardware.light-java", "android.hardware.light-java",
"android.hardware.tv.cec-V1.0-java",
"android.hardware.weaver-V1.0-java", "android.hardware.weaver-V1.0-java",
"android.hardware.biometrics.face-V1.0-java", "android.hardware.biometrics.face-V1.0-java",
"android.hardware.biometrics.fingerprint-V2.1-java", "android.hardware.biometrics.fingerprint-V2.1-java",

View File

@@ -17,11 +17,18 @@
package com.android.server.hdmi; package com.android.server.hdmi;
import android.hardware.hdmi.HdmiPortInfo; import android.hardware.hdmi.HdmiPortInfo;
import android.hardware.tv.cec.V1_0.CecMessage;
import android.hardware.tv.cec.V1_0.HotplugEvent;
import android.hardware.tv.cec.V1_0.IHdmiCec;
import android.hardware.tv.cec.V1_0.IHdmiCec.getPhysicalAddressCallback;
import android.hardware.tv.cec.V1_0.IHdmiCecCallback;
import android.hardware.tv.cec.V1_0.Result; import android.hardware.tv.cec.V1_0.Result;
import android.hardware.tv.cec.V1_0.SendMessageResult; import android.hardware.tv.cec.V1_0.SendMessageResult;
import android.os.Handler; import android.os.Handler;
import android.os.IHwBinder;
import android.os.Looper; import android.os.Looper;
import android.os.MessageQueue; import android.os.MessageQueue;
import android.os.RemoteException;
import android.util.Slog; import android.util.Slog;
import android.util.SparseArray; import android.util.SparseArray;
@@ -78,6 +85,11 @@ final class HdmiCecController {
private static final int MAX_CEC_MESSAGE_HISTORY = 200; private static final int MAX_CEC_MESSAGE_HISTORY = 200;
private static final int INVALID_PHYSICAL_ADDRESS = 0xFFFF;
/** Cookie for matching the right end point. */
protected static final int HDMI_CEC_HAL_DEATH_COOKIE = 353;
// Predicate for whether the given logical address is remote device's one or not. // Predicate for whether the given logical address is remote device's one or not.
private final Predicate<Integer> mRemoteDeviceAddressPredicate = new Predicate<Integer>() { private final Predicate<Integer> mRemoteDeviceAddressPredicate = new Predicate<Integer>() {
@Override @Override
@@ -101,10 +113,6 @@ final class HdmiCecController {
// device or issued by internal state change. // device or issued by internal state change.
private Handler mControlHandler; private Handler mControlHandler;
// Stores the pointer to the native implementation of the service that
// interacts with HAL.
private volatile long mNativePtr;
private final HdmiControlService mService; private final HdmiControlService mService;
// Stores the local CEC devices in the system. Device type is used for key. // Stores the local CEC devices in the system. Device type is used for key.
@@ -140,23 +148,21 @@ final class HdmiCecController {
* A factory method with injection of native methods for testing. * A factory method with injection of native methods for testing.
*/ */
static HdmiCecController createWithNativeWrapper( static HdmiCecController createWithNativeWrapper(
HdmiControlService service, NativeWrapper nativeWrapper) { HdmiControlService service, NativeWrapper nativeWrapper) {
HdmiCecController controller = new HdmiCecController(service, nativeWrapper); HdmiCecController controller = new HdmiCecController(service, nativeWrapper);
long nativePtr = nativeWrapper String nativePtr = nativeWrapper.nativeInit();
.nativeInit(controller, service.getServiceLooper().getQueue()); if (nativePtr == null) {
if (nativePtr == 0L) { HdmiLogger.warning("Couldn't get tv.cec service.");
controller = null; return null;
return null; }
} controller.init(nativeWrapper);
return controller;
controller.init(nativePtr);
return controller;
} }
private void init(long nativePtr) { private void init(NativeWrapper nativeWrapper) {
mIoHandler = new Handler(mService.getIoLooper()); mIoHandler = new Handler(mService.getIoLooper());
mControlHandler = new Handler(mService.getServiceLooper()); mControlHandler = new Handler(mService.getServiceLooper());
mNativePtr = nativePtr; nativeWrapper.setCallback(new HdmiCecCallback());
} }
@ServiceThreadOnly @ServiceThreadOnly
@@ -251,7 +257,7 @@ final class HdmiCecController {
HdmiPortInfo[] getPortInfos() { HdmiPortInfo[] getPortInfos() {
return mNativeWrapperImpl.nativeGetPortInfos(mNativePtr); return mNativeWrapperImpl.nativeGetPortInfos();
} }
/** /**
@@ -279,7 +285,7 @@ final class HdmiCecController {
int addLogicalAddress(int newLogicalAddress) { int addLogicalAddress(int newLogicalAddress) {
assertRunOnServiceThread(); assertRunOnServiceThread();
if (HdmiUtils.isValidAddress(newLogicalAddress)) { if (HdmiUtils.isValidAddress(newLogicalAddress)) {
return mNativeWrapperImpl.nativeAddLogicalAddress(mNativePtr, newLogicalAddress); return mNativeWrapperImpl.nativeAddLogicalAddress(newLogicalAddress);
} else { } else {
return Result.FAILURE_INVALID_ARGS; return Result.FAILURE_INVALID_ARGS;
} }
@@ -296,7 +302,7 @@ final class HdmiCecController {
for (int i = 0; i < mLocalDevices.size(); ++i) { for (int i = 0; i < mLocalDevices.size(); ++i) {
mLocalDevices.valueAt(i).clearAddress(); mLocalDevices.valueAt(i).clearAddress();
} }
mNativeWrapperImpl.nativeClearLogicalAddress(mNativePtr); mNativeWrapperImpl.nativeClearLogicalAddress();
} }
@ServiceThreadOnly @ServiceThreadOnly
@@ -316,7 +322,7 @@ final class HdmiCecController {
@ServiceThreadOnly @ServiceThreadOnly
int getPhysicalAddress() { int getPhysicalAddress() {
assertRunOnServiceThread(); assertRunOnServiceThread();
return mNativeWrapperImpl.nativeGetPhysicalAddress(mNativePtr); return mNativeWrapperImpl.nativeGetPhysicalAddress();
} }
/** /**
@@ -327,7 +333,7 @@ final class HdmiCecController {
@ServiceThreadOnly @ServiceThreadOnly
int getVersion() { int getVersion() {
assertRunOnServiceThread(); assertRunOnServiceThread();
return mNativeWrapperImpl.nativeGetVersion(mNativePtr); return mNativeWrapperImpl.nativeGetVersion();
} }
/** /**
@@ -338,7 +344,7 @@ final class HdmiCecController {
@ServiceThreadOnly @ServiceThreadOnly
int getVendorId() { int getVendorId() {
assertRunOnServiceThread(); assertRunOnServiceThread();
return mNativeWrapperImpl.nativeGetVendorId(mNativePtr); return mNativeWrapperImpl.nativeGetVendorId();
} }
/** /**
@@ -351,7 +357,7 @@ final class HdmiCecController {
void setOption(int flag, boolean enabled) { void setOption(int flag, boolean enabled) {
assertRunOnServiceThread(); assertRunOnServiceThread();
HdmiLogger.debug("setOption: [flag:%d, enabled:%b]", flag, enabled); HdmiLogger.debug("setOption: [flag:%d, enabled:%b]", flag, enabled);
mNativeWrapperImpl.nativeSetOption(mNativePtr, flag, enabled); mNativeWrapperImpl.nativeSetOption(flag, enabled);
} }
/** /**
@@ -365,7 +371,7 @@ final class HdmiCecController {
if (!LanguageTag.isLanguage(language)) { if (!LanguageTag.isLanguage(language)) {
return; return;
} }
mNativeWrapperImpl.nativeSetLanguage(mNativePtr, language); mNativeWrapperImpl.nativeSetLanguage(language);
} }
/** /**
@@ -377,7 +383,7 @@ final class HdmiCecController {
@ServiceThreadOnly @ServiceThreadOnly
void enableAudioReturnChannel(int port, boolean enabled) { void enableAudioReturnChannel(int port, boolean enabled) {
assertRunOnServiceThread(); assertRunOnServiceThread();
mNativeWrapperImpl.nativeEnableAudioReturnChannel(mNativePtr, port, enabled); mNativeWrapperImpl.nativeEnableAudioReturnChannel(port, enabled);
} }
/** /**
@@ -389,7 +395,7 @@ final class HdmiCecController {
@ServiceThreadOnly @ServiceThreadOnly
boolean isConnected(int port) { boolean isConnected(int port) {
assertRunOnServiceThread(); assertRunOnServiceThread();
return mNativeWrapperImpl.nativeIsConnected(mNativePtr, port); return mNativeWrapperImpl.nativeIsConnected(port);
} }
/** /**
@@ -511,7 +517,7 @@ final class HdmiCecController {
// <Polling Message> is a message which has empty body. // <Polling Message> is a message which has empty body.
int ret = int ret =
mNativeWrapperImpl.nativeSendCecCommand( mNativeWrapperImpl.nativeSendCecCommand(
mNativePtr, sourceAddress, destinationAddress, EMPTY_BODY); sourceAddress, destinationAddress, EMPTY_BODY);
if (ret == SendMessageResult.SUCCESS) { if (ret == SendMessageResult.SUCCESS) {
return true; return true;
} else if (ret != SendMessageResult.NACK) { } else if (ret != SendMessageResult.NACK) {
@@ -615,7 +621,7 @@ final class HdmiCecController {
int i = 0; int i = 0;
int errorCode = SendMessageResult.SUCCESS; int errorCode = SendMessageResult.SUCCESS;
do { do {
errorCode = mNativeWrapperImpl.nativeSendCecCommand(mNativePtr, errorCode = mNativeWrapperImpl.nativeSendCecCommand(
cecMessage.getSource(), cecMessage.getDestination(), body); cecMessage.getSource(), cecMessage.getDestination(), body);
if (errorCode == SendMessageResult.SUCCESS) { if (errorCode == SendMessageResult.SUCCESS) {
break; break;
@@ -639,7 +645,7 @@ final class HdmiCecController {
} }
/** /**
* Called by native when incoming CEC message arrived. * Called when incoming CEC message arrived.
*/ */
@ServiceThreadOnly @ServiceThreadOnly
private void handleIncomingCecCommand(int srcAddress, int dstAddress, byte[] body) { private void handleIncomingCecCommand(int srcAddress, int dstAddress, byte[] body) {
@@ -651,7 +657,7 @@ final class HdmiCecController {
} }
/** /**
* Called by native when a hotplug event issues. * Called when a hotplug event issues.
*/ */
@ServiceThreadOnly @ServiceThreadOnly
private void handleHotplug(int port, boolean connected) { private void handleHotplug(int port, boolean connected) {
@@ -687,18 +693,19 @@ final class HdmiCecController {
} }
protected interface NativeWrapper { protected interface NativeWrapper {
long nativeInit(HdmiCecController handler, MessageQueue messageQueue); String nativeInit();
int nativeSendCecCommand(long controllerPtr, int srcAddress, int dstAddress, byte[] body); void setCallback(HdmiCecCallback callback);
int nativeAddLogicalAddress(long controllerPtr, int logicalAddress); int nativeSendCecCommand(int srcAddress, int dstAddress, byte[] body);
void nativeClearLogicalAddress(long controllerPtr); int nativeAddLogicalAddress(int logicalAddress);
int nativeGetPhysicalAddress(long controllerPtr); void nativeClearLogicalAddress();
int nativeGetVersion(long controllerPtr); int nativeGetPhysicalAddress();
int nativeGetVendorId(long controllerPtr); int nativeGetVersion();
HdmiPortInfo[] nativeGetPortInfos(long controllerPtr); int nativeGetVendorId();
void nativeSetOption(long controllerPtr, int flag, boolean enabled); HdmiPortInfo[] nativeGetPortInfos();
void nativeSetLanguage(long controllerPtr, String language); void nativeSetOption(int flag, boolean enabled);
void nativeEnableAudioReturnChannel(long controllerPtr, int port, boolean flag); void nativeSetLanguage(String language);
boolean nativeIsConnected(long controllerPtr, int port); void nativeEnableAudioReturnChannel(int port, boolean flag);
boolean nativeIsConnected(int port);
} }
private static native long nativeInit(HdmiCecController handler, MessageQueue messageQueue); private static native long nativeInit(HdmiCecController handler, MessageQueue messageQueue);
@@ -716,67 +723,200 @@ final class HdmiCecController {
int port, boolean flag); int port, boolean flag);
private static native boolean nativeIsConnected(long controllerPtr, int port); private static native boolean nativeIsConnected(long controllerPtr, int port);
private static final class NativeWrapperImpl implements NativeWrapper { private static final class NativeWrapperImpl implements NativeWrapper,
IHwBinder.DeathRecipient, getPhysicalAddressCallback {
private IHdmiCec mHdmiCec;
private final Object mLock = new Object();
private int mPhysicalAddress = INVALID_PHYSICAL_ADDRESS;
@Override @Override
public long nativeInit(HdmiCecController handler, MessageQueue messageQueue) { public String nativeInit() {
return HdmiCecController.nativeInit(handler, messageQueue); return (connectToHal() ? mHdmiCec.toString() : null);
}
boolean connectToHal() {
try {
mHdmiCec = IHdmiCec.getService();
try {
mHdmiCec.linkToDeath(this, HDMI_CEC_HAL_DEATH_COOKIE);
} catch (RemoteException e) {
HdmiLogger.error("Couldn't link to death : ", e);
}
} catch (RemoteException e) {
HdmiLogger.error("Couldn't get tv.cec service : ", e);
return false;
}
return true;
} }
@Override @Override
public int nativeSendCecCommand(long controllerPtr, int srcAddress, int dstAddress, public void setCallback(HdmiCecCallback callback) {
byte[] body) { try {
return HdmiCecController.nativeSendCecCommand(controllerPtr, srcAddress, dstAddress, body); mHdmiCec.setCallback(callback);
} catch (RemoteException e) {
HdmiLogger.error("Couldn't initialise tv.cec callback : ", e);
}
} }
@Override @Override
public int nativeAddLogicalAddress(long controllerPtr, int logicalAddress) { public int nativeSendCecCommand(int srcAddress, int dstAddress, byte[] body) {
return HdmiCecController.nativeAddLogicalAddress(controllerPtr, logicalAddress); CecMessage message = new CecMessage();
message.initiator = srcAddress;
message.destination = dstAddress;
message.body = new ArrayList<>(body.length);
for (byte b : body) {
message.body.add(b);
}
try {
return mHdmiCec.sendMessage(message);
} catch (RemoteException e) {
HdmiLogger.error("Failed to send CEC message : ", e);
return SendMessageResult.FAIL;
}
} }
@Override @Override
public void nativeClearLogicalAddress(long controllerPtr) { public int nativeAddLogicalAddress(int logicalAddress) {
HdmiCecController.nativeClearLogicalAddress(controllerPtr); try {
return mHdmiCec.addLogicalAddress(logicalAddress);
} catch (RemoteException e) {
HdmiLogger.error("Failed to add a logical address : ", e);
return Result.FAILURE_INVALID_ARGS;
}
} }
@Override @Override
public int nativeGetPhysicalAddress(long controllerPtr) { public void nativeClearLogicalAddress() {
return HdmiCecController.nativeGetPhysicalAddress(controllerPtr); try {
mHdmiCec.clearLogicalAddress();
} catch (RemoteException e) {
HdmiLogger.error("Failed to clear logical address : ", e);
}
} }
@Override @Override
public int nativeGetVersion(long controllerPtr) { public int nativeGetPhysicalAddress() {
return HdmiCecController.nativeGetVersion(controllerPtr); try {
mHdmiCec.getPhysicalAddress(this);
return mPhysicalAddress;
} catch (RemoteException e) {
HdmiLogger.error("Failed to get physical address : ", e);
return INVALID_PHYSICAL_ADDRESS;
}
} }
@Override @Override
public int nativeGetVendorId(long controllerPtr) { public int nativeGetVersion() {
return HdmiCecController.nativeGetVendorId(controllerPtr); try {
return mHdmiCec.getCecVersion();
} catch (RemoteException e) {
HdmiLogger.error("Failed to get cec version : ", e);
return Result.FAILURE_UNKNOWN;
}
} }
@Override @Override
public HdmiPortInfo[] nativeGetPortInfos(long controllerPtr) { public int nativeGetVendorId() {
return HdmiCecController.nativeGetPortInfos(controllerPtr); try {
return mHdmiCec.getVendorId();
} catch (RemoteException e) {
HdmiLogger.error("Failed to get vendor id : ", e);
return Result.FAILURE_UNKNOWN;
}
} }
@Override @Override
public void nativeSetOption(long controllerPtr, int flag, boolean enabled) { public HdmiPortInfo[] nativeGetPortInfos() {
HdmiCecController.nativeSetOption(controllerPtr, flag, enabled); try {
ArrayList<android.hardware.tv.cec.V1_0.HdmiPortInfo> hdmiPortInfos =
mHdmiCec.getPortInfo();
HdmiPortInfo[] hdmiPortInfo = new HdmiPortInfo[hdmiPortInfos.size()];
int i = 0;
for (android.hardware.tv.cec.V1_0.HdmiPortInfo portInfo : hdmiPortInfos) {
hdmiPortInfo[i] = new HdmiPortInfo(portInfo.portId,
portInfo.type,
portInfo.physicalAddress,
portInfo.cecSupported,
false,
portInfo.arcSupported);
i++;
}
return hdmiPortInfo;
} catch (RemoteException e) {
HdmiLogger.error("Failed to get port information : ", e);
return null;
}
} }
@Override @Override
public void nativeSetLanguage(long controllerPtr, String language) { public void nativeSetOption(int flag, boolean enabled) {
HdmiCecController.nativeSetLanguage(controllerPtr, language); try {
mHdmiCec.setOption(flag, enabled);
} catch (RemoteException e) {
HdmiLogger.error("Failed to set option : ", e);
}
} }
@Override @Override
public void nativeEnableAudioReturnChannel(long controllerPtr, int port, boolean flag) { public void nativeSetLanguage(String language) {
HdmiCecController.nativeEnableAudioReturnChannel(controllerPtr, port, flag); try {
mHdmiCec.setLanguage(language);
} catch (RemoteException e) {
HdmiLogger.error("Failed to set language : ", e);
}
} }
@Override @Override
public boolean nativeIsConnected(long controllerPtr, int port) { public void nativeEnableAudioReturnChannel(int port, boolean flag) {
return HdmiCecController.nativeIsConnected(controllerPtr, port); try {
mHdmiCec.enableAudioReturnChannel(port, flag);
} catch (RemoteException e) {
HdmiLogger.error("Failed to enable/disable ARC : ", e);
}
}
@Override
public boolean nativeIsConnected(int port) {
try {
return mHdmiCec.isConnected(port);
} catch (RemoteException e) {
HdmiLogger.error("Failed to get connection info : ", e);
return false;
}
}
@Override
public void serviceDied(long cookie) {
if (cookie == HDMI_CEC_HAL_DEATH_COOKIE) {
HdmiLogger.error(TAG, "Service died cokkie : " + cookie + "; reconnecting");
connectToHal();
}
}
@Override
public void onValues(int result, short addr) {
if (result == Result.SUCCESS) {
synchronized (mLock) {
mPhysicalAddress = new Short(addr).intValue();
}
}
}
}
final class HdmiCecCallback extends IHdmiCecCallback.Stub {
@Override
public void onCecMessage(CecMessage message) throws RemoteException {
byte[] body = new byte[message.body.size()];
for (int i = 0; i < message.body.size(); i++) {
body[i] = message.body.get(i);
}
runOnServiceThread(
() -> handleIncomingCecCommand(message.initiator, message.destination, body));
}
@Override
public void onHotplugEvent(HotplugEvent event) throws RemoteException {
runOnServiceThread(() -> handleHotplug(event.portId, event.connected));
} }
} }

View File

@@ -71,6 +71,10 @@ final class HdmiLogger {
getLogger().errorInternal(toLogString(logMessage, objs)); getLogger().errorInternal(toLogString(logMessage, objs));
} }
static final void error(String logMessage, Exception e, Object... objs) {
getLogger().errorInternal(toLogString(logMessage + e, objs));
}
private void errorInternal(String logMessage) { private void errorInternal(String logMessage) {
String log = updateLog(mErrorTimingCache, logMessage); String log = updateLog(mErrorTimingCache, logMessage);
if (!log.isEmpty()) { if (!log.isEmpty()) {

View File

@@ -17,7 +17,6 @@ package com.android.server.hdmi;
import android.hardware.hdmi.HdmiPortInfo; import android.hardware.hdmi.HdmiPortInfo;
import android.hardware.tv.cec.V1_0.SendMessageResult; import android.hardware.tv.cec.V1_0.SendMessageResult;
import android.os.MessageQueue;
import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting;
import com.android.server.hdmi.HdmiCecController.NativeWrapper; import com.android.server.hdmi.HdmiCecController.NativeWrapper;
@@ -53,13 +52,16 @@ final class FakeNativeWrapper implements NativeWrapper {
private HdmiPortInfo[] mHdmiPortInfo = null; private HdmiPortInfo[] mHdmiPortInfo = null;
@Override @Override
public long nativeInit(HdmiCecController handler, MessageQueue messageQueue) { public String nativeInit() {
return 1L; return "[class or subclass of IHdmiCec]@Proxy";
} }
@Override
public void setCallback(HdmiCecController.HdmiCecCallback callback) {}
@Override @Override
public int nativeSendCecCommand( public int nativeSendCecCommand(
long controllerPtr, int srcAddress, int dstAddress, byte[] body) { int srcAddress, int dstAddress, byte[] body) {
if (body.length == 0) { if (body.length == 0) {
return mPollAddressResponse[dstAddress]; return mPollAddressResponse[dstAddress];
} else { } else {
@@ -69,30 +71,30 @@ final class FakeNativeWrapper implements NativeWrapper {
} }
@Override @Override
public int nativeAddLogicalAddress(long controllerPtr, int logicalAddress) { public int nativeAddLogicalAddress(int logicalAddress) {
return 0; return 0;
} }
@Override @Override
public void nativeClearLogicalAddress(long controllerPtr) {} public void nativeClearLogicalAddress() {}
@Override @Override
public int nativeGetPhysicalAddress(long controllerPtr) { public int nativeGetPhysicalAddress() {
return mMyPhysicalAddress; return mMyPhysicalAddress;
} }
@Override @Override
public int nativeGetVersion(long controllerPtr) { public int nativeGetVersion() {
return 0; return 0;
} }
@Override @Override
public int nativeGetVendorId(long controllerPtr) { public int nativeGetVendorId() {
return 0; return 0;
} }
@Override @Override
public HdmiPortInfo[] nativeGetPortInfos(long controllerPtr) { public HdmiPortInfo[] nativeGetPortInfos() {
if (mHdmiPortInfo == null) { if (mHdmiPortInfo == null) {
mHdmiPortInfo = new HdmiPortInfo[1]; mHdmiPortInfo = new HdmiPortInfo[1];
mHdmiPortInfo[0] = new HdmiPortInfo(1, 1, 0x1000, true, true, true); mHdmiPortInfo[0] = new HdmiPortInfo(1, 1, 0x1000, true, true, true);
@@ -101,16 +103,16 @@ final class FakeNativeWrapper implements NativeWrapper {
} }
@Override @Override
public void nativeSetOption(long controllerPtr, int flag, boolean enabled) {} public void nativeSetOption(int flag, boolean enabled) {}
@Override @Override
public void nativeSetLanguage(long controllerPtr, String language) {} public void nativeSetLanguage(String language) {}
@Override @Override
public void nativeEnableAudioReturnChannel(long controllerPtr, int port, boolean flag) {} public void nativeEnableAudioReturnChannel(int port, boolean flag) {}
@Override @Override
public boolean nativeIsConnected(long controllerPtr, int port) { public boolean nativeIsConnected(int port) {
return false; return false;
} }