mirror of
https://github.com/Luzifer/streamdeck.git
synced 2024-12-20 17:51:21 +00:00
Handle mute and absent devices
Signed-off-by: Knut Ahlers <knut@ahlers.me>
This commit is contained in:
parent
661edb591a
commit
2fd1279eb3
2 changed files with 37 additions and 19 deletions
|
@ -30,8 +30,10 @@ func (d displayElementPulseVolume) Display(ctx context.Context, idx int, attribu
|
||||||
sinkInputOK = sinkInputOK && sinkInputMatch != ""
|
sinkInputOK = sinkInputOK && sinkInputMatch != ""
|
||||||
|
|
||||||
var (
|
var (
|
||||||
err error
|
err error
|
||||||
volume float64
|
mute bool
|
||||||
|
notPresent bool
|
||||||
|
volume float64
|
||||||
)
|
)
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
|
@ -40,21 +42,35 @@ func (d displayElementPulseVolume) Display(ctx context.Context, idx int, attribu
|
||||||
return errors.New("Exactly one of 'sink' and 'sink_input' must be specified")
|
return errors.New("Exactly one of 'sink' and 'sink_input' must be specified")
|
||||||
|
|
||||||
case sinkInputOK:
|
case sinkInputOK:
|
||||||
volume, err = pulseClient.GetSinkInputVolume(sinkInputMatch)
|
volume, mute, err = pulseClient.GetSinkInputVolume(sinkInputMatch)
|
||||||
|
|
||||||
case sinkOK:
|
case sinkOK:
|
||||||
volume, err = pulseClient.GetSinkVolume(sinkMatch)
|
volume, mute, err = pulseClient.GetSinkVolume(sinkMatch)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err == errPulseNoSuchDevice {
|
||||||
|
notPresent = true
|
||||||
|
} else if err != nil {
|
||||||
return errors.Wrap(err, "Unable to get volume")
|
return errors.Wrap(err, "Unable to get volume")
|
||||||
}
|
}
|
||||||
|
|
||||||
img := newTextOnImageRenderer()
|
img := newTextOnImageRenderer()
|
||||||
|
|
||||||
|
var (
|
||||||
|
text = fmt.Sprintf("%.0f%%", volume*100)
|
||||||
|
textColor color.Color = color.RGBA{0xff, 0xff, 0xff, 0xff}
|
||||||
|
)
|
||||||
|
|
||||||
|
if notPresent {
|
||||||
|
text = "--"
|
||||||
|
textColor = color.RGBA{0xff, 0x0, 0x0, 0x0}
|
||||||
|
} else if mute {
|
||||||
|
text = "M"
|
||||||
|
textColor = color.RGBA{0xff, 0x0, 0x0, 0x0}
|
||||||
|
}
|
||||||
|
|
||||||
// Initialize color
|
// Initialize color
|
||||||
var textColor color.Color = color.RGBA{0xff, 0xff, 0xff, 0xff}
|
|
||||||
if rgba, ok := attributes["color"].([]interface{}); ok {
|
if rgba, ok := attributes["color"].([]interface{}); ok {
|
||||||
if len(rgba) != 4 {
|
if len(rgba) != 4 {
|
||||||
return errors.New("RGBA color definition needs 4 hex values")
|
return errors.New("RGBA color definition needs 4 hex values")
|
||||||
|
@ -85,7 +101,7 @@ func (d displayElementPulseVolume) Display(ctx context.Context, idx int, attribu
|
||||||
border = v
|
border = v
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = img.DrawBigText(fmt.Sprintf("%.0f%%", volume*100), fontsize, border, textColor); err != nil {
|
if err = img.DrawBigText(text, fontsize, border, textColor); err != nil {
|
||||||
return errors.Wrap(err, "Unable to draw text")
|
return errors.Wrap(err, "Unable to draw text")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,8 @@ func init() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var errPulseNoSuchDevice = errors.New("No such device")
|
||||||
|
|
||||||
type pulseAudioClient struct {
|
type pulseAudioClient struct {
|
||||||
client *pulse.Client
|
client *pulse.Client
|
||||||
}
|
}
|
||||||
|
@ -36,42 +38,42 @@ func newPulseAudioClient() (*pulseAudioClient, error) {
|
||||||
|
|
||||||
func (p pulseAudioClient) Close() { p.client.Close() }
|
func (p pulseAudioClient) Close() { p.client.Close() }
|
||||||
|
|
||||||
func (p pulseAudioClient) GetSinkInputVolume(match string) (float64, error) {
|
func (p pulseAudioClient) GetSinkInputVolume(match string) (float64, bool, error) {
|
||||||
m, err := regexp.Compile(match)
|
m, err := regexp.Compile(match)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, errors.Wrap(err, "Unable to compile given match RegEx")
|
return 0, false, errors.Wrap(err, "Unable to compile given match RegEx")
|
||||||
}
|
}
|
||||||
|
|
||||||
var resp proto.GetSinkInputInfoListReply
|
var resp proto.GetSinkInputInfoListReply
|
||||||
if err := p.client.RawRequest(&proto.GetSinkInputInfoList{}, &resp); err != nil {
|
if err := p.client.RawRequest(&proto.GetSinkInputInfoList{}, &resp); err != nil {
|
||||||
return 0, errors.Wrap(err, "Unable to list sink inputs")
|
return 0, false, errors.Wrap(err, "Unable to list sink inputs")
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, info := range resp {
|
for _, info := range resp {
|
||||||
if !m.MatchString(info.MediaName) && !m.Match(info.Properties["application.name"]) {
|
if !m.MatchString(info.MediaName) && !m.Match(info.Properties["application.name"]) || info.Corked {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
sinkBase, err := p.getSinkBaseVolumeByIndex(info.SinkIndex)
|
sinkBase, err := p.getSinkBaseVolumeByIndex(info.SinkIndex)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, errors.Wrap(err, "Unable to get sink base volume")
|
return 0, false, errors.Wrap(err, "Unable to get sink base volume")
|
||||||
}
|
}
|
||||||
|
|
||||||
return p.unifyChannelVolumes(info.ChannelVolumes) / sinkBase, nil
|
return p.unifyChannelVolumes(info.ChannelVolumes) / sinkBase, info.Muted, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0, errors.New("No such sink")
|
return 0, false, errPulseNoSuchDevice
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p pulseAudioClient) GetSinkVolume(match string) (float64, error) {
|
func (p pulseAudioClient) GetSinkVolume(match string) (float64, bool, error) {
|
||||||
m, err := regexp.Compile(match)
|
m, err := regexp.Compile(match)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, errors.Wrap(err, "Unable to compile given match RegEx")
|
return 0, false, errors.Wrap(err, "Unable to compile given match RegEx")
|
||||||
}
|
}
|
||||||
|
|
||||||
var resp proto.GetSinkInfoListReply
|
var resp proto.GetSinkInfoListReply
|
||||||
if err := p.client.RawRequest(&proto.GetSinkInfoList{}, &resp); err != nil {
|
if err := p.client.RawRequest(&proto.GetSinkInfoList{}, &resp); err != nil {
|
||||||
return 0, errors.Wrap(err, "Unable to list sinks")
|
return 0, false, errors.Wrap(err, "Unable to list sinks")
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, info := range resp {
|
for _, info := range resp {
|
||||||
|
@ -79,10 +81,10 @@ func (p pulseAudioClient) GetSinkVolume(match string) (float64, error) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
return p.unifyChannelVolumes(info.ChannelVolumes) / float64(info.BaseVolume), nil
|
return p.unifyChannelVolumes(info.ChannelVolumes) / float64(info.BaseVolume), info.Mute, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0, errors.New("No such sink")
|
return 0, false, errPulseNoSuchDevice
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p pulseAudioClient) getSinkBaseVolumeByIndex(idx uint32) (float64, error) {
|
func (p pulseAudioClient) getSinkBaseVolumeByIndex(idx uint32) (float64, error) {
|
||||||
|
|
Loading…
Reference in a new issue