Linux Embedded - подключение блютуз профилей A2DP, HFP, разъем RFCOMM - PullRequest
0 голосов
/ 07 ноября 2019

Я работаю над приложением 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. Какие-либо предложения? Спасибо за совет.

...