From fbc5c992dddc09f8a87098b50e62c4609f0d9881 Mon Sep 17 00:00:00 2001 From: deathbybandaid Date: Wed, 14 Oct 2020 19:30:15 -0400 Subject: [PATCH] Improve Tuner Grabbing --- fHDHR/fHDHRerrors/__init__.py | 2 +- fHDHR/fHDHRweb/__init__.py | 3 +- fHDHR/fHDHRweb/fHDHRdevice/debug_json.py | 4 +- fHDHR/fHDHRweb/fHDHRdevice/tuners.py | 77 ++++++++++++++++++++---- fHDHR/fHDHRweb/fHDHRdevice/watch.py | 18 +++--- 5 files changed, 78 insertions(+), 26 deletions(-) diff --git a/fHDHR/fHDHRerrors/__init__.py b/fHDHR/fHDHRerrors/__init__.py index 9bdf882..9def67e 100644 --- a/fHDHR/fHDHRerrors/__init__.py +++ b/fHDHR/fHDHRerrors/__init__.py @@ -4,7 +4,7 @@ class TunerError(Exception): self.value = value def __str__(self): - return 'LoginError: %s' % self.value + return 'TunerError: %s' % self.value class LoginError(Exception): diff --git a/fHDHR/fHDHRweb/__init__.py b/fHDHR/fHDHRweb/__init__.py index 133507f..6a0e9ed 100644 --- a/fHDHR/fHDHRweb/__init__.py +++ b/fHDHR/fHDHRweb/__init__.py @@ -57,7 +57,7 @@ class HDHR_Hub(): return self.lineupjson.get_lineup_json(base_url) def get_debug_json(self, base_url): - return self.debug.get_debug_json(base_url, self.tuners.tuners) + return self.debug.get_debug_json(base_url, self.tuners) def get_html_error(self, message): return self.htmlerror.get_html_error(message) @@ -184,6 +184,7 @@ class HDHR_HTTP_Server(): "channel": channel.replace('v', ''), "method": request.args.get('method', default=hdhr.config.dict["fhdhr"]["stream_type"], type=str), "duration": request.args.get('duration', default=0, type=int), + "accessed": str(request.headers["host"]) + str(request.url_rule), } stream_args = hdhr.get_stream_info(stream_args) if stream_args["channelUri"]: diff --git a/fHDHR/fHDHRweb/fHDHRdevice/debug_json.py b/fHDHR/fHDHRweb/fHDHRdevice/debug_json.py index a271ba4..09f39c7 100644 --- a/fHDHR/fHDHRweb/fHDHRdevice/debug_json.py +++ b/fHDHR/fHDHRweb/fHDHRdevice/debug_json.py @@ -10,7 +10,7 @@ class Debug_JSON(): def get_debug_json(self, base_url, tuners): debugjson = { "base_url": base_url, - "available tuners": tuners, - "total channels": self.origserv.get_station_total() + "total channels": self.origserv.get_station_total(), + "tuner status": tuners.status(), } return json.dumps(debugjson, indent=4) diff --git a/fHDHR/fHDHRweb/fHDHRdevice/tuners.py b/fHDHR/fHDHRweb/fHDHRdevice/tuners.py index a89f6ee..e05aa70 100644 --- a/fHDHR/fHDHRweb/fHDHRdevice/tuners.py +++ b/fHDHR/fHDHRweb/fHDHRdevice/tuners.py @@ -3,24 +3,75 @@ import threading from fHDHR.fHDHRerrors import TunerError +class Tuner(): + def __init__(self, inum): + self.number = inum + self.tuner_lock = threading.Lock() + self.status = {} + + def grab(self, stream_args): + if self.tuner_lock.locked(): + raise TunerError("Tuner #" + str(self.number) + " is not available.") + + print("Tuner #" + str(self.number) + " to be used for stream.") + self.tuner_lock.acquire() + self.status = { + "status": "Active", + "method": stream_args["method"], + "accessed": stream_args["accessed"], + "proxied_url": stream_args["channelUri"], + } + + def close(self): + print("Tuner #" + str(self.number) + " Shutting Down.") + self.status = {} + self.tuner_lock.release() + + def get_status(self): + if not self.tuner_lock.locked(): + return {"status": "Inactive"} + return self.status + + class Tuners(): def __init__(self, settings): self.config = settings - self.max_tuners = int(self.config.dict["fhdhr"]["tuner_count"]) - self.tuners = self.max_tuners - self.tuner_lock = threading.Lock() - def tuner_grab(self): - self.tuner_lock.acquire() - if self.tuners == 0: - self.tuner_lock.release() + for i in range(1, self.max_tuners + 1): + exec("%s = %s" % ("self.tuner_" + str(i), "Tuner(i)")) + + def tuner_grab(self, stream_args, tunernum=None): + tunerselected = None + + if tunernum: + if tunernum not in range(1, self.max_tuners + 1): + raise TunerError("Tuner " + str(tunernum) + " does not exist.") + eval("self.tuner_" + str(tunernum) + ".grab(stream_args)") + tunerselected = tunernum + + else: + + for tunernum in range(1, self.max_tuners + 1): + try: + eval("self.tuner_" + str(tunernum) + ".grab(stream_args)") + except TunerError: + continue + else: + tunerselected = tunernum + break + + if not tunerselected: raise TunerError("No Available Tuners.") - self.tuners -= 1 - self.tuner_lock.release() + else: + return tunerselected - def tuner_close(self): - self.tuner_lock.acquire() - self.tuners += 1 - self.tuner_lock.release() + def tuner_close(self, tunernum): + eval("self.tuner_" + str(tunernum) + ".close()") + + def status(self): + all_status = {} + for tunernum in range(1, self.max_tuners + 1): + all_status[tunernum] = eval("self.tuner_" + str(tunernum) + ".get_status()") + return all_status diff --git a/fHDHR/fHDHRweb/fHDHRdevice/watch.py b/fHDHR/fHDHRweb/fHDHRdevice/watch.py index 9b18a09..786b805 100644 --- a/fHDHR/fHDHRweb/fHDHRdevice/watch.py +++ b/fHDHR/fHDHRweb/fHDHRdevice/watch.py @@ -13,7 +13,7 @@ class WatchStream(): self.tuners = tuners self.web = fHDHR.tools.WebReq() - def direct_stream(self, stream_args): + def direct_stream(self, stream_args, tunernum): chunksize = int(self.tuners.config.dict["direct_stream"]['chunksize']) @@ -36,11 +36,11 @@ class WatchStream(): except GeneratorExit: req.close() print("Connection Closed.") - self.tuners.tuner_close() + self.tuners.tuner_close(tunernum) return generate() - def ffmpeg_stream(self, stream_args): + def ffmpeg_stream(self, stream_args, tunernum): bytes_per_read = int(self.config.dict["ffmpeg"]["bytes_per_read"]) @@ -84,25 +84,25 @@ class WatchStream(): ffmpeg_proc.terminate() ffmpeg_proc.communicate() print("Connection Closed.") - self.tuners.tuner_close() + self.tuners.tuner_close(tunernum) return generate() def get_stream(self, stream_args): try: - self.tuners.tuner_grab() - except TunerError: + tunernum = self.tuners.tuner_grab(stream_args) + except TunerError as e: print("A " + stream_args["method"] + " stream request for channel " + - str(stream_args["channel"]) + " was rejected do to a lack of available tuners.") + str(stream_args["channel"]) + " was rejected do to " + str(e)) return print("Attempting a " + stream_args["method"] + " stream request for channel " + str(stream_args["channel"])) if stream_args["method"] == "ffmpeg": - return self.ffmpeg_stream(stream_args) + return self.ffmpeg_stream(stream_args, tunernum) elif stream_args["method"] == "direct": - return self.direct_stream(stream_args) + return self.direct_stream(stream_args, tunernum) def get_stream_info(self, stream_args):