问题描述
我正在尝试将Wiimote连接到我的OUYA(运行Android 4.1.2).我设法让wiimotes使用其他应用程序进行连接,例如 Bluez-IME ,所以我知道这是有可能的,但我想自己能够做到
I'm trying to connect a wiimote to my OUYA (running Android 4.1.2). I've managed to get wiimotes to connect using other apps like Bluez-IME, so I know it is possible, but I'd like to be able to do it myself
这是我到目前为止所拥有的:
This is what I have so far:
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()
时,它会阻塞并且永远不会返回.套接字对象在那里,在调试器中,我可以看到它的所有数据.
The problem is when I get to socket.connect()
it blocks and never returns. The socket object is there and in the debugger I can see all the data for it.
推荐答案
不是使用L2CAP套接字的UUID,而是需要使用通道号(或代码中的端口号).要连接到wiimote,您需要分别打开用于控制(从应用程序到wiimote的命令)和数据(从wiimote到应用程序的输入)通道的套接字.
Instead of using the UUID for the L2CAP socket you need to use the channel number (or port number in your code). To connect to wiimote you need to open sockets separately for control (commands from your app to wiimote) and data (input from wiimote to your app) channels.
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套接字无法连接的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!