#include "server.hpp" #include #include #include #include #include "dbc.hpp" using namespace fmt; FILE *run_ffmpeg(Config &config) { string ffmpeg_cmd = format("ffmpeg -listen 1 -i {} -bufsize 3000k", config.listen_at); for(auto &el : config.send_to) { SendTo send_spec = el.second; ffmpeg_cmd += format(" -maxrate {} -flags +global_header -c:v libx264 -preset veryfast -tune zerolatency -g:v 60 -vb {} -c:a copy -f flv {}", send_spec.bitrate, send_spec.bitrate, send_spec.url); } println("RUNNING: {}", ffmpeg_cmd); return popen(ffmpeg_cmd.c_str(), "re"); } bool Server::stopped() { return in_state(ServerState::STOP); } void Server::event(ServerEvent ev) { switch(_state) { FSM_STATE(ServerState, START, ev); FSM_STATE(ServerState, READING, ev); FSM_STATE(ServerState, STOP, ev); FSM_STATE(ServerState, ERROR, ev); } } void Server::START(ServerEvent ev) { handle = run_ffmpeg(config); if(handle == nullptr) { dbc::log("ERROR when launching ffmpeg"); state(ServerState::ERROR); } else { wait_time = 200ms; fail_count = 0; state(ServerState::READING); } } void Server::READING(ServerEvent ev) { res = fgets(buffer, BUF_MAX, handle); if(res == nullptr) { dbc::log("STOP shutting down..."); state(ServerState::STOP); } else { state(ServerState::READING); } } void Server::STOP(ServerEvent ev) { int rc = pclose(handle); if(rc != 0) { dbc::log("ERROR when calling pclose on ffmpeg"); state(ServerState::ERROR); } else { state(ServerState::STOP); } } void Server::ERROR(ServerEvent ev) { fail_count++; if(fail_count < config.fail_max) { println("Error in server, waiting {}...", wait_time); wait_time *= 2; std::this_thread::sleep_for(wait_time); dbc::log("Attempting to run it again..."); state(ServerState::START); } else { dbc::log("ffmpeg failed to many times, exiting."); state(ServerState::STOP); } }