from copy import deepcopy
-VIDEO_PIPELINE_BASE="""{video_source} {video_options} \
+VIDEO_PIPELINE_BASE="""{gst_video_source} {gst_video_options} \
! {format}, width={width}, height={height}, framerate={framerate}/1 \
! {decoder} \
! queue ! videoflip method={flip} \
! queue ! videoconvert \
! queue ! vp8enc threads=4 deadline=2 target-bitrate={vp8_bitrate} \
! muxout. \
- {audio_source} {audio_options} client-name="webm_streaming_{id}_audio" ! audio/x-raw, format=F32LE, channels={channels} \
+ {gst_audio_source} {gst_audio_options} client-name="webm_streaming_{id}_audio" ! audio/x-raw, format=F32LE, channels={channels} \
! queue ! audiocheblimit mode=high-pass cutoff={hp_frequency} poles={hp_poles} \
! queue ! volume volume={volume_pre} \
! queue ! audiodynamic characteristics=soft-knee mode=compressor threshold={comp_threshold} ratio={comp_ratio} \
! queue ! shout2send ip={ip} port={port} password={password} mount=telecaster_live_{id}.webm > /dev/null
"""
-AUDIO_PIPELINE_BASE="""{audio_source} {audio_options} client-name="mp3_streaming_audio" \
+AUDIO_PIPELINE_BASE="""{gst_audio_source} {gst_audio_options} client-name="mp3_streaming_audio" \
! audio/x-raw, format=F32LE, channels={channels} \
! queue ! audiocheblimit mode=high-pass cutoff={hp_frequency} poles={hp_poles} \
! queue ! volume volume={volume_pre} \
DEFAULT_CONFIG_FILE = "/etc/telecaster/telecaster.yml"
-JACK_CONFIG = {"engine": "jackd",
- "options": "-R -P{priority} -dalsa -r{samplerate} -p{buffer} -n3 -Chw:{card} -Phw:{card}",
- "tools": ["qjackctl", "catia", "konsole"],
- "gst_audio_source": "jackaudiosrc",
- "gst_audio_options": "connect=2 low-latency=true",
- "connect":
- ["jack_connect system:capture_1 webm_streaming_0_audio:in_jackaudiosrc0_1",
- "jack_connect system:capture_2 webm_streaming_0_audio:in_jackaudiosrc0_2",
- "jack_connect system:capture_1 mp3_streaming_audio:in_jackaudiosrc0_1",
- "jack_connect system:capture_2 mp3_streaming_audio:in_jackaudiosrc0_2"
- ]
- }
-
-PIPEWIRE_CONFIG = {"engine": "pipewire",
- "options": "",
- "gst_audio_source": "pipewiresrc",
- "gst_audio_options": "target-object={target_object}",
- "tools": ["qpwgraph", "konsole"],
- "connect":""
- }
+PARAMS = {
+ "jack": {
+ "engine": "jackd",
+ "options": "-R -P{priority} -dalsa -r{samplerate} -p{buffer} -n3 -Chw:{card} -Phw:{card}",
+ "tools": ["qjackctl", "catia", "konsole"],
+ "gst_video_source": "v4l2src",
+ "gst_video_options": "device=/dev/video{id}",
+ "gst_audio_source": "jackaudiosrc",
+ "gst_audio_options": "connect=2 low-latency=true",
+ "connect":
+ ["jack_connect system:capture_1 webm_streaming_0_audio:in_jackaudiosrc0_1",
+ "jack_connect system:capture_2 webm_streaming_0_audio:in_jackaudiosrc0_2",
+ "jack_connect system:capture_1 mp3_streaming_audio:in_jackaudiosrc0_1",
+ "jack_connect system:capture_2 mp3_streaming_audio:in_jackaudiosrc0_2"
+ ]
+},
+ "pipewire": {
+ "engine": "pipewire",
+ "options": "",
+ "gst_video_source": "pipewiresrc",
+ "gst_video_options": "target-object=v4l2:/dev/video{id}",
+ "gst_audio_source": "pipewiresrc",
+ "gst_audio_options": "target-object={target_object}",
+ "tools": ["qpwgraph", "konsole"],
+ "connect":""
+ }
+}
class TeleCasterGStream(Thread):
def __init__(self, pipeline):
Thread.__init__(self)
self.pipeline = pipeline
- # print(self.pipeline)
def run(self):
os.system('gst-launch-1.0 ' + self.pipeline + ' & ')
class TeleCaster(Thread):
- def __init__(self, conf_file_path):
+ def __init__(self, conf_file_path, verbose, dry_run):
Thread.__init__(self)
conf_file = open(conf_file_path, 'r')
+ self.verbose = verbose
+ self.dry_run = dry_run
self.conf = yaml.safe_load(conf_file)["telecaster"]
self.stream_types = ["audio", "video"]
self.deefuzzer_video_conf_file = "/tmp/telecaster_deefuzzer_webm_monitor.yml"
self.deefuzzer_audio_conf_file = "/tmp/telecaster_deefuzzer_mp3_monitor.yml"
# print(self.conf)
- audio_source = self.conf["audio"]["gstreamer"]["audio_source"]
- if "pipewire" in audio_source:
- self.audio_config = PIPEWIRE_CONFIG
- elif "jack" in audio_source:
- self.audio_config = JACK_CONFIG
+
+ audio_engine = self.conf["audio"]["engine"]
+
+ self.params = PARAMS[audio_engine]
+ self.params["options"] = self.params["options"].format(**self.conf["audio"][audio_engine])
+ self.params["gst_audio_options"] = self.params["gst_audio_options"].format(**self.conf["audio"][audio_engine])
+
+ if self.verbose:
+ print(self.params)
+
def write_conf(self, conf_dict, path):
filename, ext = os.path.splitext(path)
for param in params:
command = "v4l2-ctl -d %s -c %s=%s" % (video["id"], param, params[param])
args = shlex.split(command)
- # print(args)
- subprocess.call(command, shell=True)
+ if self.verbose:
+ print(command)
+ if not self.dry_run:
+ subprocess.call(command, shell=True)
def audio_engine_start(self):
- command = self.audio_config["engine"] + " " + self.audio_config["options"].format(**self.conf["audio"]["jack"])
+ command = self.params["engine"] + " " + self.params["options"]
thread = TeleCasterThreadedCommand(command)
- thread.start()
+ if self.verbose:
+ print(command)
+ if not self.dry_run:
+ thread.start()
time.sleep(BOOT_TIME_DELAY)
def audio_tools_start(self):
- for tool in self.audio_config["tools"]:
+ for tool in self.params["tools"]:
command = TeleCasterCommand(tool)
- command.start()
+ if self.verbose:
+ print(tool)
+ if not self.dry_run:
+ command.start()
def deefuzzer_start(self, conf, conf_file):
# print(self.conf)
self.write_conf(conf, conf_file)
deefuzzer = TeleCasterDeeFuzzer(conf_file)
- deefuzzer.start()
+ if not self.dry_run:
+ deefuzzer.start()
def video_start(self):
deefuzzer_default_conf = deepcopy(self.conf["video"]["deefuzzer"])
if "v4l2-ctl" in video:
self.v4l2_ctl(video)
+ self.params["gst_video_options"] = self.params["gst_video_options"].format(**video)
+
pipeline = VIDEO_PIPELINE_BASE.format(**video,
**self.conf["audio"]["gstreamer"],
- **self.conf["server"])
+ **self.conf["server"],
+ **self.params,
+ )
stream = TeleCasterGStream(pipeline)
- stream.start()
+ if self.verbose:
+ print(pipeline)
+ if not self.dry_run:
+ stream.start()
time.sleep(BOOT_TIME_DELAY)
deefuzzer_local_conf = deepcopy(deefuzzer_station_conf)
deefuzzer_global_conf["deefuzzer"]["station"].append(deefuzzer_local_conf)
time.sleep(BOOT_TIME_DELAY)
- self.deefuzzer_start(deefuzzer_global_conf, self.deefuzzer_video_conf_file)
+ if not self.dry_run:
+ self.deefuzzer_start(deefuzzer_global_conf, self.deefuzzer_video_conf_file)
def audio_start(self):
deefuzzer_default_conf = deepcopy(self.conf["audio"]["deefuzzer"])
pipeline = AUDIO_PIPELINE_BASE.format(
**self.conf["audio"]["gstreamer"],
- **self.conf["server"])
+ **self.conf["server"],
+ **self.params,
+ )
stream = TeleCasterGStream(pipeline)
- stream.start()
+ if self.verbose:
+ print(pipeline)
+ if not self.dry_run:
+ stream.start()
time.sleep(BOOT_TIME_DELAY)
deefuzzer_local_conf = deepcopy(deefuzzer_station_conf)
deefuzzer_global_conf["deefuzzer"]["station"].append(deefuzzer_local_conf)
time.sleep(BOOT_TIME_DELAY)
- self.deefuzzer_start(deefuzzer_global_conf, self.deefuzzer_audio_conf_file)
+ if not self.dry_run:
+ self.deefuzzer_start(deefuzzer_global_conf, self.deefuzzer_audio_conf_file)
def connect(self):
- for post_command in self.audio_config["connect"]:
- command = TeleCasterCommand(post_command)
- command.start()
+ for connect in self.params["connect"]:
+ command = TeleCasterCommand(connect)
+ if self.verbose:
+ print(connect)
+ if not self.dry_run:
+ command.start()
def run(self):
self.audio_engine_start()
self.connect()
-
def main():
+ verbose = False
+ dry_run = False
+
if len(sys.argv) >= 2:
- tc = TeleCaster(sys.argv[-1])
+ tc = TeleCaster(sys.argv[-1], verbose, dry_run)
tc.start()
elif os.path.exists(DEFAULT_CONFIG_FILE):
- tc = TeleCaster(DEFAULT_CONFIG_FILE)
+ tc = TeleCaster(DEFAULT_CONFIG_FILE, verbose, dry_run)
tc.start()
else:
sys.exit()