/*************************************************************************************** * * 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(); }