Add Chinese locale, fix audio device duplicates, remove display lock restriction
- Add Simplified Chinese (中文) locale with all 906 translation keys - Fix duplicate audio devices: WASAPI two-pass enumerate avoids double-listing loopback endpoints; cross-engine dedup by (name, is_loopback) prefers higher-priority engine - Remove redundant display lock check from capture template, picture source, and postprocessing template test endpoints — screen capture is read-only and concurrent access is safe Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -253,13 +253,27 @@ class AudioCaptureManager:
|
||||
"""List available audio devices from all registered engines.
|
||||
|
||||
Returns list of dicts with device info, each tagged with engine_type.
|
||||
Deduplicates by (name, is_loopback), keeping the entry from the
|
||||
highest-priority engine.
|
||||
"""
|
||||
# Collect from all engines, sorted by descending priority
|
||||
engines = [
|
||||
(engine_class.ENGINE_PRIORITY, engine_type, engine_class)
|
||||
for engine_type, engine_class in AudioEngineRegistry.get_all_engines().items()
|
||||
]
|
||||
engines.sort(key=lambda x: x[0], reverse=True)
|
||||
|
||||
seen: set = set()
|
||||
result = []
|
||||
for engine_type, engine_class in AudioEngineRegistry.get_all_engines().items():
|
||||
for _priority, engine_type, engine_class in engines:
|
||||
try:
|
||||
if not engine_class.is_available():
|
||||
continue
|
||||
for dev in engine_class.enumerate_devices():
|
||||
key = (dev.name, dev.is_loopback)
|
||||
if key in seen:
|
||||
continue
|
||||
seen.add(key)
|
||||
result.append({
|
||||
"index": dev.index,
|
||||
"name": dev.name,
|
||||
|
||||
@@ -163,34 +163,56 @@ class WasapiEngine(AudioCaptureEngine):
|
||||
wasapi_idx = wasapi_info["index"]
|
||||
|
||||
result = []
|
||||
loopback_names: set = set()
|
||||
device_count = pa.get_device_count()
|
||||
|
||||
# First pass: collect input devices. PyAudioWPatch creates
|
||||
# dedicated loopback input endpoints for output devices; these
|
||||
# show up as input devices whose name already contains
|
||||
# "[Loopback]". We mark them as loopback and remember the name
|
||||
# so the second pass won't duplicate them.
|
||||
for i in range(device_count):
|
||||
dev = pa.get_device_info_by_index(i)
|
||||
if dev["hostApi"] != wasapi_idx:
|
||||
continue
|
||||
if dev["maxInputChannels"] <= 0:
|
||||
continue
|
||||
|
||||
is_input = dev["maxInputChannels"] > 0
|
||||
is_output = dev["maxOutputChannels"] > 0
|
||||
name = dev["name"]
|
||||
is_loopback = "[Loopback]" in name
|
||||
if is_loopback:
|
||||
loopback_names.add(name)
|
||||
|
||||
if is_input:
|
||||
result.append(AudioDeviceInfo(
|
||||
index=i,
|
||||
name=dev["name"],
|
||||
is_input=True,
|
||||
is_loopback=False,
|
||||
channels=dev["maxInputChannels"],
|
||||
default_samplerate=dev["defaultSampleRate"],
|
||||
))
|
||||
result.append(AudioDeviceInfo(
|
||||
index=i,
|
||||
name=name,
|
||||
is_input=True,
|
||||
is_loopback=is_loopback,
|
||||
channels=dev["maxInputChannels"],
|
||||
default_samplerate=dev["defaultSampleRate"],
|
||||
))
|
||||
|
||||
if is_output:
|
||||
result.append(AudioDeviceInfo(
|
||||
index=i,
|
||||
name=f"{dev['name']} [Loopback]",
|
||||
is_input=False,
|
||||
is_loopback=True,
|
||||
channels=dev["maxOutputChannels"],
|
||||
default_samplerate=dev["defaultSampleRate"],
|
||||
))
|
||||
# Second pass: add loopback entries for output devices that
|
||||
# don't already have a dedicated loopback input endpoint.
|
||||
for i in range(device_count):
|
||||
dev = pa.get_device_info_by_index(i)
|
||||
if dev["hostApi"] != wasapi_idx:
|
||||
continue
|
||||
if dev["maxOutputChannels"] <= 0:
|
||||
continue
|
||||
|
||||
loopback_name = f"{dev['name']} [Loopback]"
|
||||
if loopback_name in loopback_names:
|
||||
continue # already covered by a dedicated loopback endpoint
|
||||
|
||||
result.append(AudioDeviceInfo(
|
||||
index=i,
|
||||
name=loopback_name,
|
||||
is_input=False,
|
||||
is_loopback=True,
|
||||
channels=dev["maxOutputChannels"],
|
||||
default_samplerate=dev["defaultSampleRate"],
|
||||
))
|
||||
|
||||
return result
|
||||
|
||||
|
||||
Reference in New Issue
Block a user