/*************************************************************************************** * * IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. * * By downloading, copying, installing or using the software you agree to this license. * If you do not agree to this license, do not download, install, * copy or use the software. * * Copyright (C) 2014-2024, Happytimesoft Corporation, all rights reserved. * * Redistribution and use in binary forms, with or without modification, are permitted. * * Unless required by applicable law or agreed to in writing, software distributed * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR * CONDITIONS OF ANY KIND, either express or implied. See the License for the specific * language governing permissions and limitations under the License. * ****************************************************************************************/ #include "sys_inc.h" #include "rtp.h" #include "word_analyse.h" #include "rtsp_parse.h" #include "rtsp_rcua.h" #include "rfc_md5.h" #include "base64.h" #include "rtsp_util.h" #include "http_cln.h" #ifdef OVER_WEBSOCKET #include "rtsp_ws.h" #endif /***********************************************************************/ void rcua_build_auth_line(RCUA * p_rua, HRTSP_MSG * tx_msg, const char * p_method) { if (0 == p_rua->need_auth) { return; } HD_AUTH_INFO * p_auth = &p_rua->auth_info; if (p_rua->auth_mode == 1) // digest { int offset; int buflen; char buff[500] = {'\0'}; http_calc_auth_digest(p_auth, p_method); offset = 0; buflen = sizeof(buff); offset += snprintf(buff+offset, buflen-offset, "Digest username=\"%s\", realm=\"%s\", nonce=\"%s\", " "uri=\"%s\", response=\"%s\"", p_auth->auth_name, p_auth->auth_realm, p_auth->auth_nonce, p_auth->auth_uri, p_auth->auth_response); if (p_auth->auth_opaque_flag) { offset += snprintf(buff+offset, buflen-offset, ", opaque=\"%s\"", p_auth->auth_opaque); } if (p_auth->auth_qop[0] != '\0') { offset += snprintf(buff+offset, buflen-offset, ", qop=\"%s\", cnonce=\"%s\", nc=%s", p_auth->auth_qop, p_auth->auth_cnonce, p_auth->auth_ncstr); } if (p_auth->auth_algorithm[0] != '\0') { offset += snprintf(buff+offset, buflen-offset, ", algorithm=%s", p_auth->auth_algorithm); } rtsp_add_tx_msg_line(tx_msg, "Authorization", "%s", buff); } else if (p_rua->auth_mode == 0) // basic { char buff[512] = {'\0'}; char basic[512] = {'\0'}; snprintf(buff, sizeof(buff), "%s:%s", p_auth->auth_name, p_auth->auth_pwd); base64_encode((uint8 *)buff, (int)strlen(buff), basic, sizeof(basic)); rtsp_add_tx_msg_line(tx_msg, "Authorization", "Basic %s", basic); } } HRTSP_MSG * rcua_build_options(RCUA * p_rua) { HRTSP_MSG * tx_msg = rtsp_get_msg_buf(); if (tx_msg == NULL) { log_print(HT_LOG_ERR, "%s, rtsp_get_msg_buf return NULL!!!\r\n", __FUNCTION__); return NULL; } tx_msg->msg_type = 0; tx_msg->msg_sub_type = RTSP_MT_OPTIONS; rtsp_add_tx_msg_fline(tx_msg, "OPTIONS", "%s RTSP/1.0", p_rua->uri); rtsp_add_tx_msg_line(tx_msg, "CSeq", "%u", p_rua->cseq); rcua_build_auth_line(p_rua, tx_msg, "OPTIONS"); if (p_rua->sid[0] != '\0') { rtsp_add_tx_msg_line(tx_msg, "Session", "%s", p_rua->sid); } rtsp_add_tx_msg_line(tx_msg, "User-Agent", p_rua->user_agent); return tx_msg; } HRTSP_MSG * rcua_build_describe(RCUA * p_rua) { HRTSP_MSG * tx_msg = rtsp_get_msg_buf(); if (tx_msg == NULL) { log_print(HT_LOG_ERR, "%s, rtsp_get_msg_buf return NULL!!!\r\n", __FUNCTION__); return NULL; } tx_msg->msg_type = 0; tx_msg->msg_sub_type = RTSP_MT_DESCRIBE; rtsp_add_tx_msg_fline(tx_msg, "DESCRIBE", "%s RTSP/1.0", p_rua->uri); rtsp_add_tx_msg_line(tx_msg, "CSeq", "%u", p_rua->cseq); rcua_build_auth_line(p_rua, tx_msg, "DESCRIBE"); rtsp_add_tx_msg_line(tx_msg, "Accept", "application/sdp"); rtsp_add_tx_msg_line(tx_msg, "User-Agent", p_rua->user_agent); #ifdef BACKCHANNEL if (p_rua->backchannel) { rtsp_add_tx_msg_line(tx_msg, "Require", "www.onvif.org/ver20/backchannel"); } #endif return tx_msg; } void rcua_build_setup_fline(HRTSP_MSG * tx_msg, const char * ctl, const char * uri) { if (strncmp(ctl, "rtsp://", 7) == 0) { rtsp_add_tx_msg_fline(tx_msg, "SETUP", "%s RTSP/1.0", ctl); } else { int len = (int)strlen(uri); if (uri[len-1] == '/') { rtsp_add_tx_msg_fline(tx_msg, "SETUP", "%s%s RTSP/1.0", uri, ctl); } else { rtsp_add_tx_msg_fline(tx_msg, "SETUP", "%s/%s RTSP/1.0", uri, ctl); } } } HRTSP_MSG * rcua_build_setup(RCUA * p_rua, int av_t) { HRTSP_MSG * tx_msg = rtsp_get_msg_buf(); if (tx_msg == NULL) { log_print(HT_LOG_ERR, "%s, rtsp_get_msg_buf return NULL!!!\r\n", __FUNCTION__); return NULL; } tx_msg->msg_type = 0; tx_msg->msg_sub_type = RTSP_MT_SETUP; rcua_build_setup_fline(tx_msg, p_rua->channels[av_t].ctl, p_rua->uri); rtsp_add_tx_msg_line(tx_msg, "CSeq", "%u", p_rua->cseq); if (p_rua->sid[0] != '\0') { rtsp_add_tx_msg_line(tx_msg, "Session", "%s", p_rua->sid); } rcua_build_auth_line(p_rua, tx_msg, "SETUP"); if (p_rua->rtp_tcp) // TCP { rtsp_add_tx_msg_line(tx_msg, "Transport", "RTP/AVP/TCP;unicast;interleaved=%u-%u", p_rua->channels[av_t].interleaved, p_rua->channels[av_t].interleaved+1); } else if (p_rua->rtp_mcast) // rtp multicast { rtsp_add_tx_msg_line(tx_msg, "Transport", "RTP/AVP;multicast;port=%u-%u", p_rua->channels[av_t].r_port, p_rua->channels[av_t].r_port+1); } else { rtsp_add_tx_msg_line(tx_msg, "Transport", "RTP/AVP;unicast;client_port=%u-%u", p_rua->channels[av_t].l_port, p_rua->channels[av_t].l_port+1); } rtsp_add_tx_msg_line(tx_msg, "User-Agent", p_rua->user_agent); #ifdef BACKCHANNEL if (av_t == AV_TYPE_BACKCHANNEL) // backchannel { rtsp_add_tx_msg_line(tx_msg, "Require", "www.onvif.org/ver20/backchannel"); } #endif #ifdef REPLAY if (p_rua->replay) { rtsp_add_tx_msg_line(tx_msg, "Require", "onvif-replay"); } #endif return tx_msg; } HRTSP_MSG * rcua_build_play(RCUA * p_rua) { HRTSP_MSG * tx_msg = rtsp_get_msg_buf(); if (tx_msg == NULL) { log_print(HT_LOG_ERR, "%s, rtsp_get_msg_buf return NULL!!!\r\n", __FUNCTION__); return NULL; } tx_msg->msg_type = 0; tx_msg->msg_sub_type = RTSP_MT_PLAY; rtsp_add_tx_msg_fline(tx_msg, "PLAY", "%s RTSP/1.0", p_rua->uri); rtsp_add_tx_msg_line(tx_msg, "CSeq", "%u", p_rua->cseq); rcua_build_auth_line(p_rua, tx_msg, "PLAY"); rtsp_add_tx_msg_line(tx_msg, "Session", "%s", p_rua->sid); rtsp_add_tx_msg_line(tx_msg, "Range", "npt=%0.3f-", p_rua->seek_pos/1000.0); rtsp_add_tx_msg_line(tx_msg, "User-Agent", p_rua->user_agent); #ifdef BACKCHANNEL if (p_rua->backchannel) // backchannel { rtsp_add_tx_msg_line(tx_msg, "Require", "www.onvif.org/ver20/backchannel"); } #endif #ifdef REPLAY if (p_rua->replay) { rtsp_add_tx_msg_line(tx_msg, "Require", "onvif-replay"); if (p_rua->scale_flag) { rtsp_add_tx_msg_line(tx_msg, "Scale", "%8.2f", p_rua->scale / 100.0); } if (p_rua->rate_control_flag) { rtsp_add_tx_msg_line(tx_msg, "Rate-Control", "%s", p_rua->rate_control ? "yes" : "no"); } if (p_rua->immediate_flag && p_rua->immediate) { rtsp_add_tx_msg_line(tx_msg, "Immediate", "yes"); } if (p_rua->frame_flag) { if (1 == p_rua->frame) { rtsp_add_tx_msg_line(tx_msg, "Frames", "predicted"); } else if (2 == p_rua->frame) { if (p_rua->frame_interval_flag && p_rua->frame_interval) { rtsp_add_tx_msg_line(tx_msg, "Frames", "intra/%d", p_rua->frame_interval); } else { rtsp_add_tx_msg_line(tx_msg, "Frames", "intra"); } } } if (p_rua->range_flag && p_rua->replay_start > 0) { char range[256] = {'\0'}; char start[32] = {'\0'}, end[32] = {'\0'}; struct tm *t1; t1 = gmtime(&p_rua->replay_start); snprintf(start, sizeof(start)-1, "%04d%02d%02dT%02d%02d%02dZ", t1->tm_year+1900, t1->tm_mon+1, t1->tm_mday, t1->tm_hour, t1->tm_min, t1->tm_sec); if (p_rua->replay_end > 0) { t1 = gmtime(&p_rua->replay_end); snprintf(end, sizeof(end)-1, "%04d%02d%02dT%02d%02d%02dZ", t1->tm_year+1900, t1->tm_mon+1, t1->tm_mday, t1->tm_hour, t1->tm_min, t1->tm_sec); snprintf(range, sizeof(range)-1, "clock=%s-%s", start, end); } else { snprintf(range, sizeof(range)-1, "clock=%s-", start); } rtsp_add_tx_msg_line(tx_msg, "Range", range); } } #endif return tx_msg; } HRTSP_MSG * rcua_build_pause(RCUA * p_rua) { HRTSP_MSG * tx_msg = rtsp_get_msg_buf(); if (tx_msg == NULL) { log_print(HT_LOG_ERR, "%s::rtsp_get_msg_buf return NULL!!!\r\n", __FUNCTION__); return NULL; } tx_msg->msg_type = 0; tx_msg->msg_sub_type = RTSP_MT_PAUSE; rtsp_add_tx_msg_fline(tx_msg, "PAUSE", "%s RTSP/1.0", p_rua->uri); rtsp_add_tx_msg_line(tx_msg, "CSeq", "%u", p_rua->cseq); rcua_build_auth_line(p_rua, tx_msg, "PAUSE"); rtsp_add_tx_msg_line(tx_msg, "Session", "%s", p_rua->sid); rtsp_add_tx_msg_line(tx_msg, "User-Agent", p_rua->user_agent); return tx_msg; } HRTSP_MSG * rcua_build_get_parameter(RCUA * p_rua) { HRTSP_MSG * tx_msg = rtsp_get_msg_buf(); if (tx_msg == NULL) { log_print(HT_LOG_ERR, "%s, rtsp_get_msg_buf return NULL!!!\r\n", __FUNCTION__); return NULL; } tx_msg->msg_type = 0; tx_msg->msg_sub_type = RTSP_MT_GET_PARAMETER; rtsp_add_tx_msg_fline(tx_msg, "GET_PARAMETER", "%s RTSP/1.0", p_rua->uri); rtsp_add_tx_msg_line(tx_msg, "CSeq", "%u", p_rua->cseq); rcua_build_auth_line(p_rua, tx_msg, "GET_PARAMETER"); rtsp_add_tx_msg_line(tx_msg, "Session", "%s", p_rua->sid); rtsp_add_tx_msg_line(tx_msg, "User-Agent", p_rua->user_agent); return tx_msg; } HRTSP_MSG * rcua_build_teardown(RCUA * p_rua) { HRTSP_MSG * tx_msg = rtsp_get_msg_buf(); if (tx_msg == NULL) { log_print(HT_LOG_ERR, "%s, rtsp_get_msg_buf return NULL!!!\r\n", __FUNCTION__); return NULL; } tx_msg->msg_type = 0; tx_msg->msg_sub_type = RTSP_MT_TEARDOWN; rtsp_add_tx_msg_fline(tx_msg, "TEARDOWN", "%s RTSP/1.0", p_rua->uri); rtsp_add_tx_msg_line(tx_msg, "CSeq", "%u", p_rua->cseq); rcua_build_auth_line(p_rua, tx_msg, "TEARDOWN"); rtsp_add_tx_msg_line(tx_msg, "Session", "%s", p_rua->sid); rtsp_add_tx_msg_line(tx_msg, "User-Agent", p_rua->user_agent); #ifdef BACKCHANNEL if (p_rua->backchannel) // backchannel { rtsp_add_tx_msg_line(tx_msg, "Require", "www.onvif.org/ver20/backchannel"); } #endif return tx_msg; } BOOL rcua_get_media_info(RCUA * p_rua, HRTSP_MSG * rx_msg) { if (rx_msg == NULL || p_rua == NULL) { return FALSE; } if (!rtsp_msg_with_sdp(rx_msg)) { return FALSE; } rtsp_get_remote_cap(rx_msg, "video", &(p_rua->channels[AV_VIDEO_CH].cap_count), p_rua->channels[AV_VIDEO_CH].cap, &p_rua->channels[AV_VIDEO_CH].r_port); rtsp_get_remote_cap_desc(rx_msg, "video", p_rua->channels[AV_VIDEO_CH].cap_desc); #ifdef BACKCHANNEL if (p_rua->backchannel) { rtsp_get_remote_cap(rx_msg, "audio", &(p_rua->channels[AV_AUDIO_CH].cap_count), p_rua->channels[AV_AUDIO_CH].cap, &p_rua->channels[AV_AUDIO_CH].r_port, "recvonly"); rtsp_get_remote_cap_desc(rx_msg, "audio", p_rua->channels[AV_AUDIO_CH].cap_desc, "recvonly"); rtsp_get_remote_cap(rx_msg, "audio", &(p_rua->channels[AV_BACK_CH].cap_count), p_rua->channels[AV_BACK_CH].cap, &p_rua->channels[AV_BACK_CH].r_port, "sendonly"); rtsp_get_remote_cap_desc(rx_msg, "audio", p_rua->channels[AV_BACK_CH].cap_desc, "sendonly"); } else #endif { rtsp_get_remote_cap(rx_msg, "audio", &(p_rua->channels[AV_AUDIO_CH].cap_count), p_rua->channels[AV_AUDIO_CH].cap, &p_rua->channels[AV_AUDIO_CH].r_port); rtsp_get_remote_cap_desc(rx_msg, "audio", p_rua->channels[AV_AUDIO_CH].cap_desc); } #ifdef METADATA rtsp_get_remote_cap(rx_msg, "application", &(p_rua->channels[AV_METADATA_CH].cap_count), p_rua->channels[AV_METADATA_CH].cap, &p_rua->channels[AV_METADATA_CH].r_port); rtsp_get_remote_cap_desc(rx_msg, "application", p_rua->channels[AV_METADATA_CH].cap_desc); #endif return TRUE; } void rcua_send_rtsp_msg(RCUA * p_rua, HRTSP_MSG * tx_msg) { int slen; char * tx_buf; int offset = 0; int buf_len; char rtsp_tx_buffer[2048+RTSP_SND_RESV_SIZE]; SOCKET fd = -1; if (tx_msg == NULL) { return; } #ifdef OVER_HTTP if (p_rua->over_http) { fd = p_rua->rtsp_send.cfd; } else #endif #ifdef OVER_WEBSOCKET if (p_rua->over_ws) { fd = p_rua->ws_http.cfd; } else #endif fd = p_rua->fd; if (fd <= 0) { return; } tx_buf = rtsp_tx_buffer + RTSP_SND_RESV_SIZE; buf_len = sizeof(rtsp_tx_buffer) - RTSP_SND_RESV_SIZE; offset += snprintf(tx_buf+offset, buf_len-offset, "%s %s\r\n", tx_msg->first_line.header, tx_msg->first_line.value_string); HDRV * pHdrV = (HDRV *)pps_lookup_start(&(tx_msg->rtsp_ctx)); while (pHdrV != NULL) { offset += snprintf(tx_buf+offset, buf_len-offset, "%s: %s\r\n", pHdrV->header, pHdrV->value_string); pHdrV = (HDRV *)pps_lookup_next(&(tx_msg->rtsp_ctx), pHdrV); } pps_lookup_end(&(tx_msg->rtsp_ctx)); offset += snprintf(tx_buf+offset, buf_len-offset, "\r\n"); if (tx_msg->sdp_ctx.node_num != 0) { pHdrV = (HDRV *)pps_lookup_start(&(tx_msg->sdp_ctx)); while (pHdrV != NULL) { if (pHdrV->header[0] != '\0') { offset += snprintf(tx_buf+offset, buf_len-offset, "%s=%s\r\n", pHdrV->header, pHdrV->value_string); } else { offset += snprintf(tx_buf+offset, buf_len-offset, "%s\r\n", pHdrV->value_string); } pHdrV = (HDRV *)pps_lookup_next(&(tx_msg->sdp_ctx), pHdrV); } pps_lookup_end(&(tx_msg->sdp_ctx)); } log_print(HT_LOG_DBG, "TX >> %s\r\n", tx_buf); #ifdef OVER_HTTP if (p_rua->over_http) { char tx_buf_base64[4096]; base64_encode((uint8 *)tx_buf, offset, tx_buf_base64, sizeof(tx_buf_base64)); tx_buf = tx_buf_base64; offset = strlen(tx_buf_base64); slen = http_cln_tx(&p_rua->rtsp_send, tx_buf, offset); } else #endif #ifdef OVER_WEBSOCKET if (p_rua->over_ws) { int extra = rtsp_ws_encode_data((uint8 *)tx_buf, offset, 0x82, 1); tx_buf -= extra; offset += extra; slen = http_cln_tx(&p_rua->ws_http, tx_buf, offset); } else #endif { slen = send(fd, tx_buf, offset, 0); } if (slen != offset) { log_print(HT_LOG_ERR, "%s, slen=%d, offset=%d, send message failed!!!\r\n", __FUNCTION__, slen, offset); } } BOOL rcua_get_sdp_video_desc(RCUA * p_rua, const char * key, int * pt, char * p_sdp, int max_len) { int payload_type = 0, i; int rtpmap_len = (int)strlen("a=rtpmap:"); char key_str[64] = {'\0'}; strncpy(key_str, key, sizeof(key_str)-1); for (i=0; ichannels[AV_VIDEO_CH].cap_desc[i]; if (memcmp(ptr, "a=rtpmap:", rtpmap_len) == 0) { char pt_buf[16]; char code_buf[64] = {'\0'}; int next_offset = 0; ptr += rtpmap_len; if (GetLineWord(ptr, 0, (int)strlen(ptr), pt_buf, sizeof(pt_buf), &next_offset, WORD_TYPE_NUM) == FALSE) { return FALSE; } GetLineWord(ptr, next_offset, (int)strlen(ptr)-next_offset, code_buf, sizeof(code_buf), &next_offset, WORD_TYPE_STRING); if (memcmp(uppercase(code_buf), uppercase(key_str), strlen(key_str)) == 0) { payload_type = atoi(pt_buf); break; } } } if (payload_type <= 0) { return FALSE; } if (pt) { *pt = payload_type; } if (p_sdp == NULL) { return TRUE; } p_sdp[0] = '\0'; char fmtp_buf[32]; int fmtp_len = snprintf(fmtp_buf, sizeof(fmtp_buf), "a=fmtp:%d", payload_type); for (i=0; ichannels[AV_VIDEO_CH].cap_desc[i]; if (memcmp(ptr, fmtp_buf, fmtp_len) == 0) { ptr += rtpmap_len+1; strncpy(p_sdp, ptr, max_len); break; } } return TRUE; } BOOL rcua_get_sdp_audio_desc(RCUA * p_rua, const char * key, int * pt, char * p_sdp, int max_len) { int payload_type = 0, i; int rtpmap_len = (int)strlen("a=rtpmap:"); char key_str[64] = {'\0'}; strncpy(key_str, key, sizeof(key_str)-1); for (i=0; ichannels[AV_AUDIO_CH].cap_desc[i]; if (memcmp(ptr, "a=rtpmap:", rtpmap_len) == 0) { char pt_buf[16]; char code_buf[64] = {'\0'}; int next_offset = 0; ptr += rtpmap_len; if (GetLineWord(ptr, 0, (int)strlen(ptr), pt_buf, sizeof(pt_buf), &next_offset, WORD_TYPE_NUM) == FALSE) { return FALSE; } GetLineWord(ptr, next_offset, (int)strlen(ptr)-next_offset, code_buf, sizeof(code_buf), &next_offset, WORD_TYPE_STRING); if (memcmp(uppercase(code_buf), uppercase(key_str), strlen(key_str)) == 0) { payload_type = atoi(pt_buf); break; } } } if (payload_type <= 0) { return FALSE; } if (pt) { *pt = payload_type; } if (p_sdp == NULL) { return TRUE; } p_sdp[0] = '\0'; char fmtp_buf[32]; int fmtp_len = snprintf(fmtp_buf, sizeof(fmtp_buf), "a=fmtp:%d", payload_type); for (i=0; ichannels[AV_AUDIO_CH].cap_desc[i]; if (memcmp(ptr, fmtp_buf, fmtp_len) == 0) { ptr += rtpmap_len+1; strncpy(p_sdp, ptr, max_len); break; } } return TRUE; } BOOL rcua_get_sdp_h264_desc(RCUA * p_rua, int * pt, char * p_sdp, int max_len) { return rcua_get_sdp_video_desc(p_rua, "H264/90000", pt, p_sdp, max_len); } BOOL rcua_get_sdp_h264_params(RCUA * p_rua, int * pt, char * p_sps_pps, int max_len) { BOOL ret = FALSE; char sdp[1024] = {'\0'}; if (rcua_get_sdp_h264_desc(p_rua, pt, sdp, sizeof(sdp)) == FALSE) { return FALSE; } char * p_substr = strstr(sdp, "sprop-parameter-sets="); if (p_substr != NULL) { p_substr += strlen("sprop-parameter-sets="); char * p_tmp = p_substr; while (*p_tmp != ' ' && *p_tmp != ';' && *p_tmp != '\0') { p_tmp++; } int sps_base64_len = (int)(p_tmp - p_substr); if (sps_base64_len < max_len) { memcpy(p_sps_pps, p_substr, sps_base64_len); p_sps_pps[sps_base64_len] = '\0'; ret = TRUE; } } return ret; } BOOL rcua_get_sdp_h265_desc(RCUA * p_rua, int * pt, char * p_sdp, int max_len) { return rcua_get_sdp_video_desc(p_rua, "H265/90000", pt, p_sdp, max_len); } BOOL rcua_get_sdp_h265_params(RCUA * p_rua, int * pt, BOOL * donfield, char * p_vps, int vps_len, char * p_sps, int sps_len, char * p_pps, int pps_len) { char sdp[1024] = {'\0'}; if (rcua_get_sdp_h265_desc(p_rua, pt, sdp, sizeof(sdp)) == FALSE) { return FALSE; } char * p_substr = strstr(sdp, "sprop-depack-buf-nalus="); if (p_substr != NULL) { p_substr += strlen("sprop-depack-buf-nalus="); char * p_tmp = p_substr; while (*p_tmp != ' ' && *p_tmp != ';' && *p_tmp != '\0') { p_tmp++; } int len = (int)(p_tmp - p_substr); if (len > 0) { if (donfield) { *donfield = (atoi(p_substr) > 0 ? TRUE : FALSE); } } else { return FALSE; } } p_substr = strstr(sdp, "sprop-vps="); if (p_substr != NULL) { p_substr += strlen("sprop-vps="); char * p_tmp = p_substr; while (*p_tmp != ' ' && *p_tmp != ';' && *p_tmp != '\0') { p_tmp++; } int len = (int)(p_tmp - p_substr); if (len < vps_len) { memcpy(p_vps, p_substr, len); p_vps[len] = '\0'; } else { return FALSE; } } p_substr = strstr(sdp, "sprop-sps="); if (p_substr != NULL) { p_substr += strlen("sprop-sps="); char * p_tmp = p_substr; while (*p_tmp != ' ' && *p_tmp != ';' && *p_tmp != '\0') { p_tmp++; } int len = (int)(p_tmp - p_substr); if (len < sps_len) { memcpy(p_sps, p_substr, len); p_sps[len] = '\0'; } else { return FALSE; } } p_substr = strstr(sdp, "sprop-pps="); if (p_substr != NULL) { p_substr += strlen("sprop-pps="); char * p_tmp = p_substr; while (*p_tmp != ' ' && *p_tmp != ';' && *p_tmp != '\0') { p_tmp++; } int len = (int)(p_tmp - p_substr); if (len < pps_len) { memcpy(p_pps, p_substr, len); p_pps[len] = '\0'; } else { return FALSE; } } return TRUE; } BOOL rcua_get_sdp_mp4_desc(RCUA * p_rua, int * pt, char * p_sdp, int max_len) { return rcua_get_sdp_video_desc(p_rua, "MP4V-ES/90000", pt, p_sdp, max_len); } BOOL rcua_get_sdp_mp4_params(RCUA * p_rua, int * pt, char * p_cfg, int max_len) { BOOL ret = FALSE; char sdp[1024] = {'\0'}; if (rcua_get_sdp_mp4_desc(p_rua, pt, sdp, sizeof(sdp)) == FALSE) { return FALSE; } char * p_substr = strstr(sdp, "config="); if (p_substr != NULL) { p_substr += strlen("config="); char * p_tmp = p_substr; while (*p_tmp != ' ' && *p_tmp != ';' && *p_tmp != '\0') { p_tmp++; } int cfg_len = (int)(p_tmp - p_substr); if (cfg_len < max_len) { memcpy(p_cfg, p_substr, cfg_len); p_cfg[cfg_len] = '\0'; ret = TRUE; } else { ret = FALSE; } } return ret; } BOOL rcua_get_sdp_aac_desc(RCUA * p_rua, int * pt, char * p_sdp, int max_len) { return rcua_get_sdp_audio_desc(p_rua, "MPEG4-GENERIC", pt, p_sdp, max_len); } BOOL rcua_get_sdp_aac_params(RCUA * p_rua, int *pt, int *sizelength, int *indexlength, int *indexdeltalength, char * p_cfg, int max_len) { char sdp[1024] = {'\0'}; if (rcua_get_sdp_aac_desc(p_rua, pt, sdp, sizeof(sdp)) == FALSE) { return FALSE; } char * p_substr = strstr(sdp, "config="); if (p_substr != NULL) { p_substr += strlen("config="); char * p_tmp = p_substr; while (*p_tmp != ' ' && *p_tmp != ';' && *p_tmp != '\0') { p_tmp++; } int len = (int)(p_tmp - p_substr); if (len < max_len) { memcpy(p_cfg, p_substr, len); p_cfg[len] = '\0'; } else { return FALSE; } } p_substr = strstr(sdp, "sizelength="); if (p_substr != NULL) { p_substr += strlen("sizelength="); char * p_tmp = p_substr; while (*p_tmp != ' ' && *p_tmp != ';' && *p_tmp != '\0') { p_tmp++; } int len = (int)(p_tmp - p_substr); if (len > 0) { *sizelength = atoi(p_substr); } } p_substr = strstr(sdp, "indexlength="); if (p_substr != NULL) { p_substr += strlen("indexlength="); char * p_tmp = p_substr; while (*p_tmp != ' ' && *p_tmp != ';' && *p_tmp != '\0') { p_tmp++; } int len = (int)(p_tmp - p_substr); if (len > 0) { *indexlength = atoi(p_substr); } } p_substr = strstr(sdp, "indexdeltalength="); if (p_substr != NULL) { p_substr += strlen("indexdeltalength="); char * p_tmp = p_substr; while (*p_tmp != ' ' && *p_tmp != ';' && *p_tmp != '\0') { p_tmp++; } int len = (int)(p_tmp - p_substr); if (len > 0) { *indexdeltalength = atoi(p_substr); } } return TRUE; } SOCKET rcua_init_udp_connection(uint16 port) { struct sockaddr_in addr; SOCKET fd = socket(AF_INET, SOCK_DGRAM, 0); if (fd <= 0) { log_print(HT_LOG_ERR, "%s, socket SOCK_DGRAM error!\n", __FUNCTION__); return -1; } addr.sin_family = AF_INET; addr.sin_addr.s_addr = htonl(INADDR_ANY); addr.sin_port = htons(port); int len = 1024*1024; if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (char*)&len, sizeof(int))) { log_print(HT_LOG_WARN, "%s, setsockopt SO_RCVBUF error!\r\n", __FUNCTION__); } if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) == -1) { log_print(HT_LOG_ERR, "%s, Bind udp socket fail, port = %d, error = %s\r\n", __FUNCTION__, port, sys_os_get_socket_error()); closesocket(fd); return -1; } return fd; } SOCKET rcua_init_mc_connection(uint16 port, char * destination) { struct sockaddr_in addr; struct ip_mreq mcast; SOCKET fd = socket(AF_INET, SOCK_DGRAM, 0); if (fd <= 0) { log_print(HT_LOG_ERR, "%s, socket SOCK_DGRAM error!\n", __FUNCTION__); return -1; } addr.sin_family = AF_INET; addr.sin_addr.s_addr = get_default_if_ip(); addr.sin_port = htons(port); /* reuse socket addr */ int opt = 1; if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&opt, sizeof(opt))) { log_print(HT_LOG_WARN, "%s, setsockopt SO_REUSEADDR error!\r\n", __FUNCTION__); } int len = 1024*1024; if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (char*)&len, sizeof(int))) { log_print(HT_LOG_WARN, "%s, setsockopt SO_RCVBUF error!\r\n", __FUNCTION__); } if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) == -1) { log_print(HT_LOG_ERR, "%s, Bind udp socket fail, port = %d, error = %s\r\n", __FUNCTION__, port, sys_os_get_socket_error()); closesocket(fd); return -1; } int ttl = 255; setsockopt(fd, IPPROTO_IP, IP_MULTICAST_TTL, (char*)&ttl, sizeof(ttl)); mcast.imr_multiaddr.s_addr = inet_addr(destination); mcast.imr_interface.s_addr = addr.sin_addr.s_addr; if (setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char*)&mcast, sizeof(mcast)) < 0) { log_print(HT_LOG_ERR, "%s, setsockopt IP_ADD_MEMBERSHIP error!%s\r\n", __FUNCTION__, sys_os_get_socket_error()); closesocket(fd); return -1; } return fd; }