Merge branch 'master' of https://github.com/ZLMediaKit/ZLMediaKit into feature/transcode2

# Conflicts:
#	conf/config.ini
#	src/Codec/Transcode.cpp
#	src/Common/MediaSource.h
#	src/Common/MultiMediaSourceMuxer.cpp
#	src/Common/MultiMediaSourceMuxer.h
#	src/Common/macros.h
#	webrtc/WebRtcPusher.cpp
#	webrtc/WebRtcTransport.cpp
#	webrtc/WebRtcTransport.h
This commit is contained in:
cqm
2026-04-03 09:35:50 +08:00
283 changed files with 42056 additions and 13083 deletions

View File

@@ -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)
@@ -76,6 +82,9 @@ API_EXPORT void API_CALL mk_stop_all_server(){
#ifdef ENABLE_WEBRTC
rtcServer_udp = nullptr;
rtcServer_tcp = nullptr;
iceServer_udp = nullptr;
iceServer_tcp = nullptr;
CLEAR_ARR(signaling_server);
#endif
#ifdef ENABLE_SRT
srtServer = nullptr;
@@ -288,46 +297,46 @@ 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<TcpServer>();
if (ssl) {
signaling_server[ssl]->start<WebRtcWebcosktSignalSslSession>(port);
} else {
signaling_server[ssl]->start<WebRtcWebcosktSignalingSession>(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<HttpSession>(Socket::createSocket());
std::string offer_str = offer;
std::shared_ptr<void> ptr(user_data, user_data_free ? user_data_free : [](void *) {});
auto args = std::make_shared<WebRtcArgsUrl>(url);
WebRtcPluginManager::Instance().negotiateSdp(*session, type, *args, [offer_str, session, ptr, cb](const WebRtcInterface &exchanger) mutable {
auto &handler = const_cast<WebRtcInterface &>(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<TcpServer>();
iceServer_udp = std::make_shared<UdpServer>();
iceServer_udp->start<IceSession>(port);
iceServer_tcp->start<IceSession>(port);
return 0;
} catch (std::exception &ex) {
iceServer_udp = nullptr;
iceServer_tcp = nullptr;
WarnL << ex.what();
return 0;
}
#else
WarnL << "未启用webrtc功能, 编译时请开启ENABLE_WEBRTC";
return 0;
#endif
}

View File

@@ -296,6 +296,13 @@ API_EXPORT int API_CALL mk_media_source_seek_to(const mk_media_source ctx,uint32
MediaSource *src = (MediaSource *)ctx;
return src->seekTo(stamp);
}
API_EXPORT void API_CALL mk_media_source_set_speed(const mk_media_source ctx, float speed) {
assert(ctx);
MediaSource *src = (MediaSource *)ctx;
src->getOwnerPoller()->async([=]() mutable { src->speed(speed); });
}
API_EXPORT void API_CALL mk_media_source_start_send_rtp(const mk_media_source ctx, const char *dst_url, uint16_t dst_port, const char *ssrc, int con_type, on_mk_media_source_send_rtp_result cb, void *user_data) {
mk_media_source_start_send_rtp2(ctx, dst_url, dst_port, ssrc, con_type, cb, user_data, nullptr);
}
@@ -347,6 +354,7 @@ API_EXPORT void API_CALL mk_media_source_start_send_rtp4(const mk_media_source c
args.close_delay_ms = (*ini_ptr)["close_delay_ms"].empty() ? 0 : (*ini_ptr)["close_delay_ms"].as<int>();
args.rtcp_timeout_ms = (*ini_ptr)["rtcp_timeout_ms"].empty() ? 30000 : (*ini_ptr)["rtcp_timeout_ms"].as<int>();
args.rtcp_send_interval_ms = (*ini_ptr)["rtcp_send_interval_ms"].empty() ? 5000 : (*ini_ptr)["rtcp_send_interval_ms"].as<int>();
args.enable_origin_recv_limit = (*ini_ptr)["enable_origin_recv_limit"].empty() ? false : (*ini_ptr)["enable_origin_recv_limit"].as<bool>();
std::shared_ptr<void> ptr(
user_data, user_data_free ? user_data_free : [](void *) {});
src->getOwnerPoller()->async([=]() mutable {

View File

@@ -11,6 +11,7 @@
#include "mk_frame.h"
#include "Record/MPEG.h"
#include "Extension/Factory.h"
#include "Rtp/PSDecoder.h"
using namespace mediakit;
@@ -223,4 +224,36 @@ API_EXPORT int API_CALL mk_mpeg_muxer_input_frame(mk_mpeg_muxer ctx, mk_frame fr
assert(ctx && frame);
auto ptr = reinterpret_cast<MpegMuxerForC *>(ctx);
return ptr->inputFrame(*((Frame::Ptr *) frame));
}
}
//////////////////////////////////////////////////////////////////////
#if defined(ENABLE_RTPPROXY)
API_EXPORT mk_ps_decoder API_CALL mk_ps_decoder_create(on_mk_ps_decoder_stream scb, on_mk_ps_decoder_frame dcb, void * user_data) {
assert(dcb);
auto ps_decoder = new PSDecoder();
std::shared_ptr<void> ptr(user_data, [](void *) {});
if (scb) {
ps_decoder->setOnStream([ptr,scb](int stream, int codecid, const void *extra, size_t bytes, int finish) {
scb(ptr.get(), stream, getCodecByMpegId(codecid), extra, bytes, finish);
});
}
ps_decoder->setOnDecode([ptr,dcb](int stream, int codecid, int flags, int64_t pts, int64_t dts, const void *data, size_t bytes) {
dcb(ptr.get(), stream,getCodecByMpegId(codecid),flags,pts,dts,data,bytes);
});
return reinterpret_cast<mk_ps_decoder>(ps_decoder);
}
API_EXPORT void API_CALL mk_ps_decoder_release(mk_ps_decoder ctx) {
assert(ctx);
auto ptr = reinterpret_cast<PSDecoder *>(ctx);
delete ptr;
}
API_EXPORT void API_CALL mk_ps_decoder_input(mk_ps_decoder ctx, const char * data, size_t bytes) {
assert(ctx && data);
auto ptr = reinterpret_cast<PSDecoder *>(ctx);
ptr->input(reinterpret_cast<const uint8_t *>(data), bytes);
}
#endif

View File

@@ -309,7 +309,7 @@ API_EXPORT void API_CALL mk_media_start_send_rtp2(mk_media ctx, const char *dst_
auto ref = *obj;
std::shared_ptr<void> ptr(user_data, user_data_free ? user_data_free : [](void *) {});
(*obj)->getChannel()->getOwnerPoller(MediaSource::NullMediaSource())->async([args, ref, cb, ptr]() {
ref->getChannel()->startSendRtp(MediaSource::NullMediaSource(), args, [cb, ptr](uint16_t local_port, const SockException &ex) {
ref->getChannel()->getMuxer(MediaSource::NullMediaSource())->startSendRtp( args, [cb, ptr](uint16_t local_port, const SockException &ex) {
if (cb) {
cb(ptr.get(), local_port, ex.getErrCode(), ex.what());
}
@@ -343,13 +343,14 @@ API_EXPORT void API_CALL mk_media_start_send_rtp4(mk_media ctx, const char *dst_
args.close_delay_ms = (*ini_ptr)["close_delay_ms"].empty() ? 30000 : (*ini_ptr)["close_delay_ms"].as<int>();
args.rtcp_timeout_ms = (*ini_ptr)["rtcp_timeout_ms"].empty() ? 30000 : (*ini_ptr)["rtcp_timeout_ms"].as<int>();
args.rtcp_send_interval_ms = (*ini_ptr)["rtcp_send_interval_ms"].empty() ? 5000 : (*ini_ptr)["rtcp_send_interval_ms"].as<int>();
args.enable_origin_recv_limit = (*ini_ptr)["enable_origin_recv_limit"].empty() ? false : (*ini_ptr)["enable_origin_recv_limit"].as<bool>();
// sender参数无用 [AUTO-TRANSLATED:21590ae5]
// The sender parameter is useless
auto ref = *obj;
std::shared_ptr<void> ptr(
user_data, user_data_free ? user_data_free : [](void *) {});
(*obj)->getChannel()->getOwnerPoller(MediaSource::NullMediaSource())->async([args, ref, cb, ptr]() {
ref->getChannel()->startSendRtp(MediaSource::NullMediaSource(), args, [cb, ptr](uint16_t local_port, const SockException &ex) {
ref->getChannel()->getMuxer(MediaSource::NullMediaSource())->startSendRtp(args, [cb, ptr](uint16_t local_port, const SockException &ex) {
if (cb) {
cb(ptr.get(), local_port, ex.getErrCode(), ex.what());
}
@@ -365,7 +366,7 @@ API_EXPORT void API_CALL mk_media_stop_send_rtp(mk_media ctx, const char *ssrc)
auto ref = *obj;
string ssrc_str = ssrc ? ssrc : "";
(*obj)->getChannel()->getOwnerPoller(MediaSource::NullMediaSource())->async([ref, ssrc_str]() {
ref->getChannel()->stopSendRtp(MediaSource::NullMediaSource(), ssrc_str);
ref->getChannel()->getMuxer(MediaSource::NullMediaSource())->stopSendRtp(ssrc_str);
});
}

View File

@@ -85,6 +85,27 @@ API_EXPORT int API_CALL mk_recorder_stop(int type, const char *vhost, const char
return stopRecord((Recorder::type)type,vhost,app,stream);
}
API_EXPORT int API_CALL mk_recorder_start_task(const char *vhost, const char *app, const char *stream, const char *path, uint32_t back_ms, uint32_t forward_ms) {
assert(vhost && app && stream);
auto src = MediaSource::find(vhost, app, stream);
if (!src) {
WarnL << "未找到相关的MediaSource,startRecordTask失败:" << vhost << "/" << app << "/" << stream;
return false;
}
bool ret;
src->getOwnerPoller()->async([=]() mutable {
std::string err;
try {
src->getMuxer()->startRecord(path, back_ms, forward_ms);
} catch (std::exception &ex) {
err = ex.what();
WarnL << "MediaSource开启startRecordTask失败:" << vhost << "/" << app << "/" << stream << " what: " << err;
}
ret = err.empty();
});
return ret;
}
API_EXPORT void API_CALL mk_load_mp4_file(const char *vhost, const char *app, const char *stream, const char *file_path, int file_repeat) {
mINI ini;
mk_load_mp4_file2(vhost, app, stream, file_path, file_repeat, (mk_ini)&ini);

View File

@@ -31,6 +31,13 @@ API_EXPORT mk_rtp_server API_CALL mk_rtp_server_create2(uint16_t port, int tcp_m
return (mk_rtp_server)server;
}
API_EXPORT mk_rtp_server API_CALL mk_rtp_server_create3(uint16_t port, int tcp_mode, const char *vhost, const char *app, const char *stream_id, int multiplex) {
RtpServer::Ptr *server = new RtpServer::Ptr(new RtpServer);
GET_CONFIG(std::string, local_ip, General::kListenIP)
(*server)->start(port, local_ip.c_str(), MediaTuple { vhost, app, stream_id, "" }, (RtpServer::TcpMode)tcp_mode,multiplex);
return (mk_rtp_server)server;
}
API_EXPORT void API_CALL mk_rtp_server_connect(mk_rtp_server ctx, const char *dst_url, uint16_t dst_port, on_mk_rtp_server_connected cb, void *user_data) {
mk_rtp_server_connect2(ctx, dst_url, dst_port, cb, user_data, nullptr);
}
@@ -73,6 +80,41 @@ API_EXPORT void API_CALL mk_rtp_server_set_on_detach2(mk_rtp_server ctx, on_mk_r
}
}
API_EXPORT void API_CALL mk_rtp_server_update_ssrc(mk_rtp_server ctx, uint32_t ssrc) {
assert(ctx);
RtpServer::Ptr *server = (RtpServer::Ptr *)ctx;
(*server)->updateSSRC(ssrc);
}
API_EXPORT void API_CALL mk_rtp_get_info(const char *app, const char *stream, on_mk_rtp_get_info cb) {
assert(cb);
auto src = MediaSource::find(DEFAULT_VHOST, app, stream);
auto process = src ? src->getRtpProcess() : nullptr;
if (!process) {
cb(0, nullptr, 0, nullptr, 0, nullptr);
return;
}
SockInfo *info = process.get();
cb(1, info->get_local_ip().c_str(), info->get_peer_port(), info->get_local_ip().c_str(), info->get_local_port(), info->getIdentifier().c_str());
}
API_EXPORT void API_CALL mk_rtp_pause_check(const char *app, const char *stream) {
auto src = MediaSource::find(DEFAULT_VHOST, app, stream);
auto process = src ? src->getRtpProcess() : nullptr;
if (process) {
process->pauseRtpTimeout(true);
}
}
API_EXPORT void API_CALL mk_rtp_resume_check(const char *app, const char *stream) {
auto src = MediaSource::find(DEFAULT_VHOST, app, stream);
auto process = src ? src->getRtpProcess() : nullptr;
if (process) {
process->pauseRtpTimeout(false);
}
}
#else
API_EXPORT mk_rtp_server API_CALL mk_rtp_server_create(uint16_t port, int enable_tcp, const char *stream_id) {

190
api/source/mk_webrtc.cpp Normal file
View File

@@ -0,0 +1,190 @@
/*
* 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 <stdarg.h>
#include <unordered_map>
#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"
using namespace std;
using namespace toolkit;
using namespace mediakit;
#ifdef ENABLE_WEBRTC
#include "webrtc/WebRtcProxyPlayer.h"
#include "webrtc/WebRtcProxyPlayerImp.h"
#include "webrtc/WebRtcSignalingPeer.h"
#include "webrtc/WebRtcSignalingSession.h"
#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<HttpSession>(Socket::createSocket());
std::string offer_str = offer;
std::shared_ptr<void> ptr(user_data, user_data_free ? user_data_free : [](void *) {});
auto args = std::make_shared<WebRtcArgsUrl>(url);
WebRtcPluginManager::Instance().negotiateSdp(*session, type, *args, [offer_str, session, ptr, cb](const WebRtcInterface &exchanger) mutable {
auto &handler = const_cast<WebRtcInterface &>(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<WebRtcProxyPlayerImp>(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<void> 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<void> 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
}