?? manager.c
字號:
memset(&record, 0, sizeof(sdp_record_t)); sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP); root = sdp_list_append(0, &root_uuid); sdp_set_browse_groups(&record, root); sdp_uuid16_create(&svclass_uuid, HANDSFREE_AGW_SVCLASS_ID); svclass_id = sdp_list_append(0, &svclass_uuid); sdp_uuid16_create(&ga_svclass_uuid, GENERIC_AUDIO_SVCLASS_ID); svclass_id = sdp_list_append(svclass_id, &ga_svclass_uuid); sdp_set_service_classes(&record, svclass_id); sdp_uuid16_create(&profile.uuid, HANDSFREE_PROFILE_ID); profile.version = 0x0105; pfseq = sdp_list_append(0, &profile); sdp_set_profile_descs(&record, pfseq); sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID); proto[0] = sdp_list_append(0, &l2cap_uuid); apseq = sdp_list_append(0, proto[0]); sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID); proto[1] = sdp_list_append(0, &rfcomm_uuid); channel = sdp_data_alloc(SDP_UINT8, &ch); proto[1] = sdp_list_append(proto[1], channel); apseq = sdp_list_append(apseq, proto[1]); sdpfeat = (uint16_t) feat & 0xF; features = sdp_data_alloc(SDP_UINT16, &sdpfeat); sdp_attr_add(&record, SDP_ATTR_SUPPORTED_FEATURES, features); aproto = sdp_list_append(0, apseq); sdp_set_access_protos(&record, aproto); sdp_set_info_attr(&record, "Hands-Free Audio Gateway", 0, 0); sdp_attr_add(&record, SDP_ATTR_EXTERNAL_NETWORK, network); if (sdp_gen_record_pdu(&record, buf) < 0) ret = -1; else ret = 0; sdp_data_free(channel); sdp_list_free(proto[0], 0); sdp_list_free(proto[1], 0); sdp_list_free(apseq, 0); sdp_list_free(pfseq, 0); sdp_list_free(aproto, 0); sdp_list_free(root, 0); sdp_list_free(svclass_id, 0); sdp_list_free(record.attrlist, (sdp_free_func_t) sdp_data_free); sdp_list_free(record.pattern, free); return ret;}uint32_t add_service_record(DBusConnection *conn, sdp_buf_t *buf){ DBusMessage *msg, *reply; DBusError derr; dbus_uint32_t rec_id; msg = dbus_message_new_method_call("org.bluez", "/org/bluez", "org.bluez.Database", "AddServiceRecord"); if (!msg) { error("Can't allocate new method call"); return 0; } dbus_message_append_args(msg, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &buf->data, buf->data_size, DBUS_TYPE_INVALID); dbus_error_init(&derr); reply = dbus_connection_send_with_reply_and_block(connection, msg, -1, &derr); dbus_message_unref(msg); if (dbus_error_is_set(&derr) || dbus_set_error_from_message(&derr, reply)) { error("Adding service record failed: %s", derr.message); dbus_error_free(&derr); return 0; } dbus_message_get_args(reply, &derr, DBUS_TYPE_UINT32, &rec_id, DBUS_TYPE_INVALID); if (dbus_error_is_set(&derr)) { error("Invalid arguments to AddServiceRecord reply: %s", derr.message); dbus_message_unref(reply); dbus_error_free(&derr); return 0; } dbus_message_unref(reply); debug("add_service_record: got record id 0x%x", rec_id); return rec_id;}int remove_service_record(DBusConnection *conn, uint32_t rec_id){ DBusMessage *msg, *reply; DBusError derr; msg = dbus_message_new_method_call("org.bluez", "/org/bluez", "org.bluez.Database", "RemoveServiceRecord"); if (!msg) { error("Can't allocate new method call"); return 0; } dbus_message_append_args(msg, DBUS_TYPE_UINT32, &rec_id, DBUS_TYPE_INVALID); dbus_error_init(&derr); reply = dbus_connection_send_with_reply_and_block(connection, msg, -1, &derr); dbus_message_unref(msg); if (dbus_error_is_set(&derr)) { error("Removing service record 0x%x failed: %s", rec_id, derr.message); dbus_error_free(&derr); return 0; } dbus_message_unref(reply); return 0;}static void auth_cb(DBusPendingCall *call, void *data){ struct device *device = data; DBusMessage *reply = dbus_pending_call_steal_reply(call); DBusError err; const char *uuid; if (get_hfp_active(device)) uuid = HFP_AG_UUID; else uuid = HSP_AG_UUID; dbus_error_init(&err); if (dbus_set_error_from_message(&err, reply)) { error("Access denied: %s", err.message); if (dbus_error_has_name(&err, DBUS_ERROR_NO_REPLY)) { debug("Canceling authorization request"); manager_cancel_authorize(&device->dst, uuid, NULL); } dbus_error_free(&err); headset_set_state(device, HEADSET_STATE_DISCONNECTED); } else { char hs_address[18]; headset_set_authorized(device); ba2str(&device->dst, hs_address); debug("Accepted headset connection from %s for %s", hs_address, device->path); } dbus_message_unref(reply);}static gboolean ag_io_cb(GIOChannel *chan, GIOCondition cond, void *data){ int srv_sk, cli_sk; struct sockaddr_rc addr; socklen_t size; const char *uuid; struct device *device; gboolean hfp_active; if (cond & G_IO_NVAL) return FALSE; if (cond & (G_IO_HUP | G_IO_ERR)) { error("Hangup or error on rfcomm server socket"); g_io_channel_close(chan); raise(SIGTERM); return FALSE; } srv_sk = g_io_channel_unix_get_fd(chan); size = sizeof(struct sockaddr_rc); cli_sk = accept(srv_sk, (struct sockaddr *) &addr, &size); if (cli_sk < 0) { error("accept: %s (%d)", strerror(errno), errno); return TRUE; } if (chan == hs_server) { hfp_active = FALSE; uuid = HSP_AG_UUID; } else { hfp_active = TRUE; uuid = HFP_AG_UUID; } device = manager_device_connected(&addr.rc_bdaddr, uuid); if (!device) { close(cli_sk); return TRUE; } if (headset_get_state(device) > HEADSET_STATE_DISCONNECTED) { debug("Refusing new connection since one already exists"); close(cli_sk); return TRUE; } set_hfp_active(device, hfp_active); if (headset_connect_rfcomm(device, cli_sk) < 0) { error("Allocating new GIOChannel failed!"); close(cli_sk); return TRUE; } if (!manager_authorize(&device->dst, uuid, auth_cb, device, NULL)) goto failed; headset_set_state(device, HEADSET_STATE_CONNECT_IN_PROGRESS); return TRUE;failed: headset_close_rfcomm(device); return TRUE;}static GIOChannel *server_socket(uint8_t *channel){ int sock, lm; struct sockaddr_rc addr; socklen_t sa_len; GIOChannel *io; sock = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM); if (sock < 0) { error("server socket: %s (%d)", strerror(errno), errno); return NULL; } lm = RFCOMM_LM_SECURE; if (setsockopt(sock, SOL_RFCOMM, RFCOMM_LM, &lm, sizeof(lm)) < 0) { error("server setsockopt: %s (%d)", strerror(errno), errno); close(sock); return NULL; } memset(&addr, 0, sizeof(addr)); addr.rc_family = AF_BLUETOOTH; bacpy(&addr.rc_bdaddr, BDADDR_ANY); addr.rc_channel = channel ? *channel : 0; if (bind(sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) { error("server bind: %s", strerror(errno), errno); close(sock); return NULL; } if (listen(sock, 1) < 0) { error("server listen: %s", strerror(errno), errno); close(sock); return NULL; } sa_len = sizeof(struct sockaddr_rc); getsockname(sock, (struct sockaddr *) &addr, &sa_len); *channel = addr.rc_channel; io = g_io_channel_unix_new(sock); if (!io) { error("Unable to allocate new io channel"); close(sock); return NULL; } return io;}static int headset_server_init(DBusConnection *conn, GKeyFile *config){ uint8_t chan = DEFAULT_HS_AG_CHANNEL; sdp_buf_t buf; gboolean no_hfp = FALSE; GError *err = NULL; uint32_t features; if (!(enabled.headset || enabled.gateway)) return 0; hs_server = server_socket(&chan); if (!hs_server) return -1; if (hsp_ag_record(&buf, chan) < 0) { error("Unable to allocate new service record"); return -1; } hs_record_id = add_service_record(conn, &buf); free(buf.data); if (!hs_record_id) { error("Unable to register HS AG service record"); g_io_channel_unref(hs_server); hs_server = NULL; return -1; } g_io_add_watch(hs_server, G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL, (GIOFunc) ag_io_cb, NULL); if (config) { no_hfp = g_key_file_get_boolean(config, "Headset", "DisableHFP", &err); if (err) { debug("audio.conf: %s", err->message); g_error_free(err); err = NULL; } } if (no_hfp) return 0; chan = DEFAULT_HF_AG_CHANNEL; hf_server = server_socket(&chan); if (!hf_server) return -1; features = headset_config_init(config); if (hfp_ag_record(&buf, chan, features) < 0) { error("Unable to allocate new service record"); return -1; } hf_record_id = add_service_record(conn, &buf); free(buf.data); if (!hf_record_id) { error("Unable to register HS AG service record"); g_io_channel_unref(hf_server); hs_server = NULL; return -1; } g_io_add_watch(hf_server, G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL, (GIOFunc) ag_io_cb, NULL); return 0;}static void server_exit(void){ if (hs_record_id) { remove_service_record(connection, hs_record_id); hs_record_id = 0; } if (hs_server) { g_io_channel_unref(hs_server); hs_server = NULL; } if (hf_record_id) { remove_service_record(connection, hf_record_id); hf_record_id = 0; } if (hf_server) { g_io_channel_unref(hf_server); hf_server = NULL; }}int audio_init(DBusConnection *conn, GKeyFile *config){ char *str; GError *err = NULL; connection = dbus_connection_ref(conn); if (config) { str = g_key_file_get_string(config, "General", "Enable", &err); if (err) { debug("audio.conf: %s", err->message); g_error_free(err); err = NULL; } else { if (strstr(str, "Headset")) enabled.headset = TRUE; if (strstr(str, "Gateway")) enabled.gateway = TRUE; if (strstr(str, "Sink")) enabled.sink = TRUE; if (strstr(str, "Source")) enabled.source = TRUE; if (strstr(str, "Control")) enabled.control = TRUE; g_free(str); } str = g_key_file_get_string(config, "General", "Disable", &err); if (err) { debug("audio.conf: %s", err->message); g_error_free(err); err = NULL; } else { if (strstr(str, "Headset")) enabled.headset = FALSE; if (strstr(str, "Gateway")) enabled.gateway = FALSE; if (strstr(str, "Sink")) enabled.sink = FALSE; if (strstr(str, "Source")) enabled.source = FALSE; if (strstr(str, "Control")) enabled.control = FALSE; g_free(str); } } if (!dbus_connection_create_object_path(conn, AUDIO_MANAGER_PATH, NULL, manager_unregister)) { error("D-Bus failed to register %s path", AUDIO_MANAGER_PATH); goto failed; } if (enabled.headset) { if (headset_server_init(conn, config) < 0) goto failed; } if (enabled.source || enabled.sink) { if (a2dp_init(conn, config) < 0) goto failed; } if (enabled.control && avrcp_init(conn) < 0) goto failed; if (!dbus_connection_register_interface(conn, AUDIO_MANAGER_PATH, AUDIO_MANAGER_INTERFACE, manager_methods, manager_signals, NULL)) { error("Failed to register %s interface to %s", AUDIO_MANAGER_INTERFACE, AUDIO_MANAGER_PATH); goto failed; } info("Registered manager path:%s", AUDIO_MANAGER_PATH); register_stored(); return 0;failed: audio_exit(); return -1;}void audio_exit(void){ server_exit(); dbus_connection_destroy_object_path(connection, AUDIO_MANAGER_PATH); dbus_connection_unref(connection); connection = NULL;}struct device *manager_default_device(void){ return default_dev;}struct device *manager_get_connected_device(void){ GSList *l; for (l = devices; l != NULL; l = g_slist_next(l)) { struct device *device = l->data; if ((device->sink || device->source) && avdtp_is_connected(&device->src, &device->dst)) return device; if (device->headset && headset_is_active(device)) return device; } return NULL;}void manager_cancel_authorize(bdaddr_t *dba, const char *uuid, DBusPendingCall *pending){ DBusMessage *cancel; char addr[18], *address = addr; if (pending) dbus_pending_call_cancel(pending); cancel = dbus_message_new_method_call("org.bluez", "/org/bluez", "org.bluez.Database", "CancelAuthorizationRequest"); if (!cancel) { error("Unable to allocate new method call"); return; } ba2str(dba, addr); dbus_message_append_args(cancel, DBUS_TYPE_STRING, &address, DBUS_TYPE_STRING, &uuid, DBUS_TYPE_INVALID); send_message_and_unref(connection, cancel);}gboolean manager_authorize(bdaddr_t *dba, const char *uuid, DBusPendingCallNotifyFunction cb, void *user_data, DBusPendingCall **pending){ DBusMessage *auth; char address[18], *addr_ptr = address; DBusPendingCall *p; ba2str(dba, address); debug("Requesting authorization for device %s, UUID %s", address, uuid); auth = dbus_message_new_method_call("org.bluez", "/org/bluez", "org.bluez.Database", "RequestAuthorization"); if (!auth) { error("Unable to allocate RequestAuthorization method call"); return FALSE; } dbus_message_append_args(auth, DBUS_TYPE_STRING, &addr_ptr, DBUS_TYPE_STRING, &uuid, DBUS_TYPE_INVALID); if (!dbus_connection_send_with_reply(connection, auth, &p, -1)) { error("Sending of authorization request failed"); dbus_message_unref(auth); return FALSE; } dbus_pending_call_set_notify(p, cb, user_data, NULL); if (pending) *pending = p; else dbus_pending_call_unref(p); dbus_message_unref(auth); return TRUE;}struct device *manager_find_device(bdaddr_t *bda, const char *interface, gboolean connected){ GSList *l; if (!bacmp(bda, BDADDR_ANY) && !interface && !connected) return default_dev; for (l = devices; l != NULL; l = l->next) { struct device *dev = l->data; if (bacmp(bda, BDADDR_ANY) && bacmp(&dev->dst, bda)) continue; if (interface && !strcmp(AUDIO_HEADSET_INTERFACE, interface) && !dev->headset) continue; if (interface && !strcmp(AUDIO_SINK_INTERFACE, interface) && !dev->sink) continue; if (interface && !strcmp(AUDIO_SOURCE_INTERFACE, interface) && !dev->source) continue; if (interface && !strcmp(AUDIO_CONTROL_INTERFACE, interface) && !dev->control) continue; if (connected && !device_is_connected(dev, interface)) continue; return dev; } return NULL;}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -