first commit

This commit is contained in:
wdp
2024-12-15 20:42:32 +08:00
commit 986b2fca12
586 changed files with 154149 additions and 0 deletions

View File

@@ -0,0 +1,717 @@
/***************************************************************************************
*
* 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-2022, 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 "gb28181.h"
#include "gb28181_cfg.h"
#include "sip_inc.h"
#include "hsip.h"
#include "sip_cm.h"
#include "xml_node.h"
#include "sua.h"
#include "sua_sdp.h"
#include "sip_util.h"
#include "media_format.h"
#ifdef MEDIA_PROXY
#include "media_proxy.h"
#ifdef RTMP_PROXY
#include "log.h"
#endif
#endif
#if defined(MEDIA_FILE) || defined(MEDIA_DEVICE)
#ifdef ANDROID
#include "audio_play_qt.h"
#elif defined(IOS)
#include "audio_play_mac.h"
#elif __WINDOWS_OS__
#include "audio_play_win.h"
#elif __LINUX_OS__
#include "audio_play_linux.h"
#endif
#endif
/***************************************************************************************/
GB28181_CLASS g_gb28181_cls;
extern HSIP_CLASS hsip;
/***************************************************************************************/
#if defined(MEDIA_FILE) || defined(MEDIA_DEVICE)
void sip_audio_decode_cb(AVFrame * frame, void * userdata)
{
SUA * p_sua = (SUA *) userdata;
if (NULL == p_sua->media_info.audio_play)
{
#ifdef ANDROID
p_sua->media_info.audio_play = new CQAudioPlay();
#elif defined(IOS)
p_sua->media_info.audio_play = new CMAudioPlay();
#elif __WINDOWS_OS__
p_sua->media_info.audio_play = new CWAudioPlay();
#elif __LINUX_OS__
p_sua->media_info.audio_play = new CLAudioPlay();
#endif
if (p_sua->media_info.audio_play)
{
SDPINFO sdp;
if (sua_get_audio_sdp(p_sua, 1, 0, &sdp) >= 0)
{
p_sua->media_info.audio_play->setVolume(HTVOLUME_MAX);
p_sua->media_info.audio_play->startPlay(sdp.hz, sdp.chn);
}
}
}
if (p_sua->media_info.audio_play)
{
p_sua->media_info.audio_play->playAudio(frame->data[0], frame->nb_samples * frame->channels * av_get_bytes_per_sample((enum AVSampleFormat)frame->format));
}
}
#endif
#if defined(MEDIA_PROXY) && defined(RTMP_PROXY)
void gb28181_log_callback(int level, const char *format, va_list vl)
{
int lvl = HT_LOG_DBG;
int offset = 0;
char str[2048] = {'\0'};
offset += vsnprintf(str, sizeof(str)-1, format, vl);
offset += snprintf(str+offset, sizeof(str)-1-offset, "\r\n");
if (level == RTMP_LOGCRIT)
{
lvl = HT_LOG_FATAL;
}
else if (level == RTMP_LOGERROR)
{
lvl = HT_LOG_ERR;
}
else if (level == RTMP_LOGWARNING)
{
lvl = HT_LOG_WARN;
}
else if (level == RTMP_LOGINFO)
{
lvl = HT_LOG_INFO;
}
else if (level == RTMP_LOGDEBUG)
{
lvl = HT_LOG_DBG;
}
log_print(lvl, str);
}
void gb28181_set_rtmp_log()
{
RTMP_LogLevel lvl;
RTMP_LogSetCallback(gb28181_log_callback);
switch (g_gb28181_cfg.log_level)
{
case HT_LOG_TRC:
lvl = RTMP_LOGALL;
break;
case HT_LOG_DBG:
lvl = RTMP_LOGDEBUG;
break;
case HT_LOG_INFO:
lvl = RTMP_LOGINFO;
break;
case HT_LOG_WARN:
lvl = RTMP_LOGWARNING;
break;
case HT_LOG_ERR:
lvl = RTMP_LOGERROR;
break;
case HT_LOG_FATAL:
lvl = RTMP_LOGCRIT;
break;
default:
lvl = RTMP_LOGERROR;
break;
}
RTMP_LogSetLevel(lvl);
}
#endif
void sip_call_cb(void * sua, int evt, void * user_data)
{
printf("%s, evt : %s\r\n", __FUNCTION__, sip_get_puaevt_name((PUAEVT)evt));
gb28181_put_msg(evt, 0, sua);
}
int sip_audio_cb(void * sua, uint8 * p_data, int len, uint32 ts, uint16 seq, void * p_usrdata)
{
printf("sip_audio_cb, len=%d, seq=%d\r\n", len, seq);
#if defined(MEDIA_FILE) || defined(MEDIA_DEVICE)
SUA * p_sua = (SUA *) sua;
if (NULL == p_sua->media_info.audio_decoder)
{
p_sua->media_info.audio_decoder = new CAudioDecoder();
if (p_sua->media_info.audio_decoder)
{
SDPINFO sdp;
if (sua_get_audio_sdp(p_sua, 1, 0, &sdp) >= 0)
{
int codec = AUDIO_CODEC_NONE;
if (strcasecmp(sdp.encoder, "MPEG4-GENERIC") == 0) // AAC
{
codec = AUDIO_CODEC_AAC;
}
else if (strcasecmp(sdp.encoder, "OPUS") == 0) // OPUS
{
codec = AUDIO_CODEC_OPUS;
}
else if (sdp.pt == 0) // PCMU
{
codec = AUDIO_CODEC_G711U;
}
else if (sdp.pt == 8) // PCMA
{
codec = AUDIO_CODEC_G711A;
}
else if (sdp.pt == 2) // G726
{
codec = AUDIO_CODEC_G726;
}
else if (sdp.pt == 9) // G722
{
codec = AUDIO_CODEC_G722;
}
p_sua->media_info.audio_decoder->init(codec, sdp.hz, sdp.chn);
p_sua->media_info.audio_decoder->setCallback(sip_audio_decode_cb, sua);
}
}
}
if (p_sua->media_info.audio_decoder)
{
p_sua->media_info.audio_decoder->decode(p_data, len);
}
#endif
return 0;
}
void sip_call_in(SUA * p_sua)
{
char * p_calltype = cm_get_sname(p_sua);
char * p_remote = cm_get_remote_acct(p_sua);
char * p_local = cm_get_req_acct(p_sua);
printf("calltype = %s, local = %s, remote = %s\r\n", p_calltype, p_local, p_remote);
GBCHANNEL * p_channel = gb28181_get_channel(p_local);
if (NULL == p_channel)
{
cm_sip_cmd(p_sua, PUCMD_DISCONNECT);
return;
}
if (p_channel->media_url[0] != '\0')
{
strcpy(p_sua->media_info.media_url, p_channel->media_url);
}
else
{
strcpy(p_sua->media_info.media_url, "test.mp4");
}
p_sua->media_info.v_info.codec = p_channel->output.video.codec;
#ifdef DEMO
if (VIDEO_CODEC_H265 == p_sua->media_info.v_info.codec)
{
p_sua->media_info.v_info.codec = VIDEO_CODEC_H264;
}
#endif
p_sua->media_info.v_info.width = p_channel->output.video.width;
p_sua->media_info.v_info.height = p_channel->output.video.height;
p_sua->media_info.v_info.framerate = p_channel->output.video.framerate;
p_sua->media_info.v_info.bitrate = p_channel->output.video.bitrate;
p_sua->media_info.a_info.codec = p_channel->output.audio.codec;
#ifdef DEMO
if (AUDIO_CODEC_AAC == p_sua->media_info.a_info.codec)
{
p_sua->media_info.a_info.codec = AUDIO_CODEC_G711A;
}
#endif
p_sua->media_info.a_info.samplerate = p_channel->output.audio.samplerate;
p_sua->media_info.a_info.channels = p_channel->output.audio.channels;
p_sua->media_info.a_info.bitrate = p_channel->output.audio.bitrate;
if (0 == p_sua->media_info.a_info.samplerate)
{
p_sua->media_info.a_info.samplerate = 8000;
}
if (0 == p_sua->media_info.a_info.channels)
{
p_sua->media_info.a_info.channels = 1;
}
if (VIDEO_CODEC_NONE == p_sua->media_info.v_info.codec)
{
p_sua->media_info.v_info.codec = VIDEO_CODEC_H264;
}
if (AUDIO_CODEC_NONE == p_sua->media_info.a_info.codec)
{
p_sua->media_info.a_info.codec = AUDIO_CODEC_G711A;
}
if (strcasecmp(p_calltype, "Play") == 0) // 实时视频
{
cm_clear_sua_cap(p_sua, "audio");
cm_clear_sua_cap(p_sua, "video");
p_sua->uaf_ps_audio_tx = 1;
// 可以根据远端的能力进行动态设置
cm_add_sua_cap(p_sua, "video", 96, "PS", 90000, 1, SDP_SENDRECV_TXONLY);
// cm_add_sua_cap(p_sua, "video", 97, "H264", 90000, 1, SDP_SENDRECV_TXONLY);
}
else if (strcasecmp(p_calltype, "Talk") == 0) // 语音对讲
{
int pt = 0;
char pt_name[8];
if (p_sua->media_info.a_info.codec == AUDIO_CODEC_G711A)
{
pt = 8;
strcpy(pt_name, "PCMA");
}
else if (p_sua->media_info.a_info.codec == AUDIO_CODEC_G711U)
{
pt = 0;
strcpy(pt_name, "PCMU");
}
else
{
pt = 8;
strcpy(pt_name, "PCMA");
}
cm_clear_sua_cap(p_sua, "audio");
cm_clear_sua_cap(p_sua, "video");
cm_add_sua_cap(p_sua, "audio", pt, pt_name,
p_sua->media_info.a_info.samplerate,
p_sua->media_info.a_info.channels,
SDP_SENDRECV_TXRX);
sua_set_audio_cb(p_sua, sip_audio_cb);
}
else if (strcasecmp(p_calltype, "Playback") == 0) // 录像回放
{
p_sua->uaf_playback = 1;
cm_clear_sua_cap(p_sua, "audio");
cm_clear_sua_cap(p_sua, "video");
cm_add_sua_cap(p_sua, "video", 96, "PS", 90000, 1, SDP_SENDRECV_TXONLY);
}
else if (strcasecmp(p_calltype, "Download") == 0) // 录像下载
{
p_sua->uaf_download = 1;
cm_clear_sua_cap(p_sua, "audio");
cm_clear_sua_cap(p_sua, "video");
cm_add_sua_cap(p_sua, "video", 96, "PS", 90000, 1, SDP_SENDRECV_TXONLY);
}
else
{
cm_sip_cmd(p_sua, PUCMD_DISCONNECT);
return;
}
sua_set_state_cb(p_sua, sip_call_cb, NULL);
cm_sip_cmd(p_sua, PUCMD_CONNECT);
}
BOOL sip_audio_call_out(const char * p_local, const char * p_remote)
{
SUA * p_sua = (SUA *)sua_new_handle();
if (NULL == p_sua)
{
log_print(HT_LOG_ERR, "%s, sua_new_handle failed\r\n", __FUNCTION__);
return FALSE;
}
int pt = 0;
char pt_name[8];
GBCHANNEL * p_channel = gb28181_get_channel(p_local);
if (NULL == p_channel)
{
cm_sip_cmd(p_sua, PUCMD_DISCONNECT);
return FALSE;
}
if (p_channel->media_url[0] != '\0')
{
strcpy(p_sua->media_info.media_url, p_channel->media_url);
}
else
{
strcpy(p_sua->media_info.media_url, "test.mp4");
}
p_sua->media_info.a_info.codec = p_channel->output.audio.codec;
p_sua->media_info.a_info.samplerate = p_channel->output.audio.samplerate;
p_sua->media_info.a_info.channels = p_channel->output.audio.channels;
p_sua->media_info.a_info.bitrate = p_channel->output.audio.bitrate;
if (0 == p_sua->media_info.a_info.samplerate)
{
p_sua->media_info.a_info.samplerate = 8000;
}
if (0 == p_sua->media_info.a_info.channels)
{
p_sua->media_info.a_info.channels = 1;
}
if (p_sua->media_info.a_info.codec == AUDIO_CODEC_G711A)
{
pt = 8;
strcpy(pt_name, "PCMA");
}
else if (p_sua->media_info.a_info.codec == AUDIO_CODEC_G711U)
{
pt = 0;
strcpy(pt_name, "PCMU");
}
else
{
pt = 8;
strcpy(pt_name, "PCMA");
}
p_sua->uaf_a_tcp_rtp = g_gb28181_cfg.media_protocol;
sua_set_state_cb(p_sua, sip_call_cb, NULL);
sua_set_audio_cb(p_sua, sip_audio_cb);
cm_clear_sua_cap(p_sua, "audio");
cm_clear_sua_cap(p_sua, "video");
cm_add_sua_cap(p_sua, "audio", pt, pt_name,
p_sua->media_info.a_info.samplerate,
p_sua->media_info.a_info.channels,
SDP_SENDRECV_TXRX);
cm_set_sname(p_sua, "Play");
cm_set_remote_acct(p_sua, p_remote);
return cm_sip_cmd(p_sua, PUCMD_CALL);
}
void sip_ntf_cb(uint32 index, PUAEVT evt, void * p_ctx, int len, void * user_data)
{
printf("%s, evt : %s\r\n", __FUNCTION__, sip_get_puaevt_name((PUAEVT)evt));
gb28181_put_msg(evt, index, NULL);
}
BOOL gb28181_init_proxy()
{
#ifdef MEDIA_PROXY
int i;
for (i = 0; i < g_gb28181_cfg.channel_nums; i++)
{
char proto[32];
BOOL isUrl = FALSE;
url_split(g_gb28181_cfg.channels[i].media_url, proto, sizeof(proto),
NULL, 0, NULL, 0, NULL, 0, NULL, NULL, 0);
if (strcasecmp(proto, "rtsp") == 0 ||
strcasecmp(proto, "http") == 0 ||
strcasecmp(proto, "https") == 0)
{
isUrl = TRUE;
}
#ifdef OVER_WEBSOCKET
else if (strcasecmp(proto, "ws") == 0 ||
strcasecmp(proto, "wss") == 0)
{
isUrl = TRUE;
}
#endif
#ifdef RTMP_PROXY
else if (strcasecmp(proto, "rtmp") == 0 ||
strcasecmp(proto, "rtmpt") == 0 ||
strcasecmp(proto, "rtmps") == 0 ||
strcasecmp(proto, "rtmpe") == 0 ||
strcasecmp(proto, "rtmpfp") == 0 ||
strcasecmp(proto, "rtmpte") == 0 ||
strcasecmp(proto, "rtmpts") == 0)
{
isUrl = TRUE;
}
#endif
#ifdef SRT_PROXY
else if (strcasecmp(proto, "srt") == 0)
{
isUrl = TRUE;
}
#endif
if (!isUrl)
{
continue;
}
MEDIA_PRY * p_proxy = media_add_proxy();
if (p_proxy)
{
p_proxy->cfg.has_output = 1;
strcpy(p_proxy->cfg.key, g_gb28181_cfg.channels[i].cid);
strcpy(p_proxy->cfg.url, g_gb28181_cfg.channels[i].media_url);
memcpy(&p_proxy->cfg.output, &g_gb28181_cfg.channels[i].output, sizeof(MEDIA_INFO));
}
}
int nums = media_get_proxy_nums();
if (0 == nums)
{
return TRUE;
}
rtsp_parse_buf_init(4 * nums);
http_msg_buf_init(4 * nums);
#ifdef RTMP_PROXY
gb28181_set_rtmp_log();
#endif
media_init_proxies();
#endif
return TRUE;
}
BOOL gb28181_init()
{
if (g_gb28181_cfg.server_port <= 0 || g_gb28181_cfg.server_port > 65535)
{
g_gb28181_cfg.server_port = 5060;
}
if (g_gb28181_cfg.media_base_port == 0 || g_gb28181_cfg.media_base_port > 65500)
{
g_gb28181_cfg.media_base_port = 19000;
}
memset(&g_gb28181_cls, 0, sizeof(g_gb28181_cls));
g_gb28181_cls.msg_queue = hqCreate(MAX_CH_NUMS * 2, sizeof(GBMSG), HQ_GET_WAIT);
if (NULL == g_gb28181_cls.msg_queue)
{
log_print(HT_LOG_ERR, "%s, create task queue failed!!!\r\n", __FUNCTION__);
return FALSE;
}
return TRUE;
}
void gb28181_put_msg(int evt, uint32 index, void * sua)
{
GBMSG scm;
memset(&scm, 0, sizeof(scm));
scm.evt = evt;
scm.index = index;
scm.sua = sua;
if (hqBufPut(g_gb28181_cls.msg_queue, (char *)&scm) == FALSE)
{
log_print(HT_LOG_ERR, "%s, hqBufPut return fail!!!\r\n", __FUNCTION__);
}
}
void * gb28181_task(void * argv)
{
GBMSG scm;
memset(&scm, 0, sizeof(scm));
while (g_gb28181_cls.task_running)
{
if (hqBufGet(g_gb28181_cls.msg_queue, (char *)&scm))
{
switch(scm.evt)
{
case PUEVT_REG_PASS: // 注册成功
log_print(HT_LOG_INFO, "reg pass!\r\n");
break;
case PUEVT_REG_FAIL: // 认证失败
log_print(HT_LOG_INFO, "reg failed!\r\n");
break;
case PUEVT_CALL_IN: // 呼叫进入
sip_call_in(sua_get_by_index(scm.index));
break;
case PUEVT_HANGUP:
case PUEVT_LINE_FREE:
case PUEVT_TMEP_UNAVAILABLE:
case PUEVT_BUSY:
case PUEVT_CALL_FORBIDDEN:
case PUEVT_CANCEL_FINISH:
case PUEVT_CALL_TERMINATE:
case PUEVT_ERROR:
case PUEVT_M_TIMEOUT:
case PUEVT_TIMEOUT:
break;
}
}
}
g_gb28181_cls.tid_task = 0;
return NULL;
}
// GB28181 SIP注册校时
void gb28181_time_update(const char * time_str)
{
printf("sip server date : %s\r\n", time_str);
log_print(HT_LOG_INFO, "sip server date : %s\r\n", time_str);
time_t st = get_time_by_tstring(time_str);
if (st > 0)
{
// struct timeval tv;
// tv.tv_sec = st;
// tv.tv_usec= 0;
// settimeofday(&tv, (struct timezone *)0);
}
}
BOOL gb28181_start1()
{
if (!gb28181_init())
{
log_print(HT_LOG_ERR, "%s, gb28181_init failed\r\n", __FUNCTION__);
return FALSE;
}
srand((uint32)time(NULL));
sip_start();
gb28181_init_proxy();
sprintf(hsip.ver, "Happytime GB28181 %s", GB_DEVICE_VERSION);
cm_set_ntf_func(sip_ntf_cb, NULL);
cm_server_set(g_gb28181_cfg.server_ip, g_gb28181_cfg.server_port, g_gb28181_cfg.server_id, g_gb28181_cfg.server_domain);
cm_acct_set(g_gb28181_cfg.device_id, g_gb28181_cfg.password, g_gb28181_cfg.protocol);
if (!cm_start_reg())
{
log_print(HT_LOG_ERR, "%s, register failed\r\n", __FUNCTION__);
return FALSE;
}
g_gb28181_cls.task_running = 1;
g_gb28181_cls.tid_task = sys_os_create_thread((void *)gb28181_task, 0);
return TRUE;
}
BOOL gb28181_start(const char * config)
{
printf("Happytime GB28181 Device %s\r\n", GB_DEVICE_VERSION);
gb28181_read_config(config);
if (g_gb28181_cfg.log_enable)
{
log_init(GB28181_LOG_FILE);
log_set_level(g_gb28181_cfg.log_level);
}
else
{
log_close();
}
return gb28181_start1();
}
void gb28181_stop()
{
sip_stop();
g_gb28181_cls.task_running = 0;
// 停止gb28181 task
log_print(HT_LOG_INFO, "%s, stop gb28181 task.\r\n", __FUNCTION__);
GBMSG scm;
memset(&scm, 0, sizeof(GBMSG));
hqBufPut(g_gb28181_cls.msg_queue, (char *)&scm);
while (g_gb28181_cls.tid_task != 0)
{
usleep(100*1000);
}
hqDelete(g_gb28181_cls.msg_queue);
log_close();
}