I'm trying to write audio application for Bluetooth headphones under Linux (over BlueZ stack). It's embedded version so I want to use only C++ and BlueZ without any DBus or Python. For now I could successfully inquire devices and pair with them. But after few seconds connection gets lost.
As far as I understand - there's should be some link established after pairing to prevent disconnection. But I can't figure out what am I doing wrong..
Here is my code sample:
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;
}
Okay, thanks to all who helped me (yes, you Google and you Github). The sollution was to init all SDP routine to get required channel for required protocol befor connecting. For now RFCOMM connection establishing successfully