static void rfcomm_io_callback(pa_mainloop_api *io, pa_io_event *e, int fd, pa_io_event_flags_t events, void *userdata) { pa_bluetooth_transport *t = userdata; pa_assert(io); pa_assert(t); if (events & (PA_IO_EVENT_HANGUP|PA_IO_EVENT_ERROR)) { pa_log_info("Lost RFCOMM connection."); goto fail; } if (events & PA_IO_EVENT_INPUT) { char buf[512]; ssize_t len; int gain; len = read(fd, buf, 511); buf[len] = 0; pa_log_debug("RFCOMM << %s", buf); if (sscanf(buf, "AT+VGS=%d", &gain) == 1) { t->speaker_gain = gain; pa_hook_fire(pa_bluetooth_discovery_hook(t->device->discovery, PA_BLUETOOTH_HOOK_TRANSPORT_SPEAKER_GAIN_CHANGED), t); } 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); /* 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) pa_log_error("RFCOMM write error: %s", pa_cstrerror(errno)); } return; fail: pa_bluetooth_transport_unlink(t); pa_bluetooth_transport_free(t); return; }
static void rfcomm_io_callback(pa_mainloop_api *io, pa_io_event *e, int fd, pa_io_event_flags_t events, void *userdata) { pa_bluetooth_transport *t = userdata; pa_assert(io); pa_assert(t); if (events & (PA_IO_EVENT_HANGUP|PA_IO_EVENT_ERROR)) { pa_log_info("Lost RFCOMM connection."); goto fail; } if (events & PA_IO_EVENT_INPUT) { char buf[512]; ssize_t len; int gain, dummy; bool do_reply = false; len = pa_read(fd, buf, 511, NULL); if (len < 0) { pa_log_error("RFCOMM read error: %s", pa_cstrerror(errno)); goto fail; } buf[len] = 0; pa_log_debug("RFCOMM << %s", buf); /* There are only four HSP AT commands: * AT+VGS=value: value between 0 and 15, sent by the HS to AG to set the speaker gain. * +VGS=value is sent by AG to HS as a response to an AT+VGS command or when the gain * is changed on the AG side. * AT+VGM=value: value between 0 and 15, sent by the HS to AG to set the microphone gain. * +VGM=value is sent by AG to HS as a response to an AT+VGM command or when the gain * is changed on the AG side. * AT+CKPD=200: Sent by HS when headset button is pressed. * RING: Sent by AG to HS to notify of an incoming call. It can safely be ignored because * it does not expect a reply. */ if (sscanf(buf, "AT+VGS=%d", &gain) == 1 || sscanf(buf, "\r\n+VGM=%d\r\n", &gain) == 1) { t->speaker_gain = gain; pa_hook_fire(pa_bluetooth_discovery_hook(t->device->discovery, PA_BLUETOOTH_HOOK_TRANSPORT_SPEAKER_GAIN_CHANGED), t); do_reply = true; } else if (sscanf(buf, "AT+VGM=%d", &gain) == 1 || sscanf(buf, "\r\n+VGS=%d\r\n", &gain) == 1) { t->microphone_gain = gain; pa_hook_fire(pa_bluetooth_discovery_hook(t->device->discovery, PA_BLUETOOTH_HOOK_TRANSPORT_MICROPHONE_GAIN_CHANGED), t); do_reply = true; } else if (sscanf(buf, "AT+CKPD=%d", &dummy) == 1) { do_reply = true; } else { do_reply = false; } if (do_reply) { pa_log_debug("RFCOMM >> OK"); len = write(fd, "\r\nOK\r\n", 6); /* 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) pa_log_error("RFCOMM write error: %s", pa_cstrerror(errno)); } } return; fail: pa_bluetooth_transport_unlink(t); pa_bluetooth_transport_free(t); }