mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2025-12-05 21:15:38 -05:00
fix bluetooth codec modal
This commit is contained in:
@@ -10,6 +10,7 @@ import qs.Common
|
||||
import qs.Modules.ControlCenter
|
||||
import qs.Modules.ControlCenter.Widgets
|
||||
import qs.Modules.ControlCenter.Details
|
||||
import qs.Modules.ControlCenter.Details 1.0 as Details
|
||||
import qs.Services
|
||||
import qs.Widgets
|
||||
|
||||
@@ -74,43 +75,48 @@ DankPopout {
|
||||
}
|
||||
|
||||
content: Component {
|
||||
Rectangle {
|
||||
id: controlContent
|
||||
Item {
|
||||
implicitHeight: controlContent.implicitHeight
|
||||
property alias bluetoothCodecSelector: bluetoothCodecSelector
|
||||
|
||||
Rectangle {
|
||||
id: controlContent
|
||||
|
||||
implicitHeight: mainColumn.implicitHeight + Theme.spacingM
|
||||
anchors.fill: parent
|
||||
implicitHeight: mainColumn.implicitHeight + Theme.spacingM
|
||||
|
||||
color: Theme.popupBackground()
|
||||
radius: Theme.cornerRadius
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g,
|
||||
Theme.outline.b, 0.08)
|
||||
border.width: 1
|
||||
antialiasing: true
|
||||
smooth: true
|
||||
focus: true
|
||||
color: Theme.popupBackground()
|
||||
radius: Theme.cornerRadius
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g,
|
||||
Theme.outline.b, 0.08)
|
||||
border.width: 1
|
||||
antialiasing: true
|
||||
smooth: true
|
||||
focus: true
|
||||
|
||||
Component.onCompleted: {
|
||||
if (root.shouldBeVisible)
|
||||
forceActiveFocus()
|
||||
}
|
||||
|
||||
Keys.onPressed: function (event) {
|
||||
if (event.key === Qt.Key_Escape) {
|
||||
root.close()
|
||||
event.accepted = true
|
||||
} else {
|
||||
event.accepted = false
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
function onShouldBeVisibleChanged() {
|
||||
Component.onCompleted: {
|
||||
if (root.shouldBeVisible)
|
||||
Qt.callLater(function () {
|
||||
controlContent.forceActiveFocus()
|
||||
})
|
||||
forceActiveFocus()
|
||||
}
|
||||
|
||||
Keys.onPressed: function (event) {
|
||||
if (event.key === Qt.Key_Escape) {
|
||||
root.close()
|
||||
event.accepted = true
|
||||
} else {
|
||||
event.accepted = false
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
function onShouldBeVisibleChanged() {
|
||||
if (root.shouldBeVisible)
|
||||
Qt.callLater(function () {
|
||||
controlContent.forceActiveFocus()
|
||||
})
|
||||
}
|
||||
target: root
|
||||
}
|
||||
target: root
|
||||
}
|
||||
|
||||
Column {
|
||||
id: mainColumn
|
||||
@@ -808,7 +814,13 @@ DankPopout {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Details.BluetoothCodecSelector {
|
||||
id: bluetoothCodecSelector
|
||||
anchors.fill: parent
|
||||
z: 10000
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -819,7 +831,17 @@ DankPopout {
|
||||
|
||||
Component {
|
||||
id: bluetoothDetailComponent
|
||||
BluetoothDetail {}
|
||||
BluetoothDetail {
|
||||
id: bluetoothDetail
|
||||
onShowCodecSelector: function(device) {
|
||||
if (contentLoader.item && contentLoader.item.bluetoothCodecSelector) {
|
||||
contentLoader.item.bluetoothCodecSelector.show(device)
|
||||
contentLoader.item.bluetoothCodecSelector.codecSelected.connect(function(deviceAddress, codecName) {
|
||||
bluetoothDetail.updateDeviceCodecDisplay(deviceAddress, codecName)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
|
||||
@@ -6,7 +6,7 @@ import qs.Common
|
||||
import qs.Services
|
||||
import qs.Widgets
|
||||
|
||||
Rectangle {
|
||||
Item {
|
||||
id: root
|
||||
|
||||
property var device: null
|
||||
@@ -15,7 +15,8 @@ Rectangle {
|
||||
property var availableCodecs: []
|
||||
property string currentCodec: ""
|
||||
property bool isLoading: false
|
||||
property bool parsingTargetCard: false
|
||||
|
||||
signal codecSelected(string deviceAddress, string codecName)
|
||||
|
||||
function show(bluetoothDevice) {
|
||||
device = bluetoothDevice;
|
||||
@@ -39,75 +40,68 @@ Rectangle {
|
||||
|
||||
function queryCodecs() {
|
||||
if (!device)
|
||||
return ;
|
||||
return;
|
||||
|
||||
codecQueryProcess.cardName = BluetoothService.getCardName(device);
|
||||
codecQueryProcess.running = true;
|
||||
BluetoothService.getAvailableCodecs(device, function(codecs, current) {
|
||||
availableCodecs = codecs;
|
||||
currentCodec = current;
|
||||
isLoading = false;
|
||||
});
|
||||
}
|
||||
|
||||
function selectCodec(profileName) {
|
||||
if (!device || isLoading)
|
||||
return ;
|
||||
return;
|
||||
|
||||
let selectedCodec = availableCodecs.find(c => c.profile === profileName);
|
||||
if (selectedCodec && device) {
|
||||
BluetoothService.updateDeviceCodec(device.address, selectedCodec.name);
|
||||
codecSelected(device.address, selectedCodec.name);
|
||||
}
|
||||
|
||||
isLoading = true;
|
||||
codecSwitchProcess.cardName = BluetoothService.getCardName(device);
|
||||
codecSwitchProcess.profile = profileName;
|
||||
codecSwitchProcess.running = true;
|
||||
}
|
||||
|
||||
function parseCodecLine(line) {
|
||||
if (!codecQueryProcess.cardName)
|
||||
return ;
|
||||
|
||||
if (line.includes(`Name: ${codecQueryProcess.cardName}`)) {
|
||||
parsingTargetCard = true;
|
||||
return ;
|
||||
}
|
||||
if (parsingTargetCard && line.startsWith("Name: ") && !line.includes(codecQueryProcess.cardName)) {
|
||||
parsingTargetCard = false;
|
||||
return ;
|
||||
}
|
||||
if (parsingTargetCard) {
|
||||
if (line.startsWith("Active Profile:")) {
|
||||
let profile = line.split(": ")[1] || "";
|
||||
let activeCodec = availableCodecs.find((c) => {
|
||||
return c.profile === profile;
|
||||
});
|
||||
if (activeCodec)
|
||||
currentCodec = activeCodec.name;
|
||||
|
||||
return ;
|
||||
BluetoothService.switchCodec(device, profileName, function(success, message) {
|
||||
isLoading = false;
|
||||
if (success) {
|
||||
ToastService.showToast(message, ToastService.levelInfo);
|
||||
Qt.callLater(root.hide);
|
||||
} else {
|
||||
ToastService.showToast(message, ToastService.levelError);
|
||||
}
|
||||
if (line.includes("codec") && line.includes("available: yes")) {
|
||||
let parts = line.split(": ");
|
||||
if (parts.length >= 2) {
|
||||
let profile = parts[0].trim();
|
||||
let description = parts[1];
|
||||
let codecMatch = description.match(/codec ([^\)\s]+)/i);
|
||||
let codecName = codecMatch ? codecMatch[1].toUpperCase() : "UNKNOWN";
|
||||
let codecInfo = BluetoothService.getCodecInfo(codecName);
|
||||
if (codecInfo && !availableCodecs.some((c) => {
|
||||
return c.profile === profile;
|
||||
})) {
|
||||
let newCodecs = availableCodecs.slice();
|
||||
newCodecs.push({
|
||||
"name": codecInfo.name,
|
||||
"profile": profile,
|
||||
"description": codecInfo.description,
|
||||
"qualityColor": codecInfo.qualityColor
|
||||
});
|
||||
availableCodecs = newCodecs;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
visible: false
|
||||
anchors.fill: parent
|
||||
color: "transparent"
|
||||
z: 2000
|
||||
opacity: modalVisible ? 1 : 0
|
||||
|
||||
MouseArea {
|
||||
id: modalBlocker
|
||||
anchors.fill: parent
|
||||
visible: modalVisible
|
||||
enabled: modalVisible
|
||||
hoverEnabled: true
|
||||
preventStealing: true
|
||||
propagateComposedEvents: false
|
||||
|
||||
onClicked: root.hide()
|
||||
onWheel: (wheel) => { wheel.accepted = true }
|
||||
onPositionChanged: (mouse) => { mouse.accepted = true }
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: modalBackground
|
||||
anchors.fill: parent
|
||||
color: Qt.rgba(0, 0, 0, 0.5)
|
||||
opacity: modalVisible ? 1 : 0
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
duration: Theme.mediumDuration
|
||||
easing.type: Theme.emphasizedEasing
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FocusScope {
|
||||
id: focusScope
|
||||
@@ -116,17 +110,14 @@ Rectangle {
|
||||
focus: root.visible
|
||||
enabled: root.visible
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: root.hide()
|
||||
onWheel: (wheel) => {
|
||||
return wheel.accepted = true;
|
||||
}
|
||||
Keys.onEscapePressed: {
|
||||
root.hide()
|
||||
event.accepted = true
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: modalContent
|
||||
anchors.centerIn: parent
|
||||
width: 320
|
||||
height: Math.min(contentColumn.implicitHeight + Theme.spacingL * 2, 400)
|
||||
@@ -139,8 +130,12 @@ Rectangle {
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: {
|
||||
}
|
||||
hoverEnabled: true
|
||||
preventStealing: true
|
||||
propagateComposedEvents: false
|
||||
onClicked: (mouse) => { mouse.accepted = true }
|
||||
onWheel: (wheel) => { wheel.accepted = true }
|
||||
onPositionChanged: (mouse) => { mouse.accepted = true }
|
||||
}
|
||||
|
||||
Column {
|
||||
@@ -309,55 +304,4 @@ Rectangle {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Process {
|
||||
id: codecQueryProcess
|
||||
|
||||
property string cardName: ""
|
||||
|
||||
command: ["pactl", "list", "cards"]
|
||||
onExited: function(exitCode, exitStatus) {
|
||||
isLoading = false;
|
||||
if (exitCode !== 0)
|
||||
console.warn("Failed to query codecs:", exitCode);
|
||||
|
||||
}
|
||||
|
||||
stdout: SplitParser {
|
||||
splitMarker: "\n"
|
||||
onRead: (data) => {
|
||||
return parseCodecLine(data.trim());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Process {
|
||||
id: codecSwitchProcess
|
||||
|
||||
property string cardName: ""
|
||||
property string profile: ""
|
||||
|
||||
command: ["pactl", "set-card-profile", cardName, profile]
|
||||
onExited: function(exitCode, exitStatus) {
|
||||
isLoading = false;
|
||||
if (exitCode === 0) {
|
||||
queryCodecs();
|
||||
ToastService.showToast("Codec switched successfully", ToastService.levelInfo);
|
||||
Qt.callLater(root.hide);
|
||||
} else {
|
||||
ToastService.showToast("Failed to switch codec", ToastService.levelError);
|
||||
console.warn("Failed to switch codec:", exitCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
duration: Theme.mediumDuration
|
||||
easing.type: Theme.emphasizedEasing
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -13,7 +13,19 @@ Rectangle {
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08)
|
||||
border.width: 1
|
||||
|
||||
property var bluetoothCodecModalRef: bluetoothCodecModal
|
||||
property var bluetoothCodecModalRef: null
|
||||
|
||||
signal showCodecSelector(var device)
|
||||
|
||||
function updateDeviceCodecDisplay(deviceAddress, codecName) {
|
||||
for (let i = 0; i < pairedRepeater.count; i++) {
|
||||
let item = pairedRepeater.itemAt(i)
|
||||
if (item && item.modelData && item.modelData.address === deviceAddress) {
|
||||
item.currentCodec = codecName
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Row {
|
||||
id: headerRow
|
||||
@@ -131,9 +143,17 @@ Rectangle {
|
||||
required property var modelData
|
||||
required property int index
|
||||
|
||||
property string currentCodec: BluetoothService.deviceCodecs[modelData.address] || ""
|
||||
|
||||
width: parent.width
|
||||
height: 50
|
||||
radius: Theme.cornerRadius
|
||||
|
||||
Component.onCompleted: {
|
||||
if (modelData.connected && BluetoothService.isAudioDevice(modelData)) {
|
||||
BluetoothService.refreshDeviceCodec(modelData)
|
||||
}
|
||||
}
|
||||
color: {
|
||||
if (modelData.state === BluetoothDeviceState.Connecting)
|
||||
return Qt.rgba(Theme.warning.r, Theme.warning.g, Theme.warning.b, 0.12)
|
||||
@@ -189,8 +209,13 @@ Rectangle {
|
||||
text: {
|
||||
if (modelData.state === BluetoothDeviceState.Connecting)
|
||||
return "Connecting..."
|
||||
if (modelData.connected)
|
||||
return "Connected"
|
||||
if (modelData.connected) {
|
||||
let status = "Connected"
|
||||
if (currentCodec) {
|
||||
status += " • " + currentCodec
|
||||
}
|
||||
return status
|
||||
}
|
||||
return "Paired"
|
||||
}
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
@@ -484,8 +509,8 @@ Rectangle {
|
||||
}
|
||||
|
||||
onTriggered: {
|
||||
if (bluetoothCodecModalRef && bluetoothContextMenu.currentDevice) {
|
||||
bluetoothCodecModalRef.show(bluetoothContextMenu.currentDevice)
|
||||
if (bluetoothContextMenu.currentDevice) {
|
||||
showCodecSelector(bluetoothContextMenu.currentDevice)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -515,9 +540,4 @@ Rectangle {
|
||||
}
|
||||
}
|
||||
|
||||
BluetoothCodecSelector {
|
||||
id: bluetoothCodecModal
|
||||
anchors.fill: parent
|
||||
z: 3000
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@ pragma ComponentBehavior: Bound
|
||||
|
||||
import QtQuick
|
||||
import Quickshell
|
||||
import Quickshell.Io
|
||||
import Quickshell.Bluetooth
|
||||
|
||||
Singleton {
|
||||
@@ -221,4 +222,255 @@ Singleton {
|
||||
qualityColor: "#9E9E9E"
|
||||
}
|
||||
}
|
||||
|
||||
property var deviceCodecs: ({})
|
||||
|
||||
function updateDeviceCodec(deviceAddress, codec) {
|
||||
deviceCodecs[deviceAddress] = codec
|
||||
deviceCodecsChanged()
|
||||
}
|
||||
|
||||
function refreshDeviceCodec(device) {
|
||||
if (!device || !device.connected || !isAudioDevice(device)) {
|
||||
return
|
||||
}
|
||||
|
||||
let cardName = getCardName(device)
|
||||
codecQueryProcess.cardName = cardName
|
||||
codecQueryProcess.deviceAddress = device.address
|
||||
codecQueryProcess.availableCodecs = []
|
||||
codecQueryProcess.parsingTargetCard = false
|
||||
codecQueryProcess.detectedCodec = ""
|
||||
codecQueryProcess.running = true
|
||||
}
|
||||
|
||||
function getCurrentCodec(device, callback) {
|
||||
if (!device || !device.connected || !isAudioDevice(device)) {
|
||||
callback("")
|
||||
return
|
||||
}
|
||||
|
||||
let cardName = getCardName(device)
|
||||
codecQueryProcess.cardName = cardName
|
||||
codecQueryProcess.callback = callback
|
||||
codecQueryProcess.availableCodecs = []
|
||||
codecQueryProcess.parsingTargetCard = false
|
||||
codecQueryProcess.detectedCodec = ""
|
||||
codecQueryProcess.running = true
|
||||
}
|
||||
|
||||
function getAvailableCodecs(device, callback) {
|
||||
if (!device || !device.connected || !isAudioDevice(device)) {
|
||||
callback([], "")
|
||||
return
|
||||
}
|
||||
|
||||
let cardName = getCardName(device)
|
||||
codecFullQueryProcess.cardName = cardName
|
||||
codecFullQueryProcess.callback = callback
|
||||
codecFullQueryProcess.availableCodecs = []
|
||||
codecFullQueryProcess.parsingTargetCard = false
|
||||
codecFullQueryProcess.detectedCodec = ""
|
||||
codecFullQueryProcess.running = true
|
||||
}
|
||||
|
||||
function switchCodec(device, profileName, callback) {
|
||||
if (!device || !isAudioDevice(device)) {
|
||||
callback(false, "Invalid device")
|
||||
return
|
||||
}
|
||||
|
||||
let cardName = getCardName(device)
|
||||
codecSwitchProcess.cardName = cardName
|
||||
codecSwitchProcess.profile = profileName
|
||||
codecSwitchProcess.callback = callback
|
||||
codecSwitchProcess.running = true
|
||||
}
|
||||
|
||||
Process {
|
||||
id: codecQueryProcess
|
||||
|
||||
property string cardName: ""
|
||||
property string deviceAddress: ""
|
||||
property var callback: null
|
||||
property bool parsingTargetCard: false
|
||||
property string detectedCodec: ""
|
||||
property var availableCodecs: []
|
||||
|
||||
command: ["pactl", "list", "cards"]
|
||||
|
||||
onExited: function(exitCode, exitStatus) {
|
||||
if (exitCode === 0 && detectedCodec) {
|
||||
if (deviceAddress) {
|
||||
root.updateDeviceCodec(deviceAddress, detectedCodec)
|
||||
}
|
||||
if (callback) {
|
||||
callback(detectedCodec)
|
||||
}
|
||||
} else if (callback) {
|
||||
callback("")
|
||||
}
|
||||
|
||||
parsingTargetCard = false
|
||||
detectedCodec = ""
|
||||
availableCodecs = []
|
||||
deviceAddress = ""
|
||||
callback = null
|
||||
}
|
||||
|
||||
stdout: SplitParser {
|
||||
splitMarker: "\n"
|
||||
onRead: (data) => {
|
||||
let line = data.trim()
|
||||
|
||||
if (line.includes(`Name: ${codecQueryProcess.cardName}`)) {
|
||||
codecQueryProcess.parsingTargetCard = true
|
||||
return
|
||||
}
|
||||
|
||||
if (codecQueryProcess.parsingTargetCard && line.startsWith("Name: ") && !line.includes(codecQueryProcess.cardName)) {
|
||||
codecQueryProcess.parsingTargetCard = false
|
||||
return
|
||||
}
|
||||
|
||||
if (codecQueryProcess.parsingTargetCard) {
|
||||
if (line.startsWith("Active Profile:")) {
|
||||
let profile = line.split(": ")[1] || ""
|
||||
let activeCodec = codecQueryProcess.availableCodecs.find((c) => {
|
||||
return c.profile === profile
|
||||
})
|
||||
if (activeCodec) {
|
||||
codecQueryProcess.detectedCodec = activeCodec.name
|
||||
}
|
||||
return
|
||||
}
|
||||
if (line.includes("codec") && line.includes("available: yes")) {
|
||||
let parts = line.split(": ")
|
||||
if (parts.length >= 2) {
|
||||
let profile = parts[0].trim()
|
||||
let description = parts[1]
|
||||
let codecMatch = description.match(/codec ([^\)\s]+)/i)
|
||||
let codecName = codecMatch ? codecMatch[1].toUpperCase() : "UNKNOWN"
|
||||
let codecInfo = root.getCodecInfo(codecName)
|
||||
if (codecInfo && !codecQueryProcess.availableCodecs.some((c) => {
|
||||
return c.profile === profile
|
||||
})) {
|
||||
let newCodecs = codecQueryProcess.availableCodecs.slice()
|
||||
newCodecs.push({
|
||||
"name": codecInfo.name,
|
||||
"profile": profile,
|
||||
"description": codecInfo.description,
|
||||
"qualityColor": codecInfo.qualityColor
|
||||
})
|
||||
codecQueryProcess.availableCodecs = newCodecs
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Process {
|
||||
id: codecFullQueryProcess
|
||||
|
||||
property string cardName: ""
|
||||
property var callback: null
|
||||
property bool parsingTargetCard: false
|
||||
property string detectedCodec: ""
|
||||
property var availableCodecs: []
|
||||
|
||||
command: ["pactl", "list", "cards"]
|
||||
|
||||
onExited: function(exitCode, exitStatus) {
|
||||
if (callback) {
|
||||
callback(exitCode === 0 ? availableCodecs : [], exitCode === 0 ? detectedCodec : "")
|
||||
}
|
||||
parsingTargetCard = false
|
||||
detectedCodec = ""
|
||||
availableCodecs = []
|
||||
callback = null
|
||||
}
|
||||
|
||||
stdout: SplitParser {
|
||||
splitMarker: "\n"
|
||||
onRead: (data) => {
|
||||
let line = data.trim()
|
||||
|
||||
if (line.includes(`Name: ${codecFullQueryProcess.cardName}`)) {
|
||||
codecFullQueryProcess.parsingTargetCard = true
|
||||
return
|
||||
}
|
||||
|
||||
if (codecFullQueryProcess.parsingTargetCard && line.startsWith("Name: ") && !line.includes(codecFullQueryProcess.cardName)) {
|
||||
codecFullQueryProcess.parsingTargetCard = false
|
||||
return
|
||||
}
|
||||
|
||||
if (codecFullQueryProcess.parsingTargetCard) {
|
||||
if (line.startsWith("Active Profile:")) {
|
||||
let profile = line.split(": ")[1] || ""
|
||||
let activeCodec = codecFullQueryProcess.availableCodecs.find((c) => {
|
||||
return c.profile === profile
|
||||
})
|
||||
if (activeCodec) {
|
||||
codecFullQueryProcess.detectedCodec = activeCodec.name
|
||||
}
|
||||
return
|
||||
}
|
||||
if (line.includes("codec") && line.includes("available: yes")) {
|
||||
let parts = line.split(": ")
|
||||
if (parts.length >= 2) {
|
||||
let profile = parts[0].trim()
|
||||
let description = parts[1]
|
||||
let codecMatch = description.match(/codec ([^\)\s]+)/i)
|
||||
let codecName = codecMatch ? codecMatch[1].toUpperCase() : "UNKNOWN"
|
||||
let codecInfo = root.getCodecInfo(codecName)
|
||||
if (codecInfo && !codecFullQueryProcess.availableCodecs.some((c) => {
|
||||
return c.profile === profile
|
||||
})) {
|
||||
let newCodecs = codecFullQueryProcess.availableCodecs.slice()
|
||||
newCodecs.push({
|
||||
"name": codecInfo.name,
|
||||
"profile": profile,
|
||||
"description": codecInfo.description,
|
||||
"qualityColor": codecInfo.qualityColor
|
||||
})
|
||||
codecFullQueryProcess.availableCodecs = newCodecs
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Process {
|
||||
id: codecSwitchProcess
|
||||
|
||||
property string cardName: ""
|
||||
property string profile: ""
|
||||
property var callback: null
|
||||
|
||||
command: ["pactl", "set-card-profile", cardName, profile]
|
||||
|
||||
onExited: function(exitCode, exitStatus) {
|
||||
if (callback) {
|
||||
callback(exitCode === 0, exitCode === 0 ? "Codec switched successfully" : "Failed to switch codec")
|
||||
}
|
||||
|
||||
// If successful, refresh the codec for this device
|
||||
if (exitCode === 0) {
|
||||
if (root.adapter && root.adapter.devices) {
|
||||
root.adapter.devices.values.forEach(device => {
|
||||
if (device && root.getCardName(device) === cardName) {
|
||||
Qt.callLater(() => root.refreshDeviceCodec(device))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
callback = null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,6 @@ Singleton {
|
||||
property list<int> values: Array(6)
|
||||
property int refCount: 0
|
||||
property bool cavaAvailable: false
|
||||
property string monitorSource: AudioService.sink && AudioService.sink.name ? AudioService.sink.name + ".monitor" : ""
|
||||
|
||||
Process {
|
||||
id: cavaCheck
|
||||
@@ -31,9 +30,7 @@ Singleton {
|
||||
id: cavaProcess
|
||||
|
||||
running: root.cavaAvailable && root.refCount > 0
|
||||
command: ["sh", "-c", root.monitorSource
|
||||
? `printf '[general]\\nmode=normal\\nframerate=25\\nautosens=0\\nsensitivity=30\\nbars=6\\nlower_cutoff_freq=50\\nhigher_cutoff_freq=12000\\n[input]\\nmethod=pulse\\nsource=${root.monitorSource}\\n[output]\\nmethod=raw\\nraw_target=/dev/stdout\\ndata_format=ascii\\nchannels=mono\\nmono_option=average\\n[smoothing]\\nnoise_reduction=35\\nintegral=90\\ngravity=95\\nignore=2\\nmonstercat=1.5' | cava -p /dev/stdin`
|
||||
: `printf '[general]\\nmode=normal\\nframerate=25\\nautosens=0\\nsensitivity=30\\nbars=6\\nlower_cutoff_freq=50\\nhigher_cutoff_freq=12000\\n[output]\\nmethod=raw\\nraw_target=/dev/stdout\\ndata_format=ascii\\nchannels=mono\\nmono_option=average\\n[smoothing]\\nnoise_reduction=35\\nintegral=90\\ngravity=95\\nignore=2\\nmonstercat=1.5' | cava -p /dev/stdin`]
|
||||
command: ["sh", "-c", `printf '[general]\\nmode=normal\\nframerate=25\\nautosens=0\\nsensitivity=30\\nbars=6\\nlower_cutoff_freq=50\\nhigher_cutoff_freq=12000\\n[output]\\nmethod=raw\\nraw_target=/dev/stdout\\ndata_format=ascii\\nchannels=mono\\nmono_option=average\\n[smoothing]\\nnoise_reduction=35\\nintegral=90\\ngravity=95\\nignore=2\\nmonstercat=1.5' | cava -p /dev/stdin`]
|
||||
|
||||
onRunningChanged: {
|
||||
if (!running) {
|
||||
|
||||
Reference in New Issue
Block a user