简体   繁体   English

通过蓝牙将多个设备连接到一个设备

[英]Connect multiple devices to one device via Bluetooth

I would like to create a game, where you must connect multiple devices (4+) to a main device (ex. a tablet) via Bluetooth. 我想创建一个游戏,您必须通过蓝牙将多个设备(4+)连接到主设备(例如平板电脑)。 There would be two apps, a main one to which all data would be send from the phones, and to the phones. 将有两个应用程序,一个主要的应用程序,所有数据将从手机发送到手机。 Is that even possible? 这甚至可能吗?

Yes, that is possible. 是的,这是可能的。 At its lowest level Bluetooth allows you to connect up to 7 devices to one master device. 在最低级别,蓝牙允许您将最多7个设备连接到一个主设备。 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. 我已经做到了这一点并且它对我有用,但只在我有很多手动控制的其他平台(linux)上 - 我从来没有在Android上试过这个并且有一些可能的复杂性所以你需要做一些测试待确认。

One of the issues is that you need the tablet to the master and Android doesn't give you any explicit control of this. 其中一个问题是你需要平板电脑到掌握,Android没有给你任何明确的控制。 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, eg what if two devices already have a Bluetooth connection for some other app - how might that affect the roles? 我会提醒大家,大多数在移动设备上使用蓝牙的应用程序并没有尝试多次同时连接,蓝牙可能有点脆弱,例如,如果两个设备已经有一些其他应用程序的蓝牙连接怎么办 - 这可能会影响角色?

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. 蓝牙4.0允许您在蓝牙微微网中一个主设备可以与多达7个活动从设备通信,其他一些设备可能有多达248个设备正在休眠。

Also you can use some slaves as bridge to participate with more devices. 您还可以使用一些从站作为桥接器来参与更多设备。

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.gradl e . 要使用此库,请在build.gradl e的依赖项部分中添加compile com.mdg.androble:library:0.1.2

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 : 这是XML布局:

<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" />

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. 根据蓝牙4.0,协议不支持此功能。 However there is a improvement going on to broadcast the audio/voice data. 然而,广播音频/语音数据有所改进。

That is partly possible (for max 2 devices), because device can be connected only to one other device same time. 这部分是可能的(对于最多2个设备),因为设备可以同时仅连接到另一个设备。 Better solution in your case will be create an TCP server which sends informations to other devices - but that, of course, requires internet connection. 在您的情况下,更好的解决方案是创建一个TCP服务器,将信息发送到其他设备 - 但这当然需要互联网连接。 Read also about Samsung Chord API - it provides functions which you need, but then every devices have to be connected to one and the same Wi-Fi network 另请阅读Samsung Chord API - 它提供了您需要的功能,但每个设备都必须连接到同一个Wi-Fi网络

I don't think it's possible with bluetooth, but you could try looking into WiFi Peer-to-Peer , 我不认为蓝牙是可能的,但你可以尝试研究WiFi Peer-to-Peer
which allows one-to-many connections. 允许一对多连接。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM