Android wiimote 套接字无法连接

标签 android bluetooth wiimote ouya

我正在尝试将 wiimote 连接到我的 OUYA(运行 Android 4.1.2)。我已经设法让 wiimotes 使用其他应用程序进行连接,例如 Bluez-IME , 所以我知道这是可能的,但我希望自己能够做到这一点

这是我目前所拥有的:

private void bloothoothConnect(final BluetoothAdapter mBluetoothAdapter){

    // Register the BroadcastReceiver
    IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
    filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_STARTED);
    filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
    registerReceiver(new BroadcastReceiver() {
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            // When discovery finds a device
            if (BluetoothDevice.ACTION_FOUND.equals(action)) {
                // Get the BluetoothDevice object from the Intent
                BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);               
                if(isWiiMote(device)){
                    mBluetoothAdapter.cancelDiscovery();
                    connectWiiMote(device);                     
                }
            }
        }
    }, filter);

    mBluetoothAdapter.startDiscovery();
}

private boolean isWiiMote(BluetoothDevice device){
    String name = device.getName();                 
    return name.equalsIgnoreCase("Nintendo RVL-CNT-01");        
}

private void connectWiiMote(final BluetoothDevice device){
    final int tickInterval = 30;
    WiimoteRunnable nWiiMote = new WiimoteRunnable(device, tickInterval){

        @Override
        protected void onButtonDown() { // TODO                         
        }};

    Thread nThread = new Thread(nWiiMote);
    nThread.start();    
}

private abstract class WiimoteRunnable implements Runnable{

    private BluetoothSocket socket;
    private long tickInterval;
    private byte[] buffer = new byte[1024];

    WiimoteRunnable(BluetoothDevice device, long tickInterval) {
        socket = createL2CAPBluetoothSocket(device);
        this.tickInterval = tickInterval;           
    }

    @SuppressLint("NewApi")
    @Override
    public void run() {

        try {
            if(!socket.isConnected()){
                // blocks here!
                socket.connect();
            }
            InputStream iStream = socket.getInputStream();

            while(socket.isConnected()){

                iStream.read(buffer);

                // do stuff with byte buffer here

                Thread.sleep(tickInterval);                                 
            }

        } catch (IOException e2) {
            closeSocket();
        } catch (InterruptedException e) {
            closeSocket();
            return;
        }

    }

    private void closeSocket(){         
        try {
            socket.close();
        } catch (IOException e) {
            return;
        }
    }

    // to be implemented later
    protected abstract void onButtonDown();

}


// see https://stackoverflow.com/questions/14761570/connecting-to-a-bluetooth-hid-device-mouse-using-l2cap

private static final int TYPE_L2CAP = 3;

/**
 * Create a BluetoothSocket using L2CAP protocol
 * Useful for HID Bluetooth devices
 * @param BluetoothDevice
 * @return BluetoothSocket
 */
@SuppressLint("NewApi")
private static BluetoothSocket createL2CAPBluetoothSocket(BluetoothDevice device){
  int type        = TYPE_L2CAP; // L2CAP protocol
  int fd          = -1;         // Create a new socket
  boolean auth    = false;      // No authentication
  boolean encrypt = false;      // Not encrypted
  int port        = 0;          // port to use (useless if UUID is given)

  ParcelUuid[] uuid = device.getUuids(); // Bluetooth UUID service
    if(uuid==null){
        if(!device.fetchUuidsWithSdp()){
            return null;
        } else {
            uuid = device.getUuids();
        }
    }


  try {
    Constructor<BluetoothSocket> constructor = BluetoothSocket.class.getDeclaredConstructor(
      int.class, int.class, boolean.class, boolean.class,
      BluetoothDevice.class, int.class, ParcelUuid.class);
    constructor.setAccessible(true);
    BluetoothSocket clientSocket = (BluetoothSocket) constructor.newInstance(
      type, fd, auth, encrypt, device, port, uuid[0]);
    return clientSocket;
  } catch (Exception e) {
    e.printStackTrace();
    return null;
  }
}

问题是当我到达 socket.connect() 时它会阻塞并且永远不会返回。套接字对象就在那里,在调试器中我可以看到它的所有数据。

我正在根据 Connecting to a bluetooth HID device (mouse) using L2CAP 获取套接字

最佳答案

您需要使用 channel 号(或代码中的端口号)而不是使用 L2CAP 套接字的 UUID。要连接到 wiimote,您需要分别打开用于控制(从您的应用程序到 wiimote 的命令)和数据(从 wiimote 到您的应用程序的输入) channel 的套接字。

private static final int CONTROL_CHANNEL = 0x11;
private static final int DATA_CHANNEL = 0x13;

private BluetoothSocket controlSocket;
private BluetoothSocket dataSocket;

private OutputStream os;
private InputStream is;

private static BluetoothSocket createL2CAPBluetoothSocket(BluetoothDevice device, final int channel) {
    int type = TYPE_L2CAP; // L2CAP protocol
    int fd = -1; // Create a new socket
    boolean auth = false; // No authentication
    boolean encrypt = false; // Not encrypted

    try {
        Constructor<BluetoothSocket> constructor = BluetoothSocket.class.getDeclaredConstructor(int.class,
                int.class, boolean.class, boolean.class, BluetoothDevice.class, int.class, ParcelUuid.class);
        constructor.setAccessible(true);
        BluetoothSocket clientSocket = (BluetoothSocket) constructor.newInstance(type, fd, auth, encrypt, device,
                channel, null);
        return clientSocket;
    } catch (Exception e) {
        e.printStackTrace();
        return null;
    }
}

void connect(BluetoothDevice device) {
    try {
        controlSocket = createL2CAPBluetoothSocket(device, CONTROL_CHANNEL);        
        controlSocket.connect();
        os = controlSocket.getOutputStream();

        dataSocket = createL2CAPBluetoothSocket(device, DATA_CHANNEL);
        dataSocket.connect();
        is = dataSocket.getInputStream();      

        // open transmit & receive threads for input and output streams appropriately

    } catch (Exception e) {
        e.printStackTrace();
    }
}

关于Android wiimote 套接字无法连接,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16882628/

相关文章:

android - 我可以在 Chrome for Android Lollipop 上试用网络蓝牙吗?

C# Wii Mote 手势识别

从wiimote中提取配对码的C代码,奇怪的结果

c# - Wiimote示例程序

android - Flutter:如何将变量从 StatelessWidget 传递到 StatefulWidget

java - Android JSON 解析 - 在错误的字符 0 处输入结束

swift - 在用户 200 米范围内构建近距离应用程序的最佳方法是什么?

android - 非静态如何在自定义微调器中使用 "getSystemService"

android - greendao 中主键短时出现 ClassCastException

Android BluetoothSocket OutputStream 无限写入 block