diff --git a/CMakeLists.txt b/CMakeLists.txt index dcf4983f..af75cbac 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,32 +6,26 @@ set(CMAKE_CXX_STANDARD 11) set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake") #set(CMAKE_BUILD_TYPE "Release") - -if (${CMAKE_BUILD_TYPE} MATCHES "Release") - message(STATUS "Release版本") - set(BuildType "Release") -else () - set(BuildType "Debug") - message(STATUS "Debug版本") -endif () +message(STATUS "编译类型:${CMAKE_BUILD_TYPE}") #设置bin和lib库目录 set(RELEASE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/release) -if(CMAKE_CL_64) - set(CL_32_64 64) -else(CMAKE_CL_64) - set(CL_32_64 32) -endif(CMAKE_CL_64) + if (CMAKE_SYSTEM_NAME MATCHES "Linux") - SET(LIBRARY_OUTPUT_PATH ${RELEASE_DIR}/linux${CL_32_64}/${BuildType}) - SET(EXECUTABLE_OUTPUT_PATH ${RELEASE_DIR}/linux${CL_32_64}/${BuildType}) + SET(LIBRARY_OUTPUT_PATH ${RELEASE_DIR}/linux/${CMAKE_BUILD_TYPE}) + SET(EXECUTABLE_OUTPUT_PATH ${RELEASE_DIR}/linux/${CMAKE_BUILD_TYPE}) add_compile_options(-fPIC -Wall -Wno-unused-variable -Wno-unused-value) elseif (CMAKE_SYSTEM_NAME MATCHES "Windows") - SET(LIBRARY_OUTPUT_PATH ${RELEASE_DIR}/windows${CL_32_64}/${BuildType}) - SET(EXECUTABLE_OUTPUT_PATH ${RELEASE_DIR}/windows${CL_32_64}/${BuildType}) + if (CMAKE_CL_64) + set(CL_32_64 64) + else () + set(CL_32_64 32) + endif () + SET(LIBRARY_OUTPUT_PATH ${RELEASE_DIR}/windows${CL_32_64}/${CMAKE_BUILD_TYPE}) + SET(EXECUTABLE_OUTPUT_PATH ${RELEASE_DIR}/windows${CL_32_64}/${CMAKE_BUILD_TYPE}) elseif (CMAKE_SYSTEM_NAME MATCHES "Darwin") - SET(LIBRARY_OUTPUT_PATH ${RELEASE_DIR}/mac${CL_32_64}/${BuildType}) - SET(EXECUTABLE_OUTPUT_PATH ${RELEASE_DIR}/mac${CL_32_64/${BuildType}) + SET(LIBRARY_OUTPUT_PATH ${RELEASE_DIR}/mac/${CMAKE_BUILD_TYPE}) + SET(EXECUTABLE_OUTPUT_PATH ${RELEASE_DIR}/mac/${CMAKE_BUILD_TYPE}) add_compile_options(-Wall -Wno-unused-variable -Wno-unused-value) endif () @@ -62,10 +56,9 @@ option(ENABLE_MEM_DEBUG "Enable Memory Debug" false) option(ENABLE_ASAN "Enable Address Sanitize" false) option(ENABLE_WEBRTC "Enable WebRTC" false) option(ENABLE_PLAYER "Enable Player" true) -option(ENABLE_MsvcMT "Enable MSVC Mt/Mtd lib" true) +option(ENABLE_MSVC_MT "Enable MSVC Mt/Mtd lib" true) - -if (ENABLE_STATIC AND MSVC) +if (MSVC AND ENABLE_MSVC_MT) set(CompilerFlags CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG @@ -147,7 +140,6 @@ if (OPENSSL_FOUND AND ENABLE_OPENSSL) if (CMAKE_SYSTEM_NAME MATCHES "Linux" AND OPENSSL_USE_STATIC_LIBS) list(APPEND LINK_LIB_LIST dl) endif () - else () message(WARNING "openssl未找到,rtmp将不支持flash播放器,https/wss/rtsps/rtmps也将失效") endif () @@ -301,23 +293,28 @@ if (ENABLE_WEBRTC) file(GLOB SRC_WEBRTC_LIST ./webrtc/*.cpp ./webrtc/*.h ./webrtc/*.hpp) add_library(webrtc ${SRC_WEBRTC_LIST}) list(APPEND LINK_LIB_LIST webrtc) + message(STATUS "webrtc功能已开启") else () message(WARNING "srtp未找到, webrtc相关功能打开失败") endif () endif () -if (NOT IOS) - #测试程序 - if (ENABLE_TESTS) - add_subdirectory(tests) - endif () - #主服务器 - if (ENABLE_SERVER) - add_subdirectory(server) - endif () +#ios不编译可执行程序 +if (IOS) + return() +endif() - #播放器 - if (ENABLE_PLAYER) - add_subdirectory(player) - endif () +#测试程序 +if (ENABLE_TESTS) + add_subdirectory(tests) +endif () + +#主服务器 +if (ENABLE_SERVER) + add_subdirectory(server) +endif () + +#播放器 +if (ENABLE_PLAYER) + add_subdirectory(player) endif () diff --git a/api/include/mk_media.h b/api/include/mk_media.h index 7a8f2a72..ad0b4783 100755 --- a/api/include/mk_media.h +++ b/api/include/mk_media.h @@ -143,10 +143,11 @@ API_EXPORT void API_CALL mk_media_set_on_close(mk_media ctx, on_mk_media_close c typedef int(API_CALL *on_mk_media_seek)(void *user_data,uint32_t stamp_ms); /** - * 收到客户端的pause请求时触发该回调 + * 收到客户端的pause或resume请求时触发该回调 * @param user_data 用户数据指针,通过mk_media_set_on_pause设置 + * @param pause 1:暂停, 0: 恢复 */ -typedef int(API_CALL* on_mk_media_pause)(void* user_data); +typedef int(API_CALL* on_mk_media_pause)(void* user_data, int pause); /** * 收到客户端的speed请求时触发该回调 diff --git a/api/include/mk_player.h b/api/include/mk_player.h index 81ad87b6..e0e8c83a 100755 --- a/api/include/mk_player.h +++ b/api/include/mk_player.h @@ -90,9 +90,9 @@ API_EXPORT void API_CALL mk_player_seekto(mk_player ctx, float progress); /** * 设置点播进度条 * @param ctx 对象指针 - * @param seekPos 取值范围 相对于开始时间增量 单位秒 + * @param seek_pos 取值范围 相对于开始时间增量 单位秒 */ -API_EXPORT void API_CALL mk_player_seektoByPos(mk_player ctx, int seekPos); +API_EXPORT void API_CALL mk_player_seekto_pos(mk_player ctx, int seek_pos); /** * 设置播放器开启播放结果回调函数 @@ -124,7 +124,7 @@ API_EXPORT void API_CALL mk_player_set_on_data(mk_player ctx, on_mk_play_data cb * 获取视频codec_id -1:不存在 0:H264,1:H265,2:AAC 3.G711A 4.G711U * @param ctx 播放器指针 */ -API_EXPORT int API_CALL mk_player_video_codecId(mk_player ctx); +API_EXPORT int API_CALL mk_player_video_codec_id(mk_player ctx); /** * 获取视频codec_id, vendor类型, 私有头数据 codec_id -1:不存在 0:H264,1:H265,2:AAC 3.G711A 4.G711U @@ -133,7 +133,7 @@ API_EXPORT int API_CALL mk_player_video_codecId(mk_player ctx); * @param head 厂家SDK头数据 * @param head 厂家SDK头数据长度 */ -API_EXPORT int API_CALL mk_player_video_codecId_vendor_head(mk_player ctx, char* vendor, char* head, int* headLen); +API_EXPORT int API_CALL mk_player_video_codec_id_vendor_head(mk_player ctx, char* vendor, char* head, int* headLen); /** * 获取视频宽度 @@ -154,7 +154,7 @@ API_EXPORT float API_CALL mk_player_video_fps(mk_player ctx); * 获取音频codec_id -1:不存在 0:H264,1:H265,2:AAC 3.G711A 4.G711U * @param ctx 播放器指针 */ -API_EXPORT int API_CALL mk_player_audio_codecId(mk_player ctx); +API_EXPORT int API_CALL mk_player_audio_codec_id(mk_player ctx); /** * 获取音频采样率 diff --git a/api/source/mk_media.cpp b/api/source/mk_media.cpp index 6e5e629d..e160b62e 100755 --- a/api/source/mk_media.cpp +++ b/api/source/mk_media.cpp @@ -76,24 +76,24 @@ protected: return true; } - bool seekTo(MediaSource &sender,uint32_t ui32Stamp) override{ - if(!_on_seek){ + bool seekTo(MediaSource &sender, uint32_t stamp) override { + if (!_on_seek) { return false; } - return _on_seek(_on_seek_data,ui32Stamp); + return _on_seek(_on_seek_data, stamp); } - // 通知暂停 - bool pause(MediaSource &sender) override { - if (!_on_pause) - { + + // 通知暂停或恢复 + bool pause(MediaSource &sender, bool pause) override { + if (!_on_pause) { return false; } - return _on_pause(_on_pause_data); + return _on_pause(_on_pause_data, pause); } + //通知倍数播放 - bool speed(MediaSource& sender, float speed) override { - if (!_on_speed) - { + bool speed(MediaSource &sender, float speed) override { + if (!_on_speed) { return false; } return _on_speed(_on_pause_data, speed); @@ -130,23 +130,21 @@ API_EXPORT void API_CALL mk_media_set_on_close(mk_media ctx, on_mk_media_close c (*obj)->setOnClose(cb, user_data); } -API_EXPORT void API_CALL mk_media_set_on_seek(mk_media ctx, on_mk_media_seek cb, void *user_data){ +API_EXPORT void API_CALL mk_media_set_on_seek(mk_media ctx, on_mk_media_seek cb, void *user_data) { assert(ctx); MediaHelper::Ptr *obj = (MediaHelper::Ptr *) ctx; (*obj)->setOnSeek(cb, user_data); } -API_EXPORT void API_CALL mk_media_set_on_pause(mk_media ctx, on_mk_media_pause cb, void* user_data) -{ +API_EXPORT void API_CALL mk_media_set_on_pause(mk_media ctx, on_mk_media_pause cb, void *user_data) { assert(ctx); - MediaHelper::Ptr* obj = (MediaHelper::Ptr*) ctx; + MediaHelper::Ptr *obj = (MediaHelper::Ptr *) ctx; (*obj)->setOnPause(cb, user_data); } -API_EXPORT void API_CALL mk_media_set_on_speed(mk_media ctx, on_mk_media_speed cb, void* user_data) -{ +API_EXPORT void API_CALL mk_media_set_on_speed(mk_media ctx, on_mk_media_speed cb, void *user_data) { assert(ctx); - MediaHelper::Ptr* obj = (MediaHelper::Ptr*) ctx; + MediaHelper::Ptr *obj = (MediaHelper::Ptr *) ctx; (*obj)->setOnSpeed(cb, user_data); } diff --git a/api/source/mk_player.cpp b/api/source/mk_player.cpp index d8db3182..e1fe2117 100755 --- a/api/source/mk_player.cpp +++ b/api/source/mk_player.cpp @@ -171,12 +171,12 @@ API_EXPORT void API_CALL mk_player_pause(mk_player ctx, int pause) { API_EXPORT void API_CALL mk_player_speed(mk_player ctx, float speed) { assert(ctx); - MediaPlayerForC& obj = **((MediaPlayerForC::Ptr*)ctx); + MediaPlayerForC &obj = **((MediaPlayerForC::Ptr *) ctx); auto player = obj.getPlayer(); player->getPoller()->async([speed, player]() { //切换线程后再操作 player->speed(speed); - }); + }); } API_EXPORT void API_CALL mk_player_seekto(mk_player ctx, float progress) { @@ -189,14 +189,14 @@ API_EXPORT void API_CALL mk_player_seekto(mk_player ctx, float progress) { }); } -API_EXPORT void API_CALL mk_player_seektoByPos(mk_player ctx, int seekPos){ +API_EXPORT void API_CALL mk_player_seekto_pos(mk_player ctx, int seek_pos) { assert(ctx); - MediaPlayerForC& obj = **((MediaPlayerForC::Ptr*)ctx); + MediaPlayerForC &obj = **((MediaPlayerForC::Ptr *) ctx); auto player = obj.getPlayer(); - player->getPoller()->async([seekPos, player]() { + player->getPoller()->async([seek_pos, player]() { //切换线程后再操作 - player->seekTo((uint32_t)seekPos); - }); + player->seekTo((uint32_t) seek_pos); + }); } static void mk_player_set_on_event(mk_player ctx, on_mk_play_event cb, void *user_data, int type) { @@ -219,30 +219,26 @@ API_EXPORT void API_CALL mk_player_set_on_data(mk_player ctx, on_mk_play_data cb obj.setOnData(cb,user_data); } -API_EXPORT int API_CALL mk_player_video_codecId(mk_player ctx){ +API_EXPORT int API_CALL mk_player_video_codec_id(mk_player ctx){ assert(ctx); MediaPlayerForC &obj = **((MediaPlayerForC::Ptr *)ctx); auto track = dynamic_pointer_cast(obj->getTrack(TrackVideo)); return track ? track->getCodecId() : CodecInvalid; } -API_EXPORT int API_CALL mk_player_video_codecId_vendor_head(mk_player ctx, char* vendor, char* head, int* head_len) -{ +API_EXPORT int API_CALL mk_player_video_codec_id_vendor_head(mk_player ctx, char *vendor, char *head, int *head_len) { assert(ctx); - MediaPlayerForC& obj = **((MediaPlayerForC::Ptr*)ctx); + MediaPlayerForC &obj = **((MediaPlayerForC::Ptr *) ctx); auto track = dynamic_pointer_cast(obj->getTrack(TrackVideo)); int codecId = track ? track->getCodecId() : CodecInvalid; - if (codecId == CodecH264) - { + if (codecId == CodecH264) { auto h264Track = dynamic_pointer_cast(obj->getTrack(TrackVideo)); auto pps = h264Track->getPps(); auto ppsLen = pps.size(); - if (ppsLen >= (4 + 16)) - { + if (ppsLen >= (4 + 16)) { std::string temVendor = std::string(pps.c_str() + 4, 16); memcpy(vendor, temVendor.c_str(), temVendor.length()); - if (ppsLen > (4 + 16)) - { + if (ppsLen > (4 + 16)) { std::string temHead = std::string(pps.c_str() + 20, ppsLen - 20); memcpy(head, temHead.c_str(), temHead.length()); *head_len = temHead.length(); @@ -273,7 +269,7 @@ API_EXPORT float API_CALL mk_player_video_fps(mk_player ctx) { return track ? track->getVideoFps() : 0; } -API_EXPORT int API_CALL mk_player_audio_codecId(mk_player ctx){ +API_EXPORT int API_CALL mk_player_audio_codec_id(mk_player ctx){ assert(ctx); MediaPlayerForC &obj = **((MediaPlayerForC::Ptr *)ctx); auto track = dynamic_pointer_cast(obj->getTrack(TrackAudio)); diff --git a/api/tests/pusher.c b/api/tests/pusher.c index 95f33dc7..f7bdf5fa 100644 --- a/api/tests/pusher.c +++ b/api/tests/pusher.c @@ -93,8 +93,8 @@ void API_CALL on_mk_play_event_func(void *user_data, int err_code, const char *e log_debug("play success!"); ctx->media = mk_media_create("__defaultVhost__", "live", "test", 0, 0, 0); - int video_codec = mk_player_video_codecId(ctx->player); - int audio_codec = mk_player_audio_codecId(ctx->player); + int video_codec = mk_player_video_codec_id(ctx->player); + int audio_codec = mk_player_audio_codec_id(ctx->player); if(video_codec != -1){ mk_media_init_video(ctx->media, video_codec, mk_player_video_width(ctx->player), diff --git a/server/WebApi.cpp b/server/WebApi.cpp index 9d7bf0f6..ceca6b0c 100755 --- a/server/WebApi.cpp +++ b/server/WebApi.cpp @@ -90,7 +90,7 @@ static HttpApi toApi(const function &cb) { //参数解析成map auto args = getAllArgs(parser); - cb(sender, parser.getHeader(), headerOut, args, val, invoker); + cb(sender, headerOut, HttpAllArgs(parser, args), val, invoker); }; } @@ -107,26 +107,24 @@ static HttpApi toApi(const function &cb) { HttpSession::KeyValue headerOut; headerOut["Content-Type"] = string("application/json; charset=") + charSet; - Json::Value out; - out["code"] = API::Success; + Json::Value val; + val["code"] = API::Success; if (parser["Content-Type"].find("application/json") == string::npos) { throw InvalidArgsException("该接口只支持json格式的请求"); } //参数解析成json对象然后处理 - Json::Value in; + Json::Value args; Json::Reader reader; - reader.parse(parser.Content(), in); + reader.parse(parser.Content(), args); - //参数解析成map - auto urlArgs = getAllArgs(parser); - cb(sender, parser.getHeader(), headerOut, in, urlArgs, out, invoker); + cb(sender, headerOut, HttpAllArgs(parser, args), val, invoker); }; } static HttpApi toApi(const function &cb) { return toApi([cb](API_ARGS_JSON_ASYNC) { - cb(API_ARGS_JSON_VALUE); + cb(API_ARGS_VALUE); invoker(200, headerOut, val.toStyledString()); }); } @@ -140,7 +138,7 @@ static HttpApi toApi(const function &cb) { Json::Value val; val["code"] = API::Success; - cb(sender, parser.getHeader(), headerOut, parser, val, invoker); + cb(sender, headerOut, HttpAllArgs(parser, (string &)parser.Content()), val, invoker); }; } @@ -230,19 +228,18 @@ static inline void addHttpListener(){ size = body->remainSize(); } - const std::string& content = parser.Content(); if (size && size < 4 * 1024) { string contentOut = body->readData(size)->toString(); DebugL << "\r\n# request:\r\n" << parser.Method() << " " << parser.FullUrl() << "\r\n" - << "# content:\r\n" << (content.size() > 4 * 1024 ? content.substr(0, 4 * 1024) : content) << "\r\n" - << "# response:\r\n" - << contentOut << "\r\n"; + << "# content:\r\n" << parser.Content() << "\r\n" + << "# response:\r\n" + << contentOut << "\r\n"; invoker(code, headerOut, contentOut); } else { DebugL << "\r\n# request:\r\n" << parser.Method() << " " << parser.FullUrl() << "\r\n" - << "# content:\r\n" << (content.size() > 4 * 1024 ? content.substr(0, 4 * 1024) : content) << "\r\n" - << "# response size:" - << size << "\r\n"; + << "# content:\r\n" << parser.Content() << "\r\n" + << "# response size:" + << size << "\r\n"; invoker(code, headerOut, body); } }; @@ -279,8 +276,8 @@ static recursive_mutex s_ffmpegMapMtx; #if defined(ENABLE_RTPPROXY) //rtp服务器列表 -/*static*/ unordered_map s_rtpServerMap; -/*static*/ recursive_mutex s_rtpServerMapMtx; +static unordered_map s_rtpServerMap; +static recursive_mutex s_rtpServerMapMtx; #endif static inline string getProxyKey(const string &vhost, const string &app, const string &stream) { @@ -412,7 +409,7 @@ void installWebApi() { CHECK_SECRET(); auto &ini = mINI::Instance(); int changed = API::Success; - for (auto &pr : allArgs) { + for (auto &pr : allArgs.getArgs()) { if (ini.find(pr.first) == ini.end()) { #if 1 //没有这个key @@ -564,7 +561,7 @@ void installWebApi() { CHECK_SECRET(); Value jsession; uint16_t local_port = allArgs["local_port"].as(); - string &peer_ip = allArgs["peer_ip"]; + string peer_ip = allArgs["peer_ip"]; SessionMap::Instance().for_each_session([&](const string &id,const Session::Ptr &session){ if(local_port != 0 && local_port != session->get_local_port()){ @@ -602,7 +599,7 @@ void installWebApi() { api_regist("/index/api/kick_sessions",[](API_ARGS_MAP){ CHECK_SECRET(); uint16_t local_port = allArgs["local_port"].as(); - string &peer_ip = allArgs["peer_ip"]; + string peer_ip = allArgs["peer_ip"]; size_t count_hit = 0; list session_list; @@ -859,7 +856,7 @@ void installWebApi() { //测试url http://127.0.0.1/index/api/downloadBin api_regist("/index/api/downloadBin",[](API_ARGS_MAP_ASYNC){ CHECK_SECRET(); - invoker.responseFile(headerIn,StrCaseMap(),exePath()); + invoker.responseFile(allArgs.getParser().getHeader(),StrCaseMap(),exePath()); }); #if defined(ENABLE_RTPPROXY) @@ -935,56 +932,21 @@ void installWebApi() { api_regist("/index/api/startSendRtp",[](API_ARGS_MAP_ASYNC){ CHECK_SECRET(); CHECK_ARGS("vhost", "app", "stream", "ssrc", "dst_url", "dst_port", "is_udp"); - bool isAsync = false; - if (checkArgs(allArgs, "is_async")) - isAsync = allArgs["is_async"]; - if (isAsync) - { - MediaInfo info = {}; - info._vhost = allArgs["vhost"]; - info._app = allArgs["app"]; - info._streamid = allArgs["stream"]; - info._schema = RTSP_SCHEMA; - auto session = static_cast(&sender); - auto session_ptr = session->shared_from_this(); - MediaSource::findAsync(info, session_ptr, [=](const MediaSource::Ptr& src_in) mutable { - if (!src_in) { - val["code"] = API::OtherFailed; - val["msg"] = "该媒体流不存在"; - invoker(200, headerOut, val.toStyledString()); - return; - } - auto src = dynamic_pointer_cast(src_in); - //src_port为空时,则随机本地端口 - src->startSendRtp(allArgs["dst_url"], allArgs["dst_port"], allArgs["ssrc"], allArgs["is_udp"], allArgs["src_port"], [val, headerOut, invoker](uint16_t local_port, const SockException& ex) mutable { - if (ex) { - val["code"] = API::OtherFailed; - val["msg"] = ex.what(); - } - val["local_port"] = local_port; - invoker(200, headerOut, val.toStyledString()); - }); - }); + auto src = MediaSource::find(allArgs["vhost"], allArgs["app"], allArgs["stream"]); + if (!src) { + throw ApiRetException("该媒体流不存在", API::OtherFailed); } - else - { - auto src = MediaSource::find(allArgs["vhost"], allArgs["app"], allArgs["stream"]); - if (!src) { - throw ApiRetException("该媒体流不存在", API::OtherFailed); + + //src_port为空时,则随机本地端口 + src->startSendRtp(allArgs["dst_url"], allArgs["dst_port"], allArgs["ssrc"], allArgs["is_udp"], allArgs["src_port"], [val, headerOut, invoker](uint16_t local_port, const SockException &ex) mutable{ + if (ex) { + val["code"] = API::OtherFailed; + val["msg"] = ex.what(); } - - //src_port为空时,则随机本地端口 - src->startSendRtp(allArgs["dst_url"], allArgs["dst_port"], allArgs["ssrc"], allArgs["is_udp"], allArgs["src_port"], [val, headerOut, invoker](uint16_t local_port, const SockException& ex) mutable { - if (ex) { - val["code"] = API::OtherFailed; - val["msg"] = ex.what(); - } - val["local_port"] = local_port; - invoker(200, headerOut, val.toStyledString()); - }); - } - + val["local_port"] = local_port; + invoker(200, headerOut, val.toStyledString()); + }); }); api_regist("/index/api/stopSendRtp",[](API_ARGS_MAP){ @@ -1149,7 +1111,7 @@ void installWebApi() { //截图存在,且未过期,那么返回之 res_old_snap = true; - responseSnap(path, headerIn, invoker); + responseSnap(path, allArgs.getParser().getHeader(), invoker); //中断遍历 return false; }); @@ -1171,7 +1133,7 @@ void installWebApi() { //启动FFmpeg进程,开始截图,生成临时文件,截图成功后替换为正式文件 auto new_snap_tmp = new_snap + ".tmp"; - FFmpegSnap::makeSnap(allArgs["url"], new_snap_tmp, allArgs["timeout_sec"], [invoker, headerIn, new_snap, new_snap_tmp](bool success) { + FFmpegSnap::makeSnap(allArgs["url"], new_snap_tmp, allArgs["timeout_sec"], [invoker, allArgs, new_snap, new_snap_tmp](bool success) { if (!success) { //生成截图失败,可能残留空文件 File::delete_file(new_snap_tmp.data()); @@ -1180,7 +1142,7 @@ void installWebApi() { File::delete_file(new_snap.data()); rename(new_snap_tmp.data(), new_snap.data()); } - responseSnap(new_snap, headerIn, invoker); + responseSnap(new_snap, allArgs.getParser().getHeader(), invoker); }); }); @@ -1217,9 +1179,9 @@ void installWebApi() { api_regist("/index/api/webrtc",[](API_ARGS_STRING_ASYNC){ CHECK_ARGS("app", "stream"); - auto offer_sdp = allArgs.Content(); - auto type = allArgs.getUrlArgs()["type"]; - MediaInfo info(StrPrinter << "rtc://" << headerIn["Host"] << "/" << allArgs.getUrlArgs()["app"] << "/" << allArgs.getUrlArgs()["stream"] << "?" << allArgs.Params()); + auto offer_sdp = allArgs.getArgs(); + auto type = allArgs["type"]; + MediaInfo info(StrPrinter << "rtc://" << allArgs["Host"] << "/" << allArgs["app"] << "/" << allArgs["stream"] << "?" << allArgs.getParser().Params()); //设置返回类型 headerOut["Content-Type"] = HttpFileManager::getContentType(".json"); diff --git a/server/WebApi.h b/server/WebApi.h index a039393f..569eaea0 100755 --- a/server/WebApi.h +++ b/server/WebApi.h @@ -79,16 +79,117 @@ public: ~SuccessException() = default; }; -using ApiArgsType = map; +using ApiArgsType = map; -#define API_ARGS_MAP SockInfo &sender, HttpSession::KeyValue &headerIn, HttpSession::KeyValue &headerOut, ApiArgsType &allArgs, Json::Value &val +template +string getValue(Args &args, const First &first) { + return args[first]; +} + +template +string getValue(Json::Value &args, const First &first) { + return args[first].asString(); +} + +template +string getValue(string &args, const First &first) { + return ""; +} + +template +string getValue(const Parser &parser, const First &first) { + auto ret = parser.getUrlArgs()[first]; + if (!ret.empty()) { + return ret; + } + return parser.getHeader()[first]; +} + +template +string getValue(Parser &parser, const First &first) { + return getValue((const Parser &) parser, first); +} + +template +string getValue(const Parser &parser, Args &args, const First &first) { + auto ret = getValue(args, first); + if (!ret.empty()) { + return ret; + } + return getValue(parser, first); +} + +template +class HttpAllArgs { +public: + HttpAllArgs(const Parser &parser, Args &args) { + _get_args = [&args]() { + return (void *) &args; + }; + _get_parser = [&parser]() -> const Parser & { + return parser; + }; + _get_value = [](HttpAllArgs &that, const string &key) { + return getValue(that.getParser(), that.getArgs(), key); + }; + _clone = [&](HttpAllArgs &that) { + that._get_args = [args]() { + return (void *) &args; + }; + that._get_parser = [parser]() -> const Parser & { + return parser; + }; + that._get_value = [](HttpAllArgs &that, const string &key) { + return getValue(that.getParser(), that.getArgs(), key); + }; + that._cache_able = true; + }; + } + + HttpAllArgs(const HttpAllArgs &that) { + if (that._cache_able) { + _get_args = that._get_args; + _get_parser = that._get_parser; + _get_value = that._get_value; + } else { + that._clone(*this); + } + } + + ~HttpAllArgs() = default; + + template + variant operator[](const Key &key) const { + return (variant)_get_value(*(HttpAllArgs*)this, key); + } + + const Parser &getParser() const { + return _get_parser(); + } + + Args &getArgs() { + return *((Args *) _get_args()); + } + + const Args &getArgs() const { + return *((Args *) _get_args()); + } + +private: + bool _cache_able = false; + function _get_args; + function _get_parser; + function _get_value; + function _clone; +}; + +#define API_ARGS_MAP SockInfo &sender, HttpSession::KeyValue &headerOut, const HttpAllArgs &allArgs, Json::Value &val #define API_ARGS_MAP_ASYNC API_ARGS_MAP, const HttpSession::HttpResponseInvoker &invoker -#define API_ARGS_JSON SockInfo &sender, HttpSession::KeyValue &headerIn, HttpSession::KeyValue &headerOut, Json::Value &bodyArgs, ApiArgsType &allArgs, Json::Value &val +#define API_ARGS_JSON SockInfo &sender, HttpSession::KeyValue &headerOut, const HttpAllArgs &allArgs, Json::Value &val #define API_ARGS_JSON_ASYNC API_ARGS_JSON, const HttpSession::HttpResponseInvoker &invoker -#define API_ARGS_STRING SockInfo &sender, HttpSession::KeyValue &headerIn, HttpSession::KeyValue &headerOut, const Parser &allArgs, Json::Value &val +#define API_ARGS_STRING SockInfo &sender, HttpSession::KeyValue &headerOut, const HttpAllArgs &allArgs, Json::Value &val #define API_ARGS_STRING_ASYNC API_ARGS_STRING, const HttpSession::HttpResponseInvoker &invoker -#define API_ARGS_VALUE sender, headerIn, headerOut, allArgs, val -#define API_ARGS_JSON_VALUE sender, headerIn, headerOut, bodyArgs, allArgs, val +#define API_ARGS_VALUE sender, headerOut, allArgs, val //注册http请求参数是map类型的http api void api_regist(const string &api_path, const function &func); @@ -106,26 +207,16 @@ void api_regist(const string &api_path, const function &f void api_regist(const string &api_path, const function &func); template -bool checkArgs(Args &&args, First &&first) { +bool checkArgs(Args &args, const First &first) { return !args[first].empty(); } template -bool checkArgs(Args &&args, First &&first, KeyTypes &&...keys) { - return !args[first].empty() && checkArgs(std::forward(args), std::forward(keys)...); +bool checkArgs(Args &args, const First &first, const KeyTypes &...keys) { + return checkArgs(args, first) && checkArgs(args, keys...); } -template -bool checkArgs(const Parser &args, First &&first) { - return !args.getUrlArgs()[first].empty(); -} - -template -bool checkArgs(const Parser &args, First &&first, KeyTypes &&...keys) { - return !args.getUrlArgs()[first].empty() && checkArgs(args, std::forward(keys)...); -} - -//检查http参数是否为空的宏 +//检查http url中或body中或http header参数是否为空的宏 #define CHECK_ARGS(...) \ if(!checkArgs(allArgs,##__VA_ARGS__)){ \ throw InvalidArgsException("缺少必要参数:" #__VA_ARGS__); \ diff --git a/src/Common/MediaSource.cpp b/src/Common/MediaSource.cpp index ee1dd12f..86930d6d 100644 --- a/src/Common/MediaSource.cpp +++ b/src/Common/MediaSource.cpp @@ -157,17 +157,15 @@ bool MediaSource::seekTo(uint32_t stamp) { return listener->seekTo(*this, stamp); } -bool MediaSource::pause() -{ +bool MediaSource::pause(bool pause) { auto listener = _listener.lock(); if (!listener) { return false; } - return listener->pause(*this); + return listener->pause(*this, pause); } -bool MediaSource::speed(float speed) -{ +bool MediaSource::speed(float speed) { auto listener = _listener.lock(); if (!listener) { return false; @@ -601,17 +599,15 @@ bool MediaSourceEventInterceptor::seekTo(MediaSource &sender, uint32_t stamp) { return listener->seekTo(sender, stamp); } -bool MediaSourceEventInterceptor::pause(MediaSource& sender) -{ +bool MediaSourceEventInterceptor::pause(MediaSource &sender, bool pause) { auto listener = _listener.lock(); if (!listener) { return false; } - return listener->pause(sender); + return listener->pause(sender, pause); } -bool MediaSourceEventInterceptor::speed(MediaSource& sender, float speed) -{ +bool MediaSourceEventInterceptor::speed(MediaSource &sender, float speed) { auto listener = _listener.lock(); if (!listener) { return false; diff --git a/src/Common/MediaSource.h b/src/Common/MediaSource.h index c06167ae..d99dfbbb 100644 --- a/src/Common/MediaSource.h +++ b/src/Common/MediaSource.h @@ -67,10 +67,10 @@ public: // 通知拖动进度条 virtual bool seekTo(MediaSource &sender, uint32_t stamp) { return false; } - // 通知暂停 - virtual bool pause(MediaSource& sender) { return false; } + // 通知暂停或恢复 + virtual bool pause(MediaSource &sender, bool pause) { return false; } // 通知倍数 - virtual bool speed(MediaSource& sender, float speed) { return false; } + virtual bool speed(MediaSource &sender, float speed) { return false; } // 通知其停止产生流 virtual bool close(MediaSource &sender, bool force) { return false; } // 获取观看总人数 @@ -110,8 +110,8 @@ public: std::shared_ptr getOriginSock(MediaSource &sender) const override; bool seekTo(MediaSource &sender, uint32_t stamp) override; - bool pause(MediaSource& sender) override; - bool speed(MediaSource& sender, float speed) override; + bool pause(MediaSource &sender, bool pause) override; + bool speed(MediaSource &sender, float speed) override; bool close(MediaSource &sender, bool force) override; int totalReaderCount(MediaSource &sender) override; void onReaderChanged(MediaSource &sender, int size) override; @@ -256,8 +256,7 @@ public: // 拖动进度条 bool seekTo(uint32_t stamp); //暂停 - bool pause(); - + bool pause(bool pause); //倍数播放 bool speed(float speed); // 关闭该流 diff --git a/src/Http/HttpDownloader.h b/src/Http/HttpDownloader.h index fc9f4b27..7a561063 100644 --- a/src/Http/HttpDownloader.h +++ b/src/Http/HttpDownloader.h @@ -33,11 +33,11 @@ public: protected: void onResponseBody(const char *buf, size_t size, size_t recvedSize, size_t totalSize) override; - -private: ssize_t onResponseHeader(const string &status, const HttpHeader &headers) override; void onResponseCompleted() override; void onDisconnect(const SockException &ex) override; + +private: void closeFile(); private: diff --git a/src/Http/HttpSession.cpp b/src/Http/HttpSession.cpp index bc0c631b..dcc7b152 100644 --- a/src/Http/HttpSession.cpp +++ b/src/Http/HttpSession.cpp @@ -130,7 +130,7 @@ void HttpSession::onManager() { if(_ticker.elapsedTime() > keepAliveSec * 1000){ //1分钟超时 - shutdown(SockException(Err_timeout,"session timeouted")); + shutdown(SockException(Err_timeout,"session timeout")); } } diff --git a/src/Player/MediaPlayer.cpp b/src/Player/MediaPlayer.cpp index 5859cc80..9d8be6c1 100644 --- a/src/Player/MediaPlayer.cpp +++ b/src/Player/MediaPlayer.cpp @@ -64,8 +64,7 @@ void MediaPlayer::pause(bool pause) { } } -void MediaPlayer::speed(float speed) -{ +void MediaPlayer::speed(float speed) { if (_delegate) { _delegate->speed(speed); } diff --git a/src/Player/MediaPlayer.h b/src/Player/MediaPlayer.h index 84888d92..a65f6b9a 100644 --- a/src/Player/MediaPlayer.h +++ b/src/Player/MediaPlayer.h @@ -29,7 +29,7 @@ public: virtual ~MediaPlayer(); void play(const string &url) override; void pause(bool pause) override; - void speed(float speed)override; + void speed(float speed) override; void teardown() override; EventPoller::Ptr getPoller(); void setOnCreateSocket(Socket::onCreateSocket cb); diff --git a/src/Player/PlayerBase.h b/src/Player/PlayerBase.h index 8b3791e1..cacfa7b4 100644 --- a/src/Player/PlayerBase.h +++ b/src/Player/PlayerBase.h @@ -102,7 +102,6 @@ public: /** * 获取播放进度pos,取值 相对开始时间增量 单位秒 - * @return */ virtual uint32_t getProgressPos() const { return 0; } @@ -152,15 +151,16 @@ public: typedef std::shared_ptr Ptr; template - PlayerImp(ArgsType &&...args):Parent(std::forward(args)...){} + PlayerImp(ArgsType &&...args):Parent(std::forward(args)...) {} + virtual ~PlayerImp() {} - virtual ~PlayerImp(){} void setOnShutdown(const function &cb) override { if (_delegate) { _delegate->setOnShutdown(cb); } _shutdownCB = cb; } + void setOnPlayResult(const function &cb) override { if (_delegate) { _delegate->setOnPlayResult(cb); @@ -175,31 +175,35 @@ public: _resumeCB = cb; } - bool isInited(int analysisMs) override{ + bool isInited(int analysisMs) override { if (_delegate) { return _delegate->isInited(analysisMs); } return Parent::isInited(analysisMs); } + float getDuration() const override { if (_delegate) { return _delegate->getDuration(); } return Parent::getDuration(); } - float getProgress() const override{ + + float getProgress() const override { if (_delegate) { return _delegate->getProgress(); } return Parent::getProgress(); } + uint32_t getProgressPos() const override { if (_delegate) { return _delegate->getProgressPos(); } return Parent::getProgressPos(); } - void seekTo(float fProgress) override{ + + void seekTo(float fProgress) override { if (_delegate) { return _delegate->seekTo(fProgress); } @@ -213,21 +217,21 @@ public: return Parent::seekTo(seekPos); } - void setMediaSource(const MediaSource::Ptr & src) override { + void setMediaSource(const MediaSource::Ptr &src) override { if (_delegate) { _delegate->setMediaSource(src); } _pMediaSrc = src; } - vector getTracks(bool trackReady = true) const override{ + vector getTracks(bool trackReady = true) const override { if (_delegate) { return _delegate->getTracks(trackReady); } return Parent::getTracks(trackReady); } - std::shared_ptr getSockInfo() const{ + std::shared_ptr getSockInfo() const { return dynamic_pointer_cast(_delegate); } diff --git a/src/Record/MP4Recorder.cpp b/src/Record/MP4Recorder.cpp index 1d5f7f33..101e1dc1 100644 --- a/src/Record/MP4Recorder.cpp +++ b/src/Record/MP4Recorder.cpp @@ -65,7 +65,6 @@ void MP4Recorder::createFile() { } _strFileTmp = strFileTmp; _strFile = strFile; - _createFileTicker.resetTime(); } catch (std::exception &ex) { WarnL << ex.what(); } @@ -107,21 +106,21 @@ void MP4Recorder::closeFile() { } void MP4Recorder::inputFrame(const Frame::Ptr &frame) { - if (_baseSec == 0) - _baseSec = frame->dts(); - auto dis = frame->dts() - _baseSec; - if(!_muxer || ((dis > _max_second * 1000) && - (!_haveVideo || (_haveVideo && frame->keyFrame()))) ){ + if (_baseSec == 0) { + _baseSec = frame->dts(); + } + + auto duration = frame->dts() - _baseSec; + if (!_muxer || ((duration > _max_second * 1000) && (!_haveVideo || (_haveVideo && frame->keyFrame())))) { //成立条件 //1、_muxer为空 //2、到了切片时间,并且只有音频 //3、到了切片时间,有视频并且遇到视频的关键帧 - DebugL << "create file dts:" << frame->dts() << " baseSec:" << _baseSec; _baseSec = 0; createFile(); } - if(_muxer){ + if (_muxer) { //生成mp4文件 _muxer->inputFrame(frame); } @@ -139,7 +138,6 @@ void MP4Recorder::resetTracks() { closeFile(); _tracks.clear(); _haveVideo = false; - _createFileTicker.resetTime(); } } /* namespace mediakit */ diff --git a/src/Record/MP4Recorder.h b/src/Record/MP4Recorder.h index 098800f8..a6b25f27 100644 --- a/src/Record/MP4Recorder.h +++ b/src/Record/MP4Recorder.h @@ -61,11 +61,9 @@ private: string _strPath; string _strFile; string _strFileTmp; - Ticker _createFileTicker; RecordInfo _info; MP4Muxer::Ptr _muxer; list _tracks; - uint64_t _baseSec = 0; }; diff --git a/src/Rtmp/RtmpPlayer.cpp b/src/Rtmp/RtmpPlayer.cpp index 4125359d..3fed286c 100644 --- a/src/Rtmp/RtmpPlayer.cpp +++ b/src/Rtmp/RtmpPlayer.cpp @@ -171,8 +171,7 @@ void RtmpPlayer::pause(bool bPause) { send_pause(bPause); } -void RtmpPlayer::speed(float speed) -{ +void RtmpPlayer::speed(float speed) { //todo } diff --git a/src/Rtmp/RtmpPlayer.h b/src/Rtmp/RtmpPlayer.h index 36a770bc..cb7fdb15 100644 --- a/src/Rtmp/RtmpPlayer.h +++ b/src/Rtmp/RtmpPlayer.h @@ -38,7 +38,7 @@ public: void play(const string &strUrl) override; void pause(bool bPause) override; - void speed(float speed)override; + void speed(float speed) override; void teardown() override; protected: diff --git a/src/Rtmp/RtmpPlayerImp.h b/src/Rtmp/RtmpPlayerImp.h index 184f4cdc..9d7ec790 100644 --- a/src/Rtmp/RtmpPlayerImp.h +++ b/src/Rtmp/RtmpPlayerImp.h @@ -47,7 +47,7 @@ public: } void seekTo(uint32_t seekPos) override { - uint32_t pos = MAX(float(0), MIN(seekPos, getDuration()))*1000; + uint32_t pos = MAX(float(0), MIN(seekPos, getDuration())) * 1000; seekToMilliSecond(pos); } diff --git a/src/Rtmp/RtmpSession.cpp b/src/Rtmp/RtmpSession.cpp index 72992205..163a5800 100644 --- a/src/Rtmp/RtmpSession.cpp +++ b/src/Rtmp/RtmpSession.cpp @@ -413,23 +413,18 @@ void RtmpSession::onCmd_pause(AMFDecoder &dec) { sendUserControl(paused ? CONTROL_STREAM_EOF : CONTROL_STREAM_BEGIN, STREAM_MEDIA); _paused = paused; - auto stongSrc = _player_src.lock(); - if (stongSrc) { - if (_paused) - stongSrc->pause(); - else - stongSrc->seekTo(-1); + auto strongSrc = _player_src.lock(); + if (strongSrc) { + strongSrc->pause(paused); } } -void RtmpSession::onCmd_playCtrl(AMFDecoder& dec) -{ +void RtmpSession::onCmd_playCtrl(AMFDecoder &dec) { dec.load(); auto ctrlObj = dec.load(); int ctrlType = ctrlObj["ctrlType"].as_integer(); float speed = ctrlObj["speed"].as_number(); - AMFValue status(AMF_OBJECT); status.set("level", "status"); status.set("code", "NetStream.Speed.Notify"); diff --git a/src/Rtmp/RtmpSession.h b/src/Rtmp/RtmpSession.h index 3d8be8c8..817d9ec5 100644 --- a/src/Rtmp/RtmpSession.h +++ b/src/Rtmp/RtmpSession.h @@ -53,7 +53,7 @@ private: void onCmd_seek(AMFDecoder &dec); void onCmd_pause(AMFDecoder &dec); - void onCmd_playCtrl(AMFDecoder& dec); + void onCmd_playCtrl(AMFDecoder &dec); void setMetaData(AMFDecoder &dec); void onSendMedia(const RtmpPacket::Ptr &pkt); diff --git a/src/Rtsp/RtspPlayer.cpp b/src/Rtsp/RtspPlayer.cpp index 6b83a12b..eadbd642 100644 --- a/src/Rtsp/RtspPlayer.cpp +++ b/src/Rtsp/RtspPlayer.cpp @@ -419,9 +419,8 @@ void RtspPlayer::pause(bool bPause) { sendPause(bPause ? type_pause : type_seek, getProgressMilliSecond()); } -void RtspPlayer::speed(float speed) -{ - sendRtspRequest("PLAY", _content_base, { "Scale",StrPrinter << speed }); +void RtspPlayer::speed(float speed) { + sendRtspRequest("PLAY", _content_base, {"Scale", StrPrinter << speed}); } void RtspPlayer::handleResPAUSE(const Parser& parser,int type) { diff --git a/src/Rtsp/RtspPlayer.h b/src/Rtsp/RtspPlayer.h index a745dff4..b624759b 100644 --- a/src/Rtsp/RtspPlayer.h +++ b/src/Rtsp/RtspPlayer.h @@ -41,8 +41,8 @@ public: ~RtspPlayer() override; void play(const string &strUrl) override; - void pause(bool bPause) override; - void speed(float speed)override; + void pause(bool pause) override; + void speed(float speed) override; void teardown() override; float getPacketLossRate(TrackType type) const override; diff --git a/src/Rtsp/RtspPlayerImp.h b/src/Rtsp/RtspPlayerImp.h index e02588e7..180c17c3 100644 --- a/src/Rtsp/RtspPlayerImp.h +++ b/src/Rtsp/RtspPlayerImp.h @@ -47,12 +47,11 @@ public: return getProgressMilliSecond(); } return PlayerBase::getProgressPos(); + } - }; - - void seekTo(float fProgress) override{ - fProgress = MAX(float(0),MIN(fProgress,float(1.0))); - seekToMilliSecond((uint32_t)(fProgress * getDuration() * 1000)); + void seekTo(float fProgress) override { + fProgress = MAX(float(0), MIN(fProgress, float(1.0))); + seekToMilliSecond((uint32_t) (fProgress * getDuration() * 1000)); } void seekTo(uint32_t seekPos) override { diff --git a/src/Rtsp/RtspSession.cpp b/src/Rtsp/RtspSession.cpp index 6f35a13c..e4d043f3 100644 --- a/src/Rtsp/RtspSession.cpp +++ b/src/Rtsp/RtspSession.cpp @@ -101,13 +101,13 @@ void RtspSession::onManager() { if (_push_src && _alive_ticker.elapsedTime() > keep_alive_sec * 1000) { //推流超时 - shutdown(SockException(Err_timeout, "pusher session timeouted")); + shutdown(SockException(Err_timeout, "pusher session timeout")); return; } if (!_push_src && _rtp_type == Rtsp::RTP_UDP && _enable_send_rtp && _alive_ticker.elapsedTime() > keep_alive_sec * 4000) { //rtp over udp播放器超时 - shutdown(SockException(Err_timeout, "rtp over udp player timeouted")); + shutdown(SockException(Err_timeout, "rtp over udp player timeout")); } } @@ -774,36 +774,27 @@ void RtspSession::handleReq_Play(const Parser &parser) { } bool useGOP = true; - //_enable_send_rtp = false; float iStartTime = 0; - auto strRange = parser["Range"]; - auto strScale = parser["Scale"]; - if (strScale.size() == 0) - { + auto &strRange = parser["Range"]; + auto &strScale = parser["Scale"]; - if (strRange.size()) { - //这个是seek操作 - auto strStart = FindField(strRange.data(), "npt=", "-"); - if (strStart == "now") { - strStart = "0"; - } - iStartTime = 1000 * (float)atof(strStart.data()); - InfoP(this) << "rtsp seekTo(ms):" << iStartTime; - useGOP = !play_src->seekTo((uint32_t)iStartTime); - } - else if (play_src->totalReaderCount() == 0) { - //第一个消费者 - play_src->seekTo(0); - } - else if (play_src->totalReaderCount() > 0) - { - _enable_send_rtp = true; - play_src->seekTo(-1); - } + if (!strScale.empty()) { + //这是设置播放速度 + auto speed = atof(strScale.data()); + play_src->speed(speed); + InfoP(this) << "rtp set play speed:" << speed; } - else - { - play_src->speed(atof(strScale.data())); + + if (!strRange.empty()) { + //这是seek操作 + _enable_send_rtp = false; + auto strStart = FindField(strRange.data(), "npt=", "-"); + if (strStart == "now") { + strStart = "0"; + } + iStartTime = 1000 * (float) atof(strStart.data()); + useGOP = !play_src->seekTo((uint32_t) iStartTime); + InfoP(this) << "rtsp seekTo(ms):" << iStartTime; } _StrPrinter rtp_info; @@ -828,7 +819,10 @@ void RtspSession::handleReq_Play(const Parser &parser) { "RTP-Info",rtp_info }); + //在回复rtsp信令后再恢复播放 _enable_send_rtp = true; + play_src->pause(false); + setSocketFlags(); if (!_play_reader && _rtp_type != Rtsp::RTP_MULTICAST) { @@ -856,26 +850,21 @@ void RtspSession::handleReq_Play(const Parser &parser) { void RtspSession::handleReq_Pause(const Parser &parser) { if (parser["Session"] != _sessionid) { send_SessionNotFound(); - throw SockException(Err_shutdown,"session not found when pause"); + throw SockException(Err_shutdown, "session not found when pause"); } sendRtspResponse("200 OK"); - + _enable_send_rtp = false; auto play_src = _play_src.lock(); - if (!play_src) { - send_StreamNotFound(); - shutdown(SockException(Err_shutdown, "rtsp stream released")); - return; + if (play_src) { + play_src->pause(true); } - - play_src->pause(); - //_enable_send_rtp = false; } void RtspSession::handleReq_Teardown(const Parser &parser) { sendRtspResponse("200 OK"); - throw SockException(Err_shutdown,"rtsp player send teardown request"); + throw SockException(Err_shutdown,"recv teardown request"); } void RtspSession::handleReq_Get(const Parser &parser) {