Linux Embedded - подключение профилей Bluetooth A2DP, HFP, разъем RFCOMM
Я работаю над приложением 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-To-Talk. Проблема в том, что я могу подключить аудиоуслуги (A2DP и HFP) или соединение RFCOMM, но мне нужно подключить все профили одновременно. Как я могу читать сообщения RFCOMM после подключения устройства с помощью инструмента "bluetoothctl"? Единственный способ показать пакеты Bluetooth с сообщениями Push-To-Talk - запустить "btmon" (монитор Bluetooth) из командной строки, но я считаю, что это неправильный способ, и также я не знаю, как интегрировать его в свой C++. заявление. К сожалению, с библиотеками Qt невозможно подключить аудио-профили Bluetooth, по этой причине я использую инструмент bluetoothctl. "Bluetoothctl", вероятно, отправляет сообщения dbus, разрешающие "bluez-library"для подключения профиля A2DP и SCO и создания виртуальной звуковой карты PCM с драйвером alsa. Какие-либо предложения? Спасибо за совет.