mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-10-29 05:40:27 -04:00
spa: bluez: native: do not use spa_aprintf()
Instead of spa_aprintf(), convert `rfcomm_send_{cmd,query}`
to take a printf-style format string.
Furthermore, handle overflows and return errors from
`rfcomm_send_{cmd,reply}`. And make those functions
take an rfcomm as argument instead of any spa_source.
And match conversion specifiers to the actual types
in format strings.
This commit is contained in:
parent
c0e158aa0c
commit
48dbb4da3c
1 changed files with 107 additions and 77 deletions
|
|
@ -25,6 +25,7 @@
|
|||
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <stdarg.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
|
|
@ -245,36 +246,76 @@ static void rfcomm_free(struct rfcomm *rfcomm)
|
|||
free(rfcomm);
|
||||
}
|
||||
|
||||
static void rfcomm_send_cmd(struct spa_source *source, char *data)
|
||||
{
|
||||
struct rfcomm *rfcomm = source->data;
|
||||
struct impl *backend = rfcomm->backend;
|
||||
char message[256];
|
||||
ssize_t len;
|
||||
#define RFCOMM_MESSAGE_MAX_LENGTH 256
|
||||
|
||||
spa_log_debug(backend->log, NAME": RFCOMM >> %s", data);
|
||||
sprintf(message, "%s\n", data);
|
||||
len = write(source->fd, message, strlen(message));
|
||||
SPA_PRINTF_FUNC(2, 3)
|
||||
static ssize_t rfcomm_send_cmd(const struct rfcomm *rfcomm, const char *format, ...)
|
||||
{
|
||||
struct impl *backend = rfcomm->backend;
|
||||
char message[RFCOMM_MESSAGE_MAX_LENGTH + 1];
|
||||
ssize_t len;
|
||||
va_list args;
|
||||
|
||||
va_start(args, format);
|
||||
len = vsnprintf(message, RFCOMM_MESSAGE_MAX_LENGTH + 1, format, args);
|
||||
va_end(args);
|
||||
|
||||
if (len < 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (len > RFCOMM_MESSAGE_MAX_LENGTH)
|
||||
return -E2BIG;
|
||||
|
||||
spa_log_debug(backend->log, NAME": RFCOMM >> %s", message);
|
||||
|
||||
message[len] = '\n';
|
||||
/* `message` is no longer null-terminated */
|
||||
|
||||
len = write(rfcomm->source.fd, message, len + 1);
|
||||
/* we ignore any errors, it's not critical and real errors should
|
||||
* be caught with the HANGUP and ERROR events handled above */
|
||||
if (len < 0)
|
||||
if (len < 0) {
|
||||
len = -errno;
|
||||
spa_log_error(backend->log, NAME": RFCOMM write error: %s", strerror(errno));
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static int rfcomm_send_reply(struct spa_source *source, const char *data)
|
||||
SPA_PRINTF_FUNC(2, 3)
|
||||
static ssize_t rfcomm_send_reply(const struct rfcomm *rfcomm, const char *format, ...)
|
||||
{
|
||||
struct rfcomm *rfcomm = source->data;
|
||||
struct impl *backend = rfcomm->backend;
|
||||
char message[256];
|
||||
char message[RFCOMM_MESSAGE_MAX_LENGTH + 4];
|
||||
ssize_t len;
|
||||
va_list args;
|
||||
|
||||
spa_log_debug(backend->log, NAME": RFCOMM >> %s", data);
|
||||
sprintf(message, "\r\n%s\r\n", data);
|
||||
len = write(source->fd, message, strlen(message));
|
||||
va_start(args, format);
|
||||
len = vsnprintf(&message[2], RFCOMM_MESSAGE_MAX_LENGTH + 1, format, args);
|
||||
va_end(args);
|
||||
|
||||
if (len < 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (len > RFCOMM_MESSAGE_MAX_LENGTH)
|
||||
return -E2BIG;
|
||||
|
||||
spa_log_debug(backend->log, NAME": RFCOMM >> %s", &message[2]);
|
||||
|
||||
message[0] = '\r';
|
||||
message[1] = '\n';
|
||||
message[len + 2] = '\r';
|
||||
message[len + 3] = '\n';
|
||||
/* `message` is no longer null-terminated */
|
||||
|
||||
len = write(rfcomm->source.fd, message, len + 4);
|
||||
/* we ignore any errors, it's not critical and real errors should
|
||||
* be caught with the HANGUP and ERROR events handled above */
|
||||
if (len < 0)
|
||||
if (len < 0) {
|
||||
len = -errno;
|
||||
spa_log_error(backend->log, NAME": RFCOMM write error: %s", strerror(errno));
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
|
|
@ -325,22 +366,22 @@ static bool rfcomm_hsp_ag(struct spa_source *source, char* buf)
|
|||
if (sscanf(buf, "AT+VGS=%d", &gain) == 1) {
|
||||
if (gain <= SPA_BT_VOLUME_HS_MAX) {
|
||||
rfcomm_emit_volume_changed(rfcomm, SPA_BT_VOLUME_ID_TX, gain);
|
||||
rfcomm_send_reply(source, "OK");
|
||||
rfcomm_send_reply(rfcomm, "OK");
|
||||
} else {
|
||||
spa_log_debug(backend->log, NAME": RFCOMM receive unsupported VGS gain: %s", buf);
|
||||
rfcomm_send_reply(source, "ERROR");
|
||||
rfcomm_send_reply(rfcomm, "ERROR");
|
||||
}
|
||||
} else if (sscanf(buf, "AT+VGM=%d", &gain) == 1) {
|
||||
if (gain <= SPA_BT_VOLUME_HS_MAX) {
|
||||
if (!rfcomm->broken_mic_hw_volume)
|
||||
rfcomm_emit_volume_changed(rfcomm, SPA_BT_VOLUME_ID_RX, gain);
|
||||
rfcomm_send_reply(source, "OK");
|
||||
rfcomm_send_reply(rfcomm, "OK");
|
||||
} else {
|
||||
rfcomm_send_reply(source, "ERROR");
|
||||
rfcomm_send_reply(rfcomm, "ERROR");
|
||||
spa_log_debug(backend->log, NAME": RFCOMM receive unsupported VGM gain: %s", buf);
|
||||
}
|
||||
} else if (sscanf(buf, "AT+CKPD=%d", &dummy) == 1) {
|
||||
rfcomm_send_reply(source, "OK");
|
||||
rfcomm_send_reply(rfcomm, "OK");
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
|
@ -352,7 +393,7 @@ static bool rfcomm_send_volume_cmd(struct spa_source *source, int id)
|
|||
{
|
||||
struct rfcomm *rfcomm = source->data;
|
||||
struct spa_bt_transport_volume *t_volume;
|
||||
char *cmd;
|
||||
const char *format;
|
||||
int hw_volume;
|
||||
|
||||
if (!rfcomm_volume_enabled(rfcomm))
|
||||
|
|
@ -367,14 +408,14 @@ static bool rfcomm_send_volume_cmd(struct spa_source *source, int id)
|
|||
rfcomm->volumes[id].hw_volume = hw_volume;
|
||||
|
||||
if (id == SPA_BT_VOLUME_ID_TX)
|
||||
cmd = spa_aprintf("AT+VGM=%u", hw_volume);
|
||||
format = "AT+VGM=%d";
|
||||
else if (id == SPA_BT_VOLUME_ID_RX)
|
||||
cmd = spa_aprintf("AT+VGS=%u", hw_volume);
|
||||
format = "AT+VGS=%d";
|
||||
else
|
||||
spa_assert_not_reached();
|
||||
|
||||
rfcomm_send_cmd(source, cmd);
|
||||
free(cmd);
|
||||
rfcomm_send_cmd(rfcomm, format, hw_volume);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -616,7 +657,6 @@ static bool rfcomm_hfp_ag(struct spa_source *source, char* buf)
|
|||
|
||||
if (sscanf(buf, "AT+BRSF=%u", &features) == 1) {
|
||||
unsigned int ag_features = SPA_BT_HFP_AG_FEATURE_NONE;
|
||||
char *cmd;
|
||||
|
||||
/*
|
||||
* Determine device volume control. Some headsets only support control of
|
||||
|
|
@ -652,10 +692,8 @@ static bool rfcomm_hfp_ag(struct spa_source *source, char* buf)
|
|||
}
|
||||
|
||||
/* send reply to HF with the features supported by Audio Gateway (=computer) */
|
||||
cmd = spa_aprintf("+BRSF: %d", ag_features);
|
||||
rfcomm_send_reply(source, cmd);
|
||||
free(cmd);
|
||||
rfcomm_send_reply(source, "OK");
|
||||
rfcomm_send_reply(rfcomm, "+BRSF: %u", ag_features);
|
||||
rfcomm_send_reply(rfcomm, "OK");
|
||||
} else if (strncmp(buf, "AT+BAC=", 7) == 0) {
|
||||
/* retrieve supported codecs */
|
||||
/* response has the form AT+BAC=<codecID1>,<codecID2>,<codecIDx>
|
||||
|
|
@ -681,22 +719,22 @@ static bool rfcomm_hfp_ag(struct spa_source *source, char* buf)
|
|||
cntr++;
|
||||
}
|
||||
|
||||
rfcomm_send_reply(source, "OK");
|
||||
rfcomm_send_reply(rfcomm, "OK");
|
||||
} else if (strncmp(buf, "AT+CIND=?", 9) == 0) {
|
||||
rfcomm_send_reply(source, "+CIND:(\"service\",(0-1)),(\"call\",(0-1)),(\"callsetup\",(0-3)),(\"callheld\",(0-2))");
|
||||
rfcomm_send_reply(source, "OK");
|
||||
rfcomm_send_reply(rfcomm, "+CIND:(\"service\",(0-1)),(\"call\",(0-1)),(\"callsetup\",(0-3)),(\"callheld\",(0-2))");
|
||||
rfcomm_send_reply(rfcomm, "OK");
|
||||
} else if (strncmp(buf, "AT+CIND?", 8) == 0) {
|
||||
rfcomm_send_reply(source, "+CIND: 0,0,0,0");
|
||||
rfcomm_send_reply(source, "OK");
|
||||
rfcomm_send_reply(rfcomm, "+CIND: 0,0,0,0");
|
||||
rfcomm_send_reply(rfcomm, "OK");
|
||||
} else if (strncmp(buf, "AT+CMER", 7) == 0) {
|
||||
rfcomm->slc_configured = true;
|
||||
rfcomm_send_reply(source, "OK");
|
||||
rfcomm_send_reply(rfcomm, "OK");
|
||||
|
||||
/* switch codec to mSBC by sending unsolicited +BCS message */
|
||||
if (rfcomm->codec_negotiation_supported && rfcomm->msbc_supported_by_hfp) {
|
||||
spa_log_debug(backend->log, NAME": RFCOMM initial codec setup");
|
||||
rfcomm->hfp_ag_initial_codec_setup = HFP_AG_INITIAL_CODEC_SETUP_SEND;
|
||||
rfcomm_send_reply(&rfcomm->source, "+BCS: 2");
|
||||
rfcomm_send_reply(rfcomm, "+BCS: 2");
|
||||
codec_switch_start_timer(rfcomm, HFP_CODEC_SWITCH_INITIAL_TIMEOUT_MSEC);
|
||||
} else {
|
||||
rfcomm->transport = _transport_create(rfcomm);
|
||||
|
|
@ -712,7 +750,7 @@ static bool rfcomm_hfp_ag(struct spa_source *source, char* buf)
|
|||
|
||||
} else if (!rfcomm->slc_configured) {
|
||||
spa_log_warn(backend->log, NAME": RFCOMM receive command before SLC completed: %s", buf);
|
||||
rfcomm_send_reply(source, "ERROR");
|
||||
rfcomm_send_reply(rfcomm, "ERROR");
|
||||
return false;
|
||||
} else if (sscanf(buf, "AT+BCS=%u", &selected_codec) == 1) {
|
||||
/* parse BCS(=Bluetooth Codec Selection) reply */
|
||||
|
|
@ -723,7 +761,7 @@ static bool rfcomm_hfp_ag(struct spa_source *source, char* buf)
|
|||
|
||||
if (selected_codec != HFP_AUDIO_CODEC_CVSD && selected_codec != HFP_AUDIO_CODEC_MSBC) {
|
||||
spa_log_warn(backend->log, NAME": unsupported codec negotiation: %d", selected_codec);
|
||||
rfcomm_send_reply(source, "ERROR");
|
||||
rfcomm_send_reply(rfcomm, "ERROR");
|
||||
if (was_switching_codec)
|
||||
spa_bt_device_emit_codec_switched(rfcomm->device, -EIO);
|
||||
return true;
|
||||
|
|
@ -741,7 +779,7 @@ static bool rfcomm_hfp_ag(struct spa_source *source, char* buf)
|
|||
if (rfcomm->transport == NULL) {
|
||||
spa_log_warn(backend->log, NAME": can't create transport: %m");
|
||||
// TODO: We should manage the missing transport
|
||||
rfcomm_send_reply(source, "ERROR");
|
||||
rfcomm_send_reply(rfcomm, "ERROR");
|
||||
if (was_switching_codec)
|
||||
spa_bt_device_emit_codec_switched(rfcomm->device, -ENOMEM);
|
||||
return true;
|
||||
|
|
@ -750,30 +788,30 @@ static bool rfcomm_hfp_ag(struct spa_source *source, char* buf)
|
|||
spa_bt_device_connect_profile(rfcomm->device, rfcomm->profile);
|
||||
rfcomm_emit_volume_changed(rfcomm, -1, SPA_BT_VOLUME_INVALID);
|
||||
|
||||
rfcomm_send_reply(source, "OK");
|
||||
rfcomm_send_reply(rfcomm, "OK");
|
||||
if (was_switching_codec)
|
||||
spa_bt_device_emit_codec_switched(rfcomm->device, 0);
|
||||
} else if (sscanf(buf, "AT+VGM=%u", &gain) == 1) {
|
||||
if (gain <= SPA_BT_VOLUME_HS_MAX) {
|
||||
if (!rfcomm->broken_mic_hw_volume)
|
||||
rfcomm_emit_volume_changed(rfcomm, SPA_BT_VOLUME_ID_RX, gain);
|
||||
rfcomm_send_reply(source, "OK");
|
||||
rfcomm_send_reply(rfcomm, "OK");
|
||||
} else {
|
||||
spa_log_debug(backend->log, NAME": RFCOMM receive unsupported VGM gain: %s", buf);
|
||||
rfcomm_send_reply(source, "ERROR");
|
||||
rfcomm_send_reply(rfcomm, "ERROR");
|
||||
}
|
||||
} else if (sscanf(buf, "AT+VGS=%u", &gain) == 1) {
|
||||
if (gain <= SPA_BT_VOLUME_HS_MAX) {
|
||||
rfcomm_emit_volume_changed(rfcomm, SPA_BT_VOLUME_ID_TX, gain);
|
||||
rfcomm_send_reply(source, "OK");
|
||||
rfcomm_send_reply(rfcomm, "OK");
|
||||
} else {
|
||||
spa_log_debug(backend->log, NAME": RFCOMM receive unsupported VGS gain: %s", buf);
|
||||
rfcomm_send_reply(source, "ERROR");
|
||||
rfcomm_send_reply(rfcomm, "ERROR");
|
||||
}
|
||||
} else if (strncmp(buf, "AT+XAPL=", 8) == 0) {
|
||||
// We expect battery status only (bitmask 10)
|
||||
rfcomm_send_reply(source, "+XAPL: iPhone,2");
|
||||
rfcomm_send_reply(source, "OK");
|
||||
rfcomm_send_reply(rfcomm, "+XAPL: iPhone,2");
|
||||
rfcomm_send_reply(rfcomm, "OK");
|
||||
} else if (sscanf(buf, "AT+IPHONEACCEV=%u", &len) == 1) {
|
||||
unsigned int i;
|
||||
int k, v;
|
||||
|
|
@ -807,7 +845,7 @@ static bool rfcomm_hfp_ag(struct spa_source *source, char* buf)
|
|||
}
|
||||
} else if (strncmp(buf, "AT+APLSIRI?", 11) == 0) {
|
||||
// This command is sent when we activate Apple extensions
|
||||
rfcomm_send_reply(source, "OK");
|
||||
rfcomm_send_reply(rfcomm, "OK");
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
|
@ -836,8 +874,6 @@ static bool rfcomm_hfp_hf(struct spa_source *source, char* buf)
|
|||
rfcomm->msbc_supported_by_hfp)
|
||||
rfcomm->codec_negotiation_supported = true;
|
||||
} else if (strncmp(token, "+BCS", 4) == 0 && rfcomm->codec_negotiation_supported) {
|
||||
char *cmd;
|
||||
|
||||
/* get next token */
|
||||
token = strtok(NULL, separators);
|
||||
selected_codec = atoi(token);
|
||||
|
|
@ -848,9 +884,8 @@ static bool rfcomm_hfp_hf(struct spa_source *source, char* buf)
|
|||
spa_log_debug(backend->log, NAME": RFCOMM selected_codec = %i", selected_codec);
|
||||
|
||||
/* send codec selection to AG */
|
||||
cmd = spa_aprintf("AT+BCS=%u", selected_codec);
|
||||
rfcomm_send_cmd(source, cmd);
|
||||
free(cmd);
|
||||
rfcomm_send_cmd(rfcomm, "AT+BCS=%u", selected_codec);
|
||||
|
||||
rfcomm->hf_state = hfp_hf_bcs;
|
||||
|
||||
if (!rfcomm->transport || (rfcomm->transport->codec != selected_codec) ) {
|
||||
|
|
@ -894,23 +929,23 @@ static bool rfcomm_hfp_hf(struct spa_source *source, char* buf)
|
|||
switch(rfcomm->hf_state) {
|
||||
case hfp_hf_brsf:
|
||||
if (rfcomm->codec_negotiation_supported) {
|
||||
rfcomm_send_cmd(source, "AT+BAC=1,2");
|
||||
rfcomm_send_cmd(rfcomm, "AT+BAC=1,2");
|
||||
rfcomm->hf_state = hfp_hf_bac;
|
||||
} else {
|
||||
rfcomm_send_cmd(source, "AT+CIND=?");
|
||||
rfcomm_send_cmd(rfcomm, "AT+CIND=?");
|
||||
rfcomm->hf_state = hfp_hf_cind1;
|
||||
}
|
||||
break;
|
||||
case hfp_hf_bac:
|
||||
rfcomm_send_cmd(source, "AT+CIND=?");
|
||||
rfcomm_send_cmd(rfcomm, "AT+CIND=?");
|
||||
rfcomm->hf_state = hfp_hf_cind1;
|
||||
break;
|
||||
case hfp_hf_cind1:
|
||||
rfcomm_send_cmd(source, "AT+CIND?");
|
||||
rfcomm_send_cmd(rfcomm, "AT+CIND?");
|
||||
rfcomm->hf_state = hfp_hf_cind2;
|
||||
break;
|
||||
case hfp_hf_cind2:
|
||||
rfcomm_send_cmd(source, "AT+CMER=3,0,0,0");
|
||||
rfcomm_send_cmd(rfcomm, "AT+CMER=3,0,0,0");
|
||||
rfcomm->hf_state = hfp_hf_cmer;
|
||||
break;
|
||||
case hfp_hf_cmer:
|
||||
|
|
@ -990,7 +1025,7 @@ static void rfcomm_event(struct spa_source *source)
|
|||
|
||||
if (!res) {
|
||||
spa_log_debug(backend->log, NAME": RFCOMM receive unsupported command: %s", buf);
|
||||
rfcomm_send_reply(source, "ERROR");
|
||||
rfcomm_send_reply(rfcomm, "ERROR");
|
||||
}
|
||||
}
|
||||
return;
|
||||
|
|
@ -1332,7 +1367,7 @@ static int sco_set_volume_cb(void *data, int id, float volume)
|
|||
struct spa_bt_transport_volume *t_volume = &t->volumes[id];
|
||||
struct transport_data *td = t->user_data;
|
||||
struct rfcomm *rfcomm = td->rfcomm;
|
||||
char *msg;
|
||||
const char *format;
|
||||
int value;
|
||||
|
||||
if (!rfcomm_volume_enabled(rfcomm)
|
||||
|
|
@ -1349,21 +1384,20 @@ static int sco_set_volume_cb(void *data, int id, float volume)
|
|||
|
||||
if (id == SPA_BT_VOLUME_ID_RX)
|
||||
if (rfcomm->profile & SPA_BT_PROFILE_HFP_HF)
|
||||
msg = spa_aprintf("+VGM: %d", value);
|
||||
format = "+VGM: %d";
|
||||
else
|
||||
msg = spa_aprintf("+VGM=%d", value);
|
||||
format = "+VGM=%d";
|
||||
else if (id == SPA_BT_VOLUME_ID_TX)
|
||||
if (rfcomm->profile & SPA_BT_PROFILE_HFP_HF)
|
||||
msg = spa_aprintf("+VGS: %d", value);
|
||||
format = "+VGS: %d";
|
||||
else
|
||||
msg = spa_aprintf("+VGS=%d", value);
|
||||
format = "+VGS=%d";
|
||||
else
|
||||
spa_assert_not_reached();
|
||||
|
||||
if (rfcomm->transport)
|
||||
rfcomm_send_reply(&rfcomm->source, msg);
|
||||
rfcomm_send_reply(rfcomm, format, value);
|
||||
|
||||
free(msg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -1443,7 +1477,7 @@ static void codec_switch_timer_event(struct spa_source *source)
|
|||
case HFP_AG_INITIAL_CODEC_SETUP_SEND:
|
||||
/* Retry codec selection */
|
||||
rfcomm->hfp_ag_initial_codec_setup = HFP_AG_INITIAL_CODEC_SETUP_WAIT;
|
||||
rfcomm_send_reply(&rfcomm->source, "+BCS: 2");
|
||||
rfcomm_send_reply(rfcomm, "+BCS: 2");
|
||||
codec_switch_start_timer(rfcomm, HFP_CODEC_SWITCH_TIMEOUT_MSEC);
|
||||
return;
|
||||
case HFP_AG_INITIAL_CODEC_SETUP_WAIT:
|
||||
|
|
@ -1458,7 +1492,7 @@ static void codec_switch_timer_event(struct spa_source *source)
|
|||
spa_bt_device_connect_profile(rfcomm->device, rfcomm->profile);
|
||||
}
|
||||
}
|
||||
rfcomm_send_reply(&rfcomm->source, "+BCS: 1");
|
||||
rfcomm_send_reply(rfcomm, "+BCS: 1");
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
|
|
@ -1500,7 +1534,6 @@ static int backend_native_ensure_codec(void *data, struct spa_bt_device *device,
|
|||
struct impl *backend = data;
|
||||
struct rfcomm *rfcomm;
|
||||
int res;
|
||||
char msg[16];
|
||||
|
||||
res = backend_native_supports_codec(data, device, codec);
|
||||
if (res <= 0)
|
||||
|
|
@ -1518,8 +1551,7 @@ static int backend_native_ensure_codec(void *data, struct spa_bt_device *device,
|
|||
return 0;
|
||||
}
|
||||
|
||||
snprintf(msg, sizeof(msg), "+BCS: %d", codec);
|
||||
if ((res = rfcomm_send_reply(&rfcomm->source, msg)) < 0)
|
||||
if ((res = rfcomm_send_reply(rfcomm, "+BCS: %u", codec)) < 0)
|
||||
return res;
|
||||
|
||||
rfcomm->hfp_ag_switching_codec = true;
|
||||
|
|
@ -1636,7 +1668,6 @@ static DBusHandlerResult profile_new_connection(DBusConnection *conn, DBusMessag
|
|||
} else if (profile == SPA_BT_PROFILE_HFP_AG) {
|
||||
/* Start SLC connection */
|
||||
unsigned int hf_features = SPA_BT_HFP_HF_FEATURE_NONE;
|
||||
char *cmd;
|
||||
|
||||
/* Decide if we want to signal that the HF supports mSBC negotiation
|
||||
This should be done when the bluetooth adapter supports the necessary transport mode */
|
||||
|
|
@ -1656,9 +1687,8 @@ static DBusHandlerResult profile_new_connection(DBusConnection *conn, DBusMessag
|
|||
}
|
||||
|
||||
/* send command to AG with the features supported by Hands-Free */
|
||||
cmd = spa_aprintf("AT+BRSF=%u", hf_features);
|
||||
rfcomm_send_cmd(&rfcomm->source, cmd);
|
||||
free(cmd);
|
||||
rfcomm_send_cmd(rfcomm, "AT+BRSF=%u", hf_features);
|
||||
|
||||
rfcomm->hf_state = hfp_hf_brsf;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue