diff --git a/api/include/mk_common.h b/api/include/mk_common.h index 5d01e8e0..78233ba3 100755 --- a/api/include/mk_common.h +++ b/api/include/mk_common.h @@ -259,31 +259,24 @@ API_EXPORT uint16_t API_CALL mk_rtp_server_start(uint16_t port); */ API_EXPORT uint16_t API_CALL mk_rtc_server_start(uint16_t port); -// 获取webrtc answer sdp回调函数 [AUTO-TRANSLATED:10c93fa9] -// Get webrtc answer sdp callback function -typedef void(API_CALL *on_mk_webrtc_get_answer_sdp)(void *user_data, const char *answer, const char *err); /** - * webrtc交换sdp,根据offer sdp生成answer sdp - * @param user_data 回调用户指针 - * @param cb 回调函数 - * @param type webrtc插件类型,支持echo,play,push - * @param offer webrtc offer sdp - * @param url rtc url, 例如 rtc://__defaultVhost/app/stream?key1=val1&key2=val2 - * webrtc exchange sdp, generate answer sdp based on offer sdp - * @param user_data Callback user pointer - * @param cb Callback function - * @param type webrtc plugin type, supports echo, play, push - * @param offer webrtc offer sdp - * @param url rtc url, for example rtc://__defaultVhost/app/stream?key1=val1&key2=val2 - - * [AUTO-TRANSLATED:ea79659b] + * 创建websocket[s]信令服务器 + * @param port websocket监听端口 + * @param ssl 是否为ssl类型服务器 + * @return 0:失败,非0:端口号 + * */ -API_EXPORT void API_CALL mk_webrtc_get_answer_sdp(void *user_data, on_mk_webrtc_get_answer_sdp cb, const char *type, - const char *offer, const char *url); +API_EXPORT uint16_t API_CALL mk_signaling_server_start(uint16_t port, int ssl); + +/** + * 创建webrtc-ice[s]服务器 + * @param port websocket监听端口 + * @return 0:失败,非0:端口号 + * + */ +API_EXPORT uint16_t API_CALL mk_ice_server_start(uint16_t port); -API_EXPORT void API_CALL mk_webrtc_get_answer_sdp2(void *user_data, on_user_data_free user_data_free, on_mk_webrtc_get_answer_sdp cb, const char *type, - const char *offer, const char *url); /** * 创建srt服务器 diff --git a/api/include/mk_mediakit.h b/api/include/mk_mediakit.h index b7682195..2fba3812 100755 --- a/api/include/mk_mediakit.h +++ b/api/include/mk_mediakit.h @@ -27,5 +27,6 @@ #include "mk_frame.h" #include "mk_track.h" #include "mk_transcode.h" +#include "mk_webrtc.h" #endif /* MK_API_H_ */ diff --git a/api/include/mk_webrtc.h b/api/include/mk_webrtc.h new file mode 100644 index 00000000..3844e391 --- /dev/null +++ b/api/include/mk_webrtc.h @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2016-present The ZLMediaKit project authors. All Rights Reserved. + * + * This file is part of ZLMediaKit(https://github.com/ZLMediaKit/ZLMediaKit). + * + * Use of this source code is governed by MIT-like license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef MK_WEBRTC_H +#define MK_WEBRTC_H +#include "mk_common.h" +#include "mk_proxyplayer.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + + +// 获取webrtc answer sdp回调函数 [AUTO-TRANSLATED:10c93fa9] +// Get webrtc answer sdp callback function +typedef void(API_CALL *on_mk_webrtc_get_answer_sdp)(void *user_data, const char *answer, const char *err); + +// 获取webrtc proxy player信息回调函数 +typedef void(API_CALL *on_mk_webrtc_get_proxy_player_info_cb)(const char *info_json, const char *err); + +//WebRTC-注册到信令服务器、WebRTC-从信令服务器注销回调函数 +typedef void(API_CALL *on_mk_webrtc_room_keeper_info_cb)(void *user_data, const char *room_key, const char *err); + +//获取WebRTC-Peer查看注册信息、WebRTC-信令服务器查看注册信息回调函数 +typedef void(API_CALL *on_mk_webrtc_room_keeper_data_cb)(const char *data); + + +/** + * webrtc交换sdp,根据offer sdp生成answer sdp + * @param user_data 回调用户指针 + * @param cb 回调函数 + * @param type webrtc插件类型,支持echo,play,push + * @param offer webrtc offer sdp + * @param url rtc url, 例如 rtc://__defaultVhost/app/stream?key1=val1&key2=val2 + * webrtc exchange sdp, generate answer sdp based on offer sdp + * @param user_data Callback user pointer + * @param cb Callback function + * @param type webrtc plugin type, supports echo, play, push + * @param offer webrtc offer sdp + * @param url rtc url, for example rtc://__defaultVhost/app/stream?key1=val1&key2=val2 + + * [AUTO-TRANSLATED:ea79659b] + */ +API_EXPORT void API_CALL mk_webrtc_get_answer_sdp(void *user_data, on_mk_webrtc_get_answer_sdp cb, const char *type, const char *offer, const char *url); + +API_EXPORT void API_CALL mk_webrtc_get_answer_sdp2( + void *user_data, on_user_data_free user_data_free, on_mk_webrtc_get_answer_sdp cb, const char *type, const char *offer, const char *url); + +/** + * 获取webrtc proxy player信息 + * @param mk_proxy_player 代理 + * @param cb 回调函数 + */ +API_EXPORT void API_CALL mk_webrtc_get_proxy_player_info(mk_proxy_player ctx, on_mk_webrtc_get_proxy_player_info_cb cb); + + +/** + * WebRTC-注册到信令服务器 + * @param server_host 信令服务器host + * @param server_port 信令服务器port + * @param room_id 房间id + * @param ssl 是否启用ssl + * @param cb 回调函数 + * @param user_data 用户数据 + */ +API_EXPORT void API_CALL +mk_webrtc_add_room_keeper(const char *room_id, const char *server_host, uint16_t server_port, int ssl, on_mk_webrtc_room_keeper_info_cb cb, void *user_data); + + +API_EXPORT void API_CALL mk_webrtc_add_room_keeper2( + const char *room_id, const char *server_host, uint16_t server_port, int ssl, on_mk_webrtc_room_keeper_info_cb cb, void *user_data, + on_user_data_free user_data_free); + + +/** + * WebRTC-从信令服务器注销 + * @param room_key 房间key + * @param cb 回调函数 + * @param user_data 用户数据 + */ +API_EXPORT void API_CALL mk_webrtc_del_room_keeper(const char *room_key, on_mk_webrtc_room_keeper_info_cb cb, void *user_data); + +API_EXPORT void API_CALL +mk_webrtc_del_room_keeper2(const char *room_key, on_mk_webrtc_room_keeper_info_cb cb, void *user_data, on_user_data_free user_data_free); + + +/** + * WebRTC-Peer查看注册信息 + * @param cb 回调函数 + */ +API_EXPORT void API_CALL mk_webrtc_list_room_keeper(on_mk_webrtc_room_keeper_data_cb cb); + +/** + * WebRTC-信令服务器查看注册信息 + * @param cb 回调函数 + */ +API_EXPORT void API_CALL mk_webrtc_list_rooms(on_mk_webrtc_room_keeper_data_cb cb); + +#ifdef __cplusplus +} +#endif + +#endif /* MK_WEBRTC_H */ \ No newline at end of file diff --git a/api/source/mk_common.cpp b/api/source/mk_common.cpp index 3bc274da..e0a15e6f 100644 --- a/api/source/mk_common.cpp +++ b/api/source/mk_common.cpp @@ -29,6 +29,7 @@ using namespace mediakit; static TcpServer::Ptr rtsp_server[2]; static TcpServer::Ptr rtmp_server[2]; static TcpServer::Ptr http_server[2]; +static TcpServer::Ptr signaling_server[2]; static TcpServer::Ptr shell_server; #ifdef ENABLE_RTPPROXY @@ -37,9 +38,14 @@ static RtpServer::Ptr rtpServer; #endif #ifdef ENABLE_WEBRTC -#include "../webrtc/WebRtcSession.h" +#include "webrtc/WebRtcSession.h" +#include "webrtc/IceSession.hpp" +#include "webrtc/WebRtcSignalingSession.h" +#include "webrtc/WebRtcTransport.h" static UdpServer::Ptr rtcServer_udp; static TcpServer::Ptr rtcServer_tcp; +static UdpServer::Ptr iceServer_udp; +static TcpServer::Ptr iceServer_tcp; #endif #if defined(ENABLE_SRT) @@ -288,46 +294,45 @@ API_EXPORT uint16_t API_CALL mk_rtc_server_start(uint16_t port) { #endif } -#ifdef ENABLE_WEBRTC -class WebRtcArgsUrl : public mediakit::WebRtcArgs { -public: - WebRtcArgsUrl(std::string url) { _url = std::move(url); } - toolkit::variant operator[](const std::string &key) const override { - if (key == "url") { - return _url; +API_EXPORT uint16_t API_CALL mk_signaling_server_start(uint16_t port, int ssl) { +#ifdef ENABLE_WEBRTC + ssl = MAX(0, MIN(ssl, 1)); + try { + signaling_server[ssl] = std::make_shared(); + if (ssl) { + signaling_server[ssl]->start(port); + } else { + signaling_server[ssl]->start(port); } - return ""; + return signaling_server[ssl]->getPort(); + } catch (std::exception &ex) { + signaling_server[ssl] = nullptr; + WarnL << ex.what(); + return 0; } - -private: - std::string _url; -}; -#endif - -API_EXPORT void API_CALL mk_webrtc_get_answer_sdp(void *user_data, on_mk_webrtc_get_answer_sdp cb, const char *type, - const char *offer, const char *url) { - mk_webrtc_get_answer_sdp2(user_data, nullptr, cb, type, offer, url); -} -API_EXPORT void API_CALL mk_webrtc_get_answer_sdp2(void *user_data, on_user_data_free user_data_free, on_mk_webrtc_get_answer_sdp cb, const char *type, - const char *offer, const char *url) { -#ifdef ENABLE_WEBRTC - assert(type && offer && url && cb); - auto session = std::make_shared(Socket::createSocket()); - 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().negotiateSdp(*session, type, *args, [offer_str, session, ptr, cb](const WebRtcInterface &exchanger) mutable { - auto &handler = const_cast(exchanger); - try { - auto sdp_answer = handler.getAnswerSdp(offer_str); - cb(ptr.get(), sdp_answer.data(), nullptr); - } catch (std::exception &ex) { - cb(ptr.get(), nullptr, ex.what()); - } - }); #else WarnL << "未启用webrtc功能, 编译时请开启ENABLE_WEBRTC"; + return 0; +#endif +} + +API_EXPORT uint16_t API_CALL mk_ice_server_start(uint16_t port){ +#ifdef ENABLE_WEBRTC + try { + iceServer_tcp = std::make_shared(); + iceServer_udp = std::make_shared(); + iceServer_udp->start(port); + iceServer_tcp->start(port); + } catch (std::exception &ex) { + iceServer_udp = nullptr; + iceServer_tcp = nullptr; + WarnL << ex.what(); + return 0; + } +#else + WarnL << "未启用webrtc功能, 编译时请开启ENABLE_WEBRTC"; + return 0; #endif } diff --git a/api/source/mk_webrtc.cpp b/api/source/mk_webrtc.cpp new file mode 100644 index 00000000..0aa089d6 --- /dev/null +++ b/api/source/mk_webrtc.cpp @@ -0,0 +1,187 @@ +/* + * Copyright (c) 2016-present The ZLMediaKit project authors. All Rights Reserved. + * + * This file is part of ZLMediaKit(https://github.com/ZLMediaKit/ZLMediaKit). + * + * Use of this source code is governed by MIT-like license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. + */ + +#include "mk_webrtc.h" +#include "mk_util.h" + +#include +#include +#include "Util/logger.h" +#include "Util/SSLBox.h" +#include "Util/File.h" +#include "Network/TcpServer.h" +#include "Network/UdpServer.h" +#include "Thread/WorkThreadPool.h" + +#include "Rtsp/RtspSession.h" +#include "Rtmp/RtmpSession.h" +#include "Http/HttpSession.h" +#include "Shell/ShellSession.h" +#include "Player/PlayerProxy.h" +#include "webrtc/WebRtcProxyPlayer.h" +#include "webrtc/WebRtcProxyPlayerImp.h" +#include "../webrtc/WebRtcSignalingPeer.h" +#include "../webrtc/WebRtcSignalingSession.h" +using namespace std; +using namespace toolkit; +using namespace mediakit; + +#ifdef ENABLE_WEBRTC +#include "../webrtc/WebRtcSession.h" +static UdpServer::Ptr rtcServer_udp; +static TcpServer::Ptr rtcServer_tcp; +class WebRtcArgsUrl : public mediakit::WebRtcArgs { +public: + WebRtcArgsUrl(std::string url) { _url = std::move(url); } + + toolkit::variant operator[](const std::string &key) const override { + if (key == "url") { + return _url; + } + return ""; + } + +private: + std::string _url; +}; +#endif + +API_EXPORT void API_CALL mk_webrtc_get_answer_sdp(void *user_data, on_mk_webrtc_get_answer_sdp cb, const char *type, const char *offer, const char *url) { + mk_webrtc_get_answer_sdp2(user_data, nullptr, cb, type, offer, url); +} +API_EXPORT void API_CALL mk_webrtc_get_answer_sdp2( + void *user_data, on_user_data_free user_data_free, on_mk_webrtc_get_answer_sdp cb, const char *type, const char *offer, const char *url) { +#ifdef ENABLE_WEBRTC + assert(type && offer && url && cb); + auto session = std::make_shared(Socket::createSocket()); + 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().negotiateSdp(*session, type, *args, [offer_str, session, ptr, cb](const WebRtcInterface &exchanger) mutable { + auto &handler = const_cast(exchanger); + try { + auto sdp_answer = handler.getAnswerSdp(offer_str); + cb(ptr.get(), sdp_answer.data(), nullptr); + } catch (std::exception &ex) { + cb(ptr.get(), nullptr, ex.what()); + } + }); +#else + WarnL << "未启用webrtc功能, 编译时请开启ENABLE_WEBRTC"; +#endif +} + +API_EXPORT void API_CALL mk_webrtc_get_proxy_player_info(mk_proxy_player ctx, on_mk_webrtc_get_proxy_player_info_cb cb) { +#ifdef ENABLE_WEBRTC + assert(ctx && cb); + PlayerProxy::Ptr *obj = (PlayerProxy::Ptr *)ctx; + auto media_player = obj->get()->getDelegate(); + if (!media_player) { + cb(nullptr, "Media player not found"); + return; + } + + auto webrtc_player_imp = std::dynamic_pointer_cast(media_player); + if (!webrtc_player_imp) { + cb(nullptr, "Stream proxy is not WebRTC type"); + return; + } + + auto webrtc_transport = webrtc_player_imp->getWebRtcTransport(); + if (!webrtc_transport) { + cb(nullptr, "WebRTC transport not available"); + return; + } + + webrtc_transport->getTransportInfo([cb](Json::Value transport_info) mutable { + if (transport_info.isMember("error")) { + cb(nullptr, strdup(transport_info["error"].asCString())); + return; + } + cb(strdup(transport_info.toStyledString().c_str()), ""); + }); +#else + WarnL << "未启用webrtc功能, 编译时请开启ENABLE_WEBRTC"; +#endif +} + +API_EXPORT void API_CALL mk_webrtc_add_room_keeper( + const char *room_id, const char *server_host, uint16_t server_port, int ssl, on_mk_webrtc_room_keeper_info_cb cb, void *user_data) { + mk_webrtc_add_room_keeper2(room_id, server_host, server_port, ssl, cb, user_data, nullptr); +} + +API_EXPORT void API_CALL mk_webrtc_add_room_keeper2( + const char *room_id, const char *server_host, uint16_t server_port, int ssl, on_mk_webrtc_room_keeper_info_cb cb, void *user_data, + on_user_data_free user_data_free) { +#ifdef ENABLE_WEBRTC + assert(server_host && server_port && room_id && cb); + // server_host: 信令服务器host + // server_post: 信令服务器host + // room_id: 注册的id,信令服务器会对该id进行唯一性检查 + std::string server_host_str(server_host), room_id_str(room_id); + std::shared_ptr ptr(user_data, user_data_free ? user_data_free : [](void *) {}); + addWebrtcRoomKeeper(server_host_str, server_port, room_id_str, ssl, [ptr,cb](const SockException &ex, const string &key) mutable { + if (ex) { + cb(ptr.get(), nullptr, ex.what()); + } else { + cb(ptr.get(), key.c_str(), nullptr); + } + }); +#else + WarnL << "未启用webrtc功能, 编译时请开启ENABLE_WEBRTC"; +#endif +} + +API_EXPORT void API_CALL mk_webrtc_del_room_keeper(const char *room_key, on_mk_webrtc_room_keeper_info_cb cb, void *user_data) { + mk_webrtc_del_room_keeper2(room_key,cb,user_data,nullptr); +} + +API_EXPORT void API_CALL +mk_webrtc_del_room_keeper2(const char *room_key, on_mk_webrtc_room_keeper_info_cb cb, void *user_data, on_user_data_free user_data_free) { +#ifdef ENABLE_WEBRTC + assert(room_key && cb); + std::string room_key_str(room_key); + std::shared_ptr ptr(user_data, user_data_free ? user_data_free : [](void *) {}); + delWebrtcRoomKeeper(room_key_str, [room_key_str, ptr, cb](const SockException &ex) mutable { + if (ex) { + cb(ptr.get(), room_key_str.c_str(), ex.what()); + } + cb(ptr.get(), room_key_str.c_str(), nullptr); + }); +#else + WarnL << "未启用webrtc功能, 编译时请开启ENABLE_WEBRTC"; +#endif +} + +API_EXPORT void API_CALL mk_webrtc_list_room_keeper(on_mk_webrtc_room_keeper_data_cb cb) { +#ifdef ENABLE_WEBRTC + assert(cb); + listWebrtcRoomKeepers([cb](const std::string &key, const WebRtcSignalingPeer::Ptr &p) { + Json::Value item = ToJson(p); + item["room_key"] = key; + cb(strdup(item.toStyledString().c_str())); + }); +#else + WarnL << "未启用webrtc功能, 编译时请开启ENABLE_WEBRTC"; +#endif +} + +API_EXPORT void API_CALL mk_webrtc_list_rooms(on_mk_webrtc_room_keeper_data_cb cb){ +#ifdef ENABLE_WEBRTC + assert(cb); + listWebrtcRooms([cb](const std::string &key, const WebRtcSignalingSession::Ptr &p) { + Json::Value item = ToJson(p); + item["room_id"] = key; + cb(strdup(item.toStyledString().c_str())); + }); +#else + WarnL << "未启用webrtc功能, 编译时请开启ENABLE_WEBRTC"; +#endif +} \ No newline at end of file diff --git a/webrtc/WebRtcClient.cpp b/webrtc/WebRtcClient.cpp index 3cd40b04..54608817 100755 --- a/webrtc/WebRtcClient.cpp +++ b/webrtc/WebRtcClient.cpp @@ -154,6 +154,7 @@ void WebRtcClient::doNegotiateWhepOrWhip() { _negotiate = make_shared(); _negotiate->setMethod("POST"); + _negotiate->addHeader("Content-Type", "application/sdp"); _negotiate->setBody(std::move(offer_sdp)); _negotiate->startRequester(_url._negotiate_url, [weak_self](const toolkit::SockException &ex, const Parser &response) { auto strong_self = weak_self.lock();