// RFC3550 6.4.1 SR: Sender Report RTCP Packet

#include "rtp-internal.h"
#include "rtp-util.h"

void rtcp_sr_unpack(struct rtp_context *ctx, const rtcp_header_t *header, const uint8_t* ptr, size_t bytes)
{
	uint32_t i;
	rtcp_sr_t *sr;
	rtcp_rb_t *rb;
	struct rtcp_msg_t msg;
	struct rtp_member *sender;

	assert(24 == sizeof(rtcp_sr_t));
	assert(24 == sizeof(rtcp_rb_t));
	if (bytes < 24/*sizeof(rtcp_sr_t)*/ + header->rc * 24/*sizeof(rtcp_rb_t)*/)
	{
		assert(0);
		return;
	}
	msg.ssrc = nbo_r32(ptr);
	msg.type = RTCP_RR;

	sender = rtp_sender_fetch(ctx, msg.ssrc);
	if(!sender) return; // error

	assert(sender != ctx->self);
	assert(sender->rtcp_sr.ssrc == msg.ssrc);
	//assert(sender->rtcp_rb.ssrc == msg.ssrc);
	sender->rtcp_clock = rtpclock();

	// update sender information
	sr = &sender->rtcp_sr;
	sr->ntpmsw = nbo_r32(ptr + 4);
	sr->ntplsw = nbo_r32(ptr + 8);
	sr->rtpts = nbo_r32(ptr + 12);
	sr->spc = nbo_r32(ptr + 16);
	sr->soc = nbo_r32(ptr + 20);

	ptr += 24;
	// report block
	for(i = 0; i < header->rc; i++, ptr+=24/*sizeof(rtcp_rb_t)*/) 
	{
		msg.u.sr.ssrc = nbo_r32(ptr);
		//if(msg.u.rr.ssrc != ctx->self->ssrc)
		//	continue; // ignore
		//rb = &sender->rtcp_rb;

		rb = &msg.u.sr;
		rb->fraction = ptr[4];
		rb->cumulative = (((uint32_t)ptr[5])<<16) | (((uint32_t)ptr[6])<<8)| ptr[7];
		rb->exthsn = nbo_r32(ptr+8);
		rb->jitter = nbo_r32(ptr+12);
		rb->lsr = nbo_r32(ptr+16);
		rb->dlsr = nbo_r32(ptr+20);

		ctx->handler.on_rtcp(ctx->cbparam, &msg);
	}
}

int rtcp_sr_pack(struct rtp_context *ctx, uint8_t* ptr, int bytes)
{
	uint32_t i, timestamp;
	uint64_t ntp;
	rtcp_header_t header;

	assert(24 == sizeof(rtcp_sr_t));
	assert(24 == sizeof(rtcp_rb_t));
	assert(rtp_member_list_count(ctx->senders) < 32);
	header.v = 2;
	header.p = 0;
	header.pt = RTCP_SR;
	header.rc = MIN(31, rtp_member_list_count(ctx->senders));
	header.length = (24/*sizeof(rtcp_sr_t)*/ + header.rc*24/*sizeof(rtcp_rb_t)*/)/4; // see 6.4.1 SR: Sender Report RTCP Packet

	if((uint32_t)bytes < (header.length+1) * 4)
		return (header.length+1) * 4;

	nbo_write_rtcp_header(ptr, &header);

	// RFC3550 6.4.1 SR: Sender Report RTCP Packet (p32)
	// Note that in most cases this timestamp will not be equal to the RTP
	// timestamp in any adjacent data packet. Rather, it must be calculated from the corresponding
	// NTP timestamp using the relationship between the RTP timestamp counter and real time as
	// maintained by periodically checking the wallclock time at a sampling instant.
	ntp = rtpclock();
	if (0 == ctx->self->rtp_packets)
		ctx->self->rtp_clock = ntp;
	timestamp = (uint32_t)((ntp - ctx->self->rtp_clock) * ctx->frequence / 1000000) + ctx->self->rtp_timestamp;

	ntp = clock2ntp(ntp);
	nbo_w32(ptr+4, ctx->self->ssrc);
	nbo_w32(ptr+8, (uint32_t)(ntp >> 32));
	nbo_w32(ptr+12, (uint32_t)(ntp & 0xFFFFFFFF));
	nbo_w32(ptr+16, timestamp);
	nbo_w32(ptr+20, ctx->self->rtp_packets); // send packets
	nbo_w32(ptr+24, (uint32_t)ctx->self->rtp_bytes); // send bytes

	ptr += 28;
	// report block
	for(i = 0; i < header.rc; i++)
	{
		struct rtp_member *sender;

		sender = rtp_member_list_get(ctx->senders, i);
		if(0 == sender->rtp_packets || sender->ssrc == ctx->self->ssrc)
			continue; // don't receive any packet

		ptr += rtcp_report_block(sender, ptr, 24);
	}

	return (header.length+1) * 4;
}

int rtcp_report_block(struct rtp_member* sender, uint8_t* ptr, int bytes)
{
	uint64_t delay;
	int lost_interval;
	int lost;
	uint32_t fraction;
	uint32_t expected, extseq;
	uint32_t expected_interval;
	uint32_t received_interval;
	uint32_t lsr, dlsr;

	if (bytes < 24)
		return 0;

	extseq = sender->rtp_seq_cycles + sender->rtp_seq; // 32-bits sequence number
	assert(extseq >= sender->rtp_seq_base);
	expected = extseq - sender->rtp_seq_base + 1;
	expected_interval = expected - sender->rtp_expected0;
	received_interval = sender->rtp_packets - sender->rtp_packets0;
	lost_interval = (int)(expected_interval - received_interval);
	if (lost_interval < 0 || 0 == expected_interval)
		fraction = 0;
	else
		fraction = (lost_interval << 8) / expected_interval;

	lost = expected - sender->rtp_packets;
	if (lost > 0x007FFFFF)
	{
		lost = 0x007FFFFF;
	}
	else if (lost < 0)
	{
		// 'Clamp' this loss number to a 24-bit signed value:
		// live555 RTCP.cpp RTCPInstance::enqueueReportBlock line:799
		lost = 0;
	}

	delay = rtpclock() - sender->rtcp_clock; // now - Last SR time
	lsr = ((sender->rtcp_sr.ntpmsw & 0xFFFF) << 16) | ((sender->rtcp_sr.ntplsw >> 16) & 0xFFFF);
	// in units of 1/65536 seconds
	// 65536/1000000 == 1024/15625
	dlsr = (uint32_t)(delay / 1000000.0f * 65536);

	nbo_w32(ptr, sender->ssrc);
	ptr[4] = (unsigned char)fraction;
	ptr[5] = (unsigned char)((lost >> 16) & 0xFF);
	ptr[6] = (unsigned char)((lost >> 8) & 0xFF);
	ptr[7] = (unsigned char)(lost & 0xFF);
	nbo_w32(ptr + 8, extseq);
	nbo_w32(ptr + 12, (uint32_t)sender->jitter);
	nbo_w32(ptr + 16, lsr);
	nbo_w32(ptr + 20, 0 == lsr ? 0 : dlsr);

	sender->rtp_expected0 = expected; // update source prior data
	sender->rtp_packets0 = sender->rtp_packets;

	return 24; /*sizeof(rtcp_rb_t)*/
}
