Я работаю над приложением Qt C ++ для подключения Bluetooth Walketalkie (с кнопкой Push-To-Talk) к интегрированному устройству на основе встроенного Linux (Cortex-A9 Core). В мое устройство встроен адаптер Bluetooth 450-0159 с чипом Cypress / Broadcom CYW4343W / BCM4343W BT / WLAN. Я использую bluez-5.43 и bluez-alsa для подключения аудио сервисов bluetooth (A2DP и HFP). В моем приложении через библиотеки Bluetooth я могу правильно управлять адаптером Bluetooth, включением, выключением, сопряжением, но не могу подключить профили аудио Bluetooth. Таким образом, я реализовал следующие методы для подключения / отключения Bluetooth Walketalkie:
void BluetoothMgmt::connectDevice(QString address) {
QString command = "echo -e \"connect " + address + "\nquit\" | bluetoothctl";
QString output = execSystemCommand(command);
qDebug() << "OUTPUT EXEC SYSTEM COMMAND 1:" << output;
}
void BluetoothMgmt::disconnectDevice(QString address) {
QString command = "echo -e \"disconnect " + address + "\nquit\" | bluetoothctl";
QString output = execSystemCommand(command);
qDebug() << "OUTPUT EXEC SYSTEM COMMAND 1:" << output;
}
bool BluetoothMgmt::isDeviceConnected(QString address) {
bool connected = false;
QString command = "echo -e \"info " + address + "\nquit\" | bluetoothctl | grep Connected";
QString output = execSystemCommand(command);
qDebug() << "command output:" << output;
QStringList outputParts = output.split(WHITESPACE_CHAR);
QString status = outputParts.at(1);
if(status.contains("yes", Qt::CaseInsensitive))
connected = true;
return connected;
}
После вызова функции connectDevice мой Walketalkie правильно соединен с профилем A2DP и HFP, и я использую функцию isDeviceConnected, чтобы знатьСостояние устройства Bluetooth, если оно подключено или нет. Теперь я должен получить информацию о сокете RFCOMM, чтобы узнать состояние кнопки Push-To-Talk, если она нажата или нет, поэтому я реализовал этот код для подключения сокета RFCOMM:
QBluetoothSocket *socket;
socket = new QBluetoothSocket(QBluetoothServiceInfo::RfcommProtocol);
connect(socket, SIGNAL(connected()), this, SLOT(socketConnected()));
connect(socket, SIGNAL(disconnected()), this, SLOT(socketDisconnect()));
connect(socket, SIGNAL(readyRead()), this, SLOT(readSocket()));
connect(socket, SIGNAL(error(QBluetoothSocket::SocketError)), this, SLOT(socketError(QBluetoothSocket::SocketError)));
void BluetoothMgmt::socketConnected() {
qDebug() << "Socket connected:" << socket->peerName();
}
void BluetoothMgmt::socketDisconnect() {
qDebug() << "Socket disconnected";
}
void BluetoothMgmt::readSocket() {
QString message;
message = QString::fromLatin1(socket->readAll().data());
/* Code to parse Push-To-Talk button status */
}
void BluetoothMgmt::socketError(QBluetoothSocket::SocketError error) {
qDebug() << "Socket Error:" << socket->errorString();
}
/* To connect QBluetoothSocket */
int channel = 11
socket->connectToService(bluetooth_device_address, channel);
Чтобы узнать канал для подключения сокетаЯ запустил "sdptool records bluetooth_device_address" из командной строки. Вывод моего устройства следующий:
root@localhost:/dev# sdptool records 00:1F:82:3A:6E:5F
Service RecHandle: 0x10002
Service Class ID List:
"Audio Sink" (0x110b)
Protocol Descriptor List:
"L2CAP" (0x0100)
PSM: 25
"AVDTP" (0x0019)
uint16: 0x0103
Profile Descriptor List:
"Advanced Audio" (0x110d)
Version: 0x0103
Service RecHandle: 0x10003
Service Class ID List:
"PnP Information" (0x1200)
Service RecHandle: 0x10004
Service Class ID List:
"AV Remote" (0x110e)
"AV Remote Controller" (0x110f)
Protocol Descriptor List:
"L2CAP" (0x0100)
PSM: 23
"AVCTP" (0x0017)
uint16: 0x0104
Profile Descriptor List:
"AV Remote" (0x110e)
Version: 0x0106
Service RecHandle: 0x10005
Service Class ID List:
"AV Remote Target" (0x110c)
Protocol Descriptor List:
"L2CAP" (0x0100)
PSM: 23
"AVCTP" (0x0017)
uint16: 0x0104
Profile Descriptor List:
"AV Remote" (0x110e)
Version: 0x0106
Service Name: Headset
Service RecHandle: 0x1000a
Service Class ID List:
"Headset" (0x1108)
"" (0x1131)
"Generic Audio" (0x1203)
Protocol Descriptor List:
"L2CAP" (0x0100)
"RFCOMM" (0x0003)
Channel: 13
Language Base Attr List:
code_ISO639: 0x656e
encoding: 0x6a
base_offset: 0x100
Profile Descriptor List:
"Headset" (0x1108)
Version: 0x0102
Service Name: Hands-Free unit
Service RecHandle: 0x1000d
Service Class ID List:
"Handsfree" (0x111e)
"Generic Audio" (0x1203)
Protocol Descriptor List:
"L2CAP" (0x0100)
"RFCOMM" (0x0003)
Channel: 12
Language Base Attr List:
code_ISO639: 0x656e
encoding: 0x6a
base_offset: 0x100
Profile Descriptor List:
"Handsfree" (0x111e)
Version: 0x0105
Я использую канал номер 13 для соединения через сокет (RfcommProtocol).
Соединение RFCOMM работает нормально, и я могу читать Push-Состояние кнопки разговора. Проблема в том, что я могу подключить аудио сервисы (A2DP и HFP) или RFCOMM, но мне нужно подключить все профили одновременно. Как я могу прочитать сообщения RFCOMM после подключения устройства с помощью инструмента "bluetoothctl"? Единственный способ показать пакеты Bluetooth с сообщениями Push-To-Talk - это запустить «btmon» (монитор Bluetooth) из командной строки, но я верю, что это не правильный путь, и также я не знаю, как интегрировать его в мой c ++применение. К сожалению, с библиотеками Qt невозможно подключить аудио профили Bluetooth, по этой причине я использую инструмент «bluetoothctl». «Bluetoothctl», вероятно, отправляет сообщения dbus, которые позволяют «bluez-library» объединить профиль A2DP и SCO и создать виртуальную звуковую карту PCM с драйвером alsa. Какие-либо предложения? Спасибо за совет.