177 lines
4.4 KiB
C++
177 lines
4.4 KiB
C++
#include "rtsp-server-aio.h"
|
|
#include "aio-transport.h"
|
|
#include "rtp-over-rtsp.h"
|
|
#include "sys/sock.h"
|
|
#include "sys/atomic.h"
|
|
#include "sys/system.h"
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <assert.h>
|
|
#include <errno.h>
|
|
|
|
#define TIMEOUT_RECV 65000
|
|
#define TIMEOUT_SEND 10000
|
|
|
|
struct rtsp_session_t
|
|
{
|
|
socket_t socket;
|
|
aio_transport_t* aio;
|
|
struct rtp_over_rtsp_t rtp;
|
|
int rtsp_need_more_data;
|
|
uint8_t buffer[4 * 1024];
|
|
|
|
struct rtsp_server_t *rtsp;
|
|
struct sockaddr_storage addr;
|
|
socklen_t addrlen;
|
|
|
|
void (*onerror)(void* param, rtsp_server_t* rtsp, int code);
|
|
void (*onrtp)(void* param, uint8_t channel, const void* data, uint16_t bytes);
|
|
void* param;
|
|
};
|
|
|
|
static void rtsp_session_ondestroy(void* param)
|
|
{
|
|
struct rtsp_session_t *session;
|
|
session = (struct rtsp_session_t *)param;
|
|
|
|
// user call rtsp_server_destroy
|
|
if (session->rtsp)
|
|
{
|
|
rtsp_server_destroy(session->rtsp);
|
|
session->rtsp = NULL;
|
|
}
|
|
|
|
if (session->rtp.data)
|
|
{
|
|
assert(session->rtp.capacity > 0);
|
|
free(session->rtp.data);
|
|
session->rtp.data = NULL;
|
|
session->rtp.capacity = 0;
|
|
}
|
|
|
|
#if defined(_DEBUG) || defined(DEBUG)
|
|
memset(session, 0xCC, sizeof(*session));
|
|
#endif
|
|
free(session);
|
|
}
|
|
|
|
static void rtsp_session_onrecv(void* param, int code, size_t bytes)
|
|
{
|
|
size_t remain;
|
|
const uint8_t* p, *end;
|
|
struct rtsp_session_t *session;
|
|
session = (struct rtsp_session_t *)param;
|
|
|
|
if (0 == code && 0 == bytes)
|
|
code = ECONNRESET;
|
|
|
|
if (0 == code)
|
|
{
|
|
p = session->buffer;
|
|
end = session->buffer + bytes;
|
|
do
|
|
{
|
|
if (0 == session->rtsp_need_more_data && ('$' == *p || 0 != session->rtp.state))
|
|
{
|
|
p = rtp_over_rtsp(&session->rtp, p, end);
|
|
}
|
|
else
|
|
{
|
|
remain = end - p;
|
|
code = rtsp_server_input(session->rtsp, p, &remain);
|
|
session->rtsp_need_more_data = code;
|
|
if (0 == code)
|
|
{
|
|
// TODO: pipeline remain data
|
|
assert(bytes > remain);
|
|
assert(0 == remain || '$' == *(end - remain));
|
|
}
|
|
p = end - remain;
|
|
}
|
|
} while (p < end && 0 == code);
|
|
|
|
if (code >= 0)
|
|
{
|
|
// need more data
|
|
code = aio_transport_recv(session->aio, session->buffer, sizeof(session->buffer));
|
|
}
|
|
}
|
|
|
|
// error or peer closed
|
|
if (0 != code || 0 == bytes)
|
|
{
|
|
session->onerror(session->param, session->rtsp, code ? code : ECONNRESET);
|
|
aio_transport_destroy(session->aio);
|
|
}
|
|
}
|
|
|
|
static void rtsp_session_onsend(void* param, int code, size_t bytes)
|
|
{
|
|
struct rtsp_session_t *session;
|
|
session = (struct rtsp_session_t *)param;
|
|
// session->server->onsend(session, code, bytes);
|
|
if (0 != code)
|
|
{
|
|
session->onerror(session->param, session->rtsp, code);
|
|
aio_transport_destroy(session->aio);
|
|
}
|
|
(void)bytes;
|
|
}
|
|
|
|
static int rtsp_session_send(void* ptr, const void* data, size_t bytes)
|
|
{
|
|
struct rtsp_session_t *session;
|
|
session = (struct rtsp_session_t *)ptr;
|
|
//return aio_tcp_transport_send(session->aio, data, bytes);
|
|
|
|
// TODO: send multiple rtp packet once time
|
|
return bytes == socket_send(session->socket, data, bytes, 0) ? 0 : -1;
|
|
}
|
|
|
|
int rtsp_transport_tcp_create(socket_t socket, const struct sockaddr* addr, socklen_t addrlen, struct aio_rtsp_handler_t* handler, void* param)
|
|
{
|
|
char ip[65];
|
|
unsigned short port;
|
|
struct rtsp_session_t *session;
|
|
struct rtsp_handler_t rtsphandler;
|
|
struct aio_transport_handler_t h;
|
|
|
|
memset(&h, 0, sizeof(h));
|
|
h.ondestroy = rtsp_session_ondestroy;
|
|
h.onrecv = rtsp_session_onrecv;
|
|
h.onsend = rtsp_session_onsend;
|
|
|
|
memcpy(&rtsphandler, &handler->base, sizeof(rtsphandler));
|
|
rtsphandler.send = rtsp_session_send;
|
|
|
|
session = (struct rtsp_session_t*)calloc(1, sizeof(*session));
|
|
if (!session) return -ENOMEM;
|
|
|
|
session->socket = socket;
|
|
socket_addr_to(addr, addrlen, ip, &port);
|
|
assert(addrlen <= sizeof(session->addr));
|
|
session->addrlen = addrlen < sizeof(session->addr) ? addrlen : sizeof(session->addr);
|
|
memcpy(&session->addr, addr, session->addrlen); // save client ip/port
|
|
|
|
session->param = param;
|
|
session->onerror = handler->onerror;
|
|
session->aio = aio_transport_create(socket, &h, session);
|
|
session->rtsp = rtsp_server_create(ip, port, &rtsphandler, param, session); // reuse-able, don't need create in every link
|
|
if (!session->rtsp || !session->aio)
|
|
{
|
|
rtsp_session_ondestroy(session);
|
|
return -ENOMEM;
|
|
}
|
|
|
|
session->rtp.param = param;
|
|
session->rtp.onrtp = handler->onrtp;
|
|
aio_transport_set_timeout(session->aio, TIMEOUT_RECV, TIMEOUT_SEND);
|
|
if (0 != aio_transport_recv(session->aio, session->buffer, sizeof(session->buffer)))
|
|
{
|
|
rtsp_session_ondestroy(session);
|
|
return -ENOTCONN;
|
|
}
|
|
|
|
return 0;
|
|
}
|