a
This commit is contained in:
parent
fa5ccb3b86
commit
3aeb7b39cf
|
@ -1,75 +1,126 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# Pulseaudio Socket Bridge v1.0.1
|
import asyncio
|
||||||
# by Zoey Mae (izalia@barkshark.xyz)
|
import os
|
||||||
#
|
import signal
|
||||||
# Creates a unix socket to listen on and sends any connections to the specified
|
import sys
|
||||||
# Pulseaudio server via socat. Socat will try to reconnect and will be restarted
|
import traceback
|
||||||
# if closed for any reason
|
|
||||||
#
|
|
||||||
# Usage:
|
|
||||||
# pa-socket-bridge.py [server ip]
|
|
||||||
|
|
||||||
import os, signal, sys, time
|
|
||||||
from pathlib import Path
|
|
||||||
from subprocess import Popen
|
|
||||||
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
server = sys.argv[1]
|
remote_address = sys.argv[1]
|
||||||
except IndexError:
|
except IndexError:
|
||||||
server = "127.0.0.1"
|
raise ValueError('No remote address specified')
|
||||||
|
|
||||||
sock_path = Path(f'/var/run/user/{os.getuid()}/pulse/native')
|
try:
|
||||||
command = ['socat', f'UNIX-LISTEN:{sock_path},fork,reuseaddr,mode=777', f'TCP:{server}:4713,retry']
|
remote_port = int(sys.argv[2])
|
||||||
shutdown = False
|
except IndexError:
|
||||||
|
remote_port = 4713
|
||||||
if not sock_path.parent.exists():
|
|
||||||
sock_path.parent.mkdir(parents=True)
|
|
||||||
|
|
||||||
if sock_path.exists():
|
|
||||||
print('Socket already exists. Is Pulseaudio or another bridge running?')
|
|
||||||
sys.exit()
|
|
||||||
|
|
||||||
|
|
||||||
def signal_handler(func, *args, **kwargs):
|
running = False
|
||||||
handler = lambda signum, frame: func(signum, frame, *args, **kwargs)
|
socket_path = f'/var/run/user/{os.getuid()}/pulse/native'
|
||||||
|
tasks = []
|
||||||
signal.signal(signal.SIGHUP, handler)
|
signals_to_handle = [
|
||||||
signal.signal(signal.SIGINT, handler)
|
signal.SIGHUP,
|
||||||
signal.signal(signal.SIGQUIT, handler)
|
signal.SIGINT,
|
||||||
signal.signal(signal.SIGTERM, handler)
|
signal.SIGTERM,
|
||||||
|
signal.SIGQUIT
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
def handle_shutdown(signum, frame):
|
async def proxy(reader, writer):
|
||||||
global shutdown
|
while True:
|
||||||
shutdown = True
|
if not running:
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
data = await reader.read(512)
|
||||||
|
|
||||||
|
if not data:
|
||||||
|
break
|
||||||
|
|
||||||
|
writer.write(data)
|
||||||
|
await writer.drain()
|
||||||
|
|
||||||
|
except ConnectionResetError:
|
||||||
|
break
|
||||||
|
|
||||||
|
writer.close()
|
||||||
|
|
||||||
|
|
||||||
|
async def handle_connection(source_reader, source_writer):
|
||||||
|
if not running:
|
||||||
|
loop.stop()
|
||||||
|
return
|
||||||
|
|
||||||
|
target_reader, target_writer = await asyncio.open_connection(remote_address, remote_port)
|
||||||
|
|
||||||
|
try:
|
||||||
|
address = source_writer.get_extra_info('peername')[0]
|
||||||
|
except IndexError:
|
||||||
|
address = 'unix socket'
|
||||||
|
|
||||||
|
print('New connection from', address)
|
||||||
|
|
||||||
|
await asyncio.gather(*[proxy(source_reader, target_writer), proxy(target_reader, source_writer)])
|
||||||
|
|
||||||
|
print('Closed connection to', address)
|
||||||
|
|
||||||
|
|
||||||
|
def signal_handler(callback=None):
|
||||||
|
for sig in signals_to_handle:
|
||||||
|
if callback:
|
||||||
|
loop.add_signal_handler(sig, callback)
|
||||||
|
|
||||||
|
else:
|
||||||
|
loop.remove_signal_handler(sig)
|
||||||
|
|
||||||
|
|
||||||
|
def stop(*args):
|
||||||
|
global running
|
||||||
|
|
||||||
|
if not running:
|
||||||
|
return
|
||||||
|
|
||||||
|
running = False
|
||||||
|
signal_handler()
|
||||||
|
|
||||||
|
for server in servers:
|
||||||
|
server.close()
|
||||||
|
|
||||||
|
for task in tasks:
|
||||||
|
task.cancel()
|
||||||
|
|
||||||
|
while True:
|
||||||
|
if task.done():
|
||||||
|
break
|
||||||
|
|
||||||
|
loop.stop()
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
print('Starting Pulseaudio socket bridge')
|
if os.path.exists(socket_path):
|
||||||
|
os.remove(socket_path)
|
||||||
|
|
||||||
signal_handler(handle_shutdown)
|
loop = asyncio.new_event_loop()
|
||||||
|
|
||||||
proc = Popen(command)
|
signal_handler(stop)
|
||||||
timer = 0.0
|
|
||||||
|
|
||||||
while not shutdown:
|
servers = [
|
||||||
if proc.poll() != None:
|
asyncio.start_server(handle_connection, 'localhost', 4713),
|
||||||
print('Restarting process')
|
asyncio.start_unix_server(handle_connection, path=socket_path)
|
||||||
proc = Popen(command)
|
]
|
||||||
|
|
||||||
time.sleep(0.25)
|
for server in servers:
|
||||||
|
tasks.append(loop.create_task(server))
|
||||||
|
|
||||||
print('Terminating process')
|
running = True
|
||||||
proc.terminate()
|
|
||||||
|
|
||||||
while proc.poll() == None:
|
try:
|
||||||
time.sleep(0.25)
|
loop.run_forever()
|
||||||
timer += 0.25
|
except KeyboardInterrupt:
|
||||||
|
pass
|
||||||
|
|
||||||
if timer >= 5.0:
|
stop()
|
||||||
proc.kill()
|
|
||||||
print('Socat failed to terminate. Killing process.')
|
|
||||||
break
|
|
||||||
|
|
||||||
print('Bye! :3')
|
loop.close()
|
||||||
|
|
|
@ -8,9 +8,19 @@ from urllib.request import Request, urlopen, urlretrieve
|
||||||
|
|
||||||
|
|
||||||
url = 'https://api.github.com/repos/GloriousEggroll/proton-ge-custom/releases/latest'
|
url = 'https://api.github.com/repos/GloriousEggroll/proton-ge-custom/releases/latest'
|
||||||
protondir = Path('~/.steam/compatibilitytools.d/').expanduser()
|
compatdirs = [
|
||||||
|
'~/.steam/compatibilitytools.d',
|
||||||
|
'~/.steam/debian-installation/compatibilitytools.d',
|
||||||
|
'~/.steam/steam/compatibilitytools.d'
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
for directory in compatdirs:
|
||||||
|
protondir = Path(directory).expanduser()
|
||||||
|
|
||||||
|
if protondir.exists():
|
||||||
|
break
|
||||||
|
|
||||||
if not protondir.exists():
|
if not protondir.exists():
|
||||||
protondir.mkdir(parents=True, exist_ok=True)
|
protondir.mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue