From 1ee542ea3ec06739a027dc27f7ef8f88373fd906 Mon Sep 17 00:00:00 2001 From: Matthew Stratford Date: Tue, 12 Oct 2021 20:45:29 +0100 Subject: [PATCH] Fix linux to use pulseaudio. --- .gitignore | 2 ++ dev/scripts/get_linux_outputs.py | 24 ++++++++++++++++++++++++ helpers/device_manager.py | 14 ++++++++------ package-lock.json | 12 ++++++++++-- package.json | 5 ++++- player.py | 5 ++++- server.py | 6 ++++-- web_server.py | 15 +++++++++------ 8 files changed, 65 insertions(+), 18 deletions(-) create mode 100644 dev/scripts/get_linux_outputs.py diff --git a/.gitignore b/.gitignore index 66518ac..772a7f1 100644 --- a/.gitignore +++ b/.gitignore @@ -25,3 +25,5 @@ music-tmp/ presenter-build + +node_modules/ \ No newline at end of file diff --git a/dev/scripts/get_linux_outputs.py b/dev/scripts/get_linux_outputs.py new file mode 100644 index 0000000..323b6f2 --- /dev/null +++ b/dev/scripts/get_linux_outputs.py @@ -0,0 +1,24 @@ +import os + +os.environ["PYGAME_HIDE_SUPPORT_PROMPT"] = "hide" +os.putenv('SDL_AUDIODRIVER', 'pulseaudio') +import pygame._sdl2 as sdl2 +import pygame +from pygame import mixer +#pygame.init() +import time +mixer.init(44100, -16, 2, 1024) +is_capture = 0 # zero to request playback devices, non-zero to request recording devices +num = sdl2.get_num_audio_devices(is_capture) +names = [str(sdl2.get_audio_device_name(i, is_capture), encoding="utf-8") for i in range(num)] +mixer.quit() +for i in names: + print(i) + mixer.init(44100, -16, 2, 1024, devicename=i) + print(mixer.get_init()) + mixer.music.load("/home/mstratford/Downloads/managed_play.mp3") + mixer.music.play() + #my_song = mixer.Sound("/home/mstratford/Downloads/managed_play.mp3") + #my_song.play() + time.sleep(5) + pygame.quit() \ No newline at end of file diff --git a/helpers/device_manager.py b/helpers/device_manager.py index ae5c930..a7871f9 100644 --- a/helpers/device_manager.py +++ b/helpers/device_manager.py @@ -20,10 +20,10 @@ class DeviceManager: return host_api @classmethod - def _getAudioDevices(cls) -> sd.DeviceList: + def _getSDAudioDevices(cls): # To update the list of devices - # Sadly this doesn't work on MacOS. - if not isMacOS(): + # Sadly this only works on Windows. Linux hangs, MacOS crashes. + if isWindows(): sd._terminate() sd._initialize() devices: sd.DeviceList = sd.query_devices() @@ -31,11 +31,13 @@ class DeviceManager: @classmethod def getAudioOutputs(cls) -> Tuple[List[Dict]]: - host_apis = sd.query_hostapis() - devices: sd.DeviceList = cls._getAudioDevices() + + host_apis = list(sd.query_hostapis()) + devices: sd.DeviceList = cls._getSDAudioDevices() for host_api_id in range(len(host_apis)): - if isWindows() and host_apis[host_api_id]["name"] not in WINDOWS_APIS: + # Linux SDL uses PortAudio, which SoundDevice doesn't find. So mark all as unsable. + if (isWindows() and host_apis[host_api_id]["name"] not in WINDOWS_APIS) or (isLinux()): host_apis[host_api_id]["usable"] = False else: host_apis[host_api_id]["usable"] = True diff --git a/package-lock.json b/package-lock.json index 939f4ff..ac7f15d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,5 +1,13 @@ { "name": "bapsicle", - "version": "3.0.0", - "lockfileVersion": 1 + "version": "3.1.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "yarn": { + "version": "1.22.15", + "resolved": "https://registry.npmjs.org/yarn/-/yarn-1.22.15.tgz", + "integrity": "sha512-AzoEDxj256BOS/jqDXA3pjyhmi4FRBBUMgYoTHI4EIt2EhREkvH0soPVEtnD+DQIJfU5R9bKhcZ1H9l8zPWeoA==" + } + } } diff --git a/package.json b/package.json index cae6ea8..2d3161e 100644 --- a/package.json +++ b/package.json @@ -24,5 +24,8 @@ "bugs": { "url": "https://github.com/universityradioyork/bapsicle/issues" }, - "homepage": "https://github.com/universityradioyork/bapsicle#readme" + "homepage": "https://github.com/universityradioyork/bapsicle#readme", + "dependencies": { + "yarn": "^1.22.15" + } } diff --git a/player.py b/player.py index 5230432..0574168 100644 --- a/player.py +++ b/player.py @@ -21,8 +21,11 @@ # Stop the Pygame Hello message. import os - os.environ["PYGAME_HIDE_SUPPORT_PROMPT"] = "hide" +from helpers.os_environment import isLinux +# It's the only one we could get to work. +if isLinux(): + os.putenv('SDL_AUDIODRIVER', 'pulseaudio') from queue import Empty import multiprocessing diff --git a/server.py b/server.py index 82dde6e..4734dd4 100644 --- a/server.py +++ b/server.py @@ -23,7 +23,7 @@ import json from setproctitle import setproctitle import psutil -from helpers.os_environment import isMacOS +from helpers.os_environment import isLinux, isMacOS if not isMacOS(): # Rip, this doesn't like threading on MacOS. @@ -206,7 +206,9 @@ class BAPSicleServer: time.sleep(1) def startServer(self): - if isMacOS(): + # On MacOS, the default causes something to keep creating new processes. + # On Linux, this is needed to make pulseaudio initiate properly. + if isMacOS() or isLinux(): multiprocessing.set_start_method("spawn", True) process_title = "startServer" diff --git a/web_server.py b/web_server.py index 142db8a..1ae5068 100644 --- a/web_server.py +++ b/web_server.py @@ -540,9 +540,12 @@ def WebServer(player_to: List[Queue], player_from: List[Queue], state: StateMana ) except Exception: break - loop = asyncio.get_event_loop() - if loop: - loop.close() - if app: - app.stop() - del app + try: + loop = asyncio.get_event_loop() + if loop: + loop.close() + if app: + app.stop() + del app + except: + pass