2019-12-18 11:47:49 +08:00
|
|
|
|
/*
|
2023-12-09 16:23:51 +08:00
|
|
|
|
* Copyright (c) 2016-present The ZLMediaKit project authors. All Rights Reserved.
|
2019-12-17 18:45:31 +08:00
|
|
|
|
*
|
2023-12-09 16:23:51 +08:00
|
|
|
|
* This file is part of ZLMediaKit(https://github.com/ZLMediaKit/ZLMediaKit).
|
2019-12-17 18:45:31 +08:00
|
|
|
|
*
|
2023-12-09 16:23:51 +08:00
|
|
|
|
* Use of this source code is governed by MIT-like license that can be found in the
|
2020-04-04 20:30:09 +08:00
|
|
|
|
* 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.
|
2019-12-17 18:45:31 +08:00
|
|
|
|
*/
|
|
|
|
|
|
2022-02-02 20:34:50 +08:00
|
|
|
|
#include <cstdarg>
|
|
|
|
|
#include <cassert>
|
|
|
|
|
|
2019-12-27 10:10:31 +08:00
|
|
|
|
#include "mk_util.h"
|
2021-10-18 15:09:02 +08:00
|
|
|
|
#include "Util/util.h"
|
2023-02-11 11:39:26 +08:00
|
|
|
|
#include "Util/mini.h"
|
2019-12-27 10:10:31 +08:00
|
|
|
|
#include "Util/logger.h"
|
2024-05-19 10:30:29 +08:00
|
|
|
|
#include "Util/TimeTicker.h"
|
|
|
|
|
#include "Poller/EventPoller.h"
|
|
|
|
|
#include "Thread/WorkThreadPool.h"
|
2023-02-11 11:39:26 +08:00
|
|
|
|
#include "Common/config.h"
|
2022-02-02 20:34:50 +08:00
|
|
|
|
|
2019-12-27 10:10:31 +08:00
|
|
|
|
using namespace std;
|
|
|
|
|
using namespace toolkit;
|
2023-02-11 11:39:26 +08:00
|
|
|
|
using namespace mediakit;
|
2019-12-27 10:10:31 +08:00
|
|
|
|
|
2023-02-11 11:39:26 +08:00
|
|
|
|
API_EXPORT void API_CALL mk_free(void *ptr) {
|
|
|
|
|
free(ptr);
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-27 10:10:31 +08:00
|
|
|
|
API_EXPORT char* API_CALL mk_util_get_exe_path(){
|
2021-01-17 18:31:50 +08:00
|
|
|
|
return _strdup(exePath().data());
|
2019-12-27 10:10:31 +08:00
|
|
|
|
}
|
|
|
|
|
|
2020-02-21 11:35:53 +08:00
|
|
|
|
API_EXPORT char* API_CALL mk_util_get_exe_dir(const char *relative_path){
|
2019-12-27 10:10:31 +08:00
|
|
|
|
if(relative_path){
|
2021-01-17 18:31:50 +08:00
|
|
|
|
return _strdup((exeDir() + relative_path).data());
|
2019-12-27 10:10:31 +08:00
|
|
|
|
}
|
2021-01-17 18:31:50 +08:00
|
|
|
|
return _strdup(exeDir().data());
|
2019-12-27 10:10:31 +08:00
|
|
|
|
}
|
|
|
|
|
|
2020-02-21 11:35:53 +08:00
|
|
|
|
API_EXPORT uint64_t API_CALL mk_util_get_current_millisecond(){
|
2019-12-27 10:10:31 +08:00
|
|
|
|
return getCurrentMillisecond();
|
|
|
|
|
}
|
|
|
|
|
|
2020-02-21 11:35:53 +08:00
|
|
|
|
API_EXPORT char* API_CALL mk_util_get_current_time_string(const char *fmt){
|
2019-12-27 10:10:31 +08:00
|
|
|
|
assert(fmt);
|
2021-01-17 18:31:50 +08:00
|
|
|
|
return _strdup(getTimeStr(fmt).data());
|
2019-12-27 10:10:31 +08:00
|
|
|
|
}
|
|
|
|
|
|
2020-02-21 11:35:53 +08:00
|
|
|
|
API_EXPORT char* API_CALL mk_util_hex_dump(const void *buf, int len){
|
2019-12-27 10:10:31 +08:00
|
|
|
|
assert(buf && len > 0);
|
2021-01-17 18:31:50 +08:00
|
|
|
|
return _strdup(hexdump(buf,len).data());
|
2019-12-27 10:10:31 +08:00
|
|
|
|
}
|
|
|
|
|
|
2023-02-11 11:39:26 +08:00
|
|
|
|
API_EXPORT mk_ini API_CALL mk_ini_create() {
|
2023-02-26 21:45:14 +08:00
|
|
|
|
return (mk_ini)new mINI;
|
2023-02-11 11:39:26 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
API_EXPORT mk_ini API_CALL mk_ini_default() {
|
2023-02-26 21:45:14 +08:00
|
|
|
|
return (mk_ini)&(mINI::Instance());
|
2023-02-11 11:39:26 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void emit_ini_file_reload(mk_ini ini) {
|
|
|
|
|
if (ini == mk_ini_default()) {
|
|
|
|
|
// 广播配置文件热加载
|
2023-09-02 10:52:07 +08:00
|
|
|
|
NOTICE_EMIT(BroadcastReloadConfigArgs, Broadcast::kBroadcastReloadConfig);
|
2023-02-11 11:39:26 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
API_EXPORT void API_CALL mk_ini_load_string(mk_ini ini, const char *str) {
|
|
|
|
|
assert(str);
|
|
|
|
|
auto ptr = (mINI *)ini;
|
|
|
|
|
ptr->parse(str);
|
|
|
|
|
emit_ini_file_reload(ini);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
API_EXPORT void API_CALL mk_ini_load_file(mk_ini ini, const char *file) {
|
|
|
|
|
assert(file);
|
|
|
|
|
auto ptr = (mINI *)ini;
|
|
|
|
|
ptr->parseFile(file);
|
|
|
|
|
emit_ini_file_reload(ini);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
API_EXPORT void API_CALL mk_ini_release(mk_ini ini) {
|
|
|
|
|
assert(ini);
|
|
|
|
|
delete (mINI *)ini;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
API_EXPORT void API_CALL mk_ini_set_option(mk_ini ini, const char *key, const char *value) {
|
|
|
|
|
assert(ini && key && value);
|
|
|
|
|
auto ptr = (mINI *)ini;
|
|
|
|
|
(*ptr)[key] = value;
|
|
|
|
|
emit_ini_file_reload(ini);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
API_EXPORT void API_CALL mk_ini_set_option_int(mk_ini ini, const char *key, int value) {
|
|
|
|
|
assert(ini && key);
|
|
|
|
|
auto ptr = (mINI *)ini;
|
|
|
|
|
(*ptr)[key] = value;
|
|
|
|
|
emit_ini_file_reload(ini);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
API_EXPORT const char *API_CALL mk_ini_get_option(mk_ini ini, const char *key) {
|
|
|
|
|
assert(ini && key);
|
|
|
|
|
auto ptr = (mINI *)ini;
|
|
|
|
|
auto it = ptr->find(key);
|
|
|
|
|
if (it == ptr->end()) {
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
return it->second.data();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
API_EXPORT int API_CALL mk_ini_del_option(mk_ini ini, const char *key) {
|
|
|
|
|
assert(ini && key);
|
|
|
|
|
auto ptr = (mINI *)ini;
|
|
|
|
|
auto it = ptr->find(key);
|
|
|
|
|
if (it == ptr->end()) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
ptr->erase(it);
|
|
|
|
|
emit_ini_file_reload(ini);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
API_EXPORT char *API_CALL mk_ini_dump_string(mk_ini ini) {
|
|
|
|
|
assert(ini);
|
|
|
|
|
auto ptr = (mINI *)ini;
|
|
|
|
|
return _strdup(ptr->dump().data());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
API_EXPORT void API_CALL mk_ini_dump_file(mk_ini ini, const char *file) {
|
|
|
|
|
assert(ini && file);
|
|
|
|
|
auto ptr = (mINI *)ini;
|
|
|
|
|
ptr->dumpFile(file);
|
|
|
|
|
}
|
|
|
|
|
|
2024-05-19 10:30:29 +08:00
|
|
|
|
extern uint64_t getTotalMemUsage();
|
|
|
|
|
extern uint64_t getTotalMemBlock();
|
|
|
|
|
extern uint64_t getThisThreadMemUsage();
|
|
|
|
|
extern uint64_t getThisThreadMemBlock();
|
|
|
|
|
extern std::vector<size_t> getBlockTypeSize();
|
|
|
|
|
extern uint64_t getTotalMemBlockByType(int type);
|
|
|
|
|
extern uint64_t getThisThreadMemBlockByType(int type);
|
|
|
|
|
|
|
|
|
|
namespace mediakit {
|
|
|
|
|
class MediaSource;
|
|
|
|
|
class MultiMediaSourceMuxer;
|
|
|
|
|
class FrameImp;
|
|
|
|
|
class Frame;
|
|
|
|
|
class RtpPacket;
|
|
|
|
|
class RtmpPacket;
|
|
|
|
|
} // namespace mediakit
|
|
|
|
|
|
|
|
|
|
namespace toolkit {
|
|
|
|
|
class TcpServer;
|
|
|
|
|
class TcpSession;
|
|
|
|
|
class UdpServer;
|
|
|
|
|
class UdpSession;
|
|
|
|
|
class TcpClient;
|
|
|
|
|
class Socket;
|
|
|
|
|
class Buffer;
|
|
|
|
|
class BufferRaw;
|
|
|
|
|
class BufferLikeString;
|
|
|
|
|
class BufferList;
|
|
|
|
|
} // namespace toolkit
|
|
|
|
|
|
|
|
|
|
API_EXPORT void API_CALL mk_get_statistic(on_mk_get_statistic_cb func, void *user_data, on_user_data_free free_cb) {
|
|
|
|
|
assert(func);
|
|
|
|
|
std::shared_ptr<void> data(user_data, free_cb);
|
|
|
|
|
auto cb = [func, data](const toolkit::mINI &ini) { func(data.get(), (mk_ini)&ini); };
|
|
|
|
|
auto obj = std::make_shared<toolkit::mINI>();
|
|
|
|
|
auto &val = *obj;
|
|
|
|
|
|
|
|
|
|
val["object.MediaSource"] = ObjectStatistic<MediaSource>::count();
|
|
|
|
|
val["object.MultiMediaSourceMuxer"] = ObjectStatistic<MultiMediaSourceMuxer>::count();
|
|
|
|
|
|
|
|
|
|
val["object.TcpServer"] = ObjectStatistic<TcpServer>::count();
|
|
|
|
|
val["object.TcpSession"] = ObjectStatistic<TcpSession>::count();
|
|
|
|
|
val["object.UdpServer"] = ObjectStatistic<UdpServer>::count();
|
|
|
|
|
val["object.UdpSession"] = ObjectStatistic<UdpSession>::count();
|
|
|
|
|
val["object.TcpClient"] = ObjectStatistic<TcpClient>::count();
|
|
|
|
|
val["object.Socket"] = ObjectStatistic<Socket>::count();
|
|
|
|
|
|
|
|
|
|
val["object.FrameImp"] = ObjectStatistic<FrameImp>::count();
|
|
|
|
|
val["object.Frame"] = ObjectStatistic<Frame>::count();
|
|
|
|
|
|
|
|
|
|
val["object.Buffer"] = ObjectStatistic<Buffer>::count();
|
|
|
|
|
val["object.BufferRaw"] = ObjectStatistic<BufferRaw>::count();
|
|
|
|
|
val["object.BufferLikeString"] = ObjectStatistic<BufferLikeString>::count();
|
|
|
|
|
val["object.BufferList"] = ObjectStatistic<BufferList>::count();
|
|
|
|
|
|
|
|
|
|
val["object.RtpPacket"] = ObjectStatistic<RtpPacket>::count();
|
|
|
|
|
val["object.RtmpPacket"] = ObjectStatistic<RtmpPacket>::count();
|
|
|
|
|
#ifdef ENABLE_MEM_DEBUG
|
|
|
|
|
auto bytes = getTotalMemUsage();
|
|
|
|
|
val["memory.memUsage"] = bytes;
|
|
|
|
|
val["memory.memUsageMB"] = (int)(bytes / 1024 / 1024);
|
|
|
|
|
val["memory.memBlock"] = getTotalMemBlock();
|
|
|
|
|
static auto block_type_size = getBlockTypeSize();
|
|
|
|
|
{
|
|
|
|
|
int i = 0;
|
|
|
|
|
string str;
|
|
|
|
|
size_t last = 0;
|
|
|
|
|
for (auto sz : block_type_size) {
|
|
|
|
|
str.append(to_string(last) + "~" + to_string(sz) + ":" + to_string(getTotalMemBlockByType(i++)) + ";");
|
|
|
|
|
last = sz;
|
|
|
|
|
}
|
|
|
|
|
str.pop_back();
|
|
|
|
|
val["memory.memBlockTypeCount"] = str;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
auto thread_size = EventPollerPool::Instance().getExecutorSize() + WorkThreadPool::Instance().getExecutorSize();
|
|
|
|
|
std::shared_ptr<vector<toolkit::mINI>> thread_mem_info = std::make_shared<vector<toolkit::mINI>>(thread_size);
|
|
|
|
|
|
|
|
|
|
shared_ptr<void> finished(nullptr, [thread_mem_info, cb, obj](void *) {
|
|
|
|
|
for (auto &val : *thread_mem_info) {
|
|
|
|
|
auto thread_name = val["name"];
|
|
|
|
|
replace(thread_name, "...", "~~~");
|
|
|
|
|
auto prefix = "thread-" + thread_name + ".";
|
|
|
|
|
for (auto &pr : val) {
|
|
|
|
|
(*obj).emplace(prefix + pr.first, std::move(pr.second));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// 触发回调
|
|
|
|
|
cb(*obj);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
auto pos = 0;
|
|
|
|
|
auto lambda = [&](const TaskExecutor::Ptr &executor) {
|
|
|
|
|
auto &val = (*thread_mem_info)[pos++];
|
|
|
|
|
val["load"] = executor->load();
|
|
|
|
|
Ticker ticker;
|
|
|
|
|
executor->async([finished, &val, ticker]() {
|
|
|
|
|
val["name"] = getThreadName();
|
|
|
|
|
val["delay"] = ticker.elapsedTime();
|
|
|
|
|
#ifdef ENABLE_MEM_DEBUG
|
|
|
|
|
auto bytes = getThisThreadMemUsage();
|
|
|
|
|
val["memUsage"] = bytes;
|
|
|
|
|
val["memUsageMB"] = bytes / 1024 / 1024;
|
|
|
|
|
val["memBlock"] = getThisThreadMemBlock();
|
|
|
|
|
{
|
|
|
|
|
int i = 0;
|
|
|
|
|
string str;
|
|
|
|
|
size_t last = 0;
|
|
|
|
|
for (auto sz : block_type_size) {
|
|
|
|
|
str.append(to_string(last) + "~" + to_string(sz) + ":" + to_string(getThisThreadMemBlockByType(i++)) + ";");
|
|
|
|
|
last = sz;
|
|
|
|
|
}
|
|
|
|
|
str.pop_back();
|
|
|
|
|
val["memBlockTypeCount"] = str;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
EventPollerPool::Instance().for_each(lambda);
|
|
|
|
|
WorkThreadPool::Instance().for_each(lambda);
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-27 10:10:31 +08:00
|
|
|
|
API_EXPORT void API_CALL mk_log_printf(int level, const char *file, const char *function, int line, const char *fmt, ...) {
|
2021-10-18 15:09:02 +08:00
|
|
|
|
va_list ap;
|
|
|
|
|
va_start(ap, fmt);
|
2022-01-10 19:57:26 +08:00
|
|
|
|
toolkit::LoggerWrapper::printLogV(getLogger(), level, file, function, line, fmt, ap);
|
2021-10-18 15:09:02 +08:00
|
|
|
|
va_end(ap);
|
2019-12-27 10:10:31 +08:00
|
|
|
|
}
|
|
|
|
|
|