Linux 下的 C++ 蓝牙耳机超过 BlueZ
C++ Bluetooth headphones under Linux over BlueZ
我正尝试在 Linux(通过 BlueZ 堆栈)下为蓝牙耳机编写音频应用程序。它是嵌入式版本,所以我只想使用 C++ 和 BlueZ,而不使用任何 DBus 或 Python。现在我可以成功查询设备并与它们配对。但几秒钟后连接断开。
据我了解 - 配对后应该建立一些 link 以防止断开连接。但是我不知道我做错了什么..
这是我的代码示例:
int main(int argc, char** argv) {
int max_rsp, num_rsp;
int dev_id, sock, len, flags;
inquiry_info* ii = NULL;
char addr[19] = {0};
char name[248] = {0};
uint8_t cod[3] = {0};
const char localName[8] = "TestKIT";
dev_id = hci_get_route(NULL);
sock = hci_open_dev(dev_id);
if (dev_id < 0 || sock < 0) {
std::cerr << "HCI open device:\t\t" << strerror(errno) << std::endl;
return -1;
}
hci_write_local_name(sock, localName, 8);
std::cout << std::endl;
std::cout << "Device name set to:\t\"" << localName << "\"" << std::endl;
len = 8;
max_rsp = 255;
flags = IREQ_CACHE_FLUSH;
ii = new inquiry_info[max_rsp * sizeof(inquiry_info)];
num_rsp = hci_inquiry(dev_id, len, max_rsp, NULL, &ii, flags);
if (num_rsp < 0) {
std::cerr << "HCI inquiry: " << strerror(errno) << std::endl;
}
std::cout << std::endl;
std::cout << "=========================================================================" << std::endl;
std::cout << " #\t" << "BTA\t\t\t" << "Name\t\t\t\t" << "COD" << std::endl;
std::cout << "-------------------------------------------------------------------------" << std::endl;
for (int i = 0; i < num_rsp; ++i) {
ba2str(&ii[i].bdaddr, addr);
memset(name, 0, sizeof(name));
if (hci_read_remote_name(sock, &ii[i].bdaddr, sizeof(name), name, 0) < 0) {
strcpy(name, "[unknown]");
}
hci_read_class_of_dev(sock, cod, 0);
std::cout << std::setw(2) << std::setfill(' ') << i + 1 << '.' << "\t";
std::cout << addr << "\t";
std::cout << std::setw(30) << std::left << name << "\t" << std::right;
std::cout << "0x";
std::cout << std::setw(2) << std::setfill('0') << std::hex << static_cast<unsigned int>(cod[2]);
std::cout << std::setw(2) << std::setfill('0') << std::hex << static_cast<unsigned int>(cod[1]);
std::cout << std::setw(2) << std::setfill('0') << std::hex << static_cast<unsigned int>(cod[0]);
std::cout << std::endl;
}
std::cout << "=========================================================================" << std::endl;
unsigned int userChoise = 0;
std::cout << std::endl;
std::cout << "Device to connect: ";
std::cin >> userChoise;
uint16_t handle;
unsigned int ptype = HCI_DM1 | HCI_DM3 | HCI_DM5 | HCI_DH1 | HCI_DH3 | HCI_DH5;
if (userChoise > 0 && userChoise <= num_rsp) {
std::cout << "Connecting to device #" << userChoise << " ..." << std::endl;
std::cout << std::endl;
if (hci_create_connection(sock, &ii[userChoise - 1].bdaddr, htobs(ptype), 0, 0, &handle, 0) < 0) {
std::cerr << "HCI create connection:\t" << strerror(errno) << std::endl;
} else {
std::cout << "Connection:\t\tOK" << std::endl;
}
if (hci_authenticate_link(sock, handle, 0) < 0) {
std::cerr << "HCI authenticate connection:\t" << strerror(errno) << std::endl;
} else {
std::cout << "Authentication:\t\tOK" << std::endl;
}
if (hci_encrypt_link(sock, handle, 1, 0) < 0) {
std::cerr << "HCI encrypt connection:\t" << strerror(errno) << std::endl;
} else {
std::cout << "Encryption:\t\tOK" << std::endl;
}
} else {
std::cout << "Wrong device number: " << userChoise << " (should be ";
if (num_rsp > 1) {
std::cout << "in range [1 .. " << num_rsp << "]";
} else {
std::cout << "1";
}
std::cout << ")" << std::endl;
}
hci_close_dev(sock);
close(sock);
// Connection to prevent disconnect
struct sockaddr_l2 rAddr;
int sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);
if (sk < 0) {
std::cerr << "Socket:\t" << strerror(errno) << std::endl;
}
memset(&rAddr, 0, sizeof(rAddr));
rAddr.l2_family = AF_BLUETOOTH;
rAddr.l2_psm = 0x1001;
rAddr.l2_bdaddr = ii[userChoise - 1].bdaddr;
if (connect(sk, (struct sockaddr *) &rAddr, sizeof(rAddr)) < 0 ) {
std::cerr << "Connect:\t" << strerror(errno) << std::endl;
}
std::cout << "Socket "sk": " << sk << std::endl;
delete [] ii;
ii = NULL;
return 0;
}
好的,找到了解决方案 - 它是在连接之前初始化所有 SDP 例程以获取所需协议所需的通道。
目前RFCOMM连接建立成功。
这是它目前的工作方式:C++ example form my GitHub。
P.S。注意-这个项目现在没有维护,因为我没有足够的时间。不过以后可能会变
我正尝试在 Linux(通过 BlueZ 堆栈)下为蓝牙耳机编写音频应用程序。它是嵌入式版本,所以我只想使用 C++ 和 BlueZ,而不使用任何 DBus 或 Python。现在我可以成功查询设备并与它们配对。但几秒钟后连接断开。
据我了解 - 配对后应该建立一些 link 以防止断开连接。但是我不知道我做错了什么..
这是我的代码示例:
int main(int argc, char** argv) {
int max_rsp, num_rsp;
int dev_id, sock, len, flags;
inquiry_info* ii = NULL;
char addr[19] = {0};
char name[248] = {0};
uint8_t cod[3] = {0};
const char localName[8] = "TestKIT";
dev_id = hci_get_route(NULL);
sock = hci_open_dev(dev_id);
if (dev_id < 0 || sock < 0) {
std::cerr << "HCI open device:\t\t" << strerror(errno) << std::endl;
return -1;
}
hci_write_local_name(sock, localName, 8);
std::cout << std::endl;
std::cout << "Device name set to:\t\"" << localName << "\"" << std::endl;
len = 8;
max_rsp = 255;
flags = IREQ_CACHE_FLUSH;
ii = new inquiry_info[max_rsp * sizeof(inquiry_info)];
num_rsp = hci_inquiry(dev_id, len, max_rsp, NULL, &ii, flags);
if (num_rsp < 0) {
std::cerr << "HCI inquiry: " << strerror(errno) << std::endl;
}
std::cout << std::endl;
std::cout << "=========================================================================" << std::endl;
std::cout << " #\t" << "BTA\t\t\t" << "Name\t\t\t\t" << "COD" << std::endl;
std::cout << "-------------------------------------------------------------------------" << std::endl;
for (int i = 0; i < num_rsp; ++i) {
ba2str(&ii[i].bdaddr, addr);
memset(name, 0, sizeof(name));
if (hci_read_remote_name(sock, &ii[i].bdaddr, sizeof(name), name, 0) < 0) {
strcpy(name, "[unknown]");
}
hci_read_class_of_dev(sock, cod, 0);
std::cout << std::setw(2) << std::setfill(' ') << i + 1 << '.' << "\t";
std::cout << addr << "\t";
std::cout << std::setw(30) << std::left << name << "\t" << std::right;
std::cout << "0x";
std::cout << std::setw(2) << std::setfill('0') << std::hex << static_cast<unsigned int>(cod[2]);
std::cout << std::setw(2) << std::setfill('0') << std::hex << static_cast<unsigned int>(cod[1]);
std::cout << std::setw(2) << std::setfill('0') << std::hex << static_cast<unsigned int>(cod[0]);
std::cout << std::endl;
}
std::cout << "=========================================================================" << std::endl;
unsigned int userChoise = 0;
std::cout << std::endl;
std::cout << "Device to connect: ";
std::cin >> userChoise;
uint16_t handle;
unsigned int ptype = HCI_DM1 | HCI_DM3 | HCI_DM5 | HCI_DH1 | HCI_DH3 | HCI_DH5;
if (userChoise > 0 && userChoise <= num_rsp) {
std::cout << "Connecting to device #" << userChoise << " ..." << std::endl;
std::cout << std::endl;
if (hci_create_connection(sock, &ii[userChoise - 1].bdaddr, htobs(ptype), 0, 0, &handle, 0) < 0) {
std::cerr << "HCI create connection:\t" << strerror(errno) << std::endl;
} else {
std::cout << "Connection:\t\tOK" << std::endl;
}
if (hci_authenticate_link(sock, handle, 0) < 0) {
std::cerr << "HCI authenticate connection:\t" << strerror(errno) << std::endl;
} else {
std::cout << "Authentication:\t\tOK" << std::endl;
}
if (hci_encrypt_link(sock, handle, 1, 0) < 0) {
std::cerr << "HCI encrypt connection:\t" << strerror(errno) << std::endl;
} else {
std::cout << "Encryption:\t\tOK" << std::endl;
}
} else {
std::cout << "Wrong device number: " << userChoise << " (should be ";
if (num_rsp > 1) {
std::cout << "in range [1 .. " << num_rsp << "]";
} else {
std::cout << "1";
}
std::cout << ")" << std::endl;
}
hci_close_dev(sock);
close(sock);
// Connection to prevent disconnect
struct sockaddr_l2 rAddr;
int sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);
if (sk < 0) {
std::cerr << "Socket:\t" << strerror(errno) << std::endl;
}
memset(&rAddr, 0, sizeof(rAddr));
rAddr.l2_family = AF_BLUETOOTH;
rAddr.l2_psm = 0x1001;
rAddr.l2_bdaddr = ii[userChoise - 1].bdaddr;
if (connect(sk, (struct sockaddr *) &rAddr, sizeof(rAddr)) < 0 ) {
std::cerr << "Connect:\t" << strerror(errno) << std::endl;
}
std::cout << "Socket "sk": " << sk << std::endl;
delete [] ii;
ii = NULL;
return 0;
}
好的,找到了解决方案 - 它是在连接之前初始化所有 SDP 例程以获取所需协议所需的通道。 目前RFCOMM连接建立成功。
这是它目前的工作方式:C++ example form my GitHub。
P.S。注意-这个项目现在没有维护,因为我没有足够的时间。不过以后可能会变