Diff between c584335d44365520d14bc63abeaa48dd3da9a38f and bac077c96b67c8db8df76a49f68f4493db39fc61

Changed Files

File Additions Deletions Status
profiles/audio/transport.c +55 -14 modified

Full Patch

diff --git a/profiles/audio/transport.c b/profiles/audio/transport.c
index 83e3c97..08ed699 100644
--- a/profiles/audio/transport.c
+++ b/profiles/audio/transport.c
@@ -108,6 +108,7 @@ struct bap_transport {
 	struct bt_bap_qos	qos;
 	guint			resume_id;
 	struct iovec		*meta;
+	guint			chan_id;
 };
 
 struct media_transport_ops {
@@ -2098,10 +2099,20 @@ static guint transport_bap_suspend(struct media_transport *transport,
 	return id;
 }
 
+static void bap_clear_chan(struct bap_transport *bap)
+{
+	if (bap->chan_id) {
+		g_source_remove(bap->chan_id);
+		bap->chan_id = 0;
+	}
+}
+
 static void transport_bap_cancel(struct media_transport *transport, guint id)
 {
 	struct bap_transport *bap = transport->data;
 
+	bap_clear_chan(bap);
+
 	if (id == bap->resume_id && bap->resume_id) {
 		g_source_remove(bap->resume_id);
 		bap->resume_id = 0;
@@ -2162,6 +2173,38 @@ static void bap_metadata_changed(struct media_transport *transport)
 	}
 }
 
+static gboolean bap_transport_fd_ready(GIOChannel *chan, GIOCondition cond,
+								gpointer data)
+{
+	struct media_transport *transport = data;
+	struct bap_transport *bap = transport->data;
+	int fd;
+	uint16_t imtu, omtu;
+	GError *err = NULL;
+
+	if (cond & (G_IO_HUP | G_IO_ERR | G_IO_NVAL)) {
+		error("Transport connection failed");
+		goto done;
+	}
+
+	if (!bt_io_get(chan, &err, BT_IO_OPT_OMTU, &omtu,
+					BT_IO_OPT_IMTU, &imtu,
+					BT_IO_OPT_INVALID)) {
+		error("%s", err->message);
+		goto done;
+	}
+
+	fd = g_io_channel_unix_get_fd(chan);
+	media_transport_set_fd(transport, fd, imtu, omtu);
+	transport_update_playing(transport, TRUE);
+
+done:
+	bap->chan_id = 0;
+	bap_resume_complete(transport);
+
+	return FALSE;
+}
+
 static void bap_state_changed(struct bt_bap_stream *stream, uint8_t old_state,
 				uint8_t new_state, void *user_data)
 {
@@ -2170,9 +2213,7 @@ static void bap_state_changed(struct bt_bap_stream *stream, uint8_t old_state,
 	struct media_owner *owner = transport->owner;
 	struct io *io;
 	GIOChannel *chan;
-	GError *err = NULL;
 	int fd;
-	uint16_t imtu, omtu;
 
 	if (bap->stream != stream)
 		return;
@@ -2209,7 +2250,6 @@ static void bap_state_changed(struct bt_bap_stream *stream, uint8_t old_state,
 			bap_update_bcast_qos(transport);
 
 		bap_metadata_changed(transport);
-		transport_update_playing(transport, TRUE);
 		break;
 	case BT_BAP_STREAM_STATE_RELEASING:
 		if (bt_bap_stream_io_dir(stream) == BT_BAP_BCAST_SINK)
@@ -2231,21 +2271,20 @@ static void bap_state_changed(struct bt_bap_stream *stream, uint8_t old_state,
 		goto done;
 	}
 
-	chan = g_io_channel_unix_new(fd);
-
-	if (!bt_io_get(chan, &err, BT_IO_OPT_OMTU, &omtu,
-					BT_IO_OPT_IMTU, &imtu,
-					BT_IO_OPT_INVALID)) {
-		error("%s", err->message);
-		goto done;
-	}
+	/* Wait for FD to become ready */
+	bap_clear_chan(bap);
 
+	chan = g_io_channel_unix_new(fd);
+	bap->chan_id = g_io_add_watch(chan,
+				G_IO_OUT | G_IO_IN |
+				G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+				bap_transport_fd_ready, transport);
 	g_io_channel_unref(chan);
-
-	media_transport_set_fd(transport, fd, imtu, omtu);
-	transport_update_playing(transport, TRUE);
+	if (bap->chan_id)
+		return;
 
 done:
+	bap_clear_chan(bap);
 	bap_resume_complete(transport);
 }
 
@@ -2287,6 +2326,8 @@ static void transport_bap_destroy(void *data)
 {
 	struct bap_transport *bap = data;
 
+	bap_clear_chan(bap);
+
 	util_iov_free(bap->meta, 1);
 	bt_bap_state_unregister(bt_bap_stream_get_session(bap->stream),
 							bap->state_id);