//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的消息