static gboolean audio_receive_data_msg()

in chime/chime-call-audio.c [404:478]


static gboolean audio_receive_data_msg(ChimeCallAudio *audio, gconstpointer pkt, gsize len)
{
	gboolean ret = FALSE;
	DataMessage *msg = data_message__unpack(NULL, len, pkt);
	if (!msg)
		return FALSE;

	chime_debug("Got DataMessage seq %d msg_id %d offset %d\n", msg->seq, msg->msg_id, msg->offset);
	if (!msg->has_seq || !msg->has_msg_id || !msg->has_msg_len)
		goto fail;

	/* First process ACKs */

	/* If 'pending' then packat 'data_next_seq - 1' also needs to be acked. */
	gboolean pending = !!audio->data_ack_source;

	if (pending || audio->data_ack_mask) {
		while (msg->seq > audio->data_next_seq) {
			if (audio->data_ack_mask & 0x8000000000000000ULL) {
				do_send_ack(audio);
				pending = FALSE;
				break;
			}
			audio->data_next_seq++;
			audio->data_ack_mask <<= 1;

			/* Iff there was already an ack pending, set that bit in the mask */
			if (pending) {
				audio->data_ack_mask |= 1;
				pending = FALSE;
			}
		}
	}
	audio->data_next_seq = msg->seq + 1;
	audio->data_ack_mask <<= 1;
	if (pending)
		audio->data_ack_mask |= 1;
	if (!audio->data_ack_source)
		audio->data_ack_source = g_idle_add(idle_send_ack, audio);

	/* Now process the incoming data packet. First, drop packets
	   that look like replays and are too old. */
	if (msg->msg_id < audio->data_next_logical_msg)
		goto drop;

	struct message_buf *m = find_msgbuf(audio, msg->msg_id, msg->msg_len);
	if (msg->msg_len != m->len ||
	    msg->offset + msg->data.len > m->len)
		goto fail;

	memcpy(m->buf + msg->offset, msg->data.data, msg->data.len);
	if (insert_frag(m, msg->offset, msg->offset + msg->data.len)) {
		struct xrp_header *hdr = (void *)m->buf;
		if (m->len > sizeof(*hdr) && ntohs(hdr->len) == m->len &&
		    ntohs(hdr->type) == XRP_STREAM_MESSAGE) {
			audio_receive_stream_msg(audio, m->buf + sizeof(*hdr), m->len - sizeof(*hdr));
			audio->data_next_logical_msg = m->msg_id + 1;
		}
		/* Now kill *all* pending messagse up to and including this one */
		while (audio->data_messages) {
			struct message_buf *m = audio->data_messages->data;

			if (m->msg_id >= audio->data_next_logical_msg)
				break;

			audio->data_messages = g_slist_remove(audio->data_messages, m);
			free_msgbuf(m);
		}
	}
 drop:
	ret = TRUE;
 fail:
	data_message__free_unpacked(msg, NULL);
	return ret;
}