mirror of
https://github.com/anotherhadi/settuings.git
synced 2026-10-05 16:18:24 +02:00
@@ -0,0 +1,54 @@
|
||||
// Package audio wraps wpctl (and the pw-play/pw-cat helper tools that ship
|
||||
// alongside it) to read and control PipeWire audio state: output/input
|
||||
// devices, their volume and mute, the default device, and per-application
|
||||
// streams. Every exported function shells out to a CLI tool; there is no
|
||||
// direct PipeWire/WirePlumber library integration.
|
||||
package audio
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
var ErrNotFound = errors.New("wpctl not found in PATH")
|
||||
|
||||
const defaultTimeout = 15 * time.Second
|
||||
|
||||
// CheckAvailable reports whether wpctl is installed and PipeWire is
|
||||
// reachable. Call it before using the rest of the package.
|
||||
func CheckAvailable() error {
|
||||
if _, err := exec.LookPath("wpctl"); err != nil {
|
||||
return ErrNotFound
|
||||
}
|
||||
if _, err := run("status"); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func run(args ...string) (string, error) {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), defaultTimeout)
|
||||
defer cancel()
|
||||
|
||||
cmd := exec.CommandContext(ctx, "wpctl", args...) // #nosec G204 -- args are fixed wpctl subcommands or IDs read back from `wpctl status`, never shell-interpreted
|
||||
var stdout, stderr bytes.Buffer
|
||||
cmd.Stdout = &stdout
|
||||
cmd.Stderr = &stderr
|
||||
|
||||
if err := cmd.Run(); err != nil {
|
||||
if errors.Is(err, exec.ErrNotFound) {
|
||||
return "", ErrNotFound
|
||||
}
|
||||
msg := strings.TrimSpace(stderr.String())
|
||||
if msg == "" {
|
||||
msg = err.Error()
|
||||
}
|
||||
return "", fmt.Errorf("wpctl %s: %s", strings.Join(args, " "), msg)
|
||||
}
|
||||
return stdout.String(), nil
|
||||
}
|
||||
Reference in New Issue
Block a user