diff options
author | Johan Hedberg <johan.hedberg@nokia.com> | 2007-08-18 21:57:26 +0000 |
---|---|---|
committer | Johan Hedberg <johan.hedberg@nokia.com> | 2007-08-18 21:57:26 +0000 |
commit | c0e0aa5745b38505b180ffdd7d5df44612597e75 (patch) | |
tree | 5c0951ac25effac1d9a4f9d34975413c8847fee7 /audio/a2dp.c | |
parent | 86892be8d38960096f9b9c5613ba28fc9003d288 (diff) |
Accept start requests and add timeout for suspending unused streams
Diffstat (limited to 'audio/a2dp.c')
-rw-r--r-- | audio/a2dp.c | 147 |
1 files changed, 108 insertions, 39 deletions
diff --git a/audio/a2dp.c b/audio/a2dp.c index 2ad660b6..8206b880 100644 --- a/audio/a2dp.c +++ b/audio/a2dp.c @@ -41,6 +41,10 @@ #include "sink.h" #include "a2dp.h" +/* The duration that streams without users are allowed to stay in + * STREAMING state. */ +#define SUSPEND_TIMEOUT 5000 + #ifndef MIN # define MIN(x, y) ((x) < (y) ? (x) : (y)) #endif @@ -51,9 +55,11 @@ struct a2dp_sep { struct avdtp_local_sep *sep; + struct avdtp *session; struct avdtp_stream *stream; struct device *used_by; uint32_t record_id; + guint suspend_timer; gboolean start_requested; gboolean suspending; gboolean starting; @@ -76,11 +82,26 @@ struct a2dp_stream_setup { static DBusConnection *connection = NULL; -static struct a2dp_sep sink = { NULL, NULL, 0 }; -static struct a2dp_sep source = { NULL, NULL, 0 }; +static struct a2dp_sep sink = { NULL }; +static struct a2dp_sep source = { NULL }; static struct a2dp_stream_setup *setup = NULL; +static void stream_cleanup(struct a2dp_sep *sep) +{ + if (sep->suspend_timer) { + g_source_remove(sep->suspend_timer); + sep->suspend_timer = 0; + } + + if (sep->session) { + avdtp_unref(sep->session); + sep->session = NULL; + } + + sep->stream = NULL; +} + static void stream_setup_free(struct a2dp_stream_setup *s) { if (s->session) @@ -109,16 +130,18 @@ static gboolean setconf_ind(struct avdtp *session, GSList *caps, uint8_t *err, uint8_t *category) { + struct a2dp_sep *a2dp_sep; struct device *dev; bdaddr_t addr; if (sep == sink.sep) { debug("SBC Sink: Set_Configuration_Ind"); - return TRUE; + a2dp_sep = &sink; + } else { + debug("SBC Source: Set_Configuration_Ind"); + a2dp_sep = &source; } - debug("SBC Source: Set_Configuration_Ind"); - avdtp_get_peers(session, NULL, &addr); dev = manager_device_connected(&addr, A2DP_SOURCE_UUID); @@ -128,9 +151,10 @@ static gboolean setconf_ind(struct avdtp *session, return FALSE; } - source.stream = stream; + a2dp_sep->stream = stream; - sink_new_stream(dev, session, stream); + if (a2dp_sep == &source) + sink_new_stream(dev, session, stream); return TRUE; } @@ -193,23 +217,25 @@ static void setconf_cfm(struct avdtp *session, struct avdtp_local_sep *sep, struct avdtp_stream *stream, struct avdtp_error *err) { + struct a2dp_sep *a2dp_sep; int ret; if (sep == sink.sep) { debug("SBC Sink: Set_Configuration_Cfm"); - return; + a2dp_sep = &sink; + } else { + debug("SBC Source: Set_Configuration_Cfm"); + a2dp_sep = &source; } - debug("SBC Source: Set_Configuration_Cfm"); - if (err) { - source.stream = NULL; + a2dp_sep->stream = NULL; if (setup) finalize_stream_setup(setup); return; } - source.stream = stream; + a2dp_sep->stream = stream; if (!setup) return; @@ -287,18 +313,40 @@ finalize: finalize_stream_setup(setup); } +static gboolean suspend_timeout(struct a2dp_sep *sep) +{ + if (avdtp_suspend(sep->session, sep->stream) == 0) + sep->suspending = TRUE; + + sep->suspend_timer = FALSE; + + avdtp_unref(sep->session); + sep->session = NULL; + + return FALSE; +} + static gboolean start_ind(struct avdtp *session, struct avdtp_local_sep *sep, struct avdtp_stream *stream, uint8_t *err) { - if (sep == sink.sep) + struct a2dp_sep *a2dp_sep; + + if (sep == sink.sep) { debug("SBC Sink: Start_Ind"); - else + a2dp_sep = &sink; + } + else { debug("SBC Source: Start_Ind"); + a2dp_sep = &source; + } - /* Refuse to go into streaming state since this action should only be - * initiated by alsa */ - *err = AVDTP_NOT_SUPPORTED_COMMAND; - return FALSE; + a2dp_sep->session = avdtp_ref(session); + + a2dp_sep->suspend_timer = g_timeout_add(SUSPEND_TIMEOUT, + (GSourceFunc) suspend_timeout, + a2dp_sep); + + return TRUE; } static void start_cfm(struct avdtp *session, struct avdtp_local_sep *sep, @@ -338,39 +386,45 @@ static gboolean suspend_ind(struct avdtp *session, struct avdtp_local_sep *sep, static void suspend_cfm(struct avdtp *session, struct avdtp_local_sep *sep, struct avdtp_stream *stream, struct avdtp_error *err) { + struct a2dp_sep *a2dp_sep; + if (sep == sink.sep) { debug("SBC Sink: Suspend_Cfm"); - return; + a2dp_sep = &sink; + } else { + debug("SBC Source: Suspend_Cfm"); + a2dp_sep = &source; } - debug("SBC Source: Suspend_Cfm"); - - source.suspending = FALSE; + a2dp_sep->suspending = FALSE; if (err) { - source.start_requested = FALSE; + a2dp_sep->start_requested = FALSE; if (setup) finalize_stream_setup(setup); return; } - if (source.start_requested) { + if (a2dp_sep->start_requested) { avdtp_start(session, stream); - source.start_requested = FALSE; + a2dp_sep->start_requested = FALSE; } } static gboolean close_ind(struct avdtp *session, struct avdtp_local_sep *sep, struct avdtp_stream *stream, uint8_t *err) { + struct a2dp_sep *a2dp_sep; + if (sep == sink.sep) { debug("SBC Sink: Close_Ind"); - return TRUE; + a2dp_sep = &sink; + } else { + debug("SBC Source: Close_Ind"); + a2dp_sep = &source; } - debug("SBC Source: Close_Ind"); - - source.stream = NULL; + stream_cleanup(a2dp_sep); return TRUE; } @@ -378,27 +432,33 @@ static gboolean close_ind(struct avdtp *session, struct avdtp_local_sep *sep, static void close_cfm(struct avdtp *session, struct avdtp_local_sep *sep, struct avdtp_stream *stream, struct avdtp_error *err) { + struct a2dp_sep *a2dp_sep; + if (sep == sink.sep) { debug("SBC Sink: Close_Cfm"); - return; + a2dp_sep = &sink; + } else { + debug("SBC Source: Close_Cfm"); + a2dp_sep = &source; } - debug("SBC Source: Close_Cfm"); - - source.stream = NULL; + stream_cleanup(a2dp_sep); } static gboolean abort_ind(struct avdtp *session, struct avdtp_local_sep *sep, struct avdtp_stream *stream, uint8_t *err) { + struct a2dp_sep *a2dp_sep; + if (sep == sink.sep) { debug("SBC Sink: Abort_Ind"); - return TRUE; + a2dp_sep = &sink; + } else { + debug("SBC Source: Abort_Ind"); + a2dp_sep = &source; } - debug("SBC Source: Abort_Ind"); - - source.stream = NULL; + stream_cleanup(a2dp_sep); return TRUE; } @@ -406,10 +466,17 @@ static gboolean abort_ind(struct avdtp *session, struct avdtp_local_sep *sep, static void abort_cfm(struct avdtp *session, struct avdtp_local_sep *sep, struct avdtp_stream *stream, struct avdtp_error *err) { - if (sep == sink.sep) + struct a2dp_sep *a2dp_sep; + + if (sep == sink.sep) { debug("SBC Sink: Abort_Cfm"); - else + a2dp_sep = &sink; + } else { debug("SBC Source: Abort_Cfm"); + a2dp_sep = &source; + } + + stream_cleanup(a2dp_sep); } static gboolean reconf_ind(struct avdtp *session, struct avdtp_local_sep *sep, @@ -853,6 +920,8 @@ unsigned int a2dp_source_request_stream(struct avdtp *session, break; case AVDTP_STATE_STREAMING: if (!start || !source.suspending) { + if (source.suspend_timer) + g_source_remove(source.suspend_timer); g_idle_add((GSourceFunc) finalize_stream_setup, setup); return cb_data->id; } |