static void device_sink_cb(struct audio_device *dev, sink_state_t old_state, sink_state_t new_state, void *user_data) { struct dev_priv *priv = dev->priv; if (!dev->sink) return; priv->sink_state = new_state; switch (new_state) { case SINK_STATE_DISCONNECTED: if (dev->control) { device_remove_control_timer(dev); avrcp_disconnect(dev); } device_set_state(dev, AUDIO_STATE_DISCONNECTED); break; case SINK_STATE_CONNECTING: device_remove_avdtp_timer(dev); device_set_state(dev, AUDIO_STATE_CONNECTING); break; case SINK_STATE_CONNECTED: if (old_state == SINK_STATE_PLAYING) break; device_set_state(dev, AUDIO_STATE_CONNECTED); break; case SINK_STATE_PLAYING: break; } }
static DBusMessage *dev_disconnect(DBusConnection *conn, DBusMessage *msg, void *data) { struct audio_device *dev = data; struct dev_priv *priv = dev->priv; if (priv->state == AUDIO_STATE_DISCONNECTED) return g_dbus_create_error(msg, ERROR_INTERFACE ".NotConnected", "Not connected"); if (priv->dc_req) return dbus_message_new_method_return(msg); priv->dc_req = dbus_message_ref(msg); if (dev->control) { device_remove_control_timer(dev); avrcp_disconnect(dev); } if (dev->sink && priv->sink_state != SINK_STATE_DISCONNECTED) sink_shutdown(dev->sink); else if (priv->hs_state != HEADSET_STATE_DISCONNECTED) headset_shutdown(dev); else { dbus_message_unref(priv->dc_req); priv->dc_req = NULL; return dbus_message_new_method_return(msg); } return NULL; }
static void disconnect_cb(struct btd_device *btd_dev, gboolean removal, void *user_data) { struct audio_device *dev = user_data; struct dev_priv *priv = dev->priv; if (priv->state == AUDIO_STATE_DISCONNECTED) return; if (priv->disconnecting) return; priv->disconnecting = TRUE; device_remove_control_timer(dev); device_remove_avdtp_timer(dev); if (dev->control) avrcp_disconnect(dev); if (dev->sink && priv->sink_state != SINK_STATE_DISCONNECTED) sink_disconnect(dev, TRUE); else priv->disconnecting = FALSE; }
gboolean avrcp_connect(struct audio_device *dev) { struct control *control = dev->control; struct avctp *session; int err; if (control->session) return TRUE; session = avctp_get(&dev->src, &dev->dst); if (!session) { error("Unable to create new AVCTP session"); return FALSE; } device_remove_control_timer(dev); session->dev = dev; session->state = AVCTP_STATE_CONNECTING; err = bt_l2cap_connect(&dev->src, &dev->dst, AVCTP_PSM, 0, avctp_connect_cb, session); if (err < 0) { avctp_unref(session); error("Connect failed. %s(%d)", strerror(-err), -err); return FALSE; } control->session = session; return TRUE; }
static void device_sink_cb(struct audio_device *dev, sink_state_t old_state, sink_state_t new_state, void *user_data) { struct dev_priv *priv = dev->priv; if (!dev->sink) return; priv->sink_state = new_state; switch (new_state) { case SINK_STATE_DISCONNECTED: if (dev->control) { device_remove_control_timer(dev); avrcp_disconnect(dev); } if (priv->hs_state == HEADSET_STATE_DISCONNECTED) device_set_state(dev, AUDIO_STATE_DISCONNECTED); else if (old_state == SINK_STATE_CONNECTING) { switch (priv->hs_state) { case HEADSET_STATE_CONNECTED: case HEADSET_STATE_PLAY_IN_PROGRESS: case HEADSET_STATE_PLAYING: device_set_state(dev, AUDIO_STATE_CONNECTED); default: break; } } break; case SINK_STATE_CONNECTING: device_remove_avdtp_timer(dev); if (priv->hs_state == HEADSET_STATE_DISCONNECTED) device_set_state(dev, AUDIO_STATE_CONNECTING); break; case SINK_STATE_CONNECTED: if (old_state == SINK_STATE_PLAYING) break; #ifdef ANDROID /* google code, Broadcom Bluetooth Feature android_set_high_priority(&dev->dst); */ #endif if (dev->auto_connect) { if (!dev->headset) device_set_state(dev, AUDIO_STATE_CONNECTED); if (priv->hs_state == HEADSET_STATE_DISCONNECTED) device_set_headset_timer(dev); else if (priv->hs_state == HEADSET_STATE_CONNECTED) device_set_state(dev, AUDIO_STATE_CONNECTED); } else if (priv->hs_state != HEADSET_STATE_CONNECTED) device_set_state(dev, AUDIO_STATE_CONNECTED); break; case SINK_STATE_PLAYING: break; } }
static void device_sink_cb(struct audio_device *dev, sink_state_t old_state, sink_state_t new_state, void *user_data) { struct dev_priv *priv = dev->priv; if (!dev->sink) return; priv->sink_state = new_state; switch (new_state) { case SINK_STATE_DISCONNECTED: if (dev->control) { device_remove_control_timer(dev); avrcp_disconnect(dev); } if (priv->hs_state == HEADSET_STATE_DISCONNECTED) device_set_state(dev, AUDIO_STATE_DISCONNECTED); else if (old_state == SINK_STATE_CONNECTING) { switch (priv->hs_state) { case HEADSET_STATE_CONNECTED: case HEADSET_STATE_PLAY_IN_PROGRESS: case HEADSET_STATE_PLAYING: device_set_state(dev, AUDIO_STATE_CONNECTED); default: break; } } break; case SINK_STATE_CONNECTING: device_remove_avdtp_timer(dev); if (priv->hs_state == HEADSET_STATE_DISCONNECTED) device_set_state(dev, AUDIO_STATE_CONNECTING); break; case SINK_STATE_CONNECTED: if (old_state == SINK_STATE_PLAYING) break; if (dev->auto_connect) { if (!dev->headset) device_set_state(dev, AUDIO_STATE_CONNECTED); else if (priv->hs_state == HEADSET_STATE_DISCONNECTED) device_set_headset_timer(dev); else if (priv->hs_state == HEADSET_STATE_CONNECTED || priv->hs_state == HEADSET_STATE_PLAY_IN_PROGRESS || priv->hs_state == HEADSET_STATE_PLAYING) device_set_state(dev, AUDIO_STATE_CONNECTED); } else if (priv->hs_state == HEADSET_STATE_DISCONNECTED || priv->hs_state == HEADSET_STATE_CONNECTING) device_set_state(dev, AUDIO_STATE_CONNECTED); break; case SINK_STATE_PLAYING: break; } }
static void device_avctp_cb(struct audio_device *dev, avctp_state_t old_state, avctp_state_t new_state, void *user_data) { if (!dev->control) return; dev->priv->avctp_state = new_state; switch (new_state) { case AVCTP_STATE_DISCONNECTED: break; case AVCTP_STATE_CONNECTING: device_remove_control_timer(dev); break; case AVCTP_STATE_CONNECTED: break; } }
static void device_sink_cb(struct audio_device *dev, sink_state_t old_state, sink_state_t new_state, void *user_data) { struct dev_priv *priv = dev->priv; if (!dev->sink) return; priv->sink_state = new_state; switch (new_state) { case SINK_STATE_DISCONNECTED: if (dev->control) { device_remove_control_timer(dev); avrcp_disconnect(dev); } if (priv->hs_state != HEADSET_STATE_DISCONNECTED && priv->dc_req) { headset_shutdown(dev); break; } if (priv->hs_state == HEADSET_STATE_DISCONNECTED) device_set_state(dev, AUDIO_STATE_DISCONNECTED); else if (old_state == SINK_STATE_CONNECTING) { switch (priv->hs_state) { case HEADSET_STATE_CONNECTED: case HEADSET_STATE_PLAY_IN_PROGRESS: case HEADSET_STATE_PLAYING: device_set_state(dev, AUDIO_STATE_CONNECTED); default: break; } } break; case SINK_STATE_CONNECTING: device_remove_avdtp_timer(dev); if (priv->hs_state == HEADSET_STATE_DISCONNECTED) device_set_state(dev, AUDIO_STATE_CONNECTING); break; case SINK_STATE_CONNECTED: if (old_state == SINK_STATE_PLAYING) break; #ifdef ANDROID android_set_high_priority(&dev->dst); #endif if (dev->auto_connect) { if (!dev->headset) device_set_state(dev, AUDIO_STATE_CONNECTED); else if (priv->hs_state == HEADSET_STATE_DISCONNECTED) device_set_headset_timer(dev); else if (priv->hs_state == HEADSET_STATE_CONNECTED || priv->hs_state == HEADSET_STATE_PLAY_IN_PROGRESS || priv->hs_state == HEADSET_STATE_PLAYING) device_set_state(dev, AUDIO_STATE_CONNECTED); } else if (priv->hs_state == HEADSET_STATE_DISCONNECTED || priv->hs_state == HEADSET_STATE_CONNECTING) device_set_state(dev, AUDIO_STATE_CONNECTED); break; case SINK_STATE_PLAYING: //Terry Cheng, 20101222, force to send high priority when playing + #ifdef ANDROID //Re-send high priority when playing A2DP. It may not work when only connecting A2DP profile android_set_high_priority(&dev->dst); #endif //Terry Cheng, 20101222, force to send high priority when playing - break; } }
static void avctp_server_cb(GIOChannel *chan, int err, const bdaddr_t *src, const bdaddr_t *dst, gpointer data) { socklen_t size; struct l2cap_options l2o; struct avctp *session; GIOCondition flags = G_IO_ERR | G_IO_HUP | G_IO_NVAL; struct audio_device *dev; char address[18]; if (err < 0) { error("AVCTP server socket: %s (%d)", strerror(-err), -err); return; } session = avctp_get(src, dst); if (!session) { error("Unable to create new AVCTP session"); goto drop; } if (session->sock >= 0) { error("Refusing unexpected connect from %s", address); goto drop; } dev = manager_find_device(&session->dst, AUDIO_CONTROL_INTERFACE, FALSE); if (!dev) { error("Unable to get audio device object for %s", address); goto drop; } if (!dev->control) dev->control = control_init(dev); device_remove_control_timer(dev); session->state = AVCTP_STATE_CONNECTING; session->sock = g_io_channel_unix_get_fd(chan); memset(&l2o, 0, sizeof(l2o)); size = sizeof(l2o); if (getsockopt(session->sock, SOL_L2CAP, L2CAP_OPTIONS, &l2o, &size) < 0) { err = errno; error("getsockopt(L2CAP_OPTIONS): %s (%d)", strerror(err), err); avctp_unref(session); goto drop; } session->mtu = l2o.imtu; if (session->io) g_source_remove(session->io); session->io = g_io_add_watch(chan, flags, (GIOFunc) session_cb, session); g_io_channel_unref(chan); if (avdtp_is_connected(src, dst)) goto proceed; if (service_req_auth(src, dst, AVRCP_TARGET_UUID, auth_cb, session) < 0) goto drop; return; proceed: avctp_connect_session(session); return; drop: close(session->sock); }