Audiomixer zeigt Programme statt Prozesse
Core Audio meldet Prozesse, nicht Programme. Angezeigt wurden deshalb Kennungen wie „com.apple.WebKit.GPU" und Dutzende Systemdienste, die theoretisch Ton ausgeben könnten, es aber nie tun. ProcessNaming fragt erst das laufende Programm, kürzt sonst bekannte Hilfsprozess-Endungen weg und schlägt das übergeordnete Programm nach — Chromes Ton kommt aus einem Helfer, angezeigt gehört Chrome. Symbole gehen denselben Weg, sonst steht neben dem Namen ein Platzhalter. ProcessVisibility zeigt, was klingt, kürzlich klang oder geregelt wird. Die Nachlaufzeit von zwei Minuten ist der eigentliche Punkt: ohne sie verschwindet Spotify beim Pausieren aus der Liste, und man kann die Lautstärke genau dann nicht mehr einstellen, wenn man es will. Geregelte Programme bleiben immer — wer etwas leiser gedreht hat, muss es auch zurückdrehen können. Die Prozentzahl wandert vom Namen zum Regler. Oben war sie genau die Breite, die den Namen abgeschnitten hat. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
100
Packages/OnyxKit/Tests/AudioProviderTests/ProcessNameTests.swift
Normal file
100
Packages/OnyxKit/Tests/AudioProviderTests/ProcessNameTests.swift
Normal file
@@ -0,0 +1,100 @@
|
||||
import Testing
|
||||
@testable import AudioProvider
|
||||
|
||||
// Core Audio meldet Prozesse, nicht Programme. Was dort ankommt, heißt
|
||||
// `com.google.Chrome.helper` oder `com.apple.WebKit.GPU` — Kennungen, die in
|
||||
// einem Mischpult nichts zu suchen haben. Wer „Spotify leiser" sucht, sucht
|
||||
// nach „Spotify".
|
||||
|
||||
@Suite("Programmnamen")
|
||||
struct ProcessNameTests {
|
||||
|
||||
@Test("Aus einer Kennung wird ein lesbarer Name")
|
||||
func plainIdentifier() {
|
||||
#expect(ProcessNaming.fallbackName(for: "com.spotify.client") == "Spotify")
|
||||
}
|
||||
|
||||
@Test("Hilfsprozesse werden ihrem Programm zugeordnet")
|
||||
func helpersMapToParent() {
|
||||
// Chromes Ton kommt aus einem Hilfsprozess. Ihn als
|
||||
// „com.google.Chrome.helper" zu zeigen wäre technisch richtig und
|
||||
// praktisch nutzlos.
|
||||
#expect(ProcessNaming.parentBundleID(for: "com.google.Chrome.helper")
|
||||
== "com.google.Chrome")
|
||||
#expect(ProcessNaming.parentBundleID(for: "com.google.Chrome.helper.Renderer")
|
||||
== "com.google.Chrome")
|
||||
}
|
||||
|
||||
@Test("Weitere übliche Endungen von Hilfsprozessen")
|
||||
func knownHelperSuffixes() {
|
||||
#expect(ProcessNaming.parentBundleID(for: "net.whatsapp.WhatsApp.ServiceExtension")
|
||||
== "net.whatsapp.WhatsApp")
|
||||
#expect(ProcessNaming.parentBundleID(for: "com.example.App.Helper")
|
||||
== "com.example.App")
|
||||
}
|
||||
|
||||
@Test("Eine gewöhnliche Kennung bleibt unverändert")
|
||||
func plainIdentifierIsUntouched() {
|
||||
#expect(ProcessNaming.parentBundleID(for: "com.spotify.client") == "com.spotify.client")
|
||||
}
|
||||
|
||||
@Test("Der Hilfsprozess einer Komponente zeigt die Komponente")
|
||||
func helperShowsItsComponent() {
|
||||
// `.GPU` ist eine Hilfsprozess-Endung, also bleibt WebKit übrig. Das
|
||||
// ist die nützlichere Auskunft: „GPU" allein sagt niemandem etwas.
|
||||
#expect(ProcessNaming.fallbackName(for: "com.apple.WebKit.GPU") == "WebKit")
|
||||
#expect(ProcessNaming.fallbackName(for: "pro.betterdisplay.BetterDisplay")
|
||||
== "BetterDisplay")
|
||||
}
|
||||
|
||||
@Test("Eine Kennung ohne Punkte bleibt sie selbst")
|
||||
func singleComponent() {
|
||||
#expect(ProcessNaming.fallbackName(for: "systemsoundserverd") == "systemsoundserverd")
|
||||
}
|
||||
|
||||
@Test("Eine leere Kennung ergibt keinen leeren Namen")
|
||||
func emptyIsHandled() {
|
||||
#expect(!ProcessNaming.fallbackName(for: "").isEmpty)
|
||||
}
|
||||
}
|
||||
|
||||
@Suite("Sichtbarkeit im Mischpult")
|
||||
struct ProcessVisibilityTests {
|
||||
|
||||
@Test("Was gerade Ton ausgibt, wird gezeigt")
|
||||
func playingIsVisible() {
|
||||
#expect(ProcessVisibility.shouldShow(isPlaying: true, secondsSinceHeard: nil,
|
||||
isManaged: false))
|
||||
}
|
||||
|
||||
@Test("Was nie Ton ausgegeben hat, wird nicht gezeigt")
|
||||
func neverHeardIsHidden() {
|
||||
// Der eigentliche Punkt: Core Audio führt Dutzende Systemdienste, die
|
||||
// theoretisch Ton ausgeben könnten. In einem Mischpult sind sie nur
|
||||
// Rauschen.
|
||||
#expect(!ProcessVisibility.shouldShow(isPlaying: false, secondsSinceHeard: nil,
|
||||
isManaged: false))
|
||||
}
|
||||
|
||||
@Test("Kurz nach dem Verstummen bleibt es sichtbar")
|
||||
func recentlyHeardStaysVisible() {
|
||||
// Sonst verschwindet Spotify beim Pausieren aus der Liste, und man kann
|
||||
// die Lautstärke genau dann nicht mehr einstellen, wenn man es will.
|
||||
#expect(ProcessVisibility.shouldShow(isPlaying: false, secondsSinceHeard: 30,
|
||||
isManaged: false))
|
||||
}
|
||||
|
||||
@Test("Lange danach verschwindet es")
|
||||
func longSilentDisappears() {
|
||||
#expect(!ProcessVisibility.shouldShow(isPlaying: false, secondsSinceHeard: 600,
|
||||
isManaged: false))
|
||||
}
|
||||
|
||||
@Test("Ein geregeltes Programm bleibt immer sichtbar")
|
||||
func managedIsAlwaysVisible() {
|
||||
// Wer die Lautstärke von etwas eingestellt hat, muss sie auch wieder
|
||||
// zurücknehmen können — auch wenn gerade nichts läuft.
|
||||
#expect(ProcessVisibility.shouldShow(isPlaying: false, secondsSinceHeard: 99999,
|
||||
isManaged: true))
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user