Wie kann ich die Lautstärke eines Hintergrundmusik-Streams reduzieren, wenn eine andere Audioquelle abgespielt wird?

7

Mit PulseAudio ist es möglich, das Volumen auf Anwendungsbasis zu verwalten, aber ich finde es kaum sinnvoll, es manuell zu tun. Was ich lieber hätte, ist Folgendes: Ich höre normalerweise Musik, möchte aber manchmal ein YouTube-Video ansehen - dann muss ich die Lautstärke der Musik manuell anhalten oder verringern, oft vergesse ich, sie wieder einzuschalten, wenn Das Video ist vorbei.

Was muss ich tun, um die Lautstärke eines Audiostreams (der Hintergrundmusik) automatisch zu verringern, wenn eine andere Anwendung Sound wiedergibt?

Pantalaimon
quelle
2
Dies wird als "Audio-Ducking" bezeichnet. Ich habe selbst nicht damit gespielt, kann also keine Antwort schreiben, aber hier ist eine Dokumentation: freedesktop.org/wiki/Software/PulseAudio/Documentation/User/… ... dieser Anker sieht nicht vertrauenswürdig aus, Es geht um den Abschnitt "Modul-Rolle-Ente".
Derobert

Antworten:

2

Keine gute Antwort, aber ich könnte genauso gut die Probleme / Möglichkeiten beschreiben, die ich gefunden habe.

Ich kann keine Möglichkeit finden, ein Shell-Skript dafür zu schreiben. Es gibt keine (dokumentierte) Möglichkeit, mit pactl/ pro Anwendungsvolumen zu ändern pacmd. Ich kann auch nicht feststellen, wann ein neuer Client hinzugefügt wird, ohne wiederholt folgende Abfragen durchzuführen:

pactl list short clients

Pulse Audio kann so eingestellt werden, dass es sich anmeldet. syslogEine Möglichkeit besteht darin, ein Skript mit dem Namen via rsyslogaufzurufen (sofern die Distribution dies hat). In meiner Antwort hier finden Sie Hinweise dazu. Dies hängt natürlich von der pulseaudioProtokollierung von Informationen über neue Clients ab.

Dies ist definitiv machbar, das pavucontrolProgramm ist ein hervorragendes Beispiel dafür. Derzeit sieht es jedoch so aus, als gäbe es keine CLI, die dieselben Aufgaben ausführen könnte. Daher ist wahrscheinlich eine direktere Schnittstelle zur pulseaudioAPI erforderlich .

Aktualisieren

Wenn man sich den Link von @ derobert ansieht , ist das Rollenducking- Modul leicht zu aktivieren, erfordert jedoch die Angabe von media.roleEigenschaften. Ich kann sowieso nicht finden, was das sind! Es ist wahrscheinlich, dass sie nicht für viele Streams definiert sind (viele Programme glauben immer noch, dass sie ALSA verwenden). Wenn es eine Möglichkeit gibt, diese aufzulisten und sie möglicherweise so zu konfigurieren, dass sie zugewiesen werden (möglicherweise basierend auf dem Namen des Prozesses), ist dies der einfachste Weg.

Update 2

media.rolekann über die PULSE_PROPUmgebungsvariable eingestellt werden. Z.B:

PULSE_PROP='media.role=music' play some_music.mp3 &
pactl list clients | grep -C 10 'media.role = "music"'

Dies kann für eine andere Anwendung festgelegt werden, indem .desktopDateien bearbeitet und / oder Wrapper-Skripte erstellt werden. Dies scheint jedoch kein sehr guter Weg zu sein.

Graeme
quelle
3
Es gibt eine dokumentierte CLI zum Ändern von Volumes pro Client ... ZB pactl set-sink-input-volume 1384 100%wobei 1384 die Clientnummer ist. Das Geheimnis ist, dass sie als "Sink-Eingänge" für Wiedergabeclients (und als Quellausgänge für Aufnahmeclients) bezeichnet werden.
Derobert
1
@derobert das funktioniert aber bei mir nicht mit der kundennummer. Wenn ich die Senken-Eingangsnummer von pactl list sink-inputsanstelle der Client-Nummer verwende, funktioniert es. clientscheint eine breitere Gruppe zu sein, sink-inputda sie mehr als nur Anwendungen enthält, die Sound abspielen. Ich kann keine Puls-Audio-Dokumentation finden, in der diese Begriffe richtig definiert sind.
Graeme
1

Die Hinweise in den Kommentaren von @derobert und @ Graeme sind hilfreich, aber das Ausgabeformat ist unpraktisch. Deshalb habe ich einen Parser geschrieben, in den ich ihn umwandeln kann 0 Name 0.0, der einfacher zu analysieren ist. Dabei habe ich auch einen Helfer hinzugefügt, um die Lautstärke einfach zu ändern.

Es ist möglich, dies in eine Schleife einzubetten und zu tun, was Sie wollen. Dies ist in der Nim- Sprache.

import osproc, strutils, pegs, os, parseopt2, sequtils

type Application = object
  id: int
  name: string
  volume: float

var verbose = false

proc tryExec(cmd): auto =
  if verbose: echo("executing $1" % [cmd])
  let output = execCmdEx(cmd)
  if output.exitCode != 0:
    raise newException(EBase, "Failed to execute `$1` with error code $2\nOutput:\n===\n$3\n===" %
                              [cmd, $output.exitCode, output.output])
  return output.output

iterator getPlayingApps(): auto =
  let paOutput = tryExec("pactl list sink-inputs")

  let sinkStrings = paOutput.split("\l\l")

  for str in sinkStrings:
    var num: int
    var volume: float
    var applicationName: string

    var matches = ["", ""]

    if str.find(peg"'Sink Input #'{\d+}", matches) != -1:
      num = parseInt(matches[0])
    else:
      raise newException(EBase, "Could not find sink input number in \n===\n$1" % [str])

    if str.find(peg"'Volume'@'/'\s*{\d+}'%'", matches) != -1:
      volume = parseFloat(matches[0])
    else:
      raise newException(EBase, "Could not find application volume in \n===\n$1" % [str])

    if str.find(peg"'application.name = ""'{[^""]+}'""'", matches) != -1:
      applicationName = matches[0]
    else:
      raise newException(EBase, "Could not find application name in \n===\n$1" % [str])

    yield Application(id: num, name: applicationName, volume: volume)

proc adjustAppVolume(app: Application, percent: float) =
  let nextVol = min((app.volume + (app.volume * (percent - 100) / 100.0)).int, 100)
  discard tryExec("pactl set-sink-input-volume $1 $2%" % [$app.id, $nextVol])

proc adjustName(name: string, percent: float) =
  for app in getPlayingApps():
    if app.name.contains(peg(name)):
      adjustAppVolume(app, percent)

proc printInfo() =
  for app in getPlayingApps():
    echo("$1\t$2\t$3" % [$app.id, app.name, $app.volume])

var params: seq[string] = @[]
for kind, key, val in getopt():
  case kind
  of cmdArgument:
    params.add(key)
  of cmdLongOption, cmdShortOption:
    case key
    of "help", "h":
      echo "usage: parsepa [-h|--help] [-v|--verbose] [<name expression> percent (-a|--adjust)] [-p|--print]"
      quit(QuitSuccess)
    of "verbose", "v":
      verbose = true
    of "adjust", "a":
      adjustName(params[0], parseFloat(params[1]))
      quit(QuitSuccess)
    of "print", "p":
      printInfo()
      quit(QuitSuccess)
    else:
      echo "Invalid Argument"
      quit(QuitFailure)
  else:
    echo "Invalid Argument"
    quit(QuitFailure)

x64-Binärdatei in dieser Liste für Faulenzer: https://gist.github.com/flaviut/9feb9a75bd452e6ddd03

user60561
quelle