blueZ 笔记一

//adapter初始化
adapter_register
    btd_profile_foreach(probe_profile, adapter);
        probe_profile    
            //依次调用profile的adapter_probe
            profile->adapter_probe(profile, adapter);
                a2dp_source_server_probe
                a2dp_sink_server_probe
                    //注册a2dp_server,sink/source共用一个
                    struct a2dp_server *server;
                    struct a2dp_server {
                    	struct btd_adapter *adapter;
                    	GSList *sinks;
                    	GSList *sources;
                    	uint32_t source_record_id;
                    	uint32_t sink_record_id;
                    	gboolean sink_enabled;
                    	gboolean source_enabled;
                    	GIOChannel *io;
                    	struct queue *seps;
                    	struct queue *channels;
                    };

                    a2dp_server_register(adapter);
                	    struct a2dp_server *server;
	                    server = g_new0(struct a2dp_server, 1);
	                    server->adapter = btd_adapter_ref(adapter);
	                    server->seps = queue_new();
	                    server->channels = queue_new();
	                    servers = g_slist_append(servers, server);


//adapter的驱动
static struct btd_adapter_driver media_driver = {
	.name		= "media",
	.probe		= media_server_probe,
	.remove		= media_server_remove,
};
media_server_probe
    media_register
        struct media_adapter *adapter;
       	adapter->btd_adapter = btd_adapter_ref(btd_adapter);
        //对外注册一个Media的操作接口
        g_dbus_register_interface(btd_get_dbus_connection(),
					adapter_get_path(btd_adapter),
					MEDIA_INTERFACE,//"org.bluez.Media1"
					media_methods, NULL, NULL,
					adapter, path_free)
static const GDBusMethodTable media_methods[] = {
	{ GDBUS_METHOD("RegisterEndpoint",
		GDBUS_ARGS({ "endpoint", "o" }, { "properties", "a{sv}" }),
		NULL, register_endpoint) },
	{ GDBUS_METHOD("UnregisterEndpoint",
		GDBUS_ARGS({ "endpoint", "o" }), NULL, unregister_endpoint) },
	{ GDBUS_METHOD("RegisterPlayer",
		GDBUS_ARGS({ "player", "o" }, { "properties", "a{sv}" }),
		NULL, register_player) },
	{ GDBUS_METHOD("UnregisterPlayer",
		GDBUS_ARGS({ "player", "o" }), NULL, unregister_player) },
	{ },
};



//SDP服务发现完成后,获取到对端设备所支持的profile,然后依次...
device_probe_profiles
    btd_profile_foreach(dev_probe, &d);
        dev_probe
            probe_service
                struct btd_service *service;
                service = service_create(device, profile);//根据profile(a2dp sink/source/arvcp ct/tg)创建对应service
                    service->profile = profile;
                service_probe

static struct btd_profile avrcp_target_profile
static struct btd_profile avrcp_target_profile


service_probe //根据profile依次调用对应的probe函数
    service->profile->device_probe(service);

//"avrcp-controller"
//"audio-avrcp-target"
avrcp_controller_probe() path /org/bluez/hci0/dev_E0_62_67_38_2A_B7
avrcp_target_probe
    control = control_init(service);
        //注册一个设备控制接口
        //Registered interface org.bluez.MediaControl1 on path /org/bluez/hci0/dev_E0_62_67_38_2A_B7
        g_dbus_register_interface(btd_get_dbus_connection(),
					device_get_path(dev),    ///org/bluez/hci0/dev_E0_62_67_38_2A_B7
					AUDIO_CONTROL_INTERFACE, //"org.bluez.MediaControl1"
					control_methods, NULL,
					control_properties, control,
					path_unregister)
	    control->dev = dev; //一个设备对应唯一一个control,跟sink/source无关
	    control->avctp_id = avctp_add_state_cb(dev, state_changed, control);
        devices = g_slist_prepend(devices, control);
    control->remote = btd_service_ref(service); //"avrcp-controller"
    control->target = btd_service_ref(service); //"audio-avrcp-target"


static struct btd_profile a2dp_sink_profile
static struct btd_profile a2dp_source_profile

//对于本机sink设备,远端设备是支持source profe
static struct btd_profile a2dp_source_profile = {
	.name		= "a2dp-source",
	.priority	= BTD_PROFILE_PRIORITY_MEDIUM,
	.remote_uuid	= A2DP_SOURCE_UUID,

a2dp_source_probe
    struct source *source;
   	source->service = btd_service_ref(service); //service为source profile
    btd_service_set_user_data(service, source);
        service->user_data = user_data; //service->user_data = source;


//blue-alsa
static const a2dp_sbc_t a2dp_sbc = {
	.frequency =
		SBC_SAMPLING_FREQ_16000 |
		SBC_SAMPLING_FREQ_32000 |
		SBC_SAMPLING_FREQ_44100 |
		SBC_SAMPLING_FREQ_48000,
	.channel_mode =
		SBC_CHANNEL_MODE_MONO |
		SBC_CHANNEL_MODE_DUAL_CHANNEL |
		SBC_CHANNEL_MODE_STEREO |
		SBC_CHANNEL_MODE_JOINT_STEREO,
	.block_length =
		SBC_BLOCK_LENGTH_4 |
		SBC_BLOCK_LENGTH_8 |
		SBC_BLOCK_LENGTH_12 |
		SBC_BLOCK_LENGTH_16,
	.subbands =
		SBC_SUBBANDS_4 |
		SBC_SUBBANDS_8,
	.allocation_method =
		SBC_ALLOCATION_SNR |
		SBC_ALLOCATION_LOUDNESS,
	.min_bitpool = SBC_MIN_BITPOOL,
	.max_bitpool = SBC_MAX_BITPOOL,
};
static const struct bluez_a2dp_codec a2dp_codec_sink_sbc = {
	.dir = BLUEZ_A2DP_SINK,
	.id = A2DP_CODEC_SBC,
	.cfg = &a2dp_sbc,
	.cfg_size = sizeof(a2dp_sbc),
	.channels = a2dp_sbc_channels,
	.channels_size = ARRAYSIZE(a2dp_sbc_channels),
	.samplings = a2dp_sbc_samplings,
	.samplings_size = ARRAYSIZE(a2dp_sbc_samplings),
};
bluez_register_a2dp_endpoint(BLUETOOTH_UUID_A2DP_SINK, BLUETOOTH_PROFILE_A2DP_SINK, c);
    //调用media接口RegisterEndpoint注册endpoint
    msg = g_dbus_message_new_method_call("org.bluez", dev,
			"org.bluez.Media1", "RegisterEndpoint");
    	for (i = 0; i < codec->cfg_size; i++)
		g_variant_builder_add(&caps, "y", ((uint8_t *)codec->cfg)[i]);
    //添加参数
	g_variant_builder_add(&properties, "{sv}", "UUID", g_variant_new_string(uuid));
	g_variant_builder_add(&properties, "{sv}", "DelayReporting", g_variant_new_boolean(TRUE));
	g_variant_builder_add(&properties, "{sv}", "Codec", g_variant_new_byte(codec->id));
	g_variant_builder_add(&properties, "{sv}", "Capabilities", g_variant_builder_end(&caps));



//register_endpoint
register_endpoint
    //解析上面传下来的属性
    parse_properties(&props, &uuid, &delay_reporting, &codec,
						&capabilities, &size)

    media_endpoint_create(adapter, sender, path, uuid, delay_reporting,
				codec, capabilities, size, &err)
        //新建一个media_endpoint
        struct media_endpoint *endpoint;
        endpoint = g_new0(struct media_endpoint, 1);
        endpoint->sender = g_strdup(sender);
        endpoint->path = g_strdup(path);
        endpoint->uuid = g_strdup(uuid);
        endpoint->codec = codec;
        endpoint_init_a2dp_sink(endpoint,
							delay_reporting, err)
            endpoint->sep = a2dp_add_sep(endpoint->adapter->btd_adapter,
					AVDTP_SEP_TYPE_SINK, endpoint->codec,
					delay_reporting, &a2dp_endpoint,
					endpoint, a2dp_destroy_endpoint, err);
                    //创建a2dp_sep
                	sep = g_new0(struct a2dp_sep, 1);

                    //创建本地sep: avdtp_local_sep
            	    sep->lsep = avdtp_register_sep(server->seps, type,
			    		    AVDTP_MEDIA_TYPE_AUDIO, codec,
				    	    delay_reporting, &endpoint_ind,
					        &cfm, sep);
                            //新建avdtp_local_sep
                        	sep = g_new0(struct avdtp_local_sep, 1);
	                        sep->state = AVDTP_STATE_IDLE;
	                        sep->info.seid = seid;
	                        sep->info.type = type;
	                        sep->info.media_type = media_type;
	                        sep->codec = codec_type;
                            //static struct avdtp_sep_cfm cfm;
                            //static struct avdtp_sep_ind endpoint_ind;
	                        sep->ind = ind;
	                        sep->cfm = cfm;
	                        sep->user_data = user_data;
	                        sep->delay_reporting = delay_reporting;
                            //server->seps: 把lsep挂在a2dp_server的seps队列上
                            queue_push_tail(lseps, sep);
                            return sep;
                    sep->server = server;//a2dp_server
                    static struct a2dp_endpoint a2dp_endpoint = {
                    	.get_name = get_name,
                    	.get_capabilities = get_capabilities,
                    	.select_configuration = select_config,
                    	.set_configuration = set_config,
	                    .clear_configuration = clear_config,
                        .set_delay = set_delay
                    };
                	sep->endpoint = endpoint;//a2dp_endpoint 
                	sep->codec = codec;
                	sep->type = type;
                	sep->delay_reporting = delay_reporting;
                	sep->user_data = user_data;
                	sep->destroy = destroy;
                
                    l = &server->sinks;            
                    record_id = &server->sink_record_id;

                    //创建支持sink的sdp record记录
                    record = a2dp_record(type);

                    adapter_service_add(server->adapter, record);               

                    a2dp_server_listen
                        //监听AVDTP_PSM:AVDTP的事件
                        server->io = bt_io_listen(NULL, confirm_cb, server, NULL, &err,
				            BT_IO_OPT_SOURCE_BDADDR,
				            btd_adapter_get_address(server->adapter),
				            BT_IO_OPT_PSM, AVDTP_PSM,
				            BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_MEDIUM,
				            BT_IO_OPT_MASTER, true,
				            BT_IO_OPT_INVALID);

                    *record_id = record->handle; //server->sink_record_id: 记录sdp sink的handle
                    *l = g_slist_append(*l, sep); //server->sinks: 连接a2dp_sep
    //把media_endpoint记录到adapter
    adapter->endpoints = g_slist_append(adapter->endpoints, endpoint);


//服务发现流程,以sink为例
main
    //主要服务于远端SDP请求
    start_sdp_server(sdp_mtu, sdp_flags);
       	/* Create L2CAP socket */
    	l2cap_sock = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);
	    l2addr.l2_family = AF_BLUETOOTH;
	    bacpy(&l2addr.l2_bdaddr, BDADDR_ANY);
	    l2addr.l2_psm = htobs(SDP_PSM);
        listen(l2cap_sock, 5)
        l2cap_id = g_io_add_watch(io, G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
					io_accept_event, &l2cap_sock);//创建io监听事件:监听外部连接
    io_accept_event
        //accept一个外部连接
        nsk = accept(l2cap_sock, (struct sockaddr *) &addr, &len);
   	    io = g_io_channel_unix_new(nsk);
   	    g_io_add_watch(io, G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
					io_session_event, data); //监听连接socket的事件
    io_session_event
        //处理对应的SDP PDU
        handle_request(sk, buf, len);
            case SDP_SVC_SEARCH_REQ:
            case SDP_SVC_SEARCH_ATTR_REQ:
            ... ...
    
    //介绍sink主动发现远端SDP服务
    adapter.c:connected_callback //远端设备连接进来
    adapter.c:new_link_key_callback //linkkey交换
        browse_remote_sdp(&addr->bdaddr); //启动SDP发现
            bt_search_service(&adapter.bdaddr,
    			    &req->bdaddr, &uuid, browse_cb, req, NULL , 0)
                sdp_connect(src, dst, SDP_NON_BLOCKING | flags);
                    sdp_connect_l2cap
                    //直到连接成功
                    connect(session->sock, (struct sockaddr *) &sa, sizeof(sa)
                //设置可写监听
                g_io_add_watch(chan,
				    G_IO_OUT | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
				    connect_watch, *ctxt);
       connect_watch
           sdp_service_search_attr_async //发起SDP PDU请求
           //设置请求完成后的处理函数
           sdp_set_notify(ctxt->session, search_completed_cb, ctxt)
           g_io_add_watch(chan,
				G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
				search_process_cb, ctxt); //设置处理函数
       search_process_cb
           sdp_process
               SDP_SVC_SEARCH_ATTR_RSP:
               //收到PDU RSP,调用search_completed_cb
               search_completed_cb
                    browse_cb //调用bt_search_service设置的回调函数
                        search_cb
                            //根据SDP发现的profile进行设备probe
                            device_probe_profiles
                            device_svc_resolved(device, BROWSE_SDP, BDADDR_BREDR, err);
                                g_dbus_emit_property_changed(dbus_conn, device->path,
					DEVICE_INTERFACE, "ServicesResolved");
                                g_dbus_emit_property_changed(dbus_conn, dev->path,
						DEVICE_INTERFACE, "Paired");
                                while (dev->svc_callbacks)
                                    cb->func(dev, err, cb->user_data);
                                        auth_cb //通过btd_request_authorization添加
                        



//远程设备建立AVDTP signal
confirm_cb
    //profiles/audio/a2dp.c:confirm_cb() AVDTP: incoming connect from E0:62:67:38:2A:B7
    chan = channel_new(server, device, io);
        	chan = g_new0(struct a2dp_channel, 1);
    	chan->server = server; //a2dp_server
	    chan->device = device;
	    chan->state_id = avdtp_add_state_cb(device, avdtp_state_cb, chan);
        queue_push_tail(server->channels, chan) // 添加到a2dp_server channels链表
    chan->auth_id = btd_request_authorization(&src, &dst,
							ADVANCED_AUDIO_UUID,
							auth_cb, chan); //这里等待SDP必要的服务发现完成
 auth_cb
    bt_io_accept(chan->io, connect_cb, chan, NULL, &err)
    connect_cb
        chan->session = avdtp_new(chan->io, chan->device, chan->server->seps);
            avdtp_connect_cb
                session->io_id = g_io_add_watch_full(chan,
						G_PRIORITY_LOW,
						G_IO_IN | G_IO_ERR | G_IO_HUP
						| G_IO_NVAL,
						(GIOFunc) session_cb, session,
						NULL);    
 session_cb //处理AVDTP的消息

    

 

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
3. 蓝牙驱动介绍............................................................................................................................................... 4 3.1 串口驱动介绍........................................................................................................................................ 5 3.2 初始化.................................................................................................................................................... 5 3.2.1 模块上电........................................................................................................................................ 5 3.2.2 PSKEY的设置................................................................................................................................. 6 3.3 HCIATTACH的工作原理.......................................................................................................................... 7 3.3.1 Hci_uar和bcsp层的加入................................................................................................................. 9 3.3.2 hci层的加入.................................................................................................................................. 10 3.3.3 hci_attach的内核处理.................................................................................................................. 11 4. 数据在驱动的传递流程.............................................................................................................................. 13 4.1 UART层的数据接收.............................................................................................................................. 13 4.2 HCI_UART的数据接收.......................................................................................................................... 14 4.3 BCSP层的处理...................................................................................................................................... 15 4.4 HCI层及以上的处理............................................................................................................................. 15 4.5 数据流程的总结.................................................................................................................................. 17 5. 扫描过程的分析......................................................................................................................................... 18 5.1 用户使用例子...................................................................................................................................... 18 5.2 用HCITOOL扫描时的逻辑..................................................................................................................... 18 5.2.1 上层逻辑...................................................................................................................................... 18 5.2.2 内核层逻辑.................................................................................................................................. 19 5.3 通过DBUS触发的逻辑.......................................................................................................................... 21 5.3.1 上层逻辑之adapter dbus方法的建立........................................................................................... 21 5.3.2 上层扫描方法的调用................................................................................................................... 22 5.3.3 Dbus触发的扫描对应于内核层的处理........................................................................................ 25 5.3.4 上层的扫描数据收集................................................................................................................... 26 5.3.5 Hci_send_frame的讨论................................................................................................................. 28 6. A2DP的使用过程........................................................................................................................................ 28 6.1 如何使用.............................................................................................................................................. 28 6.2 服务的激活.......................................................................................................................................... 29 6.3 设备的创建.......................................................................................................................................... 30 6.3.1............................................................................................................................................................. 33 6.3.2............................................................................................................................................................. 33 6.3.3............................................................................................................................................................. 33 6.3.4............................................................................................................................................................. 33 6.4 设备的连接.......................................................................................................................................... 33
要在bluez中注册一个UUID,可以使用以下步骤: 1. 首先,需要创建一个包含UUID定义的XML文件。例如,创建一个名为`myuuids.xml`的文件,并将以下内容添加到该文件中: ``` <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE node PUBLIC "-//BlueZ//DTD D-Bus ObjectManager 1.0//EN" "http://git.kernel.org/cgit/bluetooth/bluez.git/plain/doc/dbus-objects-spec.txt"> <node> <interface name="org.bluez.GattService1"> <method name="GetPrimary"> <arg type="b" name="primary" direction="out"/> </method> <method name="GetCharacteristics"> <arg type="a{oa{sv}}" name="characteristics" direction="out"/> </method> <property name="UUID" type="s" access="read"/> <property name="Primary" type="b" access="read"/> <property name="Includes" type="as" access="read"/> </interface> <interface name="org.bluez.GattCharacteristic1"> <method name="ReadValue"> <arg type="a{sv}" name="options" direction="in" /> <arg type="ay" name="value" direction="out" /> </method> <method name="WriteValue"> <arg type="ay" name="value" direction="in" /> <arg type="a{sv}" name="options" direction="in" /> </method> <method name="Acquire"> <arg type="b" name="success" direction="out"/> </method> <method name="Release"/> <signal name="ValueChanged"> <arg type="ay" name="value"/> </signal> <property name="UUID" type="s" access="read"/> <property name="Service" type="o" access="read"/> <property name="Value" type="ay" access="readwrite"/> <property name="Notifying" type="b" access="readwrite"/> <property name="Flags" type="as" access="read"/> </interface> <interface name="org.freedesktop.DBus.Properties"> <method name="Get"> <arg type="s" name="interface_name" direction="in"/> <arg type="s" name="property_name" direction="in"/> <arg type="v" name="value" direction="out"/> </method> <method name="Set"> <arg type="s" name="interface_name" direction="in"/> <arg type="s" name="property_name" direction="in"/> <arg type="v" name="value" direction="in"/> </method> <method name="GetAll"> <arg type="s" name="interface_name" direction="in"/> <arg type="a{sv}" name="properties" direction="out"/> </method> <signal name="PropertiesChanged"> <arg type="s" name="interface_name"/> <arg type="a{sv}" name="changed_properties"/> <arg type="as" name="invalidated_properties"/> </signal> </interface> </node> ``` 2. 然后,使用以下命令将该文件注册到bluez中: ``` sudo gatttool -i hci0 -s /org/bluez/hci0 -a <handle> --char-write-req --value <uuid_xml> ``` 其中,`<handle>`是该服务的句柄值(可以使用`hcitool leinfo <device>`命令查找),`<uuid_xml>`是上面创建的XML文件的内容,需要将其转换为16进制格式并添加到命令中。 例如,如果你的服务句柄值为0x000c,可以使用以下命令注册UUID: ``` sudo gatttool -i hci0 -s /org/bluez/hci0 -a 0x000c --char-write-req --value 75 69 64 3d 22 6d 79 75 75 69 64 22 20 70 72 69 6d 61 72 79 3d 22 74 72 75 65 22 ``` 请注意,为了执行此命令,你需要具有管理员权限。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值