Connect multiple devices to one device via Bluetooth

前端 未结 7 638
夕颜
夕颜 2021-01-30 11:27

I would like to create a game, where you must connect multiple devices (4+) to a main device (ex. a tablet) via Bluetooth. There would be two apps, a main one to which all data

相关标签:
7条回答
  • 2021-01-30 11:35

    This is the class where the connection is established and messages are recieved. Make sure to pair the devices before you run the application. If you want to have a slave/master connection, where each slave can only send messages to the master , and the master can broadcast messages to all slaves. You should only pair the master with each slave , but you shouldn't pair the slaves together.

        package com.example.gaby.coordinatorv1;
        import java.io.DataInputStream;
        import java.io.IOException;
        import java.io.InputStream;
        import java.io.OutputStream;
        import java.util.ArrayList;
        import java.util.HashMap;
        import java.util.Set;
        import java.util.UUID;
        import android.bluetooth.BluetoothAdapter;
        import android.bluetooth.BluetoothDevice;
        import android.bluetooth.BluetoothServerSocket;
        import android.bluetooth.BluetoothSocket;
        import android.content.Context;
        import android.os.Bundle;
        import android.os.Handler;
        import android.os.Message;
        import android.util.Log;
        import android.widget.Toast;
    
        public class Piconet {
    
    
            private final static String TAG = Piconet.class.getSimpleName();
    
            // Name for the SDP record when creating server socket
            private static final String PICONET = "ANDROID_PICONET_BLUETOOTH";
    
            private final BluetoothAdapter mBluetoothAdapter;
    
            // String: device address
            // BluetoothSocket: socket that represent a bluetooth connection
            private HashMap<String, BluetoothSocket> mBtSockets;
    
            // String: device address
            // Thread: thread for connection
            private HashMap<String, Thread> mBtConnectionThreads;
    
            private ArrayList<UUID> mUuidList;
    
            private ArrayList<String> mBtDeviceAddresses;
    
            private Context context;
    
    
            private Handler handler = new Handler() {
                public void handleMessage(Message msg) {
                    switch (msg.what) {
                        case 1:
                            Toast.makeText(context, msg.getData().getString("msg"), Toast.LENGTH_SHORT).show();
                            break;
                        default:
                            break;
                    }
                };
            };
    
            public Piconet(Context context) {
                this.context = context;
    
                mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
    
                mBtSockets = new HashMap<String, BluetoothSocket>();
                mBtConnectionThreads = new HashMap<String, Thread>();
                mUuidList = new ArrayList<UUID>();
                mBtDeviceAddresses = new ArrayList<String>();
    
                // Allow up to 7 devices to connect to the server
                mUuidList.add(UUID.fromString("a60f35f0-b93a-11de-8a39-08002009c666"));
                mUuidList.add(UUID.fromString("54d1cc90-1169-11e2-892e-0800200c9a66"));
                mUuidList.add(UUID.fromString("6acffcb0-1169-11e2-892e-0800200c9a66"));
                mUuidList.add(UUID.fromString("7b977d20-1169-11e2-892e-0800200c9a66"));
                mUuidList.add(UUID.fromString("815473d0-1169-11e2-892e-0800200c9a66"));
                mUuidList.add(UUID.fromString("503c7434-bc23-11de-8a39-0800200c9a66"));
                mUuidList.add(UUID.fromString("503c7435-bc23-11de-8a39-0800200c9a66"));
    
                Thread connectionProvider = new Thread(new ConnectionProvider());
                connectionProvider.start();
    
            }
    
    
    
            public void startPiconet() {
                Log.d(TAG, " -- Looking devices -- ");
                // The devices must be already paired
                Set<BluetoothDevice> pairedDevices = mBluetoothAdapter
                        .getBondedDevices();
                if (pairedDevices.size() > 0) {
                    for (BluetoothDevice device : pairedDevices) {
                        // X , Y and Z are the Bluetooth name (ID) for each device you want to connect to
                        if (device != null && (device.getName().equalsIgnoreCase("X") || device.getName().equalsIgnoreCase("Y")
                                || device.getName().equalsIgnoreCase("Z") || device.getName().equalsIgnoreCase("M"))) {
                            Log.d(TAG, " -- Device " + device.getName() + " found --");
                            BluetoothDevice remoteDevice = mBluetoothAdapter
                                    .getRemoteDevice(device.getAddress());
                            connect(remoteDevice);
                        }
                    }
                } else {
                    Toast.makeText(context, "No paired devices", Toast.LENGTH_SHORT).show();
                }
            }
    
            private class ConnectionProvider implements Runnable {
                @Override
                public void run() {
                    try {
                        for (int i=0; i<mUuidList.size(); i++) {
                            BluetoothServerSocket myServerSocket = mBluetoothAdapter
                                    .listenUsingRfcommWithServiceRecord(PICONET, mUuidList.get(i));
                            Log.d(TAG, " ** Opened connection for uuid " + i + " ** ");
    
                            // This is a blocking call and will only return on a
                            // successful connection or an exception
                            Log.d(TAG, " ** Waiting connection for socket " + i + " ** ");
                            BluetoothSocket myBTsocket = myServerSocket.accept();
                            Log.d(TAG, " ** Socket accept for uuid " + i + " ** ");
                            try {
                                // Close the socket now that the
                                // connection has been made.
                                myServerSocket.close();
                            } catch (IOException e) {
                                Log.e(TAG, " ** IOException when trying to close serverSocket ** ");
                            }
    
                            if (myBTsocket != null) {
                                String address = myBTsocket.getRemoteDevice().getAddress();
    
                                mBtSockets.put(address, myBTsocket);
                                mBtDeviceAddresses.add(address);
    
                                Thread mBtConnectionThread = new Thread(new BluetoohConnection(myBTsocket));
                                mBtConnectionThread.start();
    
                                Log.i(TAG," ** Adding " + address + " in mBtDeviceAddresses ** ");
                                mBtConnectionThreads.put(address, mBtConnectionThread);
                            } else {
                                Log.e(TAG, " ** Can't establish connection ** ");
                            }
                        }
                    } catch (IOException e) {
                        Log.e(TAG, " ** IOException in ConnectionService:ConnectionProvider ** ", e);
                    }
                }
            }
    
            private class BluetoohConnection implements Runnable {
                private String address;
    
                private final InputStream mmInStream;
    
                public BluetoohConnection(BluetoothSocket btSocket) {
    
                    InputStream tmpIn = null;
    
                    try {
                        tmpIn = new DataInputStream(btSocket.getInputStream());
                    } catch (IOException e) {
                        Log.e(TAG, " ** IOException on create InputStream object ** ", e);
                    }
                    mmInStream = tmpIn;
                }
                @Override
                public void run() {
                    byte[] buffer = new byte[1];
                    String message = "";
                    while (true) {
    
                        try {
                            int readByte = mmInStream.read();
                            if (readByte == -1) {
                                Log.e(TAG, "Discarting message: " + message);
                                message = "";
                                continue;
                            }
                            buffer[0] = (byte) readByte;
    
                            if (readByte == 0) { // see terminateFlag on write method
                                onReceive(message);
                                message = "";
                            } else { // a message has been recieved
                                message += new String(buffer, 0, 1);
                            }
                        } catch (IOException e) {
                            Log.e(TAG, " ** disconnected ** ", e);
                        }
    
                        mBtDeviceAddresses.remove(address);
                        mBtSockets.remove(address);
                        mBtConnectionThreads.remove(address);
                    }
                }
            }
    
            /**
             * @param receiveMessage
             */
            private void onReceive(String receiveMessage) {
                if (receiveMessage != null && receiveMessage.length() > 0) {
                    Log.i(TAG, " $$$$ " + receiveMessage + " $$$$ ");
                    Bundle bundle = new Bundle();
                    bundle.putString("msg", receiveMessage);
                    Message message = new Message();
                    message.what = 1;
                    message.setData(bundle);
                    handler.sendMessage(message);
                }
            }
    
            /**
             * @param device
             * @param uuidToTry
             * @return
             */
            private BluetoothSocket getConnectedSocket(BluetoothDevice device, UUID uuidToTry) {
                BluetoothSocket myBtSocket;
                try {
                    myBtSocket = device.createRfcommSocketToServiceRecord(uuidToTry);
                    myBtSocket.connect();
                    return myBtSocket;
                } catch (IOException e) {
                    Log.e(TAG, "IOException in getConnectedSocket", e);
                }
                return null;
            }
    
            private void connect(BluetoothDevice device) {
                BluetoothSocket myBtSocket = null;
                String address = device.getAddress();
                BluetoothDevice remoteDevice = mBluetoothAdapter.getRemoteDevice(address);
                // Try to get connection through all uuids available
                for (int i = 0; i < mUuidList.size() && myBtSocket == null; i++) {
                    // Try to get the socket 2 times for each uuid of the list
                    for (int j = 0; j < 2 && myBtSocket == null; j++) {
                        Log.d(TAG, " ** Trying connection..." + j + " with " + device.getName() + ", uuid " + i + "...** ");
                        myBtSocket = getConnectedSocket(remoteDevice, mUuidList.get(i));
                        if (myBtSocket == null) {
                            try {
                                Thread.sleep(200);
                            } catch (InterruptedException e) {
                                Log.e(TAG, "InterruptedException in connect", e);
                            }
                        }
                    }
                }
                if (myBtSocket == null) {
                    Log.e(TAG, " ** Could not connect ** ");
                    return;
                }
                Log.d(TAG, " ** Connection established with " + device.getName() +"! ** ");
                mBtSockets.put(address, myBtSocket);
                mBtDeviceAddresses.add(address);
                Thread mBluetoohConnectionThread = new Thread(new BluetoohConnection(myBtSocket));
                mBluetoohConnectionThread.start();
                mBtConnectionThreads.put(address, mBluetoohConnectionThread);
    
            }
    
            public void bluetoothBroadcastMessage(String message) {
                //send message to all except Id
                for (int i = 0; i < mBtDeviceAddresses.size(); i++) {
                    sendMessage(mBtDeviceAddresses.get(i), message);
                }
            }
    
            private void sendMessage(String destination, String message) {
                BluetoothSocket myBsock = mBtSockets.get(destination);
                if (myBsock != null) {
                    try {
                        OutputStream outStream = myBsock.getOutputStream();
                        final int pieceSize = 16;
                        for (int i = 0; i < message.length(); i += pieceSize) {
                            byte[] send = message.substring(i,
                                    Math.min(message.length(), i + pieceSize)).getBytes();
                            outStream.write(send);
                        }
                        // we put at the end of message a character to sinalize that message
                        // was finished
                        byte[] terminateFlag = new byte[1];
                        terminateFlag[0] = 0; // ascii table value NULL (code 0)
                        outStream.write(new byte[1]);
                    } catch (IOException e) {
                        Log.d(TAG, "line 278", e);
                    }
                }
            }
    
        }
    

    Your main activity should be as follow :

    package com.example.gaby.coordinatorv1;
    
    import android.app.Activity;
    import android.os.Bundle;
    import android.view.View;
    import android.widget.Button;
    
    public class MainActivity extends Activity {
    
        private Button discoveryButton;
        private Button messageButton;
    
        private Piconet piconet;
    
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            piconet = new Piconet(getApplicationContext());
    
            messageButton = (Button) findViewById(R.id.messageButton);
            messageButton.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    piconet.bluetoothBroadcastMessage("Hello World---*Gaby Bou Tayeh*");
                }
            });
    
            discoveryButton = (Button) findViewById(R.id.discoveryButton);
            discoveryButton.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    piconet.startPiconet();
                }
            });
    
        }
    
    }
    

    And here's the XML Layout :

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity" >
    
    <Button
        android:id="@+id/discoveryButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Discover"
        />
    
    <Button
        android:id="@+id/messageButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Send message"
        />
    

    Do not forget to add the following permissions to your Manifest File :

        <uses-permission android:name="android.permission.BLUETOOTH" />
    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
    
    0 讨论(0)
  • 2021-01-30 11:35

    I think its possible provided if it is a serial data in broadcasting method. but you will not be able to transfer any voice/audio data to the other slave device. As per Bluetooth 4.0, the protocol does not support this. However there is a improvement going on to broadcast the audio/voice data.

    0 讨论(0)
  • 2021-01-30 11:36

    I don't think it's possible with bluetooth, but you could try looking into WiFi Peer-to-Peer,
    which allows one-to-many connections.

    0 讨论(0)
  • 2021-01-30 11:37

    Yes, that is possible. At its lowest level Bluetooth allows you to connect up to 7 devices to one master device. I have done this and it has worked well for me, but only on other platforms (linux) where I had lots of manual control - I've never tried that on Android and there are some possible complications so you will need to do some testing to be certain.

    One of the issues is that you need the tablet to the master and Android doesn't give you any explicit control of this. It is likely that this won't be a problem because * the tablet will automatically become the master when you try to connect a second device to it, or * you will be able to control the master/slave roles by how you setup your socket connection

    I will caution though that most apps using Bluetooth on mobile are not attempting many simultaneous connections and Bluetooth can be a bit fragile, e.g. what if two devices already have a Bluetooth connection for some other app - how might that affect the roles?

    0 讨论(0)
  • 2021-01-30 11:39

    Bluetooth 4.0 Allows you in a Bluetooth piconet one master can communicate up to 7 active slaves, there can be some other devices up to 248 devices which sleeping.

    Also you can use some slaves as bridge to participate with more devices.

    0 讨论(0)
  • 2021-01-30 11:44

    Yes you can do so and I have created a library for the same.
    This allows you to connect up-to four devices to the main server device creating different channels for each client and running interactions on different threads.
    To use this library simple add compile com.mdg.androble:library:0.1.2 in dependency section of your build.gradle .

    0 讨论(0)
提交回复
热议问题