|
|
@ -1,13 +1,17 @@ |
|
|
|
#define FSM_DEBUG 1 |
|
|
|
#define FSM_DEBUG 1 |
|
|
|
#include <fmt/core.h> |
|
|
|
#include <fmt/core.h> |
|
|
|
|
|
|
|
#include <fmt/chrono.h> |
|
|
|
#include <nlohmann/json.hpp> |
|
|
|
#include <nlohmann/json.hpp> |
|
|
|
#include <fstream> |
|
|
|
#include <fstream> |
|
|
|
|
|
|
|
#include <chrono> |
|
|
|
|
|
|
|
#include <thread> |
|
|
|
#include "dbc.hpp" |
|
|
|
#include "dbc.hpp" |
|
|
|
#include "fsm.hpp" |
|
|
|
#include "fsm.hpp" |
|
|
|
|
|
|
|
|
|
|
|
#define BUF_MAX 1024 * 10 |
|
|
|
#define BUF_MAX 1024 * 10 |
|
|
|
using namespace fmt; |
|
|
|
using namespace fmt; |
|
|
|
using namespace nlohmann; |
|
|
|
using namespace nlohmann; |
|
|
|
|
|
|
|
using namespace std::chrono_literals; |
|
|
|
|
|
|
|
|
|
|
|
struct Config { |
|
|
|
struct Config { |
|
|
|
json json_config; |
|
|
|
json json_config; |
|
|
@ -30,7 +34,7 @@ struct Config { |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
FILE *run_ffmpeg(Config &config) { |
|
|
|
FILE *run_ffmpeg(Config &config) { |
|
|
|
string ffmpeg_cmd = format("ffmpeg -listen 1 -i {} -bufsize 3000k -maxrate {} -flags +global_header -c:v libx264 -preset veryfast -tune zerolatency -g:v 60 -vb {} -c:a copy -f flv {}", |
|
|
|
string ffmpeg_cmd = format("ffmpeg -listen 1 -i {} -bufsize 3000k -maxrate {} -flags +global_header -c:v libx264 -preset veryfast -tune zerolatency -g:v 60 -vb {} -c:a copy -f flv {} 2> output.log", |
|
|
|
config.listen_at, |
|
|
|
config.listen_at, |
|
|
|
config.bitrate, |
|
|
|
config.bitrate, |
|
|
|
config.bitrate, |
|
|
|
config.bitrate, |
|
|
@ -38,7 +42,7 @@ FILE *run_ffmpeg(Config &config) { |
|
|
|
|
|
|
|
|
|
|
|
println("RUNNING: {}", ffmpeg_cmd); |
|
|
|
println("RUNNING: {}", ffmpeg_cmd); |
|
|
|
|
|
|
|
|
|
|
|
return popen(ffmpeg_cmd.c_str(), "r"); |
|
|
|
return popen(ffmpeg_cmd.c_str(), "re"); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -55,13 +59,14 @@ class Server : DeadSimpleFSM<ServerState, ServerEvent> { |
|
|
|
FILE *handle = nullptr; |
|
|
|
FILE *handle = nullptr; |
|
|
|
char buffer[BUF_MAX]; |
|
|
|
char buffer[BUF_MAX]; |
|
|
|
char *res = nullptr; |
|
|
|
char *res = nullptr; |
|
|
|
|
|
|
|
std::chrono::milliseconds wait_time = 200ms; |
|
|
|
|
|
|
|
|
|
|
|
public: |
|
|
|
public: |
|
|
|
|
|
|
|
|
|
|
|
Server(Config &config) : config(config) {}; |
|
|
|
Server(Config &config) : config(config) {}; |
|
|
|
|
|
|
|
|
|
|
|
bool stopped() { |
|
|
|
bool stopped() { |
|
|
|
return in_state(ServerState::STOP) || in_state(ServerState::ERROR); |
|
|
|
return in_state(ServerState::STOP); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void event(ServerEvent ev) { |
|
|
|
void event(ServerEvent ev) { |
|
|
@ -76,8 +81,10 @@ public: |
|
|
|
void START(ServerEvent ev) { |
|
|
|
void START(ServerEvent ev) { |
|
|
|
handle = run_ffmpeg(config); |
|
|
|
handle = run_ffmpeg(config); |
|
|
|
if(handle == nullptr) { |
|
|
|
if(handle == nullptr) { |
|
|
|
|
|
|
|
dbc::log("ERROR when launching ffmpeg"); |
|
|
|
state(ServerState::ERROR); |
|
|
|
state(ServerState::ERROR); |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
|
|
|
|
wait_time = 200ms; |
|
|
|
state(ServerState::READING); |
|
|
|
state(ServerState::READING); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
@ -86,6 +93,7 @@ public: |
|
|
|
res = fgets(buffer, BUF_MAX, handle); |
|
|
|
res = fgets(buffer, BUF_MAX, handle); |
|
|
|
|
|
|
|
|
|
|
|
if(res == nullptr) { |
|
|
|
if(res == nullptr) { |
|
|
|
|
|
|
|
dbc::log("STOP shutting down..."); |
|
|
|
state(ServerState::STOP); |
|
|
|
state(ServerState::STOP); |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
state(ServerState::READING); |
|
|
|
state(ServerState::READING); |
|
|
@ -95,6 +103,7 @@ public: |
|
|
|
void STOP(ServerEvent ev) { |
|
|
|
void STOP(ServerEvent ev) { |
|
|
|
int rc = pclose(handle); |
|
|
|
int rc = pclose(handle); |
|
|
|
if(rc != 0) { |
|
|
|
if(rc != 0) { |
|
|
|
|
|
|
|
dbc::log("ERROR when calling pclose on ffmpeg"); |
|
|
|
state(ServerState::ERROR); |
|
|
|
state(ServerState::ERROR); |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
state(ServerState::STOP); |
|
|
|
state(ServerState::STOP); |
|
|
@ -102,12 +111,18 @@ public: |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void ERROR(ServerEvent ev) { |
|
|
|
void ERROR(ServerEvent ev) { |
|
|
|
state(ServerState::ERROR); |
|
|
|
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); |
|
|
|
} |
|
|
|
} |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
int main() { |
|
|
|
int main(int argc, char *argv[]) { |
|
|
|
Config config("config.json"); |
|
|
|
dbc::check(argc == 2, "USAGE: distributary config.json"); |
|
|
|
|
|
|
|
println("Using config {}", argv[1]); |
|
|
|
|
|
|
|
Config config(argv[1]); |
|
|
|
Server server(config); |
|
|
|
Server server(config); |
|
|
|
|
|
|
|
|
|
|
|
while(!server.stopped()) { |
|
|
|
while(!server.stopped()) { |
|
|
|