Warning, /plasma/plasma-mobile/components/mobileshell/qml/dataproviders/AudioInfo.qml is written in an unsupported language. File is not indexed.

0001 // SPDX-FileCopyrightText: 2023 Devin Lin <devin@kde.org>
0002 // SPDX-License-Identifier: GPL-2.0-or-later
0003 
0004 pragma Singleton
0005 
0006 import QtQuick
0007 
0008 import org.kde.plasma.private.volume
0009 
0010 QtObject {
0011     id: root
0012 
0013     property var config: GlobalConfig {}
0014 
0015     property SinkModel paSinkModel: SinkModel {}
0016 
0017     // whether the audio icon should be visible in the status bar
0018     readonly property bool isVisible: paSinkModel.preferredSink
0019 
0020     // the icon that should be displayed in the status bar
0021     readonly property string icon: paSinkModel.preferredSink && !isDummyOutput(paSinkModel.preferredSink)
0022                                     ? iconName(paSinkModel.preferredSink.volume, paSinkModel.preferredSink.muted)
0023                                     : iconName(0, true)
0024 
0025     // the name of the audio device when it isn't valid
0026     readonly property string dummyOutputName: "auto_null"
0027 
0028     // the maximum volume amount (percentage)
0029     readonly property int maxVolumePercent: config.raiseMaximumVolume ? 150 : 100
0030 
0031     // the maximum volume amount
0032     readonly property int maxVolumeValue: maxVolumePercent * PulseAudio.NormalVolume / 100
0033 
0034     // step that increments when adjusting the volume
0035     readonly property int volumeStep: Math.round(5 * PulseAudio.NormalVolume / 100.0)
0036 
0037     // The current audio volume (updated by connecting to sinks)
0038     property int volumeValue
0039 
0040     function isDummyOutput(output) {
0041         return output && output.name === dummyOutputName;
0042     }
0043 
0044     function boundVolume(volume) {
0045         return Math.max(PulseAudio.MinimalVolume, Math.min(volume, maxVolumeValue));
0046     }
0047 
0048     function volumePercent(volume, max){
0049         if (!max) {
0050             max = PulseAudio.NormalVolume;
0051         }
0052         return Math.round(volume / max * maxVolumePercent);
0053     }
0054 
0055     function increaseVolume() {
0056         if (!paSinkModel.preferredSink || isDummyOutput(paSinkModel.preferredSink)) {
0057             return;
0058         }
0059 
0060         var volume = boundVolume(paSinkModel.preferredSink.volume + volumeStep);
0061         var percent = volumePercent(volume, maxVolumeValue);
0062         paSinkModel.preferredSink.muted = percent == 0;
0063         paSinkModel.preferredSink.volume = volume;
0064     }
0065 
0066     function decreaseVolume() {
0067         if (!paSinkModel.preferredSink || isDummyOutput(paSinkModel.preferredSink)) {
0068             return;
0069         }
0070 
0071         var volume = boundVolume(paSinkModel.preferredSink.volume - volumeStep);
0072         var percent = volumePercent(volume, maxVolumeValue);
0073         paSinkModel.preferredSink.muted = percent == 0;
0074         paSinkModel.preferredSink.volume = volume;
0075     }
0076 
0077     function muteVolume() {
0078         if (!paSinkModel.preferredSink || isDummyOutput(paSinkModel.preferredSink)) {
0079             return;
0080         }
0081 
0082         paSinkModel.preferredSink.muted = !paSinkModel.preferredSink.muted;
0083     }
0084 
0085     function iconName(volume, muted, prefix) {
0086         if (!prefix) {
0087             prefix = "audio-volume";
0088         }
0089         var icon = null;
0090         var percent = volume / maxVolumeValue;
0091         if (percent <= 0.0 || muted) {
0092             icon = prefix + "-muted";
0093         } else if (percent <= 0.25) {
0094             icon = prefix + "-low";
0095         } else if (percent <= 0.75) {
0096             icon = prefix + "-medium";
0097         } else {
0098             icon = prefix + "-high";
0099         }
0100         return icon;
0101     }
0102 
0103     // emitted when the volume changed, but not due to sink switching
0104     signal volumeChanged()
0105 
0106     property var updateVolume: Connections {
0107         target: root.paSinkModel ? (root.paSinkModel.preferredSink ? root.paSinkModel.preferredSink : null) : null
0108         enabled: target !== null
0109 
0110         function onVolumeChanged() {
0111             root.volumeValue = root.volumePercent(root.paSinkModel.preferredSink.volume, root.maxVolumeValue);
0112             root.volumeChanged();
0113         }
0114 
0115         function onMutedChanged() {
0116             root.volumeValue = root.paSinkModel.preferredSink.muted ? 0 : root.volumePercent(root.paSinkModel.preferredSink.volume, root.maxVolumeValue);
0117             root.volumeChanged();
0118         }
0119     }
0120 
0121     property var updateVolumeOnSinkChange: Connections {
0122         target: root.paSinkModel ? root.paSinkModel : null
0123         enabled: target !== null
0124 
0125         function onPreferredSinkChanged() {
0126             if (root.paSinkModel.preferredSink) {
0127                 root.volumeValue = root.volumePercent(root.paSinkModel.preferredSink.volume, root.maxVolumeValue);
0128             }
0129         }
0130     }
0131 }