GK SDK 源码库: XMIPCLinuxV100R005C00SPC030 (kernel/tools/open_source excluded)
This commit is contained in:
+335
@@ -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
@@ -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
@@ -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
@@ -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 */
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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 */
|
||||
Reference in New Issue
Block a user