diff options
| author | Johan Hedberg <johan.hedberg@nokia.com> | 2007-08-24 12:15:20 +0000 | 
|---|---|---|
| committer | Johan Hedberg <johan.hedberg@nokia.com> | 2007-08-24 12:15:20 +0000 | 
| commit | 666938b54d631956826343ed278e2af4b982fc29 (patch) | |
| tree | 90828ce9054d431a304bda457ac392cd3798bd9e | |
| parent | c3cd59ae39ebb53e27ddd99ee48f1875bd480c1d (diff) | |
Support up to two simultaneous streams
| -rw-r--r-- | audio/a2dp.c | 435 | ||||
| -rw-r--r-- | audio/a2dp.h | 5 | ||||
| -rw-r--r-- | audio/avdtp.c | 92 | ||||
| -rw-r--r-- | audio/avdtp.h | 50 | ||||
| -rw-r--r-- | audio/sink.c | 6 | ||||
| -rw-r--r-- | audio/unix.c | 8 | 
6 files changed, 364 insertions, 232 deletions
| diff --git a/audio/a2dp.c b/audio/a2dp.c index febc112c..daeda70c 100644 --- a/audio/a2dp.c +++ b/audio/a2dp.c @@ -54,12 +54,13 @@  #endif  struct a2dp_sep { +	uint8_t type;  	struct avdtp_local_sep *sep;  	struct avdtp *session;  	struct avdtp_stream *stream;  	struct device *used_by; -	uint32_t record_id;  	guint suspend_timer; +	gboolean locked;  	gboolean start_requested;  	gboolean suspending;  	gboolean starting; @@ -82,8 +83,11 @@ struct a2dp_stream_setup {  static DBusConnection *connection = NULL; -static struct a2dp_sep sink = { NULL }; -static struct a2dp_sep source = { NULL }; +static GSList *sinks = NULL; +static GSList *sources = NULL; + +static uint32_t source_record_id = 0; +static uint32_t sink_record_id = 0;  static struct a2dp_stream_setup *setup = NULL; @@ -138,19 +142,16 @@ static gboolean setconf_ind(struct avdtp *session,  				struct avdtp_local_sep *sep,  				struct avdtp_stream *stream,  				GSList *caps, uint8_t *err, -				uint8_t *category) +				uint8_t *category, void *user_data)  { -	struct a2dp_sep *a2dp_sep; +	struct a2dp_sep *a2dp_sep = user_data;  	struct device *dev;  	bdaddr_t addr; -	if (sep == sink.sep) { +	if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)  		debug("SBC Sink: Set_Configuration_Ind"); -		a2dp_sep = &sink; -	} else { +	else  		debug("SBC Source: Set_Configuration_Ind"); -		a2dp_sep = &source; -	}  	avdtp_get_peers(session, NULL, &addr); @@ -164,19 +165,20 @@ static gboolean setconf_ind(struct avdtp *session,  	avdtp_stream_add_cb(session, stream, stream_state_changed, a2dp_sep);  	a2dp_sep->stream = stream; -	if (a2dp_sep == &source) +	if (a2dp_sep->type == AVDTP_SEP_TYPE_SOURCE)  		sink_new_stream(dev, session, stream);  	return TRUE;  }  static gboolean getcap_ind(struct avdtp *session, struct avdtp_local_sep *sep, -				GSList **caps, uint8_t *err) +				GSList **caps, uint8_t *err, void *user_data)  { +	struct a2dp_sep *a2dp_sep = user_data;  	struct avdtp_service_capability *media_transport, *media_codec;  	struct sbc_codec_cap sbc_cap; -	if (sep == sink.sep) +	if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)  		debug("SBC Sink: Get_Capability_Ind");  	else  		debug("SBC Source: Get_Capability_Ind"); @@ -226,18 +228,15 @@ static gboolean getcap_ind(struct avdtp *session, struct avdtp_local_sep *sep,  static void setconf_cfm(struct avdtp *session, struct avdtp_local_sep *sep,  				struct avdtp_stream *stream, -				struct avdtp_error *err) +				struct avdtp_error *err, void *user_data)  { -	struct a2dp_sep *a2dp_sep; +	struct a2dp_sep *a2dp_sep = user_data;  	int ret; -	if (sep == sink.sep) { +	if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)  		debug("SBC Sink: Set_Configuration_Cfm"); -		a2dp_sep = &sink; -	} else { +	else  		debug("SBC Source: Set_Configuration_Cfm"); -		a2dp_sep = &source; -	}  	if (err) {  		if (setup) @@ -261,9 +260,11 @@ static void setconf_cfm(struct avdtp *session, struct avdtp_local_sep *sep,  }  static gboolean getconf_ind(struct avdtp *session, struct avdtp_local_sep *sep, -				uint8_t *err) +				uint8_t *err, void *user_data)  { -	if (sep == sink.sep) +	struct a2dp_sep *a2dp_sep = user_data; + +	if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)  		debug("SBC Sink: Get_Configuration_Ind");  	else  		debug("SBC Source: Get_Configuration_Ind"); @@ -271,18 +272,24 @@ static gboolean getconf_ind(struct avdtp *session, struct avdtp_local_sep *sep,  }  static void getconf_cfm(struct avdtp *session, struct avdtp_local_sep *sep, -			struct avdtp_stream *stream, struct avdtp_error *err) +			struct avdtp_stream *stream, struct avdtp_error *err, +			void *user_data)  { -	if (sep == sink.sep) +	struct a2dp_sep *a2dp_sep = user_data; + +	if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)  		debug("SBC Sink: Set_Configuration_Cfm");  	else  		debug("SBC Source: Set_Configuration_Cfm");  }  static gboolean open_ind(struct avdtp *session, struct avdtp_local_sep *sep, -				struct avdtp_stream *stream, uint8_t *err) +				struct avdtp_stream *stream, uint8_t *err, +				void *user_data)  { -	if (sep == sink.sep) +	struct a2dp_sep *a2dp_sep = user_data; + +	if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)  		debug("SBC Sink: Open_Ind");  	else  		debug("SBC Source: Open_Ind"); @@ -290,9 +297,12 @@ static gboolean open_ind(struct avdtp *session, struct avdtp_local_sep *sep,  }  static void open_cfm(struct avdtp *session, struct avdtp_local_sep *sep, -			struct avdtp_stream *stream, struct avdtp_error *err) +			struct avdtp_stream *stream, struct avdtp_error *err, +			void *user_data)  { -	if (sep == sink.sep) +	struct a2dp_sep *a2dp_sep = user_data; + +	if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)  		debug("SBC Sink: Open_Cfm");  	else  		debug("SBC Source: Open_Cfm"); @@ -338,18 +348,15 @@ static gboolean suspend_timeout(struct a2dp_sep *sep)  }  static gboolean start_ind(struct avdtp *session, struct avdtp_local_sep *sep, -				struct avdtp_stream *stream, uint8_t *err) +				struct avdtp_stream *stream, uint8_t *err, +				void *user_data)  { -	struct a2dp_sep *a2dp_sep; +	struct a2dp_sep *a2dp_sep = user_data; -	if (sep == sink.sep) { +	if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)  		debug("SBC Sink: Start_Ind"); -		a2dp_sep = &sink; -	} -	else { +	else  		debug("SBC Source: Start_Ind"); -		a2dp_sep = &source; -	}  	a2dp_sep->session = avdtp_ref(session); @@ -360,9 +367,12 @@ static gboolean start_ind(struct avdtp *session, struct avdtp_local_sep *sep,  }  static void start_cfm(struct avdtp *session, struct avdtp_local_sep *sep, -			struct avdtp_stream *stream, struct avdtp_error *err) +			struct avdtp_stream *stream, struct avdtp_error *err, +			void *user_data)  { -	if (sep == sink.sep) +	struct a2dp_sep *a2dp_sep = user_data; + +	if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)  		debug("SBC Sink: Start_Cfm");  	else  		debug("SBC Source: Start_Cfm"); @@ -384,9 +394,12 @@ static void start_cfm(struct avdtp *session, struct avdtp_local_sep *sep,  }  static gboolean suspend_ind(struct avdtp *session, struct avdtp_local_sep *sep, -				struct avdtp_stream *stream, uint8_t *err) +				struct avdtp_stream *stream, uint8_t *err, +				void *user_data)  { -	if (sep == sink.sep) +	struct a2dp_sep *a2dp_sep = user_data; + +	if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)  		debug("SBC Sink: Suspend_Ind");  	else  		debug("SBC Source: Suspend_Ind"); @@ -394,17 +407,15 @@ 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 avdtp_stream *stream, struct avdtp_error *err, +			void *user_data)  { -	struct a2dp_sep *a2dp_sep; +	struct a2dp_sep *a2dp_sep = user_data; -	if (sep == sink.sep) { +	if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)  		debug("SBC Sink: Suspend_Cfm"); -		a2dp_sep = &sink; -	} else { +	else  		debug("SBC Source: Suspend_Cfm"); -		a2dp_sep = &source; -	}  	a2dp_sep->suspending = FALSE; @@ -422,69 +433,63 @@ static void suspend_cfm(struct avdtp *session, struct avdtp_local_sep *sep,  }  static gboolean close_ind(struct avdtp *session, struct avdtp_local_sep *sep, -				struct avdtp_stream *stream, uint8_t *err) +				struct avdtp_stream *stream, uint8_t *err, +				void *user_data)  { -	struct a2dp_sep *a2dp_sep; +	struct a2dp_sep *a2dp_sep = user_data; -	if (sep == sink.sep) { +	if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)  		debug("SBC Sink: Close_Ind"); -		a2dp_sep = &sink; -	} else { +	else  		debug("SBC Source: Close_Ind"); -		a2dp_sep = &source; -	}  	return TRUE;  }  static void close_cfm(struct avdtp *session, struct avdtp_local_sep *sep, -			struct avdtp_stream *stream, struct avdtp_error *err) +			struct avdtp_stream *stream, struct avdtp_error *err, +			void *user_data)  { -	struct a2dp_sep *a2dp_sep; +	struct a2dp_sep *a2dp_sep = user_data; -	if (sep == sink.sep) { +	if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)  		debug("SBC Sink: Close_Cfm"); -		a2dp_sep = &sink; -	} else { +	else  		debug("SBC Source: Close_Cfm"); -		a2dp_sep = &source; -	}  }  static gboolean abort_ind(struct avdtp *session, struct avdtp_local_sep *sep, -				struct avdtp_stream *stream, uint8_t *err) +				struct avdtp_stream *stream, uint8_t *err, +				void *user_data)  { -	struct a2dp_sep *a2dp_sep; +	struct a2dp_sep *a2dp_sep = user_data; -	if (sep == sink.sep) { +	if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)  		debug("SBC Sink: Abort_Ind"); -		a2dp_sep = &sink; -	} else { +	else  		debug("SBC Source: Abort_Ind"); -		a2dp_sep = &source; -	}  	return TRUE;  }  static void abort_cfm(struct avdtp *session, struct avdtp_local_sep *sep, -			struct avdtp_stream *stream, struct avdtp_error *err) +			struct avdtp_stream *stream, struct avdtp_error *err, +			void *user_data)  { -	struct a2dp_sep *a2dp_sep; +	struct a2dp_sep *a2dp_sep = user_data; -	if (sep == sink.sep) { +	if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)  		debug("SBC Sink: Abort_Cfm"); -		a2dp_sep = &sink; -	} else { +	else  		debug("SBC Source: Abort_Cfm"); -		a2dp_sep = &source; -	}  }  static gboolean reconf_ind(struct avdtp *session, struct avdtp_local_sep *sep, -				uint8_t *err) +				uint8_t *err, void *user_data)  { -	if (sep == sink.sep) +	struct a2dp_sep *a2dp_sep = user_data; + +	if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)  		debug("SBC Sink: ReConfigure_Ind");  	else  		debug("SBC Source: ReConfigure_Ind"); @@ -492,9 +497,12 @@ static gboolean reconf_ind(struct avdtp *session, struct avdtp_local_sep *sep,  }  static void reconf_cfm(struct avdtp *session, struct avdtp_local_sep *sep, -			struct avdtp_stream *stream, struct avdtp_error *err) +			struct avdtp_stream *stream, struct avdtp_error *err, +			void *user_data)  { -	if (sep == sink.sep) +	struct a2dp_sep *a2dp_sep = user_data; + +	if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)  		debug("SBC Sink: ReConfigure_Cfm");  	else  		debug("SBC Source: ReConfigure_Cfm"); @@ -594,10 +602,62 @@ static int a2dp_sink_record(sdp_buf_t *buf)  	return 0;  } -int a2dp_init(DBusConnection *conn, gboolean enable_sink, gboolean enable_source) +static struct a2dp_sep *a2dp_add_sep(DBusConnection *conn, uint8_t type)  { +	struct a2dp_sep *sep; +	GSList **l; +	int (*create_record)(sdp_buf_t *buf); +	uint32_t *record_id;  	sdp_buf_t buf; +	sep = g_new0(struct a2dp_sep, 1); + +	sep->sep = avdtp_register_sep(type, AVDTP_MEDIA_TYPE_AUDIO, +					&ind, &cfm, sep); +	if (sep->sep == NULL) { +		g_free(sep); +		return NULL; +	} + +	sep->type = type; + +	if (type == AVDTP_SEP_TYPE_SOURCE) { +		l = &sources; +		create_record = a2dp_source_record; +		record_id = &source_record_id; +	} else { +		l = &sinks; +		create_record = a2dp_sink_record; +		record_id = &sink_record_id; +	} + +	if (*record_id != 0) +		goto add; + +	if (create_record(&buf) < 0) { +		error("Unable to allocate new service record"); +		avdtp_unregister_sep(sep->sep); +		g_free(sep); +		return NULL; +	} + +	*record_id = add_service_record(conn, &buf); +	free(buf.data); +	if (!*record_id) { +		error("Unable to register A2DP service record"); +		avdtp_unregister_sep(sep->sep); +		g_free(sep); +		return NULL; +	} + +add: +	*l = g_slist_append(*l, sep); + +	return sep; +} + +int a2dp_init(DBusConnection *conn, gboolean enable_sink, gboolean enable_source) +{  	if (!enable_sink && !enable_source)  		return 0; @@ -606,68 +666,40 @@ int a2dp_init(DBusConnection *conn, gboolean enable_sink, gboolean enable_source  	avdtp_init();  	if (enable_sink) { -		source.sep = avdtp_register_sep(AVDTP_SEP_TYPE_SOURCE, -						AVDTP_MEDIA_TYPE_AUDIO, -						&ind, &cfm); -		if (source.sep == NULL) -			return -1; - -		if (a2dp_source_record(&buf) < 0) { -			error("Unable to allocate new service record"); -			return -1; -		} - -		source.record_id = add_service_record(conn, &buf); -		free(buf.data); -		if (!source.record_id) { -			error("Unable to register A2DP Source service record"); -			return -1; -		} +		a2dp_add_sep(conn, AVDTP_SEP_TYPE_SOURCE); +		a2dp_add_sep(conn, AVDTP_SEP_TYPE_SOURCE);  	} -	if (enable_source) { -		sink.sep = avdtp_register_sep(AVDTP_SEP_TYPE_SINK, -						AVDTP_MEDIA_TYPE_AUDIO, -						&ind, &cfm); -		if (sink.sep == NULL) -			return -1; - -		if (a2dp_sink_record(&buf) < 0) { -			error("Unable to allocate new service record"); -			return -1; -		} - -		sink.record_id = add_service_record(conn, &buf); -		free(buf.data); -		if (!sink.record_id) { -			error("Unable to register A2DP Sink service record"); -			return -1; -		} -	} +	if (enable_source) +		a2dp_add_sep(conn, AVDTP_SEP_TYPE_SINK);  	return 0;  } +static void a2dp_unregister_sep(struct a2dp_sep *sep) +{ +	avdtp_unregister_sep(sep->sep); +	g_free(sep); +} +  void a2dp_exit()  { -	if (sink.sep) { -		avdtp_unregister_sep(sink.sep); -		sink.sep = NULL; -	} +	g_slist_foreach(sinks, (GFunc) a2dp_unregister_sep, NULL); +	g_slist_free(sinks); +	sinks = NULL; -	if (source.sep) { -		avdtp_unregister_sep(source.sep); -		source.sep = NULL; -	} +	g_slist_foreach(sources, (GFunc) a2dp_unregister_sep, NULL); +	g_slist_free(sources); +	sources = NULL; -	if (source.record_id) { -		remove_service_record(connection, source.record_id); -		source.record_id = 0; +	if (source_record_id) { +		remove_service_record(connection, source_record_id); +		source_record_id = 0;  	} -	if (sink.record_id) { -		remove_service_record(connection, sink.record_id); -		sink.record_id = 0; +	if (sink_record_id) { +		remove_service_record(connection, sink_record_id); +		sink_record_id = 0;  	}  	dbus_connection_unref(connection); @@ -878,15 +910,31 @@ gboolean a2dp_source_cancel_stream(int id)  }  unsigned int a2dp_source_request_stream(struct avdtp *session, -					struct device *dev, -					gboolean start, a2dp_stream_cb_t cb, -					void *user_data) +						struct device *dev, +						gboolean start, +						a2dp_stream_cb_t cb, +						void *user_data, +						struct a2dp_sep **ret)  {  	struct a2dp_stream_cb *cb_data;  	static unsigned int cb_id = 0; +	GSList *l; +	struct a2dp_sep *sep = NULL; -	if (source.used_by != NULL && source.used_by != dev) { -		error("a2dp_source_request_stream: SEP is locked"); +	for (l = sources; l != NULL; l = l->next) { +		struct a2dp_sep *tmp = l->data; + +		if (tmp->locked) +			continue; + +		if (tmp->used_by == NULL || tmp->used_by == dev) { +			sep = tmp; +			break; +		} +	} + +	if (!sep) { +		error("a2dp_source_request_stream: no available SEP found");  		return 0;  	} @@ -896,6 +944,10 @@ unsigned int a2dp_source_request_stream(struct avdtp *session,  		return 0;  	} +	sep->used_by = dev; + +	debug("a2dp_source_request_stream: selected SEP %p", sep); +  	cb_data = g_new(struct a2dp_stream_cb, 1);  	cb_data->cb = cb;  	cb_data->user_data = user_data; @@ -914,9 +966,9 @@ unsigned int a2dp_source_request_stream(struct avdtp *session,  	setup->dev = dev;  	setup->cb = g_slist_append(setup->cb, cb_data);  	setup->start = start; -	setup->stream = source.stream; +	setup->stream = sep->stream; -	switch (avdtp_sep_get_state(source.sep)) { +	switch (avdtp_sep_get_state(sep->sep)) {  	case AVDTP_STATE_IDLE:  		if (avdtp_discover(session, discovery_complete, setup) < 0) {  			error("avdtp_discover failed"); @@ -928,32 +980,35 @@ unsigned int a2dp_source_request_stream(struct avdtp *session,  			g_idle_add((GSourceFunc) finalize_stream_setup, setup);  			break;  		} -		if (source.starting) +		if (sep->starting)  			break; -		if (avdtp_start(session, source.stream) < 0) { +		if (avdtp_start(session, sep->stream) < 0) {  			error("avdtp_start failed");  			goto failed;  		}  		break;  	case AVDTP_STATE_STREAMING: -		if (!start || !source.suspending) { -			if (source.suspend_timer) { -				g_source_remove(source.suspend_timer); -				source.suspend_timer = 0; +		if (!start || !sep->suspending) { +			if (sep->suspend_timer) { +				g_source_remove(sep->suspend_timer); +				sep->suspend_timer = 0;  			} -			if (source.session) { -				avdtp_unref(source.session); -				source.session = NULL; +			if (sep->session) { +				avdtp_unref(sep->session); +				sep->session = NULL;  			}  			g_idle_add((GSourceFunc) finalize_stream_setup, setup);  			return cb_data->id;  		} -		source.start_requested = TRUE; +		sep->start_requested = TRUE;  		break;  	default:  		error("SEP in bad state for requesting a new stream");  		goto failed;  	} +	 +	if (ret) +		*ret = sep;  	return cb_data->id; @@ -965,33 +1020,51 @@ failed:  gboolean a2dp_source_lock(struct device *dev, struct avdtp *session)  { -	if (source.used_by) -		return FALSE; +	GSList *l; -	debug("SBC Source locked"); +	for (l = sources; l != NULL; l = l->next) { +		struct a2dp_sep *sep = l->data; -	source.used_by = dev; +		if (sep->locked) +			continue; -	return TRUE; +		debug("SBC Source SEP %p locked", sep); +		sep->locked = TRUE; +		return TRUE; +	} + +	return FALSE;  }  gboolean a2dp_source_unlock(struct device *dev, struct avdtp *session)  {  	avdtp_state_t state; +	GSList *l; +	struct a2dp_sep *sep = NULL; -	if (!source.sep) -		return FALSE; +	for (l = sources; l != NULL; l = l->next) { +		struct a2dp_sep *tmp = l->data; + +		if (!sep->locked) +			continue; + +		if (tmp->sep && tmp->used_by == dev) { +			sep = tmp; +			break; +		} +	} -	if (source.used_by != dev) +	if (!sep)  		return FALSE; -	state = avdtp_sep_get_state(source.sep); +	state = avdtp_sep_get_state(sep->sep); -	source.used_by = NULL; +	sep->locked = FALSE; +	sep->used_by = NULL; -	debug("SBC Source unlocked"); +	debug("SBC Source SEP %p unlocked", sep); -	if (!source.stream || state == AVDTP_STATE_IDLE) +	if (!sep->stream || state == AVDTP_STATE_IDLE)  		return TRUE;  	switch (state) { @@ -999,8 +1072,8 @@ gboolean a2dp_source_unlock(struct device *dev, struct avdtp *session)  		/* Set timer here */  		break;  	case AVDTP_STATE_STREAMING: -		if (avdtp_suspend(session, source.stream) == 0) -			source.suspending = TRUE; +		if (avdtp_suspend(session, sep->stream) == 0) +			sep->suspending = TRUE;  		break;  	default:  		break; @@ -1012,20 +1085,28 @@ gboolean a2dp_source_unlock(struct device *dev, struct avdtp *session)  gboolean a2dp_source_suspend(struct device *dev, struct avdtp *session)  {  	avdtp_state_t state; +	GSList *l; +	struct a2dp_sep *sep = NULL; -	if (!source.sep) -		return FALSE; +	for (l = sources; l != NULL; l = l->next) { +		struct a2dp_sep *tmp = l->data; -	if (source.used_by != dev) +		if (tmp->sep && tmp->used_by == dev) { +			sep = tmp; +			break; +		} +	} + +	if (!sep)  		return FALSE; -	state = avdtp_sep_get_state(source.sep); +	state = avdtp_sep_get_state(sep->sep); -	if (!source.stream || state != AVDTP_STATE_STREAMING) +	if (!sep->stream || state != AVDTP_STATE_STREAMING)  		return TRUE; -	if (avdtp_suspend(session, source.stream) == 0) { -		source.suspending = TRUE; +	if (avdtp_suspend(session, sep->stream) == 0) { +		sep->suspending = TRUE;  		return TRUE;  	} @@ -1035,14 +1116,22 @@ gboolean a2dp_source_suspend(struct device *dev, struct avdtp *session)  gboolean a2dp_source_start_stream(struct device *dev, struct avdtp *session)  {  	avdtp_state_t state; +	GSList *l; +	struct a2dp_sep *sep = NULL; -	if (!source.sep) -		return FALSE; +	for (l = sources; l != NULL; l = l->next) { +		struct a2dp_sep *tmp = l->data; + +		if (tmp->sep && tmp->used_by == dev) { +			sep = tmp; +			break; +		} +	} -	if (source.used_by != dev) +	if (!sep)  		return FALSE; -	state = avdtp_sep_get_state(source.sep); +	state = avdtp_sep_get_state(sep->sep);  	if (state < AVDTP_STATE_OPEN) {  		error("a2dp_source_start_stream: no stream open"); @@ -1052,7 +1141,7 @@ gboolean a2dp_source_start_stream(struct device *dev, struct avdtp *session)  	if (state == AVDTP_STATE_STREAMING)  		return TRUE; -	if (avdtp_start(session, source.stream) < 0) +	if (avdtp_start(session, sep->stream) < 0)  		return FALSE;  	return TRUE; diff --git a/audio/a2dp.h b/audio/a2dp.h index 6d69189c..0a838b62 100644 --- a/audio/a2dp.h +++ b/audio/a2dp.h @@ -58,6 +58,8 @@ struct sbc_codec_cap {  	uint8_t max_bitpool;  } __attribute__ ((packed)); +struct a2dp_sep; +  typedef void (*a2dp_stream_cb_t) (struct avdtp *session, struct device *dev,  					struct avdtp_stream *stream,  					void *user_data); @@ -69,7 +71,8 @@ void a2dp_exit(void);  unsigned int a2dp_source_request_stream(struct avdtp *session,  					struct device *dev,  					gboolean start, a2dp_stream_cb_t cb, -					void *user_data); +					void *user_data, +					struct a2dp_sep **sep);  gboolean a2dp_source_cancel_stream(int id);  gboolean a2dp_source_lock(struct device *dev, struct avdtp *session); diff --git a/audio/avdtp.c b/audio/avdtp.c index 0b56340f..99a929f4 100644 --- a/audio/avdtp.c +++ b/audio/avdtp.c @@ -219,7 +219,7 @@ struct avdtp_local_sep {  	GSList *caps;  	struct avdtp_sep_ind *ind;  	struct avdtp_sep_cfm *cfm; -	void *data; +	void *user_data;  };  struct stream_callback { @@ -573,7 +573,7 @@ static void release_stream(struct avdtp_stream *stream, struct avdtp *session)  		g_source_remove(stream->io);  	if (sep->cfm && sep->cfm->abort) -		sep->cfm->abort(session, sep, stream, NULL); +		sep->cfm->abort(session, sep, stream, NULL, sep->user_data);  	avdtp_sep_set_state(session, sep, AVDTP_STATE_IDLE);  } @@ -815,7 +815,8 @@ static gboolean avdtp_getcap_cmd(struct avdtp *session,  		goto failed;  	} -	if (!sep->ind->get_capability(session, sep, &caps, &err)) +	if (!sep->ind->get_capability(session, sep, &caps, &err, +					sep->user_data))  		goto failed;  	init_response(&rsp->header, &req->header, TRUE); @@ -882,7 +883,8 @@ static gboolean avdtp_setconf_cmd(struct avdtp *session,  	if (sep->ind && sep->ind->set_configuration) {  		if (!sep->ind->set_configuration(session, sep, stream,  							stream->caps, &err, -							&category)) { +							&category, +							sep->user_data)) {  			stream_free(stream);  			goto failed;  		} @@ -949,7 +951,8 @@ static gboolean avdtp_open_cmd(struct avdtp *session, struct seid_req *req,  	stream = sep->stream;  	if (sep->ind && sep->ind->open) { -		if (!sep->ind->open(session, sep, stream, &err)) +		if (!sep->ind->open(session, sep, stream, &err, +					sep->user_data))  			goto failed;  	} @@ -1009,7 +1012,8 @@ static gboolean avdtp_start_cmd(struct avdtp *session, struct start_req *req,  		}  		if (sep->ind && sep->ind->start) { -			if (!sep->ind->start(session, sep, stream, &err)) +			if (!sep->ind->start(session, sep, stream, &err, +						sep->user_data))  				goto failed;  		} @@ -1057,7 +1061,8 @@ static gboolean avdtp_close_cmd(struct avdtp *session, struct seid_req *req,  	stream = sep->stream;  	if (sep->ind && sep->ind->close) { -		if (!sep->ind->close(session, sep, stream, &err)) +		if (!sep->ind->close(session, sep, stream, &err, +					sep->user_data))  			goto failed;  	} @@ -1116,7 +1121,8 @@ static gboolean avdtp_suspend_cmd(struct avdtp *session,  		}  		if (sep->ind && sep->ind->suspend) { -			if (!sep->ind->suspend(session, sep, stream, &err)) +			if (!sep->ind->suspend(session, sep, stream, &err, +						sep->user_data))  				goto failed;  		} @@ -1156,7 +1162,8 @@ static gboolean avdtp_abort_cmd(struct avdtp *session, struct seid_req *req,  	}  	if (sep->ind && sep->ind->abort) { -		if (!sep->ind->abort(session, sep, sep->stream, &err)) +		if (!sep->ind->abort(session, sep, sep->stream, &err, +					sep->user_data))  			goto failed;  	} @@ -1230,7 +1237,8 @@ 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, NULL); +		sep->cfm->close(stream->session, sep, stream, NULL, +				sep->user_data);  	avdtp_sep_set_state(stream->session, sep, AVDTP_STATE_IDLE); @@ -1255,7 +1263,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, NULL); +		sep->cfm->open(session, sep, stream, NULL, sep->user_data);  	channel = g_io_channel_unix_new(stream->sock); @@ -1556,36 +1564,41 @@ static gboolean request_timeout(gpointer user_data)  	case AVDTP_RECONFIGURE:  		error("Reconfigure request timed out");  		if (lsep && lsep->cfm && lsep->cfm->reconfigure) -			lsep->cfm->reconfigure(session, lsep, stream, &err); +			lsep->cfm->reconfigure(session, lsep, stream, &err, +						lsep->user_data);  		break;  	case AVDTP_OPEN:  		error("Open request timed out");  		if (lsep && lsep->cfm && lsep->cfm->open) -			lsep->cfm->open(session, lsep, stream, &err); +			lsep->cfm->open(session, lsep, stream, &err, +					lsep->user_data);  		break;  	case AVDTP_START:  		error("Start request timed out");  		if (lsep && lsep->cfm && lsep->cfm->start) -			lsep->cfm->start(session, lsep, stream, &err); +			lsep->cfm->start(session, lsep, stream, &err, +						lsep->user_data);  		break;  	case AVDTP_SUSPEND:  		error("Suspend request timed out");  		if (lsep && lsep->cfm && lsep->cfm->suspend) -			lsep->cfm->suspend(session, lsep, stream, &err); +			lsep->cfm->suspend(session, lsep, stream, &err, +						lsep->user_data);  		break;  	case AVDTP_CLOSE:  		error("Close request timed out");  		if (lsep && lsep->cfm && lsep->cfm->close) -			lsep->cfm->close(session, lsep, stream, &err); +			lsep->cfm->close(session, lsep, stream, &err, +						lsep->user_data);  		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 */ +			lsep->cfm->set_configuration(session, lsep, stream, +							&err, lsep->user_data); +		goto failed;  	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"); @@ -1756,7 +1769,8 @@ 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, NULL); +		sep->cfm->set_configuration(session, sep, stream, NULL, +						sep->user_data);  	avdtp_sep_set_state(session, sep, AVDTP_STATE_CONFIGURED); @@ -1794,7 +1808,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, NULL); +		sep->cfm->start(session, sep, stream, NULL, sep->user_data);  	avdtp_sep_set_state(session, sep, AVDTP_STATE_STREAMING); @@ -1825,7 +1839,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, NULL); +		sep->cfm->suspend(session, sep, stream, NULL, sep->user_data);  	return TRUE;  } @@ -1837,7 +1851,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, NULL); +		sep->cfm->suspend(session, sep, stream, NULL, sep->user_data);  	avdtp_sep_set_state(session, sep, AVDTP_STATE_IDLE); @@ -1973,7 +1987,8 @@ static gboolean avdtp_parse_rej(struct avdtp *session, struct avdtp_stream *stre  		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); +			sep->cfm->open(session, sep, stream, &err, +					sep->user_data);  		return TRUE;  	case AVDTP_SET_CONFIGURATION:  		if (!conf_rej_to_err((void *) header, size, &err, &category)) @@ -1981,7 +1996,8 @@ static gboolean avdtp_parse_rej(struct avdtp *session, struct avdtp_stream *stre  		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); +			sep->cfm->set_configuration(session, sep, stream, +							&err, sep->user_data);  		return TRUE;  	case AVDTP_RECONFIGURE:  		if (!conf_rej_to_err((void *) header, size, &err, &category)) @@ -1989,7 +2005,8 @@ static gboolean avdtp_parse_rej(struct avdtp *session, struct avdtp_stream *stre  		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); +			sep->cfm->reconfigure(session, sep, stream, &err, +						sep->user_data);  		return TRUE;  	case AVDTP_START:  		if (!stream_rej_to_err((void *) header, size, &err, &acp_seid)) @@ -1997,7 +2014,8 @@ static gboolean avdtp_parse_rej(struct avdtp *session, struct avdtp_stream *stre  		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); +			sep->cfm->start(session, sep, stream, &err, +					sep->user_data);  		return TRUE;  	case AVDTP_SUSPEND:  		if (!stream_rej_to_err((void *) header, size, &err, &acp_seid)) @@ -2005,7 +2023,8 @@ static gboolean avdtp_parse_rej(struct avdtp *session, struct avdtp_stream *stre  		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); +			sep->cfm->suspend(session, sep, stream, &err, +						sep->user_data);  		return TRUE;  	case AVDTP_CLOSE:  		if (!stream_rej_to_err((void *) header, size, &err, &acp_seid)) @@ -2013,7 +2032,8 @@ static gboolean avdtp_parse_rej(struct avdtp *session, struct avdtp_stream *stre  		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); +			sep->cfm->close(session, sep, stream, &err, +					sep->user_data);  		return TRUE;  	case AVDTP_ABORT:  		if (!stream_rej_to_err((void *) header, size, &err, &acp_seid)) @@ -2021,7 +2041,8 @@ static gboolean avdtp_parse_rej(struct avdtp *session, struct avdtp_stream *stre  		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); +			sep->cfm->abort(session, sep, stream, &err, +					sep->user_data);  		return TRUE;  	default:  		error("Unknown reject response signal id: %u", @@ -2298,6 +2319,9 @@ int avdtp_set_configuration(struct avdtp *session,  	if (!(lsep && rsep))  		return -EINVAL; +	debug("avdtp_set_configuration(%p): int_seid=%u, acp_seid=%u", +			session, lsep->info.seid, rsep->seid); +  	new_stream = g_new0(struct avdtp_stream, 1);  	new_stream->session = session; @@ -2314,8 +2338,8 @@ int avdtp_set_configuration(struct avdtp *session,  	req = g_malloc0(sizeof(struct setconf_req) + caps_len);  	init_request(&req->header, AVDTP_SET_CONFIGURATION); -	req->acp_seid = lsep->info.seid; -	req->int_seid = rsep->seid; +	req->int_seid = lsep->info.seid; +	req->acp_seid = rsep->seid;  	/* Copy the capabilities into the request */  	for (l = caps, ptr = req->caps; l != NULL; l = g_slist_next(l)) { @@ -2457,7 +2481,8 @@ int avdtp_abort(struct avdtp *session, struct avdtp_stream *stream)  struct avdtp_local_sep *avdtp_register_sep(uint8_t type, uint8_t media_type,  						struct avdtp_sep_ind *ind, -						struct avdtp_sep_cfm *cfm) +						struct avdtp_sep_cfm *cfm, +						void *user_data)  {  	struct avdtp_local_sep *sep; @@ -2472,6 +2497,7 @@ struct avdtp_local_sep *avdtp_register_sep(uint8_t type, uint8_t media_type,  	sep->info.media_type = media_type;  	sep->ind = ind;  	sep->cfm = cfm; +	sep->user_data = user_data;  	local_seps = g_slist_append(local_seps, sep); diff --git a/audio/avdtp.h b/audio/avdtp.h index 49907cff..d759be48 100644 --- a/audio/avdtp.h +++ b/audio/avdtp.h @@ -97,28 +97,32 @@ struct avdtp_sep_cfm {  	void (*set_configuration) (struct avdtp *session,  					struct avdtp_local_sep *lsep,  					struct avdtp_stream *stream, -					struct avdtp_error *err); +					struct avdtp_error *err, +					void *user_data);  	void (*get_configuration) (struct avdtp *session,  					struct avdtp_local_sep *lsep,  					struct avdtp_stream *stream, -					struct avdtp_error *err); +					struct avdtp_error *err, +					void *user_data);  	void (*open) (struct avdtp *session, struct avdtp_local_sep *lsep, -			struct avdtp_stream *stream, struct avdtp_error *err); +			struct avdtp_stream *stream, struct avdtp_error *err, +			void *user_data);  	void (*start) (struct avdtp *session, struct avdtp_local_sep *lsep, -			struct avdtp_stream *stream, struct avdtp_error *err); +			struct avdtp_stream *stream, struct avdtp_error *err, +			void *user_data);  	void (*suspend) (struct avdtp *session, struct avdtp_local_sep *lsep,  				struct avdtp_stream *stream, -				struct avdtp_error *err); +				struct avdtp_error *err, void *user_data);  	void (*close) (struct avdtp *session, struct avdtp_local_sep *lsep,  				struct avdtp_stream *stream, -				struct avdtp_error *err); +				struct avdtp_error *err, void *user_data);  	void (*abort) (struct avdtp *session, struct avdtp_local_sep *lsep,  				struct avdtp_stream *stream, -				struct avdtp_error *err); +				struct avdtp_error *err, void *user_data);  	void (*reconfigure) (struct avdtp *session,  				struct avdtp_local_sep *lsep,  				struct avdtp_stream *stream, -				struct avdtp_error *err); +				struct avdtp_error *err, void *user_data);  };  /* Callbacks for indicating when we received a new command. The return value @@ -126,32 +130,35 @@ struct avdtp_sep_cfm {  struct avdtp_sep_ind {  	gboolean (*get_capability) (struct avdtp *session,  					struct avdtp_local_sep *sep, -					GSList **caps, uint8_t *err); +					GSList **caps, uint8_t *err, +					void *user_data);  	gboolean (*set_configuration) (struct avdtp *session,  					struct avdtp_local_sep *lsep,  					struct avdtp_stream *stream,  					GSList *caps, uint8_t *err, -					uint8_t *category); +					uint8_t *category, void *user_data);  	gboolean (*get_configuration) (struct avdtp *session,  					struct avdtp_local_sep *lsep, -					uint8_t *err); +					uint8_t *err, void *user_data);  	gboolean (*open) (struct avdtp *session, struct avdtp_local_sep *lsep, -				struct avdtp_stream *stream, uint8_t *err); +				struct avdtp_stream *stream, uint8_t *err, +				void *user_data);  	gboolean (*start) (struct avdtp *session, struct avdtp_local_sep *lsep, -				struct avdtp_stream *stream, -				uint8_t *err); +				struct avdtp_stream *stream, uint8_t *err, +				void *user_data);  	gboolean (*suspend) (struct avdtp *session,  				struct avdtp_local_sep *sep, -				struct avdtp_stream *stream, -				uint8_t *err); +				struct avdtp_stream *stream, uint8_t *err, +				void *user_data);  	gboolean (*close) (struct avdtp *session, struct avdtp_local_sep *sep, -				struct avdtp_stream *stream, -				uint8_t *err); +				struct avdtp_stream *stream, uint8_t *err, +				void *user_data);  	gboolean (*abort) (struct avdtp *session, struct avdtp_local_sep *sep, -				struct avdtp_stream *stream, uint8_t *err); +				struct avdtp_stream *stream, uint8_t *err, +				void *user_data);  	gboolean (*reconfigure) (struct avdtp *session,  					struct avdtp_local_sep *lsep, -					uint8_t *err); +					uint8_t *err, void *user_data);  };  typedef void (*avdtp_discover_cb_t) (struct avdtp *session, GSList *seps, @@ -200,7 +207,8 @@ int avdtp_abort(struct avdtp *session, struct avdtp_stream *stream);  struct avdtp_local_sep *avdtp_register_sep(uint8_t type, uint8_t media_type,  						struct avdtp_sep_ind *ind, -						struct avdtp_sep_cfm *cfm); +						struct avdtp_sep_cfm *cfm, +						void *user_data);  /* Find a matching pair of local and remote SEP ID's */  int avdtp_get_seps(struct avdtp *session, uint8_t type, uint8_t media, diff --git a/audio/sink.c b/audio/sink.c index 8141eff5..0dc12eb3 100644 --- a/audio/sink.c +++ b/audio/sink.c @@ -149,11 +149,13 @@ static void stream_setup_complete(struct avdtp *session, struct device *dev,  		DBusMessage *reply;  		reply = dbus_message_new_method_return(pending->msg);  		send_message_and_unref(pending->conn, reply); +		debug("Stream successfully created");  	}  	else {  		err_failed(pending->conn, pending->msg, "Stream setup failed");  		avdtp_unref(sink->session);  		sink->session = NULL; +		debug("Stream setup failed");  	}  	pending_request_free(pending); @@ -186,7 +188,7 @@ static DBusHandlerResult sink_connect(DBusConnection *conn,  	sink->connect = pending;  	id = a2dp_source_request_stream(sink->session, dev, FALSE, -					stream_setup_complete, pending); +					stream_setup_complete, pending, NULL);  	if (id == 0) {  		pending_request_free(pending);  		sink->connect = NULL; @@ -196,6 +198,8 @@ static DBusHandlerResult sink_connect(DBusConnection *conn,  						"Failed to request a stream");  	} +	debug("stream creation in progress"); +  	pending->id = id;  	return DBUS_HANDLER_RESULT_HANDLED; diff --git a/audio/unix.c b/audio/unix.c index 2b9b74f0..a04c5bfb 100644 --- a/audio/unix.c +++ b/audio/unix.c @@ -61,10 +61,12 @@ typedef void (*notify_cb_t) (struct device *dev, void *data);  struct a2dp_data {  	struct avdtp *session;  	struct avdtp_stream *stream; +	struct a2dp_sep *sep;  };  struct unix_client {  	struct device *dev; +	struct avdtp_local_sep *sep;  	service_type_t type;  	union {  		struct a2dp_data a2dp; @@ -335,7 +337,7 @@ proceed:  		id = a2dp_source_request_stream(a2dp->session, dev,  						TRUE, a2dp_setup_complete, -						client); +						client, &a2dp->sep);  		if (id == 0) {  			error("request_stream failed");  			goto failed; @@ -414,7 +416,7 @@ static gboolean client_cb(GIOChannel *chan, GIOCondition cond, gpointer data)  	}  	if (cond & (G_IO_HUP | G_IO_ERR)) { -		debug("Unix client disconnected"); +		debug("Unix client disconnected (fd=%d)", client->sock);  		if (!client->dev)  			goto failed;  		if (client->disconnect) @@ -488,7 +490,7 @@ static gboolean server_cb(GIOChannel *chan, GIOCondition cond, gpointer data)  		return TRUE;  	} -	debug("Accepted new client connection on unix socket"); +	debug("Accepted new client connection on unix socket (fd=%d)", cli_sk);  	client = g_new0(struct unix_client, 1);  	client->sock = cli_sk; | 
