On Sat, 2016-08-20 at 15:05 -0700, James Bottomley wrote: > +static int hfp_rfcomm_handle(int fd, pa_bluetooth_transport *t, const char *buf) > +{ > +Â Â Â Â struct hfp_config *c = t->config; > +Â Â Â Â int val; > + > +Â Â Â Â /* stateful negotiation */ > +Â Â Â Â if (c->state == 0 && sscanf(buf, "AT+BRSF=%d", &val) == 1) { > + Â Â c->capabilities = val; > + Â Â pa_log_info("HFP capabilities returns 0x%x", val); > + Â Â hfp_send_features(fd); > + Â Â c->state = 1; > + Â Â return 0; > +Â Â Â Â } else if (c->state == 1 && pa_strcont("AT+CIND=?", buf)) { > + Â Â /* we declare minimal indicators */ > + rfcomm_write(fd, "+CIND: (\"call\",(0,1))"); > + c->state = 2; > + return 0; > +Â Â Â Â } else if (c->state == 2 && pa_strcont("AT+CIND?", buf)) { > + rfcomm_write(fd, "+CIND: 0"); > + c->state = 3; > + return 0; > +Â Â Â Â } else if (c->state == 3 && pa_strcont("AT+CMER=", buf)) { > + rfcomm_write(fd, "OK"); > + c->state = 4; > + transport_put(t); > + return 1; > +Â Â Â Â } > + > + > +Â Â Â Â if (c->state != 4) > + goto error; > + > +Â Â Â Â /* misc things to handle in fully connected state */ > + > +Â Â Â Â if (pa_strcont("AT+BTRH?", buf)) { > + return 0; > +Â Â Â Â } else if (pa_strcont("AT+CHLD=?", buf)) { > + return 0; > +Â Â Â Â } The commands are queries, so shouldn't they receive some kind of a reply (in addition to just "OK")? Now that I've read some of the HFP spec, I believe there are other commands (possibly many of them) that we may encounter too after the initial setup, for example AT+CMER. How did these two commands end up being handled specially? Did your headset not work without this code? It seems likely that other headsets will have other requirements, which is why I don't feel comfortable switching the majority of headsets from HSP to this partial HFP implementation by default. One possibility for avoiding manual configuration in HFP-only use cases would be to add some logic to automatically register the HFP profile when we notice that a HFP-only headset is being used. Tabs are still appearing here. > @@ -246,16 +358,18 @@ static void rfcomm_io_callback(pa_mainloop_api *io, pa_io_event *e, int fd, pa_i > Â Â Â Â Â Â Â Â Â } else if (sscanf(buf, "AT+VGM=%d", &gain) == 1) { > Â Â Â Â Â Â Â Â Â Â Â t->microphone_gain = gain; > Â Â Â Â Â Â Â Â Â Â Â pa_hook_fire(pa_bluetooth_discovery_hook(t->device->discovery, PA_BLUETOOTH_HOOK_TRANSPORT_MICROPHONE_GAIN_CHANGED), t); > -Â Â Â Â Â Â Â Â } > - > -Â Â Â Â Â Â Â Â pa_log_debug("RFCOMM >> OK"); > - > -Â Â Â Â Â Â Â Â len = write(fd, "\r\nOK\r\n", 6); > +Â Â Â Â Â Â Â Â } else if (t->config) { The assumption here is that non-NULL config means that we're using HFP rather than HSP, right? I think that should be clarified with a comment, or in some other way. > + Â Â Â Â switch (hfp_rfcomm_handle(fd, t, buf)) { > + Â Â Â Â case -1: > + goto fail; hfp_rfcomm_handle() never returns -1, so this looks weird. > + Â Â Â Â case 1: > + return; > + Â Â Â Â } > + } > + rfcomm_write(fd, "OK"); > Â > Â Â Â Â Â Â Â Â Â /* we ignore any errors, it's not critical and real errors should > Â Â Â Â Â Â Â Â Â Â * be caught with the HANGUP and ERROR events handled above */ This comment talks about errors from write(), but since the write() call moved elsewhere, this comment doesn't make much sense here anymore. > @@ -381,9 +495,14 @@ static DBusMessage *profile_new_connection(DBusConnection *conn, DBusMessage *m, > Â Â Â Â Â Â Â Â Â rfcomm_io_callback, t); > Â Â Â Â Â t->userdata =Â Â trfc; > Â > -Â Â Â Â pa_bluetooth_transport_put(t); > +Â Â Â Â if (!is_hfp) > + transport_put(t); > +Â Â Â Â else { > + pa_log_debug("beginning sleep"); > + sleep(1); > + pa_log_debug("ending sleep"); What's this about? > +/* see if the string b contains a as a prefix */ > +static inline bool pa_strcont(const char *a, const char *b) { > +Â Â Â Â if (a == NULL || b == NULL) > + return a == b; > +Â Â Â Â return !strncmp(a, b, strlen(a)); > +} We already have pa_startswith(). --Â Tanu