【蓝牙专题】bluez代码分析——a2dp流程二


        前面我们已经分析完了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;
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值