def tuner_scan(self): """Temporarily use a tuner for a scan""" if not self.available_tuner_count(): raise TunerError("805 - All Tuners In Use") tunernumber = self.get_available_tuner() self.tuners[str(tunernumber)].channel_scan() if not tunernumber: raise TunerError("805 - All Tuners In Use")
def first_available(self, origin, channel_number, dograb=True): if not self.available_tuner_count(origin): raise TunerError("805 - All Tuners In Use") tunernumber = self.get_available_tuner(origin) if not tunernumber: raise TunerError("805 - All Tuners In Use") else: self.tuners[origin][str(tunernumber)].grab(origin, channel_number) return tunernumber
def first_available(self): if not self.available_tuner_count(): raise TunerError("805 - All Tuners In Use") for tunernum in list(self.tuners.keys()): try: self.tuners[int(tunernum)].grab() except TunerError: continue else: return tunernum raise TunerError("805 - All Tuners In Use")
def grab(self): if self.tuner_lock.locked(): self.fhdhr.logger.error("Tuner #" + str(self.number) + " is not available.") raise TunerError("804 - Tuner In Use") self.tuner_lock.acquire() self.status["status"] = "Acquired" self.fhdhr.logger.info("Tuner #" + str(self.number) + " Acquired.")
def __init__(self, fhdhr, stream_args, tuner): self.fhdhr = fhdhr self.stream_args = stream_args self.tuner = tuner if not os.path.isfile(self.stream_args["stream_info"]["url"]): raise TunerError("806 - Tune Failed: %s PATH does not seem to exist" % self.stream_args["stream_info"]["url"])
def __init__(self, fhdhr, stream_args, tuner): self.fhdhr = fhdhr self.stream_args = stream_args self.tuner = tuner try: self.udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) self.udp_socket.bind((self.address, 0)) self.udp_socket_address = self.udp_socket.getsockname()[0] self.udp_socket_port = self.udp_socket.getsockname()[1] self.udp_socket.settimeout(5) self.fhdhr.logger.info( "Created UDP socket at %s:%s." % (self.udp_socket_address, self.udp_socket_port)) except Exception as exerror: error_out = self.fhdhr.logger.lazy_exception( exerror, "806 - Tune Failed") raise TunerError(error_out) finally: self.fhdhr.logger.info( "Closing UDP socket at %s:%s." % (self.udp_socket_address, self.udp_socket_port)) self.udp_socket.close()
def tuner_scan(self, origin="all"): """Temporarily use a tuner for a scan""" if origin == "all": origins = list(self.tuners.keys()) else: origins = [origin] for origin in origins: if not self.available_tuner_count(origin): raise TunerError("805 - All Tuners In Use") tunernumber = self.get_available_tuner(origin) self.tuners[origin][str(tunernumber)].channel_scan(origin) if not tunernumber: raise TunerError("805 - All Tuners In Use")
def __init__(self, fhdhr, plugin_utils, stream_args, tuner): self.fhdhr = fhdhr self.plugin_utils = plugin_utils self.stream_args = stream_args self.tuner = tuner if self.plugin_utils.versions.dict["vlc"]["version"] == "Missing": raise TunerError("806 - Tune Failed: VLC Missing") self.vlc_command = self.vlc_command_assemble(stream_args)
def tuner_grab(self, tuner_number, origin, channel_number): if str(tuner_number) not in list(self.tuners[origin].keys()): self.fhdhr.logger.error("Tuner %s does not exist for %s." % (tuner_number, origin)) raise TunerError("806 - Tune Failed") # TunerError will raise if unavailable self.tuners[origin][str(tuner_number)].grab(origin, channel_number) return tuner_number
def grab(self, origin, channel_number): if self.tuner_lock.locked(): self.fhdhr.logger.error("Tuner #%s is not available." % self.number) raise TunerError("804 - Tuner In Use") self.tuner_lock.acquire() self.status["status"] = "Acquired" self.status["origin"] = origin self.status["channel"] = channel_number self.status["time_start"] = datetime.datetime.utcnow() self.fhdhr.logger.info("Tuner #%s Acquired." % str(self.number))
def __init__(self, fhdhr, plugin_utils, stream_args, tuner): self.fhdhr = fhdhr self.plugin_utils = plugin_utils self.stream_args = stream_args self.tuner = tuner if self.plugin_utils.config.internal["versions"]["ffmpeg"]["version"] == "Missing": raise TunerError("806 - Tune Failed: FFMPEG Missing") self.bytes_per_read = int(plugin_utils.config.dict["streaming"]["bytes_per_read"]) self.ffmpeg_command = self.ffmpeg_command_assemble(stream_args)
def tuner_grab(self, tuner_number): if int(tuner_number) not in list(self.tuners.keys()): self.fhdhr.logger.error("Tuner %s does not exist." % str(tuner_number)) raise TunerError("806 - Tune Failed") # TunerError will raise if unavailable self.tuners[int(tuner_number)].grab() return tuner_number
def __init__(self, fhdhr, plugin_utils, stream_args, tuner): self.fhdhr = fhdhr self.plugin_utils = plugin_utils self.stream_args = stream_args self.tuner = tuner if self.plugin_utils.versions.dict["webwatch_ffmpeg"][ "version"] == "Missing": raise TunerError("806 - Tune Failed: FFMPEG Missing") self.bytes_per_read = 1024 self.ffmpeg_command = self.ffmpeg_command_assemble(stream_args)
def __init__(self, fhdhr, plugin_utils, stream_args, tuner): self.fhdhr = fhdhr self.plugin_utils = plugin_utils self.stream_args = stream_args self.tuner = tuner self.ffmpeg_path = self.plugin_utils.config.dict["ffmpeg"]["path"] self.buffsize = self.plugin_utils.config.dict["ffmpeg"]["buffsize"] if self.plugin_utils.versions.dict["ffmpeg"]["version"] == "Missing": raise TunerError("806 - Tune Failed: FFMPEG Missing") self.ffmpeg_command = self.ffmpeg_command_assemble(stream_args)
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"], "time_start": datetime.datetime.utcnow(), }
def get_stream_info(self, stream_args): stream_info = self.channels.get_channel_stream(stream_args, stream_args["origin"]) if not stream_info: raise TunerError("806 - Tune Failed") if isinstance(stream_info, str): stream_info = {"url": stream_info, "headers": None} stream_args["stream_info"] = stream_info if not stream_args["stream_info"]["url"]: raise TunerError("806 - Tune Failed") if "headers" not in list(stream_args["stream_info"].keys()): stream_args["stream_info"]["headers"] = None if stream_args["stream_info"]["url"].startswith("udp://"): stream_args["true_content_type"] = "video/mpeg" stream_args["content_type"] = "video/mpeg" else: channel_stream_url_headers = self.fhdhr.web.session.head( stream_args["stream_info"]["url"]).headers stream_args["true_content_type"] = channel_stream_url_headers[ 'Content-Type'] if stream_args["true_content_type"].startswith( tuple(["application/", "text/"])): stream_args["content_type"] = "video/mpeg" if stream_args["origin_quality"] != -1: stream_args["stream_info"]["url"] = self.m3u8_quality( stream_args) else: stream_args["content_type"] = stream_args["true_content_type"] return stream_args
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.") else: return tunerselected
def get_origin_stream_info(self): """ Pull Stream Information from Origin Plugin """ stream_info_defaults = {"headers": None} # Pull Stream Info from Origin Plugin self.fhdhr.logger.debug( "Attempting to gather stream information for %s channel %s %s %s." % (self.stream_args["origin_name"], self.stream_args["channel"], self.stream_args["channel_name"], self.stream_args["channel_callsign"])) stream_info = self.fhdhr.origins.origins_dict[ self.stream_args["origin_name"]].get_channel_stream( self.chan_dict, self.stream_args) if not stream_info: raise TunerError("806 - Tune Failed") if not stream_info: raise TunerError("806 - Tune Failed") # Format Information from Origin Plugin if isinstance(stream_info, str): stream_info = {"url": stream_info} # Fail if no url present if not stream_info["url"]: raise TunerError("806 - Tune Failed") # Add keys/values to stream_info if missing for default_key in list(stream_info_defaults.keys()): if default_key not in list(stream_info.keys()): stream_info[default_key] = stream_info_defaults[default_key] self.stream_args["stream_info"] = stream_info
def channel_scan(self, grabbed=False): if self.tuner_lock.locked() and not grabbed: self.fhdhr.logger.error("Tuner #%s is not available." % str(self.number)) raise TunerError("804 - Tuner In Use") if self.status["status"] == "Scanning": self.fhdhr.logger.info("Channel Scan Already In Progress!") else: if not grabbed: self.tuner_lock.acquire() self.status["status"] = "Scanning" self.fhdhr.logger.info("Tuner #%s Performing Channel Scan." % str(self.number)) chanscan = threading.Thread(target=self.runscan) chanscan.start()
def get_stream_info(self, stream_args): stream_args["channelUri"] = self.channels.get_channel_stream( str(stream_args["channel"])) if not stream_args["channelUri"]: raise TunerError("806 - Tune Failed") channelUri_headers = self.fhdhr.web.session.head( stream_args["channelUri"]).headers stream_args["true_content_type"] = channelUri_headers['Content-Type'] if stream_args["true_content_type"].startswith( tuple(["application/", "text/"])): stream_args["content_type"] = "video/mpeg" else: stream_args["content_type"] = stream_args["true_content_type"] return stream_args
def channel_scan(self, origin, grabbed=False): if self.tuner_lock.locked() and not grabbed: self.fhdhr.logger.error("%s Tuner #%s is not available." % (self.origin, self.number)) raise TunerError("804 - Tuner In Use") if self.status["status"] == "Scanning": self.fhdhr.logger.info("Channel Scan Already In Progress!") else: if not grabbed: self.tuner_lock.acquire() self.status["status"] = "Scanning" self.status["origin"] = origin self.status["time_start"] = datetime.datetime.utcnow() self.fhdhr.logger.info( "Tuner #%s Performing Channel Scan for %s origin." % (self.number, origin)) chanscan = threading.Thread(target=self.runscan, args=(origin, )) chanscan.start()
def validate_stream_url(self): """ Validate Stream URL from Origin """ # Make sure URL is not empty if "://" in self.stream_args["stream_info"]["url"]: if (not len( self.stream_args["stream_info"]["url"].split("://")[-1]) or self.stream_args["stream_info"]["url"].split("://")[-1] == "None"): raise TunerError("806 - Tune Failed") # Set parameters for HTTP/s protocols if self.stream_args["stream_info"]["url"].startswith( tuple(["http://", "https://"])): try: channel_stream_url_headers = self.fhdhr.web.session.head( self.stream_args["stream_info"]["url"]).headers self.stream_args[ "true_content_type"] = channel_stream_url_headers[ 'Content-Type'] except self.fhdhr.web.exceptions.MissingSchema: raise TunerError("806 - Tune Failed") except self.fhdhr.web.exceptions.ConnectionError: raise TunerError("806 - Tune Failed") except KeyError: # Set for M3U8 if self.stream_args["stream_info"]["url"].endswith( tuple([".m3u8", ".m3u"])): self.fhdhr.logger.warning( "Stream Headers couldn't be properly determined, defaulting to application/text as content_type." ) self.stream_args["true_content_type"] = "application/text" else: self.fhdhr.logger.warning( "Stream Headers couldn't be properly determined, defaulting to video/mpeg as content_type." ) self.stream_args["true_content_type"] = "video/mpeg" if self.stream_args["true_content_type"].startswith( tuple(["application/", "text/"])): self.stream_args["content_type"] = "video/mpeg" if self.stream_args["origin_quality"] != -1: self.stream_args["stream_info"]["url"] = m3u8_quality( self.fhdhr, self.stream_args) else: self.stream_args["content_type"] = self.stream_args[ "true_content_type"] # Set parameters for Hardware Devices elif self.stream_args["stream_info"]["url"].startswith( tuple(["/dev/", "file://dev/"])): # TODO some attempt to determine this information properly self.stream_args["true_content_type"] = "video/mpeg" # Set parameters for file:// elif self.stream_args["stream_info"]["url"].startswith( tuple(["file://"])): # Set for M3U8 if self.stream_args["stream_info"]["url"].endswith( tuple([".m3u8", ".m3u"])): self.stream_args["true_content_type"] = "application/text" else: # TODO some attempt to determine this information properly self.stream_args["true_content_type"] = "video/mpeg" # Set parameters for RTP/s protocols elif self.stream_args["stream_info"]["url"].startswith( tuple(["rtp://", "rtsp://"])): # TODO some attempt to determine this information properly self.stream_args["true_content_type"] = "video/mpeg" # Set parameters for UDP protocol elif self.stream_args["stream_info"]["url"].startswith( tuple(["udp://"])): # TODO some attempt to determine this information properly self.stream_args["true_content_type"] = "video/mpeg" # Set parameters for fallback else: self.fhdhr.logger.warning( "Content Type couldn't be properly determined, defaulting to video/mpeg as content_type." ) self.stream_args["true_content_type"] = "video/mpeg" if self.stream_args["true_content_type"].startswith( tuple(["application/", "text/"])): self.stream_args["content_type"] = "video/mpeg" if self.stream_args["origin_quality"] != -1: self.stream_args["stream_info"]["url"] = m3u8_quality( self.fhdhr, self.stream_args) else: self.stream_args["content_type"] = self.stream_args[ "true_content_type"]
def stream_setup(self): if self.stream_obj.stream_args["method"] == "direct": # Select the HTTP stream method for HTTP/s addresses if (self.stream_obj.stream_args["stream_info"]["url"].startswith(tuple(["http://", "https://"])) and not self.stream_obj.stream_args["true_content_type"].startswith(tuple(["application/", "text/"]))): self.fhdhr.logger.info("Stream Method Detected as HTTP/s.") self.method = Direct_HTTP_Stream(self.fhdhr, self.stream_obj.stream_args, self.tuner) # Select the FILE method for file:// PATHS elif (self.stream_obj.stream_args["stream_info"]["url"].startswith(tuple(["file://"])) and not self.stream_obj.stream_args["true_content_type"].startswith(tuple(["file://dev/"]))): self.fhdhr.logger.info("Stream Method Detected as file://.") self.method = Direct_FILE_Stream(self.fhdhr, self.stream_obj.stream_args, self.tuner) # Select the M3U8 stream method for hadnling M3U/8 streams elif self.stream_obj.stream_args["true_content_type"].startswith(tuple(["application/", "text/"])): self.fhdhr.logger.info("Stream Method Detected as M3U8.") self.method = Direct_M3U8_Stream(self.fhdhr, self.stream_obj.stream_args, self.tuner) # Select the RTP stream method for RTP/s addresses elif self.stream_obj.stream_args["stream_info"]["url"].startswith(tuple(["rtp://", "rtsp://"])): self.fhdhr.logger.info("Stream Method Detected as RTP/s.") self.method = Direct_RTP_Stream(self.fhdhr, self.stream_obj.stream_args, self.tuner) # Select the UDP stream method for UDP addresses elif self.stream_obj.stream_args["stream_info"]["url"].startswith(tuple(["udp://"])): self.fhdhr.logger.info("Stream Method Detected as UDP.") self.method = Direct_UDP_Stream(self.fhdhr, self.stream_obj.stream_args, self.tuner) # Select the HardWare stream method for /dev/ hardware devices elif self.stream_obj.stream_args["stream_info"]["url"].startswith(tuple(["/dev/", "file://dev/"])): self.fhdhr.logger.info("Stream Method Detected as a /dev/ hardware device.") self.method = Direct_HardWare_Stream(self.fhdhr, self.stream_obj.stream_args, self.tuner) # Select the Direct HTTP stream method as a fallback else: self.fhdhr.logger.warning("Stream Method couldn't be properly determined, defaulting to HTTP method.") self.method = Direct_HTTP_Stream(self.fhdhr, self.stream_obj.stream_args, self.tuner) else: if self.stream_obj.stream_args["method"] not in list(self.alt_stream_handlers.keys()): raise TunerError("806 - Tune Failed: %s Plugin Not Found." % self.stream_obj.stream_args["method"]) stream_args = self.stream_obj.stream_args plugin = self.alt_stream_handlers[self.stream_obj.stream_args["method"]] plugin_utils = plugin.plugin_utils try: self.method = plugin.Plugin_OBJ(self.fhdhr, plugin_utils, stream_args, self.tuner) except TunerError as exerror: error_out = self.fhdhr.logger.lazy_exception(exerror, "Tuner Setup Failed") raise TunerError(error_out) except Exception as exerror: error_out = self.fhdhr.logger.lazy_exception(exerror, "Tuner Setup Failed (lazily handled)") raise TunerError(error_out)
def __init__(self, fhdhr, stream_args, tuner): self.fhdhr = fhdhr self.stream_args = stream_args self.tuner = tuner self.fhdhr.logger.info("Attempting to create socket to listen on.") self.address = self.get_sock_address() if not self.address: raise TunerError("806 - Tune Failed: Could Not Create Socket") # TODO determine if the RTP stream is TCP or UDP try: self.tcp_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.tcp_socket.bind((self.address, 0)) self.tcp_socket_address = self.tcp_socket.getsockname()[0] self.tcp_socket_port = self.tcp_socket.getsockname()[1] self.fhdhr.logger.info( "Created TCP socket at %s:%s." % (self.tcp_socket_address, self.tcp_socket_port)) self.udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) self.udp_socket.bind((self.address, 0)) self.udp_socket_address = self.udp_socket.getsockname()[0] self.udp_socket_port = self.udp_socket.getsockname()[1] self.udp_socket.settimeout(5) self.fhdhr.logger.info( "Created UDP socket at %s:%s." % (self.udp_socket_address, self.udp_socket_port)) credentials = "%s:%s" % ( self.stream_args["stream_info"]["username"], self.stream_args["stream_info"]["password"]) credentials_bytes = credentials.encode("ascii") credentials_base64_bytes = base64.b64encode(credentials_bytes) credentials_base64_string = credentials_base64_bytes.decode( "ascii") self.describe = "DESCRIBE %s RTSP/1.0\r\nCSeq: 2\r\nUser-Agent: python\r\nAccept: application/sdp\r\nAuthorization: Basic %s\r\n\r\n" % ( self.stream_args["stream_info"]["url"], credentials_base64_string) self.setup = "SETUP %s/trackID=1 RTSP/1.0\r\nCSeq: 3\r\nUser-Agent: python\r\nTransport: RTP/AVP;unicast;client_port=%s\r\nAuthorization: Basic %s\r\n\r\n" % ( self.stream_args["stream_info"]["url"], self.udp_socket_port, credentials_base64_string) self.fhdhr.logger.info("Connecting to Socket") self.tcp_socket.connect( (self.stream_args["stream_info"]["address"], self.stream_args["stream_info"]["port"])) self.fhdhr.logger.info("Sending DESCRIBE") self.tcp_socket.send(self.describe.encode("utf-8")) recst = self.tcp_socket.recv(4096).decode() self.fhdhr.logger.info("Got response: %s" % recst) self.fhdhr.logger.info("Sending SETUP") self.tcp_socket.send(self.setup.encode("utf-8")) recst = self.tcp_socket.recv(4096).decode() self.fhdhr.logger.info("Got response: %s" % recst) self.sessionid = self.sessionid(recst) self.fhdhr.logger.info("SessionID=%s" % self.sessionid) self.play = "PLAY %s RTSP/1.0\r\nCSeq: 5\r\nUser-Agent: python\r\nSession: %s\r\nRange: npt=0.000-\r\nAuthorization: Basic %s\r\n\r\n" % ( self.stream_args["stream_info"]["url"], self.sessionid, credentials_base64_string) except Exception as exerror: self.fhdhr.logger.info( "Closing UDP socket at %s:%s." % (self.udp_socket_address, self.udp_socket_port)) self.udp_socket.close() self.fhdhr.logger.info( "Closing TCP socket at %s:%s." % (self.tcp_socket_address, self.tcp_socket_port)) self.tcp_socket.close() error_out = self.fhdhr.logger.lazy_exception( exerror, "806 - Tune Failed: Could Not Create Socket") raise TunerError(error_out)