Data notiated in a session should be reset once disconnected, to fix this a new structure is introduced called headset_session is introduced to hold the session data which is freed when disconnected. --- audio/headset.c | 187 +++++++++++++++++++++++++++++++------------------------ 1 files changed, 106 insertions(+), 81 deletions(-) diff --git a/audio/headset.c b/audio/headset.c index 7002a3a..4decc18 100644 --- a/audio/headset.c +++ b/audio/headset.c @@ -128,6 +128,25 @@ struct pending_connect { uint16_t svclass; }; +struct headset_session { + char buf[BUF_SIZE]; + int data_start; + int data_length; + + gboolean cli_active; + gboolean cme_enabled; + gboolean cwa_enabled; + gboolean pending_ring; + gboolean inband_ring; + gboolean nrec; + gboolean nrec_req; + + int sp_gain; + int mic_gain; + + unsigned int hf_features; +}; + struct headset { uint32_t hsp_handle; uint32_t hfp_handle; @@ -144,28 +163,14 @@ struct headset { guint dc_timer; - char buf[BUF_SIZE]; - int data_start; - int data_length; - gboolean hfp_active; gboolean search_hfp; - gboolean cli_active; - gboolean cme_enabled; - gboolean cwa_enabled; - gboolean pending_ring; - gboolean inband_ring; - gboolean nrec; - gboolean nrec_req; headset_state_t state; struct pending_connect *pending; - int sp_gain; - int mic_gain; - - unsigned int hf_features; headset_lock_t lock; + struct headset_session *session; }; struct event { @@ -338,14 +343,15 @@ static int headset_send(struct headset *hs, char *format, ...) static int supported_features(struct audio_device *device, const char *buf) { struct headset *hs = device->headset; + struct headset_session *session = hs->session; int err; if (strlen(buf) < 9) return -EINVAL; - hs->hf_features = strtoul(&buf[8], NULL, 10); + session->hf_features = strtoul(&buf[8], NULL, 10); - print_hf_features(hs->hf_features); + print_hf_features(session->hf_features); err = headset_send(hs, "\r\n+BRSF: %u\r\n", ag.features); if (err < 0) @@ -534,10 +540,12 @@ static void send_foreach_headset(GSList *devices, static int cli_cmp(struct headset *hs) { + struct headset_session *session = hs->session; + if (!hs->hfp_active) return -1; - if (hs->cli_active) + if (session->cli_active) return 0; else return -1; @@ -560,6 +568,7 @@ static void sco_connect_cb(GIOChannel *chan, GError *err, gpointer user_data) int sk; struct audio_device *dev = user_data; struct headset *hs = dev->headset; + struct headset_session *session = hs->session; struct pending_connect *p = hs->pending; if (err) { @@ -599,12 +608,12 @@ static void sco_connect_cb(GIOChannel *chan, GError *err, gpointer user_data) headset_set_state(dev, HEADSET_STATE_PLAYING); - if (hs->pending_ring) { + if (session->pending_ring) { ring_timer_cb(NULL); ag.ring_timer = g_timeout_add_seconds(RING_INTERVAL, ring_timer_cb, NULL); - hs->pending_ring = FALSE; + session->pending_ring = FALSE; } } @@ -684,9 +693,10 @@ static void hfp_slc_complete(struct audio_device *dev) static int telephony_generic_rsp(struct audio_device *device, cme_error_t err) { struct headset *hs = device->headset; + struct headset_session *session = hs->session; if (err != CME_ERROR_NONE) { - if (hs->cme_enabled) + if (session->cme_enabled) return headset_send(hs, "\r\n+CME ERROR: %d\r\n", err); else return headset_send(hs, "\r\nERROR\r\n"); @@ -699,6 +709,7 @@ int telephony_event_reporting_rsp(void *telephony_device, cme_error_t err) { struct audio_device *device = telephony_device; struct headset *hs = device->headset; + struct headset_session *session = hs->session; int ret; if (err != CME_ERROR_NONE) @@ -711,7 +722,7 @@ int telephony_event_reporting_rsp(void *telephony_device, cme_error_t err) if (hs->state != HEADSET_STATE_CONNECTING) return 0; - if (hs->hf_features & HF_FEATURE_CALL_WAITING_AND_3WAY && + if (session->hf_features & HF_FEATURE_CALL_WAITING_AND_3WAY && ag.features & AG_FEATURE_THREE_WAY_CALLING) return 0; @@ -865,11 +876,12 @@ static int terminate_call(struct audio_device *device, const char *buf) static int cli_notification(struct audio_device *device, const char *buf) { struct headset *hs = device->headset; + struct headset_session *session = hs->session; if (strlen(buf) < 9) return -EINVAL; - hs->cli_active = buf[8] == '1' ? TRUE : FALSE; + session->cli_active = buf[8] == '1' ? TRUE : FALSE; return headset_send(hs, "\r\nOK\r\n"); } @@ -937,6 +949,7 @@ static int dial_number(struct audio_device *device, const char *buf) static int signal_gain_setting(struct audio_device *device, const char *buf) { struct headset *hs = device->headset; + struct headset_session *session = hs->session; const char *property; const char *name; dbus_uint16_t gain; @@ -955,18 +968,18 @@ static int signal_gain_setting(struct audio_device *device, const char *buf) switch (buf[5]) { case HEADSET_GAIN_SPEAKER: - if (hs->sp_gain == gain) + if (session->sp_gain == gain) goto ok; name = "SpeakerGainChanged"; property = "SpeakerGain"; - hs->sp_gain = gain; + session->sp_gain = gain; break; case HEADSET_GAIN_MICROPHONE: - if (hs->mic_gain == gain) + if (session->mic_gain == gain) goto ok; name = "MicrophoneGainChanged"; property = "MicrophoneGain"; - hs->mic_gain = gain; + session->mic_gain = gain; break; default: error("Unknown gain setting"); @@ -1030,15 +1043,16 @@ static int list_current_calls(struct audio_device *device, const char *buf) static int extended_errors(struct audio_device *device, const char *buf) { struct headset *hs = device->headset; + struct headset_session *session = hs->session; if (strlen(buf) < 9) return -EINVAL; if (buf[8] == '1') { - hs->cme_enabled = TRUE; + session->cme_enabled = TRUE; debug("CME errors enabled for headset %p", hs); } else { - hs->cme_enabled = FALSE; + session->cme_enabled = FALSE; debug("CME errors disabled for headset %p", hs); } @@ -1048,15 +1062,16 @@ static int extended_errors(struct audio_device *device, const char *buf) static int call_waiting_notify(struct audio_device *device, const char *buf) { struct headset *hs = device->headset; + struct headset_session *session = hs->session; if (strlen(buf) < 9) return -EINVAL; if (buf[8] == '1') { - hs->cwa_enabled = TRUE; + session->cwa_enabled = TRUE; debug("Call waiting notification enabled for headset %p", hs); } else { - hs->cwa_enabled = FALSE; + session->cwa_enabled = FALSE; debug("Call waiting notification disabled for headset %p", hs); } @@ -1077,9 +1092,10 @@ int telephony_nr_and_ec_rsp(void *telephony_device, cme_error_t err) { struct audio_device *device = telephony_device; struct headset *hs = device->headset; + struct headset_session *session = hs->session; if (err == CME_ERROR_NONE) - hs->nrec = hs->nrec_req; + session->nrec = hs->session->nrec_req; return telephony_generic_rsp(telephony_device, err); } @@ -1123,16 +1139,17 @@ static int operator_selection(struct audio_device *device, const char *buf) static int nr_and_ec(struct audio_device *device, const char *buf) { struct headset *hs = device->headset; + struct headset_session *session = hs->session; if (strlen(buf) < 9) return -EINVAL; if (buf[8] == '0') - hs->nrec_req = FALSE; + session->nrec_req = FALSE; else - hs->nrec_req = TRUE; + session->nrec_req = TRUE; - telephony_nr_and_ec_req(device, hs->nrec_req); + telephony_nr_and_ec_req(device, session->nrec_req); return 0; } @@ -1214,6 +1231,7 @@ static gboolean rfcomm_io_cb(GIOChannel *chan, GIOCondition cond, struct audio_device *device) { struct headset *hs; + struct headset_session *session; unsigned char buf[BUF_SIZE]; gsize bytes_read = 0; gsize free_space; @@ -1222,6 +1240,7 @@ static gboolean rfcomm_io_cb(GIOChannel *chan, GIOCondition cond, return FALSE; hs = device->headset; + session = hs->session; if (cond & (G_IO_ERR | G_IO_HUP)) { debug("ERR or HUP on RFCOMM socket"); @@ -1232,7 +1251,8 @@ static gboolean rfcomm_io_cb(GIOChannel *chan, GIOCondition cond, &bytes_read) != G_IO_ERROR_NONE) return TRUE; - free_space = sizeof(hs->buf) - hs->data_start - hs->data_length - 1; + free_space = sizeof(session->buf) - session->data_start - + session->data_length - 1; if (free_space < bytes_read) { /* Very likely that the HS is sending us garbage so @@ -1241,45 +1261,45 @@ static gboolean rfcomm_io_cb(GIOChannel *chan, GIOCondition cond, goto failed; } - memcpy(&hs->buf[hs->data_start], buf, bytes_read); - hs->data_length += bytes_read; + memcpy(&session->buf[session->data_start], buf, bytes_read); + session->data_length += bytes_read; /* Make sure the data is null terminated so we can use string * functions */ - hs->buf[hs->data_start + hs->data_length] = '\0'; + session->buf[session->data_start + session->data_length] = '\0'; - while (hs->data_length > 0) { + while (session->data_length > 0) { char *cr; int err; off_t cmd_len; - cr = strchr(&hs->buf[hs->data_start], '\r'); + cr = strchr(&session->buf[session->data_start], '\r'); if (!cr) break; - cmd_len = 1 + (off_t) cr - (off_t) &hs->buf[hs->data_start]; + cmd_len = 1 + (off_t) cr - (off_t) &session->buf[session->data_start]; *cr = '\0'; if (cmd_len > 1) - err = handle_event(device, &hs->buf[hs->data_start]); + err = handle_event(device, &session->buf[session->data_start]); else /* Silently skip empty commands */ err = 0; if (err == -EINVAL) { error("Badly formated or unrecognized command: %s", - &hs->buf[hs->data_start]); + &session->buf[session->data_start]); err = headset_send(hs, "\r\nERROR\r\n"); } else if (err < 0) error("Error handling command %s: %s (%d)", - &hs->buf[hs->data_start], + &session->buf[session->data_start], strerror(-err), -err); - hs->data_start += cmd_len; - hs->data_length -= cmd_len; + session->data_start += cmd_len; + session->data_length -= cmd_len; - if (!hs->data_length) - hs->data_start = 0; + if (!session->data_length) + session->data_start = 0; } return TRUE; @@ -1337,6 +1357,9 @@ void headset_connect_cb(GIOChannel *chan, GError *err, gpointer user_data) debug("%s: Connected to %s", dev->path, hs_address); + hs->session = g_new0(struct headset_session, 1); + hs->session->nrec = TRUE; + /* In HFP mode wait for Service Level Connection */ if (hs->hfp_active) return; @@ -1811,10 +1834,11 @@ static DBusMessage *hs_get_speaker_gain(DBusConnection *conn, { struct audio_device *device = data; struct headset *hs = device->headset; + struct headset_session *session = hs->session; DBusMessage *reply; dbus_uint16_t gain; - if (hs->state < HEADSET_STATE_CONNECTED || hs->sp_gain < 0) + if (hs->state < HEADSET_STATE_CONNECTED || session == NULL) return g_dbus_create_error(msg, ERROR_INTERFACE ".NotAvailable", "Operation not Available"); @@ -1822,7 +1846,7 @@ static DBusMessage *hs_get_speaker_gain(DBusConnection *conn, if (!reply) return NULL; - gain = (dbus_uint16_t) hs->sp_gain; + gain = (dbus_uint16_t) session->sp_gain; dbus_message_append_args(reply, DBUS_TYPE_UINT16, &gain, DBUS_TYPE_INVALID); @@ -1836,10 +1860,11 @@ static DBusMessage *hs_get_mic_gain(DBusConnection *conn, { struct audio_device *device = data; struct headset *hs = device->headset; + struct headset_session *session = hs->session; DBusMessage *reply; dbus_uint16_t gain; - if (hs->state < HEADSET_STATE_CONNECTED || hs->mic_gain < 0) + if (hs->state < HEADSET_STATE_CONNECTED || session == NULL) return g_dbus_create_error(msg, ERROR_INTERFACE ".NotAvailable", "Operation not Available"); @@ -1847,7 +1872,7 @@ static DBusMessage *hs_get_mic_gain(DBusConnection *conn, if (!reply) return NULL; - gain = (dbus_uint16_t) hs->mic_gain; + gain = (dbus_uint16_t) session->mic_gain; dbus_message_append_args(reply, DBUS_TYPE_UINT16, &gain, DBUS_TYPE_INVALID); @@ -1862,6 +1887,7 @@ static DBusMessage *hs_set_gain(DBusConnection *conn, { struct audio_device *device = data; struct headset *hs = device->headset; + struct headset_session *session = hs->session; DBusMessage *reply; int err; @@ -1891,14 +1917,14 @@ static DBusMessage *hs_set_gain(DBusConnection *conn, done: if (type == HEADSET_GAIN_SPEAKER) { - hs->sp_gain = gain; + session->sp_gain = gain; g_dbus_emit_signal(conn, device->path, AUDIO_HEADSET_INTERFACE, "SpeakerGainChanged", DBUS_TYPE_UINT16, &gain, DBUS_TYPE_INVALID); } else { - hs->mic_gain = gain; + session->mic_gain = gain; g_dbus_emit_signal(conn, device->path, AUDIO_HEADSET_INTERFACE, "MicrophoneGainChanged", @@ -1975,11 +2001,13 @@ static DBusMessage *hs_get_properties(DBusConnection *conn, /* SpeakerGain */ dict_append_entry(&dict, "SpeakerGain", - DBUS_TYPE_UINT16, &device->headset->sp_gain); + DBUS_TYPE_UINT16, + &device->headset->session->sp_gain); /* MicrophoneGain */ dict_append_entry(&dict, "MicrophoneGain", - DBUS_TYPE_UINT16, &device->headset->mic_gain); + DBUS_TYPE_UINT16, + &device->headset->session->mic_gain); done: dbus_message_iter_close_container(&iter, &dict); @@ -2118,10 +2146,8 @@ static int headset_close_rfcomm(struct audio_device *dev) hs->rfcomm = NULL; } - hs->data_start = 0; - hs->data_length = 0; - - hs->nrec = TRUE; + g_free(hs->session); + hs->session = NULL; return 0; } @@ -2176,12 +2202,7 @@ struct headset *headset_init(struct audio_device *dev, uint16_t svc, hs = g_new0(struct headset, 1); hs->rfcomm_ch = -1; - hs->sp_gain = -1; - hs->mic_gain = -1; hs->search_hfp = server_is_enabled(&dev->src, HANDSFREE_SVCLASS_ID); - hs->hfp_active = FALSE; - hs->cli_active = FALSE; - hs->nrec = TRUE; record = btd_device_get_record(dev->btd_dev, uuidstr); if (!record) @@ -2424,18 +2445,19 @@ int headset_connect_rfcomm(struct audio_device *dev, GIOChannel *io) int headset_connect_sco(struct audio_device *dev, GIOChannel *io) { struct headset *hs = dev->headset; + struct headset_session *session = hs->session; if (hs->sco) return -EISCONN; hs->sco = g_io_channel_ref(io); - if (hs->pending_ring) { + if (session->pending_ring) { ring_timer_cb(NULL); ag.ring_timer = g_timeout_add_seconds(RING_INTERVAL, ring_timer_cb, NULL); - hs->pending_ring = FALSE; + session->pending_ring = FALSE; } return 0; @@ -2454,6 +2476,7 @@ static void disconnect_cb(struct btd_device *btd_dev, gboolean removal, void headset_set_state(struct audio_device *dev, headset_state_t state) { struct headset *hs = dev->headset; + struct headset_session *session = hs->session; gboolean value; const char *state_str; headset_state_t old_state = hs->state; @@ -2499,9 +2522,9 @@ void headset_set_state(struct audio_device *dev, headset_state_t state) DBUS_TYPE_STRING, &state_str); if (hs->state < state) { if (ag.features & AG_FEATURE_INBAND_RINGTONE) - hs->inband_ring = TRUE; + session->inband_ring = TRUE; else - hs->inband_ring = FALSE; + session->inband_ring = FALSE; g_dbus_emit_signal(dev->conn, dev->path, AUDIO_HEADSET_INTERFACE, "Connected", @@ -2546,10 +2569,10 @@ void headset_set_state(struct audio_device *dev, headset_state_t state) AUDIO_HEADSET_INTERFACE, "Playing", DBUS_TYPE_BOOLEAN, &value); - if (hs->sp_gain >= 0) - headset_send(hs, "\r\n+VGS=%u\r\n", hs->sp_gain); - if (hs->mic_gain >= 0) - headset_send(hs, "\r\n+VGM=%u\r\n", hs->mic_gain); + if (session->sp_gain >= 0) + headset_send(hs, "\r\n+VGS=%u\r\n", session->sp_gain); + if (session->mic_gain >= 0) + headset_send(hs, "\r\n+VGM=%u\r\n", session->mic_gain); break; } @@ -2658,7 +2681,7 @@ gboolean headset_get_nrec(struct audio_device *dev) { struct headset *hs = dev->headset; - return hs->nrec; + return hs->session->nrec; } gboolean headset_get_sco_hci(struct audio_device *dev) @@ -2715,6 +2738,7 @@ int telephony_incoming_call_ind(const char *number, int type) { struct audio_device *dev; struct headset *hs; + struct headset_session *session; if (!active_devices) return -ENODEV; @@ -2722,6 +2746,7 @@ int telephony_incoming_call_ind(const char *number, int type) /* Get the latest connected device */ dev = active_devices->data; hs = dev->headset; + session = hs->session; if (ag.ring_timer) { debug("telephony_incoming_call_ind: already calling"); @@ -2730,16 +2755,16 @@ int telephony_incoming_call_ind(const char *number, int type) /* With HSP 1.2 the RING messages should *not* be sent if inband * ringtone is being used */ - if (!hs->hfp_active && hs->inband_ring) + if (!hs->hfp_active && session->inband_ring) return 0; g_free(ag.number); ag.number = g_strdup(number); ag.number_type = type; - if (hs->inband_ring && hs->hfp_active && + if (session->inband_ring && hs->hfp_active && hs->state != HEADSET_STATE_PLAYING) { - hs->pending_ring = TRUE; + session->pending_ring = TRUE; return 0; } @@ -2765,10 +2790,10 @@ int telephony_calling_stopped_ind(void) /* In case SCO isn't fully up yet */ dev = active_devices->data; - if (!dev->headset->pending_ring && !ag.ring_timer) + if (!dev->headset->session->pending_ring && !ag.ring_timer) return -EINVAL; - dev->headset->pending_ring = FALSE; + dev->headset->session->pending_ring = FALSE; return 0; } @@ -2826,7 +2851,7 @@ static int cwa_cmp(struct headset *hs) if (!hs->hfp_active) return -1; - if (hs->cwa_enabled) + if (hs->session->cwa_enabled) return 0; else return -1; -- 1.6.3.3 -- Luiz Augusto von Dentz Computer Engineer -- To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html