前面我们已经分析完了audio插件的初始化,audio_exit函数可自行分析;
下面我们看一下当有语音流时,代码的流程,我们从代码sink_connect入手,一步步来分析,至于sink_connect是在哪里调用,是在设备配对连接完成后的回调中,等后面分析设备配对连接时再去详细看吧;
首先上一张配图,我们下面肯定会用到这个,是AVDTP建立连接的流程图,其实我们在之前分析AVDTP协议时已经看过了,不过还是放到这里:
我们先从sink_connect函数开始分析,其定义如下:
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)//session是否为空,为空需要使用avdtp_get获取/创建一个
sink->session = avdtp_get(&dev->src, &dev->dst);
if (!sink->session)如果avdtp_get也没有获取新的session,这里应该报错退出
return btd_error_failed(msg, "Unable to get a session");
if (sink->connect || sink->disconnect)
return btd_error_busy(msg);
if (sink->stream_state >= AVDTP_STATE_OPEN)//
return btd_error_already_connected(msg);
if (!sink_setup_stream(sink, NULL))//创建数据链流程
return btd_error_failed(msg, "Failed to create a stream");
dev->auto_connect = FALSE;
pending = sink->connect;
pending->conn = dbus_connection_ref(conn);
pending->msg = dbus_message_ref(msg);
DBG("stream creation in progress");
return NULL;
}
这里我们分三部分解析,第一部分,第8-12行,得到avdtp session,我们知道,a2dp是个应用层协议,AVDTP定义了A/V stream协商、建链和传输过程和数据传输的格式,我们先看avdtp_get函数,定义如下:
struct avdtp *avdtp_get(bdaddr_t *src, bdaddr_t *dst)
{
struct avdtp *session;
session = avdtp_get_internal(src, dst);
if (!session)
return NULL;
return avdtp_ref(session);
}
static struct avdtp *avdtp_get_internal(const bdaddr_t *src, const bdaddr_t *dst)
{
struct avdtp_server *server;
struct avdtp *session;
assert(src != NULL);
assert(dst != NULL);
server = find_server(servers, src);
if (server == NULL)
return NULL;
session = find_session(server->sessions, dst);
if (session) {
if (session->pending_auth)
return NULL;
else
return session;
}
session = g_new0(struct avdtp, 1);
session->server = server;
bacpy(&session->dst, dst);
session->ref = 1;
/* We don't use avdtp_set_state() here since this isn't a state change
* but just setting of the initial state */
session->state = AVDTP_SESSION_STATE_DISCONNECTED;
session->auto_dc = TRUE;
session->version = get_version(session);
server->sessions = g_slist_append(server->sessions, session);
return session;
}
函数avdtp_get比较容易理解,根据蓝牙地址去查找是否存在avdtp对话,如果不存在,则创建一个,这里我们看下struct avdtp的定义,见下注释;
/* Structure describing an AVDTP connection between two devices */
struct avdtp {
int ref;
int free_lock;
uint16_t version;
struct avdtp_server *server;
bdaddr_t dst;
avdtp_session_state_t state;//avdtp state,已连接,未连接,正在连接几个状态
/* True if the session should be automatically disconnected */
gboolean auto_dc;
/* True if the entire device is being disconnected */
gboolean device_disconnect;
GIOChannel *io;
guint io_id;
GSList *seps; /* Elements of type struct avdtp_remote_sep * *///上一篇我们分析了a2dp_add_sep函数
GSList *streams; /* Elements of type struct avdtp_stream * */
GSList *req_queue; /* Elements of type struct pending_req * */
GSList *prio_queue; /* Same as req_queue but is processed before it */
struct avdtp_stream *pending_open;
uint16_t imtu;
uint16_t omtu;
struct in_buf in;
char *buf;
avdtp_discover_cb_t discov_cb;//这个回调函数后面还会看到
void *user_data;
struct pending_req *req;
guint dc_timer;
/* Attempt stream setup instead of disconnecting */
gboolean stream_setup;
DBusPendingCall *pending_auth;
};
第二部分,第14-21行,14-18行是判断是否已经连接,我们主要看20行,有了avdpt session,下面就可以去创建流的通道,函数sink_setup_stream定义如下,其逻辑比较简单,此时state = AVDTP_SESSION_STATE_DISCONNECTED(在上面的avdtp_get->avdtp_get_internal中设置了state为AVDTP_SESSION_STATE_DISCONNECTED),此时的代码逻辑为avdtp_discover->send_request->send_req->l2cap_connect,l2cap_connect最终通过socket来创建连接,下面我们具体分析;
gboolean sink_setup_stream(struct sink *sink, struct avdtp *session)
{
if (sink->connect || sink->disconnect)
return FALSE;
if (session && !sink->session)
sink->session = avdtp_ref(session);//
if (!sink->session)
return FALSE;
avdtp_set_auto_disconnect(sink->session, FALSE);
if (avdtp_discover(sink->session, discovery_complete, sink) < 0)
return FALSE;
sink->connect = g_new0(struct pending_request, 1);
return TRUE;
}
由文章开始的流程图我们可以得知,AVDTP建立连接的第一步是Discovery,我们在函数sink_setup_stream中看到了我们想要的avdtp_discover函数,其定义如下,这里还有一个回调函数discovery_complete,别忘记,待会我们还会回个头来看这个函数;
int avdtp_discover(struct avdtp *session, avdtp_discover_cb_t cb,
void *user_data)
{
int err;
if (session->discov_cb)
return -EBUSY;
if (session->seps) {
session->discov_cb = cb;
session->user_data = user_data;
g_idle_add(process_discover, session);
return 0;
}
err = send_request(session, FALSE, NULL, AVDTP_DISCOVER, NULL, 0);
if (err == 0) {
session->discov_cb = cb;
session->user_data = user_data;
}
return err;
}
函数avdtp_discover比较简单,在内部调用了send_request,然后又调用函数send_req,其定义如下
static int send_req(struct avdtp *session, gboolean priority,
struct pending_req *req)
{
static int transaction = 0;
int err;
if (session->state == AVDTP_SESSION_STATE_DISCONNECTED) {//在AVDTP的discover状态时,执行这一分支
session->io = l2cap_connect(session);
if (!session->io) {
err = -EIO;
goto failed;
}
avdtp_set_state(session, AVDTP_SESSION_STATE_CONNECTING);
}
if (session->state < AVDTP_SESSION_STATE_CONNECTED ||
session->req != NULL) {
queue_request(session, req, priority);
return 0;
}
req->transaction = transaction++;
transaction %= 16;
/* FIXME: Should we retry to send if the buffer
was not totally sent or in case of EINTR? */
if (!avdtp_send(session, req->transaction, AVDTP_MSG_TYPE_COMMAND,
req->signal_id, req->data, req->data_size)) {
err = -EIO;
goto failed;
}
session->req = req;
req->timeout = g_timeout_add_seconds(req->signal_id == AVDTP_ABORT ?
ABORT_TIMEOUT : REQ_TIMEOUT,
request_timeout,
session);
return 0;
failed:
g_free(req->data);
g_free(req);
return err;
}
最开始执行session->state == AVDTP_SESSION_STATE_DISCONNECTED分支,注意这里把状态修改为AVDTP_SESSION_STATE_CONNECTING,l2cap_connect函数定义如下,这有两个函数我们看下,一个是bt_io_connect,另一个是回调函数avdtp_connect_cb;
static GIOChannel *l2cap_connect(struct avdtp *session)
{
GError *err = NULL;
GIOChannel *io;
io = bt_io_connect(BT_IO_L2CAP, avdtp_connect_cb, session,
NULL, &err,
BT_IO_OPT_SOURCE_BDADDR, &session->server->src,
BT_IO_OPT_DEST_BDADDR, &session->dst,
BT_IO_OPT_PSM, AVDTP_PSM,
BT_IO_OPT_INVALID);
if (!io) {
error("%s", err->message);
g_error_free(err);
return NULL;
}
return io;
}
先看函数bt_io_connect,这里我们传进来的type是BT_IO_L2CAP,是为AVDTP创建一个L2CAP通道,所以这里会调用l2cap_connect,注意最后的函数connect_add,这里将我们前面的函数avdtp_connect_cb放到了g_io_add_watch_full,当此通道的L2CAP有数据时,会调用这个回调;这里多说一点,就是L2CAP的独立性,我们这个L2CAP通道就是给AVDTP的指定session创建的,当有新的session时,需要重新建立L2CAP通道;
l2cap_connect函数比较简单,使用socket的connect函数,如果对socket不熟悉,请自行补课;
GIOChannel *bt_io_connect(BtIOType type, BtIOConnect connect,
gpointer user_data, GDestroyNotify destroy,
GError **gerr, BtIOOption opt1, ...)
{
GIOChannel *io;
va_list args;
struct set_opts opts;
int err, sock;
gboolean ret;
va_start(args, opt1);
ret = parse_set_opts(&opts, gerr, opt1, args);
va_end(args);
if (ret == FALSE)
return NULL;
io = create_io(type, FALSE, &opts, gerr);
if (io == NULL)
return NULL;
sock = g_io_channel_unix_get_fd(io);
switch (type) {
case BT_IO_L2RAW:
err = l2cap_connect(sock, &opts.dst, 0, opts.cid);
break;
case BT_IO_L2CAP:
err = l2cap_connect(sock, &opts.dst, opts.psm, opts.cid);
break;
case BT_IO_RFCOMM:
err = rfcomm_connect(sock, &opts.dst, opts.channel);
break;
case BT_IO_SCO:
err = sco_connect(sock, &opts.dst);
break;
default:
g_set_error(gerr, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
"Unknown BtIO type %d", type);
return NULL;
}
if (err < 0) {
g_set_error(gerr, BT_IO_ERROR, BT_IO_ERROR_CONNECT_FAILED,
"connect: %s (%d)", strerror(-err), -err);
g_io_channel_unref(io);
return NULL;
}
connect_add(io, connect, user_data, destroy);
return io;
}
static int l2cap_connect(int sock, const bdaddr_t *dst,
uint16_t psm, uint16_t cid)
{
int err;
struct sockaddr_l2 addr;
memset(&addr, 0, sizeof(addr));
addr.l2_family = AF_BLUETOOTH;
bacpy(&addr.l2_bdaddr, dst);
if (cid)
addr.l2_cid = htobs(cid);
else
addr.l2_psm = htobs(psm);
err = connect(sock, (struct sockaddr *) &addr, sizeof(addr));
if (err < 0 && !(errno == EAGAIN || errno == EINPROGRESS))
return err;
return 0;
}
看到这里,我们再回过头去,我们是从函数avdtp_discover,但因为链路没有建立,所以第一次执行时,先建立了socket通道,此时DISCOVER命令还没有发送出去,那是在什么地方发送的命令?答案是在函数avdtp_connect_cb中;
我们前面说到在bt_io_connect中会注册回调函数avdtp_connect_cb,当有数据数据时,会执行avdtp_connect_cb函数,我们看下定义,当连接建立时,函数avdtp_connect_cb实际执行的是第53行的handle_transport_connect和63行的process_queue,下面我们分别来看这两个函数;
static void avdtp_connect_cb(GIOChannel *chan, GError *err, gpointer user_data)
{
struct avdtp *session = user_data;
char address[18];
GError *gerr = NULL;
if (err) {
error("%s", err->message);
goto failed;
}
if (!session->io)
session->io = g_io_channel_ref(chan);
bt_io_get(chan, BT_IO_L2CAP, &gerr,
BT_IO_OPT_OMTU, &session->omtu,
BT_IO_OPT_IMTU, &session->imtu,
BT_IO_OPT_INVALID);
if (gerr) {
error("%s", gerr->message);
g_error_free(gerr);
goto failed;
}
ba2str(&session->dst, address);
DBG("AVDTP: connected %s channel to %s",
session->pending_open ? "transport" : "signaling",
address);
if (session->state == AVDTP_SESSION_STATE_CONNECTING) {
DBG("AVDTP imtu=%u, omtu=%u", session->imtu, session->omtu);
session->buf = g_malloc0(MAX(session->imtu, session->omtu));
avdtp_set_state(session, AVDTP_SESSION_STATE_CONNECTED);
if (session->io_id)
g_source_remove(session->io_id);
/* This watch should be low priority since otherwise the
* connect callback might be dispatched before the session
* callback if the kernel wakes us up at the same time for
* them. This could happen if a headset is very quick in
* sending the Start command after connecting the stream
* transport channel.
*/
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);
if (session->stream_setup) {
set_disconnect_timer(session);
avdtp_set_auto_disconnect(session, FALSE);
}
} else if (session->pending_open)
handle_transport_connect(session, chan, session->imtu,
session->omtu);
else
goto failed;
process_queue(session);
return;
failed:
if (session->pending_open) {
struct avdtp_stream *stream = session->pending_open;
handle_transport_connect(session, NULL, 0, 0);
if (avdtp_abort(session, stream) < 0)
avdtp_sep_set_state(session, stream->lsep,
AVDTP_STATE_IDLE);
} else
connection_lost(session, EIO);
}
因为我们前面修改了状态,所以在函数avdtp_connect_cb中,走的是session->state == AVDTP_SESSION_STATE_CONNECTING分支,这里也是调用了g_io_add_watch_full监控,增加了一个回调函数session_cb,我们待会再看;我们继续往下分析函数process_queue,在这个函数当中发送了刚才的discover命令,其定义如下,可以看到process_queue调用了函数send_req,这个函数我们之前看过,虽然现在的状态是CONNECTING,但其session->req不为NULL,所以最终会调用函数avdtp_send发送;
static int process_queue(struct avdtp *session)
{
GSList **queue, *l;
struct pending_req *req;
if (session->req)
return 0;
if (session->prio_queue)
queue = &session->prio_queue;
else
queue = &session->req_queue;
if (!*queue)
return 0;
l = *queue;
req = l->data;
*queue = g_slist_remove(*queue, req);
return send_req(session, FALSE, req);
}
avdtp_send函数定义如下,这是比较底层的一个函数了,所有的avdtp数据包都有这个函数实现发送,前面我们看到需要发送discover命令,AVDTP有四种数据包,discover命令肯定是single包,所以只需要查看第18-33行,打包AVDTP包头后发送数据,其中try_send就是调用socket的send函数;
static gboolean avdtp_send(struct avdtp *session, uint8_t transaction,
uint8_t message_type, uint8_t signal_id,
void *data, size_t len)
{
unsigned int cont_fragments, sent;
struct avdtp_start_header start;
struct avdtp_continue_header cont;
int sock;
if (session->io == NULL) {
error("avdtp_send: session is closed");
return FALSE;
}
sock = g_io_channel_unix_get_fd(session->io);
/* Single packet - no fragmentation */
if (sizeof(struct avdtp_single_header) + len <= session->omtu) {
struct avdtp_single_header single;
memset(&single, 0, sizeof(single));
single.transaction = transaction;
single.packet_type = AVDTP_PKT_TYPE_SINGLE;
single.message_type = message_type;
single.signal_id = signal_id;
memcpy(session->buf, &single, sizeof(single));
memcpy(session->buf + sizeof(single), data, len);
return try_send(sock, session->buf, sizeof(single) + len);
}
/* Check if there is enough space to start packet */
if (session->omtu < sizeof(start)) {
error("No enough space to fragment packet");
return FALSE;
}
/* Count the number of needed fragments */
cont_fragments = (len - (session->omtu - sizeof(start))) /
(session->omtu - sizeof(cont)) + 1;
DBG("%zu bytes split into %d fragments", len, cont_fragments + 1);
/* Send the start packet */
memset(&start, 0, sizeof(start));
start.transaction = transaction;
start.packet_type = AVDTP_PKT_TYPE_START;
start.message_type = message_type;
start.no_of_packets = cont_fragments + 1;
start.signal_id = signal_id;
memcpy(session->buf, &start, sizeof(start));
memcpy(session->buf + sizeof(start), data,
session->omtu - sizeof(start));
if (!try_send(sock, session->buf, session->omtu))
return FALSE;
DBG("first packet with %zu bytes sent", session->omtu - sizeof(start));
sent = session->omtu - sizeof(start);
/* Send the continue fragments and the end packet */
while (sent < len) {
int left, to_copy;
left = len - sent;
if (left + sizeof(cont) > session->omtu) {
cont.packet_type = AVDTP_PKT_TYPE_CONTINUE;
to_copy = session->omtu - sizeof(cont);
DBG("sending continue with %d bytes", to_copy);
} else {
cont.packet_type = AVDTP_PKT_TYPE_END;
to_copy = left;
DBG("sending end with %d bytes", to_copy);
}
cont.transaction = transaction;
cont.message_type = message_type;
memcpy(session->buf, &cont, sizeof(cont));
memcpy(session->buf + sizeof(cont), data + sent, to_copy);
if (!try_send(sock, session->buf, to_copy + sizeof(cont)))
return FALSE;
sent += to_copy;
}
return TRUE;
}
上面看到了函数avdtp_send发送了AVDTP的discover命令,当对端收到命令时,会调用前面提到的session_cb函数,其定义如下:
static gboolean session_cb(GIOChannel *chan, GIOCondition cond,
gpointer data)
{
struct avdtp *session = data;
struct avdtp_common_header *header;
ssize_t size;
int fd;
DBG("");
if (cond & G_IO_NVAL)
return FALSE;
header = (void *) session->buf;
if (cond & (G_IO_HUP | G_IO_ERR))
goto failed;
fd = g_io_channel_unix_get_fd(chan);
size = read(fd, session->buf, session->imtu);
if (size < 0) {
error("IO Channel read error");
goto failed;
}
if ((size_t) size < sizeof(struct avdtp_common_header)) {
error("Received too small packet (%zu bytes)", size);
goto failed;
}
switch (avdtp_parse_data(session, session->buf, size)) {
case PARSE_ERROR:
goto failed;
case PARSE_FRAGMENT:
return TRUE;
case PARSE_SUCCESS:
break;
}
if (session->in.message_type == AVDTP_MSG_TYPE_COMMAND) {
if (!avdtp_parse_cmd(session, session->in.transaction,
session->in.signal_id,
session->in.buf,
session->in.data_size)) {
error("Unable to handle command. Disconnecting");
goto failed;
}
if (session->ref == 1 && !session->streams && !session->req)
set_disconnect_timer(session);
if (session->streams && session->dc_timer)
remove_disconnect_timer(session);
return TRUE;
}
if (session->req == NULL) {
error("No pending request, ignoring message");
return TRUE;
}
if (header->transaction != session->req->transaction) {
error("Transaction label doesn't match");
return TRUE;
}
if (session->in.signal_id != session->req->signal_id) {
error("Response signal doesn't match");
return TRUE;
}
g_source_remove(session->req->timeout);
session->req->timeout = 0;
switch (header->message_type) {
case AVDTP_MSG_TYPE_ACCEPT:
if (!avdtp_parse_resp(session, session->req->stream,
session->in.transaction,
session->in.signal_id,
session->in.buf,
session->in.data_size)) {
error("Unable to parse accept response");
goto failed;
}
break;
case AVDTP_MSG_TYPE_REJECT:
if (!avdtp_parse_rej(session, session->req->stream,
session->in.transaction,
session->in.signal_id,
session->in.buf,
session->in.data_size)) {
error("Unable to parse reject response");
goto failed;
}
break;
case AVDTP_MSG_TYPE_GEN_REJECT:
error("Received a General Reject message");
break;
default:
error("Unknown message type 0x%02X", header->message_type);
break;
}
pending_req_free(session->req);
session->req = NULL;
process_queue(session);
return TRUE;
failed:
connection_lost(session, EIO);
return FALSE;
}
分析session_cb函数时,我们就可以对照着AVDTP protocol spec来分析;首先分析session_cb的前29行,第19行使用chan参数获取fd,第20行读取数据,第21-29行对数据做简单验证;
第31行函数avdtp_parse_data定义在下面,是将读取到的header和data拷贝到入参session当中,因为AVDTP的有四种数据包格式(packet type),分别为single packets,start packets,continue packets,end packets,函数avdtp_parse_data就是按照这四种格式来解析数据包的,协议请参看下面代码及附图;
分析函数avdtp_parse_data时会用到下面结构体和函数,函数avdtp_parse_data是用来拷贝AVDTP header和data数据的,最终拷贝到入参session中;
struct in_buf {//这个结构体对照上面AVDTP格式图部分字段
gboolean active;
int no_of_packets;//包数量
uint8_t transaction;//TL
uint8_t message_type;//Message type
uint8_t signal_id;//signal identifer
uint8_t buf[1024];
uint8_t data_size;
};
static enum avdtp_parse_result avdtp_parse_data(struct avdtp *session,
void *buf, size_t size)
{
struct avdtp_common_header *header = buf;
struct avdtp_single_header *single = (void *) session->buf;
struct avdtp_start_header *start = (void *) session->buf;
void *payload;
gsize payload_size;
switch (header->packet_type) {//这里packet_type有四种类型,函数avdtp_parse_data的作用就是拷贝
case AVDTP_PKT_TYPE_SINGLE:
if (size < sizeof(*single)) {
error("Received too small single packet (%zu bytes)", size);
return PARSE_ERROR;
}
if (session->in.active) {
error("SINGLE: Invalid AVDTP packet fragmentation");
return PARSE_ERROR;
}
payload = session->buf + sizeof(*single);
payload_size = size - sizeof(*single);
session->in.active = TRUE;
session->in.data_size = 0;
session->in.no_of_packets = 1;
session->in.transaction = header->transaction;
session->in.message_type = header->message_type;
session->in.signal_id = single->signal_id;
break;
case AVDTP_PKT_TYPE_START:
if (size < sizeof(*start)) {
error("Received too small start packet (%zu bytes)", size);
return PARSE_ERROR;
}
if (session->in.active) {
error("START: Invalid AVDTP packet fragmentation");
return PARSE_ERROR;
}
session->in.active = TRUE;
session->in.data_size = 0;
session->in.transaction = header->transaction;
session->in.message_type = header->message_type;
session->in.no_of_packets = start->no_of_packets;
session->in.signal_id = start->signal_id;
payload = session->buf + sizeof(*start);
payload_size = size - sizeof(*start);
break;
case AVDTP_PKT_TYPE_CONTINUE:
if (size < sizeof(struct avdtp_continue_header)) {
error("Received too small continue packet (%zu bytes)",
size);
return PARSE_ERROR;
}
if (!session->in.active) {
error("CONTINUE: Invalid AVDTP packet fragmentation");
return PARSE_ERROR;
}
if (session->in.transaction != header->transaction) {
error("Continue transaction id doesn't match");
return PARSE_ERROR;
}
if (session->in.no_of_packets <= 1) {
error("Too few continue packets");
return PARSE_ERROR;
}
payload = session->buf + sizeof(struct avdtp_continue_header);
payload_size = size - sizeof(struct avdtp_continue_header);
break;
case AVDTP_PKT_TYPE_END:
if (size < sizeof(struct avdtp_continue_header)) {
error("Received too small end packet (%zu bytes)", size);
return PARSE_ERROR;
}
if (!session->in.active) {
error("END: Invalid AVDTP packet fragmentation");
return PARSE_ERROR;
}
if (session->in.transaction != header->transaction) {
error("End transaction id doesn't match");
return PARSE_ERROR;
}
if (session->in.no_of_packets > 1) {
error("Got an end packet too early");
return PARSE_ERROR;
}
payload = session->buf + sizeof(struct avdtp_continue_header);
payload_size = size - sizeof(struct avdtp_continue_header);
break;
default:
error("Invalid AVDTP packet type 0x%02X", header->packet_type);
return PARSE_ERROR;
}
if (session->in.data_size + payload_size >
sizeof(session->in.buf)) {
error("Not enough incoming buffer space!");
return PARSE_ERROR;
}
memcpy(session->in.buf + session->in.data_size, payload, payload_size);
session->in.data_size += payload_size;
if (session->in.no_of_packets > 1) {
session->in.no_of_packets--;
DBG("Received AVDTP fragment. %d to go",
session->in.no_of_packets);
return PARSE_FRAGMENT;
}
session->in.active = FALSE;
return PARSE_SUCCESS;
}
继续解析session_cb,函数session_cb的第40-103行是按照上图中的Message Type字段来解析的,在代码中是变量message_type,我们先来看一下Message Type字段的说明,见下图,可以看出,Message Type字段占用2bit,代表4中类型,函数session_cb的第40-103行区分这4种类型来输出错误信息;
上面我们看到函数avdtp_parse_data对收到的avdtp包进行了解析,因为avdpt是命令包,所以会执行session_cb第41行的avdtp_parse_cmd,其定义如下:
static gboolean avdtp_parse_cmd(struct avdtp *session, uint8_t transaction,
uint8_t signal_id, void *buf, int size)
{
switch (signal_id) {
case AVDTP_DISCOVER:
DBG("Received DISCOVER_CMD");
return avdtp_discover_cmd(session, transaction, buf, size);
case AVDTP_GET_CAPABILITIES:
DBG("Received GET_CAPABILITIES_CMD");
return avdtp_getcap_cmd(session, transaction, buf, size,
FALSE);
case AVDTP_GET_ALL_CAPABILITIES:
DBG("Received GET_ALL_CAPABILITIES_CMD");
return avdtp_getcap_cmd(session, transaction, buf, size, TRUE);
case AVDTP_SET_CONFIGURATION:
DBG("Received SET_CONFIGURATION_CMD");
return avdtp_setconf_cmd(session, transaction, buf, size);
case AVDTP_GET_CONFIGURATION:
DBG("Received GET_CONFIGURATION_CMD");
return avdtp_getconf_cmd(session, transaction, buf, size);
case AVDTP_RECONFIGURE:
DBG("Received RECONFIGURE_CMD");
return avdtp_reconf_cmd(session, transaction, buf, size);
case AVDTP_OPEN:
DBG("Received OPEN_CMD");
return avdtp_open_cmd(session, transaction, buf, size);
case AVDTP_START:
DBG("Received START_CMD");
return avdtp_start_cmd(session, transaction, buf, size);
case AVDTP_CLOSE:
DBG("Received CLOSE_CMD");
return avdtp_close_cmd(session, transaction, buf, size);
case AVDTP_SUSPEND:
DBG("Received SUSPEND_CMD");
return avdtp_suspend_cmd(session, transaction, buf, size);
case AVDTP_ABORT:
DBG("Received ABORT_CMD");
return avdtp_abort_cmd(session, transaction, buf, size);
case AVDTP_SECURITY_CONTROL:
DBG("Received SECURITY_CONTROL_CMD");
return avdtp_secctl_cmd(session, transaction, buf, size);
case AVDTP_DELAY_REPORT:
DBG("Received DELAY_REPORT_CMD");
return avdtp_delayreport_cmd(session, transaction, buf, size);
default:
DBG("Received unknown request id %u", signal_id);
return avdtp_unknown_cmd(session, transaction, signal_id);
}
}
可以看到函数avdtp_parse_cmd就是一个事件分发器,这里我们收到的是discover命令,所以执行avdtp_discover_cmd,其定义如下:
static gboolean avdtp_discover_cmd(struct avdtp *session, uint8_t transaction,
void *buf, int size)
{
GSList *l;
unsigned int rsp_size, sep_count, i;
struct seid_info *seps;
gboolean ret;
sep_count = g_slist_length(session->server->seps);
if (sep_count == 0) {
uint8_t err = AVDTP_NOT_SUPPORTED_COMMAND;
return avdtp_send(session, transaction, AVDTP_MSG_TYPE_REJECT,
AVDTP_DISCOVER, &err, sizeof(err));
}
rsp_size = sep_count * sizeof(struct seid_info);
seps = g_new0(struct seid_info, sep_count);
for (l = session->server->seps, i = 0; l != NULL; l = l->next, i++) {
struct avdtp_local_sep *sep = l->data;
memcpy(&seps[i], &sep->info, sizeof(struct seid_info));
}
ret = avdtp_send(session, transaction, AVDTP_MSG_TYPE_ACCEPT,
AVDTP_DISCOVER, seps, rsp_size);
g_free(seps);
return ret;
}
我们看到函数avdtp_discover_cmd的第9-15行,这里是判断SEP端点的个数,我们前面解析AVDTP时说过,所有的数据流必须通过SEP传输,如果这里SEP个数为0,则返回一个AVDTP_NOT_SUPPORTED_COMMAND的AVDTP命令,第21-25行打包SEID信息,然后由第27行的avdtp_send发送,函数avdtp_send我们前面已经看过了,AVDTP discover流程可以参看下图进行解析:
上图中的前两个字节,包括Signaling Header/RFA/AVDTP_DISCOVER(message_id)对应下面结构体:
struct avdtp_start_header {
uint8_t message_type:2;
uint8_t packet_type:2;
uint8_t transaction:4;
uint8_t no_of_packets;
uint8_t signal_id:6;
uint8_t rfa0:2;
} __attribute__ ((packed));
当接收端发了AVDTP discover的accept后,发送端同样由session_cb处理ACCEPT或REJECT,我们这里看ACCEPT的流程,回到session_cb函数,当发送端收到ACCEPT Response后,会跳到session_cb的第76行,当执行分支AVDTP_MSG_TYPE_ACCEPT时,进入函数avdtp_parse_resp,其定义如下:
static gboolean avdtp_parse_resp(struct avdtp *session,
struct avdtp_stream *stream,
uint8_t transaction, uint8_t signal_id,
void *buf, int size)
{
struct pending_req *next;
const char *get_all = "";
if (session->prio_queue)
next = session->prio_queue->data;
else if (session->req_queue)
next = session->req_queue->data;
else
next = NULL;
switch (signal_id) {
case AVDTP_DISCOVER:
DBG("DISCOVER request succeeded");
return avdtp_discover_resp(session, buf, size);
case AVDTP_GET_ALL_CAPABILITIES:
get_all = "ALL_";
case AVDTP_GET_CAPABILITIES:
DBG("GET_%sCAPABILITIES request succeeded", get_all);
if (!avdtp_get_capabilities_resp(session, buf, size))
return FALSE;
if (!(next && (next->signal_id == AVDTP_GET_CAPABILITIES ||
next->signal_id == AVDTP_GET_ALL_CAPABILITIES)))
finalize_discovery(session, 0);
return TRUE;
}
/* The remaining commands require an existing stream so bail out
* here if the stream got unexpectedly disconnected */
if (!stream) {
DBG("AVDTP: stream was closed while waiting for reply");
return TRUE;
}
switch (signal_id) {
case AVDTP_SET_CONFIGURATION:
DBG("SET_CONFIGURATION request succeeded");
return avdtp_set_configuration_resp(session, stream,
buf, size);
case AVDTP_RECONFIGURE:
DBG("RECONFIGURE request succeeded");
return avdtp_reconfigure_resp(session, stream, buf, size);
case AVDTP_OPEN:
DBG("OPEN request succeeded");
return avdtp_open_resp(session, stream, buf, size);
case AVDTP_SUSPEND:
DBG("SUSPEND request succeeded");
return avdtp_suspend_resp(session, stream, buf, size);
case AVDTP_START:
DBG("START request succeeded");
return avdtp_start_resp(session, stream, buf, size);
case AVDTP_CLOSE:
DBG("CLOSE request succeeded");
return avdtp_close_resp(session, stream, buf, size);
case AVDTP_ABORT:
DBG("ABORT request succeeded");
return avdtp_abort_resp(session, stream, buf, size);
case AVDTP_DELAY_REPORT:
DBG("DELAY_REPORT request succeeded");
return avdtp_delay_report_resp(session, stream, buf, size);
}
error("Unknown signal id in accept response: %u", signal_id);
return TRUE;
}
因为这里是处理DISCOVER命令的RESPONSE,所以会执行函数avdtp_discover_resp,其定义如下:
static gboolean avdtp_discover_resp(struct avdtp *session,
struct discover_resp *resp, int size)
{
int sep_count, i;
uint8_t getcap_cmd;
int ret = 0;
gboolean getcap_pending = FALSE;
if (session->version >= 0x0103 && session->server->version >= 0x0103)
getcap_cmd = AVDTP_GET_ALL_CAPABILITIES;
else
getcap_cmd = AVDTP_GET_CAPABILITIES;
sep_count = size / sizeof(struct seid_info);
for (i = 0; i < sep_count; i++) {
struct avdtp_remote_sep *sep;
struct avdtp_stream *stream;
struct seid_req req;
DBG("seid %d type %d media %d in use %d",
resp->seps[i].seid, resp->seps[i].type,
resp->seps[i].media_type, resp->seps[i].inuse);
stream = find_stream_by_rseid(session, resp->seps[i].seid);
sep = find_remote_sep(session->seps, resp->seps[i].seid);
if (!sep) {
if (resp->seps[i].inuse && !stream)
continue;
sep = g_new0(struct avdtp_remote_sep, 1);
session->seps = g_slist_append(session->seps, sep);
}
sep->stream = stream;
sep->seid = resp->seps[i].seid;
sep->type = resp->seps[i].type;
sep->media_type = resp->seps[i].media_type;
memset(&req, 0, sizeof(req));
req.acp_seid = sep->seid;
ret = send_request(session, TRUE, NULL, getcap_cmd,
&req, sizeof(req));
if (ret < 0)
break;
getcap_pending = TRUE;
}
if (!getcap_pending)
finalize_discovery(session, -ret);
return TRUE;
}
如上,函数avdtp_discover_resp会发送GET CAPABILITY,注意参数getcap_cmd,因为我们使用的版本大于1.03,所以这里是获取所有CAPABLITIES,分装好header后通过函数send_request发送出去,我们前面已经看过send_request了,发送流程是一样的;
我们重点看一下函数finalize_discovery,其定义如下:
static void finalize_discovery(struct avdtp *session, int err)
{
struct avdtp_error avdtp_err;
avdtp_error_init(&avdtp_err, AVDTP_ERRNO, err);
if (!session->discov_cb)
return;
session->discov_cb(session, session->seps,
err ? &avdtp_err : NULL,
session->user_data);
session->discov_cb = NULL;
session->user_data = NULL;
}
我们看到函数finalize_discovery函数执行了session->discov_cb,这个函数的赋值是在avdtp_discover的第10行,忘记的请翻看前面的分析,所以这里执行的是函数discovery_complete,其定义如下(这里source和sink流程对应的函数不同,我们主要看sink流程):
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;
int id;
if (!sink->connect) {
avdtp_unref(sink->session);
sink->session = NULL;
return;
}
pending = sink->connect;
if (err) {
avdtp_unref(sink->session);
sink->session = NULL;
if (avdtp_error_category(err) == AVDTP_ERRNO
&& avdtp_error_posix_errno(err) != EHOSTDOWN) {
DBG("connect:connect XCASE detected");
sink->retry_id =
g_timeout_add_seconds(STREAM_SETUP_RETRY_TIMER,
stream_setup_retry,
sink);
} else
goto failed;
return;
}
DBG("Discovery complete");
id = a2dp_select_capabilities(sink->session, AVDTP_SEP_TYPE_SINK, NULL,
select_complete, sink);
if (id == 0)
goto failed;
pending->id = id;
return;
failed:
if (pending->msg)
error_failed(pending->conn, pending->msg, "Stream setup failed");
pending_request_free(sink->dev, pending);
sink->connect = NULL;
avdtp_unref(sink->session);
sink->session = NULL;
}
我们在函数discovery_complete中看到,在31行之前都是做一些error check,在函数discovery_complete中,我们主要看其中的函数a2dp_select_capabilities,他有一个回调函数select_complete,后面会看到这个函数的调用,我们先看下a2dp_select_capabilities的定义:
unsigned int a2dp_select_capabilities(struct avdtp *session,
uint8_t type, const char *sender,
a2dp_select_cb_t cb,
void *user_data)
{
struct a2dp_setup *setup;
struct a2dp_setup_cb *cb_data;
struct a2dp_sep *sep;
struct avdtp_service_capability *service;
struct avdtp_media_codec_capability *codec;
sep = a2dp_select_sep(session, type, sender);
if (!sep) {
error("Unable to select SEP");
return 0;
}
setup = a2dp_setup_get(session);
if (!setup)
return 0;
cb_data = setup_cb_new(setup);
cb_data->select_cb = cb;//这里注意,重新给了回调函数,当下次调用finalize_discovery时,回调函数已经换成
cb_data->user_data = user_data;
setup->sep = sep;
setup->rsep = avdtp_find_remote_sep(session, sep->lsep);
if (setup->rsep == NULL) {
error("Could not find remote sep");
goto fail;
}
/* FIXME: Remove auto select when it is not longer possible to register
endpoint in the configuration file */
if (sep->endpoint == NULL) {
if (!select_capabilities(session, setup->rsep,
&setup->caps)) {
error("Unable to auto select remote SEP capabilities");
goto fail;
}
g_idle_add(auto_select, setup);
return cb_data->id;
}
service = avdtp_get_codec(setup->rsep);
codec = (struct avdtp_media_codec_capability *) service->data;
if (media_endpoint_select_configuration(sep->endpoint, codec->data,
service->length - sizeof(*codec),
select_cb, setup) ==
TRUE)
return cb_data->id;
fail:
setup_cb_free(cb_data);
return 0;
}
关于函数a2dp_select_capabilities,我们重点看一点,就是新增了一个回调函数,在函数a2dp_select_capabilities的第23行,重新赋值了一个回调函数,这个函数是select_complete,在函数media_endpoint_select_configuration时,会通过select_cb触发这个函数,我们后面再来详细分析;
其他的就是整理通过DISCOVER得到的数据,放到我们struct avdtp中,有兴趣的可以对照endpoint相关spec看一下;
二、GET CAPABILITIES流程
我们前面在函数avdtp_discover_resp中看到发送了GET CAPABILITIES命令,接收端还是通过session_cb来进行处理,同样是通过函数avdtp_parse_cmd进行命令分发,之后执行函数avdtp_getcap_cmd,其定义如下:
static gboolean avdtp_getcap_cmd(struct avdtp *session, uint8_t transaction,
struct seid_req *req, unsigned int size,
gboolean get_all)
{
GSList *l, *caps;
struct avdtp_local_sep *sep = NULL;
unsigned int rsp_size;
uint8_t err, buf[1024], *ptr = buf;
uint8_t cmd;
cmd = get_all ? AVDTP_GET_ALL_CAPABILITIES : AVDTP_GET_CAPABILITIES;
if (size < sizeof(struct seid_req)) {
err = AVDTP_BAD_LENGTH;
goto failed;
}
sep = find_local_sep_by_seid(session->server, req->acp_seid);
if (!sep) {
err = AVDTP_BAD_ACP_SEID;
goto failed;
}
if (get_all && session->server->version < 0x0103)
return avdtp_unknown_cmd(session, transaction, cmd);
if (!sep->ind->get_capability(session, sep, get_all, &caps,
&err, sep->user_data))
goto failed;
for (l = caps, rsp_size = 0; l != NULL; l = g_slist_next(l)) {
struct avdtp_service_capability *cap = l->data;
if (rsp_size + cap->length + 2 > sizeof(buf))
break;
memcpy(ptr, cap, cap->length + 2);
rsp_size += cap->length + 2;
ptr += cap->length + 2;
g_free(cap);
}
g_slist_free(caps);
return avdtp_send(session, transaction, AVDTP_MSG_TYPE_ACCEPT, cmd,
buf, rsp_size);
failed:
return avdtp_send(session, transaction, AVDTP_MSG_TYPE_REJECT, cmd,
&err, sizeof(err));
}
在函数avdtp_getcap_cmd中,我们来看代码第27行,sep->ind->get_capability,因为我们现在分析的是sbc编码,其函数定义如下:
static struct avdtp_sep_ind sbc_ind = {
.get_capability = sbc_getcap_ind,
.set_configuration = sbc_setconf_ind,
.get_configuration = getconf_ind,
.open = open_ind,
.start = start_ind,
.suspend = suspend_ind,
.close = close_ind,
.abort = abort_ind,
.reconfigure = reconf_ind,
.delayreport = delayreport_ind,
};
其中,我们看下sbc_getcap_ind的定义:
static gboolean sbc_getcap_ind(struct avdtp *session, struct avdtp_local_sep *sep,
gboolean get_all, GSList **caps, uint8_t *err,
void *user_data)
{
struct a2dp_sep *a2dp_sep = user_data;
struct avdtp_service_capability *media_transport, *media_codec;
struct sbc_codec_cap sbc_cap;
if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)
DBG("Sink %p: Get_Capability_Ind", sep);
else
DBG("Source %p: Get_Capability_Ind", sep);
*caps = NULL;
media_transport = avdtp_service_cap_new(AVDTP_MEDIA_TRANSPORT,
NULL, 0);
*caps = g_slist_append(*caps, media_transport);
memset(&sbc_cap, 0, sizeof(struct sbc_codec_cap));
sbc_cap.cap.media_type = AVDTP_MEDIA_TYPE_AUDIO;
sbc_cap.cap.media_codec_type = A2DP_CODEC_SBC;
sbc_cap.frequency = ( SBC_SAMPLING_FREQ_48000 |
SBC_SAMPLING_FREQ_44100 |
SBC_SAMPLING_FREQ_32000 |
SBC_SAMPLING_FREQ_16000 );
sbc_cap.channel_mode = ( SBC_CHANNEL_MODE_JOINT_STEREO |
SBC_CHANNEL_MODE_STEREO |
SBC_CHANNEL_MODE_DUAL_CHANNEL |
SBC_CHANNEL_MODE_MONO );
sbc_cap.block_length = ( SBC_BLOCK_LENGTH_16 |
SBC_BLOCK_LENGTH_12 |
SBC_BLOCK_LENGTH_8 |
SBC_BLOCK_LENGTH_4 );
sbc_cap.subbands = ( SBC_SUBBANDS_8 | SBC_SUBBANDS_4 );
sbc_cap.allocation_method = ( SBC_ALLOCATION_LOUDNESS |
SBC_ALLOCATION_SNR );
sbc_cap.min_bitpool = MIN_BITPOOL;
sbc_cap.max_bitpool = MAX_BITPOOL;
media_codec = avdtp_service_cap_new(AVDTP_MEDIA_CODEC, &sbc_cap,
sizeof(sbc_cap));
*caps = g_slist_append(*caps, media_codec);
if (get_all) {
struct avdtp_service_capability *delay_reporting;
delay_reporting = avdtp_service_cap_new(AVDTP_DELAY_REPORTING,
NULL, 0);
*caps = g_slist_append(*caps, delay_reporting);
}
return TRUE;
}
我们看到,函数sbc_getcap_ind中打包了几种capabilities,包括AVDTP_MEDIA_TRANSPORT、AVDTP_MEDIA_CODEC和AVDTP_DELAY_REPORTING,其中AVDTP_MEDIA_CODEC包含的信息可以通过下面一个结构体来查看,这些信息代表的是支持的内容;
struct sbc_codec_cap {
struct avdtp_media_codec_capability cap;
uint8_t channel_mode:4;//通道模式,mono stereo
uint8_t frequency:4;//采样率
uint8_t allocation_method:2;
uint8_t subbands:2;//子带宽度
uint8_t block_length:4;//块长度
uint8_t min_bitpool;
uint8_t max_bitpool;
} __attribute__ ((packed));
函数sbc_getcap_ind分析完成后,我们回到函数avdtp_getcap_cmd,在第46行,调用avdtp_send给发送端发送一个GET CAPABILITIES的ACCEPT,当然包含通过sbc_getcap_ind打包好的数据信息,在接收端的session_cb会来处理这个RESPONSE,执行的是case AVDTP_GET_ALL_CAPABILITIES:这一分支,会执行到函数avdtp_get_capabilities_resp,其定义如下:
static gboolean avdtp_get_capabilities_resp(struct avdtp *session,
struct getcap_resp *resp,
unsigned int size)
{
struct avdtp_remote_sep *sep;
uint8_t seid;
/* Check for minimum required packet size includes:
* 1. getcap resp header
* 2. media transport capability (2 bytes)
* 3. media codec capability type + length (2 bytes)
* 4. the actual media codec elements
* */
if (size < (sizeof(struct getcap_resp) + 4 +
sizeof(struct avdtp_media_codec_capability))) {
error("Too short getcap resp packet");
return FALSE;
}
seid = ((struct seid_req *) session->req->data)->acp_seid;
sep = find_remote_sep(session->seps, seid);
DBG("seid %d type %d media %d", sep->seid,
sep->type, sep->media_type);
if (sep->caps) {
g_slist_free_full(sep->caps, g_free);
sep->caps = NULL;
sep->codec = NULL;
sep->delay_reporting = FALSE;
}
sep->caps = caps_to_list(resp->caps, size - sizeof(struct getcap_resp),
&sep->codec, &sep->delay_reporting);
return TRUE;
}
函数avdtp_capabilites_resp中,我们就看第34行的sep->caps = caps_to_list,将我们在接收端打包的capabilities信息放入sep链表中保存,以便以后查询;
在avdtp_parse_resp处理GET_CAPABILITY ACCEPT响应时,会执行函数finalize_discovery,这里会执行到我们前面提到的select_cb,其定义如下:
static void select_cb(struct media_endpoint *endpoint, void *ret, int size,
void *user_data)
{
struct a2dp_setup *setup = user_data;
struct avdtp_service_capability *media_transport, *media_codec;
struct avdtp_media_codec_capability *cap;
if (size < 0) {
DBG("Endpoint replied an invalid configuration");
goto done;
}
media_transport = avdtp_service_cap_new(AVDTP_MEDIA_TRANSPORT,
NULL, 0);
setup->caps = g_slist_append(setup->caps, media_transport);
cap = g_malloc0(sizeof(*cap) + size);
cap->media_type = AVDTP_MEDIA_TYPE_AUDIO;
cap->media_codec_type = setup->sep->codec;
memcpy(cap->data, ret, size);
media_codec = avdtp_service_cap_new(AVDTP_MEDIA_CODEC, cap,
sizeof(*cap) + size);
setup->caps = g_slist_append(setup->caps, media_codec);
g_free(cap);
done:
finalize_select(setup);
}
其中,在finalize_select函数中,会执行cb->select_cb,我们在前面已经见过这个函数,在函数a2dp_select_capabilities中进行的赋值,其定义如下:
static void select_complete(struct avdtp *session, struct a2dp_sep *sep,
GSList *caps, void *user_data)
{
struct sink *sink = user_data;
struct pending_request *pending;
int id;
pending = sink->connect;
pending->id = 0;
id = a2dp_config(session, sep, stream_setup_complete, caps, sink);
if (id == 0)
goto failed;
pending->id = id;
return;
failed:
if (pending->msg)
error_failed(pending->conn, pending->msg, "Stream setup failed");
pending_request_free(sink->dev, pending);
sink->connect = NULL;
avdtp_unref(sink->session);
sink->session = NULL;
}
在上面的定义中看到了函数a2dp_config,这个函数我们后面查看其他AVDTP操作时还是会遇到,这里先分析AVDTP AVDTP_STATE_IDLE的流程,除了一些必要的SEP信息整理外,最重要的就是函数avdtp_set_configuration,其定义如下:
int avdtp_set_configuration(struct avdtp *session,
struct avdtp_remote_sep *rsep,
struct avdtp_local_sep *lsep,
GSList *caps,
struct avdtp_stream **stream)
{
struct setconf_req *req;
struct avdtp_stream *new_stream;
unsigned char *ptr;
int err, caps_len;
struct avdtp_service_capability *cap;
GSList *l;
if (session->state != AVDTP_SESSION_STATE_CONNECTED)
return -ENOTCONN;
if (!(lsep && rsep))
return -EINVAL;
DBG("%p: int_seid=%u, acp_seid=%u", session,
lsep->info.seid, rsep->seid);
new_stream = g_new0(struct avdtp_stream, 1);
new_stream->session = session;
new_stream->lsep = lsep;
new_stream->rseid = rsep->seid;
if (rsep->delay_reporting && lsep->delay_reporting) {
struct avdtp_service_capability *delay_reporting;
delay_reporting = avdtp_service_cap_new(AVDTP_DELAY_REPORTING,
NULL, 0);
caps = g_slist_append(caps, delay_reporting);
new_stream->delay_reporting = TRUE;
}
g_slist_foreach(caps, copy_capabilities, &new_stream->caps);
/* Calculate total size of request */
for (l = caps, caps_len = 0; l != NULL; l = g_slist_next(l)) {
cap = l->data;
caps_len += cap->length + 2;
}
req = g_malloc0(sizeof(struct setconf_req) + caps_len);
req->int_seid = lsep->info.seid;
req->acp_seid = rsep->seid;
/* Copy the capabilities into the request */
for (l = caps, ptr = req->caps; l != NULL; l = g_slist_next(l)) {
cap = l->data;
memcpy(ptr, cap, cap->length + 2);
ptr += cap->length + 2;
}
err = send_request(session, FALSE, new_stream,
AVDTP_SET_CONFIGURATION, req,
sizeof(struct setconf_req) + caps_len);
if (err < 0)
stream_free(new_stream);
else {
lsep->info.inuse = 1;
lsep->stream = new_stream;
rsep->stream = new_stream;
session->streams = g_slist_append(session->streams, new_stream);
if (stream)
*stream = new_stream;
}
g_free(req);
return err;
}
函数avdtp_set_configuration就是打包并发送了一个AVDTP的CONFIURATION的命令,到此为止我们进入第三个阶段,configuration阶段;
三、AVDTP CONFIGURATION
当发送端发送了configuration命令,接收端还是通过session_cb处理,函数avdtp_setconf_cmd来处理,其定义如下:
static gboolean avdtp_setconf_cmd(struct avdtp *session, uint8_t transaction,
struct setconf_req *req, unsigned int size)
{
struct conf_rej rej;
struct avdtp_local_sep *sep;
struct avdtp_stream *stream;
uint8_t err, category = 0x00;
struct audio_device *dev;
bdaddr_t src, dst;
GSList *l;
if (size < sizeof(struct setconf_req)) {
error("Too short getcap request");
return FALSE;
}
sep = find_local_sep_by_seid(session->server, req->acp_seid);//通过server获取SEP
if (!sep) {
err = AVDTP_BAD_ACP_SEID;
goto failed;
}
if (sep->stream) {
err = AVDTP_SEP_IN_USE;
goto failed;
}
avdtp_get_peers(session, &src, &dst);
dev = manager_get_device(&src, &dst, FALSE);//获取设备
if (!dev) {
error("Unable to get a audio device object");
err = AVDTP_BAD_STATE;
goto failed;
}
switch (sep->info.type) {//这里增加UUID属性到全局列表
case AVDTP_SEP_TYPE_SOURCE:
if (!dev->sink) {
btd_device_add_uuid(dev->btd_dev, A2DP_SINK_UUID);
if (!dev->sink) {
error("Unable to get a audio sink object");
err = AVDTP_BAD_STATE;
goto failed;
}
}
break;
case AVDTP_SEP_TYPE_SINK:
if (!dev->source) {
btd_device_add_uuid(dev->btd_dev, A2DP_SOURCE_UUID);
if (!dev->sink) {
error("Unable to get a audio source object");
err = AVDTP_BAD_STATE;
goto failed;
}
}
break;
}
stream = g_new0(struct avdtp_stream, 1);
stream->session = session;
stream->lsep = sep;
stream->rseid = req->int_seid;
stream->caps = caps_to_list(req->caps,
size - sizeof(struct setconf_req),
&stream->codec,
&stream->delay_reporting);
/* Verify that the Media Transport capability's length = 0. Reject otherwise */
for (l = stream->caps; l != NULL; l = g_slist_next(l)) {//这里AVDTP_MEDIA_TRANSPORT属性只能是length=0
struct avdtp_service_capability *cap = l->data;
if (cap->category == AVDTP_MEDIA_TRANSPORT && cap->length != 0) {
err = AVDTP_BAD_MEDIA_TRANSPORT_FORMAT;
goto failed_stream;
}
}
if (stream->delay_reporting && session->version < 0x0103)
session->version = 0x0103;
if (sep->ind && sep->ind->set_configuration) {//我们在创建SEP节点时,已经赋值了sep->ind,所以这里会执行set_configuration函数
if (!sep->ind->set_configuration(session, sep, stream,
stream->caps,
setconf_cb,
sep->user_data)) {
err = AVDTP_UNSUPPORTED_CONFIGURATION;
category = 0x00;
goto failed_stream;
}
} else {
if (!avdtp_send(session, transaction, AVDTP_MSG_TYPE_ACCEPT,
AVDTP_SET_CONFIGURATION, NULL, 0)) {
stream_free(stream);
return FALSE;
}
sep->stream = stream;
sep->info.inuse = 1;
session->streams = g_slist_append(session->streams, stream);
avdtp_sep_set_state(session, sep, AVDTP_STATE_CONFIGURED);
}
return TRUE;
failed_stream:
stream_free(stream);
failed:
rej.error = err;
rej.category = category;
return avdtp_send(session, transaction, AVDTP_MSG_TYPE_REJECT,
AVDTP_SET_CONFIGURATION, &rej, sizeof(rej));
}
对于上面这个函数,我们重点看一下sep->ind->set_configuration的定义,还要注意这里传递了一个回调函数setconf_cb,在这个回调函数中调用了SET_CONFIGURATION的ACCEPT响应,我们先来看sep->ind->set_configuration的定义,因为sbc在蓝牙种应用比较广泛,我们假设在配置文件中配置了sbc音频编码格式,则这里对应的函数为:
static struct avdtp_sep_ind sbc_ind = {
.get_capability = sbc_getcap_ind,
.set_configuration = sbc_setconf_ind,
.get_configuration = getconf_ind,
.open = open_ind,
.start = start_ind,
.suspend = suspend_ind,
.close = close_ind,
.abort = abort_ind,
.reconfigure = reconf_ind,
.delayreport = delayreport_ind,
};
static gboolean sbc_setconf_ind(struct avdtp *session,
struct avdtp_local_sep *sep,
struct avdtp_stream *stream,
GSList *caps,
avdtp_set_configuration_cb cb,
void *user_data)
{
struct a2dp_sep *a2dp_sep = user_data;
struct a2dp_setup *setup;
if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)
DBG("Sink %p: Set_Configuration_Ind", sep);
else
DBG("Source %p: Set_Configuration_Ind", sep);
setup = a2dp_setup_get(session);
if (!setup)
return FALSE;
a2dp_sep->stream = stream;
setup->sep = a2dp_sep;
setup->stream = stream;
setup->setconf_cb = cb;
/* Check valid settings */
for (; caps != NULL; caps = g_slist_next(caps)) {
struct avdtp_service_capability *cap = caps->data;
struct avdtp_media_codec_capability *codec_cap;
struct sbc_codec_cap *sbc_cap;
if (cap->category == AVDTP_DELAY_REPORTING &&
!a2dp_sep->delay_reporting) {
setup->err = g_new(struct avdtp_error, 1);
avdtp_error_init(setup->err, AVDTP_DELAY_REPORTING,
AVDTP_UNSUPPORTED_CONFIGURATION);
goto done;
}
if (cap->category != AVDTP_MEDIA_CODEC)
continue;
if (cap->length < sizeof(struct sbc_codec_cap))
continue;
codec_cap = (void *) cap->data;
if (codec_cap->media_codec_type != A2DP_CODEC_SBC)
continue;
sbc_cap = (void *) codec_cap;
if (sbc_cap->min_bitpool < MIN_BITPOOL ||
sbc_cap->max_bitpool > MAX_BITPOOL) {
setup->err = g_new(struct avdtp_error, 1);
avdtp_error_init(setup->err, AVDTP_MEDIA_CODEC,
AVDTP_UNSUPPORTED_CONFIGURATION);
goto done;
}
}
done:
g_idle_add(auto_config, setup);
return TRUE;
}
对于函数sbc_setconf_ind,其第20-23行进行参数赋值,第26-59行进行参数检查,关于详细信息请参照spec;
我们重点看第62行的g_idle_add(auto_config, setup);函数g_idle_add是指在系统空闲执行auto_config,我们看一下其定义:
static gboolean auto_config(gpointer data)
{
struct a2dp_setup *setup = data;
struct avdtp_error *err = NULL;
/* Check if configuration was aborted */
if (setup->sep->stream == NULL)
return FALSE;
if (setup->err != NULL) {
err = setup->err;
goto done;
}
avdtp_stream_add_cb(setup->session, setup->stream,
stream_state_changed, setup->sep);
if (setup->sep->type == AVDTP_SEP_TYPE_SOURCE)
sink_new_stream(setup->dev, setup->session, setup->stream);
else
source_new_stream(setup->dev, setup->session, setup->stream);
done:
if (setup->setconf_cb)
setup->setconf_cb(setup->session, setup->stream, setup->err);
finalize_config(setup);
if (err)
g_free(err);
setup_unref(setup);
return FALSE;
}
函数auto_config有两点需要说明的,都是关于函数stream_state_changed,因为stream_state_changed在不同文件中有多个定义,它被定义成static类型,也就是作用域只有c文件自身,在auto_config中调用了两处stream_state_changed,但其定义都不同,我们需要分开来看:
1、首先是函数的第15行的stream_state_changed回调函数,它的定义在a2dp.c中,定义如下,我们看到函数非常简单,其中函数media_endpoint_clear_configuration是用来清理配置的,等后面我们用到时再具体说明;
static void stream_state_changed(struct avdtp_stream *stream,
avdtp_state_t old_state,
avdtp_state_t new_state,
struct avdtp_error *err,
void *user_data)
{
struct a2dp_sep *sep = user_data;
if (new_state != AVDTP_STATE_IDLE)
return;
if (sep->suspend_timer) {
g_source_remove(sep->suspend_timer);
sep->suspend_timer = 0;
}
if (sep->session) {
avdtp_unref(sep->session);
sep->session = NULL;
}
sep->stream = NULL;
if (sep->endpoint)
media_endpoint_clear_configuration(sep->endpoint);
}
2、在函数auto_config的第18-21行,我们会用到第二个stream_state_changed,我们暂且来看sink的流程,sink流程会调用函数sink_new_stream,其定义如下,stream_state_changed出现在新增的回调函数中,这个stream_state_changed是定义在sink.c当中,具体定义如下,我们后面分析AVDTP OPEN/START等会看到这个函数,我们后面分析AVDTP OPEN、START时会具体分析;
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;
}
static void stream_state_changed(struct avdtp_stream *stream,
avdtp_state_t old_state,
avdtp_state_t new_state,
struct avdtp_error *err,
void *user_data)
{
struct audio_device *dev = user_data;
struct sink *sink = dev->sink;
gboolean value;
if (err)
return;
switch (new_state) {
case AVDTP_STATE_IDLE:
if (sink->disconnect) {
DBusMessage *reply;
struct pending_request *p;
p = sink->disconnect;
sink->disconnect = NULL;
reply = dbus_message_new_method_return(p->msg);
g_dbus_send_message(p->conn, reply);
pending_request_free(dev, p);
}
if (sink->session) {
avdtp_unref(sink->session);
sink->session = NULL;
}
sink->stream = NULL;
sink->cb_id = 0;
break;
case AVDTP_STATE_OPEN:
if (old_state == AVDTP_STATE_CONFIGURED &&
sink->state == SINK_STATE_CONNECTING) {
value = TRUE;
g_dbus_emit_signal(dev->conn, dev->path,
AUDIO_SINK_INTERFACE,
"Connected",
DBUS_TYPE_INVALID);
emit_property_changed(dev->conn, dev->path,
AUDIO_SINK_INTERFACE,
"Connected",
DBUS_TYPE_BOOLEAN, &value);
} else if (old_state == AVDTP_STATE_STREAMING) {
value = FALSE;
g_dbus_emit_signal(dev->conn, dev->path,
AUDIO_SINK_INTERFACE,
"Stopped",
DBUS_TYPE_INVALID);
emit_property_changed(dev->conn, dev->path,
AUDIO_SINK_INTERFACE,
"Playing",
DBUS_TYPE_BOOLEAN, &value);
}
sink_set_state(dev, SINK_STATE_CONNECTED);
break;
case AVDTP_STATE_STREAMING:
value = TRUE;
g_dbus_emit_signal(dev->conn, dev->path, AUDIO_SINK_INTERFACE,
"Playing", DBUS_TYPE_INVALID);
emit_property_changed(dev->conn, dev->path,
AUDIO_SINK_INTERFACE, "Playing",
DBUS_TYPE_BOOLEAN, &value);
sink_set_state(dev, SINK_STATE_PLAYING);
break;
case AVDTP_STATE_CONFIGURED:
case AVDTP_STATE_CLOSING:
case AVDTP_STATE_ABORTING:
default:
break;
}
sink->stream_state = new_state;
}
好了,到这里我们AVDTP CONFIGURATION的接收端就处理完了,这时我们回到auto_config的第24行和25行,这行是执行一个回调函数,这个回调函数的赋值是在sbc_setconf_ind中的第23行,对应的函数是setconf_cb,这个函数前面已经提到过,忘记的亲们请往前翻到GET CAPABILITY部分再回顾下,其定义如下:
static void setconf_cb(struct avdtp *session, struct avdtp_stream *stream,
struct avdtp_error *err)
{
struct conf_rej rej;
struct avdtp_local_sep *sep;
if (err != NULL) {
rej.error = AVDTP_UNSUPPORTED_CONFIGURATION;
rej.category = err->err.error_code;
avdtp_send(session, session->in.transaction,
AVDTP_MSG_TYPE_REJECT, AVDTP_SET_CONFIGURATION,
&rej, sizeof(rej));
return;
}
if (!avdtp_send(session, session->in.transaction, AVDTP_MSG_TYPE_ACCEPT,
AVDTP_SET_CONFIGURATION, NULL, 0)) {
stream_free(stream);
return;
}
sep = stream->lsep;
sep->stream = stream;
sep->info.inuse = 1;
session->streams = g_slist_append(session->streams, stream);
avdtp_sep_set_state(session, sep, AVDTP_STATE_CONFIGURED);
}
其实函数setconf_cb只做了两件事,1是给发送端发送ACCEPT响应,2是将本地的AVDTP状态设置为AVDTP_STATE_CONFIGURED;下面我们回到AVDTP CONFIGURATION发送端,继续看下当接收端收到ACCEPT后的处理;
我们依然从session_cb函数开始我们的分析,其实亲们从前面的分析可以看出,session_cb是个很重要的函数,可以说是所有AVDTP事件的分发器,从session_cb进入函数avdtp_parse_resp,因为这里是SET_CONFIGURATION的ACCEPT响应,所以会执行函数avdtp_set_configuration_resp,其定义如下:
static gboolean avdtp_set_configuration_resp(struct avdtp *session,
struct avdtp_stream *stream,
struct avdtp_single_header *resp,
int size)
{
struct avdtp_local_sep *sep = stream->lsep;
if (sep->cfm && sep->cfm->set_configuration)
sep->cfm->set_configuration(session, sep, stream, NULL,
sep->user_data);
avdtp_sep_set_state(session, sep, AVDTP_STATE_CONFIGURED);
return TRUE;
}
我们可以看到,函数avdtp_set_configuration_resp也做了两件事,1是执行sep->cfm->set_configuration,这里需要注意,这个函数和刚才在接收端碰到的函数相对应,其定义不同,一个是在ind命令时执行,一个是在响应应答时执行;2是将设备状态更改为AVDTP_STATE_CONFIGURATION;
static struct avdtp_sep_cfm cfm = {
.set_configuration = setconf_cfm,
.get_configuration = getconf_cfm,
.open = open_cfm,
.start = start_cfm,
.suspend = suspend_cfm,
.close = close_cfm,
.abort = abort_cfm,
.reconfigure = reconf_cfm,
.delay_report = delay_report_cfm,
};
static void setconf_cfm(struct avdtp *session, struct avdtp_local_sep *sep,
struct avdtp_stream *stream,
struct avdtp_error *err, void *user_data)
{
struct a2dp_sep *a2dp_sep = user_data;
struct a2dp_setup *setup;
struct audio_device *dev;
int ret;
if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)
DBG("Sink %p: Set_Configuration_Cfm", sep);
else
DBG("Source %p: Set_Configuration_Cfm", sep);
setup = find_setup_by_session(session);
if (err) {
if (setup) {
setup->err = err;
finalize_config(setup);
}
return;
}
avdtp_stream_add_cb(session, stream, stream_state_changed, a2dp_sep);
a2dp_sep->stream = stream;
if (!setup)
return;
dev = a2dp_get_dev(session);
/* Notify D-Bus interface of the new stream */
if (a2dp_sep->type == AVDTP_SEP_TYPE_SOURCE)
sink_new_stream(dev, session, setup->stream);
else
source_new_stream(dev, session, setup->stream);
/* Notify Endpoint */
if (a2dp_sep->endpoint) {
struct avdtp_service_capability *service;
struct avdtp_media_codec_capability *codec;
service = avdtp_stream_get_codec(stream);
codec = (struct avdtp_media_codec_capability *) service->data;
if (media_endpoint_set_configuration(a2dp_sep->endpoint, dev,
codec->data, service->length -
sizeof(*codec),
endpoint_open_cb, setup) ==
TRUE)
return;
setup->stream = NULL;
finalize_setup_errno(setup, -EPERM, finalize_config, NULL);
return;
}
ret = avdtp_open(session, stream);
if (ret < 0) {
error("Error on avdtp_open %s (%d)", strerror(-ret), -ret);
setup->stream = NULL;
finalize_setup_errno(setup, ret, finalize_config, NULL);
}
}
函数setconf_cfm我们分三个部分来说明:
1、函数的第25行,可以看到这里又出现了函数stream_state_changed,前面在解析AVDTP SET CONFIGURATE的接收端时分析过,那时有两处调用,虽然函数名相同,但定义在不同的c文件中,这里的stream_state_changed也不同于前面看到的两个,前面看到的是a2dp.c和sink.c中,那这里对应的就应该是source.c中的定义,如下,可以看到source.c中的stream_state_changed定义比sink.c中的定义简单的多,同样的,我们后面看AVDTP OPEN/START命令时再来解析这里;
static void stream_state_changed(struct avdtp_stream *stream,
avdtp_state_t old_state,
avdtp_state_t new_state,
struct avdtp_error *err,
void *user_data)
{
struct audio_device *dev = user_data;
struct source *source = dev->source;
if (err)
return;
switch (new_state) {
case AVDTP_STATE_IDLE:
if (source->disconnect) {
DBusMessage *reply;
struct pending_request *p;
p = source->disconnect;
source->disconnect = NULL;
reply = dbus_message_new_method_return(p->msg);
g_dbus_send_message(p->conn, reply);
pending_request_free(dev, p);
}
if (source->session) {
avdtp_unref(source->session);
source->session = NULL;
}
source->stream = NULL;
source->cb_id = 0;
break;
case AVDTP_STATE_OPEN:
source_set_state(dev, SOURCE_STATE_CONNECTED);
break;
case AVDTP_STATE_STREAMING:
source_set_state(dev, SOURCE_STATE_PLAYING);
break;
case AVDTP_STATE_CONFIGURED:
case AVDTP_STATE_CLOSING:
case AVDTP_STATE_ABORTING:
default:
break;
}
source->stream_state = new_state;
}
2、回过头继续分析函数setconf_cmf第二部分是第40行到57行,这部分是将已经协议好的configuration传递到endpoint,和前面在sink端看到的是相同的操作,这里也不过多说明;
3、函数setconf_cmf的第59行发送了AVDTP OPEN命令,最终同样调用send_request来发送;
四、AVDTP OPEN流程
我们终于要进入open流程,在上面的分析中,已经将AVDTP OPEN命令发送出去,我们来看接收端的处理,同样需要从session_cb函数开始,这里同样进入函数avdtp_parse_resp,会执行函数avdtp_open_resp,其定义如下:
static gboolean avdtp_open_cmd(struct avdtp *session, uint8_t transaction,
struct seid_req *req, unsigned int size)
{
struct avdtp_local_sep *sep;
struct avdtp_stream *stream;
uint8_t err;
if (size < sizeof(struct seid_req)) {
error("Too short abort request");
return FALSE;
}
sep = find_local_sep_by_seid(session->server, req->acp_seid);
if (!sep) {
err = AVDTP_BAD_ACP_SEID;
goto failed;
}
if (sep->state != AVDTP_STATE_CONFIGURED) {
err = AVDTP_BAD_STATE;
goto failed;
}
stream = sep->stream;
if (sep->ind && sep->ind->open) {
if (!sep->ind->open(session, sep, stream, &err,
sep->user_data))
goto failed;
}
if (!avdtp_send(session, transaction, AVDTP_MSG_TYPE_ACCEPT,
AVDTP_OPEN, NULL, 0))
return FALSE;
stream->open_acp = TRUE;
session->pending_open = stream;
stream->timer = g_timeout_add_seconds(REQ_TIMEOUT,
stream_open_timeout,
stream);
return TRUE;
failed:
return avdtp_send(session, transaction, AVDTP_MSG_TYPE_REJECT,
AVDTP_OPEN, &err, sizeof(err));
}
我们来分析函数avdtp_open_cmd,这个函数很简单,第13行-22行,是获取之前创建的SEP,我们所有的语音流都是基于SEP的,第26行执行了ind->open函数,第32行发送了AVDTP OPEN 命令的ACCEPT,第36-40行需要注意session->pending_open被赋了值,我们后面会看到对这个变量的判断,另外还增加了一个定时器,在打开超时时通过函数stream_open_timeout做相应处理;
下面我们来看下ind->open函数,其定义如下(这里依旧分析sbc格式的定义),open中并没有做实质操作:
static struct avdtp_sep_ind sbc_ind = {
.get_capability = sbc_getcap_ind,
.set_configuration = sbc_setconf_ind,
.get_configuration = getconf_ind,
.open = open_ind,
.start = start_ind,
.suspend = suspend_ind,
.close = close_ind,
.abort = abort_ind,
.reconfigure = reconf_ind,
.delayreport = delayreport_ind,
};
static gboolean open_ind(struct avdtp *session, struct avdtp_local_sep *sep,
struct avdtp_stream *stream, uint8_t *err,
void *user_data)
{
struct a2dp_sep *a2dp_sep = user_data;
if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)
DBG("Sink %p: Open_Ind", sep);
else
DBG("Source %p: Open_Ind", sep);
return TRUE;
}
我们首先分析函数handle_transport_connect,其定义如下,在蓝牙协议中还有所谓的传输层,用于屏蔽底层硬件相关的内容,函数handle_transport_connect主要做了两件事,1是设置buffer size,并执行AVDTP 的open流程,2是增加一个回调函数transport_cb,当有异常情况时,会执行close流程,其他说明见下注释;
static void handle_transport_connect(struct avdtp *session, GIOChannel *io,
uint16_t imtu, uint16_t omtu)
{
struct avdtp_stream *stream = session->pending_open;
struct avdtp_local_sep *sep = stream->lsep;
int sk, buf_size, min_buf_size;
GError *err = NULL;
session->pending_open = NULL;//already open
if (stream->timer) {
g_source_remove(stream->timer);
stream->timer = 0;
}
if (io == NULL) {//异常处理,如果通道为NULL,执行open后返回
if (!stream->open_acp && sep->cfm && sep->cfm->open) {
struct avdtp_error err;
avdtp_error_init(&err, AVDTP_ERRNO, EIO);
sep->cfm->open(session, sep, NULL, &err,
sep->user_data);
}
return;
}
if (stream->io == NULL)
stream->io = g_io_channel_ref(io);
stream->omtu = omtu;//output MTU
stream->imtu = imtu;//input MTU
/* Apply special settings only if local SEP is of type SRC */
if (sep->info.type != AVDTP_SEP_TYPE_SOURCE)//我们这里分析的是sink,所以可以直接掉到proceed分析;
goto proceed;
bt_io_set(stream->io, BT_IO_L2CAP, &err,
BT_IO_OPT_FLUSHABLE, TRUE,
BT_IO_OPT_INVALID);
if (err != NULL) {
error("Enabling flushable packets failed: %s", err->message);
g_error_free(err);
} else
DBG("Flushable packets enabled");
sk = g_io_channel_unix_get_fd(stream->io);
buf_size = get_send_buffer_size(sk);
if (buf_size < 0)
goto proceed;
DBG("sk %d, omtu %d, send buffer size %d", sk, omtu, buf_size);
min_buf_size = omtu * 2;
if (buf_size < min_buf_size) {
DBG("send buffer size to be increassed to %d",
min_buf_size);
set_send_buffer_size(sk, min_buf_size);
}
proceed:
if (!stream->open_acp && sep->cfm && sep->cfm->open)
sep->cfm->open(session, sep, stream, NULL, sep->user_data);//执行AVDTP的open流程
avdtp_sep_set_state(session, sep, AVDTP_STATE_OPEN);//设置状态未open
stream->io_id = g_io_add_watch(io, G_IO_ERR | G_IO_HUP | G_IO_NVAL,
(GIOFunc) transport_cb, stream);//增加一个回调,用于处理异常
}
这里看一下AVDTP的open流程,函数handle_transport_connect的第60行,实际执行的是struct avdtp_sep_cfm cfm的open_cfm,其定义如下:
static void open_cfm(struct avdtp *session, struct avdtp_local_sep *sep,
struct avdtp_stream *stream, struct avdtp_error *err,
void *user_data)
{
struct a2dp_sep *a2dp_sep = user_data;
struct a2dp_setup *setup;
if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)
DBG("Sink %p: Open_Cfm", sep);
else
DBG("Source %p: Open_Cfm", sep);
setup = find_setup_by_session(session);//这个setup是在configure流程创建的一个实例,我们待会分析
if (!setup)
return;
if (setup->reconfigure)
setup->reconfigure = FALSE;
if (err) {
setup->stream = NULL;
setup->err = err;
}
finalize_config(setup);//setup中存储着AVDTP协商后的配置
}
我们来看函数finalize_config的定义,其第15行的cb->config_cb调用了前面的setup内容,那么我们需要回过头去看一下configure流程;
static gboolean finalize_config(gpointer data)
{
struct a2dp_setup *s = data;
GSList *l;
struct avdtp_stream *stream = s->err ? NULL : s->stream;
for (l = s->cb; l != NULL; ) {
struct a2dp_setup_cb *cb = l->data;
l = l->next;
if (!cb->config_cb)
continue;
cb->config_cb(s->session, s->sep, stream, s->err,
cb->user_data);
setup_cb_free(cb);
}
return FALSE;
}