Files
gk-sdk/sample/live_rtsp_server/livestream/xcam_livestream_rtsp_server.c

971 lines
36 KiB
C
Executable File

/*
* 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 */