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