diff --git a/3rdpart/ZLToolKit b/3rdpart/ZLToolKit index 065b7562..1126175e 160000 --- a/3rdpart/ZLToolKit +++ b/3rdpart/ZLToolKit @@ -1 +1 @@ -Subproject commit 065b75623da5f9bb5916cecd853936a6670d71c5 +Subproject commit 1126175e2aabd811ba906e9699b43caf5837179d diff --git a/Android/app/build.gradle b/Android/app/build.gradle index 56c5646d..7e02236a 100644 --- a/Android/app/build.gradle +++ b/Android/app/build.gradle @@ -13,6 +13,7 @@ android { externalNativeBuild { cmake { cppFlags "-std=c++11 -frtti -fexceptions" + arguments "-DENABLE_API=off", "-DENABLE_TESTS=off", "-DENABLE_PLAYER=off", "-DENABLE_SERVER_LIB=on" } } ndk { diff --git a/Android/app/src/main/cpp/CMakeLists.txt b/Android/app/src/main/cpp/CMakeLists.txt index 9d3aac46..dfbe9f58 100644 --- a/Android/app/src/main/cpp/CMakeLists.txt +++ b/Android/app/src/main/cpp/CMakeLists.txt @@ -6,106 +6,33 @@ set(CMAKE_CXX_STANDARD 11) #设置生成的so动态库最后输出的路径 set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/libs_export/${ANDROID_ABI}) set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/libs_export/${ANDROID_ABI}) - -LINK_DIRECTORIES(${LIBRARY_OUTPUT_PATH}) +set(EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_SOURCE_DIR}/libs_export/${ANDROID_ABI}/binary) +set(OPENSSL_ROOT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../../../libs/${ANDROID_ABI}") +set(OPENSSL_INCLUDE_DIR "${OPENSSL_ROOT_DIR}/include") +set(OPENSSL_CRYPTO_LIBRARY "${OPENSSL_ROOT_DIR}/libcrypto.a") +set(OPENSSL_SSL_LIBRARY "${OPENSSL_ROOT_DIR}/libssl.a") #设置工程源码根目录 -set(ZLMediaKit_Root ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../) set(JNI_Root ${CMAKE_CURRENT_SOURCE_DIR}) -set(ToolKit_Root ${ZLMediaKit_Root}/3rdpart/ZLToolKit/src) -set(MediaKit_Root ${ZLMediaKit_Root}/src) -set(MediaServer_Root ${ZLMediaKit_Root}/3rdpart/media-server/) +set(ZLMediaKit_Root ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../) -#设置头文件目录 -INCLUDE_DIRECTORIES(${ToolKit_Root}) -INCLUDE_DIRECTORIES(${MediaKit_Root}) -INCLUDE_DIRECTORIES(${JNI_Root}) +#添加主工程cmake +add_subdirectory(${ZLMediaKit_Root} ${EXECUTABLE_OUTPUT_PATH}) -#收集源代码 -file(GLOB ToolKit_src_list ${ToolKit_Root}/*/*.cpp ${ToolKit_Root}/*/*.h ${ToolKit_Root}/*/*.c) -file(GLOB MediaKit_src_list ${MediaKit_Root}/*/*.cpp ${MediaKit_Root}/*/*.h ${MediaKit_Root}/*/*.c) +#设置include +include_directories(${JNI_Root}) +include_directories(${ZLMediaKit_Root}/src) +include_directories(${ZLMediaKit_Root}/srt) +include_directories(${ZLMediaKit_Root}/webrtc) +include_directories(${ZLMediaKit_Root}/server) +include_directories(${ZLMediaKit_Root}/3rdpart) +include_directories(${ZLMediaKit_Root}/3rdpart/media-server) +include_directories(${ZLMediaKit_Root}/3rdpart/ZLToolKit/src) + +#收集源代码添加动态库 file(GLOB JNI_src_list ${JNI_Root}/*.cpp ${JNI_Root}/*.h) - -#去除win32的适配代码 -if (NOT WIN32) - list(REMOVE_ITEM ToolKit_src_list ${ToolKit_Root}/win32/getopt.c) -else() - #防止Windows.h包含Winsock.h - add_definitions(-DWIN32_LEAN_AND_MEAN -DMP4V2_NO_STDINT_DEFS) -endif () - -set(ENABLE_HLS true) -set(ENABLE_OPENSSL true) -set(ENABLE_MYSQL false) -set(ENABLE_FAAC false) -set(ENABLE_X264 false) -set(ENABLE_MP4 true) - -#添加两个静态库 -if(ENABLE_HLS) - message(STATUS "ENABLE_HLS defined") - add_definitions(-DENABLE_HLS) - set(LINK_LIB_LIST zlmediakit zltoolkit mpeg) -else() - set(LINK_LIB_LIST zlmediakit zltoolkit) -endif() - - -if(ENABLE_MP4) - message(STATUS "ENABLE_MP4 defined") - add_definitions(-DENABLE_MP4) - list(APPEND LINK_LIB_LIST mov flv) -endif() - -if (ENABLE_OPENSSL) - #openssl - add_definitions(-DENABLE_OPENSSL) - INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/../../../libs/${ANDROID_ABI}/include) - LINK_DIRECTORIES(${CMAKE_SOURCE_DIR}/../../../libs/${ANDROID_ABI}/) - list(APPEND LINK_LIB_LIST ssl crypto) -endif () - -#libmpeg -if(ENABLE_HLS) - aux_source_directory(${MediaServer_Root}/libmpeg/include src_mpeg) - aux_source_directory(${MediaServer_Root}/libmpeg/source src_mpeg) - include_directories(${MediaServer_Root}/libmpeg/include) - add_library(mpeg STATIC ${src_mpeg}) - if(MSVC) - set_target_properties(mpeg PROPERTIES COMPILE_FLAGS ${VS_FALGS} ) - endif() -endif() - -if(ENABLE_MP4) - aux_source_directory(${MediaServer_Root}/libmov/include src_mov) - aux_source_directory(${MediaServer_Root}/libmov/source src_mov) - include_directories(${MediaServer_Root}/libmov/include) - aux_source_directory(${MediaServer_Root}/libflv/include src_flv) - aux_source_directory(${MediaServer_Root}/libflv/source src_flv) - include_directories(${MediaServer_Root}/libflv/include) - add_library(mov STATIC ${src_mov}) - add_library(flv STATIC ${src_flv}) - if(MSVC) - set_target_properties(mov flv PROPERTIES COMPILE_FLAGS ${VS_FALGS} ) - endif() -endif() - - -#添加库 -add_library(zltoolkit STATIC ${ToolKit_src_list}) -add_library(zlmediakit STATIC ${MediaKit_src_list}) add_library(zlmediakit_jni SHARED ${JNI_src_list}) -add_definitions(-DDISABLE_MAIN) -#添加json以及MediaServer相关代码 -include_directories(${ZLMediaKit_Root}/3rdpart) -include_directories(${ZLMediaKit_Root}/server) -file(GLOB jsoncpp_src_list ${ZLMediaKit_Root}/3rdpart/jsoncpp/*.cpp) -file(GLOB MediaServer_src_list ${ZLMediaKit_Root}/server/*.cpp) -add_library(jsoncpp STATIC ${jsoncpp_src_list}) -add_library(MediaServer STATIC ${MediaServer_src_list}) - #链接 -target_link_libraries(zlmediakit_jni MediaServer jsoncpp ${LINK_LIB_LIST} log z) - +target_link_libraries(zlmediakit_jni -Wl,--start-group log z ${LINK_LIB_LIST} -Wl,--end-group) diff --git a/Android/app/src/main/cpp/native-lib.cpp b/Android/app/src/main/cpp/native-lib.cpp index 016d81ff..5713b11e 100644 --- a/Android/app/src/main/cpp/native-lib.cpp +++ b/Android/app/src/main/cpp/native-lib.cpp @@ -15,92 +15,94 @@ #include "Common/config.h" #include "Player/MediaPlayer.h" #include "Extension/Frame.h" + using namespace std; using namespace toolkit; using namespace mediakit; -#define JNI_API(retType,funName,...) extern "C" JNIEXPORT retType Java_com_zlmediakit_jni_ZLMediaKit_##funName(JNIEnv* env, jclass cls,##__VA_ARGS__) +#define JNI_API(retType, funName, ...) extern "C" JNIEXPORT retType Java_com_zlmediakit_jni_ZLMediaKit_##funName(JNIEnv* env, jclass cls,##__VA_ARGS__) #define MediaPlayerCallBackSign "com/zlmediakit/jni/ZLMediaKit$MediaPlayerCallBack" #define MediaFrameSign "com/zlmediakit/jni/ZLMediaKit$MediaFrame" - -string stringFromJstring(JNIEnv *env,jstring jstr){ - if(!env || !jstr){ +string stringFromJstring(JNIEnv *env, jstring jstr) { + if (!env || !jstr) { WarnL << "invalid args"; return ""; } const char *field_char = env->GetStringUTFChars(jstr, 0); - string ret(field_char,env->GetStringUTFLength(jstr)); + string ret(field_char, env->GetStringUTFLength(jstr)); env->ReleaseStringUTFChars(jstr, field_char); return ret; } -string stringFromJbytes(JNIEnv *env,jbyteArray jbytes){ - if(!env || !jbytes){ + +string stringFromJbytes(JNIEnv *env, jbyteArray jbytes) { + if (!env || !jbytes) { WarnL << "invalid args"; return ""; } jbyte *bytes = env->GetByteArrayElements(jbytes, 0); - string ret((char *)bytes,env->GetArrayLength(jbytes)); - env->ReleaseByteArrayElements(jbytes,bytes,0); + string ret((char *) bytes, env->GetArrayLength(jbytes)); + env->ReleaseByteArrayElements(jbytes, bytes, 0); return ret; } -string stringFieldFromJava(JNIEnv *env, jobject jdata,jfieldID jid){ - if(!env || !jdata || !jid){ + +string stringFieldFromJava(JNIEnv *env, jobject jdata, jfieldID jid) { + if (!env || !jdata || !jid) { WarnL << "invalid args"; return ""; } - jstring field_str = (jstring)env->GetObjectField(jdata,jid); - auto ret = stringFromJstring(env,field_str); + jstring field_str = (jstring) env->GetObjectField(jdata, jid); + auto ret = stringFromJstring(env, field_str); env->DeleteLocalRef(field_str); return ret; } -string bytesFieldFromJava(JNIEnv *env, jobject jdata,jfieldID jid){ - if(!env || !jdata || !jid){ +string bytesFieldFromJava(JNIEnv *env, jobject jdata, jfieldID jid) { + if (!env || !jdata || !jid) { WarnL << "invalid args"; return ""; } - jbyteArray jbufArray = (jbyteArray)env->GetObjectField(jdata, jid); - string ret = stringFromJbytes(env,jbufArray); + jbyteArray jbufArray = (jbyteArray) env->GetObjectField(jdata, jid); + string ret = stringFromJbytes(env, jbufArray); env->DeleteLocalRef(jbufArray); return ret; } -jstring jstringFromString(JNIEnv* env, const char* pat) { - return (jstring)env->NewStringUTF(pat); +jstring jstringFromString(JNIEnv *env, const char *pat) { + return (jstring) env->NewStringUTF(pat); } -jbyteArray jbyteArrayFromString(JNIEnv* env, const char* pat,int len = 0){ - if(len <= 0){ +jbyteArray jbyteArrayFromString(JNIEnv *env, const char *pat, int len = 0) { + if (len <= 0) { len = strlen(pat); } jbyteArray jarray = env->NewByteArray(len); - env->SetByteArrayRegion(jarray, 0, len, (jbyte *)(pat)); + env->SetByteArrayRegion(jarray, 0, len, (jbyte * )(pat)); return jarray; } -jobject makeJavaFrame(JNIEnv* env,const Frame::Ptr &frame){ - static jclass jclass_obj = (jclass)env->NewGlobalRef(env->FindClass(MediaFrameSign)); +jobject makeJavaFrame(JNIEnv *env, const Frame::Ptr &frame) { + static jclass jclass_obj = (jclass) env->NewGlobalRef(env->FindClass(MediaFrameSign)); static jmethodID jmethodID_init = env->GetMethodID(jclass_obj, "", "()V"); - static jfieldID jfieldID_dts = env->GetFieldID(jclass_obj,"dts","I"); - static jfieldID jfieldID_pts = env->GetFieldID(jclass_obj,"pts","I"); - static jfieldID jfieldID_prefixSize = env->GetFieldID(jclass_obj,"prefixSize","I"); - static jfieldID jfieldID_keyFrame = env->GetFieldID(jclass_obj,"keyFrame","Z"); - static jfieldID jfieldID_data = env->GetFieldID(jclass_obj,"data","[B"); - static jfieldID jfieldID_trackType = env->GetFieldID(jclass_obj,"trackType","I"); - static jfieldID jfieldID_codecId = env->GetFieldID(jclass_obj,"codecId","I"); + static jfieldID jfieldID_dts = env->GetFieldID(jclass_obj, "dts", "I"); + static jfieldID jfieldID_pts = env->GetFieldID(jclass_obj, "pts", "I"); + static jfieldID jfieldID_prefixSize = env->GetFieldID(jclass_obj, "prefixSize", "I"); + static jfieldID jfieldID_keyFrame = env->GetFieldID(jclass_obj, "keyFrame", "Z"); + static jfieldID jfieldID_data = env->GetFieldID(jclass_obj, "data", "[B"); + static jfieldID jfieldID_trackType = env->GetFieldID(jclass_obj, "trackType", "I"); + static jfieldID jfieldID_codecId = env->GetFieldID(jclass_obj, "codecId", "I"); - if(!frame){ + if (!frame) { return nullptr; } jobject ret = env->NewObject(jclass_obj, jmethodID_init); - env->SetIntField(ret,jfieldID_dts,frame->dts()); - env->SetIntField(ret,jfieldID_pts,frame->pts()); - env->SetIntField(ret,jfieldID_prefixSize,frame->prefixSize()); - env->SetBooleanField(ret,jfieldID_keyFrame,frame->keyFrame()); - env->SetObjectField(ret,jfieldID_data,jbyteArrayFromString(env,frame->data(),frame->size())); - env->SetIntField(ret,jfieldID_trackType,frame->getTrackType()); - env->SetIntField(ret,jfieldID_codecId,frame->getCodecId()); + env->SetIntField(ret, jfieldID_dts, frame->dts()); + env->SetIntField(ret, jfieldID_pts, frame->pts()); + env->SetIntField(ret, jfieldID_prefixSize, frame->prefixSize()); + env->SetBooleanField(ret, jfieldID_keyFrame, frame->keyFrame()); + env->SetObjectField(ret, jfieldID_data, jbyteArrayFromString(env, frame->data(), frame->size())); + env->SetIntField(ret, jfieldID_trackType, frame->getTrackType()); + env->SetIntField(ret, jfieldID_codecId, frame->getCodecId()); return ret; } @@ -160,7 +162,8 @@ JNIEXPORT void JNICALL JNI_OnUnload(JavaVM* vm, void* reserved){ } extern int start_main(int argc,char *argv[]); -JNI_API(jboolean,startDemo,jstring ini_dir){ + +JNI_API(jboolean, startDemo, jstring ini_dir){ string sd_path = stringFromJstring(env,ini_dir); string ini_file = sd_path + "/zlmediakit.ini"; @@ -185,9 +188,9 @@ JNI_API(jboolean,startDemo,jstring ini_dir){ mINI::Instance()["rtsp.port"] = 8554; mINI::Instance()["rtsp.sslport"] = 8332; mINI::Instance()["general.enableVhost"] = 0; - for(auto &pr : mINI::Instance()){ + for (auto &pr : mINI::Instance()) { //替换hook默认地址 - replace(pr.second,"https://127.0.0.1/","http://127.0.0.1:8080/"); + replace(pr.second, "https://127.0.0.1/", "http://127.0.0.1:8080/"); } //默认打开hook mINI::Instance()["hook.enable"] = 0; @@ -195,10 +198,9 @@ JNI_API(jboolean,startDemo,jstring ini_dir){ mINI::Instance()["api.apiDebug"] = 1; int argc = 5; - const char *argv[] = {"","-c",ini_file.data(),"-s",pem_file.data()}; - - start_main(argc,(char **)argv); - }catch (std::exception &ex){ + const char *argv[] = {"", "-c", ini_file.data(), "-s", pem_file.data()}; + start_main(argc, (char **) argv); + } catch (std::exception &ex) { WarnL << ex.what(); } }); @@ -210,7 +212,7 @@ JNI_API(jboolean,startDemo,jstring ini_dir){ return true; }; -JNI_API(jlong,createMediaPlayer,jstring url,jobject callback){ +JNI_API(jlong, createMediaPlayer, jstring url, jobject callback){ static auto loadFrameClass = makeJavaFrame(env,nullptr); MediaPlayer::Ptr *ret = new MediaPlayer::Ptr(new MediaPlayer()); MediaPlayer::Ptr &player = *ret; @@ -260,8 +262,6 @@ JNI_API(jlong,createMediaPlayer,jstring url,jobject callback){ return (jlong)(ret); } - - JNI_API(void,releaseMediaPlayer,jlong ptr){ MediaPlayer::Ptr *player = (MediaPlayer::Ptr *)ptr; delete player; diff --git a/CMakeLists.txt b/CMakeLists.txt index 1db883c5..eb193431 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -98,11 +98,12 @@ option(ENABLE_API "Enable C API SDK" true) option(ENABLE_CXX_API "Enable C++ API SDK" false) option(ENABLE_TESTS "Enable Tests" true) option(ENABLE_SERVER "Enable Server" true) +option(ENABLE_SERVER_LIB "Enable server as android static library" false) option(ENABLE_MEM_DEBUG "Enable Memory Debug" false) option(ENABLE_ASAN "Enable Address Sanitize" false) option(ENABLE_WEBRTC "Enable WebRTC" true) option(ENABLE_PLAYER "Enable Player" true) -option(ENABLE_FFMPEG "Enable FFmpeg" true) +option(ENABLE_FFMPEG "Enable FFmpeg" false) option(ENABLE_MSVC_MT "Enable MSVC Mt/Mtd lib" true) option(ENABLE_API_STATIC_LIB "Enable mk_api static lib" false) option(USE_SOLUTION_FOLDERS "Enable solution dir supported" ON) @@ -307,7 +308,7 @@ if (JEMALLOC_FOUND) endif () #查找openssl是否安装 -find_package(OpenSSL QUIET) +find_package(OPENSSL QUIET) if (OPENSSL_FOUND AND ENABLE_OPENSSL) message(STATUS "found library:${OPENSSL_LIBRARIES},ENABLE_OPENSSL defined") include_directories(${OPENSSL_INCLUDE_DIR}) @@ -521,3 +522,7 @@ endif () if (ENABLE_PLAYER) add_subdirectory(player) endif () + +if (ENABLE_SERVER_LIB) + set(LINK_LIB_LIST ${LINK_LIB_LIST} PARENT_SCOPE) +endif () diff --git a/conf/config.ini b/conf/config.ini index 6ef59a26..49533769 100644 --- a/conf/config.ini +++ b/conf/config.ini @@ -157,6 +157,10 @@ on_server_keepalive=https://127.0.0.1/index/hook/on_server_keepalive timeoutSec=10 #keepalive hook触发间隔,单位秒,float类型 alive_interval=10.0 +#hook通知失败重试次数,正整数。为0不重试,1时重试一次,以此类推 +retry=1 +#hook通知失败重试延时,单位秒,float型 +retry_delay=3.0 [cluster] #设置源站拉流url模板, 格式跟printf类似,第一个%s指定app,第二个%s指定stream_id, @@ -200,10 +204,13 @@ dirMenu=1 #访问 http://127.0.0.1/app_b/file_b 对应的文件路径为 /path/to/b/file_b #访问其他http路径,对应的文件路径还是在rootPath内 virtualPath= -#禁止后缀的文件缓存,使用“,”隔开 +#禁止后缀的文件使用mmap缓存,使用“,”隔开 #例如赋值为 .mp4,.flv #那么访问后缀为.mp4与.flv 的文件不缓存 forbidCacheSuffix= +#可以把http代理前真实客户端ip放在http头中:https://github.com/ZLMediaKit/ZLMediaKit/issues/1388 +#切勿暴露此key,否则可能导致伪造客户端ip +forwarded_ip_header= [multicast] #rtp组播截止组播ip地址 diff --git a/server/CMakeLists.txt b/server/CMakeLists.txt index 37735b55..a94654a2 100644 --- a/server/CMakeLists.txt +++ b/server/CMakeLists.txt @@ -3,6 +3,14 @@ file(GLOB jsoncpp_src_list ../3rdpart/jsoncpp/*.cpp ../3rdpart/jsoncpp/*.h ) add_library(jsoncpp STATIC ${jsoncpp_src_list}) file(GLOB MediaServer_src_list ./*.cpp ./*.h) +if (ENABLE_SERVER_LIB) + add_definitions(-DDISABLE_MAIN) + add_library(MediaServer STATIC ${MediaServer_src_list}) + list(APPEND LINK_LIB_LIST MediaServer jsoncpp) + set(LINK_LIB_LIST ${LINK_LIB_LIST} PARENT_SCOPE) + return() +endif () + add_executable(MediaServer ${MediaServer_src_list}) if(MSVC) diff --git a/server/WebHook.cpp b/server/WebHook.cpp index d0470af0..711ae4fb 100755 --- a/server/WebHook.cpp +++ b/server/WebHook.cpp @@ -47,6 +47,8 @@ const string kOnServerStarted = HOOK_FIELD"on_server_started"; const string kOnServerKeepalive = HOOK_FIELD"on_server_keepalive"; const string kAdminParams = HOOK_FIELD"admin_params"; const string kAliveInterval = HOOK_FIELD"alive_interval"; +const string kRetry = HOOK_FIELD"retry"; +const string kRetryDelay = HOOK_FIELD"retry_delay"; onceToken token([](){ mINI::Instance()[kEnable] = false; @@ -68,6 +70,8 @@ onceToken token([](){ mINI::Instance()[kOnServerKeepalive] = ""; mINI::Instance()[kAdminParams] = "secret=035c73f7-bb6b-4889-a715-d9eb2d1925cc"; mINI::Instance()[kAliveInterval] = 30.0; + mINI::Instance()[kRetry] = 1; + mINI::Instance()[kRetryDelay] = 3.0; },nullptr); }//namespace Hook @@ -147,9 +151,10 @@ string getVhost(const HttpArgs &value) { return val != value.end() ? val->second : ""; } -void do_http_hook(const string &url,const ArgsType &body,const function &func){ +void do_http_hook(const string &url, const ArgsType &body, const function &func, uint32_t retry) { GET_CONFIG(string, mediaServerId, General::kMediaServerId); GET_CONFIG(float, hook_timeoutSec, Hook::kTimeoutSec); + GET_CONFIG(float, retry_delay, Hook::kRetryDelay); const_cast(body)["mediaServerId"] = mediaServerId; HttpRequester::Ptr requester(new HttpRequester); @@ -161,25 +166,40 @@ void do_http_hook(const string &url,const ArgsType &body,const functionaddHeader("X-VHOST", vhost); } - std::shared_ptr pTicker(new Ticker); - requester->startRequester(url, [url, func, bodyStr, requester, pTicker](const SockException &ex, - const Parser &res) mutable{ - onceToken token(nullptr, [&]() mutable{ - requester.reset(); - }); - parse_http_response(ex, res, [&](const Value &obj, const string &err) { + Ticker ticker; + requester->startRequester(url, [url, func, bodyStr, body, requester, ticker, retry](const SockException &ex, const Parser &res) mutable { + onceToken token(nullptr, [&]() mutable { requester.reset(); }); + parse_http_response(ex, res, [&](const Value &obj, const string &err) { + if (!err.empty()) { + // hook失败 + WarnL << "hook " << url << " " << ticker.elapsedTime() << "ms,failed" << err << ":" << bodyStr; + + if (retry-- > 0) { + requester->getPoller()->doDelayTask(MAX(retry_delay, 0.0) * 1000, [url, body, func, retry] { + do_http_hook(url, body, func, retry); + return 0; + }); + //重试不需要触发回调 + return; + } + + } else if (ticker.elapsedTime() > 500) { + //hook成功,但是hook响应超过500ms,打印警告日志 + DebugL << "hook " << url << " " << ticker.elapsedTime() << "ms,success:" << bodyStr; + } + if (func) { func(obj, err); } - if (!err.empty()) { - WarnL << "hook " << url << " " << pTicker->elapsedTime() << "ms,failed" << err << ":" << bodyStr; - } else if (pTicker->elapsedTime() > 500) { - DebugL << "hook " << url << " " << pTicker->elapsedTime() << "ms,success:" << bodyStr; - } }); }, hook_timeoutSec); } +void do_http_hook(const string &url, const ArgsType &body, const function &func) { + GET_CONFIG(uint32_t, hook_retry, Hook::kRetry); + do_http_hook(url, body, func, hook_retry); +} + static ArgsType make_json(const MediaInfo &args){ ArgsType body; body["schema"] = args._schema; diff --git a/src/Common/MediaSource.cpp b/src/Common/MediaSource.cpp index 531221ba..3437de93 100644 --- a/src/Common/MediaSource.cpp +++ b/src/Common/MediaSource.cpp @@ -233,10 +233,17 @@ toolkit::EventPoller::Ptr MediaSource::getOwnerPoller() { } void MediaSource::onReaderChanged(int size) { - auto listener = _listener.lock(); - if (listener) { - listener->onReaderChanged(*this, size); - } + weak_ptr weak_self = shared_from_this(); + getOwnerPoller()->async([weak_self, size]() { + auto strong_self = weak_self.lock(); + if (!strong_self) { + return; + } + auto listener = strong_self->_listener.lock(); + if (listener) { + listener->onReaderChanged(*strong_self, size); + } + }); } bool MediaSource::setupRecord(Recorder::type type, bool start, const string &custom_path, size_t max_second){ @@ -581,7 +588,7 @@ MediaSource::Ptr MediaSource::createFromMP4(const string &schema, const string & /////////////////////////////////////MediaSourceEvent////////////////////////////////////// void MediaSourceEvent::onReaderChanged(MediaSource &sender, int size){ - if (size) { + if (size || totalReaderCount(sender)) { //还有人观看该视频,不触发关闭事件 _async_close_timer = nullptr; return; @@ -618,7 +625,7 @@ void MediaSourceEvent::onReaderChanged(MediaSource &sender, int size){ strong_sender->close(false); } return false; - }, getOwnerPoller(sender)); + }, nullptr); } string MediaSourceEvent::getOriginUrl(MediaSource &sender) const { diff --git a/src/Common/Stamp.cpp b/src/Common/Stamp.cpp index 29ee3d89..364ad95e 100644 --- a/src/Common/Stamp.cpp +++ b/src/Common/Stamp.cpp @@ -11,7 +11,7 @@ #include "Stamp.h" //时间戳最大允许跳变30秒,主要是防止网络抖动导致的跳变 -#define MAX_DELTA_STAMP (30 * 1000) +#define MAX_DELTA_STAMP (3 * 1000) #define STAMP_LOOP_DELTA (60 * 1000) #define MAX_CTS 500 #define ABS(x) ((x) > 0 ? (x) : (-x)) diff --git a/src/Common/config.cpp b/src/Common/config.cpp index ae1593bf..1b775141 100644 --- a/src/Common/config.cpp +++ b/src/Common/config.cpp @@ -124,6 +124,7 @@ const string kVirtualPath = HTTP_FIELD "virtualPath"; const string kNotFound = HTTP_FIELD "notFound"; const string kDirMenu = HTTP_FIELD "dirMenu"; const string kForbidCacheSuffix = HTTP_FIELD "forbidCacheSuffix"; +const string kForwardedIpHeader = HTTP_FIELD "forwarded_ip_header"; static onceToken token([]() { mINI::Instance()[kSendBufSize] = 64 * 1024; @@ -150,6 +151,7 @@ static onceToken token([]() { "" << endl; mINI::Instance()[kForbidCacheSuffix] = ""; + mINI::Instance()[kForwardedIpHeader] = ""; }); } // namespace Http diff --git a/src/Common/config.h b/src/Common/config.h index ad87247e..787a1fe2 100644 --- a/src/Common/config.h +++ b/src/Common/config.h @@ -223,6 +223,8 @@ extern const std::string kNotFound; extern const std::string kDirMenu; // 禁止缓存文件的后缀 extern const std::string kForbidCacheSuffix; +// 可以把http代理前真实客户端ip放在http头中:https://github.com/ZLMediaKit/ZLMediaKit/issues/1388 +extern const std::string kForwardedIpHeader; } // namespace Http ////////////SHELL配置/////////// diff --git a/src/Http/HttpCookie.cpp b/src/Http/HttpCookie.cpp index 579c3542..07594453 100644 --- a/src/Http/HttpCookie.cpp +++ b/src/Http/HttpCookie.cpp @@ -29,26 +29,6 @@ void HttpCookie::setHost(const string &host) { _host = host; } -static long s_gmtoff = 0; //时间差 -static onceToken s_token([]() { -#ifdef _WIN32 - TIME_ZONE_INFORMATION tzinfo; - DWORD dwStandardDaylight; - long bias; - dwStandardDaylight = GetTimeZoneInformation(&tzinfo); - bias = tzinfo.Bias; - if (dwStandardDaylight == TIME_ZONE_ID_STANDARD) { - bias += tzinfo.StandardBias; - } - if (dwStandardDaylight == TIME_ZONE_ID_DAYLIGHT) { - bias += tzinfo.DaylightBias; - } - s_gmtoff = -bias * 60; //时间差(分钟) -#else - s_gmtoff = getLocalTime(time(nullptr)).tm_gmtoff; -#endif // _WIN32 -}); - // from https://gmbabar.wordpress.com/2010/12/01/mktime-slow-use-custom-function/#comment-58 static time_t time_to_epoch(const struct tm *ltm, int utcdiff) { const int mon_days[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; @@ -74,7 +54,7 @@ static time_t timeStrToInt(const string &date) { struct tm tt; strptime(date.data(), "%a, %b %d %Y %H:%M:%S %Z", &tt); // mktime内部有使用互斥锁,非常影响性能 - return time_to_epoch(&tt, s_gmtoff / 3600); // mktime(&tt); + return time_to_epoch(&tt, getGMTOff() / 3600); // mktime(&tt); } void HttpCookie::setExpires(const string &expires, const string &server_date) { diff --git a/src/Http/HttpFileManager.cpp b/src/Http/HttpFileManager.cpp index 0481e5bf..9fa3251f 100644 --- a/src/Http/HttpFileManager.cpp +++ b/src/Http/HttpFileManager.cpp @@ -465,6 +465,12 @@ static string getFilePath(const Parser &parser,const MediaInfo &media_info, TcpS path = rootPath; url = parser.Url(); } + for (auto &ch : url) { + if (ch == '\\') { + //如果url中存在"\",这种目录是Windows样式的;需要批量转换为标准的"/"; 防止访问目录权限外的文件 + ch = '/'; + } + } auto ret = File::absolutePath(enableVhost ? media_info._vhost + url : url, path); NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastHttpBeforeAccess, parser, ret, static_cast(sender)); return ret; diff --git a/src/Http/HttpSession.cpp b/src/Http/HttpSession.cpp index 6b9b7972..c90544b3 100644 --- a/src/Http/HttpSession.cpp +++ b/src/Http/HttpSession.cpp @@ -670,6 +670,11 @@ bool HttpSession::emitHttpEvent(bool doInvoke){ return consumed; } +std::string HttpSession::get_peer_ip() { + GET_CONFIG(string, forwarded_ip_header, Http::kForwardedIpHeader); + return forwarded_ip_header.empty() ? TcpSession::get_peer_ip() : _parser.getHeader()[forwarded_ip_header]; +} + void HttpSession::Handle_Req_POST(ssize_t &content_len) { GET_CONFIG(size_t,maxReqSize,Http::kMaxReqSize); diff --git a/src/Http/HttpSession.h b/src/Http/HttpSession.h index d78dcdc4..6f5bebdf 100644 --- a/src/Http/HttpSession.h +++ b/src/Http/HttpSession.h @@ -97,6 +97,9 @@ protected: */ void onWebSocketDecodeComplete(const WebSocketHeader &header_in) override; + //重载获取客户端ip + std::string get_peer_ip() override; + private: void Handle_Req_GET(ssize_t &content_len); void Handle_Req_GET_l(ssize_t &content_len, bool sendBody); diff --git a/src/Rtp/RtpProcess.cpp b/src/Rtp/RtpProcess.cpp index 9f15da7a..e3767d7b 100644 --- a/src/Rtp/RtpProcess.cpp +++ b/src/Rtp/RtpProcess.cpp @@ -119,7 +119,7 @@ bool RtpProcess::inputFrame(const Frame::Ptr &frame) { return _muxer->inputFrame(frame); } if (_cached_func.size() > kMaxCachedFrame) { - WarnL << "cached frame of track(" << frame->getCodecName() << ") is too much, now dropped"; + WarnL << "cached frame of track(" << frame->getCodecName() << ") is too much, now dropped, please check your on_publish hook url in config.ini file"; return false; } auto frame_cached = Frame::getCacheAbleFrame(frame); @@ -278,7 +278,7 @@ std::shared_ptr RtpProcess::getOriginSock(MediaSource &sender) const { } toolkit::EventPoller::Ptr RtpProcess::getOwnerPoller(MediaSource &sender) { - return _sock ? _sock->getPoller() : MediaSourceEventInterceptor::getOwnerPoller(sender); + return _sock ? _sock->getPoller() : nullptr; } }//namespace mediakit diff --git a/src/Rtsp/RtspPlayer.cpp b/src/Rtsp/RtspPlayer.cpp index 4924522b..498196de 100644 --- a/src/Rtsp/RtspPlayer.cpp +++ b/src/Rtsp/RtspPlayer.cpp @@ -491,9 +491,15 @@ void RtspPlayer::onRtpPacket(const char *data, size_t len) { uint8_t interleaved = data[1]; if(interleaved %2 == 0){ trackIdx = getTrackIndexByInterleaved(interleaved); + if (trackIdx == -1) { + return; + } handleOneRtp(trackIdx, _sdp_track[trackIdx]->_type, _sdp_track[trackIdx]->_samplerate, (uint8_t *)data + RtpPacket::kRtpTcpHeaderSize, len - RtpPacket::kRtpTcpHeaderSize); }else{ trackIdx = getTrackIndexByInterleaved(interleaved - 1); + if (trackIdx == -1) { + return; + } onRtcpPacket(trackIdx, _sdp_track[trackIdx], (uint8_t *) data + RtpPacket::kRtpTcpHeaderSize, len - RtpPacket::kRtpTcpHeaderSize); } } @@ -711,7 +717,8 @@ int RtspPlayer::getTrackIndexByInterleaved(int interleaved) const { if (_sdp_track.size() == 1) { return 0; } - throw SockException(Err_shutdown, StrPrinter << "no such track with interleaved:" << interleaved); + WarnL << "no such track with interleaved:" << interleaved; + return -1; } int RtspPlayer::getTrackIndexByTrackType(TrackType track_type) const { diff --git a/srt/PacketQueue.cpp b/srt/PacketQueue.cpp index 37980ae0..9349f050 100644 --- a/srt/PacketQueue.cpp +++ b/srt/PacketQueue.cpp @@ -237,11 +237,16 @@ std::string PacketQueue::dump() { //////////////////// PacketRecvQueue ////////////////////////////////// -PacketRecvQueue::PacketRecvQueue(uint32_t max_size, uint32_t init_seq, uint32_t latency) +PacketRecvQueue::PacketRecvQueue(uint32_t max_size, uint32_t init_seq, uint32_t latency,uint32_t flag) : _pkt_cap(max_size) , _pkt_latency(latency) , _pkt_expected_seq(init_seq) - , _pkt_buf(max_size) {} + , _pkt_buf(max_size) + , _srt_flag(flag) {} + +bool PacketRecvQueue::TLPKTDrop(){ + return (_srt_flag&HSExtMessage::HS_EXT_MSG_TLPKTDROP) && (_srt_flag &HSExtMessage::HS_EXT_MSG_TSBPDRCV); +} bool PacketRecvQueue::inputPacket(DataPacket::Ptr pkt, std::list &out) { // TraceL << dump() << " seq:" << pkt->packet_seq_number; while (_size > 0 && _start == _end) { @@ -265,7 +270,7 @@ bool PacketRecvQueue::inputPacket(DataPacket::Ptr pkt, std::list _pkt_latency) { + while (timeLatency() > _pkt_latency && TLPKTDrop()) { it = _pkt_buf[_start]; if (it) { _pkt_buf[_start] = nullptr; diff --git a/srt/PacketQueue.hpp b/srt/PacketQueue.hpp index d3e224c6..95ae9c66 100644 --- a/srt/PacketQueue.hpp +++ b/srt/PacketQueue.hpp @@ -65,7 +65,7 @@ class PacketRecvQueue : public PacketQueueInterface { public: using Ptr = std::shared_ptr; - PacketRecvQueue(uint32_t max_size, uint32_t init_seq, uint32_t latency); + PacketRecvQueue(uint32_t max_size, uint32_t init_seq, uint32_t latency,uint32_t flag = 0xbf); ~PacketRecvQueue() = default; bool inputPacket(DataPacket::Ptr pkt, std::list &out); @@ -85,12 +85,15 @@ private: void insertToCycleBuf(DataPacket::Ptr pkt, uint32_t diff); DataPacket::Ptr getFirst(); DataPacket::Ptr getLast(); + bool TLPKTDrop(); private: uint32_t _pkt_cap; uint32_t _pkt_latency; uint32_t _pkt_expected_seq; + uint32_t _srt_flag; + std::vector _pkt_buf; uint32_t _start = 0; uint32_t _end = 0; diff --git a/srt/PacketSendQueue.cpp b/srt/PacketSendQueue.cpp index 92730a4a..06beddde 100644 --- a/srt/PacketSendQueue.cpp +++ b/srt/PacketSendQueue.cpp @@ -2,9 +2,10 @@ namespace SRT { -PacketSendQueue::PacketSendQueue(uint32_t max_size, uint32_t latency) +PacketSendQueue::PacketSendQueue(uint32_t max_size, uint32_t latency,uint32_t flag) : _pkt_cap(max_size) - , _pkt_latency(latency) {} + , _pkt_latency(latency) + , _srt_flag(flag) {} bool PacketSendQueue::drop(uint32_t num) { decltype(_pkt_cache.begin()) it; @@ -24,12 +25,16 @@ bool PacketSendQueue::inputPacket(DataPacket::Ptr pkt) { while (_pkt_cache.size() > _pkt_cap) { _pkt_cache.pop_front(); } - while (timeLatency() > _pkt_latency) { + while (timeLatency() > _pkt_latency && TLPKTDrop()) { _pkt_cache.pop_front(); } return true; } +bool PacketSendQueue::TLPKTDrop(){ + return (_srt_flag&HSExtMessage::HS_EXT_MSG_TLPKTDROP) && (_srt_flag &HSExtMessage::HS_EXT_MSG_TSBPDSND); +} + std::list PacketSendQueue::findPacketBySeq(uint32_t start, uint32_t end) { std::list re; decltype(_pkt_cache.begin()) it; diff --git a/srt/PacketSendQueue.hpp b/srt/PacketSendQueue.hpp index be91c663..48bb36b2 100644 --- a/srt/PacketSendQueue.hpp +++ b/srt/PacketSendQueue.hpp @@ -16,7 +16,7 @@ public: using Ptr = std::shared_ptr; using LostPair = std::pair; - PacketSendQueue(uint32_t max_size, uint32_t latency); + PacketSendQueue(uint32_t max_size, uint32_t latency,uint32_t flag = 0xbf); ~PacketSendQueue() = default; bool drop(uint32_t num); @@ -25,7 +25,9 @@ public: private: uint32_t timeLatency(); + bool TLPKTDrop(); private: + uint32_t _srt_flag; uint32_t _pkt_cap; uint32_t _pkt_latency; std::list _pkt_cache; diff --git a/srt/SrtTransport.cpp b/srt/SrtTransport.cpp index 52ecc449..0ef720f2 100644 --- a/srt/SrtTransport.cpp +++ b/srt/SrtTransport.cpp @@ -182,9 +182,9 @@ void SrtTransport::handleHandshakeConclusion(HandshakePacket &pkt, struct sockad } if (req) { if (req->srt_flag != srt_flag) { - WarnL << " not support flag " << req->srt_flag; + WarnL << " flag " << req->srt_flag; } - // srt_flag = req->srt_flag; + srt_flag = req->srt_flag; delay = delay <= req->recv_tsbpd_delay ? req->recv_tsbpd_delay : delay; } TraceL << getIdentifier() << " CONCLUSION Phase "; @@ -214,8 +214,8 @@ void SrtTransport::handleHandshakeConclusion(HandshakePacket &pkt, struct sockad sendControlPacket(res, true); TraceL << " buf size = " << res->max_flow_window_size << " init seq =" << _init_seq_number << " latency=" << delay; - _recv_buf = std::make_shared(getPktBufSize(), _init_seq_number, delay * 1e3); - _send_buf = std::make_shared(getPktBufSize(), delay * 1e3); + _recv_buf = std::make_shared(getPktBufSize(), _init_seq_number, delay * 1e3,srt_flag); + _send_buf = std::make_shared(getPktBufSize(), delay * 1e3,srt_flag); _send_packet_seq_number = _init_seq_number; _buf_delay = delay; onHandShakeFinished(_stream_id, addr); @@ -413,6 +413,7 @@ void SrtTransport::sendACKPacket() { _last_ack_pkt_seq_num = pkt->last_ack_pkt_seq_number; sendControlPacket(pkt, true); // TraceL<<"send ack "<dump(); + // TraceL<<_recv_buf->dump(); } void SrtTransport::sendLightACKPacket() { diff --git a/tests/test_rtp.cpp b/tests/test_rtp.cpp index 18047b8a..5146d380 100644 --- a/tests/test_rtp.cpp +++ b/tests/test_rtp.cpp @@ -38,6 +38,7 @@ static bool loadFile(const char *path){ uint16_t len; char rtp[0xFFFF]; struct sockaddr_storage addr = {0}; + addr.ss_family = AF_INET; auto sock = Socket::createSocket(); size_t total_size = 0; while (true) { diff --git a/webrtc/SctpAssociation.cpp b/webrtc/SctpAssociation.cpp index 6da3712b..26148ddc 100644 --- a/webrtc/SctpAssociation.cpp +++ b/webrtc/SctpAssociation.cpp @@ -1,4 +1,4 @@ -#ifdef ENABLE_SCTP +#ifdef ENABLE_SCTP #define MS_CLASS "RTC::SctpAssociation" // #define MS_LOG_DEV_LEVEL 3 diff --git a/webrtc/SctpAssociation.hpp b/webrtc/SctpAssociation.hpp index 3347c22b..548221c5 100644 --- a/webrtc/SctpAssociation.hpp +++ b/webrtc/SctpAssociation.hpp @@ -1,4 +1,4 @@ -#ifndef MS_RTC_SCTP_ASSOCIATION_HPP +#ifndef MS_RTC_SCTP_ASSOCIATION_HPP #define MS_RTC_SCTP_ASSOCIATION_HPP #ifdef ENABLE_SCTP diff --git a/webrtc/WebRtcPusher.cpp b/webrtc/WebRtcPusher.cpp index 1f27f6d2..2de44e9f 100644 --- a/webrtc/WebRtcPusher.cpp +++ b/webrtc/WebRtcPusher.cpp @@ -1,4 +1,4 @@ -/* +/* * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit). diff --git a/webrtc/WebRtcPusher.h b/webrtc/WebRtcPusher.h index 4994f214..4580684b 100644 --- a/webrtc/WebRtcPusher.h +++ b/webrtc/WebRtcPusher.h @@ -1,4 +1,4 @@ -/* +/* * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit). diff --git a/webrtc/WebRtcTransport.cpp b/webrtc/WebRtcTransport.cpp index 68f02ecb..9a9989f2 100644 --- a/webrtc/WebRtcTransport.cpp +++ b/webrtc/WebRtcTransport.cpp @@ -1,4 +1,4 @@ -/* +/* * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit). diff --git a/webrtc/WebRtcTransport.h b/webrtc/WebRtcTransport.h index 7a1cc63e..c6570226 100644 --- a/webrtc/WebRtcTransport.h +++ b/webrtc/WebRtcTransport.h @@ -1,4 +1,4 @@ -/* +/* * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit). diff --git a/webrtc/logger.h b/webrtc/logger.h index ef056b61..c6b96cdb 100644 --- a/webrtc/logger.h +++ b/webrtc/logger.h @@ -3,12 +3,12 @@ #define MS_TRACE() #define MS_ERROR PrintE -#define MS_THROW_ERROR(...) do { PrintE(__VA_ARGS__); throw std::runtime_error("error"); } while(false) +#define MS_THROW_ERROR(...) do { PrintE(__VA_ARGS__); throw std::runtime_error("MS_THROW_ERROR"); } while(false) #define MS_DUMP PrintT #define MS_DEBUG_2TAGS(tag1, tag2, ...) PrintD(__VA_ARGS__) #define MS_WARN_2TAGS(tag1, tag2, ...) PrintW(__VA_ARGS__) #define MS_DEBUG_TAG(tag, ...) PrintD(__VA_ARGS__) -#define MS_ASSERT(con, ...) do { if(!(con)) { PrintE(__VA_ARGS__); abort(); } } while(false) +#define MS_ASSERT(con, ...) do { if(!(con)) { PrintE(__VA_ARGS__); std::runtime_error("MS_ASSERT"); } } while(false) #define MS_ABORT(...) do { PrintE(__VA_ARGS__); abort(); } while(false) #define MS_WARN_TAG(tag, ...) PrintW(__VA_ARGS__) #define MS_DEBUG_DEV PrintD \ No newline at end of file