#include "rtp-over-rtsp.h"
#include "rtp-header.h"
#include <stdlib.h>
#include <string.h>
#include <assert.h>

#define VMIN(x, y) ((x) < (y) ? (x) : (y))

enum rtp_over_tcp_state_t
{
	rtp_start = 0,
	rtp_channel,
	rtp_length_1,
	rtp_length_2,
	rtp_data,
};

static int rtp_alloc(struct rtp_over_rtsp_t *rtp)
{
	void* p;
	if (rtp->capacity < rtp->length)
	{
		p = realloc(rtp->data, rtp->length);
		if (!p)
			return -1;
		rtp->data = (uint8_t*)p;
		rtp->capacity = rtp->length;
	}
	return 0;
}

#if defined(RTP_OVER_RTSP_TRY_TO_FIND_NEXT_PACKET)
// skip missing data, find next start
static const uint8_t* rtp_over_rtsp_try_to_find_next_packet(struct rtp_over_rtsp_t* rtp, const uint8_t* data, const uint8_t* end)
{
	const uint8_t* p;
	p = (const uint8_t*)memchr(data, '$', end - data);
	if (!p)
		return end; // not found

	rtp->check = 1;
	return p;
}
#endif

// 10.12 Embedded (Interleaved) Binary Data
// Stream data such as RTP packets is encapsulated by an ASCII dollar sign(24 hexadecimal), 
// followed by a one-byte channel identifier,
// followed by the length of the encapsulated binary data as a binary two-byte integer in network byte order.
const uint8_t* rtp_over_rtsp(struct rtp_over_rtsp_t *rtp, const uint8_t* data, const uint8_t* end)
{
	int n;

	for (n = 0; data < end; data++)
	{
		switch (rtp->state)
		{
		case rtp_start:
			if (*data != '$') {
#if defined(RTP_OVER_RTSP_TRY_TO_FIND_NEXT_PACKET)
				return rtp_over_rtsp_try_to_find_next_packet(rtp, data, end);
#else
				return end;
#endif
			}
			rtp->bytes = 0;
			rtp->state = rtp_channel;
			break;

		case rtp_channel:
			// The channel identifier is defined in the Transport header with 
			// the interleaved parameter(Section 12.39).
			rtp->channel = *data;
			rtp->state = rtp_length_1;
			break;

		case rtp_length_1:
			rtp->length = *data << 8;
			rtp->state = rtp_length_2;
			break;

		case rtp_length_2:
			rtp->length |= *data;
			rtp->state = rtp_data;
			break;

		case rtp_data:
			if (0 == rtp->bytes && 0 != rtp_alloc(rtp))
				return end;
			n = (int)(end - data);
			n = VMIN(rtp->length - rtp->bytes, n);
			memcpy(rtp->data + rtp->bytes, data, n);
			rtp->bytes += (uint16_t)n;

#if defined(RTP_OVER_RTSP_TRY_TO_FIND_NEXT_PACKET)
			if (rtp->bytes >= 12)
			{
				uint32_t ssrc;
				ssrc = *(uint32_t*)(rtp->data + 8);

				if (rtp->check)
				{
					if (rtp->channel >= sizeof(rtp->ssrc) / sizeof(rtp->ssrc[0])
						|| ssrc != rtp->ssrc[rtp->channel]
						|| RTP_VERSION != (*rtp->data >> 6))
					{
						rtp->state = rtp_start;
						return rtp_over_rtsp_try_to_find_next_packet(rtp, data, end);
					}

					rtp->check = 0;
				}
				else if(rtp->channel < sizeof(rtp->ssrc) / sizeof(rtp->ssrc[0]) && 0 == rtp->ssrc[rtp->channel])
				{
					assert(RTP_VERSION == (*rtp->data >> 6));
					//assert(0 == rtp->ssrc[rtp->channel] || ssrc == rtp->ssrc[rtp->channel]);
					rtp->ssrc[rtp->channel] = ssrc;
				}
			}
#endif

			data += n;

			if (rtp->bytes == rtp->length)
			{
				rtp->state = rtp_start;
				if(rtp->onrtp)
					rtp->onrtp(rtp->param, rtp->channel, rtp->data, rtp->length);
				return data;
			}
			break;

		default:
			assert(0);
			return end;
		}
	}

	return data;
}
