diff options
author | Johan Hedberg <johan.hedberg@nokia.com> | 2007-08-16 21:48:33 +0000 |
---|---|---|
committer | Johan Hedberg <johan.hedberg@nokia.com> | 2007-08-16 21:48:33 +0000 |
commit | 0f458da19471c933a4105cc450c48548b72edc8e (patch) | |
tree | 3fe4c38c29c7adb1eb13cf273d8335efa97d1337 /audio/avdtp.c | |
parent | 871c0518ec53309a38debbb86a36c035c3470fba (diff) |
Handle error situations better
Diffstat (limited to 'audio/avdtp.c')
-rw-r--r-- | audio/avdtp.c | 166 |
1 files changed, 135 insertions, 31 deletions
diff --git a/audio/avdtp.c b/audio/avdtp.c index 7194177f..1687714b 100644 --- a/audio/avdtp.c +++ b/audio/avdtp.c @@ -218,6 +218,12 @@ struct avdtp_local_sep { void *data; }; +struct stream_callback { + avdtp_stream_state_cb cb; + void *user_data; + unsigned int id; +}; + struct avdtp_stream { int sock; uint16_t mtu; @@ -225,9 +231,8 @@ struct avdtp_stream { struct avdtp_local_sep *lsep; uint8_t rseid; GSList *caps; + GSList *callbacks; struct avdtp_service_capability *codec; - avdtp_stream_state_cb cb; - void *user_data; guint io; /* Transport GSource ID */ guint timer; /* Waiting for other side to close or open the transport channel */ @@ -456,10 +461,13 @@ static void stream_free(struct avdtp_stream *stream) if (stream->timer) g_source_remove(stream->timer); - if (stream->caps) { - g_slist_foreach(stream->caps, (GFunc) g_free, NULL); - g_slist_free(stream->caps); - } + + g_slist_foreach(stream->callbacks, (GFunc) g_free, NULL); + g_slist_free(stream->callbacks); + + g_slist_foreach(stream->caps, (GFunc) g_free, NULL); + g_slist_free(stream->caps); + g_free(stream); } @@ -485,9 +493,14 @@ static void avdtp_sep_set_state(struct avdtp *session, old_state = sep->state; sep->state = state; - if (stream && stream->cb) - stream->cb(stream, old_state, state, err_ptr, - stream->user_data); + if (stream) { + GSList *l; + for (l = stream->callbacks; l != NULL; l = g_slist_next(l)) { + struct stream_callback *cb = l->data; + cb->cb(stream, old_state, state, err_ptr, + cb->user_data); + } + } if (state == AVDTP_STATE_IDLE) { session->streams = g_slist_remove(session->streams, stream); @@ -1170,7 +1183,7 @@ static gboolean transport_cb(GIOChannel *chan, GIOCondition cond, struct avdtp_local_sep *sep = stream->lsep; if (stream->close_int && sep->cfm && sep->cfm->close) - sep->cfm->close(stream->session, sep, stream); + sep->cfm->close(stream->session, sep, stream, NULL); avdtp_sep_set_state(stream->session, sep, AVDTP_STATE_IDLE); @@ -1195,7 +1208,7 @@ static void handle_transport_connect(struct avdtp *session, int sock, stream->mtu = mtu; if (!stream->open_acp && sep->cfm && sep->cfm->open) - sep->cfm->open(session, sep, stream); + sep->cfm->open(session, sep, stream, NULL); channel = g_io_channel_unix_new(stream->sock); @@ -1465,33 +1478,75 @@ static gboolean request_timeout(gpointer user_data) struct avdtp *session = user_data; struct pending_req *req; struct seid_req sreq; - struct avdtp_remote_sep *sep; + struct avdtp_remote_sep *rsep; + struct avdtp_local_sep *lsep; struct avdtp_stream *stream; uint8_t seid; - - error("Request timed out"); + struct avdtp_error err; req = session->req; session->req = NULL; - switch (req->msg->signal_id) { - case AVDTP_DISCOVER: - case AVDTP_GET_CAPABILITIES: - case AVDTP_SET_CONFIGURATION: - case AVDTP_ABORT: - goto failed; - } + avdtp_error_init(&err, AVDTP_ERROR_ERRNO, ETIMEDOUT); seid = ((struct seid_req *) (req->msg))->acp_seid; - sep = find_remote_sep(session->seps, seid); - if (!sep) { + rsep = find_remote_sep(session->seps, seid); + if (!rsep) { error("Unable to find matching remote SEID %u", seid); goto failed; } stream = find_stream_by_rseid(session, seid); + if (stream) + lsep = stream->lsep; + else + lsep = NULL; + + switch (req->msg->signal_id) { + case AVDTP_RECONFIGURE: + error("Reconfigure request timed out"); + if (lsep && lsep->cfm && lsep->cfm->reconfigure) + lsep->cfm->reconfigure(session, lsep, stream, &err); + break; + case AVDTP_OPEN: + error("Open request timed out"); + if (lsep && lsep->cfm && lsep->cfm->open) + lsep->cfm->open(session, lsep, stream, &err); + break; + case AVDTP_START: + error("Start request timed out"); + if (lsep && lsep->cfm && lsep->cfm->start) + lsep->cfm->start(session, lsep, stream, &err); + break; + case AVDTP_SUSPEND: + error("Suspend request timed out"); + if (lsep && lsep->cfm && lsep->cfm->suspend) + lsep->cfm->suspend(session, lsep, stream, &err); + break; + case AVDTP_CLOSE: + error("Close request timed out"); + if (lsep && lsep->cfm && lsep->cfm->close) + lsep->cfm->close(session, lsep, stream, &err); + break; + case AVDTP_SET_CONFIGURATION: + error("SetConfiguration request timed out"); + if (lsep && lsep->cfm && lsep->cfm->set_configuration) + lsep->cfm->set_configuration(session, lsep, stream, &err); + /* fallthrough on purpose */ + case AVDTP_DISCOVER: + error("Discover request timed out"); + if (lsep && lsep->cfm && lsep->cfm->set_configuration) + goto failed; + case AVDTP_GET_CAPABILITIES: + error("GetCapabilities request timed out"); + goto failed; + case AVDTP_ABORT: + error("Abort request timed out"); + goto failed; + } + memset(&sreq, 0, sizeof(sreq)); init_request(&sreq.header, AVDTP_ABORT); sreq.acp_seid = seid; @@ -1646,7 +1701,7 @@ static gboolean avdtp_set_configuration_resp(struct avdtp *session, struct avdtp_local_sep *sep = stream->lsep; if (sep->cfm && sep->cfm->set_configuration) - sep->cfm->set_configuration(session, sep, stream); + sep->cfm->set_configuration(session, sep, stream, NULL); avdtp_sep_set_state(session, sep, AVDTP_STATE_CONFIGURED); @@ -1684,7 +1739,7 @@ static gboolean avdtp_start_resp(struct avdtp *session, struct avdtp_local_sep *sep = stream->lsep; if (sep->cfm && sep->cfm->start) - sep->cfm->start(session, sep, stream); + sep->cfm->start(session, sep, stream, NULL); avdtp_sep_set_state(session, sep, AVDTP_STATE_STREAMING); @@ -1715,7 +1770,7 @@ static gboolean avdtp_suspend_resp(struct avdtp *session, avdtp_sep_set_state(session, sep, AVDTP_STATE_OPEN); if (sep->cfm && sep->cfm->suspend) - sep->cfm->suspend(session, sep, stream); + sep->cfm->suspend(session, sep, stream, NULL); return TRUE; } @@ -1727,7 +1782,7 @@ static gboolean avdtp_abort_resp(struct avdtp *session, struct avdtp_local_sep *sep = stream->lsep; if (sep->cfm && sep->cfm->suspend) - sep->cfm->suspend(session, sep, stream); + sep->cfm->suspend(session, sep, stream, NULL); avdtp_sep_set_state(session, sep, AVDTP_STATE_IDLE); @@ -1845,6 +1900,7 @@ static gboolean avdtp_parse_rej(struct avdtp *session, struct avdtp_stream *stre { struct avdtp_error err; uint8_t acp_seid, category; + struct avdtp_local_sep *sep = stream ? stream->lsep : NULL; switch (header->signal_id) { case AVDTP_DISCOVER: @@ -1864,42 +1920,56 @@ static gboolean avdtp_parse_rej(struct avdtp *session, struct avdtp_stream *stre return FALSE; error("OPEN request rejected: %s (%d)", avdtp_strerror(&err), err.err.error_code); + if (sep && sep->cfm && sep->cfm->open) + sep->cfm->open(session, sep, stream, &err); return TRUE; case AVDTP_SET_CONFIGURATION: if (!conf_rej_to_err((void *) header, size, &err, &category)) return FALSE; error("SET_CONFIGURATION request rejected: %s (%d)", avdtp_strerror(&err), err.err.error_code); + if (sep && sep->cfm && sep->cfm->set_configuration) + sep->cfm->set_configuration(session, sep, stream, &err); return TRUE; case AVDTP_RECONFIGURE: if (!conf_rej_to_err((void *) header, size, &err, &category)) return FALSE; error("RECONFIGURE request rejected: %s (%d)", avdtp_strerror(&err), err.err.error_code); + if (sep && sep->cfm && sep->cfm->reconfigure) + sep->cfm->reconfigure(session, sep, stream, &err); return TRUE; case AVDTP_START: if (!stream_rej_to_err((void *) header, size, &err, &acp_seid)) return FALSE; error("START request rejected: %s (%d)", avdtp_strerror(&err), err.err.error_code); + if (sep && sep->cfm && sep->cfm->start) + sep->cfm->start(session, sep, stream, &err); return TRUE; case AVDTP_SUSPEND: if (!stream_rej_to_err((void *) header, size, &err, &acp_seid)) return FALSE; error("SUSPEND request rejected: %s (%d)", avdtp_strerror(&err), err.err.error_code); + if (sep && sep->cfm && sep->cfm->suspend) + sep->cfm->suspend(session, sep, stream, &err); return TRUE; case AVDTP_CLOSE: if (!stream_rej_to_err((void *) header, size, &err, &acp_seid)) return FALSE; error("CLOSE request rejected: %s (%d)", avdtp_strerror(&err), err.err.error_code); + if (sep && sep->cfm && sep->cfm->close) + sep->cfm->close(session, sep, stream, &err); return TRUE; case AVDTP_ABORT: if (!stream_rej_to_err((void *) header, size, &err, &acp_seid)) return FALSE; error("ABORT request rejected: %s (%d)", avdtp_strerror(&err), err.err.error_code); + if (sep && sep->cfm && sep->cfm->abort) + sep->cfm->abort(session, sep, stream, &err); return TRUE; default: error("Unknown reject response signal id: %u", @@ -2085,11 +2155,45 @@ int avdtp_get_seps(struct avdtp *session, uint8_t acp_type, uint8_t media_type, return -EINVAL; } -void avdtp_stream_set_cb(struct avdtp *session, struct avdtp_stream *stream, - avdtp_stream_state_cb cb, void *data) +gboolean avdtp_stream_remove_cb(struct avdtp *session, + struct avdtp_stream *stream, + unsigned int id) { - stream->cb = cb; - stream->user_data = data; + GSList *l; + struct stream_callback *cb; + + for (cb = NULL, l = stream->callbacks; l != NULL; l = l->next) { + struct stream_callback *tmp = l->data; + if (tmp->id == id) { + cb = tmp; + break; + } + } + + if (!cb) + return FALSE; + + stream->callbacks = g_slist_remove(stream->callbacks, cb); + g_free(cb); + + return TRUE; +} + +unsigned int avdtp_stream_add_cb(struct avdtp *session, + struct avdtp_stream *stream, + avdtp_stream_state_cb cb, void *data) +{ + struct stream_callback *stream_cb; + static unsigned int id = 0; + + stream_cb = g_new(struct stream_callback, 1); + stream_cb->cb = cb; + stream_cb->user_data = data; + stream_cb->id = ++id; + + stream->callbacks = g_slist_append(stream->callbacks, stream_cb);; + + return stream_cb->id; } int avdtp_get_configuration(struct avdtp *session, struct avdtp_stream *stream) |