GK SDK 源码库: XMIPCLinuxV100R005C00SPC030 (kernel/tools/open_source excluded)

This commit is contained in:
lai
2026-09-06 03:52:57 +08:00
commit b1928b41c0
21813 changed files with 4413081 additions and 0 deletions
+335
View File
@@ -0,0 +1,335 @@
/*
* Copyright (c) XCAM. All rights reserved.
*/
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <arpa/inet.h>
#include <time.h>
#include <stdlib.h>
#include "livestream_comm.h"
#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif
#endif
#ifndef UNUSED
#define UNUSED(x) (void)x
#endif
#define IP_MAX_LEN (16)
static xcam_u8 g_basis64_string[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
static xcam_u8 g_basis64_index[128] = {
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 62, 0xff, 0xff, 0xff, 63,
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 0xff, 0xff, 0xff, 0xff, 0xff
};
#define CHAR64(c) (((c) > 127) ? 0xff : g_basis64_index[(c)]) /* define CHAR64(c) */
xcam_s32 livestream_comm_format_date(xcam_char* date_buf, xcam_s32 buf_size)
{
if (XCAM_NULL == date_buf) {
LOG_LIVESTREAM_ERROR("Null pointer [date_buf]!\n");
return XCAM_FAILURE;
}
if (buf_size <= 0) {
LOG_LIVESTREAM_ERROR("Param buf_size(%d) is invalid!\n", buf_size);
return XCAM_FAILURE;
}
xcam_char buffer[MAX_DATE_LEN] = {0};
struct tm* ptime = XCAM_NULL;
time_t tt;
tt = time(XCAM_NULL);
ptime = gmtime(&tt);
if (XCAM_NULL == ptime) {
LOG_LIVESTREAM_ERROR("gmtime fail!\n");
return XCAM_FAILURE;
}
memset(buffer, '\0', sizeof(buffer));
if (strftime(buffer, sizeof(buffer), "Date: %a, %b %d %Y %H:%M:%S GMT\r\n", ptime) > 0) {
strncpy(date_buf, buffer, buf_size);
return XCAM_SUCCESS;
}
return XCAM_FAILURE;
}
xcam_void livestream_comm_random_num(xcam_u32* buf_ssrc)
{
FILE* fp_file = fopen("/dev/urandom", "r");
if (XCAM_NULL == fp_file) {
LOG_LIVESTREAM_ERROR("Open /dev/urandom failed and errno is %d!\n", errno);
return;
}
if (1 != fread(buf_ssrc, sizeof(xcam_u32), 1, fp_file)) {
LOG_LIVESTREAM_ERROR("Read /dev/urandom failed and errno is %d!\n", errno);
}
fclose(fp_file);
return;
}
xcam_void livestream_comm_random_id(xcam_char* buf_ssrc, xcam_s32 length)
{
xcam_u32* tmpid;
xcam_s32 i;
FILE* file;
file = fopen("/dev/urandom", "r");
if (XCAM_NULL == file) {
LOG_LIVESTREAM_ERROR("Open /dev/urandom failed and errno is %d!\n", errno);
return;
}
if (buf_ssrc == XCAM_NULL) {
fclose(file);
LOG_LIVESTREAM_ERROR("Null pointer [buf_ssrc]!\n");
return;
}
tmpid = (xcam_u32 *)malloc(sizeof(xcam_u32));
if (tmpid == XCAM_NULL) {
fclose(file);
LOG_LIVESTREAM_ERROR("Dynamic alloc for random id fail!\n");
return;
}
memset(tmpid, 0x00, sizeof(xcam_u32));
for (i = 0; i < length; ++i) {
if (fread(tmpid, sizeof(xcam_u32), 1, file) != 1) {
LOG_LIVESTREAM_ERROR("Read /dev/urandom failed and errno is %d!\n", errno);
fclose(file);
free(tmpid);
tmpid = XCAM_NULL;
return;
} else {
buf_ssrc[i] = (*tmpid % 10) + '0';
}
}
buf_ssrc[length] = 0;
fclose(file);
free(tmpid);
tmpid = XCAM_NULL;
}
xcam_s32 livestream_comm_base64_encode(const xcam_u8* input_str, xcam_s32 input_len,
xcam_u8* output_str, xcam_s32 output_len)
{
xcam_s32 i = 0;
xcam_s32 j = 0;
xcam_s32 pad;
UNUSED(output_len);
if (input_str == XCAM_NULL) {
LOG_LIVESTREAM_ERROR("Null pointer [input_str]!\n");
return XCAM_FAILURE;
}
if (output_str == XCAM_NULL) {
LOG_LIVESTREAM_ERROR("Null pointer [output_str]!\n");
return XCAM_FAILURE;
}
while (i < input_len) {
pad = 3 - (input_len - i);
if (pad == 2) {
output_str[j ] = g_basis64_string[input_str[i] >> 2];
output_str[j + 1] = g_basis64_string[(input_str[i] & 0x03) << 4];
output_str[j + 2] = '=';
output_str[j + 3] = '=';
} else if (pad == 1) {
output_str[j ] = g_basis64_string[input_str[i] >> 2];
output_str[j + 1] = g_basis64_string[((input_str[i] & 0x03) << 4) | ((input_str[i + 1] & 0xf0) >> 4)];
output_str[j + 2] = g_basis64_string[(input_str[i + 1] & 0x0f) << 2];
output_str[j + 3] = '=';
} else {
output_str[j ] = g_basis64_string[input_str[i] >> 2];
output_str[j + 1] = g_basis64_string[((input_str[i] & 0x03) << 4) | ((input_str[i + 1] & 0xf0) >> 4)];
output_str[j + 2] = g_basis64_string[((input_str[i + 1] & 0x0f) << 2) | ((input_str[i + 2] & 0xc0) >> 6)];
output_str[j + 3] = g_basis64_string[input_str[i + 2] & 0x3f];
}
i += 3;
j += 4;
}
return j;
}
xcam_s32 livestream_comm_base64_decode(const xcam_u8* input_str, xcam_s32 input_len,
xcam_u8* output_str, xcam_s32 output_len)
{
xcam_s32 i = 0;
xcam_s32 j = 0;
xcam_s32 pad;
xcam_u8 temp[4];
UNUSED(output_len);
if (output_str == XCAM_NULL) {
LOG_LIVESTREAM_ERROR("Null pointer [output_str]!\n");
return XCAM_FAILURE;
}
while ((i + 3) < input_len) {
pad = 0;
temp[0] = CHAR64(input_str[i ]);
if (temp[0] == 0xff) {
pad ++;
}
temp[1] = CHAR64(input_str[i + 1]);
if (temp[1] == 0xff) {
pad ++;
}
temp[2] = CHAR64(input_str[i + 2]);
if (temp[2] == 0xff) {
pad ++;
}
temp[3] = CHAR64(input_str[i + 3]);
if (temp[3] == 0xff) {
pad ++;
}
if (pad == 2) {
output_str[j++] = (temp[0] << 2) | ((temp[1] & 0x30) >> 4);
output_str[j] = (temp[1] & 0x0f) << 4;
} else if (pad == 1) {
output_str[j++] = (temp[0] << 2) | ((temp[1] & 0x30) >> 4);
output_str[j++] = ((temp[1] & 0x0f) << 4) | ((temp[2] & 0x3c) >> 2);
output_str[j] = (temp[2] & 0x03) << 6;
} else {
output_str[j++] = (temp[0] << 2) | ((temp[1] & 0x30) >> 4);
output_str[j++] = ((temp[1] & 0x0f) << 4) | ((temp[2] & 0x3c) >> 2);
output_str[j++] = ((temp[2] & 0x03) << 6) | (temp[3] & 0x3f);
}
i += 4;
}
return j;
}
xcam_s32 livestream_comm_close_socket(xcam_s32* sockfd)
{
if (sockfd == XCAM_NULL) {
return XCAM_FAILURE;
}
if (*sockfd >= 0) {
close(*sockfd);
*sockfd = INVALID_SOCKET;
return XCAM_SUCCESS;
}
return XCAM_FAILURE;
}
xcam_s32 livestream_comm_get_peer_ip_port(xcam_s32 sockfd, xcam_char* ip, xcam_u16* port)
{
xcam_char* ptr_temp = XCAM_NULL;
socklen_t name_len = 0;
struct sockaddr_in addr;
name_len = sizeof(struct sockaddr_in);
if (0 != getpeername(sockfd, (struct sockaddr*)&addr, &name_len)) {
return XCAM_FAILURE;
}
*port = (xcam_u16)ntohs(addr.sin_port);
ptr_temp = inet_ntoa(addr.sin_addr);
if (XCAM_NULL == ptr_temp) {
LOG_LIVESTREAM_ERROR("ip address inet_ntoa error!\n");
return XCAM_FAILURE;
}
if (snprintf(ip, IP_MAX_LEN - 1, "%s", ptr_temp) < 0) {
LOG_LIVESTREAM_ERROR("string print ip fail!\n");
return XCAM_FAILURE;
}
return XCAM_SUCCESS;
}
xcam_s32 livestream_comm_get_peer_sockaddr(xcam_char* ip, xcam_u16 port, struct sockaddr_in* sock_addr)
{
if (XCAM_NULL == sock_addr) {
LOG_LIVESTREAM_ERROR("param sock_addr is null!\n");
return XCAM_FAILURE;
}
sock_addr->sin_family = AF_INET;
sock_addr->sin_port = htons(port);
memset(&(sock_addr->sin_zero), '\0', sizeof(sock_addr->sin_zero));
if (0 == inet_aton(ip, (struct in_addr*) & (sock_addr->sin_addr.s_addr))) {
LOG_LIVESTREAM_ERROR("inet_aton fail!\n");
return XCAM_FAILURE;
}
return XCAM_SUCCESS;
}
xcam_s32 livestream_comm_get_host_ipaddr(xcam_s32 sockfd, xcam_char* ip)
{
xcam_char* ptr_temp = XCAM_NULL;
xcam_s32 name_len = 0;
struct sockaddr_in addr;
name_len = sizeof(struct sockaddr);
if (0 != getsockname(sockfd, (struct sockaddr*)&addr, (socklen_t*)&name_len)) {
return XCAM_FAILURE;
}
ptr_temp = inet_ntoa(addr.sin_addr);
if (XCAM_NULL == ptr_temp) {
LOG_LIVESTREAM_ERROR("inet_ntoa fail!\n");
return XCAM_FAILURE;
}
if (snprintf(ip, IP_MAX_LEN - 1, "%s", ptr_temp) < 0) {
LOG_LIVESTREAM_ERROR("string print ip address error\n");
return XCAM_FAILURE;
}
return XCAM_SUCCESS;
}
xcam_s32 livestream_comm_open_udp_socket(xcam_u16 port)
{
struct sockaddr_in addr = {0};
xcam_s32 fd;
if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
LOG_LIVESTREAM_ERROR("socket udp fail!\n");
return XCAM_FAILURE;
}
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(INADDR_ANY);
addr.sin_port = htons(port);
memset(&(addr.sin_zero), '\0', sizeof(addr.sin_zero));
if (bind(fd, (struct sockaddr*)&addr, sizeof (addr))) {
LOG_LIVESTREAM_ERROR("bind udp socket fail %s!\n", strerror(errno));
close(fd);
return XCAM_FAILURE;
}
return fd;
}
#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif /* End of #ifdef __cplusplus */
+62
View File
@@ -0,0 +1,62 @@
/*
* Copyright (c) XCAM. All rights reserved.
*/
#ifndef _LIVESTREAM_COMMON_H_
#define _LIVESTREAM_COMMON_H_
#include <netinet/in.h>
#include <sys/types.h>
#include <stdio.h>
#include <limits.h>
#include <pthread.h>
#include <time.h>
#include "xcam_type.h"
#include "xcam_log.h"
#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif
#endif /* End of #ifdef __cplusplus */
#define LOG_LIVESTREAM_INFO(fmt...) XCAM_LOG_INFO_PRINT("livestream", fmt);
#define LOG_LIVESTREAM_WARN(fmt...) XCAM_LOG_WARN_PRINT("livestream", fmt);
#define LOG_LIVESTREAM_ERROR(fmt...) XCAM_LOG_ERR_PRINT("livestream", fmt);
#define LOG_LIVESTREAM_FATAL(fmt...) XCAM_LOG_FATAL_PRINT("livestream", fmt);
#define MAX_DATE_LEN (200)
#define MIN_SEND_PORT (5000)
#define MAX_SEND_PORT (6000)
#define INVALID_SOCKET (-1)
xcam_s32 livestream_comm_format_date(xcam_char* date_buf, xcam_s32 buf_size);
xcam_void livestream_comm_random_num(xcam_u32* buf_ssrc);
xcam_void livestream_comm_random_id(xcam_char* buf_ssrc, xcam_s32 length);
xcam_s32 livestream_comm_base64_encode(const xcam_u8* input_str, xcam_s32 input_len,
xcam_u8* output_str, xcam_s32 output_len);
xcam_s32 livestream_comm_base64_decode(const xcam_u8* input_str, xcam_s32 input_len,
xcam_u8* output_str, xcam_s32 output_len);
xcam_s32 livestream_comm_get_peer_ip_port(xcam_s32 sockfd, xcam_char* ip, xcam_u16* port);
xcam_s32 livestream_comm_get_peer_sockaddr(xcam_char* ip, xcam_u16 port, struct sockaddr_in* sock_addr);
xcam_s32 livestream_comm_get_host_ipaddr(xcam_s32 sockfd, xcam_char* ip);
xcam_s32 livestream_comm_open_udp_socket(xcam_u16 port);
xcam_s32 livestream_comm_close_socket(xcam_s32* sockfd);
#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif /* End of #ifdef __cplusplus */
#endif /*_LIVESTREAM_COMMON_H_*/
+159
View File
@@ -0,0 +1,159 @@
/*
* Copyright (c) XCAM. All rights reserved.
*/
#ifndef _LIVESTREAM_ERRNO_H_
#define _LIVESTREAM_ERRNO_H_
#include "xcam_define.h"
#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif
#endif
typedef enum {
/*general error code*/
ERR_CODE_NULL_PTR = 0x30,
ERR_CODE_INVALID_HANDLE = 0x31,
ERR_CODE_INVALID_PARAM = 0x32,
ERR_CODE_MALLOC_FAILED = 0x33,
ERR_CODE_HANDLE_INVALID = 0x40, /**<rtspserver handle invalid*/
ERR_CODE_INVALID_ARG = 0x41, /**<param is null or invalid*/
ERR_CODE_MALLOC_FAIL = 0x42, /**<malloc memory fail*/
ERR_CODE_CREATE_FAIL = 0x43, /**<create rtspserverfail*/
ERR_CODE_DESTORY_FAIL = 0x44, /**<destory rtspserver fail*/
ERR_CODE_START_FAIL = 0x45, /**<start rtspserverfail*/
ERR_CODE_STOP_FAIL = 0x46, /**<stop rtspserver fail*/
ERR_CODE_REACH_MAX_CONNECT = 0x47, /**<rtspserver reach the max clients connect*/
ERR_CODE_CREATE_AGAIN = 0x48, /**<rtspserver have been created*/
ERR_CODE_NOT_CREATE = 0x49, /**<rtspserver have been created*/
/*stream related error code*/
ERR_CODE_STREAM_REMOVE_FAIL = 0x50, /**<remove stream fail*/
ERR_CODE_STREAM_ADD_FAIL = 0x51, /**<add stream fail*/
ERR_CODE_STREAM_EXISTED = 0x52, /**<add stream existed*/
ERR_CODE_STREAM_NOT_EXIST = 0x53, /**<remove or find stream not existed*/
ERR_CODE_STREAM_REMOVE_SESS_FAIL = 0x54, /**<remove stream related session fail*/
ERR_CODE_STREAM_ADD_SESS_FAIL = 0x55, /**<add a session for stream fail*/
/*mbuffer related error code */
ERR_CODE_INIT_MBUF_FAIL = 0x56, /**<init mbuffer fail*/
ERR_CODE_DEL_MBUF_FAIL = 0x57, /**<deinit mbuffer fail*/
/*listener related error code*/
ERR_CODE_CREATE_LISTENER_FAIL = 0x60, /**<create listener fail*/
ERR_CODE_DESTROY_LISTENER_FAIL = 0x61, /**<destroy listener fail*/
ERR_CODE_START_LISTENER_FAIL = 0x62, /**<start listener fail*/
ERR_CODE_STOP_LISTENER_FAIL = 0x63, /**<stop listener fail*/
ERR_CODE_START_LISTENER_AGAIN = 0x64, /**<start the listener again*/
ERR_CODE_STOP_LISTENER_NOT_STARTED = 0x65, /**<stop the listener not started*/
/*sess related error code */
ERR_CODE_SESS_HANDLE_INVALID = 0x70, /**<session handle invalidt*/
ERR_CODE_SESS_CONNECT_FAIL = 0x71, /**<session connect fail*/
ERR_CODE_SESS_CREATE_FAIL = 0x72, /**<create sess fail*/
ERR_CODE_SESS_DESTROY_FAIL = 0x73, /**<destroy sess fail*/
ERR_CODE_SESS_START_FAIL = 0x74, /**<start sess fail*/
ERR_CODE_SESS_STOP_FAIL = 0x75, /**<stop sess fail*/
ERR_CODE_SESS_SET_FAIL = 0x76, /**<set sess fail*/
ERR_CODE_SESS_EXISTED = 0x77, /**<sess already existed*/
ERR_CODE_SESS_NOT_EXISTED = 0x78, /**<sess not existed*/
ERR_CODE_SESS_BAD_REQUEST = 0x79, /**<bad request*/
ERR_CODE_SESS_STREAM_NOT_FOUND = 0x7a, /**<stream not found*/
ERR_CODE_SESS_UNSUPPORT_TRANSPORT = 0x7b, /**<unsuport transtype*/
ERR_CODE_SESS_SEND_FAIL = 0x7c, /**<send fail*/
ERR_CODE_SESS_UNSUPPORT_MEDIATYPE = 0x7d, /**<unsuport mediatype*/
ERR_CODE_SESS_NO_DATA = 0x7e, /**<read no data*/
/*rtp error code*/
ERR_CODE_RTP_DESTROY_FAIL = 0x80, /**<create rtp fail*/
ERR_CODE_RTP_CREATE_FAIL = 0x81, /**<destory rtp fail*/
ERR_CODE_RTP_TRANS_MODE = 0x82, /**<not support trans mode*/
ERR_CODE_RTP_PACKET_TYPE = 0x83, /**<not support pack type*/
ERR_CODE_RTP_TRANS_SEND = 0x84, /**<rtp trans send error*/
/*rtcp error code*/
ERR_CODE_RTCP_DESTROY_FAIL = 0x85, /**<create rtcp fail*/
ERR_CODE_RTCP_CREATE_FAIL = 0x86, /**<destory rtcp fail*/
/*write frame error code*/
ERR_CODE_WRITE_FRAME_FAIL = 0x87, /**<write frame fail*/
ERR_CODE_MBUF_FULL = 0x88, /**<buff full fail*/
ERR_CODE_BUTT = 0xFF
} rtspserver_err_code;
/*general error code*/
#define LIVESTREAM_ERRNO_NULL_PTR XCAM_BUILD_ERRNO(XCAM_MOD_LIVESTREAM, ERR_CODE_NULL_PTR)
#define LIVESTREAM_ERRNO_HANDLE_INVALID XCAM_BUILD_ERRNO(XCAM_MOD_LIVESTREAM, ERR_CODE_INVALID_HANDLE)
#define LIVESTREAM_ERRNO_ILLEGAL_PARAM XCAM_BUILD_ERRNO(XCAM_MOD_LIVESTREAM, ERR_CODE_INVALID_PARAM)
#define LIVESTREAM_ERRNO_MALLOC_FAIL XCAM_BUILD_ERRNO(XCAM_MOD_LIVESTREAM, ERR_CODE_MALLOC_FAILED)
#define LIVESTREAM_ERRNO_CREATE_FAIL XCAM_BUILD_ERRNO(XCAM_MOD_LIVESTREAM, ERR_CODE_CREATE_FAIL)
#define LIVESTREAM_ERRNO_DESTROY_FAIL XCAM_BUILD_ERRNO(XCAM_MOD_LIVESTREAM, ERR_CODE_DESTORY_FAIL)
#define LIVESTREAM_ERRNO_START_FAIL XCAM_BUILD_ERRNO(XCAM_MOD_LIVESTREAM, ERR_CODE_START_FAIL)
#define LIVESTREAM_ERRNO_STOP_FAIL XCAM_BUILD_ERRNO(XCAM_MOD_LIVESTREAM, ERR_CODE_STOP_FAIL)
#define LIVESTREAM_ERRNO_REACH_MAX_CONNECT XCAM_BUILD_ERRNO(XCAM_MOD_LIVESTREAM, ERR_CODE_REACH_MAX_CONNECT)
#define LIVESTREAM_ERRNO_CREATE_AGAIN XCAM_BUILD_ERRNO(XCAM_MOD_LIVESTREAM, ERR_CODE_CREATE_AGAIN)
#define LIVESTREAM_ERRNO_NOT_CREATE XCAM_BUILD_ERRNO(XCAM_MOD_LIVESTREAM, ERR_CODE_NOT_CREATE)
/*stream related error code*/
#define LIVESTREAM_ERRNO_STREAM_REMOVE_FAIL XCAM_BUILD_ERRNO(XCAM_MOD_LIVESTREAM, ERR_CODE_STREAM_REMOVE_FAIL)
#define LIVESTREAM_ERRNO_STREAM_ADD_FAIL XCAM_BUILD_ERRNO(XCAM_MOD_LIVESTREAM, ERR_CODE_STREAM_ADD_FAIL)
#define LIVESTREAM_ERRNO_STREAM_EXISTED XCAM_BUILD_ERRNO(XCAM_MOD_LIVESTREAM, ERR_CODE_STREAM_EXISTED)
#define LIVESTREAM_ERRNO_STREAM_NOT_EXIST XCAM_BUILD_ERRNO(XCAM_MOD_LIVESTREAM, ERR_CODE_STREAM_NOT_EXIST)
#define LIVESTREAM_ERRNO_STREAM_REMOVE_SESS_FAIL XCAM_BUILD_ERRNO(XCAM_MOD_LIVESTREAM, ERR_CODE_STREAM_REMOVE_SESS_FAIL)
#define LIVESTREAM_ERRNO_STREAM_ADD_SESS_FAIL XCAM_BUILD_ERRNO(XCAM_MOD_LIVESTREAM, ERR_CODE_STREAM_ADD_SESS_FAIL)
/*mbuffer related error code*/
#define LIVESTREAM_ERRNO_INIT_MBUF_FAIL XCAM_BUILD_ERRNO(XCAM_MOD_LIVESTREAM, ERR_CODE_INIT_MBUF_FAIL)
#define LIVESTREAM_ERRNO_DEL_MBUF_FAIL XCAM_BUILD_ERRNO(XCAM_MOD_LIVESTREAM, ERR_CODE_DEL_MBUF_FAIL)
/*listener related error code*/
#define LIVESTREAM_ERRNO_CREATE_LISTENER_FAIL XCAM_BUILD_ERRNO(XCAM_MOD_LIVESTREAM, ERR_CODE_CREATE_LISTENER_FAIL)
#define LIVESTREAM_ERRNO_DESTROY_LISTENER_FAIL XCAM_BUILD_ERRNO(XCAM_MOD_LIVESTREAM, ERR_CODE_DESTROY_LISTENER_FAIL)
#define LIVESTREAM_ERRNO_START_LISTENER_FAIL XCAM_BUILD_ERRNO(XCAM_MOD_LIVESTREAM, ERR_CODE_START_LISTENER_FAIL)
#define LIVESTREAM_ERRNO_STOP_LISTENER_FAIL XCAM_BUILD_ERRNO(XCAM_MOD_LIVESTREAM, ERR_CODE_STOP_LISTENER_FAIL)
#define LIVESTREAM_ERRNO_START_LISTENER_AGAIN XCAM_BUILD_ERRNO(XCAM_MOD_LIVESTREAM, ERR_CODE_START_LISTENER_AGAIN)
#define LIVESTREAM_ERRNO_STOP_LISTENER_NOT_STARTED XCAM_BUILD_ERRNO(XCAM_MOD_LIVESTREAM, ERR_CODE_STOP_LISTENER_NOT_STARTED)
/*sess related error code */
#define LIVESTREAM_ERRNO_SESS_HANDLE_INVALID XCAM_BUILD_ERRNO(XCAM_MOD_LIVESTREAM, ERR_CODE_SESS_HANDLE_INVALID)
#define LIVESTREAM_ERRNO_SESS_CONNECT_FAIL XCAM_BUILD_ERRNO(XCAM_MOD_LIVESTREAM, ERR_CODE_SESS_CONNECT_FAIL)
#define LIVESTREAM_ERRNO_SESS_CREATE_FAIL XCAM_BUILD_ERRNO(XCAM_MOD_LIVESTREAM, ERR_CODE_SESS_CREATE_FAIL)
#define LIVESTREAM_ERRNO_SESS_DESTROY_FAIL XCAM_BUILD_ERRNO(XCAM_MOD_LIVESTREAM, ERR_CODE_SESS_DESTROY_FAIL)
#define LIVESTREAM_ERRNO_SESS_START_FAIL XCAM_BUILD_ERRNO(XCAM_MOD_LIVESTREAM, ERR_CODE_SESS_START_FAIL)
#define LIVESTREAM_ERRNO_SESS_STOP_FAIL XCAM_BUILD_ERRNO(XCAM_MOD_LIVESTREAM, ERR_CODE_SESS_STOP_FAIL)
#define LIVESTREAM_ERRNO_SESS_SET_FAIL XCAM_BUILD_ERRNO(XCAM_MOD_LIVESTREAM, ERR_CODE_SESS_SET_FAIL)
#define LIVESTREAM_ERRNO_SESS_EXISTED XCAM_BUILD_ERRNO(XCAM_MOD_LIVESTREAM, ERR_CODE_SESS_EXISTED)
#define LIVESTREAM_ERRNO_SESS_NOT_EXISTED XCAM_BUILD_ERRNO(XCAM_MOD_LIVESTREAM, ERR_CODE_SESS_NOT_EXISTED)
#define LIVESTREAM_ERRNO_SESS_BAD_REQUEST XCAM_BUILD_ERRNO(XCAM_MOD_LIVESTREAM, ERR_CODE_SESS_BAD_REQUEST)
#define LIVESTREAM_ERRNO_SESS_STREAM_NOT_FOUND XCAM_BUILD_ERRNO(XCAM_MOD_LIVESTREAM, ERR_CODE_SESS_STREAM_NOT_FOUND)
#define LIVESTREAM_ERRNO_SESS_UNSUPPORT_TRANSPORT XCAM_BUILD_ERRNO(XCAM_MOD_LIVESTREAM, ERR_CODE_SESS_UNSUPPORT_TRANSPORT)
#define LIVESTREAM_ERRNO_SESS_SEND_FAIL XCAM_BUILD_ERRNO(XCAM_MOD_LIVESTREAM, ERR_CODE_SESS_SEND_FAIL)
#define LIVESTREAM_ERRNO_SESS_UNSUPPORT_MEDIATYPE XCAM_BUILD_ERRNO(XCAM_MOD_LIVESTREAM, ERR_CODE_SESS_UNSUPPORT_MEDIATYPE)
#define LIVESTREAM_ERRNO_SESS_NO_DATA XCAM_BUILD_ERRNO(XCAM_MOD_LIVESTREAM, ERR_CODE_SESS_NO_DATA)
/*rtp error code*/
#define LIVESTREAM_ERRNO_RTP_DESTROY_FAIL XCAM_BUILD_ERRNO(XCAM_MOD_LIVESTREAM, ERR_CODE_RTP_DESTROY_FAIL)
#define LIVESTREAM_ERRNO_RTP_CREATE_FAIL XCAM_BUILD_ERRNO(XCAM_MOD_LIVESTREAM, ERR_CODE_RTP_CREATE_FAIL)
#define LIVESTREAM_ERRNO_RTP_TRANS_MODE XCAM_BUILD_ERRNO(XCAM_MOD_LIVESTREAM, ERR_CODE_RTP_TRANS_MODE)
#define LIVESTREAM_ERRNO_RTP_PACKET_TYPE XCAM_BUILD_ERRNO(XCAM_MOD_LIVESTREAM, ERR_CODE_RTP_PACKET_TYPE)
#define LIVESTREAM_ERRNO_RTP_TRANS_SEND XCAM_BUILD_ERRNO(XCAM_MOD_LIVESTREAM, ERR_CODE_RTP_TRANS_SEND)
/*rtcp error code*/
#define LIVESTREAM_ERRNO_RTCP_DESTROY_FAIL XCAM_BUILD_ERRNO(XCAM_MOD_LIVESTREAM, ERR_CODE_RTCP_DESTROY_FAIL)
#define LIVESTREAM_ERRNO_RTCP_CREATE_FAIL XCAM_BUILD_ERRNO(XCAM_MOD_LIVESTREAM, ERR_CODE_RTCP_CREATE_FAIL)
/*write frame error code*/
#define LIVESTREAM_ERRNO_WRITE_FRAME XCAM_BUILD_ERRNO(XCAM_MOD_LIVESTREAM, ERR_CODE_WRITE_FRAME_FAIL)
#define LIVESTREAM_ERRNO_MBUF_FULL XCAM_BUILD_ERRNO(XCAM_MOD_LIVESTREAM, ERR_CODE_MBUF_FULL)
#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif /* __cplusplus */
#endif /* _LIVESTREAM_ERRNO_H_ */
+432
View File
@@ -0,0 +1,432 @@
/*
* Copyright (c) XCAM. All rights reserved.
*/
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <sys/prctl.h>
#include <fcntl.h>
#include <stdlib.h>
#include <netinet/tcp.h>
#include "livestream_comm.h"
#include "livestream_listener.h"
#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif
#endif /* End of #ifdef __cplusplus */
#define KEEPALIVE_IDLE_SECONDS (3)
#define LISTEN_PORT_NUM_MIN 0
#define LISTEN_PORT_NUM_MAX 65535
#define LISTEN_TIMEOUT_SEC (0)
#define LISTEN_TIMEOUT_USEC (10000)
#define MAX_RECV_BUFFER (1024)
#define DEFAULT_MAX_FD_NUM (32)
typedef struct {
pthread_t listen_thread;
xcam_s32 listen_sock;
xcam_u16 listen_port;
/*state of the listener */
xcam_bool is_listening;
xcam_char first_msg_buff[MAX_RECV_BUFFER];
xcam_s32 client_sock_list[DEFAULT_MAX_FD_NUM];
client_connect_hook connect_callback;
xcam_void* callback_object;
} listener_context;
static xcam_s32 listener_set_nonblock(xcam_s32 sockfd)
{
xcam_u32 flags = 0;
xcam_s32 ret;
flags = (xcam_u32)fcntl(sockfd, F_GETFL, 0);
ret = fcntl(sockfd, F_SETFL, flags | O_NONBLOCK);
if (ret < 0) {
return ret;
}
return XCAM_SUCCESS;
}
static xcam_s32 listener_set_keepalive(xcam_s32 sockfd, xcam_s32 keepalive,
xcam_s32 keepidle, xcam_s32 keepinterval, xcam_s32 keepcount)
{
xcam_s32 ret;
ret = setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, (void *)&keepalive, sizeof(keepalive));
if (ret < 0) {
return ret;
}
ret = setsockopt(sockfd, SOL_TCP, TCP_KEEPIDLE, (void*)&keepidle, sizeof(keepidle));
if (ret < 0) {
return ret;
}
ret = setsockopt(sockfd, SOL_TCP, TCP_KEEPINTVL, (void *)&keepinterval, sizeof(keepinterval));
if (ret < 0) {
return ret;
}
ret = setsockopt(sockfd, SOL_TCP, TCP_KEEPCNT, (void *)&keepcount, sizeof(keepcount));
if (ret < 0) {
return ret;
}
return XCAM_SUCCESS;
}
static xcam_s32 listener_add_fd(listener_context* listener_ctx, xcam_s32 sockfd)
{
xcam_s32 i = 0;
for (i = 0; i < DEFAULT_MAX_FD_NUM; i++) {
if (listener_ctx->client_sock_list[i] == INVALID_SOCKET) {
listener_ctx->client_sock_list[i] = sockfd;
return XCAM_SUCCESS;
}
}
return XCAM_FAILURE;
}
static xcam_s32 listener_del_fd(listener_context* listener_ctx, xcam_s32 sockfd)
{
xcam_s32 i = 0;
for (i = 0; i < DEFAULT_MAX_FD_NUM; i++) {
if (listener_ctx->client_sock_list[i] == sockfd) {
listener_ctx->client_sock_list[i] = INVALID_SOCKET;
return XCAM_SUCCESS;
}
}
return XCAM_FAILURE;
}
static xcam_s32 listener_close_client_fd(listener_context* listener_ctx)
{
xcam_s32 i = 0;
for (; i < DEFAULT_MAX_FD_NUM; i++) {
if (listener_ctx->client_sock_list[i] != INVALID_SOCKET) {
close(listener_ctx->client_sock_list[i]);
listener_ctx->client_sock_list[i] = INVALID_SOCKET;
}
}
return XCAM_SUCCESS;
}
static xcam_s32 listener_update_max_fd(const listener_context* listener_ctx, xcam_s32* ptr_maxfd_num)
{
xcam_s32 maxfd_num = -1;
xcam_s32 i = 0;
for (; i < DEFAULT_MAX_FD_NUM; i++) {
if (listener_ctx->client_sock_list[i] != INVALID_SOCKET
&& listener_ctx->client_sock_list[i] > maxfd_num) {
maxfd_num = listener_ctx->client_sock_list[i];
}
}
if (listener_ctx->listen_sock > maxfd_num) {
maxfd_num = listener_ctx->listen_sock;
}
*ptr_maxfd_num = maxfd_num + 1;
return XCAM_SUCCESS;
}
static xcam_bool listener_check_fd(listener_context* listener_ctx, fd_set* ptr_fdset, xcam_s32* ptr_sockfd)
{
xcam_s32 i = 0;
for (; i < DEFAULT_MAX_FD_NUM; i++) {
if (listener_ctx->client_sock_list[i] != INVALID_SOCKET) {
xcam_s32 fd = listener_ctx->client_sock_list[i];
if (FD_ISSET(fd, ptr_fdset)) {
*ptr_sockfd = fd;
return XCAM_TRUE;
}
}
}
return XCAM_FALSE;
}
static xcam_s32 listener_create_socket(xcam_s32 listen_port, xcam_s32* listen_sockfd)
{
struct timeval timeout = {KEEPALIVE_IDLE_SECONDS, 0};
struct sockaddr_in svr_addr = {0};
xcam_s32 sockfd = INVALID_SOCKET; /*temp listen socket*/
xcam_s32 opt_value = 1;
xcam_s32 ret = 0;
/* 1. Create socket as block mode and listen for accept new connection.*/
sockfd = socket(PF_INET, SOCK_STREAM, 0);
if (sockfd < 0) {
LOG_LIVESTREAM_ERROR("Create listen sockfd failed! \n");
return XCAM_FAILURE;
}
/*2. set sock option*/
if (-1 == setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &opt_value, sizeof(xcam_s32))) {
close(sockfd);
LOG_LIVESTREAM_ERROR("set socket option SO_REUSEADDR error.\n");
return XCAM_FAILURE;
}
if (-1 == setsockopt(sockfd, SOL_SOCKET, SO_SNDTIMEO, (char*)&timeout, sizeof(struct timeval))) {
close(sockfd);
LOG_LIVESTREAM_ERROR("set socket option SO_SNDTIMEO error.\n");
return XCAM_FAILURE;
}
if (-1 == setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout, sizeof(struct timeval))) {
close(sockfd);
LOG_LIVESTREAM_ERROR("set socket option SO_RCVTIMEO error.\n");
return XCAM_FAILURE;
}
xcam_s32 keepalive = 1;
xcam_s32 keepidle = KEEPALIVE_IDLE_SECONDS;
xcam_s32 keepinterval = 1;
xcam_s32 keepcount = 3;
ret = listener_set_keepalive(sockfd, keepalive, keepidle, keepinterval, keepcount);
if (XCAM_SUCCESS != ret) {
LOG_LIVESTREAM_ERROR("SetKeepAlive error=%d\n", ret);
}
/*3. bind socket */
svr_addr.sin_family = AF_INET;
svr_addr.sin_port = htons(listen_port);
svr_addr.sin_addr.s_addr = htonl(INADDR_ANY);
memset(&(svr_addr.sin_zero), '\0', sizeof(svr_addr.sin_zero));
if (bind(sockfd, (struct sockaddr*)&svr_addr, sizeof(struct sockaddr)) != XCAM_SUCCESS) {
LOG_LIVESTREAM_ERROR("bind fail error:%s\n", strerror(errno));
close(sockfd);
return XCAM_FAILURE;
}
/*4. listen on port*/
ret = listen(sockfd, DEFAULT_MAX_FD_NUM);
if (ret != XCAM_SUCCESS) {
LOG_LIVESTREAM_ERROR("socket listen error.\n");
close(sockfd);
return XCAM_FAILURE;
}
*listen_sockfd = sockfd;
return XCAM_SUCCESS;
}
/*main func of listen thread */
static xcam_void* listener_thread_process(void* args)
{
listener_context* listener_ctx = (listener_context*)args;
struct sockaddr_in accept_addr; /*socket addr of accepted client connect*/
struct timeval timeout_val; /* Timeout value */
xcam_s32 maxfd_num = 0; /*max socket number of read set*/
xcam_s32 accept_sock = INVALID_SOCKET; /*accepted client connect socket */
xcam_s32 sockaddr_len = 0;
xcam_s32 recv_bytes = 0;
xcam_s32 ret = XCAM_SUCCESS;
fd_set read_active_fds;
fd_set read_fds;
memset(&timeout_val, 0, sizeof(struct timeval));
memset(&accept_addr, 0, sizeof(struct sockaddr_in));
ret = listener_create_socket(listener_ctx->listen_port, &listener_ctx->listen_sock);
if (ret != XCAM_SUCCESS) {
LOG_LIVESTREAM_ERROR("create listener sockfd failed error:%d \n", ret);
return XCAM_NULL;
}
prctl(PR_SET_NAME, (unsigned long)"NetlistenProc", 0, 0, 0);
LOG_LIVESTREAM_INFO("start listener! \n");
/*init read fds and set http lisen sock into read set*/
FD_ZERO(&read_fds);
FD_ZERO(&read_active_fds);
maxfd_num = listener_ctx->listen_sock + 1;
FD_SET(listener_ctx->listen_sock, &read_active_fds);
while (listener_ctx->is_listening) {
timeout_val.tv_sec = LISTEN_TIMEOUT_SEC;
timeout_val.tv_usec = LISTEN_TIMEOUT_USEC;
memcpy(&read_fds, &read_active_fds, sizeof(fd_set));
/*jude if there is new connect or first message come through already connected link */
ret = select(maxfd_num, &read_fds, NULL, NULL, &timeout_val);
if (ret < 0) {
if (EINTR == errno || EAGAIN == errno) {
/*to do: interrupt or try again*/
continue;
}
LOG_LIVESTREAM_ERROR("select error! ret:%x,errno:%d,err:%s\n", ret, errno, strerror(errno));
break;
} else if (0 == ret) {
/*to do :select timeout over proset*/
continue;
}
if (FD_ISSET(listener_ctx->listen_sock, &read_fds)) {
/*accept new connect*/
sockaddr_len = sizeof(accept_addr);
accept_sock = accept(listener_ctx->listen_sock, (struct sockaddr*)&accept_addr, (socklen_t*)&sockaddr_len);
if (accept_sock < 0) {
LOG_LIVESTREAM_ERROR("accept conn error=%s \r\n", strerror(errno));
continue;
}
// TCP socket may block in many situations, e.g. wifi disconnected
// so we use nonblock socket and enable TCP keep alive.
ret = listener_set_nonblock(accept_sock);
if (XCAM_SUCCESS != ret) {
LOG_LIVESTREAM_ERROR("SetNonblock error=%d\n", ret);
}
ret = listener_set_keepalive(accept_sock, 1, KEEPALIVE_IDLE_SECONDS, 1, 3);
if (XCAM_SUCCESS != ret) {
LOG_LIVESTREAM_ERROR("SetKeepAlive error=%d\n", ret);
}
LOG_LIVESTREAM_INFO("a new connect has occured fd=%d.\n", accept_sock);
/*add new connection link into readfds*/
if (accept_sock + 1 > maxfd_num) {
maxfd_num = accept_sock + 1;
}
FD_SET(accept_sock , &read_active_fds);
listener_add_fd(listener_ctx, accept_sock);
} else {
xcam_s32 clientSockfd = INVALID_SOCKET;
if (listener_check_fd(listener_ctx, &read_fds, &clientSockfd)) {
memset(listener_ctx->first_msg_buff, 0, MAX_RECV_BUFFER);
recv_bytes = recv(clientSockfd, listener_ctx->first_msg_buff, MAX_RECV_BUFFER-1, 0);
FD_CLR(clientSockfd, &read_active_fds);
listener_del_fd(listener_ctx, clientSockfd);
/*updat Max read Fds Num*/
listener_update_max_fd(listener_ctx, &maxfd_num);
if (recv_bytes <= 0) {
LOG_LIVESTREAM_ERROR("recv data from error=%s\n", strerror(errno));
livestream_comm_close_socket(&clientSockfd);
continue;
}
/*callback to user*/
if (listener_ctx->connect_callback) {
listener_ctx->connect_callback(listener_ctx->callback_object,
clientSockfd, listener_ctx->first_msg_buff, recv_bytes);
}
}
}
} /*end of while*/
/*close the client fd before connect*/
listener_close_client_fd(listener_ctx);
/*close the listen socket*/
livestream_comm_close_socket(&listener_ctx->listen_sock);
LOG_LIVESTREAM_INFO("stop listener! \n");
return XCAM_NULL;
}
xcam_s32 livestream_listener_create(xcam_s32 listen_port, xcam_void** ptr_handle)
{
/* malloc listen server manage struct*/
listener_context* listener_ctx;
xcam_s32 i = 0;
if (listen_port <= LISTEN_PORT_NUM_MIN || listen_port > LISTEN_PORT_NUM_MAX) {
LOG_LIVESTREAM_ERROR("invalid listen port\n");
return XCAM_FAILURE;
}
listener_ctx = (listener_context*)malloc(sizeof(listener_context));
if (!listener_ctx) {
LOG_LIVESTREAM_ERROR("dynamic alloc for lisn server error.\r\n");
return XCAM_FAILURE;
}
memset(listener_ctx, 0x00, sizeof(listener_context));
for (; i < DEFAULT_MAX_FD_NUM; i++) {
listener_ctx->client_sock_list[i] = INVALID_SOCKET;
}
listener_ctx->listen_port = listen_port;
*ptr_handle = (xcam_void*)listener_ctx;
return XCAM_SUCCESS;
}
/*stop the lisen svr*/
xcam_s32 livestream_listener_destroy(xcam_void* handle)
{
listener_context* listener_ctx = (listener_context*)handle;
xcam_s32 ret;
ret = livestream_listener_stop(handle);
if (XCAM_SUCCESS != ret) {
LOG_LIVESTREAM_ERROR("livestream_listener_stop failed :%d \n", ret);
return ret;
}
if (listener_ctx) {
free(listener_ctx);
listener_ctx = NULL;
}
return XCAM_SUCCESS;
}
xcam_s32 livestream_listener_start(xcam_void* handle)
{
listener_context* listener_ctx;
xcam_s32 ret;
listener_ctx = (listener_context*)handle;
if (XCAM_TRUE == listener_ctx->is_listening) {
LOG_LIVESTREAM_ERROR("network listener already started in listening\n");
return XCAM_FAILURE;
}
listener_ctx->is_listening = XCAM_TRUE;
ret = pthread_create(&(listener_ctx->listen_thread), NULL, listener_thread_process, (xcam_void*)listener_ctx);
return ret;
}
xcam_s32 livestream_listener_stop(xcam_void* handle)
{
listener_context* listener_ctx = (listener_context*)handle;
xcam_s32 ret = XCAM_SUCCESS;
if (!listener_ctx) {
return XCAM_FAILURE;
}
/*set the listen svr stop flag*/
if (listener_ctx->is_listening) {
listener_ctx->is_listening = XCAM_FALSE;
ret = pthread_join(listener_ctx->listen_thread, NULL);
if (ret != 0) {
LOG_LIVESTREAM_ERROR("destroy network listener thread error!\n");
return ret;
}
}
return XCAM_SUCCESS;
}
xcam_s32 livestream_listener_register_callback(xcam_void* handle,
client_connect_hook connection_func, xcam_void* object)
{
listener_context* listener_ctx = (listener_context*)handle;
listener_ctx->connect_callback = connection_func;
listener_ctx->callback_object = object;
return XCAM_SUCCESS;
}
#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif /* End of #ifdef __cplusplus */
+34
View File
@@ -0,0 +1,34 @@
/*
* Copyright (c) XCAM. All rights reserved.
*/
#ifndef _LIVESTREAM_LISTENER_H_
#define _LIVESTREAM_LISTENER_H_
#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif
#endif /* End of #ifdef __cplusplus */
typedef xcam_s32 (*client_connect_hook)(xcam_void* object, xcam_s32 link_fd,
xcam_char* msg_buff, xcam_u32 msg_len);
xcam_s32 livestream_listener_create(xcam_s32 listen_port, xcam_void** ptr_handle);
xcam_s32 livestream_listener_destroy(xcam_void* handle);
xcam_s32 livestream_listener_start(xcam_void* handle);
xcam_s32 livestream_listener_stop(xcam_void* handle);
xcam_s32 livestream_listener_register_callback(xcam_void* handle,
client_connect_hook connection_func, xcam_void* object);
#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif /* End of #ifdef __cplusplus */
#endif /* _LIVESTREAM_LISTENER_H_ */
+219
View File
@@ -0,0 +1,219 @@
/*
* Copyright (c) XCAM. All rights reserved.
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include "livestream_comm.h"
#include "livestream_mbuffer.h"
#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif
#endif /* End of #ifdef __cplusplus */
#define UNUSED(x) (void)x
#define MAX_WAIT_COUNT (100)
#define DEFAULT_MBUFFER_SIZE (1280 * 720)
static xcam_s32 mbuffer_enable(xcam_void* handle, xcam_u8 payload_type)
{
xcam_s32 ret;
ret = xcam_mbuf_register_payload(handle, payload_type);
if (XCAM_SUCCESS != ret) {
LOG_LIVESTREAM_ERROR("mbuf register payload fail! handle:%p payload_type:%d\n",
handle, payload_type);
return ret;
}
ret = xcam_mbuf_set_rw_enable(handle, payload_type, XCAM_TRUE, XCAM_TRUE);
if (XCAM_SUCCESS != ret) {
LOG_LIVESTREAM_ERROR("mbuf set r/w enable fail, ret=%d!\n", ret);
if (XCAM_SUCCESS != xcam_mbuf_unregister_payload(handle, payload_type)) {
LOG_LIVESTREAM_ERROR("mbuf unregister payload_type:%d fail!\n", payload_type);
}
return ret;
}
return XCAM_SUCCESS;
}
xcam_s32 livestream_mbuffer_write_frame(xcam_void* handle, const xcam_mbuf_pack_info* pack_info)
{
if (pack_info != XCAM_NULL) {
return xcam_mbuf_write_pack(handle, pack_info);
}
return XCAM_FAILURE;
}
xcam_s32 livestream_mbuffer_create(const xcam_void* argv, xcam_void** buf_handle,
xcam_u32 buf_size, xcam_s32 max_payload)
{
xcam_s32 ret = XCAM_SUCCESS;
xcam_mbuf_cfg mbuf_cfg;
xcam_handle *handle;
mbuf_cfg.payload_count = max_payload;
mbuf_cfg.buf_size = buf_size;
if (mbuf_cfg.buf_size == 0) {
mbuf_cfg.buf_size = DEFAULT_MBUFFER_SIZE;
}
ret = xcam_mbuf_get_buffer(&handle, &mbuf_cfg);
if (ret != XCAM_SUCCESS) {
LOG_LIVESTREAM_ERROR("mbuf get buffer failed ret: %d\n", ret);
return XCAM_FAILURE;
}
*buf_handle = handle;
LOG_LIVESTREAM_INFO("mbuffer create success, size:%d payload_count:%d.\n",
mbuf_cfg.buf_size, mbuf_cfg.payload_count);
return XCAM_SUCCESS;
}
xcam_s32 livestream_mbuffer_destroy(xcam_void* argv, xcam_void* handle)
{
xcam_s32 ret;
ret = xcam_mbuf_release_buffer(handle);
if (ret != XCAM_SUCCESS) {
LOG_LIVESTREAM_ERROR("Release mbuf failed ret:0x%x!\n", ret);
return XCAM_FAILURE;
}
return XCAM_SUCCESS;
}
xcam_s32 livestream_mbuffer_register(xcam_void* handle, xcam_u8 media_type)
{
xcam_s32 ret;
ret = mbuffer_enable(handle, media_type);
if (XCAM_SUCCESS != ret) {
LOG_LIVESTREAM_ERROR("mbuf enable failed ret:0x%x!\n", ret);
return ret;
}
return XCAM_SUCCESS;
}
xcam_s32 livestream_mbuffer_unregister(xcam_void* handle, xcam_u8 media_type)
{
xcam_s32 ret = XCAM_SUCCESS;
ret = xcam_mbuf_unregister_payload(handle, media_type);
if (XCAM_SUCCESS != ret) {
LOG_LIVESTREAM_ERROR("mbuf unregister fail, media type:%d ret:%d!\n", media_type, ret);
return ret;
}
return XCAM_SUCCESS;
}
xcam_s32 livestream_mbuffer_read(xcam_void* handle, xcam_void** paddr, xcam_u32* plen,
xcam_u64* ppts, livestream_mbuffer_data_type* out_type, xcam_bool* bkey_flag)
{
xcam_mbuf_pack_info pack_info;
xcam_s32 ret = XCAM_FAILURE;
xcam_u32 i = 0;
pack_info.key_frame = XCAM_FALSE;
pack_info.seq = 0;
pack_info.pts = 0;
pack_info.payload_type = 0;
pack_info.pack_count = 0;
if (paddr == XCAM_NULL || plen == XCAM_NULL || ppts == XCAM_NULL
|| out_type == XCAM_NULL || bkey_flag == XCAM_NULL) {
return ret;
}
for (i = 0; i < XCAM_MBUF_MAX_PACK; i++) {
pack_info.pack_addr[i] = XCAM_NULL;
pack_info.pack_size[i] = 0;
}
*plen = 0;
ret = xcam_mbuf_read_pack(handle, XCAM_MBUF_PAYLOAD_TYPE_ALL, &pack_info);
if (XCAM_SUCCESS == ret) {
*paddr = pack_info.pack_addr[0];
for (i = 0; i < pack_info.pack_count; i++) {
*plen += pack_info.pack_size[i];
}
*ppts = pack_info.pts;
*bkey_flag = pack_info.key_frame;
switch (pack_info.payload_type) {
case BUF_PAYLOAD_H264:
case BUF_PAYLOAD_H265:
*out_type = MBUFFER_DATA_VIDEO;
break;
case BUF_PAYLOAD_G711U:
case BUF_PAYLOAD_G711A:
case BUF_PAYLOAD_G726:
case BUF_PAYLOAD_AAC:
case BUF_PAYLOAD_MP3:
*out_type = MBUFFER_DATA_AUDIO;
break;
default:
*out_type = MBUFFER_DATA_DATA;
break;
}
}
return ret;
}
xcam_s32 livestream_mbuffer_set(xcam_void* handle, xcam_u32 step)
{
xcam_s32 ret;
ret = xcam_mbuf_forward(handle, XCAM_MBUF_PAYLOAD_TYPE_ALL, step);
if (XCAM_SUCCESS != ret) {
LOG_LIVESTREAM_ERROR("mbuf forward fail, ret=%d!\n", ret);
return ret;
}
return XCAM_SUCCESS;
}
xcam_s32 livestream_mbuffer_pts(xcam_void* handle, xcam_u8 payload_type, xcam_u64* ppts)
{
xcam_s32 ret = XCAM_FAILURE;
xcam_s32 count = 0;
xcam_u32 i = 0;
xcam_mbuf_pack_info pack_info;
pack_info.key_frame = XCAM_FALSE;
pack_info.seq = 0;
pack_info.pts = 0;
pack_info.payload_type = 0;
pack_info.pack_count = 0;
for (i = 0; i < XCAM_MBUF_MAX_PACK; i++) {
pack_info.pack_addr[i] = XCAM_NULL;
pack_info.pack_size[i] = 0;
}
while (XCAM_SUCCESS != ret && count < MAX_WAIT_COUNT) {
ret = xcam_mbuf_read_pack(handle, payload_type, &pack_info);
if (XCAM_SUCCESS == ret) {
*ppts = pack_info.pts;
xcam_mbuf_forward(handle, XCAM_MBUF_PAYLOAD_TYPE_ALL, 0);
break;
}
usleep(10 * 1000);
count++;
}
return ret;
}
#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif /* End of #ifdef __cplusplus */
+66
View File
@@ -0,0 +1,66 @@
/*
* Copyright (c) XCAM. All rights reserved.
*/
#ifndef _LIVESTREAM_MBUFFER_H_
#define _LIVESTREAM_MBUFFER_H_
#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif
#endif /* End of #ifdef __cplusplus */
#include "xcam_mbuf.h"
#include "pthread.h"
typedef enum {
MBUFFER_DATA_VIDEO = 1,
MBUFFER_DATA_AUDIO,
MBUFFER_DATA_DATA,
MBUFFER_DATA_BUTT
} livestream_mbuffer_data_type;
typedef struct {
pthread_mutex_t mutex; /* lock for mbuffer write pos */
} livestream_mbuffer_info;
enum {
BUF_PAYLOAD_G711U = 0, /**< G.711 Mu */
BUF_PAYLOAD_G711A = 8, /**< G.711 A */
BUF_PAYLOAD_G726 = 97, /**< G.726 */
BUF_PAYLOAD_H264 = 96, /**< H264 */
BUF_PAYLOAD_H265 = 98, /**< H265 */
BUF_PAYLOAD_ADPCM = 104, /**< ADPCM */
BUF_PAYLOAD_AAC = 105, /**< AAC encoder */
BUF_PAYLOAD_MP3 = 109, /**< MP3 encoder */
BUF_PAYLOAD_BUTT /**< invalid */
};
xcam_s32 livestream_mbuffer_write_frame(xcam_void* handle, const xcam_mbuf_pack_info* pack_info);
xcam_s32 livestream_mbuffer_create(const xcam_void* argv, xcam_void** buf_handle,
xcam_u32 buf_size, xcam_s32 max_payload);
xcam_s32 livestream_mbuffer_destroy(xcam_void* argv, xcam_void* handle);
xcam_s32 livestream_mbuffer_register(xcam_void* handle, xcam_u8 media_type);
xcam_s32 livestream_mbuffer_unregister(xcam_void* handle, xcam_u8 media_type);
xcam_s32 livestream_mbuffer_read(xcam_void* handle, xcam_void** paddr, xcam_u32* plen,
xcam_u64* ppts, livestream_mbuffer_data_type* type, xcam_bool* ptr_bkey_flag);
xcam_s32 livestream_mbuffer_set(xcam_void* handle, xcam_u32 step);
xcam_s32 livestream_mbuffer_pts(xcam_void* handle, xcam_u8 payload_type, xcam_u64* ppts);
#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif /* End of #ifdef __cplusplus */
#endif /* _LIVESTREAM_MBUFFER_H_ */
@@ -0,0 +1,96 @@
/*
* Copyright (c) XCAM. All rights reserved.
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "livestream_comm.h"
#include "xcam_livestream_rtsp_server.h"
#include "livestream_rtcp_session.h"
#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif
#endif /* __cplusplus */
xcam_s32 livestream_rtcp_session_start_udp(livestream_rtcp_session* rtcp_session)
{
xcam_s32 sockfd = 0;
/*send rtcp socket*/
sockfd = livestream_comm_open_udp_socket(rtcp_session->server_rtcp_port);
if (INVALID_SOCKET == sockfd) {
LOG_LIVESTREAM_ERROR("open udp socket failed from port:%d.\n", rtcp_session->server_rtcp_port);
return XCAM_FAILURE;
}
rtcp_session->rtcp_send_sock = sockfd;
return XCAM_SUCCESS;
}
xcam_s32 livestream_rtcp_session_stop_udp(livestream_rtcp_session* rtcp_session)
{
if (XCAM_NULL == rtcp_session) {
LOG_LIVESTREAM_ERROR("param rtcp_session is null\n");
return XCAM_FAILURE;
}
livestream_comm_close_socket(&rtcp_session->rtcp_send_sock);
return XCAM_SUCCESS;
}
xcam_s32 livestream_rtcp_session_create(livestream_rtcp_session** pptr_session, xcam_s32 packet_len)
{
if (packet_len <= 0) {
LOG_LIVESTREAM_ERROR("rtcp_session packlen less than 0! \n");
return XCAM_FAILURE;
}
livestream_rtcp_session* rtcp_session;
rtcp_session = (livestream_rtcp_session*)malloc(sizeof(livestream_rtcp_session));
if (!rtcp_session) {
LOG_LIVESTREAM_ERROR("dynamic alloc for rtcp session failed\n");
return XCAM_FAILURE;
}
memset(rtcp_session, 0x00, sizeof(livestream_rtcp_session));
rtcp_session->pack_buff = (xcam_char*)malloc(packet_len);
if (!rtcp_session->pack_buff) {
LOG_LIVESTREAM_ERROR("dynamic alloc for pack_buff failed\n");
free(rtcp_session);
rtcp_session = XCAM_NULL;
return XCAM_FAILURE;
}
memset(rtcp_session->pack_buff, 0x00, packet_len);
*pptr_session = rtcp_session;
return XCAM_SUCCESS;
}
xcam_s32 livestream_rtcp_session_destroy(livestream_rtcp_session* rtcp_session)
{
if (XCAM_NULL == rtcp_session) {
LOG_LIVESTREAM_ERROR("param rtcp_session is null !\n");
return XCAM_FAILURE;
}
if (rtcp_session->pack_buff) {
free(rtcp_session->pack_buff);
rtcp_session->pack_buff = XCAM_NULL;
}
free(rtcp_session);
rtcp_session = XCAM_NULL;
return XCAM_SUCCESS;
}
#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif /* __cplusplus */
@@ -0,0 +1,38 @@
/*
* Copyright (c) XCAM. All rights reserved.
*/
#ifndef _LIVESTREAM_RTCP_SESSION_H_
#define _LIVESTREAM_RTCP_SESSION_H_
#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif
#endif /* End of #ifdef __cplusplus */
typedef struct {
xcam_s32 rtcp_send_sock;
xcam_s32 client_rtcp_port;
xcam_s32 server_rtcp_port;
xcam_u32 seq_num;
xcam_u32 data_len;
xcam_s32 packet_len;
xcam_char* pack_buff;
} livestream_rtcp_session;
xcam_s32 livestream_rtcp_session_start_udp(livestream_rtcp_session* rtcp_session);
xcam_s32 livestream_rtcp_session_stop_udp(livestream_rtcp_session* rtcp_session);
xcam_s32 livestream_rtcp_session_create(livestream_rtcp_session** rtcp_session, xcam_s32 packet_len);
xcam_s32 livestream_rtcp_session_destroy(livestream_rtcp_session* rtcp_session);
#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif /* End of #ifdef __cplusplus */
#endif /*_LIVESTREAM_RTCP_SESSION_H_*/
+980
View File
@@ -0,0 +1,980 @@
/*
* Copyright (c) XCAM. All rights reserved.
*/
#include <string.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include "livestream_comm.h"
#include "xcam_livestream_rtsp_server.h"
#include "livestream_mbuffer.h"
#include "livestream_rtp_session.h"
#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif
#endif /* __cplusplus */
/* audio specific header len is 4, see rfc2550*/
static const xcam_u32 g_audio_specific_header_len = 4;
/* increase 128 bytes when current rtp packet buf is over full */
static const xcam_u32 g_rtp_packet_buf_step_len = 128;
#define RTP_VERSION 2
#define RTP_DEFAULT_SSRC 41030
#define RTP_TRANS_TIMEVAL_SEC (5)
#define RTP_TRANS_TIMEVAL_USEC (0)
#define RTP_TRANS_STREAM_VIDEO (0)
#define RTP_TRANS_STREAM_AUDIO (1)
#define RTP_TRANS_STREAM_DATA (2)
#define RTP_TRANS_STREAM_MAX (3)
static xcam_void rtp_packet_hdr(xcam_char* pack_addr, xcam_u32 timestamp, xcam_u32 marker,
rtp_payload_type payload_type, xcam_u32 ssrc, xcam_u16 last_sn)
{
rtp_pack_hdr* rtp_hdr = NULL;
rtp_hdr = (rtp_pack_hdr*)pack_addr;
RTP_HDR_SET_VERSION(rtp_hdr, RTP_VERSION);
RTP_HDR_SET_P(rtp_hdr, 0); /*no padding*/
RTP_HDR_SET_X(rtp_hdr, 0); /*no extension*/
RTP_HDR_SET_CC(rtp_hdr, 0); /*0 CSRC*/
RTP_HDR_SET_M(rtp_hdr, marker);
RTP_HDR_SET_PT(rtp_hdr, payload_type);
RTP_HDR_SET_SEQNO(rtp_hdr, htons(last_sn));
RTP_HDR_SET_TS(rtp_hdr, htonl(timestamp));
RTP_HDR_SET_SSRC(rtp_hdr, htonl(ssrc));
return;
}
static xcam_s32 rtp_send_to_sockfd(xcam_s32 write_sock, const xcam_char* buffer,
xcam_u32 data_len, const struct sockaddr_in* peer_sock_addr)
{
const xcam_char* buffer_pos = NULL;
struct timeval timeout_val;
xcam_u32 rem_size = 0;
xcam_s32 err_num = 0;
xcam_s32 size = 0;
xcam_s32 ret = 0;
fd_set write_fds;
memset(&timeout_val, 0, sizeof(struct timeval));
rem_size = data_len;
buffer_pos = buffer;
while (rem_size > 0) {
FD_ZERO(&write_fds);
FD_SET(write_sock, &write_fds);
timeout_val.tv_sec = RTP_TRANS_TIMEVAL_SEC;
timeout_val.tv_usec = RTP_TRANS_TIMEVAL_USEC;
/*judge if it can send */
ret = select(write_sock + 1, NULL, &write_fds, NULL, &timeout_val);
/*select found over time or error happend*/
if (0 == ret) {
err_num = errno;
LOG_LIVESTREAM_ERROR("send media rtp data timeout,errno=%d,%s\n",
errno, strerror(err_num));
return XCAM_FAILURE;
} else if (0 > ret) {
if (EINTR == errno || EAGAIN == errno) {
LOG_LIVESTREAM_ERROR("select error: %s\n", strerror(errno));
continue;
}
err_num = errno;
LOG_LIVESTREAM_ERROR("send media rtp data, select error: %s", strerror(err_num));
return XCAM_FAILURE;
}
if (!FD_ISSET(write_sock, &write_fds)) {
err_num = errno;
LOG_LIVESTREAM_ERROR("send media rtp data error: write fd not in fdset! error:%s\n",
strerror(err_num));
return XCAM_FAILURE;
}
/*select ok and fd isset ok*/
if (peer_sock_addr == NULL) {
size = send(write_sock, buffer_pos, rem_size, MSG_DONTWAIT);
} else {
size = sendto(write_sock, buffer_pos, rem_size, 0,
(struct sockaddr*)peer_sock_addr, sizeof(struct sockaddr));
}
if (size < 0) {
/*if it is not eagain error, means can not send*/
if (errno != EINTR && errno != EAGAIN) {
err_num = errno;
LOG_LIVESTREAM_ERROR("send media data(%u Byte) error: %s\n", data_len, strerror(err_num));
return XCAM_FAILURE;
}
/*it is eagain error, means can try again*/
continue;
}
rem_size -= size;
buffer_pos += size;
}
return XCAM_SUCCESS;
}
static xcam_void rtp_rtsp_itlv_packet(xcam_char* ptr_pack_addr, xcam_s32 channel,
xcam_u32 pack_len, xcam_u32 timestamp, xcam_u32 marker,
rtp_payload_type payload_type, xcam_u32 ssrc, xcam_u16 last_sn)
{
rtsp_itleaved_hdr* ptr_rtsp_itlv_hdr = XCAM_NULL;
ptr_rtsp_itlv_hdr = (rtsp_itleaved_hdr*)ptr_pack_addr;
ptr_rtsp_itlv_hdr->daollar = '$';
ptr_rtsp_itlv_hdr->chn_id = channel;
/* rtsp payload len represent the later packet lengthpacket len = rtp head + data len */
ptr_rtsp_itlv_hdr->payload_len = htons((xcam_u16)(pack_len - sizeof(rtsp_itleaved_hdr) + sizeof(rtp_pack_hdr)));
/* packet rtp packet */
rtp_packet_hdr((xcam_char*)(&(ptr_rtsp_itlv_hdr->rtp_head)), timestamp, marker, payload_type, ssrc, last_sn);
return;
}
/*
FU-A
FU indicator
+---------------+
|0|1|2|3|4|5|6|7|
+-+-+-+-+-+-+-+-+
|F|NRI| Type |
+---------------+
FU header
+---------------+
|0|1|2|3|4|5|6|7|
+-+-+-+-+-+-+-+-+
|S|E|R| Type |
+---------------+
Type Packet Type name
---------------------------------------------------------
0 undefined -
1-23 NAL unit Single NAL unit packet per H.264
24 STAP-A Single-time aggregation packet
25 STAP-B Single-time aggregation packet
26 MTAP16 Multi-time aggregation packet
27 MTAP24 Multi-time aggregation packet
28 FU-A Fragmentation unit
29 FU-B Fragmentation unit
30-31 undefined -
*/
static xcam_s32 rtp_fu_package_header(xcam_char* ptr_header, xcam_u8* ptr_message,
xcam_u8 start, xcam_u8 end)
{
xcam_s32 head_len = 0;
xcam_u8 nal_type;
xcam_u8 nri;
if (XCAM_NULL == ptr_header || XCAM_NULL == ptr_message) {
LOG_LIVESTREAM_ERROR("ptr_header=%p ptr_message=%p\n", ptr_header, ptr_message);
fflush(stdout);
return XCAM_FAILURE;
}
if ((1 == start && 1 == end) || start > 1 || end > 1) {
LOG_LIVESTREAM_ERROR("start=%d, end=%d\n", start, end);
fflush(stdout);
return XCAM_FAILURE;
}
if ((*ptr_message != 0 || *(ptr_message + 1) != 0 || *(ptr_message + 2) != 0 || *(ptr_message + 3) != 1)
&& (*ptr_message != 0 || *(ptr_message + 1) != 0 || *(ptr_message + 2) != 1)) {
LOG_LIVESTREAM_ERROR("this package is not have NALU!\n");
fflush(stdout);
return XCAM_FAILURE;
}
if (*ptr_message == 0 && *(ptr_message + 1) == 0 && *(ptr_message + 2) == 0 && *(ptr_message + 3) == 1) {
head_len = 4;
} else if (*ptr_message == 0 && *(ptr_message + 1) == 0 && *(ptr_message + 2) == 1) {
head_len = 3;
} else {
fflush(stdout);
return XCAM_FAILURE;
}
nri = (ptr_message[head_len] & 0x60) >> 5;
nal_type = ptr_message[head_len] & 0x1F;
*ptr_header = 0;
*ptr_header = nri << 5 | 0x1c;/*NAL is 0x1c=28means FUA*/
*(ptr_header + 1) = 0;
*(ptr_header + 1) = start << 7 | end << 6 | nal_type;
return XCAM_SUCCESS;
}
static xcam_s32 rtp_session_start_tcp_itlv(livestream_rtp_session* rtp_session)
{
if ( RTP_SESSION_STATE_READY == rtp_session->session_state ) {
rtp_session->session_state = RTP_SESSION_STATE_PLAY;
} else if ( RTP_SESSION_STATE_PLAY == rtp_session->session_state) {
/*do nothing*/
} else {
LOG_LIVESTREAM_ERROR("start video error: video is in not ready state.\n");
return XCAM_FAILURE;
}
return XCAM_SUCCESS;
}
static xcam_s32 rtp_session_start_udp(livestream_rtp_session* rtp_session)
{
xcam_s32 temp_sock = 0;
if (RTP_SESSION_STATE_READY == rtp_session->session_state) {
/*send rtp socket*/
temp_sock = livestream_comm_open_udp_socket(rtp_session->server_rtp_port);
if (-1 == temp_sock) {
LOG_LIVESTREAM_ERROR("error:get socket from port%d.\n", rtp_session->server_rtp_port);
return XCAM_FAILURE;
}
rtp_session->rtp_send_sock = temp_sock;
livestream_comm_get_peer_sockaddr(rtp_session->client_ip, rtp_session->client_rtp_port, &(rtp_session->client_sockaddr));
rtp_session->session_state = RTP_SESSION_STATE_PLAY;
} else if ( RTP_SESSION_STATE_PLAY == rtp_session->session_state) {
/*do nothing*/
} else {
LOG_LIVESTREAM_ERROR("start video error: video is in not ready state.\n");
return XCAM_FAILURE;
}
return XCAM_SUCCESS;
}
xcam_s32 livestream_rtp_session_update_seq_num(livestream_rtp_session* rtp_session, xcam_u32 seq_num)
{
/*check the appointed task exit or not*/
if (XCAM_NULL == rtp_session) {
LOG_LIVESTREAM_ERROR("get RTP rtp_session NULL.\n");
return XCAM_FAILURE;
}
rtp_session->seq_num = seq_num;
return XCAM_SUCCESS;
}
xcam_s32 livestream_rtp_session_get_packet_and_send_param(livestream_rtp_session* rtp_session, xcam_s32* ptr_write_sock,
struct sockaddr_in* ptr_peer_sockaddr, xcam_u32* ptr_last_sn,
rtp_pack_type* ptr_pack_type, xcam_u32* ptr_ssrc)
{
xcam_s32 ret = 0;
rtp_trans_mode trans_mode = RTP_TRANS_BUTT;
trans_mode = rtp_session->media_trans_mode;
/*1 get packet type*/
/*if stream waiting packet is video and vidieo is in playing state,
stream can be packeted*/
/*packet the stream according to different packet type */
*ptr_pack_type = rtp_session->pack_type;
*ptr_ssrc = rtp_session->ssrc;
if (RTP_TRANS_TCP_ITLV == trans_mode) {
*ptr_write_sock = rtp_session->rtp_send_sock;
*ptr_last_sn = rtp_session->seq_num;
} else if (RTP_TRANS_UDP == trans_mode) { /*the branch must be udp transport*/
*ptr_write_sock = rtp_session->rtp_send_sock;
memcpy(ptr_peer_sockaddr, &(rtp_session->client_sockaddr), sizeof(struct sockaddr_in));
*ptr_last_sn = rtp_session->seq_num;
} else if (RTP_TRANS_BROADCAST == trans_mode) {
*ptr_write_sock = rtp_session->rtp_send_sock;
memcpy(ptr_peer_sockaddr, &(rtp_session->client_sockaddr), sizeof(struct sockaddr_in));
*ptr_last_sn = rtp_session->seq_num;
} else {
LOG_LIVESTREAM_ERROR("unsupport trans type in send trans_mode:%d.\n", trans_mode);
return ret;
}
return XCAM_SUCCESS;
}
xcam_s32 livestream_rtp_session_send_data_in_rtsp_itlv(livestream_rtp_session* rtp_session, const xcam_u8* data_addr,
xcam_u32 data_len, xcam_u32 ts, rtp_payload_type rtp_type, xcam_u32* seq_num, xcam_u32 ssrc,
xcam_s32 write_sock, struct sockaddr_in* peer_sockaddr, xcam_s32 packet_len)
{
xcam_char* tmp_pack_buf = rtp_session->pack_buffer;
const xcam_u8* pack_data_addr = data_addr;
xcam_u32 pack_payload_len = packet_len;
xcam_u32 current_seq_num = *seq_num;
xcam_u32 rtp_send_len = 0;
xcam_u32 package_len = 0;
xcam_u32 send_len = 0;
xcam_s32 channel = 0;
xcam_u8 marker = 0;
xcam_s32 ret = 0;
if (pack_data_addr == XCAM_NULL) {
LOG_LIVESTREAM_ERROR("param pack_data_addr is null\n");
return XCAM_FAILURE;
}
if (rtp_type == RTP_PT_H264) {
/*juege the slice data head length*/
xcam_u32 slice_head_len = 0;
/*H264 slice data header length*/
if ((0x00 == (xcam_u8)data_addr[0]) && (0x00 == (xcam_u8)data_addr[1])) {
if ((0x00 == (xcam_u8)data_addr[2]) && (0x01 == (xcam_u8)data_addr[3])) {
slice_head_len = 5;
}
if (0x01 == (xcam_u8)data_addr[2]) {
slice_head_len = 4;
}
} else {
LOG_LIVESTREAM_INFO("Unknow H264 Nalu Head:%x %x %x %x %x \n",
data_addr[0], data_addr[1], data_addr[2], data_addr[3], data_addr[4]);
slice_head_len = 5;
}
channel = rtp_session->itlv_client_media_chnid;
/*when the frame data length is less than the packetsize 1500*/
if (data_len - (slice_head_len - 1) + sizeof(rtsp_itleaved_hdr) <= pack_payload_len) {
send_len = data_len - (slice_head_len - 1);
rtp_send_len = send_len + sizeof( rtsp_itleaved_hdr );
/*payload data should cut the 4 bytes head :00 00 00 01*/
memcpy(tmp_pack_buf + sizeof(rtsp_itleaved_hdr),
pack_data_addr + slice_head_len - 1, send_len);
/*form the rtp itlv head */
if (0x65 == (xcam_u8)data_addr[slice_head_len - 1] || 0x61 == (xcam_u8)data_addr[slice_head_len - 1]) {
rtp_rtsp_itlv_packet(tmp_pack_buf, channel, rtp_send_len, ts, 1, rtp_type, ssrc, current_seq_num++);
} else {
rtp_rtsp_itlv_packet(tmp_pack_buf, channel, rtp_send_len, ts, 0, rtp_type, ssrc, current_seq_num++);
}
/*send the rtp packet */
ret = rtp_send_to_sockfd(write_sock, tmp_pack_buf, rtp_send_len, peer_sockaddr);
if (XCAM_SUCCESS != ret) {
LOG_LIVESTREAM_ERROR("RTP video send error\n");
return ret;
}
} else { /*when the frame data length is larger than the packetsize 1500 */
/*need to cut the frame into several rtp packets*/
while (package_len < data_len) {
if (pack_payload_len >= sizeof(rtsp_itleaved_hdr) + 2 + data_len - package_len) {
send_len = data_len - package_len;
marker = 1;
} else {
send_len = pack_payload_len - sizeof(rtsp_itleaved_hdr) - 2;
marker = 0;
}
rtp_send_len = send_len + sizeof( rtsp_itleaved_hdr ) + 2;
if (package_len == 0) { /*the first package*/
package_len += slice_head_len;
pack_data_addr += slice_head_len;
ret = rtp_fu_package_header(tmp_pack_buf + sizeof( rtsp_itleaved_hdr ) , (xcam_u8*)data_addr, 1, 0);
} else if ((package_len + send_len) < data_len) { /*in the middle packages*/
ret = rtp_fu_package_header(tmp_pack_buf + sizeof( rtsp_itleaved_hdr ), (xcam_u8*)data_addr, 0, 0);
marker = 0;
} else { /*the last package*/
ret = rtp_fu_package_header(tmp_pack_buf + sizeof( rtsp_itleaved_hdr ), (xcam_u8*)data_addr, 0, 1);
marker = 1;
}
if (XCAM_SUCCESS != ret) {
LOG_LIVESTREAM_ERROR("RTP FU Head pack error %d\n", ret);
return XCAM_FAILURE;
}
/*copy the data */
memcpy(tmp_pack_buf + sizeof( rtsp_itleaved_hdr ) + 2,
pack_data_addr, send_len);
/*form rtp itlv head*/
rtp_rtsp_itlv_packet(tmp_pack_buf, channel, rtp_send_len, ts, marker, rtp_type, ssrc, current_seq_num++);
ret = rtp_send_to_sockfd(write_sock, tmp_pack_buf, rtp_send_len, peer_sockaddr);
if (XCAM_SUCCESS != ret) {
LOG_LIVESTREAM_ERROR("RTP video send error\n");
return ret;
}
pack_data_addr += send_len; /*update the ptr to the frame data*/
package_len += send_len; /*update the send data length*/
}
}
} else if (RTP_PT_H265 == rtp_type) {
/*juege the slice data head length*/
xcam_u32 slice_head_len = 0;
/*H265 slice data header length*/
if ((0x00 == (xcam_u8)data_addr[0]) && (0x00 == (xcam_u8)data_addr[1])) {
if ((0x00 == (xcam_u8)data_addr[2]) && (0x01 == (xcam_u8)data_addr[3])) {
slice_head_len = 5;
}
if (0x01 == (xcam_u8)data_addr[2]) {
slice_head_len = 4;
}
} else {
LOG_LIVESTREAM_INFO("Unknow H264 Nalu Head:%x %x %x %x %x \n",
data_addr[0], data_addr[1], data_addr[2], data_addr[3], data_addr[4]);
slice_head_len = 5;
}
int nal_type = (data_addr[slice_head_len - 1] >> 1) & 0x3F;
channel = rtp_session->itlv_client_media_chnid;
/*when the frame data length is less than the packetsize 1500 */
if (data_len - (slice_head_len - 1) + sizeof(rtsp_itleaved_hdr) <= pack_payload_len) {
send_len = data_len - (slice_head_len - 1);
rtp_send_len = send_len + sizeof( rtsp_itleaved_hdr );
/*payload data should cut the 4 bytes head :00 00 00 01*/
memcpy(tmp_pack_buf + sizeof(rtsp_itleaved_hdr),
pack_data_addr + slice_head_len - 1, send_len);
if (0x26 == (xcam_u8)data_addr[slice_head_len - 1] || 0x02 == (xcam_u8)data_addr[slice_head_len - 1]) {
rtp_rtsp_itlv_packet(tmp_pack_buf, channel, rtp_send_len, ts, 1, rtp_type, ssrc, current_seq_num++);
} else {
rtp_rtsp_itlv_packet(tmp_pack_buf, channel, rtp_send_len, ts, 0, rtp_type, ssrc, current_seq_num++);
}
ret = rtp_send_to_sockfd(write_sock, tmp_pack_buf, rtp_send_len, peer_sockaddr);
if (XCAM_SUCCESS != ret) {
LOG_LIVESTREAM_ERROR("RTP video send error\n");
return ret;
}
} else { /*when the frame data length is larger than the packetsize 1500 */
tmp_pack_buf[sizeof(rtsp_itleaved_hdr)] = 49 << 1;
tmp_pack_buf[sizeof(rtsp_itleaved_hdr) + 1] = 1;
tmp_pack_buf[sizeof(rtsp_itleaved_hdr) + 2] = nal_type;
/*need to cut the frame into several rtp packets*/
while (package_len < data_len) {
if (pack_payload_len >= sizeof(rtsp_itleaved_hdr) + 3 + data_len - package_len) {
send_len = data_len - package_len;
marker = 1;
} else {
send_len = pack_payload_len - sizeof(rtsp_itleaved_hdr) - 3;
marker = 0;
}
rtp_send_len = send_len + sizeof( rtsp_itleaved_hdr ) + 3;
if (package_len == 0) { /*the first package*/
package_len += slice_head_len + 1;
pack_data_addr += slice_head_len + 1;
tmp_pack_buf[sizeof(rtsp_itleaved_hdr) + 2] |= 1 << 7;
} else if ((package_len + send_len) < data_len) { /* in the middle packages*/
marker = 0;
tmp_pack_buf[sizeof(rtsp_itleaved_hdr) + 2] &= ~(1 << 7);
} else { /*the last package*/
marker = 1;
tmp_pack_buf[sizeof(rtsp_itleaved_hdr) + 2] &= ~(1 << 7);
tmp_pack_buf[sizeof(rtsp_itleaved_hdr) + 2] |= 1 << 6;
}
memcpy(tmp_pack_buf + sizeof( rtsp_itleaved_hdr ) + 3, pack_data_addr, send_len);
/*form rtp itlv head*/
rtp_rtsp_itlv_packet(tmp_pack_buf, channel, rtp_send_len, ts, marker, rtp_type, ssrc, current_seq_num++);
ret = rtp_send_to_sockfd(write_sock, tmp_pack_buf, rtp_send_len, peer_sockaddr);
if (XCAM_SUCCESS != ret) {
LOG_LIVESTREAM_ERROR("RTP video send error\n");
return ret;
}
pack_data_addr += send_len; /*update the ptr to the frame data*/
package_len += send_len; /*update the send data length*/
}
}
} else if (RTP_PT_PCMA == rtp_type || RTP_PT_PCMU == rtp_type || RTP_PT_G726 == rtp_type) {
/*audio do not cut into packets*/
if (data_len >= (pack_payload_len - sizeof( rtsp_itleaved_hdr ))) {
if (rtp_session->pack_buffer) {
free(rtp_session->pack_buffer);
rtp_session->pack_buffer = XCAM_NULL;
}
rtp_session->pack_buffer = (xcam_char*)malloc((data_len + 128));
if (XCAM_NULL == rtp_session->pack_buffer) {
LOG_LIVESTREAM_ERROR("dynamic alloc fail!\n");
return XCAM_FAILURE;
}
tmp_pack_buf = rtp_session->pack_buffer;
}
channel = rtp_session->itlv_client_media_chnid;
send_len = data_len;
rtp_send_len = send_len + sizeof(rtsp_itleaved_hdr);
memcpy(tmp_pack_buf + sizeof(rtsp_itleaved_hdr), pack_data_addr, send_len);
/*form the rtp head*/
rtp_rtsp_itlv_packet(tmp_pack_buf, channel, rtp_send_len, ts, 0, rtp_type, ssrc, current_seq_num++);
/*send the audio data*/
ret = rtp_send_to_sockfd(write_sock, tmp_pack_buf, rtp_send_len, peer_sockaddr);
if (XCAM_SUCCESS != ret) {
LOG_LIVESTREAM_ERROR("RTP audio send error\n");
return ret;
}
} else if (RTP_PT_AAC == rtp_type) {
if ((data_len - 7) >= (pack_payload_len - sizeof( rtsp_itleaved_hdr ) - 4)) {
if (rtp_session->pack_buffer) {
free(rtp_session->pack_buffer);
rtp_session->pack_buffer = XCAM_NULL;
}
rtp_session->pack_buffer = (xcam_char*)malloc((data_len + 128));
if (XCAM_NULL == rtp_session->pack_buffer) {
LOG_LIVESTREAM_ERROR("dynamic alloc fail!\n");
return XCAM_FAILURE;
}
tmp_pack_buf = rtp_session->pack_buffer;
}
channel = rtp_session->itlv_client_media_chnid;
/*payload data should cut the first 7 bytes ADTS header */
send_len = data_len - 7 + 4;
rtp_send_len = send_len + sizeof( rtsp_itleaved_hdr );
/*add 4 bytes au header*/
*(tmp_pack_buf + sizeof( rtsp_itleaved_hdr )) = 0x00;
*(tmp_pack_buf + sizeof( rtsp_itleaved_hdr ) + 1) = 0x10;
*(tmp_pack_buf + sizeof( rtsp_itleaved_hdr ) + 2) = ((data_len - 7) & 0x1fe0) >> 5;
*(tmp_pack_buf + sizeof( rtsp_itleaved_hdr ) + 3) = ((data_len - 7) & 0x1f) << 3;
memcpy(tmp_pack_buf + sizeof( rtsp_itleaved_hdr ) + 4,
pack_data_addr + 7, data_len - 7);
/*add rtp head */
rtp_rtsp_itlv_packet(tmp_pack_buf, channel, rtp_send_len, ts, 1, rtp_type, ssrc, current_seq_num++);
/*send the data */
ret = rtp_send_to_sockfd(write_sock, tmp_pack_buf, rtp_send_len, peer_sockaddr);
if (XCAM_SUCCESS != ret) {
LOG_LIVESTREAM_ERROR("RTP video send error\n");
return ret;
}
} else if (rtp_type == RTP_PT_MPA) {
if (data_len >= (pack_payload_len - sizeof(rtsp_itleaved_hdr) - g_audio_specific_header_len)) {
if (rtp_session->pack_buffer) {
free(rtp_session->pack_buffer);
rtp_session->pack_buffer = XCAM_NULL;
}
rtp_session->pack_buffer = (xcam_char*)malloc((data_len + g_rtp_packet_buf_step_len));
if (rtp_session->pack_buffer == XCAM_NULL) {
LOG_LIVESTREAM_ERROR("dynamic alloc fail!\n");
return XCAM_FAILURE;
}
tmp_pack_buf = rtp_session->pack_buffer;
}
send_len = data_len + g_audio_specific_header_len;
rtp_send_len = send_len + sizeof( rtsp_itleaved_hdr );
xcam_u32 *audioSpecHeader = (xcam_u32 *)(tmp_pack_buf + sizeof(rtsp_itleaved_hdr));
*audioSpecHeader = 0;/* MBZ is reserved, and frag offset is 0, so audio specific header is 0 */
memcpy(tmp_pack_buf + sizeof(rtsp_itleaved_hdr) + g_audio_specific_header_len,
pack_data_addr, data_len);
marker = 1; /* mpa maker should be 1, see rfc2550 */
rtp_rtsp_itlv_packet(tmp_pack_buf, channel, rtp_send_len, ts, marker, rtp_type, ssrc, current_seq_num++);
ret = rtp_send_to_sockfd(write_sock, tmp_pack_buf, rtp_send_len, peer_sockaddr);
if (ret != XCAM_SUCCESS) {
LOG_LIVESTREAM_ERROR("RTP video send error\n");
return ret;
}
} else {
/*media type do not support*/
LOG_LIVESTREAM_ERROR("unsupport stream type:%d\n", rtp_type);
return XCAM_FAILURE;
}
*seq_num = current_seq_num; /*update the seq when send several packet inside*/
return XCAM_SUCCESS;
}
xcam_s32 livestream_rtp_session_send_data_in_rtp(livestream_rtp_session* session, const xcam_u8* data_addr,
xcam_u32 data_len, xcam_u32 ts, rtp_payload_type package_type, xcam_u32* seq_num,
xcam_u32 ssrc, xcam_s32 write_sock, const struct sockaddr_in* peer_sockaddr, xcam_s32 packet_len)
{
xcam_char* tmp_pack_buf = session->pack_buffer;
const xcam_u8* pack_data_addr = data_addr;
xcam_u32 pack_payload_len = packet_len;
xcam_u32 current_seq_num = *seq_num;
xcam_u32 package_len = 0;
xcam_u32 rtp_send_len = 0;
xcam_u32 send_len = 0;
xcam_u8 marker = 0;
xcam_s32 ret = 0;
if (RTP_PT_H264 == package_type) {
xcam_u32 slice_head_len = 0;
/*H264 head length */
if ((0x00 == (xcam_u8)data_addr[0]) && (0x00 == (xcam_u8)data_addr[1])) {
if ((0x00 == (xcam_u8)data_addr[2]) && (0x01 == (xcam_u8)data_addr[3])) {
slice_head_len = 5;
}
if (0x01 == (xcam_u8)data_addr[2]) {
slice_head_len = 4;
}
} else {
LOG_LIVESTREAM_INFO("Unknow H264 Nalu Head:%x %x %x %x %x \n",
data_addr[0], data_addr[1], data_addr[2], data_addr[3], data_addr[4]);
slice_head_len = 5;
}
/*datalen less than packet length*/
if (data_len - (slice_head_len - 1) + sizeof(rtp_pack_hdr) <= pack_payload_len) {
send_len = data_len - (slice_head_len - 1);
rtp_send_len = send_len + sizeof( rtp_pack_hdr );
/*payload data cut the first 4 bytres head ::00 00 00 01*/
memcpy(tmp_pack_buf + sizeof( rtp_pack_hdr ),
pack_data_addr + slice_head_len - 1, send_len);
/*add rtp head*/
if (0x65 == (xcam_u8)data_addr[slice_head_len - 1] || 0x61 == (xcam_u8)data_addr[slice_head_len - 1]) {
rtp_packet_hdr(tmp_pack_buf, ts, 1, package_type, ssrc, current_seq_num++);
} else {
rtp_packet_hdr(tmp_pack_buf, ts, 0, package_type, ssrc, current_seq_num++);
}
/*send the data */
ret = rtp_send_to_sockfd(write_sock, tmp_pack_buf, rtp_send_len, peer_sockaddr);
if (XCAM_SUCCESS != ret) {
LOG_LIVESTREAM_ERROR("RTP video send error\n");
return ret;
}
} else { /*when the frame data is larger than packet length*/
while (package_len < data_len) {
if (pack_payload_len >= sizeof(rtp_pack_hdr) + 2 + data_len - package_len) {
send_len = data_len - package_len;
marker = 1;
} else {
send_len = pack_payload_len - sizeof(rtp_pack_hdr) - 2;
marker = 0;
}
rtp_send_len = send_len + sizeof( rtp_pack_hdr ) + 2;
if (package_len == 0) { /*the first package*/
package_len += slice_head_len;
pack_data_addr += slice_head_len;
ret = rtp_fu_package_header(tmp_pack_buf + sizeof( rtp_pack_hdr ) , (xcam_u8*)data_addr, 1, 0);
} else if ((pack_payload_len == rtp_send_len) && ((package_len + send_len) < data_len)) { // in the middle packages
ret = rtp_fu_package_header(tmp_pack_buf + sizeof( rtp_pack_hdr ), (xcam_u8*)data_addr, 0, 0);
marker = 0;
} else { /*the last package*/
ret = rtp_fu_package_header(tmp_pack_buf + sizeof( rtp_pack_hdr ), (xcam_u8*)data_addr, 0, 1);
marker = 1;
}
if (XCAM_SUCCESS != ret) {
LOG_LIVESTREAM_ERROR("RTP FU Head pack error %d\n", ret);
return XCAM_FAILURE;
}
/*cp the data*/
memcpy(tmp_pack_buf + sizeof( rtp_pack_hdr ) + 2, pack_data_addr, send_len);
/*add the rtp head*/
rtp_packet_hdr(tmp_pack_buf, ts, marker, package_type, ssrc, current_seq_num++);
ret = rtp_send_to_sockfd(write_sock, tmp_pack_buf, rtp_send_len, peer_sockaddr);
if (XCAM_SUCCESS != ret) {
LOG_LIVESTREAM_ERROR("RTP video send error\n");
return ret;
}
pack_data_addr += send_len;
package_len += send_len;
}
}
} else if (RTP_PT_H265 == package_type) {
xcam_u32 slice_head_len = 0;
/*H265 slice head length*/
if ((0x00 == (xcam_u8)data_addr[0]) && (0x00 == (xcam_u8)data_addr[1])) {
if ((0x00 == (xcam_u8)data_addr[2]) && (0x01 == (xcam_u8)data_addr[3])) {
slice_head_len = 5;
}
if (0x01 == (xcam_u8)data_addr[2]) {
slice_head_len = 4;
}
} else {
LOG_LIVESTREAM_INFO("Unknow H265 Nalu Head:%x %x %x %x %x \n",
data_addr[0], data_addr[1], data_addr[2], data_addr[3], data_addr[4]);
slice_head_len = 5;
}
xcam_s32 nal_type = (data_addr[slice_head_len - 1] >> 1) & 0x3F;
/*frame date less than the packet length*/
if (data_len - (slice_head_len - 1) + sizeof(rtp_pack_hdr) <= pack_payload_len) {
send_len = data_len - (slice_head_len - 1);
rtp_send_len = send_len + sizeof( rtp_pack_hdr );
/*payload should cut the first 4 bytes head :00 00 00 01*/
memcpy(tmp_pack_buf + sizeof( rtp_pack_hdr ),
pack_data_addr + slice_head_len - 1, send_len);
/*rtpͷ*/
if (0x26 == (xcam_u8)data_addr[slice_head_len - 1] || 0x02 == (xcam_u8)data_addr[slice_head_len - 1]) {
rtp_packet_hdr(tmp_pack_buf, ts, 1, package_type, ssrc, current_seq_num++);
} else {
rtp_packet_hdr(tmp_pack_buf, ts, 0, package_type, ssrc, current_seq_num++);
}
/*send the data */
ret = rtp_send_to_sockfd(write_sock, tmp_pack_buf, rtp_send_len, peer_sockaddr);
if (XCAM_SUCCESS != ret) {
LOG_LIVESTREAM_ERROR("RTP video send error\n");
return ret;
}
} else { /*when the frame date is larger than packet length*/
tmp_pack_buf[sizeof(rtp_pack_hdr)] = 49 << 1;
tmp_pack_buf[sizeof(rtp_pack_hdr) + 1] = 1;
tmp_pack_buf[sizeof(rtp_pack_hdr) + 2] = nal_type;
while (package_len < data_len) {
if (pack_payload_len >= sizeof(rtp_pack_hdr) + 3 + data_len - package_len) {
send_len = data_len - package_len;
marker = 1;
} else {
send_len = pack_payload_len - sizeof(rtp_pack_hdr) - 3;
marker = 0;
}
rtp_send_len = send_len + sizeof( rtp_pack_hdr ) + 3;
if (package_len == 0) { /*the first package*/
package_len += slice_head_len + 1;
pack_data_addr += slice_head_len + 1;
tmp_pack_buf[sizeof(rtp_pack_hdr) + 2] |= 1 << 7;
} else if ((pack_payload_len == rtp_send_len) && ((package_len + send_len) < data_len)) { // in the middle packages
marker = 0;
tmp_pack_buf[sizeof(rtp_pack_hdr) + 2] &= ~(1 << 7);
} else { /*the last package*/
marker = 1;
tmp_pack_buf[sizeof(rtp_pack_hdr) + 2] &= ~(1 << 7);
tmp_pack_buf[sizeof(rtp_pack_hdr) + 2] |= 1 << 6;
}
/*copy the data */
memcpy(tmp_pack_buf + sizeof( rtp_pack_hdr ) + 3,
pack_data_addr, send_len);
/*add the rtp head */
rtp_packet_hdr(tmp_pack_buf, ts, marker, package_type, ssrc, current_seq_num++);
ret = rtp_send_to_sockfd(write_sock, tmp_pack_buf, rtp_send_len, peer_sockaddr);
if (XCAM_SUCCESS != ret) {
LOG_LIVESTREAM_ERROR("RTP video send error\n");
return ret;
}
pack_data_addr += send_len;
package_len += send_len;
}
}
} else if (RTP_PT_PCMA == package_type || RTP_PT_PCMU == package_type || RTP_PT_G726 == package_type) {
/*audio not cut */
if (data_len >= (pack_payload_len - sizeof( rtp_pack_hdr ))) {
if (session->pack_buffer) {
free(session->pack_buffer );
session->pack_buffer = XCAM_NULL;
}
session->pack_buffer = (xcam_char*)malloc((data_len + 128));
if (XCAM_NULL == session->pack_buffer) {
LOG_LIVESTREAM_ERROR("dynamic alloc fail!\n");
return XCAM_FAILURE;
}
tmp_pack_buf = session->pack_buffer;
}
send_len = data_len;
rtp_send_len = send_len + sizeof(rtp_pack_hdr);
memcpy(tmp_pack_buf + sizeof( rtp_pack_hdr ), pack_data_addr, send_len);
rtp_packet_hdr(tmp_pack_buf, ts, 0, package_type, ssrc, current_seq_num++);
ret = rtp_send_to_sockfd(write_sock, tmp_pack_buf, rtp_send_len, peer_sockaddr);
if (XCAM_SUCCESS != ret) {
LOG_LIVESTREAM_ERROR("RTP video send error\n");
return ret;
}
} else if (RTP_PT_AAC == package_type) {
if ((data_len - 7) >= (pack_payload_len - sizeof(rtp_pack_hdr) - 4)) {
if (session->pack_buffer) {
free(session->pack_buffer);
session->pack_buffer = XCAM_NULL;
}
session->pack_buffer = (xcam_char*)malloc( (data_len + 128));
if (XCAM_NULL == session->pack_buffer) {
LOG_LIVESTREAM_ERROR("dynamic alloc fail!\n");
return XCAM_FAILURE;
}
tmp_pack_buf = session->pack_buffer;
}
/*payload cut the first 7 BYTES ADTS head*/
send_len = data_len - 7 + 4;
rtp_send_len = send_len + sizeof( rtp_pack_hdr );
if (tmp_pack_buf == XCAM_NULL) {
return XCAM_FAILURE;
}
/*add 4 bytes au header*/
*(tmp_pack_buf + sizeof( rtp_pack_hdr )) = 0x00;
*(tmp_pack_buf + sizeof( rtp_pack_hdr ) + 1) = 0x10;
*(tmp_pack_buf + sizeof( rtp_pack_hdr ) + 2) = ((data_len - 7) & 0x1fe0) >> 5;
*(tmp_pack_buf + sizeof( rtp_pack_hdr ) + 3) = ((data_len - 7) & 0x1f) << 3;
memcpy(tmp_pack_buf + sizeof( rtp_pack_hdr ) + 4, pack_data_addr + 7, data_len - 7);
/*add rtp head */
rtp_packet_hdr(tmp_pack_buf, ts, 1, package_type, ssrc, current_seq_num++);
/*send the data */
ret = rtp_send_to_sockfd(write_sock, tmp_pack_buf, rtp_send_len, peer_sockaddr);
if (XCAM_SUCCESS != ret) {
LOG_LIVESTREAM_ERROR("RTP video send error\n");
return ret;
}
} else if (package_type == RTP_PT_MPA) {
if (data_len >= (pack_payload_len - sizeof(rtp_pack_hdr) - g_audio_specific_header_len)) {
if (session->pack_buffer) {
free(session->pack_buffer);
session->pack_buffer = XCAM_NULL;
}
session->pack_buffer = (xcam_char*)malloc((data_len + g_rtp_packet_buf_step_len));
if (session->pack_buffer == XCAM_NULL) {
LOG_LIVESTREAM_ERROR("dynamic alloc fail!\n");
return XCAM_FAILURE;
}
tmp_pack_buf = session->pack_buffer;
}
send_len = data_len + g_audio_specific_header_len;
rtp_send_len = send_len + sizeof( rtp_pack_hdr );
xcam_u32 *audioSpecHeader = (xcam_u32 *)(tmp_pack_buf + sizeof(rtp_pack_hdr));
*audioSpecHeader = 0;/* MBZ is reserved, and frag offset is 0, so audio specific header is 0 */
memcpy(tmp_pack_buf + sizeof(rtp_pack_hdr) + g_audio_specific_header_len,
pack_data_addr, data_len);
marker = 1; /* mpa maker should be 1, see rfc2550 */
rtp_packet_hdr(tmp_pack_buf, ts, marker, package_type, ssrc, current_seq_num++);
ret = rtp_send_to_sockfd(write_sock, tmp_pack_buf, rtp_send_len, peer_sockaddr);
if (ret != XCAM_SUCCESS) {
LOG_LIVESTREAM_ERROR("RTP video send error\n");
return ret;
}
} else {
/*not support type */
LOG_LIVESTREAM_ERROR("unsupport stream type:%d\n", package_type);
return XCAM_FAILURE;
}
*seq_num = current_seq_num; /*update the seq num */
return XCAM_SUCCESS;
}
xcam_s32 livestream_rtp_session_start(livestream_rtp_session* rtp_session)
{
xcam_s32 s32Ret = XCAM_SUCCESS;
if (XCAM_NULL == rtp_session) {
return XCAM_FAILURE;
}
/*if it is tcp trans type */
if (RTP_TRANS_TCP_ITLV == rtp_session->media_trans_mode) {
/*do not need create the socke while tcp_itlv cause the data trans sock is the same with session sock*/
s32Ret = rtp_session_start_tcp_itlv(rtp_session);
if (XCAM_SUCCESS != s32Ret) {
LOG_LIVESTREAM_ERROR("start task rtp_session_start_tcp_itlv fail %d.\n", s32Ret);
return s32Ret;
}
} else if (RTP_TRANS_UDP == rtp_session->media_trans_mode) {
/*if it is udp trans type, record corresponding info*/
s32Ret = rtp_session_start_udp(rtp_session);
if (XCAM_SUCCESS != s32Ret) {
LOG_LIVESTREAM_ERROR("start task rtp_session_start_udp fail %d.\n", s32Ret);
return s32Ret;
}
} else if (RTP_TRANS_TCP == rtp_session->media_trans_mode) {
/*if it is tcp trans type, record corresponding info*/
/*to do :add the part for tcp trans*/
LOG_LIVESTREAM_ERROR("start rtpSession error: not support tcp trans now.\n");
return XCAM_FAILURE;
} else {
LOG_LIVESTREAM_ERROR("start rtpSession error: unrecognized trans now.\n");
return XCAM_FAILURE;
}
return XCAM_SUCCESS;
}
xcam_s32 livestream_rtp_session_stop(livestream_rtp_session* rtp_session)
{
if (XCAM_NULL == rtp_session) {
LOG_LIVESTREAM_ERROR("Stop rtpSession error.\n");
return XCAM_FAILURE;
}
/*set all meida state as init*/
rtp_session->session_state = RTP_SESSION_STATE_STOP;
/*if it is tcp trans type*/
if (RTP_TRANS_TCP_ITLV == rtp_session->media_trans_mode) {
/*do nothing*/
} else if (RTP_TRANS_UDP == rtp_session->media_trans_mode) {
/*if it is udp trans type, record corresponding info*/
livestream_comm_close_socket(&rtp_session->rtp_send_sock);
} else if (RTP_TRANS_BROADCAST == rtp_session->media_trans_mode) {
/*if it is broadcast trans type, record corresponding info*/
livestream_comm_close_socket(&rtp_session->rtp_send_sock);
} else {
LOG_LIVESTREAM_ERROR(
"top trans task error: not unrecognized trans type %d.\n", rtp_session->media_trans_mode);
return XCAM_FAILURE;
}
return XCAM_SUCCESS;
}
xcam_s32 livestream_rtp_session_create(livestream_rtp_session** pptr_session, xcam_s32 packet_len)
{
livestream_rtp_session* ptr_rtp_session = XCAM_NULL;
if (packet_len <= 0) {
LOG_LIVESTREAM_ERROR("ptr_rtp_session packlen less than 0\n");
return XCAM_FAILURE;
}
ptr_rtp_session = (livestream_rtp_session*)malloc(sizeof(livestream_rtp_session));
if (!ptr_rtp_session) {
LOG_LIVESTREAM_ERROR("dynamic alloc for ptr_rtp_session failed\n");
return XCAM_FAILURE;
}
memset(ptr_rtp_session, 0x00, sizeof(livestream_rtp_session));
ptr_rtp_session->pack_buffer = (xcam_char*)malloc(packet_len);
if (!ptr_rtp_session->pack_buffer) {
LOG_LIVESTREAM_ERROR("dynamic alloc for pack_buffer failed\n");
free(ptr_rtp_session);
ptr_rtp_session = XCAM_NULL;
return XCAM_FAILURE;
}
memset(ptr_rtp_session->pack_buffer, 0x00, packet_len);
*pptr_session = ptr_rtp_session;
return XCAM_SUCCESS;
}
xcam_s32 livestream_rtp_session_destroy(livestream_rtp_session* rtp_session)
{
if (XCAM_NULL == rtp_session) {
LOG_LIVESTREAM_ERROR("param rtp_session is null !\n");
return XCAM_FAILURE;
}
if (rtp_session->pack_buffer) {
free(rtp_session->pack_buffer);
rtp_session->pack_buffer = XCAM_NULL;
}
free(rtp_session);
rtp_session = XCAM_NULL;
return XCAM_SUCCESS;
}
#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif /* __cplusplus */
+178
View File
@@ -0,0 +1,178 @@
/*
* Copyright (c) XCAM. All rights reserved.
*/
#ifndef _LIVESTREAM_RTP_SESSION_H_
#define _LIVESTREAM_RTP_SESSION_H_
#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif
#endif /* End of #ifdef __cplusplus */
/*RTP Payload type define rfc3551*/
typedef enum {
RTP_PT_PCMU = 0, /* mu-law G.711Mu*/
RTP_PT_GSM = 3, /* GSM */
RTP_PT_G723 = 4, /* G.723 */
RTP_PT_PCMA = 8, /* a-law G.711A*/
RTP_PT_G722 = 9, /* G.722 */
RTP_PT_L16_STEREO = 10, /* linear 16, 44.1khz, 2 channel */
RTP_PT_L16_MONO = 11, /* linear 16, 44.1khz, 1 channel */
RTP_PT_MPA = 14, /* mpeg audio */
RTP_PT_JPEG = 26, /* jpeg */
RTP_PT_H261 = 31, /* h.261 */
RTP_PT_MPV = 32, /* mpeg video */
RTP_PT_MP2T = 33, /* mpeg2 TS stream */
RTP_PT_H263 = 34, /* old H263 encapsulation */
/*96-127 dynamic*/
RTP_PT_H264 = 96, /* xmedia define as h.264 */
RTP_PT_G726 = 97, /* xmedia define as G.726 */
RTP_PT_H265 = 98, /* xmedia define as h.265 */
RTP_PT_DATA = 100, /* xmedia define as md alarm data*/
RTP_PT_AMR = 101, /* xmedia define as AMR*/
RTP_PT_MJPEG = 102, /* xmedia define as MJPEG */
RTP_PT_YUV = 103, /* xmedia define as YUV*/
RTP_PT_ADPCM = 104, /* xmedia define as ADPCM */
RTP_PT_AAC = 105, /* xmedia define as AAC */
RTP_PT_SEC = 106, /* xmedia define as SEC*/
RTP_PT_RED = 107, /* xmedia define as RED */
RTP_PT_INVALID = 128
} rtp_payload_type;
typedef enum {
PACK_TYPE_RAW = 0,
PACK_TYPE_RTP,
PACK_TYPE_RTP_STAP,
PACK_TYPE_RTP_FUA,
PACK_TYPE_RTSP_ITLV,
PACK_TYPE_XM_ITLV,
PACK_TYPE_RTSP_O_HTTP,
PACK_TYPE_BUTT
} rtp_pack_type;
typedef enum {
RTP_TRANS_UDP = 0,
RTP_TRANS_UDP_ITLV,
RTP_TRANS_TCP,
RTP_TRANS_TCP_ITLV,
RTP_TRANS_BROADCAST,
RTP_TRANS_BUTT
} rtp_trans_mode;
#ifndef BYTE_ORDER
#define BYTE_ORDER LITTLE_ENDIAN
#endif
/* total 12Bytes */
typedef struct {
#if (BYTE_ORDER == LITTLE_ENDIAN)
/* byte 0 */
xcam_u16 cc : 4; /* CSRC count */
xcam_u16 x : 1; /* header extension flag */
xcam_u16 p : 1; /* padding flag */
xcam_u16 version : 2; /* protocol version */
/* byte 1 */
xcam_u16 pt : 7; /* payload type */
xcam_u16 marker : 1; /* marker bit */
#elif (BYTE_ORDER == BIG_ENDIAN)
/* byte 0 */
xcam_u16 version : 2; /* protocol version */
xcam_u16 p : 1; /* padding flag */
xcam_u16 x : 1; /* header extension flag */
xcam_u16 cc : 4; /* CSRC count */
/*byte 1*/
xcam_u16 marker : 1; /* marker bit */
xcam_u16 pt : 7; /* payload type */
#else
#error YOU MUST DEFINE BYTE_ORDER == LITTLE_ENDIAN OR BIG_ENDIAN !
#endif
/* bytes 2, 3 */
xcam_u16 seqno : 16; /* sequence number */
/* bytes 4-7 */
xcam_u32 ts; /* timestamp in ms */
/* bytes 8-11 */
xcam_u32 ssrc; /* synchronization source */
} rtp_pack_hdr;
/*rtp field packet*/
#define RTP_HDR_SET_VERSION(HDR, val) ((HDR)->version = val)
#define RTP_HDR_SET_P(HDR, val) ((HDR)->p = val)
#define RTP_HDR_SET_X(HDR, val) ((HDR)->x = val)
#define RTP_HDR_SET_CC(HDR, val) ((HDR)->cc = val)
#define RTP_HDR_SET_M(HDR, val) ((HDR)->marker = val)
#define RTP_HDR_SET_PT(HDR, val) ((HDR)->pt = val)
#define RTP_HDR_SET_SEQNO(HDR, _sn) ((HDR)->seqno = (_sn))
#define RTP_HDR_SET_TS(HDR, _ts) ((HDR)->ts = (_ts))
#define RTP_HDR_SET_SSRC(HDR, _ssrc) ((HDR)->ssrc = _ssrc)
#define RTP_TRANS_IP_MAX_LEN (32)
/*rtsp interleaved packet*/
typedef struct {
xcam_u8 daollar; /*8, $:dollar sign(24 decimal)*/
xcam_u8 chn_id; /*8, channel id*/
xcam_u16 payload_len; /*16, payload length*/
rtp_pack_hdr rtp_head; /*rtp head*/
} rtsp_itleaved_hdr;
typedef enum {
RTP_SESSION_STATE_INIT = 0,
RTP_SESSION_STATE_READY = 1,
RTP_SESSION_STATE_PLAY = 2,
RTP_SESSION_STATE_STOP = 3,
RTP_SESSION_STATE_BUTT
} xcam_rtp_session_state;
typedef struct {
rtp_pack_type pack_type;
rtp_trans_mode media_trans_mode;
xcam_s32 rtp_send_sock;
xcam_s32 client_rtp_port;
xcam_s32 server_rtp_port;
xcam_u32 seq_num;
xcam_u32 ssrc;
xcam_u32 data_len;
xcam_char* pack_buffer;
xcam_u32 itlv_client_media_chnid;
xcam_u32 itlv_client_adapt_chnid;
xcam_rtp_session_state session_state;
xcam_char client_ip[RTP_TRANS_IP_MAX_LEN];
struct sockaddr_in client_sockaddr;
} livestream_rtp_session;
xcam_s32 livestream_rtp_session_update_seq_num(livestream_rtp_session* rtp_session, xcam_u32 seq_num);
xcam_s32 livestream_rtp_session_get_packet_and_send_param(livestream_rtp_session* rtp_session, xcam_s32* ptr_write_sock,
struct sockaddr_in* ptr_peer_sockaddr, xcam_u32* ptr_last_sn,
rtp_pack_type* ptr_pack_type, xcam_u32* ptr_ssrc);
xcam_s32 livestream_rtp_session_send_data_in_rtsp_itlv(livestream_rtp_session* rtp_session, const xcam_u8* data_addr,
xcam_u32 data_len, xcam_u32 ts, rtp_payload_type rtp_type, xcam_u32* seq_num, xcam_u32 ssrc,
xcam_s32 write_sock, struct sockaddr_in* peer_sockaddr, xcam_s32 packet_len);
xcam_s32 livestream_rtp_session_send_data_in_rtp(livestream_rtp_session* session, const xcam_u8* data_addr,
xcam_u32 data_len, xcam_u32 ts, rtp_payload_type package_type, xcam_u32* seq_num,
xcam_u32 ssrc, xcam_s32 write_sock, const struct sockaddr_in* peer_sockaddr, xcam_s32 packet_len);
xcam_s32 livestream_rtp_session_start(livestream_rtp_session* rtp_session);
xcam_s32 livestream_rtp_session_stop(livestream_rtp_session* rtp_session);
xcam_s32 livestream_rtp_session_create(livestream_rtp_session** rtp_session, xcam_s32 packet_len);
xcam_s32 livestream_rtp_session_destroy(livestream_rtp_session* rtp_session);
#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif /* End of #ifdef __cplusplus */
#endif /*_LIVESTREAM_RTP_SESSION_H_*/
@@ -0,0 +1,332 @@
/*
* Copyright (c) XCAM. All rights reserved.
*/
#include <string.h>
#include "livestream_comm.h"
#include "xcam_livestream_rtsp_server.h"
#include "livestream_rtsp_message.h"
#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif
#endif /* __cplusplus */
#define RTSP_INVALID_STATUS_STR "Invalid Status"
#define RTSP_INVALID_STATUS_CODE (-1)
typedef struct {
xcam_char* status_str;
xcam_s32 status_code;
} rtsp_msg_status;
static rtsp_msg_status g_rtsp_status[] = {
{"Continue", 100},
{"OK", 200},
{"Created", 201},
{"Accepted", 202},
{"Non-Authoritative Information", 203},
{"No Content", 204},
{"Reset Content", 205},
{"Partial Content", 206},
{"Multiple Choices", 300},
{"Moved Permanently", 301},
{"Moved Temporarily", 302},
{"Bad Request", 400},
{"Unauthorized", 401},
{"Payment Required", 402},
{"Forbidden", 403},
{"Stream Not Found", 404},
{"Method Not Allowed", 405},
{"Not Acceptable", 406},
{"Proxy Authentication Required", 407},
{"Request Time-out", 408},
{"Conflict", 409},
{"Gone", 410},
{"Length Required", 411},
{"Precondition Failed", 412},
{"Request Entity Too Large", 413},
{"Request-URI Too Large", 414},
{"Unsupported Media Type", 415},
{"Over Supported connection ", 416},
{"Bad Extension", 420},
{"Invalid Parameter", 450},
{"Parameter Not Understood", 451},
{"Conference Not Found", 452},
{"Not Enough Bandwidth", 453},
{"Session Not Found", 454},
{"Method Not Valid In This State", 455},
{"Header Field Not Valid for Resource", 456},
{"Invalid Range", 457},
{"Parameter Is Read-Only", 458},
{"Unsupported Transport", 461},
{"Internal Server Error", 500},
{"Not Implemented", 501},
{"Bad Gateway", 502},
{"Service Unavailable", 503},
{"Gateway Time-out", 504},
{"RTSP Version Not Supported", 505},
{"Option not support", 551},
{"Extended Error:", 911},
{0, RTSP_INVALID_STATUS_CODE}
};
/*response header example
RTSP/1.0 200 OK
Server: Streaming Media Server/1.0.0(Jul 30 2015)
Cseq: 1
Public: OPTIONS, DESCRIBE, SETUP, PLAY, TEARDOWN
*/
static xcam_bool msg_parser_is_response(const xcam_char* request)
{
xcam_char version[RTSP_VER_MAX_LEN] = {0};
xcam_u32 stat = 0;
xcam_s32 cnt = 0;
memset(version, '\0', sizeof(version));
cnt = sscanf(request, " %31s %d", version, &stat);
version[RTSP_VER_MAX_LEN - 1] = '\0';
if (strncasecmp(version, "RTSP/", strlen("RTSP/"))
|| cnt < RTSP_SCANF_RET_TWO || 0 == stat) {
return XCAM_FALSE; /* not a response message */
}
return XCAM_TRUE;
}
xcam_bool livestream_rtsp_message_check_request(const xcam_char* request)
{
livestream_rtsp_request_method method;
xcam_s32 ret = XCAM_SUCCESS;
/* check for request message. */
if (msg_parser_is_response(request)) {
LOG_LIVESTREAM_INFO("msg formate error, not request, just rtsp response\n");
return XCAM_FALSE;
}
/* not a response message, check for method request. */
ret = livestream_rtsp_message_parse_method(request, &method);
if (ret != XCAM_SUCCESS) {
LOG_LIVESTREAM_INFO("method=%s requested was invalid. Message discarded.\n", request);
return XCAM_FALSE;
}
return XCAM_TRUE;
}
xcam_void livestream_rtsp_message_get_response(xcam_s32 status_code, xcam_s32 cseq,
xcam_char* reply_buf, xcam_u32 buf_len)
{
xcam_char status_str[MAX_DATE_LEN] = {0};
xcam_char buffer[MAX_DATE_LEN] = {0};
int ret;
memset(status_str, '\0', sizeof(status_str));
livestream_rtsp_message_status_code_to_str(status_code, status_str, sizeof(status_str)-1);
memset(buffer, '\0', sizeof(buffer));
livestream_comm_format_date(buffer, sizeof(buffer)-1);
ret = snprintf(reply_buf, buf_len - 1,
"%s %d %s\r\n"
"CSeq: %d\r\n"
"Cache-Control: no-cache\r\n"
"Server: %s\r\n"
"%s\r\n",
RTSP_VER_STR,
status_code,
status_str,
cseq,
RTSP_SERVER_DESCRIPTION,
buffer);
if (ret < 0) {
LOG_LIVESTREAM_ERROR("string print reply_buf error\n");
return;
}
return;
}
/*OPTIONS rtsp://ip:554/12 RTSP/1.0
CSeq: 1
Authorization: Basic Og==
User-Agent: Streaming Media Client/1.0.0(May 23 2016)*/
xcam_s32 livestream_rtsp_message_get_stream_name(const xcam_char* request, xcam_char* stream_name, xcam_u32 buf_len)
{
xcam_char method[RTSP_METHOD_MAX_LEN] = {0};
xcam_char url[RTSP_URL_MAX_LEN] = {0};
xcam_char* tmp_ptr = XCAM_NULL;
xcam_s32 cnt = 0;
cnt = sscanf(request, " %15s %255s", method, url);
if (cnt != RTSP_SCANF_RET_TWO) {
LOG_LIVESTREAM_ERROR("rtsp req format error\n");
return XCAM_FAILURE;
}
method[RTSP_METHOD_MAX_LEN - 1] = '\0';
url[RTSP_URL_MAX_LEN - 1] = '\0';
tmp_ptr = strcasestr(url, "rtsp://");
if (XCAM_NULL == tmp_ptr) {
LOG_LIVESTREAM_ERROR("rtsp req format error, url do not have rtsp://\n");
return XCAM_FAILURE;
}
tmp_ptr += strlen("rtsp://");
tmp_ptr = strchr(tmp_ptr, '/');
if (!tmp_ptr) {
LOG_LIVESTREAM_ERROR("rtsp req url do not have stream name\n");
return XCAM_FAILURE;
}
strncpy(stream_name, tmp_ptr + 1, buf_len - 1);
stream_name[buf_len - 1] = '\0';
return XCAM_SUCCESS;
}
xcam_s32 livestream_rtsp_message_get_cseq( const xcam_char* request, xcam_s32* ptr_cseq)
{
xcam_char* ptr_temp = XCAM_NULL;
ptr_temp = strcasestr(request, RTSP_HEADER_CSEQ);
if (XCAM_NULL == ptr_temp) {
LOG_LIVESTREAM_ERROR("there no Cseq in req str\n");
return XCAM_FAILURE;
} else {
if (sscanf(ptr_temp, "%*s %d", ptr_cseq) != RTSP_SCANF_RET_ONE) {
return XCAM_FAILURE;
}
}
return XCAM_SUCCESS;
}
xcam_s32 livestream_rtsp_message_get_session_id(const xcam_char* ptr_msg_str, xcam_char* ptr_sess_id,
xcam_u32 sess_id_size)
{
xcam_char* ptr_temp = XCAM_NULL;
if (sess_id_size == 0) {
LOG_LIVESTREAM_ERROR("sessid buf size is 0\n");
return XCAM_FAILURE;
}
/*get sessionid*/
ptr_temp = strcasestr(ptr_msg_str, RTSP_HEADER_SESSION);
if ( XCAM_NULL == ptr_temp) {
LOG_LIVESTREAM_ERROR("there no sessid in req str\n");
return XCAM_FAILURE;
} else {
if (sscanf(ptr_temp, "%*s %15s", ptr_sess_id) != RTSP_SCANF_RET_ONE) {
return XCAM_FAILURE;
}
}
ptr_sess_id[sess_id_size - 1] = '\0';
return XCAM_SUCCESS;
}
xcam_s32 livestream_rtsp_message_parse_method(const xcam_char* request,
livestream_rtsp_request_method* ptr_method)
{
xcam_char method[RTSP_METHOD_MAX_LEN] = {0};
if (RTSP_SCANF_RET_ONE != sscanf(request, "%15[^ ]", method)) {
return XCAM_FAILURE;
}
method[RTSP_METHOD_MAX_LEN - 1] = '\0';
if (0 == strncmp(method, RTSP_METHOD_DESCRIBE, strlen(RTSP_METHOD_DESCRIBE))) {
*ptr_method = LIVESTREAM_RTSP_REQ_METHOD_DISCRIBLE;
} else if (0 == strncmp(method, RTSP_METHOD_SETUP, strlen(RTSP_METHOD_SETUP))) {
*ptr_method = LIVESTREAM_RTSP_REQ_METHOD_SETUP;
} else if (0 == strncmp(method, RTSP_METHOD_PLAY, strlen(RTSP_METHOD_PLAY))) {
*ptr_method = LIVESTREAM_RTSP_REQ_METHOD_PLAY;
} else if (0 == strncmp(method, RTSP_METHOD_TEARDOWN, strlen(RTSP_METHOD_TEARDOWN))) {
*ptr_method = LIVESTREAM_RTSP_REQ_METHOD_TEARDOWN;
} else if (0 == strncmp(method, RTSP_METHOD_OPTIONS, strlen(RTSP_METHOD_OPTIONS))) {
*ptr_method = LIVESTREAM_RTSP_REQ_METHOD_OPTIONS;
} else if (0 == strncmp(method, RTSP_METHOD_PAUSE, strlen(RTSP_METHOD_PAUSE))) {
*ptr_method = LIVESTREAM_RTSP_REQ_METHOD_PAUSE;
} else if (0 == strncmp(method, RTSP_METHOD_GET_PARAMETER, strlen(RTSP_METHOD_GET_PARAMETER))) {
*ptr_method = LIVESTREAM_RTSP_REQ_METHOD_GET_PARAM;
} else {
LOG_LIVESTREAM_INFO("not supported rtsp request method maybe rtcp in tcp_itlv\n");
return XCAM_FAILURE;
}
return XCAM_SUCCESS;
}
xcam_s32 livestream_rtsp_message_status_code_to_str(xcam_s32 code, xcam_char *out_buf_status,
xcam_s32 buf_len)
{
if (out_buf_status == XCAM_NULL || buf_len <= 0) {
LOG_LIVESTREAM_ERROR("Invalid param %d.\n", code);
return XCAM_FAILURE;
}
rtsp_msg_status* ptr;
for (ptr = g_rtsp_status; ptr->status_code != RTSP_INVALID_STATUS_CODE; ptr++) {
if (ptr->status_code == code) {
strncpy(out_buf_status, ptr->status_str, buf_len);
return XCAM_SUCCESS;
}
}
LOG_LIVESTREAM_ERROR("Invalid status code %d.\n", code);
strncpy(out_buf_status, RTSP_INVALID_STATUS_STR, buf_len);
return XCAM_FAILURE;
}
xcam_u32 livestream_rtsp_message_get_aac_config(xcam_u32 sample_rate, xcam_u32 chan_num)
{
xcam_u32 config_num = LIVESTREAM_AUDIO_DOUBLECHN_CONFIGNUM_16000;
if (chan_num == RTSP_AUDIO_SINGLE_CHN) {
switch (sample_rate) {
case LIVESTREAM_AUDIO_SAMPLE_RATE_8000:
config_num = LIVESTREAM_AUDIO_SINGLECHN_CONFIGNUM_8000;
break;
case LIVESTREAM_AUDIO_SAMPLE_RATE_16000:
config_num = LIVESTREAM_AUDIO_SINGLECHN_CONFIGNUM_16000;
break;
case LIVESTREAM_AUDIO_SAMPLE_RATE_32000:
config_num = LIVESTREAM_AUDIO_SINGLECHN_CONFIGNUM_32000;
break;
case LIVESTREAM_AUDIO_SAMPLE_RATE_48000:
config_num = LIVESTREAM_AUDIO_SINGLECHN_CONFIGNUM_48000;
break;
default:
break;
}
} else if (chan_num == RTSP_AUDIO_DOUBLE_CHN) {
switch (sample_rate) {
case LIVESTREAM_AUDIO_SAMPLE_RATE_8000:
config_num = LIVESTREAM_AUDIO_DOUBLECHN_CONFIGNUM_8000;
break;
case LIVESTREAM_AUDIO_SAMPLE_RATE_16000:
config_num = LIVESTREAM_AUDIO_DOUBLECHN_CONFIGNUM_16000;
break;
case LIVESTREAM_AUDIO_SAMPLE_RATE_32000:
config_num = LIVESTREAM_AUDIO_DOUBLECHN_CONFIGNUM_32000;
break;
case LIVESTREAM_AUDIO_SAMPLE_RATE_48000:
config_num = LIVESTREAM_AUDIO_DOUBLECHN_CONFIGNUM_48000;
break;
default:
break;
}
} else {
LOG_LIVESTREAM_ERROR("Invalid audio channel %d\n", chan_num);
}
return config_num;
}
#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif /* __cplusplus */
@@ -0,0 +1,168 @@
/*
* Copyright (c) XCAM. All rights reserved.
*/
#ifndef _LIVESTREAM_RTSP_MESSAGE_H_
#define _LIVESTREAM_RTSP_MESSAGE_H_
#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif
#endif /* End of #ifdef __cplusplus */
#define RTSP_VER_MAX_LEN (32)
#define RTSP_METHOD_MAX_LEN (16)
#define RTSP_URL_MAX_LEN (256)
#define RTSP_MAX_ONLINE_USER (16)
#define RTSP_IPADDE_LEN (16)
#define RTSP_TIME_LEN (32)
#define RTSP_SPS_MAX_LEN (128)
#define RTSP_PPS_MAX_LEN (128)
#define RTSP_VPS_MAX_LEN (128)
#define RTSP_SESSID_MAX_LEN (16)
#define RTSP_PASSWORD_MAX_LEN (256)
#define RTSP_USERNAME_MAX_LEN (256)
#define RTSP_AGENTBUF_MAX_LEN (128)
#define RTSP_LINE_MAX_LEN (256)
#define RTSP_TRASH_MAX_LEN (256)
#define RTSP_RANGE_MAX_LEN (64)
#define RTSP_OBJ_MAX_LEN (256)
#define RTSP_UNCARE_MAX_LEN (256)
#define RTSP_IP_MAX_LEN (16)
#define RTSP_COOK_MAX_LEN (64)
#define RTSP_CHAR_MAX_LEN (32)
#define RTSP_MAX_PROTOCOL_BUFFER (1024)
#define RTSP_SCANF_RET_ONE (1)
#define RTSP_SCANF_RET_TWO (2)
#define RTSP_SCANF_RET_THREE (3)
#define RTSP_AUDIO_SINGLE_CHN (1)
#define RTSP_AUDIO_DOUBLE_CHN (2)
#define RTSP_MAX_STREAMNAME_LEN (128)
#define XMRTSP_VER_STR "RTSP/1.0"
#define RTSP_LR "\r"
#define RTSP_LF "\n"
#define RTSP_LRLF "\r\n"
#define RTSP_SERVER_DESCRIPTION "XCAM RTSP Streaming Media Server/1.0.0"
#define RTSP_METHOD_OPTIONS "OPTIONS"
#define RTSP_METHOD_DESCRIBE "DESCRIBE"
#define RTSP_METHOD_SETUP "SETUP"
#define RTSP_METHOD_PLAY "PLAY"
#define RTSP_METHOD_PAUSE "PAUSE"
#define RTSP_METHOD_TEARDOWN "TEARDOWN"
#define RTSP_METHOD_GET_PARAMETER "GET_PARAMETER"
/* message header keywords */
#define RTSP_HEADER_CONTENTLENGTH "Content-Length"
#define RTSP_HEADER_ACCEPT "Accept"
#define RTSP_HEADER_CONTENTTYPE "Content-Type"
#define RTSP_HEADER_DATE "Date"
#define RTSP_HEADER_CSEQ "CSeq"
#define RTSP_HEADER_SESSION "Session"
#define RTSP_HEADER_TRANSPORT "Transport"
#define RTSP_VER_STR "RTSP/1.0"
#define RTSP_TRACK_ID "trackID="
#define RTSP_SDP_CONTENT_TYPE "application/sdp"
#define RTSP_SUPPORTED_CMD_LIST "OPTIONS, DESCRIBE, SETUP, PLAY, TEARDOWN, GET_PARAMETER"
#define RTSP_STATUS_CODE_CONTINUE (100)
#define RTSP_STATUS_CODE_OK (200)
#define RTSP_STATUS_CODE_ACCEPTED (202)
#define RTSP_STATUS_CODE_BAD_REQUEST (400)
#define RTSP_STATUS_CODE_UNAUTHORIZED (401)
#define RTSP_STATUS_CODE_STREAM_NOT_FOUND (404)
#define RTSP_STATUS_CODE_METHOD_NOT_ALLOWED (405)
#define RTSP_STATUS_CODE_OVER_SUPPORTED_CONNECTION (416)
#define RTSP_STATUS_CODE_SESSION_NOT_FOUND (454)
#define RTSP_STATUS_CODE_UNSUPPORT_TRANSPORT (461)
#define RTSP_STATUS_CODE_INTERNAL_SERVER_ERROR (500)
#define RTSP_STATUS_CODE_SERVICE_UNAVAILIABLE (503)
#define RTSP_STATUS_CODE_OPTION_UNSUPPORT (551)
typedef enum {
/* method codes */
LIVESTREAM_RTSP_REQ_METHOD_OPTIONS = 0,
LIVESTREAM_RTSP_REQ_METHOD_DISCRIBLE = 1,
LIVESTREAM_RTSP_REQ_METHOD_SETUP = 2,
LIVESTREAM_RTSP_REQ_METHOD_PLAY = 3,
LIVESTREAM_RTSP_REQ_METHOD_PAUSE = 4,
LIVESTREAM_RTSP_REQ_METHOD_TEARDOWN = 5,
LIVESTREAM_RTSP_REQ_METHOD_GET_PARAM = 6,
LIVESTREAM_RTSP_REQ_METHOD_SET_PARAM = 7,
LIVESTREAM_RTSP_REQ_METHOD_BUTT
} livestream_rtsp_request_method;
/** audio sample rate*/
typedef enum {
LIVESTREAM_AUDIO_SAMPLE_RATE_8000 = 8000, /* 8K Sample rate */
LIVESTREAM_AUDIO_SAMPLE_RATE_11025 = 11025, /* 11.025K Sample rate*/
LIVESTREAM_AUDIO_SAMPLE_RATE_16000 = 16000, /* 16K Sample rate */
LIVESTREAM_AUDIO_SAMPLE_RATE_22050 = 22050, /* 22.050K Sample rate*/
LIVESTREAM_AUDIO_SAMPLE_RATE_24000 = 24000, /* 24K Sample rate */
LIVESTREAM_AUDIO_SAMPLE_RATE_32000 = 32000, /* 32K Sample rate */
LIVESTREAM_AUDIO_SAMPLE_RATE_44100 = 44100, /* 44.1K Sample rate */
LIVESTREAM_AUDIO_SAMPLE_RATE_48000 = 48000, /* 48K Sample rate */
LIVESTREAM_AUDIO_SAMPLE_RATE_BUTT
} livestream_audio_sample_rate;
/**
aac low profile
8k single chn 1588 double chn 1590
16k single chn 1408 double chn 1410
22.05K single chn 1388 double chn 1390
24K single chn 1308 double chn 1310
32k single chn 1288 double chn 1290
44.1k single chn 1208 double chn 1210
48k single chn 1188 double chn 1190
*/
typedef enum {
LIVESTREAM_AUDIO_SINGLECHN_CONFIGNUM_8000 = 1588, /**< 8K Sample rate config num */
LIVESTREAM_AUDIO_SINGLECHN_CONFIGNUM_16000 = 1408, /* *<16K Sample rate config num */
LIVESTREAM_AUDIO_SINGLECHN_CONFIGNUM_22050 = 1388, /**<22.050K Sample rate config num */
LIVESTREAM_AUDIO_SINGLECHN_CONFIGNUM_24000 = 1308, /* *<24K Sample rate config num */
LIVESTREAM_AUDIO_SINGLECHN_CONFIGNUM_32000 = 1288, /**< 32K Sample rate config num */
LIVESTREAM_AUDIO_SINGLECHN_CONFIGNUM_44100 = 1208, /**< 44.1K Sample rate config num */
LIVESTREAM_AUDIO_SINGLECHN_CONFIGNUM_48000 = 1188, /* *<48K Sample rate config num */
LIVESTREAM_AUDIO_SINGLECHN_CONFIGNUM_BUTT
} livestream_audio_singlechn_confignum;
typedef enum {
LIVESTREAM_AUDIO_DOUBLECHN_CONFIGNUM_8000 = 1590, /**< 8K Sample rate config num */
LIVESTREAM_AUDIO_DOUBLECHN_CONFIGNUM_16000 = 1410, /**<16K Sample rate config num */
LIVESTREAM_AUDIO_DOUBLECHN_CONFIGNUM_22050 = 1390, /**< 22.050K Sample rate config num */
LIVESTREAM_AUDIO_DOUBLECHN_CONFIGNUM_24000 = 1310, /**<24K Sample rate config num */
LIVESTREAM_AUDIO_DOUBLECHN_CONFIGNUM_32000 = 1290, /* *<32K Sample rate config num */
LIVESTREAM_AUDIO_DOUBLECHN_CONFIGNUM_44100 = 1210, /* *<44.1K Sample rate config num */
LIVESTREAM_AUDIO_DOUBLECHN_CONFIGNUM_48000 = 1190, /* *<48K Sample rate config num */
LIVESTREAM_AUDIO_DOUBLECHN_CONFIGNUM_BUTT
} livestream_audio_doublechn_confignum;
xcam_bool livestream_rtsp_message_check_request(const xcam_char* request);
xcam_void livestream_rtsp_message_get_response(xcam_s32 stat_code, xcam_s32 cseq,
xcam_char* reply_buf, xcam_u32 buf_len);
xcam_s32 livestream_rtsp_message_get_stream_name(const xcam_char* request,
xcam_char* stream_name, xcam_u32 buf_len);
xcam_s32 livestream_rtsp_message_get_cseq( const xcam_char* request, xcam_s32* ptr_cseq);
xcam_s32 livestream_rtsp_message_get_session_id(const xcam_char* ptr_msg_str, xcam_char* ptr_sess_id,
xcam_u32 sess_id_size);
xcam_s32 livestream_rtsp_message_parse_method(const xcam_char* request, livestream_rtsp_request_method* ptr_method);
xcam_s32 livestream_rtsp_message_status_code_to_str(xcam_s32 code, xcam_char *out_buf_status,
xcam_s32 buf_len);
xcam_u32 livestream_rtsp_message_get_aac_config(xcam_u32 sample_rate, xcam_u32 chan_num);
#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif /* End of #ifdef __cplusplus */
#endif /*_LIVESTREAM_RTSP_MESSAGE_H_*/
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,206 @@
/*
* Copyright (c) XCAM. All rights reserved.
*/
#ifndef _LIVESTREAM_RTSP_SESSION_H_
#define _LIVESTREAM_RTSP_SESSION_H_
#include <pthread.h>
#include "list.h"
#include "xcam_livestream_rtsp_server.h"
#include "xcam_track_source.h"
#include "livestream_rtsp_message.h"
#include "livestream_rtp_session.h"
#include "livestream_rtcp_session.h"
#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif
#endif /* End of #ifdef __cplusplus */
#define RTSP_TRACKID_VIDEO (0)
#define RTSP_TRACKID_AUDIO (1)
#define RTSP_INVALID_TRACK_ID (-1)
#define RTSP_INVALID_THREAD_ID (pthread_t)(-1)
#define RTSP_MAX_NALBASE_LEN (256)
#define CHECK_WAIT_MAX_NUM (600)
#define MAX_NAL_PARAM_LEN (128) /** max len for nal param*/
#define CHECK_WAIT_TIMEOUT (10 * 1000)
#define CHECK_WAIT_I_FRAME_COUNT (100)
#define RTSPSVR_CHECK_NULL_ERROR(condition) \
do { \
if(condition == XCAM_NULL) { \
LOG_LIVESTREAM_ERROR("pointer is null\n"); \
return LIVESTREAM_ERRNO_NULL_PTR; \
}\
} while(0)
typedef enum {
LIVESTREAM_RTSP_SESSION_STATE_INIT = 0,
LIVESTREAM_RTSP_SESSION_STATE_READY,
LIVESTREAM_RTSP_SESSION_STATE_PLAY,
LIVESTREAM_RTSP_SESSION_STATE_STOP,
LIVESTREAM_RTSP_SESSION_STATE_BUTT
} livestream_rtsp_session_state;
typedef enum {
AVC_SEI = 0x06,
AVC_IDR = 0x05,
AVC_SPS = 0x07,
AVC_PPS = 0x08,
} livestream_rtsp_avc_nalu;
typedef enum {
HEVC_PSLICE = 0x01,
HEVC_IDR = 0x13,
HEVC_SPS = 0x21,
HEVC_PPS = 0x22,
HEVC_VPS = 0x20,
HEVC_SEI = 0x27
} livestream_rtsp_hevc_nalu;
typedef struct {
livestream_rtp_session* rtp_session;
livestream_rtcp_session* rtcp_session;
pthread_mutex_t mutex_get_port;
xcam_s32 track_id;
xcam_char rtsp_url[RTSP_URL_MAX_LEN];
} livestream_rtsp_media_session;
typedef struct {
/*used to maintain link list*/
struct list_head list_ptr;
xcam_char name[RTSP_MAX_STREAMNAME_LEN];
xcam_track_source_handle video_stream;
xcam_track_source_handle audio_stream;
xcam_u32 buf_size;
xcam_u32 video_start_cnt;
xcam_u32 audio_start_cnt;
} livestream_media_stream_node;
typedef struct {
struct list_head stream_list;
pthread_mutex_t stream_list_lock;
struct list_head session_list;
pthread_mutex_t session_list_lock;
xcam_server_state_listener state_listener;
xcam_s32 max_conn_num;
xcam_s32 user_num;
xcam_s32 stream_num;
xcam_s32 listen_port;
xcam_s32 packet_len;
xcam_u32 buf_size;
xcam_s32 max_payload;
xcam_s32 timeout;
xcam_void* net_listener;
xcam_bool is_started;
} livestream_rtsp_server_ctx;
/** nal param buffer struct*/
typedef struct {
xcam_u8 data_buf[MAX_NAL_PARAM_LEN];/**< nal data buf */
xcam_u32 data_len;/**< nal data len */
} nal_param_buffer;
typedef struct {
xcam_bool video_enable;
xcam_bool audio_enable;
xcam_void* mbuf_handle;
livestream_mbuffer_info mbuf_info;
xcam_track_video_source_info video_source_info;
xcam_track_audio_source_info audio_source_info;
nal_param_buffer sps_buf;
nal_param_buffer pps_buf;
nal_param_buffer vps_buf;
xcam_u64 video_start_pts; /**< start timestamp of frame */
xcam_u64 audio_start_pts; /**< start timestamp of frame */
} livestream_rtsp_media_info;
struct rtsp_stream_session;
typedef struct {
xcam_s32 (*session_destroy_func)(xcam_void* object, struct rtsp_stream_session* rtsp_session);
} livestream_rtsp_session_listener;
typedef struct rtsp_stream_session {
/*for the management of the list */
struct list_head list_ptr;
xcam_track_source_handle video_stream;
xcam_track_source_handle audio_stream;
livestream_rtsp_session_listener session_listener;
xcam_void* listener_object;
xcam_void* rtspsvr_handle; // rtspserver handle
pthread_t session_thdid;
xcam_s32 session_sockfd;
livestream_rtsp_session_state session_state;
pthread_mutex_t state_lock;
xcam_s32 cur_request_seq;
xcam_char recv_buf[RTSP_MAX_PROTOCOL_BUFFER];
xcam_char response_buf[RTSP_MAX_PROTOCOL_BUFFER];
xcam_char stream_name[RTSP_MAX_STREAMNAME_LEN];
xcam_char url[RTSP_URL_MAX_LEN];
xcam_char client_ip[RTSP_IP_MAX_LEN];
xcam_char host_ip[RTSP_IP_MAX_LEN];
xcam_u32 recv_len;
xcam_char session_id[RTSP_SESSID_MAX_LEN];
xcam_s32 packet_len;
xcam_u32 buf_size;
xcam_s32 max_payload;
xcam_s32 timeout;
xcam_u64 start_pts;
xcam_u64 last_pts;
livestream_rtsp_media_info media_info;
livestream_rtsp_media_session video_session;
livestream_rtsp_media_session audio_session;
xcam_bool is_get_key_frame;
xcam_u16 client_rtsp_port;
xcam_u32 channel_id;
} livestream_rtsp_stream_session;
/*newly add for supporting teardown one track and multi packets*/
#define RTSP_RTCP_HEADER_LENGTH (4)
#define RTSP_RTCP_BYTES_LENGTH (4)
#define RTSP_RTCP_PACKRT_TYPE_SR (200)
#define RTSP_RTCP_PACKRT_TYPE_RR (201)
#define RTSP_RTCP_PACKRT_TYPE_SDES (202)
#define RTSP_RTCP_PACKRT_TYPE_BYE (203)
#define RTSP_RTCP_PACKRT_TYPE_APP (204)
#define RTSP_RESPONSE_PACKET_LENGTH (4)
#define RTSP_RESPONSE_PACKRT_FIRST_BYTE (36)
#define RTSP_RESPONSE_PACKRT_THIRD_BYTE (0)
xcam_s32 livestream_rtsp_session_create(livestream_rtsp_stream_session** pptr_session, xcam_s32 sockfd);
xcam_s32 livestream_rtsp_session_destroy(livestream_rtsp_stream_session* rtsp_session);
xcam_void livestream_rtsp_session_set_media_source(livestream_rtsp_stream_session* rtsp_session,
xcam_track_source_handle vid_stream, xcam_track_source_handle aud_stream,
const xcam_char* stream_name);
xcam_s32 livestream_rtsp_session_set_listener(livestream_rtsp_stream_session* rtsp_session,
const livestream_rtsp_session_listener* listener, xcam_void* object);
xcam_void livestream_rtsp_session_get_client_ipaddr(livestream_rtsp_stream_session* rtsp_session,
xcam_char* buffer, xcam_s32 buf_len);
xcam_s32 livestream_rtsp_session_client_connect(livestream_rtsp_stream_session* rtsp_session,
xcam_char* client_request, xcam_u32 request_len);
xcam_s32 livestream_rtsp_session_send(xcam_s32 writ_sock, xcam_char* ptr_buff, xcam_u32 data_len);
xcam_s32 livestream_rtsp_session_stop(livestream_rtsp_stream_session* rtsp_session);
xcam_s32 livestream_rtsp_session_write_frame(livestream_rtsp_stream_session* rtsp_session,
xcam_track_source_handle track_src, const xcam_livestream_rtsp_data* stream_data);
#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif /* End of #ifdef __cplusplus */
#endif /*_LIVESTREAM_RTSP_SESSION_H_*/
@@ -0,0 +1,970 @@
/*
* Copyright (c) XCAM. All rights reserved.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include "livestream_errno.h"
#include "livestream_comm.h"
#include "livestream_listener.h"
#include "livestream_mbuffer.h"
#include "livestream_rtsp_session.h"
#include "livestream_rtsp_message.h"
#include "xcam_livestream_rtsp_server.h"
#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif
#endif /* __cplusplus */
#define RTSP_MAX_CONN_NUM (32)
#define RTSP_MAX_LISTEN_PORT (65535)
#define RTSP_MIN_BUFFER_SIZE (216*1024)
#define RTSP_MAX_BUFFER_SIZE (50*1024*1024)
#define RTSP_MAX_PAYLOAD_TYPE (254)
#define RTSP_MAX_PACKET_LEN (5000)
#define RTSP_MIN_PACKET_LEN (500)
#define RTSP_MAX_STREAM_NUM (8)
#define RTSP_KEEPALIVE_SECONDS_MIN (6)
static livestream_rtsp_server_ctx* g_server_ctx = XCAM_NULL;
static xcam_bool is_audio_codec_support(xcam_track_audio_codec codec)
{
if (codec == XCAM_TRACK_AUDIO_CODEC_AAC || codec == XCAM_TRACK_AUDIO_CODEC_G711A ||
codec == XCAM_TRACK_AUDIO_CODEC_G711U || codec == XCAM_TRACK_AUDIO_CODEC_G726 ||
codec == XCAM_TRACK_AUDIO_CODEC_ADPCM || codec == XCAM_TRACK_AUDIO_CODEC_MP3) {
return XCAM_TRUE;
}
LOG_LIVESTREAM_ERROR("Unsupport audio type: %d\n", codec);
return XCAM_FALSE;
}
static xcam_s32 check_frame_data(const xcam_livestream_rtsp_data* ptr_frame_data)
{
xcam_s32 ret = XCAM_SUCCESS;
xcam_u32 blk_idx = 0;
RTSPSVR_CHECK_NULL_ERROR(ptr_frame_data);
if (0 == ptr_frame_data->block_cnt
|| ptr_frame_data->block_cnt > RTSPSVR_FRAME_MAX_BLOCK) {
LOG_LIVESTREAM_ERROR("Illegal block count: %u!\n", ptr_frame_data->block_cnt);
ret = LIVESTREAM_ERRNO_ILLEGAL_PARAM;
}
for (blk_idx = 0; blk_idx < ptr_frame_data->block_cnt; blk_idx++) {
RTSPSVR_CHECK_NULL_ERROR(ptr_frame_data->data_ptr[blk_idx]);
if (0 == ptr_frame_data->data_len[blk_idx]) {
LOG_LIVESTREAM_ERROR("Illegal frame data len: 0!\n");
ret = LIVESTREAM_ERRNO_ILLEGAL_PARAM;
}
}
return ret;
}
static xcam_s32 check_stream_data(xcam_track_source_handle ptr_track_src, const xcam_livestream_rtsp_data* ptr_data)
{
xcam_s32 ret = XCAM_SUCCESS;
if (XCAM_TRACK_SOURCE_TYPE_VIDEO == ptr_track_src->track_type) {
if (XCAM_TRACK_VIDEO_CODEC_H264 != ptr_track_src->track_source_attr.video_info.codec_type
&& XCAM_TRACK_VIDEO_CODEC_H265 != ptr_track_src->track_source_attr.video_info.codec_type) {
LOG_LIVESTREAM_ERROR("not support video type :%d \n", ptr_track_src->track_source_attr.video_info.codec_type);
return LIVESTREAM_ERRNO_ILLEGAL_PARAM;
}
} else if (XCAM_TRACK_SOURCE_TYPE_AUDIO == ptr_track_src->track_type) {
if (is_audio_codec_support(ptr_track_src->track_source_attr.audio_info.codec_type) == XCAM_FALSE) {
LOG_LIVESTREAM_ERROR("stream data illegal\n");
return LIVESTREAM_ERRNO_ILLEGAL_PARAM;
}
} else {
LOG_LIVESTREAM_ERROR("source track type illegal \n");
return LIVESTREAM_ERRNO_ILLEGAL_PARAM;
}
ret = check_frame_data(ptr_data);
if (XCAM_SUCCESS != ret) {
LOG_LIVESTREAM_ERROR("Check frame data fail!\n");
return ret;
}
return XCAM_SUCCESS;
}
static xcam_s32 set_rtsp_config(livestream_rtsp_stream_session* stream_session,
livestream_rtsp_server_ctx* server_ctx)
{
RTSPSVR_CHECK_NULL_ERROR(stream_session);
RTSPSVR_CHECK_NULL_ERROR(server_ctx);
stream_session->max_payload = server_ctx->max_payload;
stream_session->timeout = server_ctx->timeout;
stream_session->packet_len = server_ctx->packet_len;
stream_session->rtspsvr_handle = (xcam_void*)server_ctx;
return XCAM_SUCCESS;
}
static xcam_s32 check_rtsp_config(xcam_livestream_rtsp_config* rtsp_config)
{
if (rtsp_config->packet_len < RTSP_MIN_PACKET_LEN
|| rtsp_config->packet_len > RTSP_MAX_PACKET_LEN) {
LOG_LIVESTREAM_ERROR("param packet_len not in the range min:%d- max:%d!\n",
RTSP_MIN_PACKET_LEN, RTSP_MAX_PACKET_LEN);
return LIVESTREAM_ERRNO_ILLEGAL_PARAM;
}
if (rtsp_config->max_conn_num <= 0
|| rtsp_config->max_conn_num > RTSP_MAX_CONN_NUM) {
LOG_LIVESTREAM_ERROR("param max_conn_num not in the range max:%d!\n", RTSP_MAX_CONN_NUM);
return LIVESTREAM_ERRNO_ILLEGAL_PARAM;
}
if (rtsp_config->listen_port <= 0
|| rtsp_config->listen_port > RTSP_MAX_LISTEN_PORT) {
LOG_LIVESTREAM_ERROR("param listen port not in the range max:%d!\n", RTSP_MAX_LISTEN_PORT);
return LIVESTREAM_ERRNO_ILLEGAL_PARAM;
}
if (rtsp_config->max_payload <= 0
|| rtsp_config->max_payload > RTSP_MAX_PAYLOAD_TYPE) {
LOG_LIVESTREAM_ERROR("param max_payload not in the range max:%d!\n", RTSP_MAX_PAYLOAD_TYPE);
return LIVESTREAM_ERRNO_ILLEGAL_PARAM;
}
if (rtsp_config->timeout >= 0
&& rtsp_config->timeout < RTSP_KEEPALIVE_SECONDS_MIN) {
LOG_LIVESTREAM_ERROR("timeout out of range, min:%d!\n", RTSP_KEEPALIVE_SECONDS_MIN);
return LIVESTREAM_ERRNO_ILLEGAL_PARAM;
}
return XCAM_SUCCESS;
}
/*destroy a session when connect teardown */
static xcam_s32 on_session_destroy(xcam_void* object, livestream_rtsp_stream_session* rtsp_session)
{
livestream_rtsp_server_ctx* ptr_server_ctx = (livestream_rtsp_server_ctx*)object;
livestream_rtsp_stream_session* session_in_list = XCAM_NULL;
xcam_char client_ip[RTSP_IP_MAX_LEN] = {0};
struct list_head* ptr_pos_node = XCAM_NULL;
struct list_head* ptr_tmp_node = XCAM_NULL;
xcam_bool is_found = XCAM_FALSE;
xcam_s32 ret = XCAM_SUCCESS;
RTSPSVR_CHECK_NULL_ERROR(ptr_server_ctx);
RTSPSVR_CHECK_NULL_ERROR(rtsp_session);
pthread_mutex_lock(&ptr_server_ctx->session_list_lock);
list_for_each_safe(ptr_pos_node, ptr_tmp_node, &ptr_server_ctx->session_list) {
session_in_list = list_entry(ptr_pos_node, livestream_rtsp_stream_session, list_ptr);
if (0 == strncmp(rtsp_session->session_id, session_in_list->session_id, RTSP_SESSID_MAX_LEN)) {
is_found = XCAM_TRUE;
break;
}
}
if (!is_found || XCAM_NULL == session_in_list) {
LOG_LIVESTREAM_ERROR("could not find correspond media session\n");
pthread_mutex_unlock(&ptr_server_ctx->session_list_lock);
return LIVESTREAM_ERRNO_SESS_NOT_EXISTED;
}
/* when teardown destroy the session and remove it from the sessionlist*/
list_del(&(session_in_list->list_ptr));
ptr_server_ctx->user_num -= 1;
livestream_rtsp_session_get_client_ipaddr(rtsp_session, client_ip, RTSP_IP_MAX_LEN);
ret = livestream_rtsp_session_destroy(rtsp_session);
if (XCAM_SUCCESS != ret) {
LOG_LIVESTREAM_ERROR("stream session destroy failed:0x%x\n", ret);
pthread_mutex_unlock(&ptr_server_ctx->session_list_lock);
return LIVESTREAM_ERRNO_SESS_DESTROY_FAIL;
}
if (ptr_server_ctx->state_listener.func_client_disconnect && strlen(client_ip) > 0) {
ptr_server_ctx->state_listener.func_client_disconnect(&ptr_server_ctx->state_listener, client_ip);
}
pthread_mutex_unlock(&ptr_server_ctx->session_list_lock);
return XCAM_SUCCESS;
}
/*add a connect session for rtspserver related to a stream*/
static xcam_s32 add_stream_session(livestream_rtsp_server_ctx* ptr_server_ctx,
xcam_char* client_req, xcam_u32 req_len, xcam_s32 socket_fd,
livestream_media_stream_node* ptr_stream_node)
{
livestream_rtsp_session_listener listener;
livestream_rtsp_stream_session* stream_session = XCAM_NULL;
xcam_s32 ret = XCAM_SUCCESS;
struct list_head* pos_node = XCAM_NULL;
livestream_rtsp_stream_session* session_node = XCAM_NULL;
xcam_char client_ip[RTSP_IP_MAX_LEN] = {0};
if (XCAM_NULL == ptr_server_ctx || XCAM_NULL == client_req) {
LOG_LIVESTREAM_ERROR("Invalid param!\n");
return LIVESTREAM_ERRNO_ILLEGAL_PARAM;
}
if (ptr_server_ctx->user_num >= ptr_server_ctx->max_conn_num) {
LOG_LIVESTREAM_ERROR("reach the max connect num:%d \n",
ptr_server_ctx->max_conn_num);
return LIVESTREAM_ERRNO_REACH_MAX_CONNECT;
}
ret = livestream_rtsp_session_create(&stream_session, socket_fd);
if (XCAM_SUCCESS != ret) {
LOG_LIVESTREAM_ERROR("livestream rtsp session create failed ret %d \n", ret);
return LIVESTREAM_ERRNO_SESS_CREATE_FAIL;
}
ret = set_rtsp_config(stream_session, ptr_server_ctx);
if (XCAM_SUCCESS != ret) {
LOG_LIVESTREAM_ERROR("set session rtsp config failed \n");
livestream_rtsp_session_destroy(stream_session);
return LIVESTREAM_ERRNO_SESS_SET_FAIL;
}
if (XCAM_NULL != ptr_stream_node) {
stream_session->buf_size = ptr_stream_node->buf_size;
livestream_rtsp_session_set_media_source(stream_session,
ptr_stream_node->video_stream, ptr_stream_node->audio_stream, ptr_stream_node->name);
}
listener.session_destroy_func = on_session_destroy;
ret = livestream_rtsp_session_set_listener(stream_session, &listener, (xcam_void*)ptr_server_ctx);
if (XCAM_SUCCESS != ret) {
LOG_LIVESTREAM_ERROR("set session listerner failed \n");
livestream_rtsp_session_destroy(stream_session);
return LIVESTREAM_ERRNO_SESS_SET_FAIL;
}
ret = livestream_rtsp_session_client_connect(stream_session, client_req, req_len);
if (ret != XCAM_SUCCESS) {
LOG_LIVESTREAM_ERROR("on client connect failed ret :%d \n", ret);
livestream_rtsp_session_destroy(stream_session);
return LIVESTREAM_ERRNO_SESS_CONNECT_FAIL;
}
pthread_mutex_lock(&ptr_server_ctx->session_list_lock);
list_for_each(pos_node, &ptr_server_ctx->session_list) {
session_node = list_entry(pos_node, livestream_rtsp_stream_session, list_ptr);
if (session_node == stream_session) {
LOG_LIVESTREAM_ERROR("rtsp stream session already exist\n");
pthread_mutex_unlock(&ptr_server_ctx->session_list_lock);
ret = LIVESTREAM_ERRNO_SESS_EXISTED;
goto DES_SESSION;
}
}
list_add(&(stream_session->list_ptr), &(ptr_server_ctx->session_list));
ptr_server_ctx->user_num += 1;
pthread_mutex_unlock(&ptr_server_ctx->session_list_lock);
livestream_rtsp_session_get_client_ipaddr(stream_session, client_ip, RTSP_IP_MAX_LEN);
if (ptr_server_ctx->state_listener.func_client_connect && strlen(client_ip) > 0) {
ptr_server_ctx->state_listener.func_client_connect(&ptr_server_ctx->state_listener, client_ip);
}
return XCAM_SUCCESS;
DES_SESSION:
livestream_rtsp_session_destroy(stream_session);
return ret;
}
static xcam_s32 check_list_null(livestream_rtsp_server_ctx* ptr_server_ctx, const xcam_char* stream_name)
{
livestream_rtsp_stream_session* session_in_list = XCAM_NULL;
struct list_head* pos_node = XCAM_NULL;
struct list_head* tmp_node = XCAM_NULL;
xcam_bool need_wait = XCAM_FALSE;
xcam_u32 wait_cnt = 0;
while (wait_cnt <= CHECK_WAIT_MAX_NUM) {
pthread_mutex_lock(&ptr_server_ctx->session_list_lock);
list_for_each_safe(pos_node, tmp_node, &ptr_server_ctx->session_list) {
session_in_list = list_entry(pos_node, livestream_rtsp_stream_session, list_ptr);
if (0 == strncmp(stream_name, session_in_list->stream_name, RTSP_MAX_STREAMNAME_LEN)) {
need_wait = XCAM_TRUE;
break;
}
}
pthread_mutex_unlock(&ptr_server_ctx->session_list_lock);
if (need_wait) {
usleep(CHECK_WAIT_TIMEOUT);
wait_cnt++;
need_wait = XCAM_FALSE;
continue;
} else {
return XCAM_SUCCESS;
}
}
return XCAM_FAILURE;
}
static xcam_bool find_session_valid(livestream_rtsp_server_ctx* ptr_server_ctx,
const xcam_char* stream_name, livestream_rtsp_stream_session** pptr_session)
{
livestream_rtsp_stream_session* session_in_list = XCAM_NULL;
struct list_head* pos_node = XCAM_NULL;
struct list_head* tmp_node = XCAM_NULL;
xcam_bool is_found = XCAM_FALSE;
pthread_mutex_lock(&ptr_server_ctx->session_list_lock);
list_for_each_safe(pos_node, tmp_node, &ptr_server_ctx->session_list) {
session_in_list = list_entry(pos_node, livestream_rtsp_stream_session, list_ptr);
if (0 == strncmp(stream_name, session_in_list->stream_name, RTSP_MAX_STREAMNAME_LEN)) {
if (session_in_list->session_state != LIVESTREAM_RTSP_SESSION_STATE_STOP) {
is_found = XCAM_TRUE;
*pptr_session = session_in_list;
break;
}
}
}
pthread_mutex_unlock(&ptr_server_ctx->session_list_lock);
return is_found;
}
/*remove all the session related to the media stream if a stream is removed*/
static xcam_s32 remove_stream_session(livestream_rtsp_server_ctx* ptr_server_ctx,
const xcam_char* stream_name)
{
livestream_rtsp_stream_session* session_in_list = XCAM_NULL;
xcam_bool is_found = XCAM_TRUE;
xcam_s32 ret = XCAM_SUCCESS;
if (XCAM_NULL == ptr_server_ctx || XCAM_NULL == stream_name) {
LOG_LIVESTREAM_ERROR("Invalid param ptr_server_ctx=%p, stream_name=%p\n",
ptr_server_ctx, stream_name);
return LIVESTREAM_ERRNO_ILLEGAL_PARAM;
}
while (is_found) {
is_found = find_session_valid(ptr_server_ctx, stream_name, &session_in_list);
if (!is_found) {
break;
}
/*when remove a streamsession set stop state and wait for the destroy*/
ret = livestream_rtsp_session_stop(session_in_list);
if ( XCAM_SUCCESS != ret) {
LOG_LIVESTREAM_ERROR("stream session destroy failed ret:0x%x\n", ret);
return LIVESTREAM_ERRNO_SESS_DESTROY_FAIL;
}
}
ret = check_list_null(ptr_server_ctx, stream_name);
if (XCAM_SUCCESS != ret) {
LOG_LIVESTREAM_ERROR("remove session timeout, and ret:%d\n", ret);
return LIVESTREAM_ERRNO_SESS_DESTROY_FAIL;
}
return XCAM_SUCCESS;
}
static xcam_s32 on_client_connection(xcam_void* object, xcam_s32 sockfd,
xcam_char* ptr_client_req, xcam_u32 req_len)
{
livestream_rtsp_server_ctx* ptr_server_ctx = (livestream_rtsp_server_ctx*)object;
livestream_media_stream_node* stream_node = XCAM_NULL;
xcam_char stream_str[RTSP_MAX_STREAMNAME_LEN] = {0};
xcam_char reply_str[RTSP_MAX_PROTOCOL_BUFFER] = {0};
struct list_head* pos_node = XCAM_NULL;
xcam_s32 stat_code = RTSP_STATUS_CODE_OK;
xcam_bool is_get_stream_name = XCAM_TRUE;
xcam_bool is_found = XCAM_FALSE;
xcam_s32 ret = XCAM_SUCCESS;
xcam_s32 resp_len = 0;
xcam_s32 cseq = 0;
RTSPSVR_CHECK_NULL_ERROR(ptr_server_ctx);
RTSPSVR_CHECK_NULL_ERROR(ptr_client_req);
if (!livestream_rtsp_message_check_request(ptr_client_req)) {
LOG_LIVESTREAM_ERROR("invalid rtsp request, just ignore this connection\n");
stat_code = RTSP_STATUS_CODE_BAD_REQUEST;
ret = LIVESTREAM_ERRNO_SESS_BAD_REQUEST;
goto Failed;
}
ret = livestream_rtsp_message_get_stream_name(ptr_client_req, stream_str, RTSP_MAX_STREAMNAME_LEN);
if (ret != XCAM_SUCCESS) {
LOG_LIVESTREAM_ERROR("could not find stream name!\n");
is_get_stream_name = XCAM_FALSE;
}
ret = livestream_rtsp_message_get_cseq(ptr_client_req, &cseq);
if (ret != XCAM_SUCCESS) {
LOG_LIVESTREAM_ERROR("invalid rtsp url, could not find CSeq\n");
stat_code = RTSP_STATUS_CODE_BAD_REQUEST;
ret = LIVESTREAM_ERRNO_SESS_BAD_REQUEST;
goto Failed;
}
if (!is_get_stream_name) {
if (add_stream_session(ptr_server_ctx, ptr_client_req, req_len, sockfd, XCAM_NULL) != XCAM_SUCCESS) {
LOG_LIVESTREAM_ERROR("Add stream session failed\n");
stat_code = RTSP_STATUS_CODE_INTERNAL_SERVER_ERROR;
ret = LIVESTREAM_ERRNO_STREAM_ADD_SESS_FAIL;
goto Failed;
}
return XCAM_SUCCESS;
}
//if find stream name ,start session with streamnode
pthread_mutex_lock(&ptr_server_ctx->stream_list_lock);
list_for_each(pos_node, &ptr_server_ctx->stream_list) {
stream_node = list_entry(pos_node, livestream_media_stream_node, list_ptr);
if (!strcasecmp(stream_node->name, stream_str)) {
is_found = XCAM_TRUE;
break;
}
}
if (!is_found || XCAM_NULL == stream_node) {
LOG_LIVESTREAM_ERROR("invalid rtsp request, could not find correspond stream\n");
stat_code = RTSP_STATUS_CODE_BAD_REQUEST;
ret = LIVESTREAM_ERRNO_SESS_STREAM_NOT_FOUND;
pthread_mutex_unlock(&ptr_server_ctx->stream_list_lock);
goto Failed;
}
if (add_stream_session(ptr_server_ctx, ptr_client_req, req_len, sockfd, stream_node) != XCAM_SUCCESS) {
LOG_LIVESTREAM_ERROR("Add stream session failed!\n");
stat_code = RTSP_STATUS_CODE_INTERNAL_SERVER_ERROR;
ret = LIVESTREAM_ERRNO_STREAM_ADD_SESS_FAIL;
pthread_mutex_unlock(&ptr_server_ctx->stream_list_lock);
goto Failed;
}
pthread_mutex_unlock(&ptr_server_ctx->stream_list_lock);
return XCAM_SUCCESS;
Failed:
livestream_rtsp_message_get_response(stat_code, cseq, reply_str, RTSP_MAX_PROTOCOL_BUFFER);
resp_len = strlen(reply_str);
if (resp_len > 0) {
livestream_rtsp_session_send(sockfd, reply_str, resp_len);
}
livestream_comm_close_socket(&sockfd);
return ret;
}
static xcam_s32 check_stream_config(xcam_livestream_rtsp_source* stream_src, xcam_char* stream_name, xcam_u32 buf_size)
{
if (RTSP_MAX_STREAMNAME_LEN < strlen(stream_name) || 0 == strlen(stream_name)) {
LOG_LIVESTREAM_ERROR("stream name too long max len:%d\n", RTSP_MAX_STREAMNAME_LEN);
return LIVESTREAM_ERRNO_ILLEGAL_PARAM;
}
if (buf_size < RTSP_MIN_BUFFER_SIZE || buf_size > RTSP_MAX_BUFFER_SIZE) {
LOG_LIVESTREAM_ERROR("param buf_size not in the range min:%d max:%d!\n",
RTSP_MIN_BUFFER_SIZE, RTSP_MAX_BUFFER_SIZE);
return LIVESTREAM_ERRNO_ILLEGAL_PARAM;
}
if (XCAM_NULL == stream_src->video_src_handle && XCAM_NULL == stream_src->audio_src_handle) {
LOG_LIVESTREAM_ERROR("can not add a stream with no audio and no video\n");
return LIVESTREAM_ERRNO_ILLEGAL_PARAM;
}
if (XCAM_NULL != stream_src->audio_src_handle
&& XCAM_TRACK_SOURCE_TYPE_AUDIO != stream_src->audio_src_handle->track_type) {
LOG_LIVESTREAM_ERROR("can not add a audio src with video type\n");
return LIVESTREAM_ERRNO_ILLEGAL_PARAM;
}
if (XCAM_NULL != stream_src->video_src_handle) {
if (XCAM_TRACK_SOURCE_TYPE_VIDEO != stream_src->video_src_handle->track_type) {
LOG_LIVESTREAM_ERROR("can not add a video src with audio type\n");
return LIVESTREAM_ERRNO_ILLEGAL_PARAM;
}
if (XCAM_TRACK_VIDEO_CODEC_H264 != stream_src->video_src_handle->track_source_attr.video_info.codec_type
&& XCAM_TRACK_VIDEO_CODEC_H265 != stream_src->video_src_handle->track_source_attr.video_info.codec_type) {
LOG_LIVESTREAM_ERROR("not support video type :%d \n",
stream_src->video_src_handle->track_source_attr.video_info.codec_type);
return LIVESTREAM_ERRNO_ILLEGAL_PARAM;
}
if (XCAM_NULL == stream_src->video_src_handle->func_request_key_frame) {
LOG_LIVESTREAM_ERROR("video source call back null error \n");
return LIVESTREAM_ERRNO_ILLEGAL_PARAM;
}
}
if (XCAM_NULL != stream_src->audio_src_handle) {
if (XCAM_TRACK_SOURCE_TYPE_AUDIO != stream_src->audio_src_handle->track_type) {
LOG_LIVESTREAM_ERROR("can not add a audio src with video type\n");
return LIVESTREAM_ERRNO_ILLEGAL_PARAM;
}
if (is_audio_codec_support(stream_src->audio_src_handle->track_source_attr.audio_info.codec_type) == XCAM_FALSE) {
LOG_LIVESTREAM_ERROR("stream data illegal\n");
return LIVESTREAM_ERRNO_ILLEGAL_PARAM;
}
}
return XCAM_SUCCESS;
}
static xcam_void get_one_stream(livestream_rtsp_server_ctx* server_ctx, xcam_char* name, xcam_u32 size)
{
livestream_media_stream_node* stream_node = XCAM_NULL;
struct list_head* tmp_node = XCAM_NULL;
struct list_head* pos_node = XCAM_NULL;
pthread_mutex_lock(&server_ctx->stream_list_lock);
if (size == 0) {
LOG_LIVESTREAM_ERROR("stream name buf size[%u] is illegal\n", size);
return;
}
/* delete all the session related to the mediastream*/
list_for_each_safe(pos_node, tmp_node, &server_ctx->stream_list) {
stream_node = list_entry(pos_node, livestream_media_stream_node, list_ptr);
if (snprintf(name, size - 1, "%s", stream_node->name) < 0) {
LOG_LIVESTREAM_ERROR("string print name error\n");
}
break;
}
pthread_mutex_unlock(&server_ctx->stream_list_lock);
return;
}
static xcam_bool find_one_stream_and_delete(livestream_rtsp_server_ctx* server_ctx,
const xcam_char* stream_name)
{
livestream_media_stream_node* stream_node = XCAM_NULL;
struct list_head* pos_node = XCAM_NULL;
struct list_head* tmp_node = XCAM_NULL;
xcam_bool is_found = XCAM_FALSE;
pthread_mutex_lock(&server_ctx->stream_list_lock);
list_for_each_safe(pos_node, tmp_node, &server_ctx->stream_list) {
stream_node = list_entry(pos_node, livestream_media_stream_node, list_ptr);
if (!strcasecmp(stream_node->name, stream_name))
{
is_found = XCAM_TRUE;
list_del(&(stream_node->list_ptr));
free(stream_node);
stream_node = XCAM_NULL;
server_ctx->stream_num--;
break;
}
}
pthread_mutex_unlock(&server_ctx->stream_list_lock);
return is_found;
}
xcam_s32 xcam_livestream_rtsp_server_write_frame(xcam_void* handle, xcam_track_source_handle track_src,
const xcam_livestream_rtsp_data* ptr_data)
{
livestream_rtsp_stream_session* session_in_list = XCAM_NULL;
livestream_media_stream_node* stream_node = XCAM_NULL;
livestream_rtsp_server_ctx* ptr_server_ctx = XCAM_NULL;
struct list_head* tmp_node = XCAM_NULL;
struct list_head* pos_node = XCAM_NULL;
xcam_bool is_found_stream = XCAM_FALSE;
xcam_s32 ret = XCAM_SUCCESS;
RTSPSVR_CHECK_NULL_ERROR(handle);
if (XCAM_NULL == g_server_ctx) {
LOG_LIVESTREAM_ERROR("rtspserver not created fail!\n");
return LIVESTREAM_ERRNO_NOT_CREATE;
}
if (handle != (xcam_void*)g_server_ctx) {
LOG_LIVESTREAM_ERROR("rtspserver handle invalid \n");
return LIVESTREAM_ERRNO_HANDLE_INVALID;
}
ptr_server_ctx = (livestream_rtsp_server_ctx*)handle;
RTSPSVR_CHECK_NULL_ERROR(ptr_server_ctx);
RTSPSVR_CHECK_NULL_ERROR(track_src);
RTSPSVR_CHECK_NULL_ERROR(ptr_data);
ret = check_stream_data(track_src, ptr_data);
if (XCAM_SUCCESS != ret) {
LOG_LIVESTREAM_ERROR("rtsperver write frame data illegal\n");
return ret;
}
//find the stream node in the list
pthread_mutex_lock(&ptr_server_ctx->stream_list_lock);
list_for_each_safe(pos_node, tmp_node, &ptr_server_ctx->stream_list) {
stream_node = list_entry(pos_node, livestream_media_stream_node, list_ptr);
if (stream_node->video_stream == track_src || stream_node->audio_stream == track_src) {
is_found_stream = XCAM_TRUE;
break;
}
}
pthread_mutex_unlock(&ptr_server_ctx->stream_list_lock);
if (XCAM_TRUE != is_found_stream) {
LOG_LIVESTREAM_WARN("stream not find, write frame fail\n");
return LIVESTREAM_ERRNO_STREAM_NOT_EXIST;
}
pthread_mutex_lock(&ptr_server_ctx->session_list_lock);
list_for_each_safe(pos_node, tmp_node, &ptr_server_ctx->session_list) {
session_in_list = list_entry(pos_node, livestream_rtsp_stream_session, list_ptr);
if (session_in_list->video_stream == track_src || session_in_list->audio_stream == track_src) {
/*write frame for the session*/
ret = livestream_rtsp_session_write_frame(session_in_list, track_src, ptr_data);
if (XCAM_SUCCESS != ret) {
pthread_mutex_unlock(&ptr_server_ctx->session_list_lock);
LOG_LIVESTREAM_ERROR("Write frame failed ret:0x%x mediatype:0x%x!\n",
ret, track_src->track_type);
return ret;
}
}
}
pthread_mutex_unlock(&ptr_server_ctx->session_list_lock);
return XCAM_SUCCESS;
}
xcam_s32 xcam_livestream_rtsp_server_add_media_stream(xcam_void* handle, xcam_livestream_rtsp_source* stream_src,
xcam_char* stream_name, xcam_u32 buf_size)
{
RTSPSVR_CHECK_NULL_ERROR(handle);
livestream_media_stream_node* stream_node = XCAM_NULL;
livestream_rtsp_server_ctx* ptr_server_ctx = XCAM_NULL;
struct list_head* pos_node = XCAM_NULL;
xcam_s32 ret = XCAM_SUCCESS;
if (XCAM_NULL == g_server_ctx) {
LOG_LIVESTREAM_ERROR("rtsperver not created!\n");
return LIVESTREAM_ERRNO_NOT_CREATE;
}
if (handle != (xcam_void*)g_server_ctx) {
LOG_LIVESTREAM_ERROR("rtspserver handle invalid \n");
return LIVESTREAM_ERRNO_HANDLE_INVALID;
}
ptr_server_ctx = (livestream_rtsp_server_ctx*)handle;
RTSPSVR_CHECK_NULL_ERROR(ptr_server_ctx);
RTSPSVR_CHECK_NULL_ERROR(stream_name);
RTSPSVR_CHECK_NULL_ERROR(stream_src);
if (ptr_server_ctx->stream_num >= RTSP_MAX_STREAM_NUM) {
LOG_LIVESTREAM_ERROR("rtsperver stream num reach max:%d\n", RTSP_MAX_STREAM_NUM);
return LIVESTREAM_ERRNO_STREAM_ADD_FAIL;
}
ret = check_stream_config(stream_src, stream_name, buf_size);
if (XCAM_SUCCESS != ret) {
LOG_LIVESTREAM_ERROR("rtsperver check param illegal!\n");
return ret;
}
/*find the stream node in the list */
pthread_mutex_lock(&ptr_server_ctx->stream_list_lock);
list_for_each(pos_node, &ptr_server_ctx->stream_list) {
stream_node = list_entry(pos_node, livestream_media_stream_node, list_ptr);
if (!strcasecmp(stream_node->name, stream_name)) {
LOG_LIVESTREAM_ERROR("media source streamname alreay exist\n");
pthread_mutex_unlock(&ptr_server_ctx->stream_list_lock);
return LIVESTREAM_ERRNO_STREAM_EXISTED;
}
}
/* stream node not exist then create and add to the list*/
stream_node = (livestream_media_stream_node*)malloc(sizeof(livestream_media_stream_node));
if (!stream_node) {
LOG_LIVESTREAM_ERROR("dynamic alloc rtsp LiveMediaStreamNode failed\n");
pthread_mutex_unlock(&ptr_server_ctx->stream_list_lock);
return LIVESTREAM_ERRNO_MALLOC_FAIL;
}
memset(stream_node, 0x00, sizeof(livestream_media_stream_node));
strncpy(stream_node->name, stream_name, RTSP_MAX_STREAMNAME_LEN - 1);
stream_node->name[RTSP_MAX_STREAMNAME_LEN - 1] = '\0';
stream_node->audio_stream = stream_src->audio_src_handle;
stream_node->video_stream = stream_src->video_src_handle;
stream_node->buf_size = buf_size;
stream_node->audio_start_cnt = 0;
stream_node->video_start_cnt = 0;
ptr_server_ctx->stream_num++;
list_add(&(stream_node->list_ptr), &(ptr_server_ctx->stream_list));
pthread_mutex_unlock(&ptr_server_ctx->stream_list_lock);
return XCAM_SUCCESS;
}
xcam_s32 xcam_livestream_rtsp_server_remove_media_stream(xcam_void* handle, const xcam_char* stream_name)
{
RTSPSVR_CHECK_NULL_ERROR(handle);
livestream_rtsp_server_ctx* ptr_server_ctx = XCAM_NULL;
xcam_bool is_found = XCAM_FALSE;
xcam_s32 ret = XCAM_SUCCESS;
if ( XCAM_NULL == g_server_ctx) {
LOG_LIVESTREAM_ERROR("rtsperver not created!\n");
return LIVESTREAM_ERRNO_NOT_CREATE;
}
if (handle != (xcam_void*)g_server_ctx) {
LOG_LIVESTREAM_ERROR("rtspserver handle invalid \n");
return LIVESTREAM_ERRNO_HANDLE_INVALID;
}
ptr_server_ctx = (livestream_rtsp_server_ctx*)handle;
RTSPSVR_CHECK_NULL_ERROR(ptr_server_ctx);
RTSPSVR_CHECK_NULL_ERROR(stream_name);
if (RTSP_MAX_STREAMNAME_LEN < strlen(stream_name) || 0 == strlen(stream_name)) {
LOG_LIVESTREAM_ERROR("rtsperver streamname error len \n");
return LIVESTREAM_ERRNO_ILLEGAL_PARAM;
}
/*when remove a media stream destroy the related connections if existed*/
ret = remove_stream_session(ptr_server_ctx, stream_name);
if (XCAM_SUCCESS != ret) {
LOG_LIVESTREAM_ERROR("could not find remove stream session for stream: %s ret:%d\n",
stream_name, ret);
return LIVESTREAM_ERRNO_STREAM_REMOVE_FAIL;
}
is_found = find_one_stream_and_delete(ptr_server_ctx, stream_name);
if (!is_found) {
LOG_LIVESTREAM_ERROR("could not find correspond media stream\n");
return LIVESTREAM_ERRNO_STREAM_NOT_EXIST;
}
return XCAM_SUCCESS;
}
xcam_s32 xcam_livestream_rtsp_server_start(xcam_void* handle)
{
RTSPSVR_CHECK_NULL_ERROR(handle);
livestream_rtsp_server_ctx* ptr_server_ctx = XCAM_NULL;
xcam_s32 ret = XCAM_SUCCESS;
if (XCAM_NULL == g_server_ctx) {
LOG_LIVESTREAM_ERROR("rtsperver not created!\n");
return LIVESTREAM_ERRNO_NOT_CREATE;
}
if (handle != (xcam_void*)g_server_ctx) {
LOG_LIVESTREAM_ERROR("rtspserver handle invalid \n");
return LIVESTREAM_ERRNO_HANDLE_INVALID;
}
ptr_server_ctx = (livestream_rtsp_server_ctx*)handle;
RTSPSVR_CHECK_NULL_ERROR(ptr_server_ctx);
RTSPSVR_CHECK_NULL_ERROR(ptr_server_ctx->net_listener);
if (ptr_server_ctx->is_started) {
LOG_LIVESTREAM_ERROR("Rtspserver already started \n");
return LIVESTREAM_ERRNO_START_LISTENER_AGAIN;
}
ret = livestream_listener_start(ptr_server_ctx->net_listener);
if (ret != XCAM_SUCCESS) {
LOG_LIVESTREAM_ERROR("Rtsp start listener failed ret:%d \n", ret);
return LIVESTREAM_ERRNO_START_LISTENER_FAIL;
}
livestream_listener_register_callback(ptr_server_ctx->net_listener,
on_client_connection, (xcam_void*)ptr_server_ctx);
ptr_server_ctx->is_started = XCAM_TRUE;
return XCAM_SUCCESS;
}
xcam_s32 xcam_livestream_rtsp_server_stop(xcam_void* handle)
{
RTSPSVR_CHECK_NULL_ERROR(handle);
livestream_rtsp_server_ctx* ptr_server_ctx;
xcam_char tmp_name[RTSP_MAX_STREAMNAME_LEN];
xcam_s32 ret = XCAM_SUCCESS;
if (XCAM_NULL == g_server_ctx) {
LOG_LIVESTREAM_ERROR("rtsperver not created!\n");
return LIVESTREAM_ERRNO_NOT_CREATE;
}
if (handle != (xcam_void*)g_server_ctx) {
LOG_LIVESTREAM_ERROR("rtspserver handle invalid \n");
return LIVESTREAM_ERRNO_HANDLE_INVALID;
}
ptr_server_ctx = (livestream_rtsp_server_ctx*)handle;
RTSPSVR_CHECK_NULL_ERROR(ptr_server_ctx);
if (!ptr_server_ctx->is_started) {
LOG_LIVESTREAM_ERROR("Rtspserver have not been started\n");
return LIVESTREAM_ERRNO_STOP_LISTENER_NOT_STARTED;
}
if (ptr_server_ctx->net_listener == XCAM_NULL) {
LOG_LIVESTREAM_ERROR("net_listener is XCAM_NULL Rtsp start listener failed \n");
return LIVESTREAM_ERRNO_STOP_LISTENER_FAIL;
}
ret = livestream_listener_stop(ptr_server_ctx->net_listener);
if (ret != XCAM_SUCCESS) {
LOG_LIVESTREAM_ERROR("Rtsp start listener failed ret:%d \n", ret);
return LIVESTREAM_ERRNO_STOP_LISTENER_FAIL;
}
while (0 != ptr_server_ctx->stream_num) {
get_one_stream(ptr_server_ctx, tmp_name, RTSP_MAX_STREAMNAME_LEN);
ret = remove_stream_session(ptr_server_ctx, tmp_name);
if (XCAM_SUCCESS != ret) {
LOG_LIVESTREAM_ERROR("could not find remove stream session for stream: %s\n", tmp_name);
return LIVESTREAM_ERRNO_STREAM_REMOVE_SESS_FAIL;
}
find_one_stream_and_delete(ptr_server_ctx, tmp_name);
}
ptr_server_ctx->is_started = XCAM_FALSE;
return XCAM_SUCCESS;
}
xcam_s32 xcam_livestream_rtsp_server_set_listener(xcam_void* handle, xcam_server_state_listener* state_listener)
{
RTSPSVR_CHECK_NULL_ERROR(handle);
livestream_rtsp_server_ctx* ptr_server_ctx;
if (XCAM_NULL == g_server_ctx) {
LOG_LIVESTREAM_ERROR("rtsperver not created!\n");
return LIVESTREAM_ERRNO_NOT_CREATE;
}
if (handle != (xcam_void*)g_server_ctx) {
LOG_LIVESTREAM_ERROR("rtspserver handle invalid \n");
return LIVESTREAM_ERRNO_HANDLE_INVALID;
}
ptr_server_ctx = (livestream_rtsp_server_ctx*)handle;
RTSPSVR_CHECK_NULL_ERROR(state_listener);
RTSPSVR_CHECK_NULL_ERROR(state_listener->func_client_connect);
RTSPSVR_CHECK_NULL_ERROR(state_listener->func_client_disconnect);
RTSPSVR_CHECK_NULL_ERROR(state_listener->func_server_error);
ptr_server_ctx->state_listener.func_client_connect = state_listener->func_client_connect;
ptr_server_ctx->state_listener.func_client_disconnect = state_listener->func_client_disconnect;
ptr_server_ctx->state_listener.func_server_error = state_listener->func_server_error;
return XCAM_SUCCESS;
}
xcam_s32 xcam_livestream_rtsp_server_create(xcam_void** handle, xcam_livestream_rtsp_config* ptr_rtsp_config)
{
livestream_rtsp_server_ctx* ptr_server_ctx = XCAM_NULL;
xcam_s32 ret = XCAM_SUCCESS;
RTSPSVR_CHECK_NULL_ERROR(handle);
RTSPSVR_CHECK_NULL_ERROR(ptr_rtsp_config);
ret = check_rtsp_config(ptr_rtsp_config);
if (XCAM_SUCCESS != ret) {
LOG_LIVESTREAM_ERROR("config param null !\n");
return ret;
}
if (XCAM_NULL != g_server_ctx) {
LOG_LIVESTREAM_ERROR("RTSPSERVER already created do not create again!\n");
return LIVESTREAM_ERRNO_CREATE_AGAIN;
}
ptr_server_ctx = (livestream_rtsp_server_ctx*)malloc(sizeof(livestream_rtsp_server_ctx));
if (!ptr_server_ctx) {
LOG_LIVESTREAM_ERROR("dynamic alloc livestream_rtsp_server_ctx failed\n");
return LIVESTREAM_ERRNO_MALLOC_FAIL;
}
memset(ptr_server_ctx, 0x00, sizeof(livestream_rtsp_server_ctx));
pthread_mutex_init(&ptr_server_ctx->session_list_lock, XCAM_NULL);
pthread_mutex_init(&ptr_server_ctx->stream_list_lock, XCAM_NULL);
ptr_server_ctx->max_conn_num = ptr_rtsp_config->max_conn_num;
ptr_server_ctx->listen_port = ptr_rtsp_config->listen_port;
ptr_server_ctx->max_payload = ptr_rtsp_config->max_payload;
ptr_server_ctx->packet_len = ptr_rtsp_config->packet_len;
ptr_server_ctx->timeout = ptr_rtsp_config->timeout;
ptr_server_ctx->user_num = 0;
ptr_server_ctx->stream_num = 0;
INIT_LIST_HEAD(&ptr_server_ctx->stream_list);
INIT_LIST_HEAD(&ptr_server_ctx->session_list);
ret = livestream_listener_create(ptr_server_ctx->listen_port, &ptr_server_ctx->net_listener);
if (XCAM_SUCCESS != ret) {
LOG_LIVESTREAM_ERROR("Rtsp create listener failed ret:%d\n", ret);
pthread_mutex_destroy(&ptr_server_ctx->stream_list_lock);
pthread_mutex_destroy(&ptr_server_ctx->session_list_lock);
free(ptr_server_ctx);
ptr_server_ctx = XCAM_NULL;
return LIVESTREAM_ERRNO_CREATE_LISTENER_FAIL;
}
*handle = (xcam_void*)ptr_server_ctx;
g_server_ctx = ptr_server_ctx;
return XCAM_SUCCESS;
}
xcam_s32 xcam_livestream_rtsp_server_destroy(xcam_void* handle)
{
xcam_char tmp_name[RTSP_MAX_STREAMNAME_LEN];
xcam_s32 ret = XCAM_SUCCESS;
RTSPSVR_CHECK_NULL_ERROR(handle);
if (XCAM_NULL == g_server_ctx) {
LOG_LIVESTREAM_ERROR("rtsperver not created!\n");
return LIVESTREAM_ERRNO_NOT_CREATE;
}
if (handle != (xcam_void*)g_server_ctx) {
LOG_LIVESTREAM_ERROR("rtspserver handle invalid \n");
return LIVESTREAM_ERRNO_HANDLE_INVALID;
}
livestream_rtsp_server_ctx* ptr_server_ctx = (livestream_rtsp_server_ctx*)handle;
RTSPSVR_CHECK_NULL_ERROR(ptr_server_ctx);
while (0 != ptr_server_ctx->stream_num) {
get_one_stream(ptr_server_ctx, tmp_name, RTSP_MAX_STREAMNAME_LEN);
ret = remove_stream_session(ptr_server_ctx, tmp_name);
if (XCAM_SUCCESS != ret) {
LOG_LIVESTREAM_ERROR("could not find remove stream session for stream: %s\n", tmp_name);
return LIVESTREAM_ERRNO_STREAM_REMOVE_SESS_FAIL;
}
find_one_stream_and_delete(ptr_server_ctx, tmp_name);
}
pthread_mutex_destroy(&ptr_server_ctx->stream_list_lock);
pthread_mutex_destroy(&ptr_server_ctx->session_list_lock);
ret = livestream_listener_destroy(ptr_server_ctx->net_listener);
if (XCAM_SUCCESS != ret) {
LOG_LIVESTREAM_ERROR("Rtsp destroy listener failed ret:%d \n", ret);
return LIVESTREAM_ERRNO_DESTROY_LISTENER_FAIL;
}
free(ptr_server_ctx);
ptr_server_ctx = XCAM_NULL;
g_server_ctx = XCAM_NULL;
return XCAM_SUCCESS;
}
#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif /* __cplusplus */