📄 sink.c
字号:
return TRUE;}static gboolean select_capabilities(struct avdtp *session, struct avdtp_remote_sep *rsep, GSList **caps){ struct avdtp_service_capability *media_transport, *media_codec; struct sbc_codec_cap sbc_cap; media_codec = avdtp_get_codec(rsep); if (!media_codec) return FALSE; select_sbc_params(&sbc_cap, (struct sbc_codec_cap *) media_codec->data); media_transport = avdtp_service_cap_new(AVDTP_MEDIA_TRANSPORT, NULL, 0); *caps = g_slist_append(*caps, media_transport); media_codec = avdtp_service_cap_new(AVDTP_MEDIA_CODEC, &sbc_cap, sizeof(sbc_cap)); *caps = g_slist_append(*caps, media_codec); return TRUE;}static void discovery_complete(struct avdtp *session, GSList *seps, struct avdtp_error *err, void *user_data){ struct sink *sink = user_data; struct pending_request *pending; struct avdtp_local_sep *lsep; struct avdtp_remote_sep *rsep; GSList *caps = NULL; int id; pending = sink->connect; if (err) { avdtp_unref(sink->session); sink->session = NULL; if (avdtp_error_type(err) == AVDTP_ERROR_ERRNO && avdtp_error_posix_errno(err) != EHOSTDOWN) { debug("connect:connect XCASE detected"); g_timeout_add_seconds(STREAM_SETUP_RETRY_TIMER, stream_setup_retry, sink); } else goto failed; return; } debug("Discovery complete"); if (avdtp_get_seps(session, AVDTP_SEP_TYPE_SINK, AVDTP_MEDIA_TYPE_AUDIO, A2DP_CODEC_SBC, &lsep, &rsep) < 0) { error("No matching ACP and INT SEPs found"); goto failed; } if (!select_capabilities(session, rsep, &caps)) { error("Unable to select remote SEP capabilities"); goto failed; } id = a2dp_source_config(sink->session, stream_setup_complete, caps, sink); if (id == 0) goto failed; pending->id = id; return;failed: error_failed(pending->conn, pending->msg, "Stream setup failed"); pending_request_free(pending); sink->connect = NULL; avdtp_unref(sink->session); sink->session = NULL;}static DBusMessage *sink_connect(DBusConnection *conn, DBusMessage *msg, void *data){ struct audio_device *dev = data; struct sink *sink = dev->sink; struct pending_request *pending; if (!sink->session) sink->session = avdtp_get(&dev->src, &dev->dst); if (!sink->session) return g_dbus_create_error(msg, ERROR_INTERFACE ".Failed", "Unable to get a session"); if (sink->connect || sink->disconnect) return g_dbus_create_error(msg, ERROR_INTERFACE ".Failed", "%s", strerror(EBUSY)); if (sink->state >= AVDTP_STATE_OPEN) return g_dbus_create_error(msg, ERROR_INTERFACE ".AlreadyConnected", "Device Already Connected"); pending = g_new0(struct pending_request, 1); pending->conn = dbus_connection_ref(conn); pending->msg = dbus_message_ref(msg); sink->connect = pending; avdtp_discover(sink->session, discovery_complete, sink); debug("stream creation in progress"); return NULL;}static DBusMessage *sink_disconnect(DBusConnection *conn, DBusMessage *msg, void *data){ struct audio_device *device = data; struct sink *sink = device->sink; struct pending_request *pending; int err; if (!sink->session) return g_dbus_create_error(msg, ERROR_INTERFACE ".NotConnected", "Device not Connected"); if (sink->connect || sink->disconnect) return g_dbus_create_error(msg, ERROR_INTERFACE ".Failed", "%s", strerror(EBUSY)); if (sink->state < AVDTP_STATE_OPEN) { DBusMessage *reply = dbus_message_new_method_return(msg); if (!reply) return NULL; avdtp_unref(sink->session); sink->session = NULL; return reply; } err = avdtp_close(sink->session, sink->stream); if (err < 0) return g_dbus_create_error(msg, ERROR_INTERFACE ".Failed", "%s", strerror(-err)); pending = g_new0(struct pending_request, 1); pending->conn = dbus_connection_ref(conn); pending->msg = dbus_message_ref(msg); sink->disconnect = pending; return NULL;}static DBusMessage *sink_is_connected(DBusConnection *conn, DBusMessage *msg, void *data){ struct audio_device *device = data; struct sink *sink = device->sink; DBusMessage *reply; dbus_bool_t connected; reply = dbus_message_new_method_return(msg); if (!reply) return NULL; connected = (sink->state >= AVDTP_STATE_CONFIGURED); dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN, &connected, DBUS_TYPE_INVALID); return reply;}static DBusMessage *sink_get_properties(DBusConnection *conn, DBusMessage *msg, void *data){ struct audio_device *device = data; DBusMessage *reply; DBusMessageIter iter; DBusMessageIter dict; gboolean value; reply = dbus_message_new_method_return(msg); if (!reply) return NULL; dbus_message_iter_init_append(reply, &iter); dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict); /* Playing */ value = (device->sink->state == AVDTP_STATE_STREAMING); dict_append_entry(&dict, "Playing", DBUS_TYPE_BOOLEAN, &value); /* Connected */ value = (device->sink->state >= AVDTP_STATE_CONFIGURED); dict_append_entry(&dict, "Connected", DBUS_TYPE_BOOLEAN, &value); dbus_message_iter_close_container(&iter, &dict); return reply;}static GDBusMethodTable sink_methods[] = { { "Connect", "", "", sink_connect, G_DBUS_METHOD_FLAG_ASYNC }, { "Disconnect", "", "", sink_disconnect, G_DBUS_METHOD_FLAG_ASYNC }, { "IsConnected", "", "b", sink_is_connected, G_DBUS_METHOD_FLAG_DEPRECATED }, { "GetProperties", "", "a{sv}",sink_get_properties }, { NULL, NULL, NULL, NULL }};static GDBusSignalTable sink_signals[] = { { "Connected", "", G_DBUS_SIGNAL_FLAG_DEPRECATED }, { "Disconnected", "", G_DBUS_SIGNAL_FLAG_DEPRECATED }, { "Playing", "", G_DBUS_SIGNAL_FLAG_DEPRECATED }, { "Stopped", "", G_DBUS_SIGNAL_FLAG_DEPRECATED }, { "PropertyChanged", "sv" }, { NULL, NULL }};static void sink_free(struct audio_device *dev){ struct sink *sink = dev->sink; if (sink->cb_id) avdtp_stream_remove_cb(sink->session, sink->stream, sink->cb_id); if (sink->session) avdtp_unref(sink->session); if (sink->connect) pending_request_free(sink->connect); if (sink->disconnect) pending_request_free(sink->disconnect); g_free(sink); dev->sink = NULL;}static void path_unregister(void *data){ struct audio_device *dev = data; info("Unregistered interface %s on path %s", AUDIO_SINK_INTERFACE, dev->path); sink_free(dev);}void sink_unregister(struct audio_device *dev){ g_dbus_unregister_interface(dev->conn, dev->path, AUDIO_SINK_INTERFACE);}struct sink *sink_init(struct audio_device *dev){ if (!g_dbus_register_interface(dev->conn, dev->path, AUDIO_SINK_INTERFACE, sink_methods, sink_signals, NULL, dev, path_unregister)) return NULL; info("Registered interface %s on path %s", AUDIO_SINK_INTERFACE, dev->path); return g_new0(struct sink, 1);}gboolean sink_is_active(struct audio_device *dev){ struct sink *sink = dev->sink; if (sink->session) return TRUE; return FALSE;}avdtp_state_t sink_get_state(struct audio_device *dev){ struct sink *sink = dev->sink; return sink->state;}gboolean sink_new_stream(struct audio_device *dev, struct avdtp *session, struct avdtp_stream *stream){ struct sink *sink = dev->sink; if (sink->stream) return FALSE; if (!sink->session) sink->session = avdtp_ref(session); sink->stream = stream; sink->cb_id = avdtp_stream_add_cb(session, stream, stream_state_changed, dev); return TRUE;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -