yituo_video/src/main.cpp
2025-09-10 13:15:42 +08:00

155 lines
4.8 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// main.cpp
#include "app_config.hpp"
#include "rtsp_manager.hpp"
#include "logger.hpp"
#include "mqtt_client_wrapper.hpp"
#include <thread>
#include <atomic>
#include <csignal>
#include <unistd.h> // write, STDOUT_FILENO
#include <chrono>
// 可通过这些开关快速启用/禁用线程进行调试
constexpr bool ENABLE_RTSP_THREAD = false; // 设置为 false 禁用 RTSP 线程
constexpr bool ENABLE_MQTT_THREAD = true; // 设置为 false 禁用 MQTT 线程
std::atomic<bool> g_running(true);
static void minimal_signal_handler(int signum)
{
// 只做非常有限且 async-signal-safe 的操作
g_running.store(false, std::memory_order_relaxed);
const char msg[] = "[MAIN] Signal received, initiating shutdown...\n";
write(STDERR_FILENO, msg, sizeof(msg) - 1);
// 不要调用 LOG_*、malloc、std::string、mutex、exit 等
}
int main()
{
// 安装信号处理SIGINT 和 SIGTERM
struct sigaction sigAct{};
sigAct.sa_handler = minimal_signal_handler;
sigemptyset(&sigAct.sa_mask);
sigAct.sa_flags = 0;
sigaction(SIGINT, &sigAct, nullptr);
sigaction(SIGTERM, &sigAct, nullptr);
signal(SIGPIPE, SIG_IGN);
// 初始化日志文件
Logger::set_log_to_file(get_executable_dir_file_path("app.log"));
try
{
// 从可执行文件所在目录读取配置文件
g_app_config = AppConfig::load_from_file(get_executable_dir_file_path("config.json"));
}
catch (const std::exception &e)
{
LOG_ERROR(std::string("Failed to load config: ") + e.what());
return -1;
}
// 线程退出标志,用于超时等待
std::atomic<bool> rtsp_thread_exited(false);
std::atomic<bool> mqtt_thread_exited(false);
// 先在主线程初始化 GStreamer
RTSPManager::init();
std::thread rtsp_thread;
std::thread mqtt_thread;
// 启动 RTSP 线程(如果启用)
if (ENABLE_RTSP_THREAD)
{
rtsp_thread = std::thread([&]()
{
RTSPManager::start(g_app_config.cameras);
rtsp_thread_exited.store(true, std::memory_order_relaxed); });
LOG_INFO("[MAIN] RTSP thread started");
}
else
{
LOG_INFO("[MAIN] RTSP thread disabled by build-time toggle");
}
// 启动 MQTT 线程(如果启用)
if (ENABLE_MQTT_THREAD)
{
mqtt_thread = std::thread([&]()
{
mqtt_client_thread_func();
mqtt_thread_exited.store(true, std::memory_order_relaxed); });
LOG_INFO("[MAIN] MQTT thread started");
}
else
{
LOG_INFO("[MAIN] MQTT thread disabled by build-time toggle");
}
// 等待退出信号
while (g_running.load(std::memory_order_relaxed))
std::this_thread::sleep_for(std::chrono::milliseconds(200));
LOG_INFO("[MAIN] Shutdown requested, stopping services...");
// 等线程优雅退出:总等待时间 (可调整)
const auto max_wait = std::chrono::seconds(5);
const auto poll_interval = std::chrono::milliseconds(100);
auto deadline = std::chrono::steady_clock::now() + max_wait;
if (ENABLE_RTSP_THREAD)
{
RTSPManager::stop();
auto stop_deadline = std::chrono::steady_clock::now() + std::chrono::seconds(10);
while (RTSPManager::is_any_streaming() && std::chrono::steady_clock::now() < stop_deadline)
{
std::this_thread::sleep_for(std::chrono::milliseconds(50));
}
if (rtsp_thread.joinable())
rtsp_thread.join();
}
// 重置 MQTT 线程等待的截止时间
deadline = std::chrono::steady_clock::now() + max_wait;
if (ENABLE_MQTT_THREAD)
{
while (!mqtt_thread_exited.load(std::memory_order_relaxed) &&
std::chrono::steady_clock::now() < deadline)
{
std::this_thread::sleep_for(poll_interval);
}
if (mqtt_thread.joinable())
{
if (mqtt_thread_exited.load(std::memory_order_relaxed))
{
mqtt_thread.join();
LOG_INFO("[MAIN] MQTT thread finished and joined.");
}
else
{
LOG_WARN("[MAIN] MQTT thread did not exit within timeout.");
}
}
}
// 如果有线程仍未退出,则强制终止
bool any_failed = false;
if (ENABLE_RTSP_THREAD && rtsp_thread.joinable() && !rtsp_thread_exited.load(std::memory_order_relaxed))
any_failed = true;
if (ENABLE_MQTT_THREAD && mqtt_thread.joinable() && !mqtt_thread_exited.load(std::memory_order_relaxed))
any_failed = true;
if (any_failed)
{
LOG_ERROR("[MAIN] Threads did not exit in time. Forcing immediate termination.");
_exit(1);
}
LOG_INFO("[MAIN] Program exited cleanly.");
return 0;
}