mirror of https://github.com/LedFx/LedFx.git
Refactor audio input device selection logic (#897)
* Refactor audio input device selection logic * add audio input device check in __main__.py and audio.py.
This commit is contained in:
parent
98ffbd83cb
commit
49dc34bd5a
|
@ -110,7 +110,6 @@ jobs:
|
|||
- name: Install build dependencies
|
||||
run: |
|
||||
brew install portaudio
|
||||
|
||||
- name: Setup Python ${{ env.DEFAULT_PYTHON }}
|
||||
id: python
|
||||
uses: actions/setup-python@v5
|
||||
|
|
|
@ -14,6 +14,7 @@ import os
|
|||
import sys
|
||||
from logging.handlers import RotatingFileHandler
|
||||
|
||||
from ledfx.effects.audio import AudioAnalysisSource
|
||||
from ledfx.sentry_config import setup_sentry
|
||||
|
||||
try:
|
||||
|
@ -232,7 +233,6 @@ def main():
|
|||
# Set some process priority optimisations
|
||||
if have_psutil:
|
||||
p = psutil.Process(os.getpid())
|
||||
|
||||
if psutil.WINDOWS:
|
||||
try:
|
||||
p.nice(psutil.HIGH_PRIORITY_CLASS)
|
||||
|
@ -247,7 +247,7 @@ def main():
|
|||
p.ionice(psutil.IOPRIO_CLASS_RT, value=7)
|
||||
except psutil.Error:
|
||||
_LOGGER.info(
|
||||
"Unable to set priority, please run as root or sudo if you are experiencing frame rate issues",
|
||||
"Unable to set priority, please run as root or use sudo if you are experiencing frame rate issues",
|
||||
)
|
||||
else:
|
||||
p.nice(15)
|
||||
|
@ -256,18 +256,30 @@ def main():
|
|||
setup_sentry()
|
||||
|
||||
if args.sentry_test:
|
||||
"""This will crash LedFx and submit a Sentry error if Sentry is configured"""
|
||||
_LOGGER.warning("Steering LedFx into a brick wall")
|
||||
_LOGGER.warning("Steering LedFx into a brick wall.")
|
||||
div_by_zero = 1 / 0
|
||||
|
||||
# Check if there are any audio input devices and quit if there are none.
|
||||
# TODO: Review the sentry hits for this logger statement and see if it's worth supporting without a mic.
|
||||
# NOTE: We don't do this in CI - some runners don't have audio devices.
|
||||
if (
|
||||
AudioAnalysisSource.audio_input_device_exists() is False
|
||||
and args.ci_smoke_test is False
|
||||
):
|
||||
_LOGGER.critical(
|
||||
"No audio input devices found. Please connect a microphone or input device and restart LedFx."
|
||||
)
|
||||
# Exit with code 2 to indicate that there are no audio input devices.
|
||||
sys.exit(2)
|
||||
if (args.tray or currently_frozen()) and not args.no_tray:
|
||||
# If pystray is imported on a device that can't display it, it explodes. Catch it
|
||||
try:
|
||||
import pystray
|
||||
except Exception as Error:
|
||||
msg = f"Error: Unable to virtual tray icon. Shutting down. Error: {Error}"
|
||||
msg = f"Unable to create tray icon. Error: {Error}. Try launching LedFx via --no-tray option."
|
||||
_LOGGER.critical(msg)
|
||||
sys.exit(0)
|
||||
# Exit with code 3 to indicate that there was an error creating the tray icon.
|
||||
sys.exit(3)
|
||||
|
||||
from PIL import Image
|
||||
|
||||
|
|
|
@ -360,6 +360,7 @@ def ensure_config_directory(config_dir: str) -> None:
|
|||
_LOGGER.critical(
|
||||
f"Unable to create configuration directory at {config_dir}. Shutting down."
|
||||
)
|
||||
# Exit with code 1 to indicate that there was an error creating the configuration directory.
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
|
|
|
@ -53,6 +53,13 @@ class AudioInputSource:
|
|||
"""
|
||||
return tuple(AudioInputSource.input_devices().keys())
|
||||
|
||||
@staticmethod
|
||||
def audio_input_device_exists():
|
||||
"""
|
||||
Returns True if there are valid input devices
|
||||
"""
|
||||
return len(AudioInputSource.valid_device_indexes()) > 0
|
||||
|
||||
@staticmethod
|
||||
def default_device_index():
|
||||
"""
|
||||
|
@ -68,12 +75,34 @@ class AudioInputSource:
|
|||
f"{device_list[default_output_device]['name']} [Loopback]"
|
||||
)
|
||||
# We need to run over the device list looking for the target device
|
||||
# NOTE: Some sound drivers truncate the device name, so we may not find a match
|
||||
for device_index, device in enumerate(device_list):
|
||||
if device["name"] == target_device:
|
||||
# Return the loopback device index
|
||||
_LOGGER.debug(
|
||||
f"Default audio loopback device found: {device['name']}"
|
||||
)
|
||||
return device_index
|
||||
# No Loopback device matching output found - return the default input device index
|
||||
return sd.default.device["input"]
|
||||
# If we don't match a Loopback device matching output found - return the default input device index
|
||||
default_input_device_idx = sd.default.device["input"]
|
||||
# The default input device index is not always valid (i.e no default input devices)
|
||||
if default_input_device_idx in AudioInputSource.valid_device_indexes():
|
||||
_LOGGER.debug(
|
||||
"No default audio loopback device found. Using default input device."
|
||||
)
|
||||
return default_input_device_idx
|
||||
else:
|
||||
# Return the first valid input device index if we can't find a valid default input device
|
||||
if len(AudioInputSource.valid_device_indexes()) > 0:
|
||||
_LOGGER.debug(
|
||||
"No valid default audio input device found. Using first valid input device."
|
||||
)
|
||||
return next(iter(AudioInputSource.valid_device_indexes()))
|
||||
else:
|
||||
_LOGGER.warning(
|
||||
"No valid audio input devices found. Unable to use audio reactive effects."
|
||||
)
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def query_hostapis():
|
||||
|
@ -181,6 +210,15 @@ class AudioInputSource:
|
|||
input_devices = self.query_devices()
|
||||
hostapis = self.query_hostapis()
|
||||
default_device = self.default_device_index()
|
||||
if default_device is None:
|
||||
# There are no valid audio input devices, so we can't activate the audio source.
|
||||
# We should never get here, as we check for devices on start-up.
|
||||
# This likely just captures if a device is removed after start-up.
|
||||
_LOGGER.warning(
|
||||
"Audio input device not found. Unable to activate audio source. Deactivating."
|
||||
)
|
||||
self.deactivate()
|
||||
return
|
||||
valid_device_indexes = self.valid_device_indexes()
|
||||
device_idx = self._config["audio_device"]
|
||||
|
||||
|
|
Loading…
Reference in New Issue