From 259c46fa0042e05cf6011c0f4dc8f665bd4efd85 Mon Sep 17 00:00:00 2001 From: mrbesen Date: Fri, 7 Oct 2022 22:54:27 +0200 Subject: [PATCH] basic audio transmission --- screenstreamer/gui.py | 21 ++++++++++++++++++- screenstreamer/pulse.py | 43 ++++++++++++++++++++++++++++++++++++++ screenstreamer/reciever.py | 14 ++++++++++--- screenstreamer/streamer.py | 12 +++++++++-- ui/mainwindow.ui | 23 +++++++++++++++++--- 5 files changed, 104 insertions(+), 9 deletions(-) create mode 100644 screenstreamer/pulse.py diff --git a/screenstreamer/gui.py b/screenstreamer/gui.py index 6594789..e019dcc 100644 --- a/screenstreamer/gui.py +++ b/screenstreamer/gui.py @@ -1,7 +1,9 @@ +from operator import indexOf from PySide6 import QtCore, QtWidgets from generated.mainwindow import Ui_ScreenStreamer from streamer import Streamer from reciever import Reciever +from pulse import Pulse from Xlib import display from Xlib.ext import randr @@ -19,6 +21,21 @@ class ScreenStreamerGUI(QtWidgets.QMainWindow): for disp in displays: self.ui.displaySelect.addItem("{} ({}x{})".format(disp['name'], disp['width'], disp['height']), userData=disp) + audiodevices = Pulse.get_audio_inputs() + print(audiodevices) + + self.ui.audioSource.addItem('No Audio', userData=-1) # always add this option + + for audio in audiodevices: + text = audio['description'] if audio['description'] else audio['name'] + if audio.get('monitor', False): + text += ' (Monitor)' + + self.ui.audioSource.addItem(text, userData=audio['id']) + + if audio.get('isdefault', False): + self.ui.audioSource.setCurrentIndex(indexOf(audiodevices, audio)) + self.streamer = None self.receiver = None @@ -67,6 +84,7 @@ class ScreenStreamerGUI(QtWidgets.QMainWindow): self.streamer = Streamer( self.format_display(displaydata), self.format_screensize(displaydata), + self.ui.audioSource.currentData(), self.ui.protocolSelect.currentText().lower(), self.ui.sendto.text() ) @@ -86,7 +104,8 @@ class ScreenStreamerGUI(QtWidgets.QMainWindow): self.receiver = Reciever( self.ui.protocolSelect.currentText().lower(), - self.ui.listenAddr.text() + self.ui.listenAddr.text(), + self.ui.disableAudio.checkState() == 'Checked' ) self.receiver.start() self.ui.recieveBtn.setText('Stop Recieve') diff --git a/screenstreamer/pulse.py b/screenstreamer/pulse.py new file mode 100644 index 0000000..108d7c7 --- /dev/null +++ b/screenstreamer/pulse.py @@ -0,0 +1,43 @@ +import subprocess +from os import environ + +class Pulse: + + # this method uses the intern names of the sinks + # @staticmethod + # def get_audio_inputs(): + # proc = subprocess.run(['pactl', 'list', 'short', 'sources'], capture_output=True) + # parts = [line.split('\t') for line in proc.stdout.decode('utf-8').split('\n')] + # deviceinfos = [{'id': device[0], 'name': device[1]} for device in parts if len(device) > 1] + # return deviceinfos + + @staticmethod + def get_audio_inputs(): + proc = subprocess.run(['pacmd', 'list-sources'], capture_output=True, env={**environ, 'LANG': 'C'}) + lines = proc.stdout.decode('utf-8').split('\n') + currentSourceID = -1 + currentName = '' + ismointor = False + isdefault = False + description = '' + devices = [] + for line in lines: + if line[4:].startswith('index: '): + #submit old device + if currentSourceID != -1: + devices.append({'id': currentSourceID, 'name': currentName, 'monitor': ismointor, 'description': description, 'isdefault': isdefault}) + + ismointor = False + isdefault = line[2] == '*' + description = '' + currentSourceID = int(line[11:]) + elif line.startswith('\tname: '): + currentName = line[8:-1] + elif line == '\t\tdevice.class = "monitor"': + ismointor = True + elif line.startswith('\t\tdevice.description = "'): + description = line[24:-1] + + devices.append({'id': currentSourceID, 'name': currentName, 'monitor': ismointor, 'description': description, 'isdefault': isdefault}) + + return devices diff --git a/screenstreamer/reciever.py b/screenstreamer/reciever.py index b605490..9c6d2fc 100644 --- a/screenstreamer/reciever.py +++ b/screenstreamer/reciever.py @@ -2,9 +2,10 @@ import subprocess class Reciever: - def __init__(self, protocol: str, target: str) -> None: + def __init__(self, protocol: str, target: str, disable_audio: bool) -> None: self.protocol = protocol # should be 'tcp' or 'udp' self.target = target + self.disable_audio = disable_audio self.proc = None def __del__(self) -> None: @@ -13,8 +14,15 @@ class Reciever: def start(self): # currently there is no direct ffplay support in the ffmpeg package - addr = self.protocol+ '://' + self.target + '?listen' - self.proc = subprocess.Popen(['ffplay', '-fflags', 'nobuffer', '-flags', 'low_delay', '-f', 'mpegts', addr]) + args = ['ffplay', '-fflags', 'nobuffer', '-flags', 'low_delay', '-f', 'mpegts'] + + if self.disable_audio: + args.append('-an') + + # the address + args.append(self.protocol+ '://' + self.target + '?listen') + + self.proc = subprocess.Popen(args) def stop(self): if self.proc: diff --git a/screenstreamer/streamer.py b/screenstreamer/streamer.py index 3c1abb7..f57fe47 100644 --- a/screenstreamer/streamer.py +++ b/screenstreamer/streamer.py @@ -2,9 +2,10 @@ import ffmpeg class Streamer: - def __init__(self, screendef: str, screensize: str, protocol: str, target: str) -> None: + def __init__(self, screendef: str, screensize: str, audioindex: int, protocol: str, target: str) -> None: self.screendef = screendef self.screensize = screensize + self.audioindex = audioindex self.protocol = protocol # should be 'tcp' or 'udp' self.target = target self.proc = None @@ -13,8 +14,15 @@ class Streamer: self.stop() def start(self): + streams = [] self.input = ffmpeg.input(self.screendef, f='x11grab', r=60, s=self.screensize) - self.output = ffmpeg.output(self.input, self.protocol + '://' + self.target, f='mpegts', vcodec='nvenc_hevc', tune='zerolatency') + streams.append(self.input) + + if self.audioindex != -1: + self.audio = ffmpeg.input(str(self.audioindex), f='pulse') + streams.append(self.audio) + + self.output = ffmpeg.output(*streams, self.protocol + '://' + self.target, f='mpegts', vcodec='nvenc_hevc', tune='zerolatency') self.proc = ffmpeg.run_async(self.output) def stop(self): diff --git a/ui/mainwindow.ui b/ui/mainwindow.ui index f76e10e..ddfdf7e 100644 --- a/ui/mainwindow.ui +++ b/ui/mainwindow.ui @@ -64,27 +64,37 @@ - + Reciever - + 127.0.0.1:1234 - + Stream + + + + Audio Source + + + + + + @@ -115,6 +125,13 @@ + + + + Disable Audio + + +