Не могу передать данные между двумя устройствами в Bluetooth

Ответить
Stormer
Сообщения: 39
Зарегистрирован: 13 сен 2013, 20:18

Не могу передать данные между двумя устройствами в Bluetooth

Сообщение Stormer » 08 июн 2014, 13:35

Пишу приложение, которое передает звук между двумя устройствами по Bluetooth.
В activity определено устройство:

Код: Выделить всё

private static BluetoothDevice device = null;
Это - устройство, к которому я коннекчусь. Также есть BroadcastReceiver, который изменяет значение device на реальное значение, когда коннектимся к удаленному устройству. Как только мы это устройство получаем, создаем сокет:

Код: Выделить всё

bluetoothSocket = device.createInsecureRfcommSocketToServiceRecord(java.util.UUID.fromString(UUID_STRING));
Также есть два буфера для отправки и принятия данных из потока/в поток:

Код: Выделить всё

private static byte[] receivedBuffer = new byte[BUFFER_SIZE];
private static byte[] sentBuffer = new byte[BUFFER_SIZE];
Т.о. когда я нажимаю "проигрывать", я пытаюсь записать звук с микрофона в выходной поток, а на аудиотрек записать звук с входного потока:

Код: Выделить всё

while (isRecording) {
   try {
      audioRecorder.read(sentBuffer, 0, BUFFER_AUDIO_SIZE);
      bluetoothSocket.getOutputStream().write(sentBuffer);
      bluetoothSocket.getInputStream().read(receivedBuffer);
      audioTrack.write(receivedBuffer, 0, BUFFER_AUDIO_SIZE);

   } catch (IOException e) {
   } catch (NullPointerException e) {
   }
}
Проблема в том, что несмотря на то, что .getOutputStream() и .getInputStream() выдают НЕ null-ы, на вызове методов write()/read() ловится NullPointerException(sentBuffer, receivedBuffer также не null-ы). Хотя в документации сказано, что они могут выдавать только:
IndexOutOfBoundsException if byteOffset < 0 || byteCount < 0 || byteOffset + byteCount > buffer.length.
IOException if the stream is closed or another IOException occurs.
Таким образом, звук не записывается и не проигрывается на двух устройствах.
Также, если поменять код на такой:

Код: Выделить всё

while (isRecording) {
   try {
      audioRecorder.read(sentBuffer, 0, BUFFER_AUDIO_SIZE);
      audioTrack.write(sentBuffer, 0, BUFFER_AUDIO_SIZE);

   } catch (IOException e) {
   } catch (NullPointerException e) {
   }
}
То звук успешно записывается и проигрывается сразу на одном и том же устройстве. А вот при передаче какая-то фигня...
Кто подскажет, что исправить?

Stormer
Сообщения: 39
Зарегистрирован: 13 сен 2013, 20:18

Re: Не могу передать данные между двумя устройствами в Bluet

Сообщение Stormer » 08 июн 2014, 16:38

В принципе нашёл,что надо делать

Код: Выделить всё

bluetoothSocket.connect();
Исключения выдавать перестало. Зато после того, как это делаешь, метод

Код: Выделить всё

bluetoothSocket.isConnected()
выдает false.
Т.о. проблема перешла в то, как правильно законнектиться к сокету, полученному от удаленного устройства.

Stormer
Сообщения: 39
Зарегистрирован: 13 сен 2013, 20:18

Re: Не могу передать данные между двумя устройствами в Bluet

Сообщение Stormer » 08 июн 2014, 20:28

UPD: эту тему тоже разрулил. Всё работает, когда одно устройство коннектится как клиент, другое как сервер. Теперь проблема в том, что ПОЧТИ НИКОГДА второе устройство не коннектится как сервер. 1 раз из 10 коннектится как сервер.
Соответственно звук от одного устройства к другому у меня идёт 1 раз из 10 запусков примерно, а то и меньше.

Как правильно создавать поток коннекта как сервер? Сейчас нить такая:

Код: Выделить всё

Thread connectedServerThread = new Thread() {
            public void run() {
                while (device == null) {
                    try {
                        sleep(10);
                    } catch (InterruptedException e) {
                    }
                }
                while (true) {
                    if (!isConnectedServer) {
                        try {
                            bluetoothServerSocket = mBluetoothAdapter.listenUsingRfcommWithServiceRecord("Bluetooth", java.util.UUID.fromString(UUID_STRING));
                            if (bluetoothServerSocket.accept() != null) {

                                bluetoothSocket = bluetoothServerSocket.accept();
                                isConnectedServer = true;
                                break;
                            }
                        } catch (IOException e) {
                            try {
                                bluetoothServerSocket.close();
                                isConnectedServer = false;

                            } catch (IOException e1) {
                            }

                        }
                        try {
                            sleep(1000);
                        } catch (InterruptedException e) {
                        }
                    }
                }
            }
        };
        connectedServerThread.start();
И еще: может кто знает, дуплексный вид связи через bluetooth в Android возможен? Или обязательно одно устройство в роли сервера, другое в роли клиента, и потоки идут однонаправленно (в выходной поток сервера пишем, из входного потока клиента принимаем)?

Stormer
Сообщения: 39
Зарегистрирован: 13 сен 2013, 20:18

Re: Не могу передать данные между двумя устройствами в Bluet

Сообщение Stormer » 09 июн 2014, 13:03

UPD: с проблемой коннекта тоже разобрался вчера ночью сам. Теперь вопрос один: можно ли двунаправленную связь делать. Или OutputStream идёт только от сервера, а InputStream принимает на клиенте, а обратно никак?

Igor-vrn
Сообщения: 3
Зарегистрирован: 15 май 2014, 15:10

Re: Не могу передать данные между двумя устройствами в Bluet

Сообщение Igor-vrn » 15 июн 2014, 15:48

Добрый день. Вы разрулили все проблемы с соединением?

Пишу небольшой bluetooth чат (к курсовой). Помогите.

Код: Выделить всё

public class BlueServer extends Thread {
	public static final int CONNECTION_BRING = 0x001000;
	public static final int TIMEOUT_SESSION = 0x000100;
	public static final int SERVER_SOCKET_OPENED_SUCCESFULLY = 0x00030;
	public static final int SERVER_SOCKET_OPENING_ERROR = 0x00040;
	public static final int SOCKET_IS_NOT_ACCEPTED = 0x00050;
	public static final int SOCKET_IS_ACCEPTED_WITHOUT_ERRORS = 0x00060;
	public static final int CONNECTION_IN_PROCESS = 0x00070;
	
    private final BluetoothServerSocket mmServerSocket;
    private final UUID CurrentUUID = UUID.randomUUID();
    private Handler h;
    

public BlueServer(BluetoothAdapter mBluetoothAdapter, Handler h) {
        BluetoothServerSocket tmp = null;
        this.h = h;
        try {
            tmp = mBluetoothAdapter.listenUsingRfcommWithServiceRecord("BlueXaos", CurrentUUID);;
            if(tmp != null) h.sendEmptyMessage(SERVER_SOCKET_OPENED_SUCCESFULLY);
            else h.sendEmptyMessage(SERVER_SOCKET_OPENING_ERROR);
        } catch (IOException e) {
        	h.sendEmptyMessage(SERVER_SOCKET_OPENING_ERROR);
        	e.printStackTrace();
        }
        mmServerSocket = tmp;
    }
 
    @Override
	public void run() {
    	h.sendEmptyMessage(CONNECTION_IN_PROCESS);
        BluetoothSocket socket = null;
        
        while (true) {
            try {
                socket = mmServerSocket.accept(); // ВОТ НА ЭТОЙ СТРОКЕ СРАЗУ ЛОВИТСЯ ОШИБКА
                h.sendEmptyMessage(SOCKET_IS_ACCEPTED_WITHOUT_ERRORS);
            } catch (IOException e) { // И ВЫПОЛНЯЕТСЯ ПЕРЕХВАТ ОШИБКИ
            	break;
            }
            if(socket == null) h.sendEmptyMessage(SOCKET_IS_NOT_ACCEPTED);
            // если соединение было подтверждено
            if (socket != null) {
            	h.obtainMessage(CONNECTION_BRING, socket).sendToTarget();
                try {
					mmServerSocket.close();
					return;
				} catch (IOException e) {}
                break;
            }
        }
    }

}
Код выполняется до socket.accept() и там срабатывает ошибка, перехватвается и выход из цикла. Код заимствовал из документации, точнее отсюда http://www.mobilab.ru/androiddev/blueto ... droid.html
Отправка сообщений на Handler - временная мера. Дебаггером отследил, где возникает ошибка.

Тут же, может вы поясните как здесь используется UUID? Прочитал в разных местах, но об этом пишут, как "само собой разумеется", а на дело черт знает.

Stormer
Сообщения: 39
Зарегистрирован: 13 сен 2013, 20:18

Re: Не могу передать данные между двумя устройствами в Bluet

Сообщение Stormer » 16 июн 2014, 11:55

Перехватывается именно IOException? Просто у меня лично в каких-то случаях и NullPointerException было.
А вообще, ПО-МОЕМУ, после того, как выполнился метод mmServerSocket.accept() , то в следующий раз при выполнении он уже не будет отдавать правильный результат. У меня так было кажись. Поэтому я забивал в цикл не while (true) {...}, а

Код: Выделить всё

isConnected = false;
while(!isConnected) {
    ...
       if (mmServerSocket.accept()!=null) {
           isConnected = true; 
           socket = mmServerSocket.accept();
       } 
Попробуйте так, по крайней мере. Если не прокатит, то отписывайтесь.

А про UUID и сам не знаю. Навскидку я понял, что для сервера и для клиента нужно, чтобы был один UUID.
У меня для сервера:

Код: Выделить всё

bluetoothServerSocket = mBluetoothAdapter.listenUsingRfcommWithServiceRecord("Bluetooth", java.util.UUID.fromString(UUID_STRING));
bluetoothSocket = bluetoothServerSocket.accept();
Для клиента:

Код: Выделить всё

bluetoothSocket = device.createRfcommSocketToServiceRecord(java.util.UUID.fromString(UUID_STRING));
Хотя с разными не экспериментировал опять же. Могу попробовать разные приделать. Если попробую, то отпишусь, что получилось))

Stormer
Сообщения: 39
Зарегистрирован: 13 сен 2013, 20:18

Re: Не могу передать данные между двумя устройствами в Bluet

Сообщение Stormer » 16 июн 2014, 19:59

Ой, т.е. я вам неправильно написал.
В общем строка mmServerSocket.accept() вообще должна выполняться один раз только.

А в том, что я написал, она выполняется 2 раза:

Код: Выделить всё

if (mmServerSocket.accept()!=null) { 
           isConnected = true;  
           socket = mmServerSocket.accept(); 
Первый раз в условии if, второй раз в теле. В общем accept() срабатывает только один раз. Дальше он выдает исключения. Поэтому нужно подправить вот так:

Код: Выделить всё

isConnected = false; 
while(!isConnected) { 
    ... 
       socket = mmServerSocket.accept(); 
       if (socket!=null) { 
           isConnected = true; 
       ...           
       }
    ...

Ответить