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;
}