BrainBand を 2 台接続する
Android で Bluetooth を使うを書いてから随分と時間が経ってしまいましたが、ちょっとハマっておりました。
BrainBand を追加で 1 台購入して、2 台接続を試してみたら動かないのです。1 台だけを接続する分には問題ないのですが、2 台目を接続しようとすると下記の部分で Service discovery failed. となってしまいます。
device.createRfcommSocketToServiceRecord(SPP_UUID);
下記の情報により解決はされました。
最終的なコードは下記のようになりました。
public class BluetoothService { private static final UUID SPP_UUID = UUID .fromString("00001101-0000-1000-8000-00805F9B34FB"); private List<ClientThread> clients = new LinkedList<ClientThread>(); public synchronized void connect( BluetoothDevice device, ByteStreamParser parser) { try { ClientThread thread = new ClientThread(device, parser); thread.start(); clients.add(thread); } catch (IOException ex) { } } public synchronized void stop() { for (ClientThread thread : clients) { thread.cancel(); } clients.clear(); if ((LogTag.MASK & LogTag.FLAG_BLUETOOTH) != 0) Log.d(LogTag.S, "Clients was closed."); } public synchronized boolean isActive() { return clients.isEmpty() != false; } private class ClientThread extends Thread { private final ByteStreamParser listener; private final BluetoothSocket btSocket; ClientThread(BluetoothDevice device, ByteStreamParser listener) throws IOException { this.listener = listener; try { this.btSocket = createRfcommSocket(device); } catch (IOException ex) { Log.e(LogTag.S, "BluetoothSocket can't create, address = " + device.getAddress()); throw ex; } } private BluetoothSocket createRfcommSocket(BluetoothDevice device) throws IOException { /* This code cause 'Service discovery failed.' try { return device.createRfcommSocketToServiceRecord(SPP_UUID); } catch (IOException ex) { } */ try { Method m = device.getClass().getMethod( "createRfcommSocket", new Class[] { int.class }); return (BluetoothSocket)m.invoke(device, 1); } catch (Exception ex) { throw new IOException(ex.getMessage()); } } @Override public void run() { try { if ((LogTag.MASK & LogTag.FLAG_BLUETOOTH) != 0) Log.d(LogTag.S, "BluetoothSocket connect..."); btSocket.connect(); if ((LogTag.MASK & LogTag.FLAG_BLUETOOTH) != 0) Log.d(LogTag.S, "BluetoothSocket connected."); InputStream iStream = btSocket.getInputStream(); if ((LogTag.MASK & LogTag.FLAG_BLUETOOTH) != 0) Log.d(LogTag.S, "Listen stream..."); listener.parse(iStream); } catch (IOException ex) { Log.e(LogTag.S, ex.getMessage() + ", adderss = " + btSocket.getRemoteDevice().getAddress()); closeSocket(); } } void cancel() { closeSocket(); } private void closeSocket() { try { btSocket.close(); } catch (IOException ex) { Log.e(LogTag.S, "BluetoothSocket can't close, address = " + btSocket.getRemoteDevice().getAddress()); } } } }
ちょっと createRfcommSocket(int port) メソッドの呼び出しについて調べてみると、メソッド内部では BluetoothSocket.createRfcommSocket(String address, int port) を呼び出しています。createRfcommSocketToServiceRecord(UUID uuid) メソッドの呼び出しでも BluetoothSocket.createRfcommSocket(String address, int port) を呼び出しています。createRfcommSocketToServiceRecord では UUID から channel(=port) を探し出して BluetoothSocket を生成しています。これを channel を 1 固定にすると何故動くのかは不明。詳しい方いらっしゃったら教えてください。