From 554b090890e81c4737e9becc1523e35d6af363fd Mon Sep 17 00:00:00 2001 From: Knut Ahlers Date: Sun, 9 Aug 2020 16:26:22 +0200 Subject: [PATCH] Add support for sources Signed-off-by: Knut Ahlers --- cmd/streamdeck/display_pulsevolume.go | 29 ++++++++++++++++---------- cmd/streamdeck/pulseaudio.go | 30 +++++++++++++++++++++++---- 2 files changed, 44 insertions(+), 15 deletions(-) diff --git a/cmd/streamdeck/display_pulsevolume.go b/cmd/streamdeck/display_pulsevolume.go index a39ac5b..62d6826 100644 --- a/cmd/streamdeck/display_pulsevolume.go +++ b/cmd/streamdeck/display_pulsevolume.go @@ -23,11 +23,15 @@ func (d displayElementPulseVolume) Display(ctx context.Context, idx int, attribu return errors.New("PulseAudio client not initialized") } - sinkMatch, sinkOK := attributes["sink"].(string) - sinkOK = sinkOK && sinkMatch != "" + devType, ok := attributes["device"].(string) + if !ok { + return errors.New("Missing 'device' attribute") + } - sinkInputMatch, sinkInputOK := attributes["sink_input"].(string) - sinkInputOK = sinkInputOK && sinkInputMatch != "" + match, ok := attributes["match"].(string) + if !ok { + return errors.New("Missing 'match' attribute") + } var ( err error @@ -36,16 +40,19 @@ func (d displayElementPulseVolume) Display(ctx context.Context, idx int, attribu volume float64 ) - switch { + switch devType { - case (sinkInputOK && sinkOK) || (!sinkInputOK && !sinkOK): - return errors.New("Exactly one of 'sink' and 'sink_input' must be specified") + case "input": + volume, mute, err = pulseClient.GetSinkInputVolume(match) - case sinkInputOK: - volume, mute, err = pulseClient.GetSinkInputVolume(sinkInputMatch) + case "sink": + volume, mute, err = pulseClient.GetSinkVolume(match) - case sinkOK: - volume, mute, err = pulseClient.GetSinkVolume(sinkMatch) + case "source": + volume, mute, err = pulseClient.GetSourceVolume(match) + + default: + return errors.Errorf("Unsupported device type: %q", devType) } diff --git a/cmd/streamdeck/pulseaudio.go b/cmd/streamdeck/pulseaudio.go index 5bb7653..50a2460 100644 --- a/cmd/streamdeck/pulseaudio.go +++ b/cmd/streamdeck/pulseaudio.go @@ -54,7 +54,7 @@ func (p pulseAudioClient) GetSinkInputVolume(match string) (float64, bool, error continue } - sinkBase, err := p.getSinkBaseVolumeByIndex(info.SinkIndex) + sinkBase, err := p.getSinkReferenceVolumeByIndex(info.SinkIndex) if err != nil { return 0, false, errors.Wrap(err, "Unable to get sink base volume") } @@ -81,19 +81,41 @@ func (p pulseAudioClient) GetSinkVolume(match string) (float64, bool, error) { continue } - return p.unifyChannelVolumes(info.ChannelVolumes) / float64(info.BaseVolume), info.Mute, nil + return p.unifyChannelVolumes(info.ChannelVolumes) / float64(info.NumVolumeSteps), info.Mute, nil } return 0, false, errPulseNoSuchDevice } -func (p pulseAudioClient) getSinkBaseVolumeByIndex(idx uint32) (float64, error) { +func (p pulseAudioClient) GetSourceVolume(match string) (float64, bool, error) { + m, err := regexp.Compile(match) + if err != nil { + return 0, false, errors.Wrap(err, "Unable to compile given match RegEx") + } + + var resp proto.GetSourceInfoListReply + if err := p.client.RawRequest(&proto.GetSourceInfoList{}, &resp); err != nil { + return 0, false, errors.Wrap(err, "Unable to list sources") + } + + for _, info := range resp { + if !m.MatchString(info.SourceName) && !m.MatchString(info.Device) { + continue + } + + return p.unifyChannelVolumes(info.ChannelVolumes) / float64(info.NumVolumeSteps), info.Mute, nil + } + + return 0, false, errPulseNoSuchDevice +} + +func (p pulseAudioClient) getSinkReferenceVolumeByIndex(idx uint32) (float64, error) { var resp proto.GetSinkInfoReply if err := p.client.RawRequest(&proto.GetSinkInfo{SinkIndex: idx}, &resp); err != nil { return 0, errors.Wrap(err, "Unable to get sink") } - return float64(resp.BaseVolume), nil + return float64(resp.NumVolumeSteps), nil } func (p pulseAudioClient) unifyChannelVolumes(v proto.ChannelVolumes) float64 {