basic audio transmission
This commit is contained in:
parent
ea733a2790
commit
259c46fa00
|
@ -1,7 +1,9 @@
|
||||||
|
from operator import indexOf
|
||||||
from PySide6 import QtCore, QtWidgets
|
from PySide6 import QtCore, QtWidgets
|
||||||
from generated.mainwindow import Ui_ScreenStreamer
|
from generated.mainwindow import Ui_ScreenStreamer
|
||||||
from streamer import Streamer
|
from streamer import Streamer
|
||||||
from reciever import Reciever
|
from reciever import Reciever
|
||||||
|
from pulse import Pulse
|
||||||
from Xlib import display
|
from Xlib import display
|
||||||
from Xlib.ext import randr
|
from Xlib.ext import randr
|
||||||
|
|
||||||
|
@ -19,6 +21,21 @@ class ScreenStreamerGUI(QtWidgets.QMainWindow):
|
||||||
for disp in displays:
|
for disp in displays:
|
||||||
self.ui.displaySelect.addItem("{} ({}x{})".format(disp['name'], disp['width'], disp['height']), userData=disp)
|
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.streamer = None
|
||||||
self.receiver = None
|
self.receiver = None
|
||||||
|
|
||||||
|
@ -67,6 +84,7 @@ class ScreenStreamerGUI(QtWidgets.QMainWindow):
|
||||||
self.streamer = Streamer(
|
self.streamer = Streamer(
|
||||||
self.format_display(displaydata),
|
self.format_display(displaydata),
|
||||||
self.format_screensize(displaydata),
|
self.format_screensize(displaydata),
|
||||||
|
self.ui.audioSource.currentData(),
|
||||||
self.ui.protocolSelect.currentText().lower(),
|
self.ui.protocolSelect.currentText().lower(),
|
||||||
self.ui.sendto.text()
|
self.ui.sendto.text()
|
||||||
)
|
)
|
||||||
|
@ -86,7 +104,8 @@ class ScreenStreamerGUI(QtWidgets.QMainWindow):
|
||||||
|
|
||||||
self.receiver = Reciever(
|
self.receiver = Reciever(
|
||||||
self.ui.protocolSelect.currentText().lower(),
|
self.ui.protocolSelect.currentText().lower(),
|
||||||
self.ui.listenAddr.text()
|
self.ui.listenAddr.text(),
|
||||||
|
self.ui.disableAudio.checkState() == 'Checked'
|
||||||
)
|
)
|
||||||
self.receiver.start()
|
self.receiver.start()
|
||||||
self.ui.recieveBtn.setText('Stop Recieve')
|
self.ui.recieveBtn.setText('Stop Recieve')
|
||||||
|
|
|
@ -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
|
|
@ -2,9 +2,10 @@ import subprocess
|
||||||
|
|
||||||
class Reciever:
|
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.protocol = protocol # should be 'tcp' or 'udp'
|
||||||
self.target = target
|
self.target = target
|
||||||
|
self.disable_audio = disable_audio
|
||||||
self.proc = None
|
self.proc = None
|
||||||
|
|
||||||
def __del__(self) -> None:
|
def __del__(self) -> None:
|
||||||
|
@ -13,8 +14,15 @@ class Reciever:
|
||||||
def start(self):
|
def start(self):
|
||||||
# currently there is no direct ffplay support in the ffmpeg package
|
# currently there is no direct ffplay support in the ffmpeg package
|
||||||
|
|
||||||
addr = self.protocol+ '://' + self.target + '?listen'
|
args = ['ffplay', '-fflags', 'nobuffer', '-flags', 'low_delay', '-f', 'mpegts']
|
||||||
self.proc = subprocess.Popen(['ffplay', '-fflags', 'nobuffer', '-flags', 'low_delay', '-f', 'mpegts', addr])
|
|
||||||
|
if self.disable_audio:
|
||||||
|
args.append('-an')
|
||||||
|
|
||||||
|
# the address
|
||||||
|
args.append(self.protocol+ '://' + self.target + '?listen')
|
||||||
|
|
||||||
|
self.proc = subprocess.Popen(args)
|
||||||
|
|
||||||
def stop(self):
|
def stop(self):
|
||||||
if self.proc:
|
if self.proc:
|
||||||
|
|
|
@ -2,9 +2,10 @@ import ffmpeg
|
||||||
|
|
||||||
class Streamer:
|
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.screendef = screendef
|
||||||
self.screensize = screensize
|
self.screensize = screensize
|
||||||
|
self.audioindex = audioindex
|
||||||
self.protocol = protocol # should be 'tcp' or 'udp'
|
self.protocol = protocol # should be 'tcp' or 'udp'
|
||||||
self.target = target
|
self.target = target
|
||||||
self.proc = None
|
self.proc = None
|
||||||
|
@ -13,8 +14,15 @@ class Streamer:
|
||||||
self.stop()
|
self.stop()
|
||||||
|
|
||||||
def start(self):
|
def start(self):
|
||||||
|
streams = []
|
||||||
self.input = ffmpeg.input(self.screendef, f='x11grab', r=60, s=self.screensize)
|
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)
|
self.proc = ffmpeg.run_async(self.output)
|
||||||
|
|
||||||
def stop(self):
|
def stop(self):
|
||||||
|
|
|
@ -64,27 +64,37 @@
|
||||||
<item row="1" column="1">
|
<item row="1" column="1">
|
||||||
<widget class="QComboBox" name="displaySelect"/>
|
<widget class="QComboBox" name="displaySelect"/>
|
||||||
</item>
|
</item>
|
||||||
<item row="2" column="0">
|
<item row="3" column="0">
|
||||||
<widget class="QLabel" name="RecieverLabel">
|
<widget class="QLabel" name="RecieverLabel">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Reciever</string>
|
<string>Reciever</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="2" column="1">
|
<item row="3" column="1">
|
||||||
<widget class="QLineEdit" name="sendto">
|
<widget class="QLineEdit" name="sendto">
|
||||||
<property name="placeholderText">
|
<property name="placeholderText">
|
||||||
<string>127.0.0.1:1234</string>
|
<string>127.0.0.1:1234</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="3" column="0" colspan="2">
|
<item row="4" column="0" colspan="2">
|
||||||
<widget class="QPushButton" name="streamBtn">
|
<widget class="QPushButton" name="streamBtn">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Stream</string>
|
<string>Stream</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item row="2" column="0">
|
||||||
|
<widget class="QLabel" name="audioSourceLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string>Audio Source</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="1">
|
||||||
|
<widget class="QComboBox" name="audioSource"/>
|
||||||
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
@ -115,6 +125,13 @@
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item row="2" column="0">
|
||||||
|
<widget class="QCheckBox" name="disableAudio">
|
||||||
|
<property name="text">
|
||||||
|
<string>Disable Audio</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
|
Loading…
Reference in New Issue