From abb80b89afbe2dd4c579d3d23aedf20da4180a95 Mon Sep 17 00:00:00 2001 From: Sandros Date: Fri, 21 May 2021 03:35:51 +0200 Subject: [PATCH] Initial commit --- README | 12 ++++++ config.example.json | 8 ++++ record.php | 90 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 110 insertions(+) create mode 100644 README create mode 100644 config.example.json create mode 100644 record.php diff --git a/README b/README new file mode 100644 index 0000000..4afe570 --- /dev/null +++ b/README @@ -0,0 +1,12 @@ +With this utility it is possible to record live streams that is available through a Restreamer instance. +This monitors the Restreamer API to check if the local repeater is connected. When it is, it probes the +HLS endpoint and depending on the HTTP Code in the response it starts an FFmpeg process that copies the +HLS output to a specified location on the filesystem. Then it can be played back. +It is also possible to provide a "rewindable" live stream, but keep in mind that it will introduce big +latency. + +To set this up, clone this repository and move or copy config.example.json to config.json, then edit it. +Then, run the following command to start monitoring and recording streams: php -q /path/to/record.php + +Create a cronjob or systemd service to make it run on boot and handle potential failures/exits. +Example cronjob: * * * * * flock -n /tmp/hls-recorder-flock -c "php -q /path/to/record.php" & diff --git a/config.example.json b/config.example.json new file mode 100644 index 0000000..a4cc7c7 --- /dev/null +++ b/config.example.json @@ -0,0 +1,8 @@ +{ + "vod":"\/home\/example\/web\/uploads", + "api":"http:\/\/127.0.0.1:8080\/v1", + "hls":"http:\/\/127.0.0.1:8080\/hls\/live.stream.m3u8", + "pid":"\/home\/example\/hls-recorder\/ffmpeg-flock", + "mail":["info@example.org","dir@example.org"], + "loglevel":1 +} \ No newline at end of file diff --git a/record.php b/record.php new file mode 100644 index 0000000..188385d --- /dev/null +++ b/record.php @@ -0,0 +1,90 @@ +#!/usr/bin/php += $_set->loglevel) + echo "[".date('Y-m-d H:i:s')."]".str_repeat("\t", $tabs)."$txt\n"; + if ($exit) + exit; + return true; +} +function is_dir_empty($dir) { + if (!is_readable($dir)) return NULL; + return (count(scandir($dir)) == 2); +} +function notify($sub, $msg, $loglevel = 1) +{ + global $_set; + + if (is_array($_set->mail) && !empty($_set->mail)) + foreach ($_set->mail AS $mail) + if (!@mail($mail, "=?UTF-8?B?".base64_encode('[hls-recorder] '.$sub)."?=", $msg, "Content-type: text/plain; charset=utf-8")) + logger($loglevel, 'Unable to send notification E-mail'); +} + +// Loop indefinitely +while (true) : + + if ($api = @file_get_contents($_set->api.'/states')) + if ($api = @json_decode($api)) + if (isset($api->repeat_to_local_nginx) && $api->repeat_to_local_nginx->type == 'connected') + { + logger(1, 'Repeater seems to be connected'); + + $handle = curl_init($_set->hls); + curl_setopt($handle, CURLOPT_RETURNTRANSFER, TRUE); + $response = curl_exec($handle); + $httpCode = curl_getinfo($handle, CURLINFO_HTTP_CODE); + curl_close($handle); + if ($httpCode == 200) + { + $output_directory = $_set->vod.'/vod-'.date('Ymd-His'); + $exitcode = 0; + + if (@mkdir($output_directory)) + { + logger(2, 'All checks passed, starting ffmpeg'); + notify('Recording', 'Restreamer API reported that repeating to local nginx is connected and the HLS endpoint is found. The HLS output is now being recorded. HLS URL is the following: '.$_set->hls.', Output directory is: '.$output_directory, 2); + exec('flock -n '.$_set->pid.' -c "ffmpeg -i '.$_set->hls.' -c copy '.$output_directory.'/index.m3u8 2> '.$output_directory.'/ffmpeg.log"', $output, $exitcode); + logger(2, 'ffmpeg exited with code '.$exitcode); + notify('Recording stopped', 'The FFMPEG process shut down with exit code: '.$exitcode, 2); + if ($exitcode) + { + logger(3, 'Non-clean exit (expected), checking if output directory is empty'); + if (is_dir_empty($output_directory)) + if (@rmdir($output_directory)) + logger(4, 'Output directory removed'); + else + { + logger(4, 'Unable to remove output directory'); + notify('Error', 'The FFMPEG process shut down with exit code '.$exitcode.' and the output directory is empty (nothing recorded). Output directory should have been removed automatically, but the process failed. Remove the output directory manually: '.$output_directory, 4); + } + } + } else + logger(3, 'Unable to create output directory'); + } else + logger(2, 'HLS inaccessible, HTTP Code '.$httpCode); + + } else + logger(1, 'Repeater not in connected state', 0); + else + logger(1, 'API response unreadable'); + else + logger(1, 'API can not be accessed'); + + sleep(5); + +endwhile;