From df235d1f395b10654024979180c778777bd50c71 Mon Sep 17 00:00:00 2001 From: Luiz Augusto von Dentz Date: Fri, 29 Jun 2007 23:19:36 +0000 Subject: Handle state machine in a better way and add disconnect code for plugin. --- audio/headset.c | 124 +++++++++++++++++++++----------------------------- audio/pcm_bluetooth.c | 20 ++++++++ audio/unix.c | 54 ++++++++++++++++------ 3 files changed, 114 insertions(+), 84 deletions(-) diff --git a/audio/headset.c b/audio/headset.c index 28f6ac1d..ca24e93b 100644 --- a/audio/headset.c +++ b/audio/headset.c @@ -181,11 +181,6 @@ static void close_sco(struct device *device) g_io_channel_close(hs->sco); g_io_channel_unref(hs->sco); hs->sco = NULL; - hs->state = HEADSET_STATE_CONNECTED; - dbus_connection_emit_signal(device->conn, device->path, - AUDIO_HEADSET_INTERFACE, - "Stopped", - DBUS_TYPE_INVALID); } } @@ -286,8 +281,7 @@ static gboolean rfcomm_io_cb(GIOChannel *chan, GIOCondition cond, return TRUE; failed: - close_sco(device); - headset_close_rfcomm(device); + headset_set_state(device, HEADSET_STATE_DISCONNECTED); return FALSE; } @@ -304,7 +298,7 @@ static gboolean sco_cb(GIOChannel *chan, GIOCondition cond, error("Audio connection got disconnected"); - close_sco(device); + headset_set_state(device, HEADSET_STATE_CONNECTED); return FALSE; } @@ -359,9 +353,8 @@ static gboolean sco_connect_cb(GIOChannel *chan, GIOCondition cond, { struct headset *hs; struct pending_connect *c; - int ret, sk, err, flags; + int ret, sk, err; socklen_t len; - char str[13]; if (cond & G_IO_NVAL) return FALSE; @@ -390,29 +383,12 @@ static gboolean sco_connect_cb(GIOChannel *chan, GIOCondition cond, hs->sco = chan; c->io = NULL; - flags = G_IO_ERR | G_IO_HUP | G_IO_NVAL; - - g_io_add_watch(hs->sco, flags, (GIOFunc) sco_cb, device); - g_slist_foreach(hs->pending, (GFunc)pending_connect_ok, device); g_slist_free(hs->pending); hs->pending = NULL; fcntl(sk, F_SETFL, 0); - hs->state = HEADSET_STATE_PLAYING; - dbus_connection_emit_signal(device->conn, device->path, - AUDIO_HEADSET_INTERFACE, - "Playing", DBUS_TYPE_INVALID); - - if (hs->sp_gain >= 0) { - snprintf(str, sizeof(str) - 1, "\r\n+VGS=%u\r\n", hs->sp_gain); - headset_send(device->headset, str); - } - - if (hs->mic_gain >= 0) { - snprintf(str, sizeof(str) - 1, "\r\n+VGM=%u\r\n", hs->sp_gain); - headset_send(device->headset, str); - } + headset_set_state(device, HEADSET_STATE_PLAYING); return FALSE; @@ -420,7 +396,7 @@ failed: g_slist_foreach(hs->pending, (GFunc)pending_connect_failed, device); g_slist_free(hs->pending); hs->pending = NULL; - hs->state = HEADSET_STATE_CONNECTED; + headset_set_state(device, HEADSET_STATE_CONNECTED); return FALSE; } @@ -486,7 +462,7 @@ static int sco_connect(struct device *device, struct pending_connect *c) do_callback = TRUE; } - hs->state = HEADSET_STATE_PLAY_IN_PROGRESS; + headset_set_state(device, HEADSET_STATE_PLAY_IN_PROGRESS); if (!g_slist_find(hs->pending, c)) hs->pending = g_slist_append(hs->pending, c); @@ -530,12 +506,8 @@ static gboolean rfcomm_connect_cb(GIOChannel *chan, GIOCondition cond, hs->rfcomm = chan; c->io = NULL; - hs->state = HEADSET_STATE_CONNECTED; - dbus_connection_emit_signal(device->conn, device->path, - AUDIO_HEADSET_INTERFACE, - "Connected", DBUS_TYPE_INVALID); + headset_set_state(device, HEADSET_STATE_CONNECTED); - device_store(device, FALSE); debug("Connected to %s", hs_address); g_io_add_watch(chan, G_IO_IN | G_IO_ERR | G_IO_HUP| G_IO_NVAL, @@ -558,9 +530,9 @@ failed: g_slist_free(hs->pending); hs->pending = NULL; if (hs->rfcomm) - hs->state = HEADSET_STATE_CONNECTED; + headset_set_state(device, HEADSET_STATE_CONNECTED); else - hs->state = HEADSET_STATE_DISCONNECTED; + headset_set_state(device, HEADSET_STATE_DISCONNECTED); return FALSE; } @@ -676,7 +648,7 @@ failed: g_slist_foreach(hs->pending, (GFunc)pending_connect_failed, device); g_slist_free(hs->pending); hs->pending = NULL; - hs->state = HEADSET_STATE_DISCONNECTED; + headset_set_state(device, HEADSET_STATE_DISCONNECTED); device_finish_sdp_transaction(device); } @@ -778,7 +750,7 @@ failed: g_slist_foreach(hs->pending, (GFunc)pending_connect_failed, device); g_slist_free(hs->pending); hs->pending = NULL; - hs->state = HEADSET_STATE_DISCONNECTED; + headset_set_state(device, HEADSET_STATE_DISCONNECTED); } static int get_handles(struct device *device) @@ -809,7 +781,7 @@ static int get_handles(struct device *device) DBUS_TYPE_STRING, &hs_svc, DBUS_TYPE_INVALID); - hs->state = HEADSET_STATE_CONNECT_IN_PROGRESS; + headset_set_state(device, HEADSET_STATE_CONNECT_IN_PROGRESS); if (!dbus_connection_send_with_reply(device->conn, msg, &pending, -1)) { error("Sending GetRemoteServiceHandles failed"); dbus_message_unref(msg); @@ -919,18 +891,10 @@ static DBusHandlerResult hs_stop(DBusConnection *conn, DBusMessage *msg, if (!reply) return DBUS_HANDLER_RESULT_NEED_MEMORY; - switch(hs->state) { - case HEADSET_STATE_PLAYING: - case HEADSET_STATE_PLAY_IN_PROGRESS: - close_sco(device); - break; - case HEADSET_STATE_CONNECTED: - case HEADSET_STATE_CONNECT_IN_PROGRESS: - case HEADSET_STATE_DISCONNECTED: + if (hs->state < HEADSET_STATE_PLAY_IN_PROGRESS) return err_not_connected(conn, msg); - break; - } + headset_set_state(device, HEADSET_STATE_CONNECTED); send_message_and_unref(conn, reply); return DBUS_HANDLER_RESULT_HANDLED; @@ -970,19 +934,10 @@ static DBusHandlerResult hs_disconnect(DBusConnection *conn, DBusMessage *msg, if (!reply) return DBUS_HANDLER_RESULT_NEED_MEMORY; - switch(hs->state) { - case HEADSET_STATE_PLAYING: - case HEADSET_STATE_PLAY_IN_PROGRESS: - close_sco(device); - case HEADSET_STATE_CONNECTED: - case HEADSET_STATE_CONNECT_IN_PROGRESS: - headset_close_rfcomm(device); - break; - case HEADSET_STATE_DISCONNECTED: + if (hs->state == HEADSET_STATE_DISCONNECTED) return err_not_connected(conn, msg); - break; - } + headset_set_state(device, HEADSET_STATE_DISCONNECTED); ba2str(&device->dst, hs_address); info("Disconnected from %s, %s", hs_address, device->path); @@ -1500,11 +1455,6 @@ int headset_close_rfcomm(void *device) g_io_channel_close(hs->rfcomm); g_io_channel_unref(hs->rfcomm); hs->rfcomm = NULL; - hs->state = HEADSET_STATE_DISCONNECTED; - dbus_connection_emit_signal(dev->conn, dev->path, - AUDIO_HEADSET_INTERFACE, - "Disconnected", - DBUS_TYPE_INVALID); } hs->data_start = 0; @@ -1517,32 +1467,64 @@ void headset_set_state(void *device, headset_state_t state) { struct device *dev = (struct device *) device; struct headset *hs = dev->headset; + char str[13]; + + if (hs->state == state) + return; switch(state) { case HEADSET_STATE_DISCONNECTED: + close_sco(device); + headset_close_rfcomm(device); + dbus_connection_emit_signal(dev->conn, dev->path, + AUDIO_HEADSET_INTERFACE, + "Disconnected", + DBUS_TYPE_INVALID); + break; case HEADSET_STATE_CONNECT_IN_PROGRESS: break; case HEADSET_STATE_CONNECTED: - if (hs->rfcomm) { - char hs_address[18]; - + if (hs->state < state) { g_io_add_watch(hs->rfcomm, G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL, (GIOFunc) rfcomm_io_cb, device); - ba2str(&((struct device *) device)->dst, hs_address); - dbus_connection_emit_signal(dev->conn, dev->path, AUDIO_HEADSET_INTERFACE, "Connected", DBUS_TYPE_INVALID); } + else { + close_sco(device); + dbus_connection_emit_signal(dev->conn, dev->path, + AUDIO_HEADSET_INTERFACE, + "Stopped", + DBUS_TYPE_INVALID); + } break; case HEADSET_STATE_PLAY_IN_PROGRESS: + break; case HEADSET_STATE_PLAYING: + g_io_add_watch(hs->sco, G_IO_ERR | G_IO_HUP | G_IO_NVAL, + (GIOFunc) sco_cb, device); + + dbus_connection_emit_signal(dev->conn, dev->path, + AUDIO_HEADSET_INTERFACE, + "Playing", DBUS_TYPE_INVALID); + + if (hs->sp_gain >= 0) { + snprintf(str, sizeof(str) - 1, "\r\n+VGS=%u\r\n", hs->sp_gain); + headset_send(hs, str); + } + + if (hs->mic_gain >= 0) { + snprintf(str, sizeof(str) - 1, "\r\n+VGM=%u\r\n", hs->sp_gain); + headset_send(hs, str); + } break; } + debug("State changed %s: %d -> %d", dev->path, hs->state, state); hs->state = state; } diff --git a/audio/pcm_bluetooth.c b/audio/pcm_bluetooth.c index f95dcc9c..71daab4f 100644 --- a/audio/pcm_bluetooth.c +++ b/audio/pcm_bluetooth.c @@ -86,6 +86,26 @@ static snd_pcm_sframes_t bluetooth_pointer(snd_pcm_ioplug_t *io) static void bluetooth_exit(struct bluetooth_data *data) { + int ret, len = sizeof(struct ipc_packet) + sizeof(struct ipc_data_status); + struct ipc_packet *pkt; + struct ipc_data_status *status; + + DBG("Sending PKT_TYPE_STATUS_REQ..."); + + if ((pkt = malloc(len)) == 0) + goto done; + + memset(pkt, 0, len); + pkt->type = PKT_TYPE_STATUS_REQ; + pkt->role = PKT_ROLE_NONE; + pkt->error = PKT_ERROR_NONE; + + status = (struct ipc_data_status *) pkt->data; + status->status = STATUS_DISCONNECTED; + + if ((ret = send(data->sock, pkt, len, 0)) < 0) + DBG("OK"); +done: if (data == NULL) return; diff --git a/audio/unix.c b/audio/unix.c index a4b8f2c4..0f6c53aa 100644 --- a/audio/unix.c +++ b/audio/unix.c @@ -75,13 +75,49 @@ static int unix_sendmsg_fd(int sock, int fd, struct ipc_packet *pkt) return sendmsg(sock, &msgh, MSG_NOSIGNAL); } -static gboolean unix_event(GIOChannel *chan, GIOCondition cond, gpointer data) +static void cfg_event(int clisk, struct ipc_packet *pkt) +{ + struct ipc_data_cfg *cfg = (struct ipc_data_cfg *) pkt->data; + struct device *device; + + memset(cfg, 0, sizeof(struct ipc_data_cfg)); + + if ((device = manager_default_device())) { + if (device->headset) + headset_get_config(device, clisk, pkt); + } + else + cfg->fd = -1; + + if (cfg->fd != 0) + unix_send_cfg(clisk, pkt); +} + +static void ctl_event(int clisk, struct ipc_packet *pkt) +{ +} + +static void status_event(int clisk, struct ipc_packet *pkt) { + struct ipc_data_status *status = (struct ipc_data_status *) pkt->data; struct device *device; + + if (status->status == STATUS_DISCONNECTED) { + if (!(device = manager_default_device())) + return; + + if (device->headset) + headset_set_state(device, HEADSET_STATE_DISCONNECTED); + } + + g_free(pkt); +} + +static gboolean unix_event(GIOChannel *chan, GIOCondition cond, gpointer data) +{ struct sockaddr_un addr; socklen_t addrlen; struct ipc_packet *pkt; - struct ipc_data_cfg *cfg; int sk, clisk, len; debug("chan %p cond %td data %p", chan, cond, data); @@ -114,23 +150,15 @@ static gboolean unix_event(GIOChannel *chan, GIOCondition cond, gpointer data) switch (pkt->type) { case PKT_TYPE_CFG_REQ: info("Package PKT_TYPE_CFG_REQ:%u", pkt->role); - - cfg = (struct ipc_data_cfg *) pkt->data; - - memset(cfg, 0, sizeof(struct ipc_data_cfg)); - if ((device = manager_default_device())) { - if (device->headset) - headset_get_config(device, clisk, pkt); - } - - if (cfg->fd != 0) - unix_send_cfg(clisk, pkt); + cfg_event(clisk, pkt); break; case PKT_TYPE_STATUS_REQ: info("Package PKT_TYPE_STATUS_REQ"); + status_event(clisk, pkt); break; case PKT_TYPE_CTL_REQ: info("Package PKT_TYPE_CTL_REQ"); + ctl_event(clisk, pkt); break; } -- cgit