mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-11-04 13:30:12 -05:00
bluez5: backend-native: handle multiple commands in RFCOMM input
Do relaxed parsing of RFCOMM commands for AG & HF roles, allowing multiple commands in same buffer. Use same parser code for all HFP/HSP AG/HF. Parse input in relaxed way, as some devices emit spurious \n
This commit is contained in:
parent
3da66734bd
commit
b533b06b51
1 changed files with 171 additions and 155 deletions
|
|
@ -496,19 +496,19 @@ static bool rfcomm_hsp_hs(struct rfcomm *rfcomm, char* buf)
|
||||||
* or when the gain is changed on the AG side.
|
* or when the gain is changed on the AG side.
|
||||||
* RING: Sent by AG to HS to notify of an incoming call. It can safely be ignored because
|
* RING: Sent by AG to HS to notify of an incoming call. It can safely be ignored because
|
||||||
* it does not expect a reply. */
|
* it does not expect a reply. */
|
||||||
if (sscanf(buf, "\r\n+VGS=%d\r\n", &gain) == 1) {
|
if (sscanf(buf, "+VGS=%d", &gain) == 1) {
|
||||||
if (gain <= SPA_BT_VOLUME_HS_MAX) {
|
if (gain <= SPA_BT_VOLUME_HS_MAX) {
|
||||||
rfcomm_emit_volume_changed(rfcomm, SPA_BT_VOLUME_ID_RX, gain);
|
rfcomm_emit_volume_changed(rfcomm, SPA_BT_VOLUME_ID_RX, gain);
|
||||||
} else {
|
} else {
|
||||||
spa_log_debug(backend->log, "RFCOMM receive unsupported VGS gain: %s", buf);
|
spa_log_debug(backend->log, "RFCOMM receive unsupported VGS gain: %s", buf);
|
||||||
}
|
}
|
||||||
} else if (sscanf(buf, "\r\n+VGM=%d\r\n", &gain) == 1) {
|
} else if (sscanf(buf, "+VGM=%d", &gain) == 1) {
|
||||||
if (gain <= SPA_BT_VOLUME_HS_MAX) {
|
if (gain <= SPA_BT_VOLUME_HS_MAX) {
|
||||||
rfcomm_emit_volume_changed(rfcomm, SPA_BT_VOLUME_ID_TX, gain);
|
rfcomm_emit_volume_changed(rfcomm, SPA_BT_VOLUME_ID_TX, gain);
|
||||||
} else {
|
} else {
|
||||||
spa_log_debug(backend->log, "RFCOMM receive unsupported VGM gain: %s", buf);
|
spa_log_debug(backend->log, "RFCOMM receive unsupported VGM gain: %s", buf);
|
||||||
}
|
}
|
||||||
} else if (spa_strstartswith(buf, "\r\nOK\r\n")) {
|
} else if (spa_streq(buf, "OK")) {
|
||||||
if (rfcomm->hs_state == hsp_hs_init2) {
|
if (rfcomm->hs_state == hsp_hs_init2) {
|
||||||
if (rfcomm_send_volume_cmd(rfcomm, SPA_BT_VOLUME_ID_RX))
|
if (rfcomm_send_volume_cmd(rfcomm, SPA_BT_VOLUME_ID_RX))
|
||||||
rfcomm->hs_state = hsp_hs_vgs;
|
rfcomm->hs_state = hsp_hs_vgs;
|
||||||
|
|
@ -777,12 +777,6 @@ static bool rfcomm_hfp_ag(struct rfcomm *rfcomm, char* buf)
|
||||||
int xapl_product;
|
int xapl_product;
|
||||||
int xapl_features;
|
int xapl_features;
|
||||||
|
|
||||||
spa_debug_log_mem(backend->log, SPA_LOG_LEVEL_DEBUG, 2, buf, strlen(buf));
|
|
||||||
|
|
||||||
/* Some devices send initial \n: be permissive */
|
|
||||||
while (*buf == '\n')
|
|
||||||
++buf;
|
|
||||||
|
|
||||||
if (sscanf(buf, "AT+BRSF=%u", &features) == 1) {
|
if (sscanf(buf, "AT+BRSF=%u", &features) == 1) {
|
||||||
unsigned int ag_features = SPA_BT_HFP_AG_FEATURE_NONE;
|
unsigned int ag_features = SPA_BT_HFP_AG_FEATURE_NONE;
|
||||||
|
|
||||||
|
|
@ -884,7 +878,7 @@ static bool rfcomm_hfp_ag(struct rfcomm *rfcomm, char* buf)
|
||||||
rfcomm_emit_volume_changed(rfcomm, -1, SPA_BT_VOLUME_INVALID);
|
rfcomm_emit_volume_changed(rfcomm, -1, SPA_BT_VOLUME_INVALID);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (spa_streq(buf, "\r")) {
|
} else if (spa_streq(buf, "")) {
|
||||||
/* No commands, reply OK (ITU-T Rec. V.250 Sec. 5.2.1 & 5.6) */
|
/* No commands, reply OK (ITU-T Rec. V.250 Sec. 5.2.1 & 5.6) */
|
||||||
rfcomm_send_reply(rfcomm, "OK");
|
rfcomm_send_reply(rfcomm, "OK");
|
||||||
} else if (!rfcomm->slc_configured) {
|
} else if (!rfcomm->slc_configured) {
|
||||||
|
|
@ -1178,13 +1172,11 @@ next_indicator:
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool rfcomm_hfp_hf(struct rfcomm *rfcomm, char* buf)
|
static bool rfcomm_hfp_hf(struct rfcomm *rfcomm, char* token)
|
||||||
{
|
{
|
||||||
struct impl *backend = rfcomm->backend;
|
struct impl *backend = rfcomm->backend;
|
||||||
unsigned int features, gain, selected_codec, indicator, value;
|
unsigned int features, gain, selected_codec, indicator, value;
|
||||||
char* token;
|
|
||||||
|
|
||||||
while ((token = strsep(&buf, "\r\n"))) {
|
|
||||||
if (sscanf(token, "+BRSF:%u", &features) == 1) {
|
if (sscanf(token, "+BRSF:%u", &features) == 1) {
|
||||||
if (((features & (SPA_BT_HFP_AG_FEATURE_CODEC_NEGOTIATION)) != 0) &&
|
if (((features & (SPA_BT_HFP_AG_FEATURE_CODEC_NEGOTIATION)) != 0) &&
|
||||||
rfcomm->msbc_supported_by_hfp)
|
rfcomm->msbc_supported_by_hfp)
|
||||||
|
|
@ -1320,13 +1312,41 @@ static bool rfcomm_hfp_hf(struct rfcomm *rfcomm, char* buf)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static void rfcomm_process_events(struct rfcomm *rfcomm, char *buf, bool ag, bool (*handler)(struct rfcomm *, char *))
|
||||||
|
{
|
||||||
|
struct impl *backend = rfcomm->backend;
|
||||||
|
char *token;
|
||||||
|
|
||||||
|
/* Relaxed parsing of both <COMMAND>\r (AG) and \r\n<REPLY>\r\n (HF) */
|
||||||
|
|
||||||
|
while ((token = strsep(&buf, "\r"))) {
|
||||||
|
size_t len;
|
||||||
|
|
||||||
|
/* Skip leading and trailing \n */
|
||||||
|
while (*token == '\n')
|
||||||
|
++token;
|
||||||
|
for (len = strlen(token); len > 0 && token[len - 1] == '\n'; --len)
|
||||||
|
token[len - 1] = '\0';
|
||||||
|
|
||||||
|
/* Skip empty (only last one if AG) */
|
||||||
|
if (*token == '\0' && (buf == NULL || !ag))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
spa_log_debug(backend->log, "RFCOMM event: %s", token);
|
||||||
|
|
||||||
|
if (!handler(rfcomm, token)) {
|
||||||
|
spa_log_debug(backend->log, "RFCOMM received unsupported event: %s", token);
|
||||||
|
rfcomm_send_error(rfcomm, CMEE_OPERATION_NOT_SUPPORTED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void rfcomm_event(struct spa_source *source)
|
static void rfcomm_event(struct spa_source *source)
|
||||||
{
|
{
|
||||||
struct rfcomm *rfcomm = source->data;
|
struct rfcomm *rfcomm = source->data;
|
||||||
|
|
@ -1341,41 +1361,37 @@ static void rfcomm_event(struct spa_source *source)
|
||||||
if (source->rmask & SPA_IO_IN) {
|
if (source->rmask & SPA_IO_IN) {
|
||||||
char buf[512];
|
char buf[512];
|
||||||
ssize_t len;
|
ssize_t len;
|
||||||
bool res = false;
|
|
||||||
|
|
||||||
len = read(source->fd, buf, 511);
|
len = read(source->fd, buf, sizeof(buf) - 1);
|
||||||
if (len < 0) {
|
if (len < 0) {
|
||||||
spa_log_error(backend->log, "RFCOMM read error: %s", strerror(errno));
|
spa_log_error(backend->log, "RFCOMM read error: %s", strerror(errno));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
buf[len] = 0;
|
buf[len] = 0;
|
||||||
|
|
||||||
spa_log_debug(backend->log, "RFCOMM << %s", buf);
|
spa_log_debug(backend->log, "RFCOMM << %s", buf);
|
||||||
|
spa_debug_log_mem(backend->log, SPA_LOG_LEVEL_DEBUG, 2, buf, strlen(buf));
|
||||||
|
|
||||||
switch (rfcomm->profile) {
|
switch (rfcomm->profile) {
|
||||||
#ifdef HAVE_BLUEZ_5_BACKEND_HSP_NATIVE
|
#ifdef HAVE_BLUEZ_5_BACKEND_HSP_NATIVE
|
||||||
case SPA_BT_PROFILE_HSP_HS:
|
case SPA_BT_PROFILE_HSP_HS:
|
||||||
res = rfcomm_hsp_ag(rfcomm, buf);
|
rfcomm_process_events(rfcomm, buf, true, rfcomm_hsp_ag);
|
||||||
break;
|
break;
|
||||||
case SPA_BT_PROFILE_HSP_AG:
|
case SPA_BT_PROFILE_HSP_AG:
|
||||||
res = rfcomm_hsp_hs(rfcomm, buf);
|
rfcomm_process_events(rfcomm, buf, false, rfcomm_hsp_hs);
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
#ifdef HAVE_BLUEZ_5_BACKEND_HFP_NATIVE
|
#ifdef HAVE_BLUEZ_5_BACKEND_HFP_NATIVE
|
||||||
case SPA_BT_PROFILE_HFP_HF:
|
case SPA_BT_PROFILE_HFP_HF:
|
||||||
res = rfcomm_hfp_ag(rfcomm, buf);
|
rfcomm_process_events(rfcomm, buf, true, rfcomm_hfp_ag);
|
||||||
break;
|
break;
|
||||||
case SPA_BT_PROFILE_HFP_AG:
|
case SPA_BT_PROFILE_HFP_AG:
|
||||||
res = rfcomm_hfp_hf(rfcomm, buf);
|
rfcomm_process_events(rfcomm, buf, false, rfcomm_hfp_hf);
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!res) {
|
|
||||||
spa_log_debug(backend->log, "RFCOMM received unsupported command: %s", buf);
|
|
||||||
rfcomm_send_error(rfcomm, CMEE_OPERATION_NOT_SUPPORTED);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue