diff --git a/AUTHORS b/AUTHORS index 6a25530e..fcc45452 100644 --- a/AUTHORS +++ b/AUTHORS @@ -44,7 +44,6 @@ Xinghua Zhao <(holychaossword@hotmail.com> [Dw9](https://github.com/Dw9) 明月惊鹊 cgm <2958580318@qq.com> -hejilin <1724010622@qq.com> alexliyu7352 cgm <2958580318@qq.com> [haorui wang](https://github.com/HaoruiWang) @@ -104,3 +103,8 @@ WuPeng [sandro-qiang](https://github.com/sandro-qiang) [Paul Philippov](https://github.com/themactep) [张传峰](https://github.com/zhang-chuanfeng) +[lidaofu-hub](https://github.com/lidaofu-hub) +[huangcaichun](https://github.com/huangcaichun) +[jamesZHANG500](https://github.com/jamesZHANG500) +[weidelong](https://github.com/wdl1697454803) +[小强先生](https://github.com/linshangqiang) \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index d951bc3b..1adefab1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -141,8 +141,8 @@ if(GIT_FOUND) endif() configure_file( - ${CMAKE_CURRENT_SOURCE_DIR}/version.h.ini - ${CMAKE_CURRENT_BINARY_DIR}/version.h + ${CMAKE_CURRENT_SOURCE_DIR}/ZLMVersion.h.ini + ${CMAKE_CURRENT_BINARY_DIR}/ZLMVersion.h @ONLY) message(STATUS "Git version is ${BRANCH_NAME} ${COMMIT_HASH}/${COMMIT_TIME} ${BUILD_TIME}") @@ -537,4 +537,4 @@ file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/default.pem" DESTINATION ${EXECUTABLE_OUT # Copy the default background image used by VideoStack when there is no video stream if (ENABLE_FFMPEG AND ENABLE_X264) file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/conf/novideo.yuv" DESTINATION ${EXECUTABLE_OUTPUT_PATH}) -endif () \ No newline at end of file +endif () diff --git a/README.md b/README.md index c08ed51f..44c22aa9 100644 --- a/README.md +++ b/README.md @@ -358,6 +358,11 @@ bash build_docker_images.sh [sandro-qiang](https://github.com/sandro-qiang) [Paul Philippov](https://github.com/themactep) [张传峰](https://github.com/zhang-chuanfeng) +[lidaofu-hub](https://github.com/lidaofu-hub) +[huangcaichun](https://github.com/huangcaichun) +[jamesZHANG500](https://github.com/jamesZHANG500) +[weidelong](https://github.com/wdl1697454803) +[小强先生](https://github.com/linshangqiang) 同时感谢JetBrains对开源项目的支持,本项目使用CLion开发与调试: diff --git a/README_en.md b/README_en.md index 94ca9871..b41eea20 100644 --- a/README_en.md +++ b/README_en.md @@ -516,6 +516,11 @@ Thanks to all those who have supported this project in various ways, including b [sandro-qiang](https://github.com/sandro-qiang) [Paul Philippov](https://github.com/themactep) [张传峰](https://github.com/zhang-chuanfeng) +[lidaofu-hub](https://github.com/lidaofu-hub) +[huangcaichun](https://github.com/huangcaichun) +[jamesZHANG500](https://github.com/jamesZHANG500) +[weidelong](https://github.com/wdl1697454803) +[小强先生](https://github.com/linshangqiang) Also thank to JetBrains for their support for open source project, we developed and debugged zlmediakit with CLion: diff --git a/version.h.ini b/ZLMVersion.h.ini similarity index 100% rename from version.h.ini rename to ZLMVersion.h.ini diff --git a/api/source/mk_common.cpp b/api/source/mk_common.cpp index c4a36ea1..48efeb1d 100644 --- a/api/source/mk_common.cpp +++ b/api/source/mk_common.cpp @@ -304,10 +304,10 @@ API_EXPORT void API_CALL mk_webrtc_get_answer_sdp2(void *user_data, on_user_data std::string offer_str = offer; std::shared_ptr ptr(user_data, user_data_free ? user_data_free : [](void *) {}); auto args = std::make_shared(url); - WebRtcPluginManager::Instance().getAnswerSdp(*session, type, *args, - [offer_str, session, ptr, cb](const WebRtcInterface &exchanger) mutable { + WebRtcPluginManager::Instance().negotiateSdp(*session, type, *args, [offer_str, session, ptr, cb](const WebRtcInterface &exchanger) mutable { + auto &handler = const_cast(exchanger); try { - auto sdp_answer = exchangeSdp(exchanger, offer_str); + auto sdp_answer = handler.getAnswerSdp(offer_str); cb(ptr.get(), sdp_answer.data(), nullptr); } catch (std::exception &ex) { cb(ptr.get(), nullptr, ex.what()); diff --git a/api/source/mk_events.cpp b/api/source/mk_events.cpp index 52ac6e57..7f5ed661 100644 --- a/api/source/mk_events.cpp +++ b/api/source/mk_events.cpp @@ -14,7 +14,10 @@ #include "Http/HttpSession.h" #include "Rtsp/RtspSession.h" #include "Record/MP4Recorder.h" + +#ifdef ENABLE_WEBRTC #include "webrtc/WebRtcTransport.h" +#endif using namespace toolkit; using namespace mediakit; @@ -168,7 +171,7 @@ API_EXPORT void API_CALL mk_events_listen(const mk_events *events){ sender.getMediaTuple().stream.c_str(), ssrc.c_str(), ex.getErrCode(), ex.what()); } }); - +#ifdef ENABLE_WEBRTC NoticeCenter::Instance().addListener(&s_tag, Broadcast::kBroadcastRtcSctpConnecting,[](BroadcastRtcSctpConnectArgs){ if (s_events.on_mk_rtc_sctp_connecting) { s_events.on_mk_rtc_sctp_connecting((mk_rtc_transport)&sender); @@ -204,6 +207,7 @@ API_EXPORT void API_CALL mk_events_listen(const mk_events *events){ s_events.on_mk_rtc_sctp_received((mk_rtc_transport)&sender, streamId, ppid, msg, len); } }); +#endif }); } diff --git a/api/source/mk_events_objects.cpp b/api/source/mk_events_objects.cpp index 89b8c659..c30fd0cd 100644 --- a/api/source/mk_events_objects.cpp +++ b/api/source/mk_events_objects.cpp @@ -17,7 +17,10 @@ #include "Http/HttpClient.h" #include "Rtsp/RtspSession.h" + +#ifdef ENABLE_WEBRTC #include "webrtc/WebRtcTransport.h" +#endif using namespace toolkit; using namespace mediakit; diff --git a/conf/config.ini b/conf/config.ini index 8f566338..3c8b67c8 100644 --- a/conf/config.ini +++ b/conf/config.ini @@ -357,7 +357,7 @@ tcpPort = 8000 rembBitRate=0 #rtc支持的音频codec类型,在前面的优先级更高 #以下范例为所有支持的音频codec -preferredCodecA=PCMU,PCMA,opus,mpeg4-generic +preferredCodecA=PCMA,PCMU,opus,mpeg4-generic #rtc支持的视频codec类型,在前面的优先级更高 #以下范例为所有支持的视频codec preferredCodecV=H264,H265,AV1,VP9,VP8 diff --git a/ext-codec/AACRtmp.cpp b/ext-codec/AACRtmp.cpp index e20db4df..72c96d5a 100644 --- a/ext-codec/AACRtmp.cpp +++ b/ext-codec/AACRtmp.cpp @@ -17,7 +17,7 @@ using namespace toolkit; namespace mediakit { void AACRtmpDecoder::inputRtmp(const RtmpPacket::Ptr &pkt) { - CHECK(pkt->size() > 2); + CHECK_RET(pkt->size() > 2); if (pkt->isConfigFrame()) { getTrack()->setExtraData((uint8_t *)pkt->data() + 2, pkt->size() - 2); return; diff --git a/ext-codec/H264Rtmp.cpp b/ext-codec/H264Rtmp.cpp index 30bf10eb..6dd50807 100644 --- a/ext-codec/H264Rtmp.cpp +++ b/ext-codec/H264Rtmp.cpp @@ -14,14 +14,6 @@ using namespace std; using namespace toolkit; -#define CHECK_RET(...) \ - try { \ - CHECK(__VA_ARGS__); \ - } catch (AssertFailedException & ex) { \ - WarnL << ex.what(); \ - return; \ - } - namespace mediakit { void H264RtmpDecoder::inputRtmp(const RtmpPacket::Ptr &pkt) { diff --git a/ext-codec/H265Rtmp.cpp b/ext-codec/H265Rtmp.cpp index 2b88795d..69a27390 100644 --- a/ext-codec/H265Rtmp.cpp +++ b/ext-codec/H265Rtmp.cpp @@ -18,14 +18,6 @@ using namespace std; using namespace toolkit; -#define CHECK_RET(...) \ - try { \ - CHECK(__VA_ARGS__); \ - } catch (AssertFailedException & ex) { \ - WarnL << ex.what(); \ - return; \ - } - namespace mediakit { void H265RtmpDecoder::inputRtmp(const RtmpPacket::Ptr &pkt) { diff --git a/server/VideoStack.cpp b/server/VideoStack.cpp index ff4804f1..d5168147 100644 --- a/server/VideoStack.cpp +++ b/server/VideoStack.cpp @@ -62,15 +62,16 @@ void Channel::addParam(const std::weak_ptr& p) void Channel::onFrame(const mediakit::FFmpegFrame::Ptr& frame) { std::weak_ptr weakSelf = shared_from_this(); - // toolkit::WorkThreadPool::Instance().getFirstPoller()->async([weakSelf, frame]() { - auto self = weakSelf.lock(); - if (!self) { - return; - } - self->_tmp = self->_sws->inputFrame(frame); + _poller = _poller ? _poller : toolkit::WorkThreadPool::Instance().getPoller(); + _poller->async([weakSelf, frame]() { + auto self = weakSelf.lock(); + if (!self) { + return; + } + self->_tmp = self->_sws->inputFrame(frame); - self->forEachParam([self](const Param::Ptr& p) { self->fillBuffer(p); }); - // }); + self->forEachParam([self](const Param::Ptr& p) { self->fillBuffer(p); }); + }); } void Channel::forEachParam(const std::function& func) @@ -440,6 +441,7 @@ int VideoStackManager::stopVideoStack(const std::string& id) auto it = _stackMap.find(id); if (it != _stackMap.end()) { _stackMap.erase(it); + InfoL << "VideoStack stop: " << id; return 0; } return -1; diff --git a/server/VideoStack.h b/server/VideoStack.h index d4378ab3..99455b40 100644 --- a/server/VideoStack.h +++ b/server/VideoStack.h @@ -80,6 +80,7 @@ class Channel : public std::enable_shared_from_this { std::vector> _params; mediakit::FFmpegSws::Ptr _sws; + toolkit::EventPoller::Ptr _poller; }; class StackPlayer : public std::enable_shared_from_this { diff --git a/server/WebApi.cpp b/server/WebApi.cpp index 846f280a..edbf90bc 100755 --- a/server/WebApi.cpp +++ b/server/WebApi.cpp @@ -59,7 +59,7 @@ #endif #if defined(ENABLE_VERSION) -#include "version.h" +#include "ZLMVersion.h" #endif #if defined(ENABLE_X264) && defined (ENABLE_FFMPEG) @@ -119,7 +119,7 @@ static HttpApi toApi(const function &cb) { //参数解析成map auto args = getAllArgs(parser); - cb(sender, headerOut, HttpAllArgs(parser, args), val, invoker); + cb(sender, headerOut, ArgsMap(parser, args), val, invoker); }; } @@ -147,7 +147,7 @@ static HttpApi toApi(const function &cb) { Json::Reader reader; reader.parse(parser.content(), args); - cb(sender, headerOut, HttpAllArgs(parser, args), val, invoker); + cb(sender, headerOut, ArgsJson(parser, args), val, invoker); }; } @@ -167,7 +167,7 @@ static HttpApi toApi(const function &cb) { Json::Value val; val["code"] = API::Success; - cb(sender, headerOut, HttpAllArgs(parser, (string &)parser.content()), val, invoker); + cb(sender, headerOut, ArgsString(parser, (string &)parser.content()), val, invoker); }; } @@ -584,8 +584,10 @@ void addStreamProxy(const string &vhost, const string &app, const string &stream //添加拉流代理 auto player = s_player_proxy.make(key, vhost, app, stream, option, retry_count); - // 先透传参数 - player->mINI::operator=(args); + // 先透传拷贝参数 + for (auto &pr : args) { + (*player)[pr.first] = pr.second; + } //指定RTP over TCP(播放rtsp时有效) (*player)[Client::kRtpType] = rtp_type; @@ -660,13 +662,6 @@ void addStreamPusherProxy(const string &schema, pusher->publish(url); } -template -static void getArgsValue(const HttpAllArgs &allArgs, const string &key, Type &value) { - auto val = allArgs[key]; - if (!val.empty()) { - value = (Type)val; - } -} /** * 安装api接口 @@ -733,7 +728,7 @@ void installWebApi() { CHECK_SECRET(); auto &ini = mINI::Instance(); int changed = API::Success; - for (auto &pr : allArgs.getArgs()) { + for (auto &pr : allArgs.args) { if (ini.find(pr.first) == ini.end()) { #if 1 //没有这个key @@ -1091,7 +1086,7 @@ void installWebApi() { CHECK_ARGS("vhost","app","stream","url"); mINI args; - for (auto &pr : allArgs.getArgs()) { + for (auto &pr : allArgs.args) { args.emplace(pr.first, pr.second); } @@ -1188,7 +1183,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(allArgs.getParser().getHeader(),StrCaseMap(),exePath()); + invoker.responseFile(allArgs.parser.getHeader(), StrCaseMap(), exePath()); }); #if defined(ENABLE_RTPPROXY) @@ -1695,7 +1690,7 @@ void installWebApi() { //截图存在,且未过期,那么返回之 res_old_snap = true; - responseSnap(path, allArgs.getParser().getHeader(), invoker); + responseSnap(path, allArgs.parser.getHeader(), invoker); //中断遍历 return false; }); @@ -1726,7 +1721,7 @@ void installWebApi() { File::delete_file(new_snap); rename(new_snap_tmp.data(), new_snap.data()); } - responseSnap(new_snap, allArgs.getParser().getHeader(), invoker, err_msg); + responseSnap(new_snap, allArgs.parser.getHeader(), invoker, err_msg); }); }); @@ -1741,7 +1736,7 @@ void installWebApi() { #ifdef ENABLE_WEBRTC class WebRtcArgsImp : public WebRtcArgs { public: - WebRtcArgsImp(const HttpAllArgs &args, std::string session_id) + WebRtcArgsImp(const ArgsString &args, std::string session_id) : _args(args) , _session_id(std::move(session_id)) {} ~WebRtcArgsImp() override = default; @@ -1759,40 +1754,26 @@ void installWebApi() { CHECK_ARGS("app", "stream"); return StrPrinter << "rtc://" << _args["Host"] << "/" << _args["app"] << "/" - << _args["stream"] << "?" << _args.getParser().params() + "&session=" + _session_id; + << _args["stream"] << "?" << _args.parser.params() + "&session=" + _session_id; } private: - HttpAllArgs _args; + ArgsString _args; std::string _session_id; }; api_regist("/index/api/webrtc",[](API_ARGS_STRING_ASYNC){ CHECK_ARGS("type"); auto type = allArgs["type"]; - auto offer = allArgs.getArgs(); + auto offer = allArgs.args; CHECK(!offer.empty(), "http body(webrtc offer sdp) is empty"); - std::string host = allArgs.getParser()["Host"]; - std::string localIp = host.substr(0, host.find(':')); - - auto isVaildIP = [](std::string ip)-> bool { - int a,b,c,d; - return sscanf(ip.c_str(),"%d.%d.%d.%d", &a, &b, &c, &d) == 4; - }; - if (!isVaildIP(localIp) || localIp=="127.0.0.1") { - localIp = ""; - } + auto &session = static_cast(sender); auto args = std::make_shared(allArgs, sender.getIdentifier()); - WebRtcPluginManager::Instance().getAnswerSdp(static_cast(sender), type, *args, [invoker, val, offer, headerOut, localIp](const WebRtcInterface &exchanger) mutable { - //设置返回类型 - headerOut["Content-Type"] = HttpFileManager::getContentType(".json"); - //设置跨域 - headerOut["Access-Control-Allow-Origin"] = "*"; - + WebRtcPluginManager::Instance().negotiateSdp(session, type, *args, [invoker, val, offer, headerOut](const WebRtcInterface &exchanger) mutable { + auto &handler = const_cast(exchanger); try { - setLocalIp(exchanger,localIp); - val["sdp"] = exchangeSdp(exchanger, offer); + val["sdp"] = handler.getAnswerSdp(offer); val["id"] = exchanger.getIdentifier(); val["type"] = "answer"; invoker(200, headerOut, val.toStyledString()); @@ -1806,26 +1787,24 @@ void installWebApi() { static constexpr char delete_webrtc_url [] = "/index/api/delete_webrtc"; static auto whip_whep_func = [](const char *type, API_ARGS_STRING_ASYNC) { - auto offer = allArgs.getArgs(); + auto offer = allArgs.args; CHECK(!offer.empty(), "http body(webrtc offer sdp) is empty"); auto &session = static_cast(sender); - auto location = std::string("http") + (session.overSsl() ? "s" : "") + "://" + allArgs["host"] + delete_webrtc_url; + auto location = std::string(session.overSsl() ? "https://" : "http://") + allArgs["host"] + delete_webrtc_url; auto args = std::make_shared(allArgs, sender.getIdentifier()); - WebRtcPluginManager::Instance().getAnswerSdp(session, type, *args, - [invoker, offer, headerOut, location](const WebRtcInterface &exchanger) mutable { - // 设置跨域 - headerOut["Access-Control-Allow-Origin"] = "*"; - try { - // 设置返回类型 - headerOut["Content-Type"] = "application/sdp"; - headerOut["Location"] = location + "?id=" + exchanger.getIdentifier() + "&token=" + exchanger.deleteRandStr(); - invoker(201, headerOut, exchangeSdp(exchanger, offer)); - } catch (std::exception &ex) { - headerOut["Content-Type"] = "text/plain"; - invoker(406, headerOut, ex.what()); - } - }); + WebRtcPluginManager::Instance().negotiateSdp(session, type, *args, [invoker, offer, headerOut, location](const WebRtcInterface &exchanger) mutable { + auto &handler = const_cast(exchanger); + try { + // 设置返回类型 + headerOut["Content-Type"] = "application/sdp"; + headerOut["Location"] = location + "?id=" + exchanger.getIdentifier() + "&token=" + exchanger.deleteRandStr(); + invoker(201, headerOut, handler.getAnswerSdp(offer)); + } catch (std::exception &ex) { + headerOut["Content-Type"] = "text/plain"; + invoker(406, headerOut, ex.what()); + } + }); }; api_regist("/index/api/whip", [](API_ARGS_STRING_ASYNC) { whip_whep_func("push", API_ARGS_VALUE, invoker); }); @@ -1833,7 +1812,7 @@ void installWebApi() { api_regist(delete_webrtc_url, [](API_ARGS_MAP_ASYNC) { CHECK_ARGS("id", "token"); - CHECK(allArgs.getParser().method() == "DELETE", "http method is not DELETE: " + allArgs.getParser().method()); + CHECK(allArgs.parser.method() == "DELETE", "http method is not DELETE: " + allArgs.parser.method()); auto obj = WebRtcTransportManager::Instance().getItem(allArgs["id"]); if (!obj) { invoker(404, headerOut, "id not found"); @@ -1919,11 +1898,11 @@ void installWebApi() { if (!save_name.empty()) { res_header.emplace("Content-Disposition", "attachment;filename=\"" + save_name + "\""); } - invoker.responseFile(allArgs.getParser().getHeader(), res_header, allArgs["file_path"]); + invoker.responseFile(allArgs.parser.getHeader(), res_header, allArgs["file_path"]); } }; - bool flag = NOTICE_EMIT(BroadcastHttpAccessArgs, Broadcast::kBroadcastHttpAccess, allArgs.getParser(), file_path, false, file_invoker, sender); + bool flag = NOTICE_EMIT(BroadcastHttpAccessArgs, Broadcast::kBroadcastHttpAccess, allArgs.parser, file_path, false, file_invoker, sender); if (!flag) { // 文件下载鉴权事件无人监听,不允许下载 invoker(401, StrCaseMap {}, "None http access event listener"); @@ -1935,28 +1914,23 @@ void installWebApi() { NoticeCenter::Instance().addListener(nullptr, Broadcast::kBroadcastStreamNoneReader, [](BroadcastStreamNoneReaderArgs) { auto id = sender.getMediaTuple().stream; VideoStackManager::Instance().stopVideoStack(id); - InfoL << "VideoStack: " << id <<" stop"; }); api_regist("/index/api/stack/start", [](API_ARGS_JSON_ASYNC) { CHECK_SECRET(); auto ret = VideoStackManager::Instance().startVideoStack(allArgs.getArgs()); - if (!ret) { - invoker(200, headerOut, "success"); - } else { - invoker(200, headerOut, "failed"); - } + val["code"] = ret; + val["msg"] = ret ? "failed" : "success"; + invoker(200, headerOut, val.toStyledString()); }); api_regist("/index/api/stack/stop", [](API_ARGS_MAP_ASYNC) { CHECK_SECRET(); CHECK_ARGS("id"); auto ret = VideoStackManager::Instance().stopVideoStack(allArgs["id"]); - if (!ret) { - invoker(200, headerOut, "success"); - } else { - invoker(200, headerOut, "failed"); - } + val["code"] = ret; + val["msg"] = ret ? "failed" : "success"; + invoker(200, headerOut, val.toStyledString()); }); #endif } diff --git a/server/WebApi.h b/server/WebApi.h index 1d1be694..95562bbf 100755 --- a/server/WebApi.h +++ b/server/WebApi.h @@ -115,72 +115,41 @@ std::string getValue(const mediakit::Parser &parser, Args &args, const First &fi template class HttpAllArgs { + mediakit::Parser* _parser = nullptr; + Args* _args = nullptr; public: - HttpAllArgs(const mediakit::Parser &parser, Args &args) { - _get_args = [&args]() { - return (void *) &args; - }; - _get_parser = [&parser]() -> const mediakit::Parser & { - return parser; - }; - _get_value = [](HttpAllArgs &that, const std::string &key) { - return getValue(that.getParser(), that.getArgs(), key); - }; - _clone = [&](HttpAllArgs &that) { - that._get_args = [args]() { - return (void *) &args; - }; - that._get_parser = [parser]() -> const mediakit::Parser & { - return parser; - }; - that._get_value = [](HttpAllArgs &that, const std::string &key) { - return getValue(that.getParser(), that.getArgs(), key); - }; - that._cache_able = true; - }; - } + const mediakit::Parser& parser; + Args& args; - HttpAllArgs(const HttpAllArgs &that) { - if (that._cache_able) { - _get_args = that._get_args; - _get_parser = that._get_parser; - _get_value = that._get_value; - _cache_able = true; - } else { - that._clone(*this); + HttpAllArgs(const mediakit::Parser &p, Args &a): parser(p), args(a) {} + + HttpAllArgs(const HttpAllArgs &that): _parser(new mediakit::Parser(that.parser)), + _args(new Args(that.args)), + parser(*_parser), args(*_args) {} + ~HttpAllArgs() { + if (_parser) { + delete _parser; + } + if (_args) { + delete _args; } } template toolkit::variant operator[](const Key &key) const { - return (toolkit::variant)_get_value(*(HttpAllArgs*)this, key); + return (toolkit::variant)getValue(parser, args, key); } - - const mediakit::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; - std::function _get_args; - std::function _get_parser; - std::function _get_value; - std::function _clone; }; -#define API_ARGS_MAP toolkit::SockInfo &sender, mediakit::HttpSession::KeyValue &headerOut, const HttpAllArgs &allArgs, Json::Value &val +using ArgsMap = HttpAllArgs; +using ArgsJson = HttpAllArgs; +using ArgsString = HttpAllArgs; + +#define API_ARGS_MAP toolkit::SockInfo &sender, mediakit::HttpSession::KeyValue &headerOut, const ArgsMap &allArgs, Json::Value &val #define API_ARGS_MAP_ASYNC API_ARGS_MAP, const mediakit::HttpSession::HttpResponseInvoker &invoker -#define API_ARGS_JSON toolkit::SockInfo &sender, mediakit::HttpSession::KeyValue &headerOut, const HttpAllArgs &allArgs, Json::Value &val +#define API_ARGS_JSON toolkit::SockInfo &sender, mediakit::HttpSession::KeyValue &headerOut, const ArgsJson &allArgs, Json::Value &val #define API_ARGS_JSON_ASYNC API_ARGS_JSON, const mediakit::HttpSession::HttpResponseInvoker &invoker -#define API_ARGS_STRING toolkit::SockInfo &sender, mediakit::HttpSession::KeyValue &headerOut, const HttpAllArgs &allArgs, Json::Value &val +#define API_ARGS_STRING toolkit::SockInfo &sender, mediakit::HttpSession::KeyValue &headerOut, const ArgsString &allArgs, Json::Value &val #define API_ARGS_STRING_ASYNC API_ARGS_STRING, const mediakit::HttpSession::HttpResponseInvoker &invoker #define API_ARGS_VALUE sender, headerOut, allArgs, val diff --git a/server/main.cpp b/server/main.cpp index c25a89fb..8449f102 100644 --- a/server/main.cpp +++ b/server/main.cpp @@ -38,7 +38,7 @@ #endif #if defined(ENABLE_VERSION) -#include "version.h" +#include "ZLMVersion.h" #endif #if !defined(_WIN32) diff --git a/src/Common/MediaSource.h b/src/Common/MediaSource.h index 1ce0d8c5..b156954c 100644 --- a/src/Common/MediaSource.h +++ b/src/Common/MediaSource.h @@ -136,6 +136,15 @@ private: toolkit::Timer::Ptr _async_close_timer; }; + +template +static void getArgsValue(const MAP &allArgs, const KEY &key, TYPE &value) { + auto val = ((MAP &)allArgs)[key]; + if (!val.empty()) { + value = (TYPE)val; + } +} + class ProtocolOption { public: ProtocolOption(); @@ -243,15 +252,6 @@ public: GET_OPT_VALUE(stream_replace); GET_OPT_VALUE(max_track); } - -private: - template - static void getArgsValue(const MAP &allArgs, const KEY &key, TYPE &value) { - auto val = ((MAP &)allArgs)[key]; - if (!val.empty()) { - value = (TYPE)val; - } - } }; //该对象用于拦截感兴趣的MediaSourceEvent事件 diff --git a/src/Common/Parser.cpp b/src/Common/Parser.cpp index ab41c53e..7e7de860 100644 --- a/src/Common/Parser.cpp +++ b/src/Common/Parser.cpp @@ -294,8 +294,8 @@ void RtspUrl::setup(bool is_ssl, const string &url, const string &user, const st splitUrl(ip, ip, port); _url = std::move(url); - _user = strCoding::UrlDecode(std::move(user)); - _passwd = strCoding::UrlDecode(std::move(passwd)); + _user = strCoding::UrlDecodeComponent(user); + _passwd = strCoding::UrlDecodeComponent(passwd); _host = std::move(ip); _port = port; _is_ssl = is_ssl; diff --git a/src/Common/Parser.h b/src/Common/Parser.h index 624e5f27..324658ba 100644 --- a/src/Common/Parser.h +++ b/src/Common/Parser.h @@ -30,7 +30,7 @@ struct StrCaseCompare { class StrCaseMap : public std::multimap { public: - using Super = multimap; + using Super = std::multimap; std::string &operator[](const std::string &k) { auto it = find(k); diff --git a/src/Common/macros.cpp b/src/Common/macros.cpp index 3cb95c7b..5e403b6a 100644 --- a/src/Common/macros.cpp +++ b/src/Common/macros.cpp @@ -14,7 +14,7 @@ using namespace toolkit; #if defined(ENABLE_VERSION) -#include "version.h" +#include "ZLMVersion.h" #endif extern "C" { @@ -44,4 +44,4 @@ const char kServerName[] = "ZLMediaKit-8.0(build in " __DATE__ " " __TIME__ ")" const char kServerName[] = "ZLMediaKit(git hash:" COMMIT_HASH "/" COMMIT_TIME ",branch:" BRANCH_NAME ",build time:" BUILD_TIME ")"; #endif -}//namespace mediakit \ No newline at end of file +}//namespace mediakit diff --git a/src/Common/macros.h b/src/Common/macros.h index 796bd326..b1187810 100644 --- a/src/Common/macros.h +++ b/src/Common/macros.h @@ -36,6 +36,16 @@ #define CHECK(exp, ...) ::mediakit::Assert_ThrowCpp(!(exp), #exp, __FUNCTION__, __FILE__, __LINE__, ##__VA_ARGS__) #endif // CHECK +#ifndef CHECK_RET +#define CHECK_RET(...) \ + try { \ + CHECK(__VA_ARGS__); \ + } catch (AssertFailedException & ex) { \ + WarnL << ex.what(); \ + return; \ + } +#endif + #ifndef MAX #define MAX(a, b) ((a) > (b) ? (a) : (b)) #endif // MAX diff --git a/src/Common/strCoding.cpp b/src/Common/strCoding.cpp index 59a0b7e4..1a0f0236 100644 --- a/src/Common/strCoding.cpp +++ b/src/Common/strCoding.cpp @@ -53,22 +53,6 @@ char HexStrToBin(const char *str) { return (high << 4) | low; } -string strCoding::UrlEncode(const string &str) { - string out; - size_t len = str.size(); - for (size_t i = 0; i < len; ++i) { - char ch = str[i]; - if (isalnum((uint8_t) ch)) { - out.push_back(ch); - } else { - char buf[4]; - sprintf(buf, "%%%X%X", (uint8_t) ch >> 4, (uint8_t) ch & 0x0F); - out.append(buf); - } - } - return out; -} - string strCoding::UrlEncodePath(const string &str) { const char *dont_escape = "!#&'*+:=?@/._-$,;~()"; string out; @@ -103,32 +87,6 @@ string strCoding::UrlEncodeComponent(const string &str) { return out; } -string strCoding::UrlDecode(const string &str) { - string output; - size_t i = 0, len = str.length(); - while (i < len) { - if (str[i] == '%') { - if (i + 3 > len) { - // %后面必须还有两个字节才会反转义 - output.append(str, i, len - i); - break; - } - char ch = HexStrToBin(&(str[i + 1])); - if (ch == -1) { - // %后面两个字节不是16进制字符串,转义失败;直接拼接3个原始字符 - output.append(str, i, 3); - } else { - output += ch; - } - i += 3; - } else { - output += str[i]; - ++i; - } - } - return output; -} - string strCoding::UrlDecodePath(const string &str) { const char *dont_unescape = "#$&+,/:;=?@"; string output; @@ -185,27 +143,6 @@ std::string strCoding::UrlDecodeComponent(const std::string &str) { return output; } -#if 0 -#include "Util/onceToken.h" -static toolkit::onceToken token([]() { - auto str0 = strCoding::UrlDecode( - "rtsp%3A%2F%2Fadmin%3AJm13317934%25jm%40111.47.84.69%3A554%2FStreaming%2FChannels%2F101%3Ftransportmode%3Dunicast%26amp%3Bprofile%3DProfile_1"); - auto str1 = strCoding::UrlDecode("%j1"); // 测试%后面两个字节不是16进制字符串 - auto str2 = strCoding::UrlDecode("%a"); // 测试%后面字节数不够 - auto str3 = strCoding::UrlDecode("%"); // 测试只有% - auto str4 = strCoding::UrlDecode("%%%"); // 测试多个% - auto str5 = strCoding::UrlDecode("%%%%40"); // 测试多个非法%后恢复正常解析 - auto str6 = strCoding::UrlDecode("Jm13317934%jm"); // 测试多个非法%后恢复正常解析 - cout << str0 << endl; - cout << str1 << endl; - cout << str2 << endl; - cout << str3 << endl; - cout << str4 << endl; - cout << str5 << endl; - cout << str6 << endl; -}); -#endif - ///////////////////////////////windows专用/////////////////////////////////// #if defined(_WIN32) void UnicodeToGB2312(char* pOut, wchar_t uData) diff --git a/src/Common/strCoding.h b/src/Common/strCoding.h index 14371704..e715e74d 100644 --- a/src/Common/strCoding.h +++ b/src/Common/strCoding.h @@ -18,10 +18,8 @@ namespace mediakit { class strCoding { public: - [[deprecated]] static std::string UrlEncode(const std::string &str); //url utf8编码, deprecated static std::string UrlEncodePath(const std::string &str); //url路径 utf8编码 static std::string UrlEncodeComponent(const std::string &str); // url参数 utf8编码 - [[deprecated]] static std::string UrlDecode(const std::string &str); //url utf8解码, deprecated static std::string UrlDecodePath(const std::string &str); //url路径 utf8解码 static std::string UrlDecodeComponent(const std::string &str); // url参数 utf8解码 #if defined(_WIN32) diff --git a/src/Http/HttpRequestSplitter.cpp b/src/Http/HttpRequestSplitter.cpp index 32ab476f..9cc4cfcb 100644 --- a/src/Http/HttpRequestSplitter.cpp +++ b/src/Http/HttpRequestSplitter.cpp @@ -65,18 +65,18 @@ void HttpRequestSplitter::input(const char *data,size_t len) { _content_len = onRecvHeader(header_ptr, header_size); } - if(_remain_data_size <= 0){ - //没有剩余数据,清空缓存 - _remain_data.clear(); - return; - } - /* * 恢复末尾字节 * 移动到这来,目的是防止HttpRequestSplitter::reset()导致内存失效 */ tail_ref = tail_tmp; + if(_remain_data_size <= 0){ + //没有剩余数据,清空缓存 + _remain_data.clear(); + return; + } + if(_content_len == 0){ //尚未找到http头,缓存定位到剩余数据部分 _remain_data.assign(ptr,_remain_data_size); diff --git a/src/Http/HttpSession.cpp b/src/Http/HttpSession.cpp index 3c34a661..ba74d803 100644 --- a/src/Http/HttpSession.cpp +++ b/src/Http/HttpSession.cpp @@ -683,18 +683,6 @@ void HttpSession::sendResponse(int code, AsyncSender::onSocketFlushed(data); } -string HttpSession::urlDecode(const string &str) { - auto ret = strCoding::UrlDecode(str); -#ifdef _WIN32 - GET_CONFIG(string, charSet, Http::kCharSet); - bool isGb2312 = !strcasecmp(charSet.data(), "gb2312"); - if (isGb2312) { - ret = strCoding::UTF8ToGB2312(ret); - } -#endif // _WIN32 - return ret; -} - string HttpSession::urlDecodePath(const string &str) { auto ret = strCoding::UrlDecodePath(str); #ifdef _WIN32 diff --git a/src/Http/HttpSession.h b/src/Http/HttpSession.h index 2bc1c353..0ffbf137 100644 --- a/src/Http/HttpSession.h +++ b/src/Http/HttpSession.h @@ -44,7 +44,6 @@ public: void onRecv(const toolkit::Buffer::Ptr &) override; void onError(const toolkit::SockException &err) override; void onManager() override; - [[deprecated]] static std::string urlDecode(const std::string &str); static std::string urlDecodePath(const std::string &str); static std::string urlDecodeComponent(const std::string &str); void setTimeoutSec(size_t second); diff --git a/src/Rtmp/RtmpMediaSourceMuxer.h b/src/Rtmp/RtmpMediaSourceMuxer.h index 6572fae5..1d16d5de 100644 --- a/src/Rtmp/RtmpMediaSourceMuxer.h +++ b/src/Rtmp/RtmpMediaSourceMuxer.h @@ -29,7 +29,13 @@ public: getRtmpRing()->setDelegate(_media_src); } - ~RtmpMediaSourceMuxer() override { RtmpMuxer::flush(); } + ~RtmpMediaSourceMuxer() override { + try { + RtmpMuxer::flush(); + } catch (std::exception &ex) { + WarnL << ex.what(); + } + } void setListener(const std::weak_ptr &listener){ setDelegate(listener); diff --git a/src/Rtmp/RtmpProtocol.cpp b/src/Rtmp/RtmpProtocol.cpp index f98468bf..010e30d4 100644 --- a/src/Rtmp/RtmpProtocol.cpp +++ b/src/Rtmp/RtmpProtocol.cpp @@ -165,14 +165,7 @@ void RtmpProtocol::sendResponse(int type, const string &str) { void RtmpProtocol::sendInvoke(const string &cmd, const AMFValue &val) { AMFEncoder enc; - if (val.type() == AMFType::AMF_OBJECT || val.type() == AMFType::AMF_NULL) - { - enc << cmd << ++_send_req_id << val; - } - else - { - enc << cmd << ++_send_req_id << AMFValue() << val; - } + enc << cmd << ++_send_req_id << val; sendRequest(MSG_CMD, enc.data()); } @@ -626,22 +619,12 @@ const char* RtmpProtocol::handle_rtmp(const char *data, size_t len) { case 12: chunk_data.is_abs_stamp = true; chunk_data.stream_index = load_le32(header->stream_index); - _last_stream_index = chunk_data.stream_index; case 8: chunk_data.body_size = load_be24(header->body_size); chunk_data.type_id = header->type_id; - _last_body_size = chunk_data.body_size; - _last_type_id = chunk_data.type_id; case 4: chunk_data.ts_field = load_be24(header->time_stamp); } - switch (header->fmt) { - case 2: - chunk_data.type_id = _last_type_id; - chunk_data.body_size = _last_body_size; - case 1: - chunk_data.stream_index = _last_stream_index; - } auto time_stamp = chunk_data.ts_field; if (chunk_data.ts_field == 0xFFFFFF) { diff --git a/src/Rtmp/RtmpProtocol.h b/src/Rtmp/RtmpProtocol.h index 2b7adfff..7ace93eb 100644 --- a/src/Rtmp/RtmpProtocol.h +++ b/src/Rtmp/RtmpProtocol.h @@ -11,7 +11,6 @@ #ifndef SRC_RTMP_RTMPPROTOCOL_H_ #define SRC_RTMP_RTMPPROTOCOL_H_ -#include #include #include #include @@ -88,9 +87,6 @@ protected: private: bool _data_started = false; int _now_chunk_id = 0; - uint32_t _last_stream_index = 0; - size_t _last_body_size = 0; - uint8_t _last_type_id = 0; ////////////ChunkSize//////////// size_t _chunk_size_in = DEFAULT_CHUNK_LEN; size_t _chunk_size_out = DEFAULT_CHUNK_LEN; diff --git a/src/Rtmp/RtmpPusher.cpp b/src/Rtmp/RtmpPusher.cpp index 8f3596fc..92363241 100644 --- a/src/Rtmp/RtmpPusher.cpp +++ b/src/Rtmp/RtmpPusher.cpp @@ -163,28 +163,14 @@ void RtmpPusher::send_connect() { } void RtmpPusher::send_createStream() { - // Workaround : 兼容较旧的 FMS3.0 - { - { - AMFValue obj(_stream_id); - sendInvoke("releaseStream", obj); - } - { - AMFValue obj(_stream_id); - sendInvoke("FCPublish", obj); - } - } - { - AMFValue obj(AMF_NULL); - sendInvoke("createStream", obj); - addOnResultCB([this](AMFDecoder &dec) { - //TraceL << "createStream result"; - dec.load(); - _stream_index = dec.load(); - send_publish(); - }); - } - + AMFValue obj(AMF_NULL); + sendInvoke("createStream", obj); + addOnResultCB([this](AMFDecoder &dec) { + //TraceL << "createStream result"; + dec.load(); + _stream_index = dec.load(); + send_publish(); + }); } #define RTMP_STREAM_LIVE "live" diff --git a/webrtc/Sdp.cpp b/webrtc/Sdp.cpp index bed1bf57..e1f1d045 100644 --- a/webrtc/Sdp.cpp +++ b/webrtc/Sdp.cpp @@ -20,19 +20,19 @@ namespace mediakit { namespace Rtc { #define RTC_FIELD "rtc." -const string kPreferredCodecA = RTC_FIELD"preferredCodecA"; -const string kPreferredCodecV = RTC_FIELD"preferredCodecV"; +const string kPreferredCodecA = RTC_FIELD "preferredCodecA"; +const string kPreferredCodecV = RTC_FIELD "preferredCodecV"; static onceToken token([]() { - mINI::Instance()[kPreferredCodecA] = "PCMU,PCMA,opus,mpeg4-generic"; + mINI::Instance()[kPreferredCodecA] = "PCMA,PCMU,opus,mpeg4-generic"; mINI::Instance()[kPreferredCodecV] = "H264,H265,AV1,VP9,VP8"; }); -} +} // namespace Rtc using onCreateSdpItem = function; static map sdpItemCreator; template -void registerSdpItem(){ +void registerSdpItem() { onCreateSdpItem func = [](const string &key, const string &value) { auto ret = std::make_shared(); ret->parse(value); @@ -47,52 +47,50 @@ public: virtual RtpDirection getDirection() const = 0; }; -class SdpDirectionSendonly : public SdpItem, public DirectionInterface{ +class SdpDirectionSendonly : public SdpItem, public DirectionInterface { public: - const char* getKey() const override { return getRtpDirectionString(getDirection());} - RtpDirection getDirection() const override {return RtpDirection::sendonly;} + const char *getKey() const override { return getRtpDirectionString(getDirection()); } + RtpDirection getDirection() const override { return RtpDirection::sendonly; } }; -class SdpDirectionRecvonly : public SdpItem, public DirectionInterface{ +class SdpDirectionRecvonly : public SdpItem, public DirectionInterface { public: - const char* getKey() const override { return getRtpDirectionString(getDirection());} - RtpDirection getDirection() const override {return RtpDirection::recvonly;} + const char *getKey() const override { return getRtpDirectionString(getDirection()); } + RtpDirection getDirection() const override { return RtpDirection::recvonly; } }; -class SdpDirectionSendrecv : public SdpItem, public DirectionInterface{ +class SdpDirectionSendrecv : public SdpItem, public DirectionInterface { public: - const char* getKey() const override { return getRtpDirectionString(getDirection());} - RtpDirection getDirection() const override {return RtpDirection::sendrecv;} + const char *getKey() const override { return getRtpDirectionString(getDirection()); } + RtpDirection getDirection() const override { return RtpDirection::sendrecv; } }; -class SdpDirectionInactive : public SdpItem, public DirectionInterface{ +class SdpDirectionInactive : public SdpItem, public DirectionInterface { public: - const char* getKey() const override { return getRtpDirectionString(getDirection());} - RtpDirection getDirection() const override {return RtpDirection::inactive;} + const char *getKey() const override { return getRtpDirectionString(getDirection()); } + RtpDirection getDirection() const override { return RtpDirection::inactive; } }; -class DirectionInterfaceImp : public SdpItem, public DirectionInterface{ +class DirectionInterfaceImp : public SdpItem, public DirectionInterface { public: - DirectionInterfaceImp(RtpDirection direct){ - direction = direct; - } - const char* getKey() const override { return getRtpDirectionString(getDirection());} - RtpDirection getDirection() const override {return direction;} + DirectionInterfaceImp(RtpDirection direct) { direction = direct; } + const char *getKey() const override { return getRtpDirectionString(getDirection()); } + RtpDirection getDirection() const override { return direction; } private: RtpDirection direction; }; -static bool registerAllItem(){ - registerSdpItem >(); - registerSdpItem >(); - registerSdpItem >(); - registerSdpItem >(); - registerSdpItem >(); - registerSdpItem >(); - registerSdpItem >(); - registerSdpItem >(); - registerSdpItem >(); +static bool registerAllItem() { + registerSdpItem>(); + registerSdpItem>(); + registerSdpItem>(); + registerSdpItem>(); + registerSdpItem>(); + registerSdpItem>(); + registerSdpItem>(); + registerSdpItem>(); + registerSdpItem>(); registerSdpItem(); registerSdpItem(); registerSdpItem(); @@ -138,11 +136,11 @@ DtlsRole getDtlsRole(const string &str) { return it == dtls_role_map.end() ? DtlsRole::invalid : it->second; } -const char* getDtlsRoleString(DtlsRole role){ +const char *getDtlsRoleString(DtlsRole role) { switch (role) { - case DtlsRole::active : return "active"; - case DtlsRole::passive : return "passive"; - case DtlsRole::actpass : return "actpass"; + case DtlsRole::active: return "active"; + case DtlsRole::passive: return "passive"; + case DtlsRole::actpass: return "actpass"; default: return "invalid"; } } @@ -159,12 +157,12 @@ RtpDirection getRtpDirection(const string &str) { return it == direction_map.end() ? RtpDirection::invalid : it->second; } -const char* getRtpDirectionString(RtpDirection val){ +const char *getRtpDirectionString(RtpDirection val) { switch (val) { - case RtpDirection::sendonly : return "sendonly"; - case RtpDirection::recvonly : return "recvonly"; - case RtpDirection::sendrecv : return "sendrecv"; - case RtpDirection::inactive : return "inactive"; + case RtpDirection::sendonly: return "sendonly"; + case RtpDirection::recvonly: return "recvonly"; + case RtpDirection::sendrecv: return "sendrecv"; + case RtpDirection::inactive: return "inactive"; default: return "invalid"; } } @@ -179,7 +177,7 @@ string RtcSdpBase::toString() const { return std::move(printer); } -RtpDirection RtcSdpBase::getDirection() const{ +RtpDirection RtcSdpBase::getDirection() const { for (auto &item : items) { auto attr = dynamic_pointer_cast(item); if (attr) { @@ -200,7 +198,7 @@ SdpItem::Ptr RtcSdpBase::getItem(char key_c, const char *attr_key) const { return item; } auto attr = dynamic_pointer_cast(item); - if (attr && !strcasecmp(attr->detail->getKey() , attr_key)) { + if (attr && !strcasecmp(attr->detail->getKey(), attr_key)) { return attr->detail; } } @@ -225,7 +223,7 @@ string RtcSessionSdp::getSessionInfo() const { return getStringItem('i'); } -SdpTime RtcSessionSdp::getSessionTime() const{ +SdpTime RtcSessionSdp::getSessionTime() const { return getItemClass('t'); } @@ -422,7 +420,7 @@ string SdpAttr::toString() const { return SdpItem::toString(); } -void SdpAttrGroup::parse(const string &str) { +void SdpAttrGroup::parse(const string &str) { auto vec = split(str, " "); CHECK_SDP(vec.size() >= 2); type = vec[0]; @@ -430,7 +428,7 @@ void SdpAttrGroup::parse(const string &str) { mids = std::move(vec); } -string SdpAttrGroup::toString() const { +string SdpAttrGroup::toString() const { if (value.empty()) { value = type; for (auto mid : mids) { @@ -441,14 +439,14 @@ string SdpAttrGroup::toString() const { return SdpItem::toString(); } -void SdpAttrMsidSemantic::parse(const string &str) { +void SdpAttrMsidSemantic::parse(const string &str) { auto vec = split(str, " "); CHECK_SDP(vec.size() >= 1); msid = vec[0]; token = vec.size() > 1 ? vec[1] : ""; } -string SdpAttrMsidSemantic::toString() const { +string SdpAttrMsidSemantic::toString() const { if (value.empty()) { if (token.empty()) { value = string(" ") + msid; @@ -459,7 +457,7 @@ string SdpAttrMsidSemantic::toString() const { return SdpItem::toString(); } -void SdpAttrRtcp::parse(const string &str) { +void SdpAttrRtcp::parse(const string &str) { auto vec = split(str, " "); CHECK_SDP(vec.size() == 4); port = atoi(vec[0].data()); @@ -468,14 +466,14 @@ void SdpAttrRtcp::parse(const string &str) { address = vec[3]; } -string SdpAttrRtcp::toString() const { +string SdpAttrRtcp::toString() const { if (value.empty()) { value = to_string(port) + " " + nettype + " " + addrtype + " " + address; } return SdpItem::toString(); } -void SdpAttrIceOption::parse(const string &str){ +void SdpAttrIceOption::parse(const string &str) { auto vec = split(str, " "); for (auto &v : vec) { if (!strcasecmp(v.data(), "trickle")) { @@ -489,7 +487,7 @@ void SdpAttrIceOption::parse(const string &str){ } } -string SdpAttrIceOption::toString() const{ +string SdpAttrIceOption::toString() const { if (value.empty()) { if (trickle && renomination) { value = "trickle renomination"; @@ -502,35 +500,35 @@ string SdpAttrIceOption::toString() const{ return value; } -void SdpAttrFingerprint::parse(const string &str) { +void SdpAttrFingerprint::parse(const string &str) { auto vec = split(str, " "); CHECK_SDP(vec.size() == 2); algorithm = vec[0]; hash = vec[1]; } -string SdpAttrFingerprint::toString() const { +string SdpAttrFingerprint::toString() const { if (value.empty()) { value = algorithm + " " + hash; } return SdpItem::toString(); } -void SdpAttrSetup::parse(const string &str) { +void SdpAttrSetup::parse(const string &str) { role = getDtlsRole(str); CHECK_SDP(role != DtlsRole::invalid); } -string SdpAttrSetup::toString() const { +string SdpAttrSetup::toString() const { if (value.empty()) { value = getDtlsRoleString(role); } return SdpItem::toString(); } -void SdpAttrExtmap::parse(const string &str) { - char buf[128] = {0}; - char direction_buf[32] = {0}; +void SdpAttrExtmap::parse(const string &str) { + char buf[128] = { 0 }; + char direction_buf[32] = { 0 }; if (sscanf(str.data(), "%" SCNd8 "/%31[^ ] %127s", &id, direction_buf, buf) != 3) { CHECK_SDP(sscanf(str.data(), "%" SCNd8 " %127s", &id, buf) == 2); direction = RtpDirection::sendrecv; @@ -540,30 +538,30 @@ void SdpAttrExtmap::parse(const string &str) { ext = buf; } -string SdpAttrExtmap::toString() const { +string SdpAttrExtmap::toString() const { if (value.empty()) { - if(direction == RtpDirection::invalid || direction == RtpDirection::sendrecv){ + if (direction == RtpDirection::invalid || direction == RtpDirection::sendrecv) { value = to_string((int)id) + " " + ext; } else { - value = to_string((int)id) + "/" + getRtpDirectionString(direction) + " " + ext; + value = to_string((int)id) + "/" + getRtpDirectionString(direction) + " " + ext; } } return SdpItem::toString(); } -void SdpAttrRtpMap::parse(const string &str) { - char buf[32] = {0}; +void SdpAttrRtpMap::parse(const string &str) { + char buf[32] = { 0 }; if (sscanf(str.data(), "%" SCNu8 " %31[^/]/%" SCNd32 "/%" SCNd32, &pt, buf, &sample_rate, &channel) != 4) { CHECK_SDP(sscanf(str.data(), "%" SCNu8 " %31[^/]/%" SCNd32, &pt, buf, &sample_rate) == 3); if (getTrackType(getCodecId(buf)) == TrackAudio) { - //未指定通道数时,且为音频时,那么通道数默认为1 + // 未指定通道数时,且为音频时,那么通道数默认为1 channel = 1; } } codec = buf; } -string SdpAttrRtpMap::toString() const { +string SdpAttrRtpMap::toString() const { if (value.empty()) { value = to_string((int)pt) + " " + codec + "/" + to_string(sample_rate); if (channel) { @@ -574,21 +572,21 @@ string SdpAttrRtpMap::toString() const { return SdpItem::toString(); } -void SdpAttrRtcpFb::parse(const string &str_in) { +void SdpAttrRtcpFb::parse(const string &str_in) { auto str = str_in + "\n"; - char rtcp_type_buf[32] = {0}; + char rtcp_type_buf[32] = { 0 }; CHECK_SDP(sscanf(str.data(), "%" SCNu8 " %31[^\n]", &pt, rtcp_type_buf) == 2); rtcp_type = rtcp_type_buf; } -string SdpAttrRtcpFb::toString() const { +string SdpAttrRtcpFb::toString() const { if (value.empty()) { value = to_string((int)pt) + " " + rtcp_type; } return SdpItem::toString(); } -void SdpAttrFmtp::parse(const string &str) { +void SdpAttrFmtp::parse(const string &str) { auto pos = str.find(' '); CHECK_SDP(pos != string::npos); pt = atoi(str.substr(0, pos).data()); @@ -596,31 +594,31 @@ void SdpAttrFmtp::parse(const string &str) { for (auto &item : vec) { trim(item); auto pos = item.find('='); - if(pos == string::npos){ + if (pos == string::npos) { fmtp.emplace(std::make_pair(item, "")); - } else { + } else { fmtp.emplace(std::make_pair(item.substr(0, pos), item.substr(pos + 1))); } } CHECK_SDP(!fmtp.empty()); } -string SdpAttrFmtp::toString() const { +string SdpAttrFmtp::toString() const { if (value.empty()) { value = to_string((int)pt); int i = 0; for (auto &pr : fmtp) { - value += (i++ ? ';' : ' '); + value += (i++ ? ';' : ' '); value += pr.first + "=" + pr.second; } } return SdpItem::toString(); } -void SdpAttrSSRC::parse(const string &str_in) { +void SdpAttrSSRC::parse(const string &str_in) { auto str = str_in + '\n'; - char attr_buf[32] = {0}; - char attr_val_buf[128] = {0}; + char attr_buf[32] = { 0 }; + char attr_val_buf[128] = { 0 }; if (3 == sscanf(str.data(), "%" SCNu32 " %31[^:]:%127[^\n]", &ssrc, attr_buf, attr_val_buf)) { attribute = attr_buf; attribute_value = attr_val_buf; @@ -631,7 +629,7 @@ void SdpAttrSSRC::parse(const string &str_in) { } } -string SdpAttrSSRC::toString() const { +string SdpAttrSSRC::toString() const { if (value.empty()) { value = to_string(ssrc) + ' '; value += attribute; @@ -650,14 +648,14 @@ void SdpAttrSSRCGroup::parse(const string &str) { CHECK(isFID() || isSIM()); vec.erase(vec.begin()); for (auto ssrc : vec) { - ssrcs.emplace_back((uint32_t) atoll(ssrc.data())); + ssrcs.emplace_back((uint32_t)atoll(ssrc.data())); } } -string SdpAttrSSRCGroup::toString() const { +string SdpAttrSSRCGroup::toString() const { if (value.empty()) { value = type; - //最少要求2个ssrc + // 最少要求2个ssrc CHECK(ssrcs.size() >= 2); for (auto &ssrc : ssrcs) { value += ' '; @@ -667,13 +665,13 @@ string SdpAttrSSRCGroup::toString() const { return SdpItem::toString(); } -void SdpAttrSctpMap::parse(const string &str) { - char subtypes_buf[64] = {0}; +void SdpAttrSctpMap::parse(const string &str) { + char subtypes_buf[64] = { 0 }; CHECK_SDP(3 == sscanf(str.data(), "%" SCNu16 " %63[^ ] %" SCNd32, &port, subtypes_buf, &streams)); subtypes = subtypes_buf; } -string SdpAttrSctpMap::toString() const { +string SdpAttrSctpMap::toString() const { if (value.empty()) { value = to_string(port); value += ' '; @@ -684,11 +682,11 @@ string SdpAttrSctpMap::toString() const { return SdpItem::toString(); } -void SdpAttrCandidate::parse(const string &str) { - char foundation_buf[40] = {0}; - char transport_buf[16] = {0}; - char address_buf[64] = {0}; - char type_buf[16] = {0}; +void SdpAttrCandidate::parse(const string &str) { + char foundation_buf[40] = { 0 }; + char transport_buf[16] = { 0 }; + char address_buf[64] = { 0 }; + char type_buf[16] = { 0 }; // https://datatracker.ietf.org/doc/html/rfc5245#section-15.1 CHECK_SDP(sscanf(str.data(), "%32[^ ] %" SCNu32 " %15[^ ] %" SCNu32 " %63[^ ] %" SCNu16 " typ %15[^ ]", @@ -715,10 +713,9 @@ void SdpAttrCandidate::parse(const string &str) { } } -string SdpAttrCandidate::toString() const { +string SdpAttrCandidate::toString() const { if (value.empty()) { - value = foundation + " " + to_string(component) + " " + transport + " " + to_string(priority) + - " " + address + " " + to_string(port) + " typ " + type; + value = foundation + " " + to_string(component) + " " + transport + " " + to_string(priority) + " " + address + " " + to_string(port) + " typ " + type; for (auto &pr : arr) { value += ' '; value += pr.first; @@ -730,10 +727,10 @@ string SdpAttrCandidate::toString() const { } void SdpAttrSimulcast::parse(const string &str) { - //https://www.meetecho.com/blog/simulcast-janus-ssrc/ - //a=simulcast:send/recv q;h;f - //a=simulcast:send/recv [rid=]q;h;f - //a=simulcast: recv h;m;l + // https://www.meetecho.com/blog/simulcast-janus-ssrc/ + // a=simulcast:send/recv q;h;f + // a=simulcast:send/recv [rid=]q;h;f + // a=simulcast: recv h;m;l // auto vec = split(str, " "); CHECK_SDP(vec.size() == 2); @@ -845,12 +842,12 @@ void RtcSession::loadFrom(const string &str) { for (auto &group : ssrc_groups) { if (group.isFID()) { have_rtx_ssrc = true; - //ssrc-group:FID字段必须包含rtp/rtx的ssrc + // ssrc-group:FID字段必须包含rtp/rtx的ssrc CHECK(group.ssrcs.size() == 2); - //根据rtp ssrc找到对象 + // 根据rtp ssrc找到对象 auto it = rtc_ssrc_map.find(group.ssrcs[0]); CHECK(it != rtc_ssrc_map.end()); - //设置rtx ssrc + // 设置rtx ssrc it->second.rtx_ssrc = group.ssrcs[1]; rtc_media.rtp_rtx_ssrc.emplace_back(it->second); } else if (group.isSIM()) { @@ -860,7 +857,7 @@ void RtcSession::loadFrom(const string &str) { } if (!have_rtx_ssrc) { - //按照sdp顺序依次添加ssrc + // 按照sdp顺序依次添加ssrc for (auto &attr : ssrc_attr) { if (attr.attribute == "cname") { rtc_media.rtp_rtx_ssrc.emplace_back(rtc_ssrc_map[attr.ssrc]); @@ -883,56 +880,56 @@ void RtcSession::loadFrom(const string &str) { CHECK(rid.direction == simulcast.direction); CHECK(rid_map.find(rid.rid) != rid_map.end()); } - //simulcast最少要求2种方案 + // simulcast最少要求2种方案 CHECK(simulcast.rids.size() >= 2); rtc_media.rtp_rids = simulcast.rids; } if (ssrc_group_sim) { - //指定了a=ssrc-group:SIM + // 指定了a=ssrc-group:SIM for (auto ssrc : ssrc_group_sim->ssrcs) { auto it = rtc_ssrc_map.find(ssrc); CHECK(it != rtc_ssrc_map.end()); rtc_media.rtp_ssrc_sim.emplace_back(it->second); } } else if (!rtc_media.rtp_rids.empty()) { - //未指定a=ssrc-group:SIM, 但是指定了a=simulcast, 那么只能根据ssrc顺序来对应rid顺序 + // 未指定a=ssrc-group:SIM, 但是指定了a=simulcast, 那么只能根据ssrc顺序来对应rid顺序 rtc_media.rtp_ssrc_sim = rtc_media.rtp_rtx_ssrc; } if (!rtc_media.supportSimulcast()) { - //不支持simulcast的情况下,最多一组ssrc + // 不支持simulcast的情况下,最多一组ssrc CHECK(rtc_media.rtp_rtx_ssrc.size() <= 1); } else { - //simulcast的情况下,要么没有指定ssrc,要么指定的ssrc个数与rid个数一致 - //CHECK(rtc_media.rtp_ssrc_sim.empty() || rtc_media.rtp_ssrc_sim.size() == rtc_media.rtp_rids.size()); + // simulcast的情况下,要么没有指定ssrc,要么指定的ssrc个数与rid个数一致 + // CHECK(rtc_media.rtp_ssrc_sim.empty() || rtc_media.rtp_ssrc_sim.size() == rtc_media.rtp_rids.size()); } auto rtpmap_arr = media.getAllItem('a', "rtpmap"); auto rtcpfb_arr = media.getAllItem('a', "rtcp-fb"); auto fmtp_aar = media.getAllItem('a', "fmtp"); - //方便根据pt查找rtpmap,一个pt必有一条 + // 方便根据pt查找rtpmap,一个pt必有一条 map rtpmap_map; - //方便根据pt查找rtcp-fb,一个pt可能有多条或0条 + // 方便根据pt查找rtcp-fb,一个pt可能有多条或0条 multimap rtcpfb_map; - //方便根据pt查找fmtp,一个pt最多一条 + // 方便根据pt查找fmtp,一个pt最多一条 map fmtp_map; for (auto &rtpmap : rtpmap_arr) { - //添加失败,有多条 + // 添加失败,有多条 CHECK(rtpmap_map.emplace(rtpmap.pt, rtpmap).second, "该pt存在多条a=rtpmap:", (int)rtpmap.pt); } for (auto &rtpfb : rtcpfb_arr) { rtcpfb_map.emplace(rtpfb.pt, rtpfb); } for (auto &fmtp : fmtp_aar) { - //添加失败,有多条 + // 添加失败,有多条 CHECK(fmtp_map.emplace(fmtp.pt, fmtp).second, "该pt存在多条a=fmtp:", (int)fmtp.pt); } for (auto &item : mline.fmts) { auto pt = atoi(item.c_str()); CHECK(pt < 0xFF, "invalid payload type: ", item); - //遍历所有编码方案的pt + // 遍历所有编码方案的pt rtc_media.plan.emplace_back(); auto &plan = rtc_media.plan.back(); auto rtpmap_it = rtpmap_map.find(pt); @@ -952,8 +949,7 @@ void RtcSession::loadFrom(const string &str) { if (fmtp_it != fmtp_map.end()) { plan.fmtp = fmtp_it->second.fmtp; } - for (auto rtpfb_it = rtcpfb_map.find(pt); - rtpfb_it != rtcpfb_map.end() && rtpfb_it->second.pt == pt; ++rtpfb_it) { + for (auto rtpfb_it = rtcpfb_map.find(pt); rtpfb_it != rtcpfb_map.end() && rtpfb_it->second.pt == pt; ++rtpfb_it) { plan.rtcp_fb.emplace(rtpfb_it->second.rtcp_type); } } @@ -971,7 +967,7 @@ void RtcSdpBase::toRtsp() { case 'i': case 't': case 'c': - case 'b':{ + case 'b': { ++it; break; } @@ -986,8 +982,7 @@ void RtcSdpBase::toRtsp() { case 'a': { auto attr = dynamic_pointer_cast(*it); CHECK(attr); - if (!strcasecmp(attr->detail->getKey(), "rtpmap") - || !strcasecmp(attr->detail->getKey(), "fmtp")) { + if (!strcasecmp(attr->detail->getKey(), "rtpmap") || !strcasecmp(attr->detail->getKey(), "fmtp")) { ++it; break; } @@ -1000,7 +995,7 @@ void RtcSdpBase::toRtsp() { } } -string RtcSession::toRtspSdp() const{ +string RtcSession::toRtspSdp() const { RtcSession copy = *this; copy.media.clear(); for (auto &m : media) { @@ -1056,17 +1051,17 @@ void addSdpAttrSSRC(const RtcSSRC &rtp_ssrc, RtcSdpBase &media, uint32_t ssrc_nu } } -RtcSessionSdp::Ptr RtcSession::toRtcSessionSdp() const{ +RtcSessionSdp::Ptr RtcSession::toRtcSessionSdp() const { RtcSessionSdp::Ptr ret = std::make_shared(); auto &sdp = *ret; - sdp.addItem(std::make_shared >(to_string(version))); + sdp.addItem(std::make_shared>(to_string(version))); sdp.addItem(std::make_shared(origin)); - sdp.addItem(std::make_shared >(session_name)); + sdp.addItem(std::make_shared>(session_name)); if (!session_info.empty()) { - sdp.addItem(std::make_shared >(session_info)); + sdp.addItem(std::make_shared>(session_info)); } sdp.addItem(std::make_shared(time)); - if(connection.empty()){ + if (connection.empty()) { sdp.addItem(std::make_shared(connection)); } sdp.addAttr(std::make_shared(group)); @@ -1124,21 +1119,21 @@ RtcSessionSdp::Ptr RtcSession::toRtcSessionSdp() const{ sdp_media.addAttr(std::make_shared("rtcp-rsize")); } - if(m.type != TrackApplication) { + if (m.type != TrackApplication) { for (auto &p : m.plan) { auto rtp_map = std::make_shared(); rtp_map->pt = p.pt; rtp_map->codec = p.codec; rtp_map->sample_rate = p.sample_rate; rtp_map->channel = p.channel; - //添加a=rtpmap + // 添加a=rtpmap sdp_media.addAttr(std::move(rtp_map)); - for (auto &fb : p.rtcp_fb) { + for (auto &fb : p.rtcp_fb) { auto rtcp_fb = std::make_shared(); rtcp_fb->pt = p.pt; rtcp_fb->rtcp_type = fb; - //添加a=rtcp-fb + // 添加a=rtcp-fb sdp_media.addAttr(std::move(rtcp_fb)); } @@ -1146,13 +1141,13 @@ RtcSessionSdp::Ptr RtcSession::toRtcSessionSdp() const{ auto fmtp = std::make_shared(); fmtp->pt = p.pt; fmtp->fmtp = p.fmtp; - //添加a=fmtp + // 添加a=fmtp sdp_media.addAttr(std::move(fmtp)); } } { - //添加a=msid字段 + // 添加a=msid字段 if (!m.rtp_rtx_ssrc.empty()) { if (!m.rtp_rtx_ssrc[0].msid.empty()) { auto msid = std::make_shared(); @@ -1164,14 +1159,14 @@ RtcSessionSdp::Ptr RtcSession::toRtcSessionSdp() const{ { for (auto &ssrc : m.rtp_rtx_ssrc) { - //添加a=ssrc字段 + // 添加a=ssrc字段 CHECK(!ssrc.empty()); addSdpAttrSSRC(ssrc, sdp_media, ssrc.ssrc); if (ssrc.rtx_ssrc) { addSdpAttrSSRC(ssrc, sdp_media, ssrc.rtx_ssrc); - //生成a=ssrc-group:FID字段 - //有rtx ssrc + // 生成a=ssrc-group:FID字段 + // 有rtx ssrc auto group = std::make_shared(); group->type = "FID"; group->ssrcs.emplace_back(ssrc.ssrc); @@ -1183,12 +1178,12 @@ RtcSessionSdp::Ptr RtcSession::toRtcSessionSdp() const{ { if (m.rtp_ssrc_sim.size() >= 2) { - //simulcast 要求 2~3路 + // simulcast 要求 2~3路 auto group = std::make_shared(); for (auto &ssrc : m.rtp_ssrc_sim) { group->ssrcs.emplace_back(ssrc.ssrc); } - //添加a=ssrc-group:SIM字段 + // 添加a=ssrc-group:SIM字段 group->type = "SIM"; sdp_media.addAttr(std::move(group)); } @@ -1221,17 +1216,17 @@ RtcSessionSdp::Ptr RtcSession::toRtcSessionSdp() const{ } } } - if(ice_lite) + if (ice_lite) { sdp.addAttr(std::make_shared("ice-lite")); - + } return ret; } -string RtcSession::toString() const{ +string RtcSession::toString() const { return toRtcSessionSdp()->toString(); } -string RtcCodecPlan::getFmtp(const char *key) const{ +string RtcCodecPlan::getFmtp(const char *key) const { for (auto &item : fmtp) { if (strcasecmp(item.first.data(), key) == 0) { return item.second; @@ -1240,7 +1235,7 @@ string RtcCodecPlan::getFmtp(const char *key) const{ return ""; } -const RtcCodecPlan *RtcMedia::getPlan(uint8_t pt) const{ +const RtcCodecPlan *RtcMedia::getPlan(uint8_t pt) const { for (auto &item : plan) { if (item.pt == pt) { return &item; @@ -1249,7 +1244,7 @@ const RtcCodecPlan *RtcMedia::getPlan(uint8_t pt) const{ return nullptr; } -const RtcCodecPlan *RtcMedia::getPlan(const char *codec) const{ +const RtcCodecPlan *RtcMedia::getPlan(const char *codec) const { for (auto &item : plan) { if (strcasecmp(item.codec.data(), codec) == 0) { return &item; @@ -1258,7 +1253,7 @@ const RtcCodecPlan *RtcMedia::getPlan(const char *codec) const{ return nullptr; } -const RtcCodecPlan *RtcMedia::getRelatedRtxPlan(uint8_t pt) const{ +const RtcCodecPlan *RtcMedia::getRelatedRtxPlan(uint8_t pt) const { for (auto &item : plan) { if (strcasecmp(item.codec.data(), "rtx") == 0) { auto apt = atoi(item.getFmtp("apt").data()); @@ -1294,7 +1289,7 @@ bool RtcMedia::supportSimulcast() const { return false; } -void RtcMedia::checkValid() const{ +void RtcMedia::checkValid() const { CHECK(type != TrackInvalid); CHECK(!mid.empty()); CHECK(!proto.empty()); @@ -1304,7 +1299,7 @@ void RtcMedia::checkValid() const{ bool send_rtp = (direction == RtpDirection::sendonly || direction == RtpDirection::sendrecv); if (!supportSimulcast()) { - //非simulcast时,检查有没有指定rtp ssrc + // 非simulcast时,检查有没有指定rtp ssrc CHECK(!rtp_rtx_ssrc.empty() || !send_rtp); } @@ -1318,7 +1313,7 @@ void RtcMedia::checkValid() const{ #endif } -void RtcSession::checkValid() const{ +void RtcSession::checkValid() const { CHECK(version == 0); CHECK(!origin.empty()); CHECK(!session_name.empty()); @@ -1337,15 +1332,15 @@ void RtcSession::checkValid() const{ case RtpDirection::sendrecv: case RtpDirection::sendonly: case RtpDirection::recvonly: have_active_media = true; break; - default : break; + default: break; } } CHECK(have_active_media, "必须确保最少有一个活跃的track"); } -const RtcMedia *RtcSession::getMedia(TrackType type) const{ - for(auto &m : media){ - if(m.type == type){ +const RtcMedia *RtcSession::getMedia(TrackType type) const { + for (auto &m : media) { + if (m.type == type) { return &m; } } @@ -1377,7 +1372,7 @@ bool RtcSession::isOnlyDatachannel() const { string const SdpConst::kTWCCRtcpFb = "transport-cc"; string const SdpConst::kRembRtcpFb = "goog-remb"; -void RtcConfigure::RtcTrackConfigure::enableTWCC(bool enable){ +void RtcConfigure::RtcTrackConfigure::enableTWCC(bool enable) { if (!enable) { rtcp_fb.erase(SdpConst::kTWCCRtcpFb); extmap.erase(RtpExtType::transport_cc); @@ -1387,7 +1382,7 @@ void RtcConfigure::RtcTrackConfigure::enableTWCC(bool enable){ } } -void RtcConfigure::RtcTrackConfigure::enableREMB(bool enable){ +void RtcConfigure::RtcTrackConfigure::enableREMB(bool enable) { if (!enable) { rtcp_fb.erase(SdpConst::kRembRtcpFb); extmap.erase(RtpExtType::abs_send_time); @@ -1397,7 +1392,7 @@ void RtcConfigure::RtcTrackConfigure::enableREMB(bool enable){ } } -static vector toCodecArray(const string &str){ +static vector toCodecArray(const string &str) { vector ret; auto vec = split(str, ","); for (auto &s : vec) { @@ -1409,7 +1404,7 @@ static vector toCodecArray(const string &str){ return ret; } -void RtcConfigure::RtcTrackConfigure::setDefaultSetting(TrackType type){ +void RtcConfigure::RtcTrackConfigure::setDefaultSetting(TrackType type) { rtcp_mux = true; rtcp_rsize = false; group_bundle = true; @@ -1421,47 +1416,43 @@ void RtcConfigure::RtcTrackConfigure::setDefaultSetting(TrackType type){ ice_renomination = false; switch (type) { case TrackAudio: { - //此处调整偏好的编码格式优先级 + // 此处调整偏好的编码格式优先级 GET_CONFIG_FUNC(vector, s_preferred_codec, Rtc::kPreferredCodecA, toCodecArray); CHECK(!s_preferred_codec.empty(), "rtc音频偏好codec不能为空"); preferred_codec = s_preferred_codec; - rtcp_fb = {SdpConst::kTWCCRtcpFb, SdpConst::kRembRtcpFb}; - extmap = { - {RtpExtType::ssrc_audio_level, RtpDirection::sendrecv}, - {RtpExtType::csrc_audio_level, RtpDirection::sendrecv}, - {RtpExtType::abs_send_time, RtpDirection::sendrecv}, - {RtpExtType::transport_cc, RtpDirection::sendrecv}, - //rtx重传rtp时,忽略sdes_mid类型的rtp ext,实测发现Firefox在接收rtx时,如果存在sdes_mid的ext,将导致无法播放 - //{RtpExtType::sdes_mid,RtpDirection::sendrecv}, - {RtpExtType::sdes_rtp_stream_id, RtpDirection::sendrecv}, - {RtpExtType::sdes_repaired_rtp_stream_id, RtpDirection::sendrecv} - }; + rtcp_fb = { SdpConst::kTWCCRtcpFb, SdpConst::kRembRtcpFb }; + extmap = { { RtpExtType::ssrc_audio_level, RtpDirection::sendrecv }, + { RtpExtType::csrc_audio_level, RtpDirection::sendrecv }, + { RtpExtType::abs_send_time, RtpDirection::sendrecv }, + { RtpExtType::transport_cc, RtpDirection::sendrecv }, + // rtx重传rtp时,忽略sdes_mid类型的rtp ext,实测发现Firefox在接收rtx时,如果存在sdes_mid的ext,将导致无法播放 + //{RtpExtType::sdes_mid,RtpDirection::sendrecv}, + { RtpExtType::sdes_rtp_stream_id, RtpDirection::sendrecv }, + { RtpExtType::sdes_repaired_rtp_stream_id, RtpDirection::sendrecv } }; break; } case TrackVideo: { - //此处调整偏好的编码格式优先级 + // 此处调整偏好的编码格式优先级 GET_CONFIG_FUNC(vector, s_preferred_codec, Rtc::kPreferredCodecV, toCodecArray); CHECK(!s_preferred_codec.empty(), "rtc视频偏好codec不能为空"); preferred_codec = s_preferred_codec; - rtcp_fb = {SdpConst::kTWCCRtcpFb, SdpConst::kRembRtcpFb, "nack", "ccm fir", "nack pli"}; - extmap = { - {RtpExtType::abs_send_time, RtpDirection::sendrecv}, - {RtpExtType::transport_cc, RtpDirection::sendrecv}, - //rtx重传rtp时,忽略sdes_mid类型的rtp ext,实测发现Firefox在接收rtx时,如果存在sdes_mid的ext,将导致无法播放 - //{RtpExtType::sdes_mid,RtpDirection::sendrecv}, - {RtpExtType::sdes_rtp_stream_id, RtpDirection::sendrecv}, - {RtpExtType::sdes_repaired_rtp_stream_id, RtpDirection::sendrecv}, - {RtpExtType::video_timing, RtpDirection::sendrecv}, - {RtpExtType::color_space, RtpDirection::sendrecv}, - {RtpExtType::video_content_type, RtpDirection::sendrecv}, - {RtpExtType::playout_delay, RtpDirection::sendrecv}, - //手机端推webrtc 会带有旋转角度,rtc协议能正常播放 其他协议拉流画面旋转 - //{RtpExtType::video_orientation, RtpDirection::sendrecv}, - {RtpExtType::toffset, RtpDirection::sendrecv}, - {RtpExtType::framemarking, RtpDirection::sendrecv} - }; + rtcp_fb = { SdpConst::kTWCCRtcpFb, SdpConst::kRembRtcpFb, "nack", "ccm fir", "nack pli" }; + extmap = { { RtpExtType::abs_send_time, RtpDirection::sendrecv }, + { RtpExtType::transport_cc, RtpDirection::sendrecv }, + // rtx重传rtp时,忽略sdes_mid类型的rtp ext,实测发现Firefox在接收rtx时,如果存在sdes_mid的ext,将导致无法播放 + //{RtpExtType::sdes_mid,RtpDirection::sendrecv}, + { RtpExtType::sdes_rtp_stream_id, RtpDirection::sendrecv }, + { RtpExtType::sdes_repaired_rtp_stream_id, RtpDirection::sendrecv }, + { RtpExtType::video_timing, RtpDirection::sendrecv }, + { RtpExtType::color_space, RtpDirection::sendrecv }, + { RtpExtType::video_content_type, RtpDirection::sendrecv }, + { RtpExtType::playout_delay, RtpDirection::sendrecv }, + // 手机端推webrtc 会带有旋转角度,rtc协议能正常播放 其他协议拉流画面旋转 + //{RtpExtType::video_orientation, RtpDirection::sendrecv}, + { RtpExtType::toffset, RtpDirection::sendrecv }, + { RtpExtType::framemarking, RtpDirection::sendrecv } }; break; } case TrackApplication: { @@ -1471,8 +1462,7 @@ void RtcConfigure::RtcTrackConfigure::setDefaultSetting(TrackType type){ } } -void RtcConfigure::setDefaultSetting(string ice_ufrag, string ice_pwd, RtpDirection direction, - const SdpAttrFingerprint &fingerprint) { +void RtcConfigure::setDefaultSetting(string ice_ufrag, string ice_pwd, RtpDirection direction, const SdpAttrFingerprint &fingerprint) { video.setDefaultSetting(TrackVideo); audio.setDefaultSetting(TrackAudio); application.setDefaultSetting(TrackApplication); @@ -1512,7 +1502,7 @@ void RtcConfigure::addCandidate(const SdpAttrCandidate &candidate, TrackType typ } } -void RtcConfigure::enableTWCC(bool enable, TrackType type){ +void RtcConfigure::enableTWCC(bool enable, TrackType type) { switch (type) { case TrackAudio: { audio.enableTWCC(enable); @@ -1530,7 +1520,7 @@ void RtcConfigure::enableTWCC(bool enable, TrackType type){ } } -void RtcConfigure::enableREMB(bool enable, TrackType type){ +void RtcConfigure::enableREMB(bool enable, TrackType type) { switch (type) { case TrackAudio: { audio.enableREMB(enable); @@ -1559,10 +1549,10 @@ shared_ptr RtcConfigure::createAnswer(const RtcSession &offer) const matchMedia(ret, m); } - //设置音视频端口复用 + // 设置音视频端口复用 if (!offer.group.mids.empty()) { for (auto &m : ret->media) { - //The remote end has rejected (port 0) the m-section, so it should not be putting its mid in the group attribute. + // The remote end has rejected (port 0) the m-section, so it should not be putting its mid in the group attribute. if (m.port) { ret->group.mids.emplace_back(m.mid); } @@ -1571,32 +1561,32 @@ shared_ptr RtcConfigure::createAnswer(const RtcSession &offer) const return ret; } -static RtpDirection matchDirection(RtpDirection offer_direction, RtpDirection supported){ +static RtpDirection matchDirection(RtpDirection offer_direction, RtpDirection supported) { switch (offer_direction) { - case RtpDirection::sendonly : { + case RtpDirection::sendonly: { if (supported != RtpDirection::recvonly && supported != RtpDirection::sendrecv) { - //我们不支持接收 + // 我们不支持接收 return RtpDirection::inactive; } return RtpDirection::recvonly; } - case RtpDirection::recvonly : { + case RtpDirection::recvonly: { if (supported != RtpDirection::sendonly && supported != RtpDirection::sendrecv) { - //我们不支持发送 + // 我们不支持发送 return RtpDirection::inactive; } return RtpDirection::sendonly; } - //对方支持发送接收,那么最终能力根据配置来决定 - case RtpDirection::sendrecv : return (supported == RtpDirection::invalid ? RtpDirection::inactive : supported); - case RtpDirection::inactive : return RtpDirection::inactive; + // 对方支持发送接收,那么最终能力根据配置来决定 + case RtpDirection::sendrecv: return (supported == RtpDirection::invalid ? RtpDirection::inactive : supported); + case RtpDirection::inactive: return RtpDirection::inactive; default: return RtpDirection::invalid; } } -static DtlsRole mathDtlsRole(DtlsRole role){ +static DtlsRole mathDtlsRole(DtlsRole role) { switch (role) { case DtlsRole::actpass: case DtlsRole::active: return DtlsRole::passive; @@ -1605,7 +1595,7 @@ static DtlsRole mathDtlsRole(DtlsRole role){ } } -void RtcConfigure::matchMedia(const std::shared_ptr &ret,const RtcMedia &offer_media) const { +void RtcConfigure::matchMedia(const std::shared_ptr &ret, const RtcMedia &offer_media) const { bool check_profile = true; bool check_codec = true; const RtcTrackConfigure *cfg_ptr = nullptr; @@ -1643,20 +1633,20 @@ RETRY: } const RtcCodecPlan *selected_plan = nullptr; for (auto &plan : offer_media.plan) { - //先检查编码格式是否为偏好 + // 先检查编码格式是否为偏好 if (check_codec && getCodecId(plan.codec) != codec) { continue; } - //命中偏好的编码格式,然后检查规格 + // 命中偏好的编码格式,然后检查规格 if (check_profile && !onCheckCodecProfile(plan, codec)) { continue; } - //找到中意的codec + // 找到中意的codec selected_plan = &plan; break; } if (!selected_plan) { - //offer中该媒体的所有的codec都不支持 + // offer中该媒体的所有的codec都不支持 continue; } RtcMedia answer_media; @@ -1682,24 +1672,23 @@ RETRY: answer_media.role = mathDtlsRole(offer_media.role); - //如果codec匹配失败,那么禁用该track - answer_media.direction = check_codec ? matchDirection(offer_media.direction, configure.direction) - : RtpDirection::inactive; + // 如果codec匹配失败,那么禁用该track + answer_media.direction = check_codec ? matchDirection(offer_media.direction, configure.direction) : RtpDirection::inactive; if (answer_media.direction == RtpDirection::invalid) { continue; } if (answer_media.direction == RtpDirection::sendrecv) { - //如果是收发双向,那么我们拷贝offer sdp的ssrc,确保ssrc一致 + // 如果是收发双向,那么我们拷贝offer sdp的ssrc,确保ssrc一致 answer_media.rtp_rtx_ssrc = offer_media.rtp_rtx_ssrc; } - //添加媒体plan + // 添加媒体plan answer_media.plan.emplace_back(*selected_plan); onSelectPlan(answer_media.plan.back(), codec); - set pt_selected = {selected_plan->pt}; + set pt_selected = { selected_plan->pt }; - //添加rtx,red,ulpfec plan + // 添加rtx,red,ulpfec plan if (configure.support_red || configure.support_rtx || configure.support_ulpfec) { for (auto &plan : offer_media.plan) { if (!strcasecmp(plan.codec.data(), "rtx")) { @@ -1726,7 +1715,7 @@ RETRY: } } - //对方和我方都支持的扩展,那么我们才支持 + // 对方和我方都支持的扩展,那么我们才支持 for (auto &ext : offer_media.extmap) { auto it = configure.extmap.find(RtpExt::getExtType(ext.ext)); if (it != configure.extmap.end()) { @@ -1743,10 +1732,10 @@ RETRY: auto &rtcp_fb_ref = answer_media.plan[0].rtcp_fb; rtcp_fb_ref.clear(); - //对方和我方都支持的rtcpfb,那么我们才支持 + // 对方和我方都支持的rtcpfb,那么我们才支持 for (auto &fp : selected_plan->rtcp_fb) { if (configure.rtcp_fb.find(fp) != configure.rtcp_fb.end()) { - //对方该rtcp被我们支持 + // 对方该rtcp被我们支持 rtcp_fb_ref.emplace(fp); } } @@ -1764,19 +1753,19 @@ RETRY: } if (check_profile) { - //如果是由于检查profile导致匹配失败,那么重试一次,且不检查profile + // 如果是由于检查profile导致匹配失败,那么重试一次,且不检查profile check_profile = false; goto RETRY; } if (check_codec) { - //如果是由于检查codec导致匹配失败,那么重试一次,且不检查codec + // 如果是由于检查codec导致匹配失败,那么重试一次,且不检查codec check_codec = false; goto RETRY; } } -void RtcConfigure::setPlayRtspInfo(const string &sdp){ +void RtcConfigure::setPlayRtspInfo(const string &sdp) { RtcSession session; video.direction = RtpDirection::inactive; audio.direction = RtpDirection::inactive; @@ -1784,15 +1773,15 @@ void RtcConfigure::setPlayRtspInfo(const string &sdp){ session.loadFrom(sdp); for (auto &m : session.media) { switch (m.type) { - case TrackVideo : { + case TrackVideo: { video.direction = RtpDirection::sendonly; _rtsp_video_plan = std::make_shared(m.plan[0]); video.preferred_codec.clear(); video.preferred_codec.emplace_back(getCodecId(_rtsp_video_plan->codec)); break; } - case TrackAudio : { - audio.direction = RtpDirection::sendonly; + case TrackAudio: { + audio.direction = RtpDirection::sendonly; _rtsp_audio_plan = std::make_shared(m.plan[0]); audio.preferred_codec.clear(); audio.preferred_codec.emplace_back(getCodecId(_rtsp_audio_plan->codec)); @@ -1803,21 +1792,21 @@ void RtcConfigure::setPlayRtspInfo(const string &sdp){ } } -static const string kProfile{"profile-level-id"}; -static const string kMode{"packetization-mode"}; +static const string kProfile { "profile-level-id" }; +static const string kMode { "packetization-mode" }; bool RtcConfigure::onCheckCodecProfile(const RtcCodecPlan &plan, CodecId codec) const { if (_rtsp_audio_plan && codec == getCodecId(_rtsp_audio_plan->codec)) { if (plan.sample_rate != _rtsp_audio_plan->sample_rate || plan.channel != _rtsp_audio_plan->channel) { - //音频采样率和通道数必须相同 + // 音频采样率和通道数必须相同 return false; } return true; } if (_rtsp_video_plan && codec == CodecH264 && getCodecId(_rtsp_video_plan->codec) == CodecH264) { - //h264时,profile-level-id + // h264时,profile-level-id if (strcasecmp(_rtsp_video_plan->fmtp[kProfile].data(), const_cast(plan).fmtp[kProfile].data())) { - //profile-level-id 不匹配 + // profile-level-id 不匹配 return false; } return true; diff --git a/webrtc/Sdp.h b/webrtc/Sdp.h index cec182a8..25436a9f 100644 --- a/webrtc/Sdp.h +++ b/webrtc/Sdp.h @@ -22,97 +22,87 @@ namespace mediakit { -//https://datatracker.ietf.org/doc/rfc4566/?include_text=1 -//https://blog.csdn.net/aggresss/article/details/109850434 -//https://aggresss.blog.csdn.net/article/details/106436703 -//Session description -// v= (protocol version) -// o= (originator and session identifier) -// s= (session name) -// i=* (session information) -// u=* (URI of description) -// e=* (email address) -// p=* (phone number) -// c=* (connection information -- not required if included in -// all media) -// b=* (zero or more bandwidth information lines) -// One or more time descriptions ("t=" and "r=" lines; see below) -// z=* (time zone adjustments) -// k=* (encryption key) -// a=* (zero or more session attribute lines) -// Zero or more media descriptions +// https://datatracker.ietf.org/doc/rfc4566/?include_text=1 +// https://blog.csdn.net/aggresss/article/details/109850434 +// https://aggresss.blog.csdn.net/article/details/106436703 +// Session description +// v= (protocol version) +// o= (originator and session identifier) +// s= (session name) +// i=* (session information) +// u=* (URI of description) +// e=* (email address) +// p=* (phone number) +// c=* (connection information -- not required if included in +// all media) +// b=* (zero or more bandwidth information lines) +// One or more time descriptions ("t=" and "r=" lines; see below) +// z=* (time zone adjustments) +// k=* (encryption key) +// a=* (zero or more session attribute lines) +// Zero or more media descriptions // -// Time description -// t= (time the session is active) -// r=* (zero or more repeat times) +// Time description +// t= (time the session is active) +// r=* (zero or more repeat times) // -// Media description, if present -// m= (media name and transport address) -// i=* (media title) -// c=* (connection information -- optional if included at -// session level) -// b=* (zero or more bandwidth information lines) -// k=* (encryption key) -// a=* (zero or more media attribute lines) +// Media description, if present +// m= (media name and transport address) +// i=* (media title) +// c=* (connection information -- optional if included at +// session level) +// b=* (zero or more bandwidth information lines) +// k=* (encryption key) +// a=* (zero or more media attribute lines) enum class RtpDirection { invalid = -1, - //只发送 + // 只发送 sendonly, - //只接收 + // 只接收 recvonly, - //同时发送接收 + // 同时发送接收 sendrecv, - //禁止发送数据 + // 禁止发送数据 inactive }; enum class DtlsRole { invalid = -1, - //客户端 + // 客户端 active, - //服务端 + // 服务端 passive, - //既可作做客户端也可以做服务端 + // 既可作做客户端也可以做服务端 actpass, }; -enum class SdpType { - invalid = -1, - offer, - answer -}; +enum class SdpType { invalid = -1, offer, answer }; DtlsRole getDtlsRole(const std::string &str); -const char* getDtlsRoleString(DtlsRole role); +const char *getDtlsRoleString(DtlsRole role); RtpDirection getRtpDirection(const std::string &str); -const char* getRtpDirectionString(RtpDirection val); +const char *getRtpDirectionString(RtpDirection val); class SdpItem { public: using Ptr = std::shared_ptr; virtual ~SdpItem() = default; - virtual void parse(const std::string &str) { - value = str; - } - virtual std::string toString() const { - return value; - } - virtual const char* getKey() const = 0; + virtual void parse(const std::string &str) { value = str; } + virtual std::string toString() const { return value; } + virtual const char *getKey() const = 0; - void reset() { - value.clear(); - } + void reset() { value.clear(); } protected: mutable std::string value; }; template -class SdpString : public SdpItem{ +class SdpString : public SdpItem { public: SdpString() = default; - SdpString(std::string val) {value = std::move(val);} + SdpString(std::string val) { value = std::move(val); } // *=* const char* getKey() const override { static std::string key(1, KEY); return key.data();} }; @@ -126,34 +116,34 @@ public: this->value = std::move(val); } - const char* getKey() const override { return key.data();} + const char *getKey() const override { return key.data(); } }; -class SdpTime : public SdpItem{ +class SdpTime : public SdpItem { public: - //5.9. Timing ("t=") - // t= - uint64_t start {0}; - uint64_t stop {0}; + // 5.9. Timing ("t=") + // t= + uint64_t start { 0 }; + uint64_t stop { 0 }; void parse(const std::string &str) override; std::string toString() const override; - const char* getKey() const override { return "t";} + const char *getKey() const override { return "t"; } }; -class SdpOrigin : public SdpItem{ +class SdpOrigin : public SdpItem { public: // 5.2. Origin ("o=") // o=jdoe 2890844526 2890842807 IN IP4 10.47.16.5 // o= - std::string username {"-"}; + std::string username { "-" }; std::string session_id; std::string session_version; - std::string nettype {"IN"}; - std::string addrtype {"IP4"}; - std::string address {"0.0.0.0"}; + std::string nettype { "IN" }; + std::string addrtype { "IP4" }; + std::string address { "0.0.0.0" }; void parse(const std::string &str) override; std::string toString() const override; - const char* getKey() const override { return "o";} + const char *getKey() const override { return "o"; } bool empty() const { return username.empty() || session_id.empty() || session_version.empty() || nettype.empty() || addrtype.empty() || address.empty(); @@ -165,28 +155,28 @@ public: // 5.7. Connection Data ("c=") // c=IN IP4 224.2.17.12/127 // c= - std::string nettype {"IN"}; - std::string addrtype {"IP4"}; - std::string address {"0.0.0.0"}; + std::string nettype { "IN" }; + std::string addrtype { "IP4" }; + std::string address { "0.0.0.0" }; void parse(const std::string &str) override; std::string toString() const override; - const char* getKey() const override { return "c";} - bool empty() const {return address.empty();} + const char *getKey() const override { return "c"; } + bool empty() const { return address.empty(); } }; class SdpBandwidth : public SdpItem { public: - //5.8. Bandwidth ("b=") - //b=: + // 5.8. Bandwidth ("b=") + // b=: - //AS、CT - std::string bwtype {"AS"}; - uint32_t bandwidth {0}; + // AS、CT + std::string bwtype { "AS" }; + uint32_t bandwidth { 0 }; void parse(const std::string &str) override; std::string toString() const override; - const char* getKey() const override { return "b";} - bool empty() const {return bandwidth == 0;} + const char *getKey() const override { return "b"; } + bool empty() const { return bandwidth == 0; } }; class SdpMedia : public SdpItem { @@ -195,287 +185,284 @@ public: // m= ... TrackType type; uint16_t port; - //RTP/AVP:应用场景为视频/音频的 RTP 协议。参考 RFC 3551 - //RTP/SAVP:应用场景为视频/音频的 SRTP 协议。参考 RFC 3711 - //RTP/AVPF: 应用场景为视频/音频的 RTP 协议,支持 RTCP-based Feedback。参考 RFC 4585 - //RTP/SAVPF: 应用场景为视频/音频的 SRTP 协议,支持 RTCP-based Feedback。参考 RFC 5124 + // RTP/AVP:应用场景为视频/音频的 RTP 协议。参考 RFC 3551 + // RTP/SAVP:应用场景为视频/音频的 SRTP 协议。参考 RFC 3711 + // RTP/AVPF: 应用场景为视频/音频的 RTP 协议,支持 RTCP-based Feedback。参考 RFC 4585 + // RTP/SAVPF: 应用场景为视频/音频的 SRTP 协议,支持 RTCP-based Feedback。参考 RFC 5124 std::string proto; std::vector fmts; void parse(const std::string &str) override; std::string toString() const override; - const char* getKey() const override { return "m";} + const char *getKey() const override { return "m"; } }; -class SdpAttr : public SdpItem{ +class SdpAttr : public SdpItem { public: using Ptr = std::shared_ptr; - //5.13. Attributes ("a=") - //a= - //a=: + // 5.13. Attributes ("a=") + // a= + // a=: SdpItem::Ptr detail; void parse(const std::string &str) override; std::string toString() const override; - const char* getKey() const override { return "a";} + const char *getKey() const override { return "a"; } }; -class SdpAttrGroup : public SdpItem{ +class SdpAttrGroup : public SdpItem { public: - //a=group:BUNDLE line with all the 'mid' identifiers part of the - // BUNDLE group is included at the session-level. - //a=group:LS session level attribute MUST be included wth the 'mid' - // identifiers that are part of the same lip sync group. - std::string type {"BUNDLE"}; + // a=group:BUNDLE line with all the 'mid' identifiers part of the + // BUNDLE group is included at the session-level. + // a=group:LS session level attribute MUST be included wth the 'mid' + // identifiers that are part of the same lip sync group. + std::string type { "BUNDLE" }; std::vector mids; - void parse(const std::string &str) override ; - std::string toString() const override ; - const char* getKey() const override { return "group";} + void parse(const std::string &str) override; + std::string toString() const override; + const char *getKey() const override { return "group"; } }; class SdpAttrMsidSemantic : public SdpItem { public: - //https://tools.ietf.org/html/draft-alvestrand-rtcweb-msid-02#section-3 - //3. The Msid-Semantic Attribute + // https://tools.ietf.org/html/draft-alvestrand-rtcweb-msid-02#section-3 + // 3. The Msid-Semantic Attribute // - // In order to fully reproduce the semantics of the SDP and SSRC - // grouping frameworks, a session-level attribute is defined for - // signalling the semantics associated with an msid grouping. + // In order to fully reproduce the semantics of the SDP and SSRC + // grouping frameworks, a session-level attribute is defined for + // signalling the semantics associated with an msid grouping. // - // This OPTIONAL attribute gives the message ID and its group semantic. - // a=msid-semantic: examplefoo LS + // This OPTIONAL attribute gives the message ID and its group semantic. + // a=msid-semantic: examplefoo LS // // - // The ABNF of msid-semantic is: + // The ABNF of msid-semantic is: // - // msid-semantic-attr = "msid-semantic:" " " msid token - // token = + // msid-semantic-attr = "msid-semantic:" " " msid token + // token = // - // The semantic field may hold values from the IANA registries - // "Semantics for the "ssrc-group" SDP Attribute" and "Semantics for the - // "group" SDP Attribute". - //a=msid-semantic: WMS 616cfbb1-33a3-4d8c-8275-a199d6005549 - std::string msid{"WMS"}; + // The semantic field may hold values from the IANA registries + // "Semantics for the "ssrc-group" SDP Attribute" and "Semantics for the + // "group" SDP Attribute". + // a=msid-semantic: WMS 616cfbb1-33a3-4d8c-8275-a199d6005549 + std::string msid { "WMS" }; std::string token; void parse(const std::string &str) override; std::string toString() const override; - const char* getKey() const override { return "msid-semantic";} - bool empty() const { - return msid.empty(); - } + const char *getKey() const override { return "msid-semantic"; } + bool empty() const { return msid.empty(); } }; class SdpAttrRtcp : public SdpItem { public: // a=rtcp:9 IN IP4 0.0.0.0 - uint16_t port{0}; - std::string nettype {"IN"}; - std::string addrtype {"IP4"}; - std::string address {"0.0.0.0"}; - void parse(const std::string &str) override;; + uint16_t port { 0 }; + std::string nettype { "IN" }; + std::string addrtype { "IP4" }; + std::string address { "0.0.0.0" }; + void parse(const std::string &str) override; + ; std::string toString() const override; - const char* getKey() const override { return "rtcp";} - bool empty() const { - return address.empty() || !port; - } + const char *getKey() const override { return "rtcp"; } + bool empty() const { return address.empty() || !port; } }; class SdpAttrIceUfrag : public SdpItem { public: SdpAttrIceUfrag() = default; - SdpAttrIceUfrag(std::string str) {value = std::move(str);} - //a=ice-ufrag:sXJ3 - const char* getKey() const override { return "ice-ufrag";} + SdpAttrIceUfrag(std::string str) { value = std::move(str); } + // a=ice-ufrag:sXJ3 + const char *getKey() const override { return "ice-ufrag"; } }; class SdpAttrIcePwd : public SdpItem { public: SdpAttrIcePwd() = default; - SdpAttrIcePwd(std::string str) {value = std::move(str);} - //a=ice-pwd:yEclOTrLg1gEubBFefOqtmyV - const char* getKey() const override { return "ice-pwd";} + SdpAttrIcePwd(std::string str) { value = std::move(str); } + // a=ice-pwd:yEclOTrLg1gEubBFefOqtmyV + const char *getKey() const override { return "ice-pwd"; } }; class SdpAttrIceOption : public SdpItem { public: - //a=ice-options:trickle - bool trickle{false}; - bool renomination{false}; + // a=ice-options:trickle + bool trickle { false }; + bool renomination { false }; void parse(const std::string &str) override; std::string toString() const override; - const char* getKey() const override { return "ice-options";} + const char *getKey() const override { return "ice-options"; } }; class SdpAttrFingerprint : public SdpItem { public: - //a=fingerprint:sha-256 22:14:B5:AF:66:12:C7:C7:8D:EF:4B:DE:40:25:ED:5D:8F:17:54:DD:88:33:C0:13:2E:FD:1A:FA:7E:7A:1B:79 + // a=fingerprint:sha-256 22:14:B5:AF:66:12:C7:C7:8D:EF:4B:DE:40:25:ED:5D:8F:17:54:DD:88:33:C0:13:2E:FD:1A:FA:7E:7A:1B:79 std::string algorithm; std::string hash; void parse(const std::string &str) override; std::string toString() const override; - const char* getKey() const override { return "fingerprint";} + const char *getKey() const override { return "fingerprint"; } bool empty() const { return algorithm.empty() || hash.empty(); } }; class SdpAttrSetup : public SdpItem { public: - //a=setup:actpass + // a=setup:actpass SdpAttrSetup() = default; SdpAttrSetup(DtlsRole r) { role = r; } - DtlsRole role{DtlsRole::actpass}; + DtlsRole role { DtlsRole::actpass }; void parse(const std::string &str) override; std::string toString() const override; - const char* getKey() const override { return "setup";} + const char *getKey() const override { return "setup"; } }; class SdpAttrMid : public SdpItem { public: SdpAttrMid() = default; SdpAttrMid(std::string val) { value = std::move(val); } - //a=mid:audio - const char* getKey() const override { return "mid";} + // a=mid:audio + const char *getKey() const override { return "mid"; } }; class SdpAttrExtmap : public SdpItem { public: - //https://aggresss.blog.csdn.net/article/details/106436703 - //a=extmap:1[/sendonly] urn:ietf:params:rtp-hdrext:ssrc-audio-level + // https://aggresss.blog.csdn.net/article/details/106436703 + // a=extmap:1[/sendonly] urn:ietf:params:rtp-hdrext:ssrc-audio-level uint8_t id; - RtpDirection direction{RtpDirection::invalid}; + RtpDirection direction { RtpDirection::invalid }; std::string ext; void parse(const std::string &str) override; std::string toString() const override; - const char* getKey() const override { return "extmap";} + const char *getKey() const override { return "extmap"; } }; class SdpAttrRtpMap : public SdpItem { public: - //a=rtpmap:111 opus/48000/2 + // a=rtpmap:111 opus/48000/2 uint8_t pt; std::string codec; uint32_t sample_rate; - uint32_t channel {0}; + uint32_t channel { 0 }; void parse(const std::string &str) override; std::string toString() const override; - const char* getKey() const override { return "rtpmap";} + const char *getKey() const override { return "rtpmap"; } }; class SdpAttrRtcpFb : public SdpItem { public: - //a=rtcp-fb:98 nack pli - //a=rtcp-fb:120 nack 支持 nack 重传,nack (Negative-Acknowledgment) 。 - //a=rtcp-fb:120 nack pli 支持 nack 关键帧重传,PLI (Picture Loss Indication) 。 - //a=rtcp-fb:120 ccm fir 支持编码层关键帧请求,CCM (Codec Control Message),FIR (Full Intra Request ),通常与 nack pli 有同样的效果,但是 nack pli 是用于重传时的关键帧请求。 - //a=rtcp-fb:120 goog-remb 支持 REMB (Receiver Estimated Maximum Bitrate) 。 - //a=rtcp-fb:120 transport-cc 支持 TCC (Transport Congest Control) 。 + // a=rtcp-fb:98 nack pli + // a=rtcp-fb:120 nack 支持 nack 重传,nack (Negative-Acknowledgment) 。 + // a=rtcp-fb:120 nack pli 支持 nack 关键帧重传,PLI (Picture Loss Indication) 。 + // a=rtcp-fb:120 ccm fir 支持编码层关键帧请求,CCM (Codec Control Message),FIR (Full Intra Request ),通常与 nack pli 有同样的效果,但是 nack pli + // 是用于重传时的关键帧请求。 a=rtcp-fb:120 goog-remb 支持 REMB (Receiver Estimated Maximum Bitrate) 。 a=rtcp-fb:120 transport-cc 支持 TCC (Transport + // Congest Control) 。 uint8_t pt; std::string rtcp_type; void parse(const std::string &str) override; std::string toString() const override; - const char* getKey() const override { return "rtcp-fb";} + const char *getKey() const override { return "rtcp-fb"; } }; class SdpAttrFmtp : public SdpItem { public: - //fmtp:96 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42e01f + // fmtp:96 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42e01f uint8_t pt; - std::map fmtp; + std::map fmtp; void parse(const std::string &str) override; std::string toString() const override; - const char* getKey() const override { return "fmtp";} + const char *getKey() const override { return "fmtp"; } }; class SdpAttrSSRC : public SdpItem { public: - //a=ssrc:3245185839 cname:Cx4i/VTR51etgjT7 - //a=ssrc:3245185839 msid:cb373bff-0fea-4edb-bc39-e49bb8e8e3b9 0cf7e597-36a2-4480-9796-69bf0955eef5 - //a=ssrc:3245185839 mslabel:cb373bff-0fea-4edb-bc39-e49bb8e8e3b9 - //a=ssrc:3245185839 label:0cf7e597-36a2-4480-9796-69bf0955eef5 - //a=ssrc: - //a=ssrc: : - //cname 是必须的,msid/mslabel/label 这三个属性都是 WebRTC 自创的,或者说 Google 自创的,可以参考 https://tools.ietf.org/html/draft-ietf-mmusic-msid-17, - // 理解它们三者的关系需要先了解三个概念:RTP stream / MediaStreamTrack / MediaStream : - //一个 a=ssrc 代表一个 RTP stream ; - //一个 MediaStreamTrack 通常包含一个或多个 RTP stream,例如一个视频 MediaStreamTrack 中通常包含两个 RTP stream,一个用于常规传输,一个用于 nack 重传; - //一个 MediaStream 通常包含一个或多个 MediaStreamTrack ,例如 simulcast 场景下,一个 MediaStream 通常会包含三个不同编码质量的 MediaStreamTrack ; - //这种标记方式并不被 Firefox 认可,在 Firefox 生成的 SDP 中一个 a=ssrc 通常只有一行,例如: - //a=ssrc:3245185839 cname:Cx4i/VTR51etgjT7 + // a=ssrc:3245185839 cname:Cx4i/VTR51etgjT7 + // a=ssrc:3245185839 msid:cb373bff-0fea-4edb-bc39-e49bb8e8e3b9 0cf7e597-36a2-4480-9796-69bf0955eef5 + // a=ssrc:3245185839 mslabel:cb373bff-0fea-4edb-bc39-e49bb8e8e3b9 + // a=ssrc:3245185839 label:0cf7e597-36a2-4480-9796-69bf0955eef5 + // a=ssrc: + // a=ssrc: : + // cname 是必须的,msid/mslabel/label 这三个属性都是 WebRTC 自创的,或者说 Google 自创的,可以参考 https://tools.ietf.org/html/draft-ietf-mmusic-msid-17, + // 理解它们三者的关系需要先了解三个概念:RTP stream / MediaStreamTrack / MediaStream : + // 一个 a=ssrc 代表一个 RTP stream ; + // 一个 MediaStreamTrack 通常包含一个或多个 RTP stream,例如一个视频 MediaStreamTrack 中通常包含两个 RTP stream,一个用于常规传输,一个用于 nack 重传; + // 一个 MediaStream 通常包含一个或多个 MediaStreamTrack ,例如 simulcast 场景下,一个 MediaStream 通常会包含三个不同编码质量的 MediaStreamTrack ; + // 这种标记方式并不被 Firefox 认可,在 Firefox 生成的 SDP 中一个 a=ssrc 通常只有一行,例如: + // a=ssrc:3245185839 cname:Cx4i/VTR51etgjT7 uint32_t ssrc; std::string attribute; std::string attribute_value; void parse(const std::string &str) override; std::string toString() const override; - const char* getKey() const override { return "ssrc";} + const char *getKey() const override { return "ssrc"; } }; class SdpAttrSSRCGroup : public SdpItem { public: - //a=ssrc-group 定义参考 RFC 5576(https://tools.ietf.org/html/rfc5576) ,用于描述多个 ssrc 之间的关联,常见的有两种: - //a=ssrc-group:FID 2430709021 3715850271 - // FID (Flow Identification) 最初用在 FEC 的关联中,WebRTC 中通常用于关联一组常规 RTP stream 和 重传 RTP stream 。 - //a=ssrc-group:SIM 360918977 360918978 360918980 - // 在 Chrome 独有的 SDP munging 风格的 simulcast 中使用,将三组编码质量由低到高的 MediaStreamTrack 关联在一起。 - std::string type{"FID"}; + // a=ssrc-group 定义参考 RFC 5576(https://tools.ietf.org/html/rfc5576) ,用于描述多个 ssrc 之间的关联,常见的有两种: + // a=ssrc-group:FID 2430709021 3715850271 + // FID (Flow Identification) 最初用在 FEC 的关联中,WebRTC 中通常用于关联一组常规 RTP stream 和 重传 RTP stream 。 + // a=ssrc-group:SIM 360918977 360918978 360918980 + // 在 Chrome 独有的 SDP munging 风格的 simulcast 中使用,将三组编码质量由低到高的 MediaStreamTrack 关联在一起。 + std::string type { "FID" }; std::vector ssrcs; bool isFID() const { return type == "FID"; } bool isSIM() const { return type == "SIM"; } void parse(const std::string &str) override; std::string toString() const override; - const char* getKey() const override { return "ssrc-group";} + const char *getKey() const override { return "ssrc-group"; } }; class SdpAttrSctpMap : public SdpItem { public: - //https://tools.ietf.org/html/draft-ietf-mmusic-sctp-sdp-05 - //a=sctpmap:5000 webrtc-datachannel 1024 - //a=sctpmap: sctpmap-number media-subtypes [streams] + // https://tools.ietf.org/html/draft-ietf-mmusic-sctp-sdp-05 + // a=sctpmap:5000 webrtc-datachannel 1024 + // a=sctpmap: sctpmap-number media-subtypes [streams] uint16_t port = 0; std::string subtypes; uint32_t streams = 0; void parse(const std::string &str) override; std::string toString() const override; - const char* getKey() const override { return "sctpmap";} + const char *getKey() const override { return "sctpmap"; } bool empty() const { return port == 0 && subtypes.empty() && streams == 0; } }; class SdpAttrCandidate : public SdpItem { public: using Ptr = std::shared_ptr; - //https://tools.ietf.org/html/rfc5245 - //15.1. "candidate" Attribute - //a=candidate:4 1 udp 2 192.168.1.7 58107 typ host - //a=candidate:
typ + // https://tools.ietf.org/html/rfc5245 + // 15.1. "candidate" Attribute + // a=candidate:4 1 udp 2 192.168.1.7 58107 typ host + // a=candidate:
typ std::string foundation; - //传输媒体的类型,1代表RTP;2代表 RTCP。 + // 传输媒体的类型,1代表RTP;2代表 RTCP。 uint32_t component; - std::string transport {"udp"}; + std::string transport { "udp" }; uint32_t priority; std::string address; uint16_t port; std::string type; - std::vector > arr; + std::vector> arr; void parse(const std::string &str) override; std::string toString() const override; - const char* getKey() const override { return "candidate";} + const char *getKey() const override { return "candidate"; } }; -class SdpAttrMsid : public SdpItem{ +class SdpAttrMsid : public SdpItem { public: - const char* getKey() const override { return "msid";} + const char *getKey() const override { return "msid"; } }; -class SdpAttrExtmapAllowMixed : public SdpItem{ +class SdpAttrExtmapAllowMixed : public SdpItem { public: - const char* getKey() const override { return "extmap-allow-mixed";} + const char *getKey() const override { return "extmap-allow-mixed"; } }; -class SdpAttrSimulcast : public SdpItem{ +class SdpAttrSimulcast : public SdpItem { public: - //https://www.meetecho.com/blog/simulcast-janus-ssrc/ - //https://tools.ietf.org/html/draft-ietf-mmusic-sdp-simulcast-14 - const char* getKey() const override { return "simulcast";} + // https://www.meetecho.com/blog/simulcast-janus-ssrc/ + // https://tools.ietf.org/html/draft-ietf-mmusic-sdp-simulcast-14 + const char *getKey() const override { return "simulcast"; } void parse(const std::string &str) override; std::string toString() const override; bool empty() const { return rids.empty(); } @@ -483,11 +470,11 @@ public: std::vector rids; }; -class SdpAttrRid : public SdpItem{ +class SdpAttrRid : public SdpItem { public: void parse(const std::string &str) override; std::string toString() const override; - const char* getKey() const override { return "rid";} + const char *getKey() const override { return "rid"; } std::string direction; std::string rid; }; @@ -507,8 +494,8 @@ public: RtpDirection getDirection() const; - template - cls getItemClass(char key, const char *attr_key = nullptr) const{ + template + cls getItemClass(char key, const char *attr_key = nullptr) const { auto item = std::dynamic_pointer_cast(getItem(key, attr_key)); if (!item) { return cls(); @@ -516,7 +503,7 @@ public: return *item; } - std::string getStringItem(char key, const char *attr_key = nullptr) const{ + std::string getStringItem(char key, const char *attr_key = nullptr) const { auto item = getItem(key, attr_key); if (!item) { return ""; @@ -526,7 +513,7 @@ public: SdpItem::Ptr getItem(char key, const char *attr_key = nullptr) const; - template + template std::vector getAllItem(char key_c, const char *attr_key = nullptr) const { std::vector ret; std::string key(1, key_c); @@ -555,7 +542,7 @@ private: std::vector items; }; -class RtcSessionSdp : public RtcSdpBase{ +class RtcSessionSdp : public RtcSdpBase { public: using Ptr = std::shared_ptr; int getVersion() const; @@ -572,7 +559,7 @@ public: std::string getTimeZone() const; std::string getEncryptKey() const; std::string getRepeatTimes() const; - + std::vector medias; void parse(const std::string &str); std::string toString() const override; @@ -580,45 +567,45 @@ public: ////////////////////////////////////////////////////////////////// -//ssrc相关信息 -class RtcSSRC{ +// ssrc相关信息 +class RtcSSRC { public: - uint32_t ssrc {0}; - uint32_t rtx_ssrc {0}; + uint32_t ssrc { 0 }; + uint32_t rtx_ssrc { 0 }; std::string cname; std::string msid; std::string mslabel; std::string label; - bool empty() const {return ssrc == 0 && cname.empty();} + bool empty() const { return ssrc == 0 && cname.empty(); } }; -//rtc传输编码方案 -class RtcCodecPlan{ +// rtc传输编码方案 +class RtcCodecPlan { public: using Ptr = std::shared_ptr; uint8_t pt; std::string codec; uint32_t sample_rate; - //音频时有效 + // 音频时有效 uint32_t channel = 0; - //rtcp反馈 + // rtcp反馈 std::set rtcp_fb; - std::map fmtp; + std::map fmtp; std::string getFmtp(const char *key) const; }; -//rtc 媒体描述 -class RtcMedia{ +// rtc 媒体描述 +class RtcMedia { public: - TrackType type{TrackType::TrackInvalid}; + TrackType type { TrackType::TrackInvalid }; std::string mid; - uint16_t port{0}; + uint16_t port { 0 }; SdpConnection addr; SdpBandwidth bandwidth; std::string proto; - RtpDirection direction{RtpDirection::invalid}; + RtpDirection direction { RtpDirection::invalid }; std::vector plan; //////// rtp //////// @@ -629,20 +616,20 @@ public: std::vector rtp_rids; //////// rtcp //////// - bool rtcp_mux{false}; - bool rtcp_rsize{false}; + bool rtcp_mux { false }; + bool rtcp_rsize { false }; SdpAttrRtcp rtcp_addr; //////// ice //////// - bool ice_trickle{false}; - bool ice_lite{false}; - bool ice_renomination{false}; + bool ice_trickle { false }; + bool ice_lite { false }; + bool ice_renomination { false }; std::string ice_ufrag; std::string ice_pwd; std::vector candidate; //////// dtls //////// - DtlsRole role{DtlsRole::invalid}; + DtlsRole role { DtlsRole::invalid }; SdpAttrFingerprint fingerprint; //////// extmap //////// @@ -650,7 +637,7 @@ public: //////// sctp //////////// SdpAttrSctpMap sctpmap; - uint32_t sctp_port{0}; + uint32_t sctp_port { 0 }; void checkValid() const; const RtcCodecPlan *getPlan(uint8_t pt) const; @@ -679,7 +666,7 @@ public: void checkValid() const; std::string toString() const; std::string toRtspSdp() const; - const RtcMedia *getMedia(TrackType type) const; + const RtcMedia *getMedia(TrackType type) const; bool supportRtcpFb(const std::string &name, TrackType type = TrackType::TrackVideo) const; bool supportSimulcast() const; bool isOnlyDatachannel() const; @@ -705,7 +692,7 @@ public: std::string ice_ufrag; std::string ice_pwd; - RtpDirection direction{RtpDirection::invalid}; + RtpDirection direction { RtpDirection::invalid }; SdpAttrFingerprint fingerprint; std::set rtcp_fb; @@ -752,6 +739,6 @@ private: ~SdpConst() = delete; }; -}// namespace mediakit +} // namespace mediakit -#endif //ZLMEDIAKIT_SDP_H +#endif // ZLMEDIAKIT_SDP_H diff --git a/webrtc/WebRtcEchoTest.h b/webrtc/WebRtcEchoTest.h index 397406c1..e6249ff2 100644 --- a/webrtc/WebRtcEchoTest.h +++ b/webrtc/WebRtcEchoTest.h @@ -27,7 +27,6 @@ protected: void onRtp(const char *buf, size_t len, uint64_t stamp_ms) override; void onRtcp(const char *buf, size_t len) override; - void onRecvRtp(MediaTrack &track, const std::string &rid, RtpPacket::Ptr rtp) override {}; void onBeforeEncryptRtp(const char *buf, int &len, void *ctx) override {}; void onBeforeEncryptRtcp(const char *buf, int &len, void *ctx) override {}; diff --git a/webrtc/WebRtcPlayer.cpp b/webrtc/WebRtcPlayer.cpp index bdc82697..cfafae2b 100644 --- a/webrtc/WebRtcPlayer.cpp +++ b/webrtc/WebRtcPlayer.cpp @@ -17,9 +17,8 @@ namespace mediakit { WebRtcPlayer::Ptr WebRtcPlayer::create(const EventPoller::Ptr &poller, const RtspMediaSource::Ptr &src, - const MediaInfo &info, - bool preferred_tcp) { - WebRtcPlayer::Ptr ret(new WebRtcPlayer(poller, src, info, preferred_tcp), [](WebRtcPlayer *ptr) { + const MediaInfo &info) { + WebRtcPlayer::Ptr ret(new WebRtcPlayer(poller, src, info), [](WebRtcPlayer *ptr) { ptr->onDestory(); delete ptr; }); @@ -29,8 +28,7 @@ WebRtcPlayer::Ptr WebRtcPlayer::create(const EventPoller::Ptr &poller, WebRtcPlayer::WebRtcPlayer(const EventPoller::Ptr &poller, const RtspMediaSource::Ptr &src, - const MediaInfo &info, - bool preferred_tcp) : WebRtcTransportImp(poller,preferred_tcp) { + const MediaInfo &info) : WebRtcTransportImp(poller) { _media_info = info; _play_src = src; CHECK(src); diff --git a/webrtc/WebRtcPlayer.h b/webrtc/WebRtcPlayer.h index 8daa7f8b..ccacd410 100644 --- a/webrtc/WebRtcPlayer.h +++ b/webrtc/WebRtcPlayer.h @@ -19,7 +19,7 @@ namespace mediakit { class WebRtcPlayer : public WebRtcTransportImp { public: using Ptr = std::shared_ptr; - static Ptr create(const EventPoller::Ptr &poller, const RtspMediaSource::Ptr &src, const MediaInfo &info, bool preferred_tcp = false); + static Ptr create(const EventPoller::Ptr &poller, const RtspMediaSource::Ptr &src, const MediaInfo &info); MediaInfo getMediaInfo() { return _media_info; } protected: @@ -27,10 +27,9 @@ protected: void onStartWebRTC() override; void onDestory() override; void onRtcConfigure(RtcConfigure &configure) const override; - void onRecvRtp(MediaTrack &track, const std::string &rid, RtpPacket::Ptr rtp) override {}; private: - WebRtcPlayer(const EventPoller::Ptr &poller, const RtspMediaSource::Ptr &src, const MediaInfo &info, bool preferred_tcp); + WebRtcPlayer(const EventPoller::Ptr &poller, const RtspMediaSource::Ptr &src, const MediaInfo &info); private: //媒体相关元数据 diff --git a/webrtc/WebRtcPusher.cpp b/webrtc/WebRtcPusher.cpp index 47df47c9..cde07992 100644 --- a/webrtc/WebRtcPusher.cpp +++ b/webrtc/WebRtcPusher.cpp @@ -20,9 +20,8 @@ WebRtcPusher::Ptr WebRtcPusher::create(const EventPoller::Ptr &poller, const RtspMediaSource::Ptr &src, const std::shared_ptr &ownership, const MediaInfo &info, - const ProtocolOption &option, - bool preferred_tcp) { - WebRtcPusher::Ptr ret(new WebRtcPusher(poller, src, ownership, info, option,preferred_tcp), [](WebRtcPusher *ptr) { + const ProtocolOption &option) { + WebRtcPusher::Ptr ret(new WebRtcPusher(poller, src, ownership, info, option), [](WebRtcPusher *ptr) { ptr->onDestory(); delete ptr; }); @@ -34,8 +33,7 @@ WebRtcPusher::WebRtcPusher(const EventPoller::Ptr &poller, const RtspMediaSource::Ptr &src, const std::shared_ptr &ownership, const MediaInfo &info, - const ProtocolOption &option, - bool preferred_tcp) : WebRtcTransportImp(poller,preferred_tcp) { + const ProtocolOption &option) : WebRtcTransportImp(poller) { _media_info = info; _push_src = src; _push_src_ownership = ownership; diff --git a/webrtc/WebRtcPusher.h b/webrtc/WebRtcPusher.h index bd4775e2..19b04608 100644 --- a/webrtc/WebRtcPusher.h +++ b/webrtc/WebRtcPusher.h @@ -20,8 +20,7 @@ class WebRtcPusher : public WebRtcTransportImp, public MediaSourceEvent { public: using Ptr = std::shared_ptr; static Ptr create(const EventPoller::Ptr &poller, const RtspMediaSource::Ptr &src, - const std::shared_ptr &ownership, const MediaInfo &info, const ProtocolOption &option, bool preferred_tcp = false); - + const std::shared_ptr &ownership, const MediaInfo &info, const ProtocolOption &option); protected: ///////WebRtcTransportImp override/////// @@ -53,7 +52,7 @@ protected: private: WebRtcPusher(const EventPoller::Ptr &poller, const RtspMediaSource::Ptr &src, - const std::shared_ptr &ownership, const MediaInfo &info, const ProtocolOption &option, bool preferred_tcp); + const std::shared_ptr &ownership, const MediaInfo &info, const ProtocolOption &option); private: bool _simulcast = false; diff --git a/webrtc/WebRtcTransport.cpp b/webrtc/WebRtcTransport.cpp index 786e26c3..768c543e 100644 --- a/webrtc/WebRtcTransport.cpp +++ b/webrtc/WebRtcTransport.cpp @@ -378,6 +378,12 @@ void WebRtcTransport::setRemoteDtlsFingerprint(const RtcSession &remote) { } void WebRtcTransport::onRtcConfigure(RtcConfigure &configure) const { + SdpAttrFingerprint fingerprint; + fingerprint.algorithm = _offer_sdp->media[0].fingerprint.algorithm; + fingerprint.hash = getFingerprint(fingerprint.algorithm, _dtls_transport); + configure.setDefaultSetting( + _ice_server->GetUsernameFragment(), _ice_server->GetPassword(), RtpDirection::sendrecv, fingerprint); + // 开启remb后关闭twcc,因为开启twcc后remb无效 GET_CONFIG(size_t, remb_bit_rate, Rtc::kRembBitRate); configure.enableTWCC(!remb_bit_rate); @@ -407,12 +413,7 @@ std::string WebRtcTransport::getAnswerSdp(const string &offer) { setRemoteDtlsFingerprint(*_offer_sdp); //// sdp 配置 //// - SdpAttrFingerprint fingerprint; - fingerprint.algorithm = _offer_sdp->media[0].fingerprint.algorithm; - fingerprint.hash = getFingerprint(fingerprint.algorithm, _dtls_transport); RtcConfigure configure; - configure.setDefaultSetting( - _ice_server->GetUsernameFragment(), _ice_server->GetPassword(), RtpDirection::sendrecv, fingerprint); onRtcConfigure(configure); //// 生成answer sdp //// @@ -431,10 +432,6 @@ static bool isDtls(char *buf) { return ((*buf > 19) && (*buf < 64)); } -static string getPeerAddress(RTC::TransportTuple *tuple) { - return tuple->get_peer_ip(); -} - void WebRtcTransport::inputSockData(char *buf, int len, RTC::TransportTuple *tuple) { if (RTC::StunPacket::IsStun((const uint8_t *)buf, len)) { std::unique_ptr packet(RTC::StunPacket::Parse((const uint8_t *)buf, len)); @@ -451,7 +448,7 @@ void WebRtcTransport::inputSockData(char *buf, int len, RTC::TransportTuple *tup } if (isRtp(buf, len)) { if (!_srtp_session_recv) { - WarnL << "received rtp packet when dtls not completed from:" << getPeerAddress(tuple); + WarnL << "received rtp packet when dtls not completed from:" << tuple->get_peer_ip(); return; } if (_srtp_session_recv->DecryptSrtp((uint8_t *)buf, &len)) { @@ -461,7 +458,7 @@ void WebRtcTransport::inputSockData(char *buf, int len, RTC::TransportTuple *tup } if (isRtcp(buf, len)) { if (!_srtp_session_recv) { - WarnL << "received rtcp packet when dtls not completed from:" << getPeerAddress(tuple); + WarnL << "received rtcp packet when dtls not completed from:" << tuple->get_peer_ip(); return; } if (_srtp_session_recv->DecryptSrtcp((uint8_t *)buf, &len)) { @@ -533,8 +530,7 @@ void WebRtcTransportImp::OnDtlsTransportApplicationDataReceived(const RTC::DtlsT #endif } -WebRtcTransportImp::WebRtcTransportImp(const EventPoller::Ptr &poller,bool preferred_tcp) - : WebRtcTransport(poller), _preferred_tcp(preferred_tcp) { +WebRtcTransportImp::WebRtcTransportImp(const EventPoller::Ptr &poller) : WebRtcTransport(poller) { InfoL << getIdentifier(); } @@ -674,7 +670,7 @@ void WebRtcTransportImp::onCheckAnswer(RtcSession &sdp) { }); for (auto &m : sdp.media) { m.addr.reset(); - m.addr.address = extern_ips.empty() ? _localIp.empty() ? SockUtil::get_local_ip() : _localIp : extern_ips[0]; + m.addr.address = extern_ips.empty() ? _local_ip.empty() ? SockUtil::get_local_ip() : _local_ip : extern_ips[0]; m.rtcp_addr.reset(); m.rtcp_addr.address = m.addr.address; @@ -769,7 +765,7 @@ void WebRtcTransportImp::onRtcConfigure(RtcConfigure &configure) const { return ret; }); if (extern_ips.empty()) { - std::string local_ip = _localIp.empty() ? SockUtil::get_local_ip() : _localIp; + std::string local_ip = _local_ip.empty() ? SockUtil::get_local_ip() : _local_ip; if (local_udp_port) { configure.addCandidate(*makeIceCandidate(local_ip, local_udp_port, 120, "udp")); } if (local_tcp_port) { configure.addCandidate(*makeIceCandidate(local_ip, local_tcp_port, _preferred_tcp ? 125 : 115, "tcp")); } } else { @@ -783,12 +779,16 @@ void WebRtcTransportImp::onRtcConfigure(RtcConfigure &configure) const { } } -void WebRtcTransportImp::setIceCandidate(vector cands) { - _cands = std::move(cands); +void WebRtcTransportImp::setPreferredTcp(bool flag) { + _preferred_tcp = flag; } -void WebRtcTransportImp::setLocalIp(const std::string &localIp) { - _localIp = localIp; +void WebRtcTransportImp::setLocalIp(std::string local_ip) { + _local_ip = std::move(local_ip); +} + +void WebRtcTransportImp::setIceCandidate(vector cands) { + _cands = std::move(cands); } /////////////////////////////////////////////////////////////////// @@ -1278,21 +1278,14 @@ void WebRtcPluginManager::registerPlugin(const string &type, Plugin cb) { _map_creator[type] = std::move(cb); } -std::string exchangeSdp(const WebRtcInterface &exchanger, const std::string& offer) { - return const_cast(exchanger).getAnswerSdp(offer); -} - -void setLocalIp(const WebRtcInterface& exchanger, const std::string& localIp) { - return const_cast(exchanger).setLocalIp(localIp); -} void WebRtcPluginManager::setListener(Listener cb) { lock_guard lck(_mtx_creator); _listener = std::move(cb); } -void WebRtcPluginManager::getAnswerSdp(Session &sender, const string &type, const WebRtcArgs &args, const onCreateRtc &cb_in) { - onCreateRtc cb; +void WebRtcPluginManager::negotiateSdp(Session &sender, const string &type, const WebRtcArgs &args, const onCreateWebRtc &cb_in) { + onCreateWebRtc cb; lock_guard lck(_mtx_creator); if (_listener) { auto listener = _listener; @@ -1308,21 +1301,19 @@ void WebRtcPluginManager::getAnswerSdp(Session &sender, const string &type, cons auto it = _map_creator.find(type); if (it == _map_creator.end()) { - cb(WebRtcException(SockException(Err_other, "the type can not supported"))); + cb_in(WebRtcException(SockException(Err_other, "the type can not supported"))); return; } it->second(sender, args, cb); } -void echo_plugin(Session &sender, const WebRtcArgs &args, const WebRtcPluginManager::onCreateRtc &cb) { +void echo_plugin(Session &sender, const WebRtcArgs &args, const onCreateWebRtc &cb) { cb(*WebRtcEchoTest::create(EventPollerPool::Instance().getPoller())); } -void push_plugin(Session &sender, const WebRtcArgs &args, const WebRtcPluginManager::onCreateRtc &cb) { +void push_plugin(Session &sender, const WebRtcArgs &args, const onCreateWebRtc &cb) { MediaInfo info(args["url"]); - bool preferred_tcp = args["preferred_tcp"]; - - Broadcast::PublishAuthInvoker invoker = [cb, info, preferred_tcp](const string &err, const ProtocolOption &option) mutable { + Broadcast::PublishAuthInvoker invoker = [cb, info](const string &err, const ProtocolOption &option) mutable { if (!err.empty()) { cb(WebRtcException(SockException(Err_other, err))); return; @@ -1361,7 +1352,7 @@ void push_plugin(Session &sender, const WebRtcArgs &args, const WebRtcPluginMana push_src_ownership = push_src->getOwnership(); push_src->setProtocolOption(option); } - auto rtc = WebRtcPusher::create(EventPollerPool::Instance().getPoller(), push_src, push_src_ownership, info, option, preferred_tcp); + auto rtc = WebRtcPusher::create(EventPollerPool::Instance().getPoller(), push_src, push_src_ownership, info, option); push_src->setListener(rtc); cb(*rtc); }; @@ -1374,12 +1365,10 @@ void push_plugin(Session &sender, const WebRtcArgs &args, const WebRtcPluginMana } } -void play_plugin(Session &sender, const WebRtcArgs &args, const WebRtcPluginManager::onCreateRtc &cb) { +void play_plugin(Session &sender, const WebRtcArgs &args, const onCreateWebRtc &cb) { MediaInfo info(args["url"]); - bool preferred_tcp = args["preferred_tcp"]; - auto session_ptr = static_pointer_cast(sender.shared_from_this()); - Broadcast::AuthInvoker invoker = [cb, info, session_ptr, preferred_tcp](const string &err) mutable { + Broadcast::AuthInvoker invoker = [cb, info, session_ptr](const string &err) mutable { if (!err.empty()) { cb(WebRtcException(SockException(Err_other, err))); return; @@ -1395,7 +1384,7 @@ void play_plugin(Session &sender, const WebRtcArgs &args, const WebRtcPluginMana } // 还原成rtc,目的是为了hook时识别哪种播放协议 info.schema = "rtc"; - auto rtc = WebRtcPlayer::create(EventPollerPool::Instance().getPoller(), src, info, preferred_tcp); + auto rtc = WebRtcPlayer::create(EventPollerPool::Instance().getPoller(), src, info); cb(*rtc); }); }; @@ -1408,39 +1397,63 @@ void play_plugin(Session &sender, const WebRtcArgs &args, const WebRtcPluginMana } } -static void set_webrtc_cands(const WebRtcArgs &args, const WebRtcInterface &rtc) { - vector cands; +static void setWebRtcArgs(const WebRtcArgs &args, WebRtcInterface &rtc) { { - auto cand_str = trim(args["cand_udp"]); - auto ip_port = toolkit::split(cand_str, ":"); - if (ip_port.size() == 2) { + static auto is_vaild_ip = [](const std::string &ip) -> bool { + int a, b, c, d; + return sscanf(ip.c_str(), "%d.%d.%d.%d", &a, &b, &c, &d) == 4; + }; + std::string host = args["Host"]; + if (!host.empty()) { + auto local_ip = host.substr(0, host.find(':')); + if (!is_vaild_ip(local_ip) || local_ip == "127.0.0.1") { + local_ip = ""; + } + rtc.setLocalIp(std::move(local_ip)); + } + } + + bool preferred_tcp = args["preferred_tcp"]; + { + rtc.setPreferredTcp(preferred_tcp); + } + + { + vector cands; + { + auto cand_str = trim(args["cand_udp"]); + auto ip_port = toolkit::split(cand_str, ":"); + if (ip_port.size() == 2) { + // udp优先 + auto ice_cand = makeIceCandidate(ip_port[0], atoi(ip_port[1].data()), preferred_tcp ? 100 : 120, "udp"); + cands.emplace_back(std::move(*ice_cand)); + } + } + { + auto cand_str = trim(args["cand_tcp"]); + auto ip_port = toolkit::split(cand_str, ":"); + if (ip_port.size() == 2) { + // tcp模式 + auto ice_cand = makeIceCandidate(ip_port[0], atoi(ip_port[1].data()), preferred_tcp ? 120 : 100, "tcp"); + cands.emplace_back(std::move(*ice_cand)); + } + } + if (!cands.empty()) { // udp优先 - auto ice_cand = makeIceCandidate(ip_port[0], atoi(ip_port[1].data()), 120, "udp"); - cands.emplace_back(std::move(*ice_cand)); + rtc.setIceCandidate(std::move(cands)); } } - { - auto cand_str = trim(args["cand_tcp"]); - auto ip_port = toolkit::split(cand_str, ":"); - if (ip_port.size() == 2) { - // tcp模式 - auto ice_cand = makeIceCandidate(ip_port[0], atoi(ip_port[1].data()), 100, "tcp"); - cands.emplace_back(std::move(*ice_cand)); - } - } - if (!cands.empty()) { - // udp优先 - const_cast(rtc).setIceCandidate(std::move(cands)); - } } static onceToken s_rtc_auto_register([]() { +#if !defined (NDEBUG) + // debug模式才开启echo插件 WebRtcPluginManager::Instance().registerPlugin("echo", echo_plugin); +#endif WebRtcPluginManager::Instance().registerPlugin("push", push_plugin); WebRtcPluginManager::Instance().registerPlugin("play", play_plugin); - WebRtcPluginManager::Instance().setListener([](Session &sender, const std::string &type, const WebRtcArgs &args, const WebRtcInterface &rtc) { - set_webrtc_cands(args, rtc); + setWebRtcArgs(args, const_cast(rtc)); }); }); diff --git a/webrtc/WebRtcTransport.h b/webrtc/WebRtcTransport.h index 8e8d97fc..3f920c68 100644 --- a/webrtc/WebRtcTransport.h +++ b/webrtc/WebRtcTransport.h @@ -42,13 +42,10 @@ public: virtual const std::string& getIdentifier() const = 0; virtual const std::string& deleteRandStr() const { static std::string s_null; return s_null; } virtual void setIceCandidate(std::vector cands) {} - virtual void setLocalIp(const std::string &localIp) {} + virtual void setLocalIp(std::string localIp) {} + virtual void setPreferredTcp(bool flag) {} }; -std::string exchangeSdp(const WebRtcInterface &exchanger, const std::string& offer); - -void setLocalIp(const WebRtcInterface &exchanger, const std::string &localIp); - class WebRtcException : public WebRtcInterface { public: WebRtcException(const SockException &ex) : _ex(ex) {}; @@ -88,7 +85,7 @@ public: * @param offer offer sdp * @return answer sdp */ - std::string getAnswerSdp(const std::string &offer) override; + std::string getAnswerSdp(const std::string &offer) override final; /** * 获取对象唯一id @@ -252,14 +249,16 @@ public: void onSendRtp(const RtpPacket::Ptr &rtp, bool flush, bool rtx = false); void createRtpChannel(const std::string &rid, uint32_t ssrc, MediaTrack &track); - void setIceCandidate(std::vector cands) override; void removeTuple(RTC::TransportTuple* tuple); void safeShutdown(const SockException &ex); - void setLocalIp(const std::string &localIp) override; + void setPreferredTcp(bool flag) override; + void setLocalIp(std::string local_ip) override; + void setIceCandidate(std::vector cands) override; + protected: void OnIceServerSelectedTuple(const RTC::IceServer *iceServer, RTC::TransportTuple *tuple) override; - WebRtcTransportImp(const EventPoller::Ptr &poller,bool preferred_tcp = false); + WebRtcTransportImp(const EventPoller::Ptr &poller); void OnDtlsTransportApplicationDataReceived(const RTC::DtlsTransport *dtlsTransport, const uint8_t *data, size_t len) override; void onStartWebRTC() override; void onSendSockData(Buffer::Ptr buf, bool flush = true, RTC::TransportTuple *tuple = nullptr) override; @@ -273,7 +272,7 @@ protected: void onCreate() override; void onDestory() override; void onShutdown(const SockException &ex) override; - virtual void onRecvRtp(MediaTrack &track, const std::string &rid, RtpPacket::Ptr rtp) = 0; + virtual void onRecvRtp(MediaTrack &track, const std::string &rid, RtpPacket::Ptr rtp) {} void updateTicker(); float getLossRate(TrackType type); void onRtcpBye() override; @@ -289,7 +288,7 @@ private: void onCheckAnswer(RtcSession &sdp); private: - bool _preferred_tcp; + bool _preferred_tcp = false; uint16_t _rtx_seq[2] = {0, 0}; //用掉的总流量 uint64_t _bytes_usage = 0; @@ -310,8 +309,8 @@ private: //根据接收rtp的pt获取相关信息 std::unordered_map> _pt_to_track; std::vector _cands; - //源访问的hostip - std::string _localIp; + //http访问时的host ip + std::string _local_ip; }; class WebRtcTransportManager { @@ -333,21 +332,20 @@ private: class WebRtcArgs : public std::enable_shared_from_this { public: virtual ~WebRtcArgs() = default; - virtual variant operator[](const std::string &key) const = 0; }; +using onCreateWebRtc = std::function; class WebRtcPluginManager { public: - using onCreateRtc = std::function; - using Plugin = std::function; + using Plugin = std::function; using Listener = std::function; static WebRtcPluginManager &Instance(); void registerPlugin(const std::string &type, Plugin cb); - void getAnswerSdp(Session &sender, const std::string &type, const WebRtcArgs &args, const onCreateRtc &cb); void setListener(Listener cb); + void negotiateSdp(Session &sender, const std::string &type, const WebRtcArgs &args, const onCreateWebRtc &cb); private: WebRtcPluginManager() = default;