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
+
+
+