ukui-volume-control/ 0000775 0001750 0001750 00000000000 15171074757 013456 5 ustar feng feng ukui-volume-control/ukui-shortcut-audio/ 0000775 0001750 0001750 00000000000 15171074712 017372 5 ustar feng feng ukui-volume-control/ukui-shortcut-audio/config/ 0000775 0001750 0001750 00000000000 15171074677 020651 5 ustar feng feng ukui-volume-control/ukui-shortcut-audio/config/qmldir 0000664 0001750 0001750 00000000072 15171074677 022063 0 ustar feng feng module org.ukui.shortcut.audio
plugin ukui-shortcut-audio
ukui-volume-control/ukui-shortcut-audio/res/ 0000775 0001750 0001750 00000000000 15171074677 020175 5 ustar feng feng ukui-volume-control/ukui-shortcut-audio/res/res.qrc 0000664 0001750 0001750 00000000051 15171074677 021471 0 ustar feng feng
ukui-volume-control/ukui-shortcut-audio/CMakeLists.txt 0000664 0001750 0001750 00000006441 15171074712 022137 0 ustar feng feng cmake_minimum_required(VERSION 3.14)
#定义项目名称和版本号
project(ukui-shortcut-audio)
set(VERSION_MAJOR 1)
set(VERSION_MINOR 0)
set(VERSION_MICRO 0)
set(UKUI_SHORTCUT_AUDIO_VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_MICRO})
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTORCC ON)
#查找Qt库
find_package(QT NAMES Qt6 Qt5 COMPONENTS Core Gui Widgets Quick DBus LinguistTools REQUIRED)
find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Core Gui Widgets Quick DBus LinguistTools REQUIRED)
include_directories(src/common/)
include_directories(src/control/)
include_directories(src/extra/)
include_directories(src/model/)
include_directories(src/utils/)
include_directories(config/)
include_directories(res/)
include_directories(translations/)
include_directories(qml/)
#设置数据目录和翻译目录
set(UKUI_SHORTCUT_AUDIO_DATA_DIR "/usr/share/ukui/widgets/org.ukui.shortcut.audio")
set(UKUI_SHORTCUT_AUDIO_TRANSLATION_DIR "${UKUI_SHORTCUT_AUDIO_DATA_DIR}/translations")
set(SOURCE_FILES
src/ukui-audio-main.cpp
src/ukui-audio-main.h
src/common/common.cpp
src/common/common.h
src/control/ukui-audio-control.cpp
src/control/ukui-audio-control.h
src/control/ukui-audio-sink-control.cpp
src/control/ukui-audio-sink-control.h
src/control/ukui-audio-source-control.cpp
src/control/ukui-audio-source-control.h
src/model/ukui-audio-sink-model.cpp
src/model/ukui-audio-sink-model.h
src/model/ukui-audio-source-model.cpp
src/model/ukui-audio-source-model.h
../backend/Util.h
src/extra/DBusClient.cpp
src/extra/DBusClient.h
src/extra/BaseType.h
)
set(CONFIG_FILES
config/qmldir
)
set(QML_META_FILES
qml/metadata.json
)
set(QRC_FILES
qml/qml.qrc
res/res.qrc
)
file(GLOB TS_FILES translations/*.ts)
if(${QT_VERSION_MAJOR} GREATER_EQUAL 6)
qt6_create_translation(QM_FILES ${CMAKE_CURRENT_SOURCE_DIR} ${TS_FILES} OPTIONS -no-obsolete -no-ui-lines)
else()
qt5_create_translation(QM_FILES ${CMAKE_CURRENT_SOURCE_DIR} ${TS_FILES} OPTIONS -no-obsolete -no-ui-lines)
endif()
add_library(${PROJECT_NAME} SHARED ${SOURCE_FILES} ${CONFIG_FILES} ${QML_META_FILES} ${QRC_FILES} ${QM_FILES})
target_compile_definitions(${PROJECT_NAME} PRIVATE $<$:QT_QML_DEBUG>)
target_link_libraries(${PROJECT_NAME}
PRIVATE
Qt${QT_VERSION_MAJOR}::Core
Qt${QT_VERSION_MAJOR}::Quick
Qt${QT_VERSION_MAJOR}::Gui
Qt${QT_VERSION_MAJOR}::Widgets
Qt${QT_VERSION_MAJOR}::DBus
)
target_include_directories(${PROJECT_NAME}
PUBLIC ../backend
)
message("UKUI_SHORTCUT_AUDIO_DATA_DIR:" ${UKUI_SHORTCUT_AUDIO_DATA_DIR})
message("UKUI_SHORTCUT_AUDIO_TRANSLATION_DIR:" ${UKUI_SHORTCUT_AUDIO_TRANSLATION_DIR})
install(DIRECTORY "qml/" DESTINATION ${UKUI_SHORTCUT_AUDIO_DATA_DIR})
install(DIRECTORY "res/" DESTINATION "${UKUI_SHORTCUT_AUDIO_DATA_DIR}/res")
install(FILES ${QM_FILES} DESTINATION ${UKUI_SHORTCUT_AUDIO_TRANSLATION_DIR})
install(FILES ${CONFIG_FILES} DESTINATION "/usr/lib/${CMAKE_LIBRARY_ARCHITECTURE}/qt${QT_VERSION_MAJOR}/qml/org/ukui/shortcut/audio")
install(TARGETS ${PROJECT_NAME} LIBRARY DESTINATION "/usr/lib/${CMAKE_LIBRARY_ARCHITECTURE}/qt${QT_VERSION_MAJOR}/qml/org/ukui/shortcut/audio")
ukui-volume-control/ukui-shortcut-audio/translations/ 0000775 0001750 0001750 00000000000 15171074712 022113 5 ustar feng feng ukui-volume-control/ukui-shortcut-audio/translations/ukui-shortcut-audio_zh_HK.ts 0000664 0001750 0001750 00000005355 15171074712 027503 0 ustar feng feng
AudioListArea
(
)
DeviceDelegate
EmptyDelegate
HeaderDelegate
MoreAudioSettingArea
More sound settings
更多聲音設置
QObject
Output
輸出
No output sound card detected
未檢測到輸出聲卡
There are currently no applications that play sound
暫無播放聲音的應用
Application volume
應用音量
Input
輸入
UKUIAudioSinkModel
Multi Bluetooth Output
多藍牙輸出
ukui-volume-control/ukui-shortcut-audio/translations/ukui-shortcut-audio_zh_CN.ts 0000664 0001750 0001750 00000005355 15171074712 027501 0 ustar feng feng
AudioListArea
(
)
DeviceDelegate
EmptyDelegate
HeaderDelegate
MoreAudioSettingArea
More sound settings
更多声音设置
QObject
Output
输出
No output sound card detected
未检测到输出声卡
There are currently no applications that play sound
暂无播放声音的应用
Application volume
应用音量
Input
输入
UKUIAudioSinkModel
Multi Bluetooth Output
多蓝牙输出
ukui-volume-control/ukui-shortcut-audio/translations/ukui-shortcut-audio_ky.ts 0000664 0001750 0001750 00000005701 15171074712 027116 0 ustar feng feng
AudioListArea
(
)
DeviceDelegate
EmptyDelegate
HeaderDelegate
MoreAudioSettingArea
More sound settings
داعى ەلە كۅپ دووش قۇرۇۇ ، اچۇۇ ، باشتوو جاسوو ،اتقارۇۇ
QObject
Output
چىعۇۇ
No output sound card detected
ۅندۉرۉش دووش كارتاسىن تەكشۈرمىگەن
There are currently no applications that play sound
ازىرچا قويۇلباعان دووشتۇن قولدونۇۇسۇ
Application volume
قولدونۇشچان دووش
Input
كىرگىز
UKUIAudioSinkModel
Multi Bluetooth Output
كۅپ بليۇتۇز ۅندۉرۉش
ukui-volume-control/ukui-shortcut-audio/translations/ukui-shortcut-audio_mn.ts 0000664 0001750 0001750 00000006210 15171074712 027101 0 ustar feng feng
AudioListArea
(
)
DeviceDelegate
EmptyDelegate
HeaderDelegate
MoreAudioSettingArea
More sound settings
ᠨᠡᠩ ᠣᠯᠠᠨ ᠳᠠᠭᠤ ᠵᠢ ᠳᠤᠬᠢᠷᠠᠭᠤᠯᠬᠤ
QObject
Output
ᠭᠠᠷᠭᠠᠬᠤ
No output sound card detected
ᠭᠠᠷᠭᠠᠬᠤ ᠳᠠᠭᠤᠨ ᠤ᠋ ᠺᠠᠷᠲ ᠵᠢ ᠬᠢᠨᠠᠨ ᠬᠡᠮᠵᠢᠵᠤ ᠤᠯᠤᠭᠰᠠᠨ ᠥᠬᠡᠢ
There are currently no applications that play sound
ᠲᠦᠷ ᠨᠡᠪᠳᠡᠷᠡᠬᠦᠯᠬᠦ ᠳᠠᠭᠤᠨ ᠤ᠋ ᠬᠡᠷᠡᠭᠯᠡᠭᠡ ᠪᠠᠢᠬᠤ ᠥᠬᠡᠢ
Application volume
ᠬᠡᠷᠡᠭᠯᠡᠭᠡᠨ ᠤ᠋ ᠳᠠᠭᠤᠨ ᠤ᠋ ᠬᠡᠮᠵᠢᠶᠡ
Input
ᠣᠷᠣᠭᠤᠯᠬᠤ
UKUIAudioSinkModel
Multi Bluetooth Output
ᠣᠯᠠᠨ ᠯᠠᠨᠶᠠ ᠭᠠᠷᠭᠠᠯᠳᠠ
ukui-volume-control/ukui-shortcut-audio/translations/ukui-shortcut-audio_bo_CN.ts 0000664 0001750 0001750 00000006304 15171074712 027453 0 ustar feng feng
AudioListArea
(
)
DeviceDelegate
EmptyDelegate
HeaderDelegate
MoreAudioSettingArea
More sound settings
སྐད་སྒྲ་དེ་བས་མང་བ་བཀོད་སྒྲིག་བྱེད་དགོས།
QObject
Output
ཕྱིར་འདྲེན།
No output sound card detected
ཞིབ་དཔྱད་ཚད་ལེན་མ་བྱས་པར་སྒྲའི་བྱང་བུ་ཕྱིར་གཏོང་བྱེད་པ།
There are currently no applications that play sound
གནས་སྐབས་སུ་སྐད་སྒྲ་མ་གཏོང་།
Application volume
ཉེར་སྤྱོད་སྒྲ་ཚད།
Input
མ་དངུལ་འཇོག་པ།
UKUIAudioSinkModel
Multi Bluetooth Output
སོ་སྔོན་པོ་མང་པོ་ཕྱིར་གཏོང་།
ukui-volume-control/ukui-shortcut-audio/translations/ukui-shortcut-audio_ug.ts 0000664 0001750 0001750 00000005632 15171074712 027111 0 ustar feng feng
AudioListArea
(
)
DeviceDelegate
EmptyDelegate
HeaderDelegate
MoreAudioSettingArea
More sound settings
تېخىمۇ كۆپ ئاۋاز تەسىس قىلىش
QObject
Output
چىقىرىش
No output sound card detected
چىقىرىش ئاۋاز كارتىسىنى تەكشۈرمىگەن
There are currently no applications that play sound
ھازىرچە قويۇلمىغان ئاۋازنىڭ قوللىنىشى
Application volume
قوللىنىشچان ئاۋاز
Input
كىرگۈز
UKUIAudioSinkModel
Multi Bluetooth Output
كۆپ كۆك چىش چىقىرىش
ukui-volume-control/ukui-shortcut-audio/translations/ukui-shortcut-audio_kk.ts 0000664 0001750 0001750 00000005643 15171074712 027105 0 ustar feng feng
AudioListArea
(
)
DeviceDelegate
EmptyDelegate
HeaderDelegate
MoreAudioSettingArea
More sound settings
الٸدە كوپ اۋا ورنالاسترعان ەتۋ
QObject
Output
جاريالاۋ
No output sound card detected
جاريالاۋ اۋا كارتوشكاسىن تەكسەرمەگەن
There are currently no applications that play sound
قازىرشا قويىلماعان داۋىستىڭ قولدانىلۋى
Application volume
قولدانعىش اۋا
Input
كىرگىزۋ
UKUIAudioSinkModel
Multi Bluetooth Output
كوپ بليۇتووت جاريالاۋ
ukui-volume-control/ukui-shortcut-audio/src/ 0000775 0001750 0001750 00000000000 15171074677 020173 5 ustar feng feng ukui-volume-control/ukui-shortcut-audio/src/model/ 0000775 0001750 0001750 00000000000 15171074712 021261 5 ustar feng feng ukui-volume-control/ukui-shortcut-audio/src/model/ukui-audio-source-model.h 0000664 0001750 0001750 00000011433 15171074712 026104 0 ustar feng feng /*
* Copyright (C) 2024, KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
* Authors: zhouyong
*
*/
#ifndef UKUIAUDIOSOURCEMODEL_H
#define UKUIAUDIOSOURCEMODEL_H
#include
#include
#include "../extra/DBusClient.h"
class UKUIAudioSourceModel : public QAbstractListModel
{
Q_OBJECT
public:
// 定义角色(暴露给 QML 的属性)
enum SourceInfoRoles {
ItemTypeRole = Qt::UserRole + 1,
TitleRole, // 标题内容(仅 Header 使用)
CardNameRole,
CardDescRole,
PortNameRole,
PortLabelRole,
PriorityRole,
DirectionRole,
AvailableRole,
PortEnabledRole,
PortTypeRole,
PortIconRole,
IsActivePortRole,
StreamNameRole,
StreamIndexRole,
StreamVolumeRole,
StreamRole,
StreamIconNameRole
};
Q_ENUM(SourceInfoRoles)
// 定义数据项类型
enum ItemType {
Invaild = -1,
HeaderOutput, // 输出设备标题
HeaderAppVolume, // 应用音量标题
DeviceItem, // 设备项
StreamItem, // 应用音量项
EmptyDeviceItem, // 空设备项
EmptyStreamItem // 空应用音量项
};
Q_ENUM(ItemType)
// 内部数据结构
struct SourceInfo
{
ItemType itemType = Invaild; //列表item类型 ItemType
QString title = ""; // 标题文案
QString cardName; // 声卡名称
QString cardDesc; // 声卡描述
QString portName; // 设备端口名称
QString portLabel; // 设备端口描述
uint32_t priority; // 端口优先级
quint32 direction; // 端口方向 input or output
quint32 available; // 端口可用状态
bool enabled = true; // 端口是否启用
int32_t type; // 端口的类型
QString portIcon = ""; // 设备图标
bool isActivePort = false;
friend const ClientDeviceInfo& operator>>(const ClientDeviceInfo& argument, SourceInfo& info) {
info.itemType = DeviceItem;
info.cardName = argument.cardName;
info.cardDesc = argument.cardDesc;
info.portName = argument.portName;
info.portLabel = argument.portLabel;
info.priority = argument.priority;
info.direction = argument.direction;
info.available = argument.available;
// info.enabled = argument.enabled;
// info.type = argument.type;
return argument;
}
QString streamName; // 流媒体名称
quint32 streamIndex; // 流媒体索引
uint32_t streamVolume; // 流媒体音量
QString streamRole; // 流媒体角色
QString streamIconName; // 流媒体图标名称
friend const StreamInfo& operator>>(const StreamInfo& argument, SourceInfo& info) {
info.itemType = StreamItem;
info.streamName = argument.name;
info.streamIndex = argument.index;
info.streamVolume = argument.volume;
info.streamRole = argument.role;
info.streamIconName = argument.iconName;
return argument;
}
};
static UKUIAudioSourceModel& getInstance();
void initData();
void initSlots();
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
QHash roleNames() const override;
void addDeviceHeader();
void addDevice(ClientDeviceInfo deviceInfo);
bool setDeviceActivePort(QString portName, QString cardName);
void removeDevice(int index);
void clearDevice();
void addStreamHeader();
void addStream(StreamInfo streamInfo);
void removeStream(int index);
void clearStream();
int getStreamCount();
void releaseModel();
private Q_SLOTS:
private:
UKUIAudioSourceModel() = default;
UKUIAudioSourceModel(const UKUIAudioSourceModel&) = delete;
UKUIAudioSourceModel(UKUIAudioSourceModel&&) = delete;
~UKUIAudioSourceModel();
public:
private:
QList m_sourceInfos;
};
#endif // UKUIAUDIOSOURCEMODEL_H
ukui-volume-control/ukui-shortcut-audio/src/model/ukui-audio-sink-model.h 0000664 0001750 0001750 00000013074 15171074712 025553 0 ustar feng feng /*
* Copyright (C) 2024, KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
* Authors: zhouyong
*
*/
#ifndef UKUIAUDIOSINKMODEL_H
#define UKUIAUDIOSINKMODEL_H
#include
#include
#include
#include "../extra/DBusClient.h"
class UKUIAudioSinkModel : public QAbstractListModel
{
Q_OBJECT
public:
// 定义角色(暴露给 QML 的属性)
enum SinkInfoRoles {
ItemTypeRole = Qt::UserRole + 1,
TitleRole, // 标题内容(仅 Header 使用)
CardNameRole,
CardDescRole,
PortNameRole,
PortLabelRole,
PriorityRole,
DirectionRole,
AvailableRole,
PortEnabledRole,
PortTypeRole,
PortIconRole,
IsActivePortRole,
StreamNameRole,
StreamIndexRole,
StreamVolumeRole,
StreamRole,
StreamIconNameRole
};
Q_ENUM(SinkInfoRoles)
// 定义数据项类型
enum ItemType {
Invaild = -1,
HeaderOutput, // 输出设备标题
HeaderAppVolume, // 应用音量标题
DeviceItem, // 设备项
StreamItem, // 应用音量项
EmptyDeviceItem, // 空设备项
EmptyStreamItem // 空应用音量项
};
Q_ENUM(ItemType)
// 内部数据结构
struct SinkInfo
{
ItemType itemType = Invaild; //列表item类型 ItemType
QString title = ""; // 标题文案
QString cardName; // 声卡名称
QString cardDesc; // 声卡描述
QString portName; // 设备端口名称
QString portLabel; // 设备端口描述
uint32_t priority; // 端口优先级
quint32 direction; // 端口方向 input or output
quint32 available; // 端口可用状态
bool enabled = true; // 端口是否启用
int32_t type; // 端口的类型
QString portIcon = ""; // 设备图标
bool isActivePort = false;
friend const ClientDeviceInfo& operator>>(const ClientDeviceInfo& argument, SinkInfo& info) {
info.itemType = DeviceItem;
info.cardName = argument.cardName;
info.cardDesc = argument.cardDesc;
info.portName = argument.portName;
info.portLabel = argument.portLabel;
info.priority = argument.priority;
info.direction = argument.direction;
info.available = argument.available;
info.enabled = argument.enabled;
info.type = argument.type;
return argument;
}
friend const ClientDefaultDeviceInfo& operator>>(const ClientDefaultDeviceInfo& argument, SinkInfo& info) {
info.itemType = DeviceItem;
info.cardName = argument.cardName;
info.cardDesc = argument.activePortDesc;
info.portName = argument.activePortName;
info.portLabel = tr("Multi Bluetooth Output");
info.priority = -1;
info.direction = 0;
info.available = 0;
info.enabled = 1;
info.type = 0;
return argument;
}
QString streamName; // 流媒体名称
quint32 streamIndex; // 流媒体索引
uint32_t streamVolume; // 流媒体音量
QString streamRole; // 流媒体角色
QString streamIconName; // 流媒体图标名称
friend const StreamInfo& operator>>(const StreamInfo& argument, SinkInfo& info) {
info.itemType = StreamItem;
info.streamName = argument.name;
info.streamIndex = argument.index;
info.streamVolume = argument.volume;
info.streamRole = argument.role;
info.streamIconName = argument.iconName;
return argument;
}
};
static UKUIAudioSinkModel& getInstance();
void initData();
void initSlots();
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
QHash roleNames() const override;
void addDeviceHeader();
void addEmptyDevice();
void addDevice(ClientDeviceInfo deviceInfo);
void addDevice(ClientDefaultDeviceInfo deviceInfo);
bool setDeviceActivePort(QString portName, QString cardName);
void removeDevice(int index);
void clearDevice();
int getDeviceCount();
int getEnabledDeviceCount();
int getInsertDeviceIndex();
void addStreamHeader();
void addEmptyStream();
void addStream(StreamInfo streamInfo);
void removeStream(int index);
void clearStream();
int getStreamCount();
int getStreamIndexByStreamIconName(QString iconName);
void releaseModel();
signals:
private Q_SLOTS:
private:
UKUIAudioSinkModel() = default;
UKUIAudioSinkModel(const UKUIAudioSinkModel&) = delete;
UKUIAudioSinkModel(UKUIAudioSinkModel&&) = delete;
~UKUIAudioSinkModel();
public:
private:
QList m_sinkInfos;
};
#endif // UKUIAUDIOSINKMODEL_H
ukui-volume-control/ukui-shortcut-audio/src/model/ukui-audio-source-model.cpp 0000664 0001750 0001750 00000017153 15171074712 026444 0 ustar feng feng /*
* Copyright (C) 2024, KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
* Authors: zhouyong
*
*/
#include "ukui-audio-source-model.h"
#include
UKUIAudioSourceModel& UKUIAudioSourceModel::getInstance()
{
static UKUIAudioSourceModel instance;
return instance;
}
void UKUIAudioSourceModel::initData()
{
}
void UKUIAudioSourceModel::initSlots()
{
}
int UKUIAudioSourceModel::rowCount(const QModelIndex &parent) const
{
Q_UNUSED(parent);
return m_sourceInfos.size();
}
QVariant UKUIAudioSourceModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid() || index.row() >= m_sourceInfos.size())
{
return QVariant();
}
const SourceInfo& sourceInfo = m_sourceInfos.at(index.row());
switch (role) {
case ItemTypeRole: return sourceInfo.itemType;
case TitleRole: return sourceInfo.title;
case CardNameRole: return sourceInfo.cardName;
case CardDescRole: return sourceInfo.cardDesc;
case PortNameRole: return sourceInfo.portName;
case PortLabelRole:return sourceInfo.portLabel;
case PriorityRole:return sourceInfo.priority;
case DirectionRole: return sourceInfo.direction;
case AvailableRole: return sourceInfo.available;
case PortEnabledRole: return sourceInfo.enabled;
case PortTypeRole: return sourceInfo.type;
case PortIconRole: return sourceInfo.portIcon;
case IsActivePortRole: return sourceInfo.isActivePort;
case StreamNameRole: return sourceInfo.streamName;
case StreamIndexRole: return sourceInfo.streamIndex;
case StreamVolumeRole: return sourceInfo.streamVolume;
case StreamRole: return sourceInfo.streamRole;
case StreamIconNameRole: return sourceInfo.streamIconName;
default: return QVariant();
}
}
QHash UKUIAudioSourceModel::roleNames() const
{
return {
{ItemTypeRole, "itemType"},
{TitleRole, "title"},
{CardNameRole, "cardName"},
{CardDescRole, "cardDesc"},
{PortNameRole, "portName"},
{PortLabelRole, "portLabel"},
{PriorityRole, "priority"},
{DirectionRole, "direction"},
{AvailableRole, "available"},
{PortEnabledRole, "portEnabled"},
{PortTypeRole, "portType"},
{PortIconRole, "portIcon"},
{IsActivePortRole, "isActivePort"},
{StreamNameRole, "streamName"},
{StreamIndexRole, "streamIndex"},
{StreamVolumeRole, "streamVolume"},
{StreamRole, "streamRole"},
{StreamIconNameRole, "streamIconName"}
};
}
void UKUIAudioSourceModel::addDeviceHeader()
{
beginInsertRows(QModelIndex(), rowCount(), rowCount());
m_sourceInfos.append({HeaderOutput, QObject::tr("Input"), "", "", "", "", 0, 0, 0, true, -1, "", false,
"", 0, 0, "", ""});
endInsertRows();
}
void UKUIAudioSourceModel::addDevice(ClientDeviceInfo deviceInfo)
{
SourceInfo SourceInfo;
deviceInfo >> SourceInfo;
beginInsertRows(QModelIndex(), rowCount(), rowCount());
m_sourceInfos.append(SourceInfo);
endInsertRows();
}
bool UKUIAudioSourceModel::setDeviceActivePort(QString portName, QString cardName)
{
qDebug() << __func__ << "enter" << "portName:" << portName << "cardName:" << cardName;
bool ret = false;
int index = 0;
for (; index < m_sourceInfos.size(); ++index) {
if (m_sourceInfos.at(index).itemType != DeviceItem)
{
continue;
}
qDebug() << __func__ << "index:" << index << "cardName:" << m_sourceInfos.at(index).cardName
<< "portName:" << m_sourceInfos.at(index).portName;
if ((m_sourceInfos.at(index).cardName.compare(cardName) == 0)
&& (m_sourceInfos.at(index).portName.compare(portName) == 0))
{
m_sourceInfos[index].isActivePort = true;
QModelIndex topLeft = createIndex(index, 0, nullptr);
QModelIndex bottomRight = createIndex(index, 0, nullptr);
emit dataChanged(topLeft, bottomRight);
ret = true;
}
else
{
m_sourceInfos[index].isActivePort = false;
QModelIndex topLeft = createIndex(index, 0, nullptr);
QModelIndex bottomRight = createIndex(index, 0, nullptr);
emit dataChanged(topLeft, bottomRight);
}
}
return ret;
}
void UKUIAudioSourceModel::removeDevice(int index)
{
if (index < 0 || index >= m_sourceInfos.size())
{
qDebug() << __func__ << "index is invaild" << index;
return;
}
if (m_sourceInfos.at(index).itemType != DeviceItem)
{
qDebug() << __func__ << "this index no DeviceItem" << index;
return;
}
beginRemoveRows(QModelIndex(), index, index);
m_sourceInfos.removeAt(index);
endRemoveRows();
}
void UKUIAudioSourceModel::clearDevice()
{
int index;
for (index = 0; index < m_sourceInfos.size(); ++index) {
if (m_sourceInfos.at(index).itemType == DeviceItem)
{
beginRemoveRows(QModelIndex(), index, index);
m_sourceInfos.removeAt(index);
endRemoveRows();
}
}
}
void UKUIAudioSourceModel::addStreamHeader()
{
beginInsertRows(QModelIndex(), rowCount(), rowCount());
m_sourceInfos.append({HeaderAppVolume, QObject::tr("Application volume"), "", "", "", "", 0, 0, 0, true, -1, "", false,
"", 0, 0, "", ""});
endInsertRows();
}
void UKUIAudioSourceModel::addStream(StreamInfo streamInfo)
{
SourceInfo SourceInfo;
streamInfo >> SourceInfo;
beginInsertRows(QModelIndex(), rowCount(), rowCount());
m_sourceInfos.append(SourceInfo);
endInsertRows();
}
void UKUIAudioSourceModel::removeStream(int index)
{
if (index < 0 || index >= m_sourceInfos.size())
{
qDebug() << __func__ << "index is invaild" << index;
return;
}
if (m_sourceInfos.at(index).itemType != StreamItem)
{
qDebug() << __func__ << "this index no StreamItem" << index;
return;
}
beginRemoveRows(QModelIndex(), index, index);
m_sourceInfos.removeAt(index);
endRemoveRows();
}
void UKUIAudioSourceModel::clearStream()
{
int index;
for (index = 0; index < m_sourceInfos.size(); ++index) {
if (m_sourceInfos.at(index).itemType == StreamItem)
{
beginRemoveRows(QModelIndex(), index, index);
m_sourceInfos.removeAt(index);
endRemoveRows();
}
}
}
int UKUIAudioSourceModel::getStreamCount()
{
int index = 0;
int count = 0;
for (; index < m_sourceInfos.size(); ++index) {
if (m_sourceInfos.at(index).itemType == StreamItem)
{
count++;
}
}
qDebug() << __func__ << "count:" << count;
return count;
}
void UKUIAudioSourceModel::releaseModel()
{
qDebug() << "UKUIAudioSourceModel::releaseModel" << "enter";
// beginResetModel();
m_sourceInfos.clear();
// endResetModel();
qDebug() << "UKUIAudioSourceModel::releaseModel" << "leave";
}
UKUIAudioSourceModel::~UKUIAudioSourceModel()
{
qDebug() << __func__ << "enter";
releaseModel();
}
ukui-volume-control/ukui-shortcut-audio/src/model/ukui-audio-sink-model.cpp 0000664 0001750 0001750 00000031255 15171074712 026107 0 ustar feng feng /*
* Copyright (C) 2024, KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
* Authors: zhouyong
*
*/
#include "ukui-audio-sink-model.h"
#include
UKUIAudioSinkModel& UKUIAudioSinkModel::getInstance()
{
static UKUIAudioSinkModel instance;
return instance;
}
void UKUIAudioSinkModel::initData()
{
}
void UKUIAudioSinkModel::initSlots()
{
}
int UKUIAudioSinkModel::rowCount(const QModelIndex &parent) const
{
Q_UNUSED(parent);
return m_sinkInfos.size();
}
QVariant UKUIAudioSinkModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid() || index.row() >= m_sinkInfos.size())
{
qDebug() << __func__ << "Invaild index:" << index;
return QVariant();
}
const SinkInfo& sinkInfo = m_sinkInfos.at(index.row());
switch (role) {
case ItemTypeRole: return sinkInfo.itemType;
case TitleRole: return sinkInfo.title;
case CardNameRole: return sinkInfo.cardName;
case CardDescRole: return sinkInfo.cardDesc;
case PortNameRole: return sinkInfo.portName;
case PortLabelRole:return sinkInfo.portLabel;
case PriorityRole:return sinkInfo.priority;
case DirectionRole: return sinkInfo.direction;
case AvailableRole: return sinkInfo.available;
case PortEnabledRole: return sinkInfo.enabled;
case PortTypeRole: return sinkInfo.type;
case PortIconRole: return sinkInfo.portIcon;
case IsActivePortRole: return sinkInfo.isActivePort;
case StreamNameRole: return sinkInfo.streamName;
case StreamIndexRole: return sinkInfo.streamIndex;
case StreamVolumeRole: return sinkInfo.streamVolume;
case StreamRole: return sinkInfo.streamRole;
case StreamIconNameRole: return sinkInfo.streamIconName;
default: return QVariant();
}
}
QHash UKUIAudioSinkModel::roleNames() const
{
return {
{ItemTypeRole, "itemType"},
{TitleRole, "title"},
{CardNameRole, "cardName"},
{CardDescRole, "cardDesc"},
{PortNameRole, "portName"},
{PortLabelRole, "portLabel"},
{PriorityRole, "priority"},
{DirectionRole, "direction"},
{AvailableRole, "available"},
{PortEnabledRole, "portEnabled"},
{PortTypeRole, "portType"},
{PortIconRole, "portIcon"},
{IsActivePortRole, "isActivePort"},
{StreamNameRole, "streamName"},
{StreamIndexRole, "streamIndex"},
{StreamVolumeRole, "streamVolume"},
{StreamRole, "streamRole"},
{StreamIconNameRole, "streamIconName"}
};
}
void UKUIAudioSinkModel::addDeviceHeader()
{
beginInsertRows(QModelIndex(), rowCount(), rowCount());
m_sinkInfos.append({HeaderOutput, QObject::tr("Output"), "", "", "", "", 0, 0, 0, true, -1, "", false,
"", 0, 0, "", ""});
endInsertRows();
}
void UKUIAudioSinkModel::addEmptyDevice()
{
qDebug() << __func__ << "enter insert 1 index:" << (m_sinkInfos.size() - 1);
beginInsertRows(QModelIndex(), (m_sinkInfos.size() - 1), (m_sinkInfos.size() - 1));
m_sinkInfos.insert(1, {EmptyDeviceItem, QObject::tr("No output sound card detected"), "", "", "", "", 0, 0, 0, true, -1, "", false,
"", 0, 0, "", ""});
endInsertRows();
}
void UKUIAudioSinkModel::addDevice(ClientDeviceInfo deviceInfo)
{
qDebug() << __func__ << QString("Add card: %1 port: %2 to device list").arg(deviceInfo.cardName).arg(deviceInfo.portName);
if ((m_sinkInfos.size() - 1) < 0) {
qDebug() << __func__ << "m_sinkInfos.size invaild";
return;
}
SinkInfo sinkInfo;
deviceInfo >> sinkInfo;
if (sinkInfo.portName.contains(QString("headphone"), Qt::CaseInsensitive)) {
sinkInfo.portIcon = "audio-headphones-symbolic";
} else if (sinkInfo.portName.contains(QString("headset"), Qt::CaseInsensitive)) {
sinkInfo.portIcon = "audio-headset-symbolic";
} else {
sinkInfo.portIcon = "audio-speakers-symbolic";
}
beginInsertRows(QModelIndex(), getInsertDeviceIndex(), getInsertDeviceIndex());
m_sinkInfos.insert(getInsertDeviceIndex(), sinkInfo);
endInsertRows();
}
void UKUIAudioSinkModel::addDevice(ClientDefaultDeviceInfo deviceInfo)
{
qDebug() << __func__ << QString("Add card: %1 port: %2 to device list").arg(deviceInfo.cardName).arg(deviceInfo.activePortName);
if ((m_sinkInfos.size() - 1) < 0) {
qDebug() << __func__ << "m_sinkInfos.size invaild";
return;
}
SinkInfo sinkInfo;
deviceInfo >> sinkInfo;
if (sinkInfo.portName.contains(QString("headphone"), Qt::CaseInsensitive)) {
sinkInfo.portIcon = "audio-headphones-symbolic";
} else if (sinkInfo.portName.contains(QString("headset"), Qt::CaseInsensitive)) {
sinkInfo.portIcon = "audio-headset-symbolic";
} else if (sinkInfo.portName.contains(QString("combine"), Qt::CaseInsensitive)) {
sinkInfo.portIcon = "audio-speakers-bluetooth-symbolic";
} else {
sinkInfo.portIcon = "audio-speakers-symbolic";
}
beginInsertRows(QModelIndex(), getInsertDeviceIndex(), getInsertDeviceIndex());
m_sinkInfos.insert(getInsertDeviceIndex(), sinkInfo);
endInsertRows();
}
bool UKUIAudioSinkModel::setDeviceActivePort(QString portName, QString cardName)
{
qDebug() << __func__ << "enter" << "portName:" << portName << "cardName:" << cardName;
bool ret = false;
int index = 0;
beginResetModel();
for (; index < m_sinkInfos.size(); ++index) {
if (m_sinkInfos.at(index).itemType != DeviceItem)
{
continue;
}
// qDebug() << __func__ << "index:" << index << "cardName:" << m_sinkInfos.at(index).cardName
// << "portName:" << m_sinkInfos.at(index).portName;
if ((m_sinkInfos.at(index).cardName.compare(cardName) == 0)
&& (m_sinkInfos.at(index).portName.compare(portName) == 0))
{
m_sinkInfos[index].isActivePort = true;
QModelIndex topLeft = createIndex(index, 0, nullptr);
QModelIndex bottomRight = createIndex(index, 0, nullptr);
// emit dataChanged(topLeft, bottomRight);
ret = true;
}
else
{
m_sinkInfos[index].isActivePort = false;
QModelIndex topLeft = createIndex(index, 0, nullptr);
QModelIndex bottomRight = createIndex(index, 0, nullptr);
// emit dataChanged(topLeft, bottomRight);
}
}
endResetModel();
return ret;
}
void UKUIAudioSinkModel::removeDevice(int index)
{
if (index < 0 || index >= m_sinkInfos.size())
{
qDebug() << __func__ << "index is invaild" << index;
return;
}
if (m_sinkInfos.at(index).itemType != DeviceItem)
{
qDebug() << __func__ << "this index no DeviceItem" << index;
return;
}
qDebug() << __func__ << QString("Remove %1 device.").arg(index);
beginRemoveRows(QModelIndex(), index, index);
m_sinkInfos.removeAt(index);
endRemoveRows();
}
void UKUIAudioSinkModel::clearDevice()
{
int index = m_sinkInfos.size() - 1;
for (; index >= 0; --index) {
// qDebug() << __func__ << "index:" << index << "itemType:" << m_sinkInfos.at(index).itemType << "size:" << m_sinkInfos.size();
if (m_sinkInfos.at(index).itemType == DeviceItem
|| m_sinkInfos.at(index).itemType == EmptyDeviceItem)
{
beginRemoveRows(QModelIndex(), index, index);
m_sinkInfos.removeAt(index);
endRemoveRows();
}
}
}
int UKUIAudioSinkModel::getDeviceCount()
{
int index = 0;
int count = 0;
for (; index < m_sinkInfos.size(); ++index) {
if (m_sinkInfos.at(index).itemType == DeviceItem)
{
count++;
}
}
qDebug() << __func__ << "count:" << count;
return count;
}
int UKUIAudioSinkModel::getEnabledDeviceCount()
{
int index = 0;
int count = 0;
for (; index < m_sinkInfos.size(); ++index) {
if ((m_sinkInfos.at(index).itemType == DeviceItem)
&& (m_sinkInfos.at(index).enabled))
{
count++;
}
}
qDebug() << __func__ << "count:" << count;
return count;
}
int UKUIAudioSinkModel::getInsertDeviceIndex()
{
int index = 1;
for (; index < m_sinkInfos.size(); ++index) {
if (m_sinkInfos.at(index).itemType == HeaderAppVolume)
{
break;
}
}
// qDebug() << __func__ << "index:" << index;
return index;
}
void UKUIAudioSinkModel::addStreamHeader()
{
beginInsertRows(QModelIndex(), rowCount(), rowCount());
m_sinkInfos.append({HeaderAppVolume, QObject::tr("Application volume"), "", "", "", "", 0, 0, 0, true, -1, "", false,
"", 0, 0, "", ""});
endInsertRows();
}
void UKUIAudioSinkModel::addEmptyStream()
{
qDebug() << __func__ << "enter index:" << m_sinkInfos.size();
beginInsertRows(QModelIndex(), m_sinkInfos.size(), m_sinkInfos.size());
m_sinkInfos.insert(m_sinkInfos.size(), {EmptyStreamItem, QObject::tr("There are currently no applications that play sound"), "", "", "", "", 0, 0, 0, true, -1, "", false,
"", 0, 0, "", ""});
endInsertRows();
}
void UKUIAudioSinkModel::addStream(StreamInfo streamInfo)
{
qDebug() << __func__ << "enter streamInfo.name:" << streamInfo.name << "streamInfo.index:" << streamInfo.index
<< "streamInfo.volume:" << streamInfo.volume << "streamInfo.role:" << streamInfo.role
<< "streamInfo.iconName:" << streamInfo.iconName;
if (m_sinkInfos.size() <= 0) {
qDebug() << __func__ << "m_sinkInfos.size invaild";
return;
}
if ((streamInfo.role.compare(QString("filter")) == 0) ||
(streamInfo.role.compare(QString("abstract")) == 0) ||
(streamInfo.role.compare(QString("event")) == 0)) {
qDebug() << __func__ << streamInfo.role << "abandoned";
return;
}
SinkInfo sinkInfo;
streamInfo >> sinkInfo;
beginInsertRows(QModelIndex(), m_sinkInfos.size(), m_sinkInfos.size());
m_sinkInfos.insert(m_sinkInfos.size(), sinkInfo);
endInsertRows();
}
void UKUIAudioSinkModel::removeStream(int index)
{
if (index < 0 || index >= m_sinkInfos.size())
{
qDebug() << __func__ << "index is invaild" << index;
return;
}
if (m_sinkInfos.at(index).itemType != StreamItem)
{
qDebug() << __func__ << "this index no StreamItem" << index;
return;
}
beginRemoveRows(QModelIndex(), index, index);
m_sinkInfos.removeAt(index);
endRemoveRows();
}
void UKUIAudioSinkModel::clearStream()
{
int index = m_sinkInfos.size() - 1;
for (; index >= 0; --index) {
// qDebug() << __func__ << "index:" << index << "itemType:" << m_sinkInfos.at(index).itemType << "size:" << m_sinkInfos.size();
if (m_sinkInfos.at(index).itemType == StreamItem
|| m_sinkInfos.at(index).itemType == EmptyStreamItem)
{
beginRemoveRows(QModelIndex(), index, index);
m_sinkInfos.removeAt(index);
endRemoveRows();
}
}
}
int UKUIAudioSinkModel::getStreamCount()
{
int index = 0;
int count = 0;
for (; index < m_sinkInfos.size(); ++index) {
if (m_sinkInfos.at(index).itemType == StreamItem)
{
count++;
}
}
qDebug() << __func__ << "count:" << count;
return count;
}
int UKUIAudioSinkModel::getStreamIndexByStreamIconName(QString iconName)
{
int index = 0;
int streamIndex = -1;
for (; index < m_sinkInfos.size(); ++index) {
if (m_sinkInfos.at(index).itemType == StreamItem
&& m_sinkInfos.at(index).streamIconName.compare(iconName) == 0)
{
streamIndex = m_sinkInfos.at(index).streamIndex;
break;
}
}
qDebug() << __func__ << "streamIndex:" << streamIndex;
return streamIndex;
}
void UKUIAudioSinkModel::releaseModel()
{
qDebug() << "UKUIAudioSinkModel::releaseModel" << "enter";
// beginResetModel();
m_sinkInfos.clear();
// endResetModel();
qDebug() << "UKUIAudioSinkModel::releaseModel" << "leave";
}
UKUIAudioSinkModel::~UKUIAudioSinkModel()
{
qDebug() << __func__ << "enter";
releaseModel();
}
ukui-volume-control/ukui-shortcut-audio/src/control/ 0000775 0001750 0001750 00000000000 15171074712 021641 5 ustar feng feng ukui-volume-control/ukui-shortcut-audio/src/control/ukui-audio-source-control.cpp 0000664 0001750 0001750 00000023151 15171074712 027377 0 ustar feng feng /*
* Copyright (C) 2024, KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
* Authors: zhouyong
*
*/
#include "ukui-audio-source-control.h"
#include "Util.h"
#include "../model/ukui-audio-source-model.h"
using namespace UkuiAudioFramwork;
UKUIAudioSourceControl& UKUIAudioSourceControl::getInstance()
{
static UKUIAudioSourceControl instance;
return instance;
}
bool UKUIAudioSourceControl::initData()
{
bool ret = true;
return ret;
}
bool UKUIAudioSourceControl::initSlots()
{
bool ret = true;
ret = connect(&DBusClient::getInstance(), SIGNAL(volumeChangedSignal(int, int, const QDBusVariant&)), this, SLOT(volumeChangedSlots(int, int, const QDBusVariant&)));
return ret;
}
void UKUIAudioSourceControl::volumeChangedSlots(int type, int idx, const QDBusVariant& value)
{
qDebug() << __func__ << "type:" << type << "idx:" << idx << "value:" << value.variant();
if (type == EnumToInt(NodeType::INPUT)) {
setSourceVolumeValue(value.variant().toInt());
}
}
void UKUIAudioSourceControl::deviceChangedSlots(int type, const QString& portName, const QString& cardName)
{
qDebug() << __func__ << "type:" << type << "portName:" << portName << "cardName:" << cardName;
switch (IntToEnum(type)) {
case NodeType::INPUT: {
emit sourceDeviceChanged(portName, cardName);
}
break;
case NodeType::OUTPUT:
case NodeType::SINK_INPUT:
case NodeType::SOURCE_OUTPUT:
default:
break;
}
}
void UKUIAudioSourceControl::deviceAdjustSlots(int type)
{
qDebug() << __func__ << "type:" << type;
switch (IntToEnum(type)) {
case NodeType::INPUT: {
emit sourceDeviceAdjust();
}
break;
case NodeType::OUTPUT:
case NodeType::SINK_INPUT:
case NodeType::SOURCE_OUTPUT:
default:
break;
}
}
bool UKUIAudioSourceControl::getSourceVolume(int index, QVariant& retValue)
{
qDebug() << __func__ << "index" << index;
bool ret = true;
QDBusMessage reply = DBusClient::getInstance().dbusMethodCall(AUDIO_OBJECT_SERVICE,
AUDIO_OBJECT_PATH,
AUDIO_INTERFACE,
"getVolume",
EnumToInt(NodeType::INPUT), index);
if (reply.arguments().isEmpty())
{
qDebug() << __func__ << "arguments is nullptr...";
ret = false;
return ret;
}
qDebug() << __func__ << "reply" << reply.arguments().value(0);
retValue.setValue(reply.arguments());
return ret;
}
void UKUIAudioSourceControl::updateSourceVolume(QVariant retValue)
{
qDebug() << __func__ << "enter";
if (!retValue.isValid()) {
qDebug() << __func__ << "retValue is invalid...";
return;
}
setSourceVolumeValue(retValue.toInt());
}
bool UKUIAudioSourceControl::setSourceVolume(int index, int value)
{
qDebug() << __func__ << "index" << index << "value" << value;
setSourceVolumeValue(value);
bool ret = true;
DBusClient::getInstance().dbusMethodCall(AUDIO_OBJECT_SERVICE,
AUDIO_OBJECT_PATH,
AUDIO_INTERFACE,
"setVolume",
EnumToInt(NodeType::INPUT), index, value);
return ret;
}
bool UKUIAudioSourceControl::getSourceAvailablePortList(QVariant& retValue)
{
qDebug() << __func__ << "enter";
bool ret = true;
QDBusMessage reply = DBusClient::getInstance().dbusMethodCall(AUDIO_OBJECT_SERVICE,
AUDIO_OBJECT_PATH,
AUDIO_INTERFACE,
"getAvailablePortList",
EnumToInt(NodeType::INPUT));
if (reply.arguments().isEmpty())
{
qDebug() << __func__ << "arguments is nullptr...";
ret = false;
return ret;
}
retValue.setValue(reply.arguments());
return ret;
}
void UKUIAudioSourceControl::updateSourceAvailablePortList(QVariant retValue)
{
qDebug() << __func__ << "enter";
if (!retValue.isValid()) {
qDebug() << __func__ << "retValue is invalid...";
return;
}
UKUIAudioSourceModel::getInstance().clearDevice();
UKUIAudioSourceModel::getInstance().addDeviceHeader();
const QDBusArgument& dbusArgs = retValue.value>().at(0).value();
dbusArgs.beginArray();
while (!dbusArgs.atEnd()) {
ClientDeviceInfo info;
dbusArgs >> info;
UKUIAudioSourceModel::getInstance().addDevice(info);
}
dbusArgs.endArray();
}
bool UKUIAudioSourceControl::getSourceOutputList(QVariant& retValue)
{
qDebug() << __func__ << "enter";
bool ret = true;
QDBusMessage reply = DBusClient::getInstance().dbusMethodCall(AUDIO_OBJECT_SERVICE,
AUDIO_OBJECT_PATH,
AUDIO_INTERFACE,
"getSourceOutputList");
if (reply.arguments().isEmpty())
{
qDebug() << __func__ << "arguments is nullptr...";
ret = false;
return ret;
}
retValue.setValue(reply.arguments());
return ret;
}
void UKUIAudioSourceControl::updateSourceInputList(QVariant retValue)
{
qDebug() << __func__ << "enter";
if (!retValue.isValid()) {
qDebug() << __func__ << "retValue is invalid...";
return;
}
UKUIAudioSourceModel::getInstance().clearStream();
UKUIAudioSourceModel::getInstance().addStreamHeader();
const QDBusArgument& dbusArgs = retValue.value>().at(0).value();
dbusArgs.beginArray();
while (!dbusArgs.atEnd()) {
StreamInfo info;
dbusArgs >> info;
UKUIAudioSourceModel::getInstance().addStream(info);
}
dbusArgs.endArray();
}
bool UKUIAudioSourceControl::getSourceDefaultDevice(int index, QVariant& retValue)
{
qDebug() << __func__ << "enter";
bool ret = true;
QDBusMessage reply = DBusClient::getInstance().dbusMethodCall(AUDIO_OBJECT_SERVICE,
AUDIO_OBJECT_PATH,
AUDIO_INTERFACE,
"getDefaultDevice",
EnumToInt(NodeType::INPUT), index);
if (reply.arguments().isEmpty()) {
qDebug() << __func__ << "arguments is nullptr...";
ret = false;
return ret;
}
retValue.setValue(reply.arguments());
return ret;
}
void UKUIAudioSourceControl::updateSourceDefaultDevice(QVariant retValue)
{
qDebug() << __func__ << "enter";
if (!retValue.isValid()) {
qDebug() << __func__ << "retValue is invalid...";
return;
}
const QDBusArgument& dbusArgs = retValue.value>().at(0).value();
ClientDefaultDeviceInfo info;
dbusArgs >> info;
UKUIAudioSourceModel::getInstance().setDeviceActivePort(info.activePortName, info.cardName);
}
void UKUIAudioSourceControl::updateSourceDefaultDevice(const QString& portName, const QString& cardName)
{
qDebug() << __func__ << "enter" << "portName:" << portName << "cardName:" << cardName;
UKUIAudioSourceModel::getInstance().setDeviceActivePort(portName, cardName);
}
bool UKUIAudioSourceControl::setSourceDefaultDevice(int index, const QString& portName, const QString& cardName)
{
qDebug() << __func__ << "enter";
bool ret = true;
DBusClient::getInstance().dbusMethodCall(AUDIO_OBJECT_SERVICE,
AUDIO_OBJECT_PATH,
AUDIO_INTERFACE,
"setDefaultDevice",
EnumToInt(NodeType::INPUT), index, portName, cardName);
return ret;
}
void UKUIAudioSourceControl::releaseData()
{
qDebug() << "UKUIAudioSourceControl::releaseData" << "enter";
m_sourceVolumeValue = -1;
UKUIAudioSourceModel::getInstance().releaseModel();
qDebug() << "UKUIAudioSourceControl::releaseData" << "leave";
}
void UKUIAudioSourceControl::releaseSlots()
{
qDebug() << "UKUIAudioSourceControl::releaseSlots" << "enter";
disconnect(&DBusClient::getInstance(), SIGNAL(volumeChangedSignal(int, int, const QDBusVariant&)), this, SLOT(volumeChangedSlots(int, int, const QDBusVariant&)));
qDebug() << "UKUIAudioSourceControl::releaseSlots" << "leave";
}
UKUIAudioSourceControl::~UKUIAudioSourceControl()
{
qDebug() << __func__ << "enter";
releaseSlots();
releaseData();
}
ukui-volume-control/ukui-shortcut-audio/src/control/ukui-audio-sink-control.cpp 0000664 0001750 0001750 00000053405 15171074712 027050 0 ustar feng feng /*
* Copyright (C) 2024, KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
* Authors: zhouyong
*
*/
#include "ukui-audio-sink-control.h"
#include "Util.h"
#include "../model/ukui-audio-sink-model.h"
#include "./ukui-audio-control.h"
#include "../common/common.h"
using namespace UkuiAudioFramwork;
UKUIAudioSinkControl& UKUIAudioSinkControl::getInstance()
{
static UKUIAudioSinkControl instance;
return instance;
}
bool UKUIAudioSinkControl::initData()
{
bool ret = true;
return ret;
}
bool UKUIAudioSinkControl::initSlots()
{
bool ret = true;
ret = connect(&DBusClient::getInstance(), SIGNAL(volumeChangedSignal(int, int, const QDBusVariant&)), this, SLOT(volumeChangedSlots(int, int, const QDBusVariant&)));
ret = connect(&DBusClient::getInstance(), SIGNAL(muteChangedSignal(int, int, bool)), this, SLOT(muteChangedSlots(int, int, bool)));
ret = connect(&DBusClient::getInstance(), SIGNAL(deviceChangedSignal(int, const QString&, const QString&)), this, SLOT(deviceChangedSlots(int, const QString&, const QString&)));
ret = connect(&DBusClient::getInstance(), SIGNAL(deviceAdjustSignal(int)), this, SLOT(deviceAdjustSlots(int)));
ret = connect(&DBusClient::getInstance(), SIGNAL(addStreamSignal(int, const QString&, const QString&)), this, SLOT(addStreamSlots(int, const QString&, const QString&)));
ret = connect(&DBusClient::getInstance(), SIGNAL(removeStreamSignal(int)), this, SLOT(removeStreamSlots(int)));
ret = connect(&DBusClient::getInstance(), SIGNAL(settingsChangedSignal(QString,QDBusVariant)), this, SLOT(settingsChangedSlots(QString,QDBusVariant)));
//start
ret = QDBusConnection::sessionBus().connect(QString(), QString("/"), QString("org.kylin.music"), QString("sinkInputVolumeChanged"),
this, SLOT(streamVolumeChangedSlots(QString,int,bool)));
ret = QDBusConnection::sessionBus().connect(QString(), QString("/"), QString("org.kylin.video"), QString("sinkInputVolumeChanged"),
this, SLOT(streamVolumeChangedSlots(QString,int,bool)));
//end
return ret;
}
bool UKUIAudioSinkControl::initView()
{
bool ret = true;
UKUIAudioSinkModel::getInstance().addDeviceHeader();
UKUIAudioSinkModel::getInstance().addStreamHeader();
return ret;
}
void UKUIAudioSinkControl::volumeChangedSlots(int type, int idx, const QDBusVariant& value)
{
qDebug() << __func__ << "type:" << type << "idx:" << idx << "value:" << value.variant();
if (type == EnumToInt(NodeType::OUTPUT)) {
setSinkVolumeValue(value.variant().toInt());
}
}
void UKUIAudioSinkControl::muteChangedSlots(int type, int index, bool mute)
{
qDebug() << __func__ << "type:" << type << "index:" << index << "mute:" << mute;
if (type == EnumToInt(NodeType::OUTPUT)) {
setSinkMuteStatus(mute);
}
}
void UKUIAudioSinkControl::deviceChangedSlots(int type, const QString& portName, const QString& cardName)
{
qDebug() << __func__ << "type:" << type << "portName:" << portName << "cardName:" << cardName;
switch (IntToEnum(type)) {
case NodeType::OUTPUT: {
emit sinkDeviceChanged(portName, cardName);
}
break;
case NodeType::INPUT:
case NodeType::SINK_INPUT:
case NodeType::SOURCE_OUTPUT:
default:
break;
}
}
void UKUIAudioSinkControl::deviceAdjustSlots(int type)
{
qDebug() << __func__ << "type:" << type;
switch (IntToEnum(type)) {
case NodeType::OUTPUT: {
emit sinkDeviceAdjust();
}
break;
case NodeType::INPUT:
case NodeType::SINK_INPUT:
case NodeType::SOURCE_OUTPUT:
default:
break;
}
}
void UKUIAudioSinkControl::addStreamSlots(int idx, const QString& iconName, const QString& descName)
{
qDebug() << __func__ << "idx:" << idx << "iconName:" << iconName << "descName:" << descName;
}
void UKUIAudioSinkControl::removeStreamSlots(int idx)
{
qDebug() << __func__ << "idx:" << idx;
}
void UKUIAudioSinkControl::settingsChangedSlots(const QString& key, const QDBusVariant& value)
{
qDebug() << __func__ << "key:" << key << "value:" << value.variant();
if (key.compare(VOLUME_BOOST_KEY) == 0)
{
setSinkVolumeBoostStatus(value.variant().toBool());
}
}
void UKUIAudioSinkControl::streamVolumeChangedSlots(QString name, int value, bool muteStatus)
{
qDebug() << __func__ << "name" << name << "value" << value << "muteStatus" << muteStatus;
m_sinkInputName = name;
m_sinkInputValue = value;
m_sinkInputMuteStatus = muteStatus;
if (nullptr == m_debounceTimer) {
m_debounceTimer = new QTimer(this);
m_debounceTimer->setSingleShot(true);
QObject::connect(m_debounceTimer, &QTimer::timeout, this, &UKUIAudioSinkControl::debounceTimerSlots);
} else {
m_debounceTimer->stop();
m_debounceTimer->start(200);
}
}
void UKUIAudioSinkControl::debounceTimerSlots()
{
qDebug() << __func__ << "m_sinkInputName" << m_sinkInputName << "m_sinkInputValue" << m_sinkInputValue << "m_sinkInputMuteStatus" << m_sinkInputMuteStatus;
int streamIndex = UKUIAudioSinkModel::getInstance().getStreamIndexByStreamIconName(m_sinkInputName);
if (streamIndex == -1) {
qDebug() << __func__ << "streamIndex invaild .";
return;
}
UKUIAudioControl::getInstance().startTask(Common::TaskID_SetSinkInputVolume, streamIndex, m_sinkInputValue);
}
bool UKUIAudioSinkControl::getSinkVolume(int index, QVariant& retValue)
{
qDebug() << __func__ << "index" << index;
bool ret = true;
QDBusMessage reply = DBusClient::getInstance().dbusMethodCall(AUDIO_OBJECT_SERVICE,
AUDIO_OBJECT_PATH,
AUDIO_INTERFACE,
"getVolume",
EnumToInt(NodeType::OUTPUT), index);
if (reply.arguments().isEmpty())
{
qDebug() << __func__ << "arguments is nullptr...";
ret = false;
return ret;
}
retValue.setValue(reply.arguments());
return ret;
}
void UKUIAudioSinkControl::updateSinkVolume(QVariant retValue)
{
qDebug() << __func__ << "enter";
if (!retValue.isValid()) {
qDebug() << __func__ << "retValue is invalid...";
return;
}
setSinkVolumeValue(retValue.value>().at(0).toInt());
}
bool UKUIAudioSinkControl::setSinkVolume(int index, int value)
{
qDebug() << __func__ << "index" << index << "value" << value;
setSinkVolumeValue(value);
bool ret = true;
DBusClient::getInstance().dbusMethodCall(AUDIO_OBJECT_SERVICE,
AUDIO_OBJECT_PATH,
AUDIO_INTERFACE,
"setVolume",
EnumToInt(NodeType::OUTPUT), index, value);
return ret;
}
bool UKUIAudioSinkControl::getSinkMute(int index, QVariant& retValue)
{
qDebug() << __func__ << "index" << index;
bool ret = true;
QDBusMessage reply = DBusClient::getInstance().dbusMethodCall(AUDIO_OBJECT_SERVICE,
AUDIO_OBJECT_PATH,
AUDIO_INTERFACE,
"getMute",
EnumToInt(NodeType::OUTPUT), index);
if (reply.arguments().isEmpty())
{
qDebug() << __func__ << "arguments is nullptr...";
ret = false;
return ret;
}
retValue.setValue(reply.arguments());
return ret;
}
void UKUIAudioSinkControl::updateSinkMute(QVariant retValue)
{
qDebug() << __func__ << "enter";
if (!retValue.isValid()) {
qDebug() << __func__ << "retValue is invalid...";
return;
}
setSinkMuteStatus(retValue.value>().at(0).toBool());
}
bool UKUIAudioSinkControl::setSinkMute(int index, bool muted)
{
qDebug() << __func__ << "index" << index << "muted" << muted;
setSinkMuteStatus(muted);
bool ret = true;
DBusClient::getInstance().dbusMethodCall(AUDIO_OBJECT_SERVICE,
AUDIO_OBJECT_PATH,
AUDIO_INTERFACE,
"setMute",
EnumToInt(NodeType::OUTPUT), index, muted);
return ret;
}
bool UKUIAudioSinkControl::getSinkAvailablePortList(QVariant& retValue)
{
qDebug() << __func__ << "enter";
bool ret = true;
QDBusMessage reply = DBusClient::getInstance().dbusMethodCall(AUDIO_OBJECT_SERVICE,
AUDIO_OBJECT_PATH,
AUDIO_INTERFACE,
"getAvailablePortList",
EnumToInt(NodeType::OUTPUT));
if (reply.arguments().isEmpty())
{
qDebug() << __func__ << "arguments is nullptr...";
ret = false;
return ret;
}
retValue.setValue(reply.arguments());
isExitMultiAudioDevice();
return ret;
}
void UKUIAudioSinkControl::updateSinkAvailablePortList(QVariant retValue)
{
qDebug() << __func__ << "enter";
if (!retValue.isValid()) {
qDebug() << __func__ << "retValue is invalid...";
return;
}
UKUIAudioSinkModel::getInstance().clearDevice();
const QDBusArgument& dbusArgs = retValue.value>().at(0).value();
dbusArgs.beginArray();
while (!dbusArgs.atEnd()) {
ClientDeviceInfo info;
dbusArgs >> info;
UKUIAudioSinkModel::getInstance().addDevice(info);
}
dbusArgs.endArray();
if (UKUIAudioSinkModel::getInstance().getDeviceCount() <= 0) {
UKUIAudioSinkModel::getInstance().addEmptyDevice();
} else if (UKUIAudioSinkModel::getInstance().getEnabledDeviceCount() <= 0) {
UKUIAudioSinkModel::getInstance().addEmptyDevice();
}
if (m_isExitMultiAudioDevice) {
UKUIAudioSinkModel::getInstance().addDevice(m_SinkMutiAudioDeviceInfo);
}
}
bool UKUIAudioSinkControl::getSinkInputList(QVariant& retValue)
{
qDebug() << __func__ << "enter";
bool ret = true;
QDBusMessage reply = DBusClient::getInstance().dbusMethodCall(AUDIO_OBJECT_SERVICE,
AUDIO_OBJECT_PATH,
AUDIO_INTERFACE,
"getSinkInputList");
if (reply.arguments().isEmpty())
{
qDebug() << __func__ << "arguments is nullptr...";
ret = false;
return ret;
}
retValue.setValue(reply.arguments());
return ret;
}
void UKUIAudioSinkControl::updateSinkInputList(QVariant retValue)
{
qDebug() << __func__ << "enter";
if (!retValue.isValid()) {
qDebug() << __func__ << "retValue is invalid...";
return;
}
UKUIAudioSinkModel::getInstance().clearStream();
const QDBusArgument& dbusArgs = retValue.value>().at(0).value();
dbusArgs.beginArray();
while (!dbusArgs.atEnd()) {
StreamInfo info;
dbusArgs >> info;
UKUIAudioSinkModel::getInstance().addStream(info);
}
dbusArgs.endArray();
if (UKUIAudioSinkModel::getInstance().getStreamCount() <= 0) {
UKUIAudioSinkModel::getInstance().addEmptyStream();
}
}
void UKUIAudioSinkControl::updateSinkInputVolume(QVariant retValue)
{
qDebug() << __func__ << "enter";
if (!retValue.isValid()) {
qDebug() << __func__ << "retValue is invalid...";
return;
}
}
bool UKUIAudioSinkControl::setSinkInputVolume(int index, int value)
{
qDebug() << __func__ << "index" << index << "value" << value;
bool ret = true;
DBusClient::getInstance().dbusMethodCall(AUDIO_OBJECT_SERVICE,
AUDIO_OBJECT_PATH,
AUDIO_INTERFACE,
"setVolume",
EnumToInt(NodeType::SINK_INPUT), index, value);
return ret;
}
bool UKUIAudioSinkControl::sendSinkInputVolumeChanged(const QString& iconName, int value, bool muteStatus)
{
qDebug() << __func__ << "iconName" << iconName << "value" << value << "muteStatus" << muteStatus;
bool ret = true;
if ((iconName.compare(QString("kylin-music")) == 0)
|| (iconName.compare(QString("kylin-video")) == 0)) {
QDBusMessage msg = QDBusMessage::createSignal(QString("/"), QString("org.ukui.media"), QString("sinkVolumeChanged"));
msg << iconName << value << muteStatus;
QDBusConnection::sessionBus().send(msg);
qDebug() << __func__ << "iconName:" << iconName << "value:" << value;
}
return ret;
}
bool UKUIAudioSinkControl::getSinkDefaultDevice(int index, QVariant& retValue)
{
qDebug() << __func__ << "enter" << index;
bool ret = true;
QDBusMessage reply = DBusClient::getInstance().dbusMethodCall(AUDIO_OBJECT_SERVICE,
AUDIO_OBJECT_PATH,
AUDIO_INTERFACE,
"getDefaultDevice",
EnumToInt(NodeType::OUTPUT), index);
if (reply.arguments().isEmpty()) {
qDebug() << __func__ << "arguments is nullptr...";
ret = false;
return ret;
}
retValue.setValue(reply.arguments());
return ret;
}
void UKUIAudioSinkControl::updateSinkDefaultDevice(QVariant retValue)
{
qDebug() << __func__ << "enter";
if (!retValue.isValid()) {
qDebug() << __func__ << "retValue is invalid...";
return;
}
const QDBusArgument& dbusArgs = retValue.value>().at(0).value();
ClientDefaultDeviceInfo info;
dbusArgs >> info;
UKUIAudioSinkModel::getInstance().setDeviceActivePort(info.activePortName, info.cardName);
}
void UKUIAudioSinkControl::updateSinkDefaultDevice(const QString& portName, const QString& cardName)
{
qDebug() << __func__ << "enter" << "portName:" << portName << "cardName:" << cardName;
UKUIAudioSinkModel::getInstance().setDeviceActivePort(portName, cardName);
}
bool UKUIAudioSinkControl::setSinkDefaultDevice(int index, const QString &portName, const QString&cardName)
{
qDebug() << __func__ << "enter" << index << "portName:" << portName << "cardName:" << cardName;
bool ret = true;
DBusClient::getInstance().dbusMethodCall(AUDIO_OBJECT_SERVICE,
AUDIO_OBJECT_PATH,
AUDIO_INTERFACE,
"setDefaultDevice",
EnumToInt(NodeType::OUTPUT), index, portName, cardName);
return ret;
}
bool UKUIAudioSinkControl::getSinkVolumeBoostStatus(QVariant& retValue)
{
qDebug() << __func__ << "enter";
bool ret = true;
QDBusMessage reply = DBusClient::getInstance().dbusMethodCall(AUDIO_OBJECT_SERVICE,
AUDIO_OBJECT_PATH,
SETTINGS_INTERFACE,
"getVolumeBoostStatus");
if (reply.arguments().isEmpty()) {
qDebug() << __func__ << "arguments is nullptr...";
ret = false;
return ret;
}
retValue.setValue(reply.arguments());
return ret;
}
void UKUIAudioSinkControl::updateSinkVolumeBoostStatus(QVariant retValue)
{
qDebug() << __func__ << "enter";
if (!retValue.isValid()) {
qDebug() << __func__ << "retValue is invalid...";
return;
}
setSinkVolumeBoostStatus(retValue.value>().at(0).toBool());
}
bool UKUIAudioSinkControl::getSinkVolumeBoostValue(QVariant& retValue)
{
qDebug() << __func__ << "enter";
bool ret = true;
QDBusMessage reply = DBusClient::getInstance().dbusMethodCall(AUDIO_OBJECT_SERVICE,
AUDIO_OBJECT_PATH,
SETTINGS_INTERFACE,
"getVolumeBoostValue");
if (reply.arguments().isEmpty()) {
qDebug() << __func__ << "arguments is nullptr...";
ret = false;
return ret;
}
retValue.setValue(reply.arguments());
return ret;
}
void UKUIAudioSinkControl::updateSinkVolumeBoostValue(QVariant retValue)
{
qDebug() << __func__ << "enter";
if (!retValue.isValid()) {
qDebug() << __func__ << "retValue is invalid...";
return;
}
setSinkVolumeBoostValue(retValue.value>().at(0).toInt());
}
bool UKUIAudioSinkControl::isExitMultiAudioDevice()
{
m_isExitMultiAudioDevice = false;
auto status = getSinkMultiAudioCombineStatus();
if (status) {
auto sinkList = getSinkList();
auto it = std::find_if(sinkList.begin(), sinkList.end(), [](const ClientDefaultDeviceInfo& info) {
return info.name.contains("combine");
});
if (it != sinkList.end()) {
m_isExitMultiAudioDevice = true;
m_SinkMutiAudioDeviceInfo = *it;
qDebug() << __func__ << "Add Multiple Bluetooth outputs, (*it).activePortName " << (*it).activePortName <<
"(*it).cardName" << (*it).cardName;
}
}
return m_isExitMultiAudioDevice;
}
bool UKUIAudioSinkControl::getSinkMultiAudioCombineStatus() const
{
QDBusReply reply = DBusClient::getInstance().dbusMethodCall(AUDIO_OBJECT_SERVICE,
AUDIO_OBJECT_PATH,
AUDIO_INTERFACE,
"getMultiAudioCombineStatus",
EnumToInt(NodeType::OUTPUT));
return reply;
}
QList UKUIAudioSinkControl::getSinkList() const
{
QList list;
QDBusMessage reply = DBusClient::getInstance().dbusMethodCall(AUDIO_OBJECT_SERVICE,
AUDIO_OBJECT_PATH,
AUDIO_INTERFACE,
"getSinkList");
if (reply.arguments().isEmpty()) {
qDebug() << __func__ << "empty sinklist";
return {};
}
const QDBusArgument& dbusArgs = reply.arguments().at(0).value();
dbusArgs.beginArray();
while (!dbusArgs.atEnd()) {
ClientDefaultDeviceInfo info;
dbusArgs >> info;
list.push_back(info);
}
dbusArgs.endArray();
return list;
}
int UKUIAudioSinkControl::getSinkDeviceCount()
{
return UKUIAudioSinkModel::getInstance().getDeviceCount();
}
int UKUIAudioSinkControl::getEnabledSinkDeviceCount()
{
return UKUIAudioSinkModel::getInstance().getEnabledDeviceCount();
}
void UKUIAudioSinkControl::releaseData()
{
qDebug() << "UKUIAudioSinkControl::releaseData" << "enter";
m_sinkVolumeValue = -1;
m_sinkMuteStatus = false;
m_sinkVolumeStatusIcon = "";
m_sinkVolumeBoostStatus = false;
m_sinkVolumeBoostValue = -1;
m_isExitMultiAudioDevice = false;
UKUIAudioSinkModel::getInstance().releaseModel();
qDebug() << "UKUIAudioSinkControl::releaseData" << "leave";
}
void UKUIAudioSinkControl::releaseSlots()
{
qDebug() << "UKUIAudioSinkControl::releaseSlots" << "enter";
disconnect(&DBusClient::getInstance(), SIGNAL(volumeChangedSignal(int, int, const QDBusVariant&)), this, SLOT(volumeChangedSlots(int, int, const QDBusVariant&)));
disconnect(&DBusClient::getInstance(), SIGNAL(muteChangedSignal(int, int, bool)), this, SLOT(muteChangedSlots(int, int, bool)));
disconnect(&DBusClient::getInstance(), SIGNAL(deviceChangedSignal(int, const QString&, const QString&)), this, SLOT(deviceChangedSlots(int, const QString&, const QString&)));
disconnect(&DBusClient::getInstance(), SIGNAL(deviceAdjustSignal(int)), this, SLOT(deviceAdjustSlots(int)));
disconnect(&DBusClient::getInstance(), SIGNAL(addStreamSignal(int, const QString&, const QString&)), this, SLOT(addStreamSlots(int, const QString&, const QString&)));
disconnect(&DBusClient::getInstance(), SIGNAL(removeStreamSignal(int)), this, SLOT(removeStreamSlots(int)));
qDebug() << "UKUIAudioSinkControl::releaseSlots" << "leave";
}
UKUIAudioSinkControl::~UKUIAudioSinkControl()
{
qDebug() << __func__ << "enter";
releaseSlots();
releaseData();
if (m_debounceTimer) {
m_debounceTimer->deleteLater();
m_debounceTimer = nullptr;
}
}
ukui-volume-control/ukui-shortcut-audio/src/control/ukui-audio-sink-control.h 0000664 0001750 0001750 00000020260 15171074712 026506 0 ustar feng feng /*
* Copyright (C) 2024, KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
* Authors: zhouyong
*
*/
#ifndef UKUIAUDIOSINKCONTROL_H
#define UKUIAUDIOSINKCONTROL_H
#include
#include
#include
#include "../extra/DBusClient.h"
#include "../extra/BaseType.h"
class UKUIAudioSinkControl : public QObject
{
Q_OBJECT
Q_PROPERTY(int sinkVolumeValue READ sinkVolumeValue WRITE setSinkVolumeValue NOTIFY sinkVolumeValueChanged)
Q_PROPERTY(int sinkMuteStatus READ sinkMuteStatus WRITE setSinkMuteStatus NOTIFY sinkMuteStatusChanged)
Q_PROPERTY(QString sinkVolumeStatusIcon READ sinkVolumeStatusIcon WRITE setSinkVolumeStatusIcon NOTIFY sinkVolumeStatusIconChanged)
Q_PROPERTY(bool sinkVolumeBoostStatus READ sinkVolumeBoostStatus WRITE setSinkVolumeBoostStatus NOTIFY sinkVolumeBoostStatusChanged)
Q_PROPERTY(int sinkVolumeBoostValue READ sinkVolumeBoostValue WRITE setSinkVolumeBoostValue NOTIFY sinkVolumeBoostValueChanged)
public:
static UKUIAudioSinkControl& getInstance();
bool initData();
bool initSlots();
bool initView();
int sinkVolumeValue() const { return m_sinkVolumeValue;}
void setSinkVolumeValue(int sinkVolumeValue) {
qDebug() << __func__ << "sinkVolumeValue:" << sinkVolumeValue << "m_sinkVolumeValue:" << m_sinkVolumeValue;
//start no sink device
if (getEnabledSinkDeviceCount() <= 0) {
sinkVolumeValue = 0;
}
//end
m_sinkVolumeValue = sinkVolumeValue;
emit sinkVolumeValueChanged(m_sinkVolumeValue);
QString sinkVolumeStatusIcon;
if (sinkMuteStatus() || (sinkVolumeValue == 0)) {
sinkVolumeStatusIcon = "audio-volume-muted-symbolic";
} else if (sinkVolumeValue > 66) {
sinkVolumeStatusIcon = "audio-volume-high-symbolic";
} else if (sinkVolumeValue > 33) {
sinkVolumeStatusIcon = "audio-volume-medium-symbolic";
} else {
sinkVolumeStatusIcon = "audio-volume-low-symbolic";
}
setSinkVolumeStatusIcon(sinkVolumeStatusIcon);
}
int sinkMuteStatus() const { return m_sinkMuteStatus;}
void setSinkMuteStatus(bool sinkMuteStatus) {
qDebug() << __func__ << "sinkMuteStatus:" << sinkMuteStatus << "m_sinkMuteStatus:" << m_sinkMuteStatus;
// if (sinkMuteStatus != m_sinkMuteStatus) {
m_sinkMuteStatus = sinkMuteStatus;
emit sinkMuteStatusChanged(m_sinkMuteStatus);
QString sinkVolumeStatusIcon;
if (sinkMuteStatus || (sinkVolumeValue() == 0)) {
sinkVolumeStatusIcon = "audio-volume-muted-symbolic";
} else if (sinkVolumeValue() > 66) {
sinkVolumeStatusIcon = "audio-volume-high-symbolic";
} else if (sinkVolumeValue() > 33) {
sinkVolumeStatusIcon = "audio-volume-medium-symbolic";
} else {
sinkVolumeStatusIcon = "audio-volume-low-symbolic";
}
setSinkVolumeStatusIcon(sinkVolumeStatusIcon);
// }
}
QString sinkVolumeStatusIcon() const { return m_sinkVolumeStatusIcon;}
void setSinkVolumeStatusIcon(QString sinkVolumeStatusIcon) {
qDebug() << __func__ << "sinkVolumeStatusIcon:" << sinkVolumeStatusIcon << "m_sinkVolumeStatusIcon:" << m_sinkVolumeStatusIcon;
// if (sinkVolumeStatusIcon != m_sinkVolumeStatusIcon) {
m_sinkVolumeStatusIcon = sinkVolumeStatusIcon;
emit sinkVolumeStatusIconChanged(m_sinkVolumeStatusIcon);
// }
}
bool sinkVolumeBoostStatus() const {return m_sinkVolumeBoostStatus;}
void setSinkVolumeBoostStatus(bool sinkVolumeBoostStatus) {
qDebug() << __func__ << "sinkVolumeBoostStatus:" << sinkVolumeBoostStatus << "m_sinkVolumeBoostStatus:" << m_sinkVolumeBoostStatus;
// if (sinkVolumeBoostStatus != m_sinkVolumeBoostStatus) {
m_sinkVolumeBoostStatus = sinkVolumeBoostStatus;
emit sinkVolumeBoostStatusChanged(m_sinkVolumeBoostStatus);
// }
}
int sinkVolumeBoostValue() const { return m_sinkVolumeBoostValue;}
void setSinkVolumeBoostValue(int sinkVolumeBoostValue) {
qDebug() << __func__ << "sinkVolumeBoostValue:" << sinkVolumeBoostValue << "m_sinkVolumeBoostValue:" << m_sinkVolumeBoostValue;
// if (sinkVolumeBoostValue != m_sinkVolumeBoostValue) {
m_sinkVolumeBoostValue = sinkVolumeBoostValue;
emit sinkVolumeBoostValueChanged(m_sinkVolumeBoostValue);
// }
}
signals:
void sinkVolumeValueChanged(int sinkVolumeValue);
void sinkMuteStatusChanged(bool sinkMuteStatus);
void sinkVolumeStatusIconChanged(QString sinkVolumeStatusIcon);
void sinkVolumeBoostStatusChanged(bool sinkVolumeBoostStatus);
void sinkVolumeBoostValueChanged(int sinkVolumeBoostValue);
signals:
void sinkDeviceChanged(QString, QString);
void sinkDeviceAdjust();
private Q_SLOTS:
void volumeChangedSlots(int, int, const QDBusVariant&);
void muteChangedSlots(int, int, bool);
void deviceChangedSlots(int, const QString&, const QString&);
void deviceAdjustSlots(int);
void addStreamSlots(int, const QString&, const QString&);
void removeStreamSlots(int);
void settingsChangedSlots(const QString&, const QDBusVariant&);
void streamVolumeChangedSlots(QString, int, bool);
void debounceTimerSlots();
public:
bool getSinkVolume(int, QVariant& retValue);
Q_INVOKABLE void updateSinkVolume(QVariant retValue);
bool setSinkVolume(int, int);
bool getSinkMute(int, QVariant& retValue);
Q_INVOKABLE void updateSinkMute(QVariant retValue);
bool setSinkMute(int, bool);
bool getSinkAvailablePortList(QVariant& retValue);
Q_INVOKABLE void updateSinkAvailablePortList(QVariant retValue);
bool getSinkInputList(QVariant& retValue);
Q_INVOKABLE void updateSinkInputList(QVariant retValue);
Q_INVOKABLE void updateSinkInputVolume(QVariant retValue);
bool setSinkInputVolume(int, int);
bool sendSinkInputVolumeChanged(const QString&, int, bool);
bool getSinkDefaultDevice(int, QVariant& retValue);
Q_INVOKABLE void updateSinkDefaultDevice(QVariant retValue);
Q_INVOKABLE void updateSinkDefaultDevice(const QString&, const QString&);
bool setSinkDefaultDevice(int, const QString&, const QString&);
bool getSinkVolumeBoostStatus(QVariant& retValue);
Q_INVOKABLE void updateSinkVolumeBoostStatus(QVariant retValue);
bool getSinkVolumeBoostValue(QVariant& retValue);
Q_INVOKABLE void updateSinkVolumeBoostValue(QVariant retValue);
bool isExitMultiAudioDevice();
bool getSinkMultiAudioCombineStatus() const;
QList getSinkList() const;
Q_INVOKABLE int getSinkDeviceCount();
Q_INVOKABLE int getEnabledSinkDeviceCount();
Q_INVOKABLE void releaseData();
Q_INVOKABLE void releaseSlots();
private:
UKUIAudioSinkControl() = default;
UKUIAudioSinkControl(const UKUIAudioSinkControl&) = delete;
UKUIAudioSinkControl(UKUIAudioSinkControl&&) = delete;
UKUIAudioSinkControl operator=(const UKUIAudioSinkControl&) = delete;
UKUIAudioSinkControl operator=(UKUIAudioSinkControl&&) = delete;
~UKUIAudioSinkControl();
private:
int m_sinkVolumeValue = -1;
bool m_sinkMuteStatus = false;
QString m_sinkVolumeStatusIcon = "";
bool m_sinkVolumeBoostStatus = false;
int m_sinkVolumeBoostValue = -1;
bool m_isExitMultiAudioDevice = false;
ClientDefaultDeviceInfo m_SinkMutiAudioDeviceInfo;
QTimer* m_debounceTimer = nullptr;
QString m_sinkInputName = "";
int m_sinkInputValue = 0;
bool m_sinkInputMuteStatus = false;
};
#endif // UKUIAUDIOSINKCONTROL_H
ukui-volume-control/ukui-shortcut-audio/src/control/ukui-audio-control.h 0000664 0001750 0001750 00000004217 15171074712 025550 0 ustar feng feng /*
* Copyright (C) 2024, KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
* Authors: zhouyong
*
*/
#ifndef UKUIAUDIOCONTROL_H
#define UKUIAUDIOCONTROL_H
#include
#include "../extra/DBusClient.h"
#include
#include
#include
class UKUIAudioControl : public QObject
{
Q_OBJECT
public:
static UKUIAudioControl& getInstance();
bool initData();
bool initSlots();
bool initDbusConnect();
bool jumpControlPanelAudio();
public:
Q_INVOKABLE void initMainThreadEvent();
Q_INVOKABLE void startTask(const int taskID, QVariant var1 = QVariant()
, QVariant var2 = QVariant(), QVariant var3 = QVariant());
Q_INVOKABLE void setLoadedStatus() {
m_isLoaded = true;
qDebug() << "getLoadStatus m_isLoaded:" << m_isLoaded;
}
Q_INVOKABLE bool getLoadStatus() {
qDebug() << "getLoadStatus m_isLoaded:" << m_isLoaded;
return m_isLoaded;
}
private Q_SLOTS:
signals:
void taskCompleted(int taskID, QVariant var1 = QVariant());
void taskError(int taskID);
public:
Q_INVOKABLE void releaseData();
Q_INVOKABLE void releaseSlots();
private:
UKUIAudioControl() = default;
UKUIAudioControl(const UKUIAudioControl&) = delete;
UKUIAudioControl(UKUIAudioControl&&) = delete;
UKUIAudioControl operator=(const UKUIAudioControl&) = delete;
UKUIAudioControl operator=(UKUIAudioControl&&) = delete;
~UKUIAudioControl();
private:
QMutex m_taskMutex;
bool m_isLoaded = false;
};
#endif // UKUIAUDIOCONTROL_H
ukui-volume-control/ukui-shortcut-audio/src/control/ukui-audio-source-control.h 0000664 0001750 0001750 00000006112 15171074712 027042 0 ustar feng feng /*
* Copyright (C) 2024, KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
* Authors: zhouyong
*
*/
#ifndef UKUIAUDIOSOURCECONTROL_H
#define UKUIAUDIOSOURCECONTROL_H
#include
#include
#include "../extra/DBusClient.h"
class UKUIAudioSourceControl : public QObject
{
Q_OBJECT
Q_PROPERTY(int sourceVolumeValue READ sourceVolumeValue WRITE setSourceVolumeValue NOTIFY sourceVolumeValueChanged)
public:
static UKUIAudioSourceControl& getInstance();
bool initData();
bool initSlots();
int sourceVolumeValue() const { return m_sourceVolumeValue;}
void setSourceVolumeValue(int sourceVolumeValue) {
qDebug() << __func__ << "sourceVolumeValue:" << sourceVolumeValue << "m_sourceVolumeValue:" << m_sourceVolumeValue;
if (sourceVolumeValue != m_sourceVolumeValue) {
m_sourceVolumeValue = sourceVolumeValue;
emit sourceVolumeValueChanged(m_sourceVolumeValue);
}
}
signals:
void sourceVolumeValueChanged(int sourceVolumeValue);
signals:
void sourceDeviceChanged(QString, QString);
void sourceDeviceAdjust();
private Q_SLOTS:
void volumeChangedSlots(int, int, const QDBusVariant&);
void deviceChangedSlots(int, const QString&, const QString&);
void deviceAdjustSlots(int);
public:
bool getSourceVolume(int index, QVariant& retValue);
Q_INVOKABLE void updateSourceVolume(QVariant retValue);
bool setSourceVolume(int index, int);
bool getSourceAvailablePortList(QVariant& retValue);
Q_INVOKABLE void updateSourceAvailablePortList(QVariant retValue);
bool getSourceOutputList(QVariant& retValue);
Q_INVOKABLE void updateSourceInputList(QVariant retValue);
bool getSourceDefaultDevice(int index, QVariant& retValue);
Q_INVOKABLE void updateSourceDefaultDevice(QVariant retValue);
Q_INVOKABLE void updateSourceDefaultDevice(const QString&, const QString&);
bool setSourceDefaultDevice(int index, const QString&, const QString&);
Q_INVOKABLE void releaseData();
Q_INVOKABLE void releaseSlots();
private:
UKUIAudioSourceControl() = default;
UKUIAudioSourceControl(const UKUIAudioSourceControl&) = delete;
UKUIAudioSourceControl(UKUIAudioSourceControl&&) = delete;
UKUIAudioSourceControl operator=(const UKUIAudioSourceControl&) = delete;
UKUIAudioSourceControl operator=(UKUIAudioSourceControl&&) = delete;
~UKUIAudioSourceControl();
private:
int m_sourceVolumeValue = -1;
};
#endif // UKUIAUDIOSOURCECONTROL_H
ukui-volume-control/ukui-shortcut-audio/src/control/ukui-audio-control.cpp 0000664 0001750 0001750 00000017534 15171074712 026111 0 ustar feng feng /*
* Copyright (C) 2024, KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
* Authors: zhouyong
*
*/
#include "ukui-audio-control.h"
#include
#include
#include
#include
#include "common.h"
#include "ukui-audio-sink-control.h"
#include "ukui-audio-source-control.h"
#include "ukui-audio-sink-model.h"
UKUIAudioControl& UKUIAudioControl::getInstance()
{
static UKUIAudioControl instance;
return instance;
}
bool UKUIAudioControl::initData()
{
bool ret = true;
return ret;
}
bool UKUIAudioControl::initSlots()
{
bool ret = true;
return ret;
}
bool UKUIAudioControl::initDbusConnect()
{
bool ret = true;
ret = DBusClient::getInstance().initDbusConnect();
return ret;
}
bool UKUIAudioControl::jumpControlPanelAudio()
{
qDebug() << __func__ << "enter";
int ret = true;
QProcess* process = new QProcess();
connect(process, QOverload::of(&QProcess::finished),
[process](int, QProcess::ExitStatus) {
if (process) {
process->deleteLater();
}
});
process->start("ukui-control-center", {"-m", "Audio"});
ret = process->waitForStarted();
if (!ret) {
if (process) {
process->deleteLater();
}
}
qDebug() << __func__ << "leave ret" << ret;
return ret;
}
void UKUIAudioControl::initMainThreadEvent()
{
QThread* mainThread = QCoreApplication::instance()->thread();
this->moveToThread(mainThread);
UKUIAudioSinkControl::getInstance().moveToThread(mainThread);
UKUIAudioSourceControl::getInstance().moveToThread(mainThread);
UKUIAudioSinkModel::getInstance().moveToThread(mainThread);
this->initSlots();
this->initDbusConnect();
UKUIAudioSinkControl::getInstance().initSlots();
UKUIAudioSourceControl::getInstance().initSlots();
UKUIAudioSinkControl::getInstance().initView();
}
void UKUIAudioControl::startTask(int taskID, QVariant var1, QVariant var2, QVariant var3)
{
qDebug() << __func__ << "enter taskID:" << taskID << "var1:" << var1 << "var2" << var2;
QMutex& taskMutex = m_taskMutex;
QFuture future = QtConcurrent::run([taskID,var1,var2,var3,&taskMutex,this]() {
qDebug() << "UKUIAudioControl::startTask run taskID:" << taskID;
QMetaEnum metaEnum = QMetaEnum::fromType();
if (metaEnum.isValid()) {
const char* enumName = metaEnum.valueToKey(taskID);
qDebug() << "UKUIAudioControl::startTask run taskID:" << taskID << "enumName:" << (enumName ? enumName : "unvalid");
}
bool ret = true;
if (taskMutex.tryLock(3000)) {
QVariant retValue;
switch (taskID) {
case Common::TaskID_Init: {
initData();
UKUIAudioSinkControl::getInstance().initData();
UKUIAudioSourceControl::getInstance().initData();
}
break;
case Common::TaskID_GetSinkVolume: {
ret = UKUIAudioSinkControl::getInstance().getSinkVolume(var1.toInt(), retValue);
}
break;
case Common::TaskID_SetSinkVolume: {
ret = UKUIAudioSinkControl::getInstance().setSinkVolume(var1.toInt(), var2.toInt());
}
break;
case Common::TaskID_GetSinkMute: {
ret = UKUIAudioSinkControl::getInstance().getSinkMute(var1.toInt(), retValue);
}
break;
case Common::TaskID_SetSinkMute: {
ret = UKUIAudioSinkControl::getInstance().setSinkMute(var1.toInt(), var2.toBool());
}
break;
case Common::TaskID_SetSinkInputVolume: {
ret = UKUIAudioSinkControl::getInstance().setSinkInputVolume(var1.toInt(), var2.toInt());
}
break;
case Common::TaskID_GetSourceVolume: {
ret = UKUIAudioSourceControl::getInstance().getSourceVolume(var1.toInt(), retValue);
}
break;
case Common::TaskID_SetSourceVolume: {
ret = UKUIAudioSourceControl::getInstance().setSourceVolume(var1.toInt(), var2.toInt());
}
break;
case Common::TaskID_GetSinkAvailablePortList: {
ret = UKUIAudioSinkControl::getInstance().getSinkAvailablePortList(retValue);
}
break;
case Common::TaskID_GetSourceAvailablePortList: {
ret = UKUIAudioSourceControl::getInstance().getSourceAvailablePortList(retValue);
}
break;
case Common::TaskID_GetSinkInputList: {
ret = UKUIAudioSinkControl::getInstance().getSinkInputList(retValue);
}
break;
case Common::TaskID_GetSourceInputList: {
ret = UKUIAudioSourceControl::getInstance().getSourceOutputList(retValue);
}
break;
case Common::TaskID_GetSinkDefaultDevice: {
ret = UKUIAudioSinkControl::getInstance().getSinkDefaultDevice(var1.toInt(), retValue);
}
break;
case Common::TaskID_SetSinkDefaultDevice: {
ret = UKUIAudioSinkControl::getInstance().setSinkDefaultDevice(var1.toInt(), var2.toString(), var3.toString());
}
break;
case Common::TaskID_GetSourceDefaultDevice: {
}
break;
case Common::TaskID_SetSourceDefaultDevice: {
}
break;
case Common::TaskID_JumpControlPanelAudio: {
jumpControlPanelAudio();
}
break;
case Common::TaskID_GetSinkVolumeBoostStatus: {
ret = UKUIAudioSinkControl::getInstance().getSinkVolumeBoostStatus(retValue);
}
break;
case Common::TaskID_GetSinkVolumeBoostValue: {
ret = UKUIAudioSinkControl::getInstance().getSinkVolumeBoostValue(retValue);
}
break;
case Common::TaskID_SendSinkInputVolumeChanged: {
ret = UKUIAudioSinkControl::getInstance().sendSinkInputVolumeChanged(var1.toString(), var2.toInt(), var3.toBool());
}
break;
default: {
}
break;
}
if (ret) {
emit taskCompleted(taskID, retValue);
} else {
emit taskError(taskID);
}
taskMutex.unlock();
} else {
qDebug() << "UKUIAudioControl::startTask tryLock timeout give up taskID:" << taskID;
ret = false;
emit taskError(taskID);
}
});
}
void UKUIAudioControl::releaseData()
{
qDebug() << __func__ << "enter";
UKUIAudioSinkControl::getInstance().releaseData();
UKUIAudioSourceControl::getInstance().releaseData();
qDebug() << __func__ << "leave";
}
void UKUIAudioControl::releaseSlots()
{
qDebug() << __func__ << "enter";
UKUIAudioSinkControl::getInstance().releaseSlots();
UKUIAudioSourceControl::getInstance().releaseSlots();
qDebug() << __func__ << "leave";
}
UKUIAudioControl::~UKUIAudioControl()
{
qDebug() << __func__ << "enter";
releaseSlots();
releaseData();
}
ukui-volume-control/ukui-shortcut-audio/src/common/ 0000775 0001750 0001750 00000000000 15171074712 021451 5 ustar feng feng ukui-volume-control/ukui-shortcut-audio/src/common/common.cpp 0000664 0001750 0001750 00000002066 15171074677 023463 0 ustar feng feng /*
* Copyright (C) 2024, KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
* Authors: zhouyong
*
*/
#include "common.h"
#include
#include
Common& Common::getInstance()
{
static Common instance;
return instance;
}
QVariant Common::getThemePropertyByName(QString name)
{
qDebug() << __func__ << name << qApp->property(name.toStdString().c_str());
return qApp->property(name.toStdString().c_str());
}
ukui-volume-control/ukui-shortcut-audio/src/common/common.h 0000664 0001750 0001750 00000003754 15171074712 023123 0 ustar feng feng /*
* Copyright (C) 2024, KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
* Authors: zhouyong
*
*/
#ifndef COMMON_H
#define COMMON_H
#include
#include
class Common : public QObject
{
Q_OBJECT
public:
static Common& getInstance();
enum TaskID {
TaskID_Init = 0,
TaskID_GetSinkVolume,
TaskID_SetSinkVolume,
TaskID_GetSinkMute,
TaskID_SetSinkMute,
TaskID_SetSinkInputVolume,
TaskID_GetSourceVolume,
TaskID_SetSourceVolume,
TaskID_SetSourceOutputVolume,
TaskID_GetSinkAvailablePortList,
TaskID_GetSourceAvailablePortList,
TaskID_GetSinkInputList,
TaskID_GetSourceInputList,
TaskID_GetSinkDefaultDevice,
TaskID_SetSinkDefaultDevice,
TaskID_GetSourceDefaultDevice,
TaskID_SetSourceDefaultDevice,
TaskID_JumpControlPanelAudio,
TaskID_GetSinkVolumeBoostStatus,
TaskID_GetSinkVolumeBoostValue,
TaskID_SendSinkInputVolumeChanged,
TaskID_End = 999
};
Q_ENUM(TaskID)
public:
Q_INVOKABLE QVariant getThemePropertyByName(QString);
private:
Common() = default;
Common(const Common&) = delete;
Common(Common&&) = delete;
Common operator=(const Common&) = delete;
Common operator=(Common&&) = delete;
~Common() = default;
private:
};
#endif // COMMON_H
ukui-volume-control/ukui-shortcut-audio/src/ukui-audio-main.h 0000664 0001750 0001750 00000002017 15171074677 023342 0 ustar feng feng /*
* Copyright (C) 2024, KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
* Authors: zhouyong
*
*/
#ifndef UKUIAUDIOMAIN_H
#define UKUIAUDIOMAIN_H
#include
class UKUIAudioMain : public QQmlExtensionPlugin
{
Q_OBJECT
Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid)
public:
void registerTypes(const char *uri) override;
};
#endif // UKUIAUDIOMAIN_H
ukui-volume-control/ukui-shortcut-audio/src/extra/ 0000775 0001750 0001750 00000000000 15171074712 021304 5 ustar feng feng ukui-volume-control/ukui-shortcut-audio/src/extra/DBusClient.cpp 0000664 0001750 0001750 00000012174 15171074712 024011 0 ustar feng feng /* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*-
* -*- coding: utf-8 -*-
*
* Copyright (C) 2025 KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#include "DBusClient.h"
#include
//#include "ClientMethod.h"
DBusClient& DBusClient::getInstance()
{
static DBusClient instance;
return instance;
}
bool DBusClient::initDbusConnect()
{
bool ret = true;
if(!QDBusConnection::sessionBus().connect(AUDIO_OBJECT_SERVICE, AUDIO_OBJECT_PATH, AUDIO_INTERFACE,
"volumeChanged",
this, SLOT(volumeChangedSlots(int, int, const QDBusVariant&)))) {
qDebug() << "Audio framework interface error, connect " << "volumeChanged" << "failed!";
qDebug() << QDBusConnection::sessionBus().lastError().message();
ret = false;
}
if(!QDBusConnection::sessionBus().connect(AUDIO_OBJECT_SERVICE, AUDIO_OBJECT_PATH, AUDIO_INTERFACE,
"muteChanged",
this, SLOT(muteChangedSlots(int, int, bool)))) {
qDebug() << "Audio framework interface error, connect " << "muteChanged" << "failed!";
qDebug() << QDBusConnection::sessionBus().lastError().message();
ret = false;
}
if(!QDBusConnection::sessionBus().connect(AUDIO_OBJECT_SERVICE, AUDIO_OBJECT_PATH, AUDIO_INTERFACE,
"deviceChanged",
this, SLOT(deviceChangedSlots(int, const QString&, const QString&)))) {
qDebug() << "Audio framework interface error, connect " << "deviceChanged" << "failed!";
qDebug() << QDBusConnection::sessionBus().lastError().message();
ret = false;
}
if(!QDBusConnection::sessionBus().connect(AUDIO_OBJECT_SERVICE, AUDIO_OBJECT_PATH, AUDIO_INTERFACE,
"deviceAdjust",
this, SLOT(deviceAdjustSlots(int)))) {
qDebug() << "Audio framework interface error, connect " << "deviceChanged" << "failed!";
qDebug() << QDBusConnection::sessionBus().lastError().message();
ret = false;
}
if(!QDBusConnection::sessionBus().connect(AUDIO_OBJECT_SERVICE, AUDIO_OBJECT_PATH, SETTINGS_INTERFACE,
"changed",
this, SLOT(settingsChangedSlots(const QString&, const QDBusVariant&)))) {
qDebug() << "Audio framework interface error, connect " << "changed" << "failed!" ;
qDebug() << QDBusConnection::sessionBus().lastError().message();
ret = false;
}
if(!QDBusConnection::sessionBus().connect(AUDIO_OBJECT_SERVICE, AUDIO_OBJECT_PATH, AUDIO_INTERFACE,
"addStream",
this, SLOT(addStreamSlots(int, int, const QString&, const QString&)))) {
qDebug() << "Audio framework interface error, connect " << "addStream" << "failed!" ;
qDebug() << QDBusConnection::sessionBus().lastError().message();
ret = false;
}
if(!QDBusConnection::sessionBus().connect(AUDIO_OBJECT_SERVICE, AUDIO_OBJECT_PATH, AUDIO_INTERFACE,
"removeStream",
this, SLOT(removeStreamSlots(int)))) {
qDebug() << "Audio framework interface error, connect " << "removeStream" << "failed!" ;
qDebug() << QDBusConnection::sessionBus().lastError().message();
ret = false;
}
return ret;
}
void DBusClient::volumeChangedSlots(int type, int idx, const QDBusVariant& v)
{
Q_EMIT volumeChangedSignal(type, idx, v);
}
void DBusClient::muteChangedSlots(int type, int index, bool mute)
{
Q_EMIT muteChangedSignal(type, index, mute);
}
void DBusClient::deviceChangedSlots(int type, const QString& portName, const QString& cardName)
{
Q_EMIT deviceChangedSignal(type, portName, cardName);
}
void DBusClient::deviceAdjustSlots(int type)
{
Q_EMIT deviceAdjustSignal(type);
}
void DBusClient::settingsChangedSlots(const QString& key, const QDBusVariant& v)
{
qDebug() << "DBusClient::settingsChangedSlots, key:" << key << " value: " << v.variant();
Q_EMIT settingsChangedSignal(key, v);
}
void DBusClient::addStreamSlots(int idx, int value, const QString& iconName, const QString& descName)
{
Q_EMIT addStreamSignal(idx, value, iconName, descName);
}
void DBusClient::removeStreamSlots(int idx)
{
Q_EMIT removeStreamSignal(idx);
}
ukui-volume-control/ukui-shortcut-audio/src/extra/BaseType.h 0000664 0001750 0001750 00000002663 15171074712 023200 0 ustar feng feng /* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*-
* -*- coding: utf-8 -*-
*
* Copyright (C) 2025 KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#ifndef BASETYPE_H
#define BASETYPE_H
//#include
//#include
//#include
#include
//#include "simple_logger/Formatter.h"
enum class Module
{
Service = 0,
Tray,
ControlCenter
};
//
enum class BackendType {
PULSEAUDIO = 0,
PIPEWIRE,
ALSA,
JACK,
UNKNOWN
};
enum class VolumeType {
BASE_VOLUME = 0,
BALANCE_VOLUME
};
enum class NodeType {
INPUT = 0,
OUTPUT,
SINK_INPUT,
SOURCE_OUTPUT
};
enum class PaDataType {
CARD = 0,
SINK,
SOURCE,
SINK_INPUT,
SOURCE_OUTPUT,
MODULE
};
typedef struct NodeInfo
{
uint32_t index;
uint8_t channels;
}NodeInfo;
#endif // BASETYPE_H
ukui-volume-control/ukui-shortcut-audio/src/extra/DBusClient.h 0000664 0001750 0001750 00000020641 15171074712 023454 0 ustar feng feng /* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*-
* -*- coding: utf-8 -*-
*
* Copyright (C) 2025 KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#ifndef DBUSCLIENT_H
#define DBUSCLIENT_H
#include
#include
#include
#include
#include
#include
#include
#include "Util.h"
// 注册 ClientDeviceInfo 类型
typedef struct ClientDeviceInfo
{
QString cardName; // 声卡名称
QString cardDesc; // 声卡描述
QString portName; // 设备端口名称
QString portLabel; // 设备端口描述
uint32_t priority; // 端口优先级
uint32_t direction; // 端口方向 input or output
uint32_t available; // 端口可用状态
bool enabled = true; // 端口是否启用
int32_t type; // 端口的类型
friend const QDBusArgument& operator>>(const QDBusArgument& argument, ClientDeviceInfo& info) {
argument.beginStructure();
argument >> info.cardName;
argument >> info.cardDesc;
argument >> info.portName;
argument >> info.portLabel;
argument >> info.priority;
argument >> info.direction;
argument >> info.available;
argument >> info.enabled;
// argument >> info.type;
argument.endStructure();
return argument;
}
friend const QDBusArgument &operator<<(QDBusArgument& argument, const ClientDeviceInfo& info) {
argument.beginStructure();
argument << info.cardName;
argument << info.cardDesc;
argument << info.portName;
argument << info.portLabel;
argument << info.priority;
argument << info.direction;
argument << info.available;
argument << info.enabled;
// argument << info.type;
argument.endStructure();
return argument;
}
} ClientDeviceInfo;
Q_DECLARE_METATYPE(ClientDeviceInfo);
// 注册 ClientDefaultDeviceInfo 类型
typedef struct ClientDefaultDeviceInfo
{
quint32 idx; // 默认设备的索引
QString name; // 默认设备的名称(sink/source 名称)
QString cardName; // 默认设备所在的声卡名称
QString activePortName; // 默认设备的活跃端口名称,可能为空
QString activePortDesc; // 默认设备的活跃端口描述
friend const QDBusArgument& operator>>(const QDBusArgument& argument, ClientDefaultDeviceInfo& info) {
argument.beginStructure();
argument >> info.idx;
argument >> info.name;
argument >> info.cardName;
argument >> info.activePortName;
argument >> info.activePortDesc;
argument.endStructure();
return argument;
}
friend const QDBusArgument &operator<<(QDBusArgument& argument, const ClientDefaultDeviceInfo& info) {
argument.beginStructure();
argument << info.idx;
argument << info.name;
argument << info.cardName;
argument << info.activePortName;
argument << info.activePortDesc;
argument.endStructure();
return argument;
}
} ClientDefaultDeviceInfo;
Q_DECLARE_METATYPE(ClientDefaultDeviceInfo);
// 注册 StreamInfo 类型
typedef struct StreamInfo
{
QString name; // 流媒体名称
quint32 index; // 流媒体索引
uint32_t volume; // 流媒体音量
QString role; // 流媒体角色
QString iconName; // 流媒体图标名称
friend const QDBusArgument& operator>>(const QDBusArgument& argument, StreamInfo& info) {
argument.beginStructure();
argument >> info.name;
argument >> info.index;
argument >> info.volume;
argument >> info.role;
argument >> info.iconName;
argument.endStructure();
return argument;
}
friend const QDBusArgument &operator<<(QDBusArgument& argument, const StreamInfo& info) {
argument.beginStructure();
argument << info.name;
argument << info.index;
argument << info.volume;
argument << info.role;
argument << info.iconName;
argument.endStructure();
return argument;
}
} StreamInfo;
Q_DECLARE_METATYPE(StreamInfo);
// 注册 ClientSoundThemeInfo 类型
typedef struct ClientSoundThemeInfo
{
QString name; // 音效主题的名称
QString description; // 音效主题的描述
friend const QDBusArgument& operator>>(const QDBusArgument& argument, ClientSoundThemeInfo& info) {
argument.beginStructure();
argument >> info.name;
argument >> info.description;
argument.endStructure();
return argument;
}
friend const QDBusArgument &operator<<(QDBusArgument& argument, const ClientSoundThemeInfo& info) {
argument.beginStructure();
argument << info.name;
argument << info.description;
argument.endStructure();
return argument;
}
} ClientSoundThemeInfo;
Q_DECLARE_METATYPE(ClientSoundThemeInfo);
// 注册 ClientSoundEffectFileInfo 类型
typedef struct ClientSoundEffectFileInfo
{
QString name; // 音效主题的名称
QString description; // 音效主题的描述
friend const QDBusArgument& operator>>(const QDBusArgument& argument, ClientSoundEffectFileInfo& info) {
argument.beginStructure();
argument >> info.name;
argument >> info.description;
argument.endStructure();
return argument;
}
friend const QDBusArgument &operator<<(QDBusArgument& argument, const ClientSoundEffectFileInfo& info) {
argument.beginStructure();
argument << info.name;
argument << info.description;
argument.endStructure();
return argument;
}
} ClientSoundEffectFileInfo;
Q_DECLARE_METATYPE(ClientSoundEffectFileInfo);
class DBusClient : public QObject
{
Q_OBJECT
public:
static DBusClient& getInstance();
public:
bool initDbusConnect();
template
QDBusMessage dbusMethodCall(const QString&, const QString&, const QString&, const QString&, Args &&...);
template
QDBusPendingCall dbusMethodAsyncCall(const QString&, const QString&, const QString&, const QString&, Args &&...);
Q_SIGNALS:
void volumeChangedSignal(int, int, const QDBusVariant&);
void muteChangedSignal(int, int, bool);
void deviceChangedSignal(int, const QString&, const QString&);
void deviceAdjustSignal(int);
void settingsChangedSignal(const QString&, const QDBusVariant&);
void addStreamSignal(int, int, const QString&, const QString&);
void removeStreamSignal(int);
private Q_SLOTS:
void volumeChangedSlots(int, int, const QDBusVariant&);
void muteChangedSlots(int, int, bool);
void deviceChangedSlots(int, const QString&, const QString&);
void deviceAdjustSlots(int);
void settingsChangedSlots(const QString&, const QDBusVariant&);
void addStreamSlots(int, int, const QString&, const QString&);
void removeStreamSlots(int);
private:
DBusClient() = default;
DBusClient(const DBusClient&) = delete;
DBusClient(DBusClient&&) = delete;
DBusClient operator=(const DBusClient&) = delete;
DBusClient operator=(DBusClient&&) = delete;
~DBusClient() = default;
};
template
QDBusMessage DBusClient::dbusMethodCall(const QString& destination, const QString& path, const QString& interface, const QString& method, Args&&... args)
{
QDBusInterface mediaInterface(destination, path, interface);
return mediaInterface.call(method, std::forward(args)...);
}
template
QDBusPendingCall DBusClient::dbusMethodAsyncCall(const QString& destination, const QString& path, const QString& interface, const QString& method, Args&&... args)
{
QDBusInterface mediaInterface(destination, path, interface);
return mediaInterface.asyncCall(method, std::forward(args)...);
}
#endif // DBUSCLIENT_H
ukui-volume-control/ukui-shortcut-audio/src/ukui-audio-main.cpp 0000664 0001750 0001750 00000005036 15171074677 023701 0 ustar feng feng /*
* Copyright (C) 2024, KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
* Authors: zhouyong
*
*/
#include "ukui-audio-main.h"
#include
#include
#include "common/common.h"
#include "control/ukui-audio-control.h"
#include "control/ukui-audio-sink-control.h"
#include "control/ukui-audio-source-control.h"
#include "model/ukui-audio-sink-model.h"
#include "model/ukui-audio-source-model.h"
void UKUIAudioMain::registerTypes(const char *uri)
{
Q_ASSERT(QString(uri) == QLatin1String("org.ukui.shortcut.audio"));
qDebug() << __func__ << uri;
qmlRegisterSingletonType("org.ukui.audio.common", 1, 0, "Common", [] (QQmlEngine *qmlEngine, QJSEngine *jsEngine) -> QObject* {
Common* common = &Common::getInstance();
return common;
});
qmlRegisterSingletonType("org.ukui.audio.sinkcontrol", 1, 0, "UKUIAudioSinkControl", [] (QQmlEngine *qmlEngine, QJSEngine *jsEngine) -> QObject* {
UKUIAudioSinkControl* sinkControl = &UKUIAudioSinkControl::getInstance();
return sinkControl;
});
qmlRegisterSingletonType("org.ukui.audio.sourcecontrol", 1, 0, "UKUIAudioSourceControl", [] (QQmlEngine *qmlEngine, QJSEngine *jsEngine) -> QObject* {
UKUIAudioSourceControl* sourceControl = &UKUIAudioSourceControl::getInstance();
return sourceControl;
});
qmlRegisterSingletonType("org.ukui.audio.sinkmodel", 1, 0, "UKUIAudioSinkModel", [] (QQmlEngine *qmlEngine, QJSEngine *jsEngine) -> QObject* {
UKUIAudioSinkModel* sinkModel = &UKUIAudioSinkModel::getInstance();
return sinkModel;
});
qmlRegisterSingletonType("org.ukui.shortcut.audio", 1, 0, "UKUIAudioControl", [] (QQmlEngine *qmlEngine, QJSEngine *jsEngine) -> QObject* {
UKUIAudioControl* control = &UKUIAudioControl::getInstance();
return control;
});
}
ukui-volume-control/ukui-shortcut-audio/qml/ 0000775 0001750 0001750 00000000000 15171074712 020163 5 ustar feng feng ukui-volume-control/ukui-shortcut-audio/qml/qml.qrc 0000664 0001750 0001750 00000000630 15171074677 021474 0 ustar feng feng
main.qml
AudioArea.qml
AudioListArea.qml
VolumeDelegate.qml
DeviceDelegate.qml
HeaderDelegate.qml
EmptyDelegate.qml
SystemVolumeArea.qml
MoreAudioSettingArea.qml
ukui-volume-control/ukui-shortcut-audio/qml/VolumeDelegate.qml 0000664 0001750 0001750 00000005777 15171074712 023620 0 ustar feng feng /* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*-
* -*- coding: utf-8 -*-
*
* Copyright (C) 2025 KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
import org.ukui.quick.items 1.0 as UkuiItems
Item {
id: volumeDelegate
width: volumeDelegateWidth
height: volumeDelegateHeight
property real volumeDelegateWidth: 396
property real volumeDelegateHeight: 56
property real volumeDelegateTopMargin: 0
property alias volumeValue: volumeDelegateSlider.value
property alias volumeDelegateImgSource: volumeDelegateImg.source
signal valueChanged(real value)
ItemDelegate {
anchors.fill: parent
background: Item {
}
contentItem: Item {
anchors.fill: parent
UkuiItems.ThemeIcon {
id: volumeDelegateImg
width: 32
height: 32
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
anchors.leftMargin: 24
source: ""
visible: volumeDelegateImg.source === "" ? false : true
}
UkuiItems.TouchSlider {
// Slider {
id: volumeDelegateSlider
width: 268
height: 16
anchors.verticalCenter: parent.verticalCenter
anchors.left: volumeDelegateImg.right
anchors.leftMargin: 8
from: 0
to: 100
stepSize: 1
property var sliderType: "touchSlider"
onValueChanged: {
debounceTimer.restart()
}
Timer {
id: debounceTimer
interval: 200
onTriggered: {
console.log("VolumeDelegate.qml Slider debounceTimer:", volumeDelegateSlider.value)
volumeDelegate.valueChanged(volumeDelegateSlider.value)
}
}
}
Label {
width: 48
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
anchors.left: volumeDelegateSlider.right
anchors.verticalCenter: parent.verticalCenter
text: qsTr(volumeValue +"%")
}
}
}
}
ukui-volume-control/ukui-shortcut-audio/qml/SystemVolumeArea.qml 0000664 0001750 0001750 00000010302 15171074712 024137 0 ustar feng feng /* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*-
* -*- coding: utf-8 -*-
*
* Copyright (C) 2025 KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
import org.ukui.quick.items 1.0 as UkuiItems
import org.ukui.quick.platform 1.0 as Platform
Item {
id: systemVolume
width: systemVolumeWidth
height: systemVolumeHeight
property real systemVolumeWidth: 396
property real systemVolumeHeight: 56
property real systemVolumeTopMargin: 0
property bool systemVolumeMuteStatus: false
property bool isFirstSetVolume: true
property alias systemVolumeValue: systemVolumeSlider.value
property alias systemVolumeSliderEnabled: systemVolumeSlider.enabled
property alias systemVolumeSliderRange: systemVolumeSlider.to
property alias systemVolumeBtnSource: systemVolumeBtn.icon.source
property alias systemVolumeBtnEnabled: systemVolumeBtn.enabled
signal systemVolumeBtnClick()
signal valueChanged(real value)
UkuiItems.DtThemeButton {
id: systemVolumeBtn
width: 36
height: 36
Layout.preferredWidth: 36
Layout.preferredHeight: 36
Layout.alignment: Qt.AlignVCenter
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
anchors.leftMargin: 24
enabled: true
background.radius: width/2
property var kTransparent : Platform.GradientColor {
gradientDeg : 0
gradientStart : Qt.rgba(0/255, 0/255, 0/255, 0)
gradientEnd : Qt.rgba(0/255, 0/255, 0/255, 0)
gradientBackground : Qt.rgba(0/255, 0/255, 0/255, 0)
}
background.backgroundColor: containsPress ? Platform.GlobalTheme.kContainAlphaClick
: containsMouse ? Platform.GlobalTheme.kContainAlphaHover
: kTransparent
icon.source: "audio-volume-medium-symbolic"
icon.mode: UkuiItems.Icon.AutoHighlight
onClicked: {
systemVolume.systemVolumeBtnClick()
}
onEnabledChanged: {
console.log("systemVolume.qml DtThemeButton onEnabledChanged:", enabled)
systemVolumeBtn.icon.mode = (enabled ? UkuiItems.Icon.AutoHighlight : UkuiItems.Icon.Disabled)
}
}
UkuiItems.TouchSlider {
// Slider {
id: systemVolumeSlider
width: 268
height: 16
anchors.verticalCenter: parent.verticalCenter
anchors.left: systemVolumeBtn.right
anchors.leftMargin: 6
from: 0
to: 100
stepSize: 1
enabled: true
property var sliderType: "touchSlider"
onValueChanged: {
console.log("systemVolume.qml Slider onValueChanged:", systemVolumeSlider.value, isFirstSetVolume)
if (!isFirstSetVolume) {
debounceTimer.restart()
}
isFirstSetVolume = false
}
Timer {
id: debounceTimer
interval: 300
onTriggered: {
console.log("systemVolume.qml Slider debounceTimer:", systemVolumeSlider.value)
systemVolume.valueChanged(systemVolumeSlider.value)
}
}
}
Label {
width: 48
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
anchors.left: systemVolumeSlider.right
anchors.leftMargin: 5
anchors.verticalCenter: parent.verticalCenter
text: qsTr(systemVolumeValue +"%")
enabled: systemVolumeBtn.enabled
}
}
ukui-volume-control/ukui-shortcut-audio/qml/AudioListArea.qml 0000664 0001750 0001750 00000012225 15171074712 023366 0 ustar feng feng /* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*-
* -*- coding: utf-8 -*-
*
* Copyright (C) 2025 KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
import QtQuick 2.15
import QtQuick.Controls 2.15
import org.ukui.shortcut.audio 1.0
import org.ukui.audio.common 1.0
import org.ukui.audio.sinkcontrol 1.0
import org.ukui.audio.sinkmodel 1.0
Item {
id: audioList
width: audioListWidth
height: audioListHeight
property real audioListWidth: 396
property real audioListHeight: 305
ListView {
id: listView
anchors.fill: parent
model: UKUIAudioSinkModel
clip: true
ScrollBar.vertical: ScrollBar {
id: verticalScrollBar
policy: listView.contentHeight > listView.height ? ScrollBar.AlwaysOn : ScrollBar.AlwaysOff
}
delegate: Loader {
width: parent.width
property var modelData: model
sourceComponent: {
console.log("AudioListArea.qml Item type:",model.itemType ,model.title ,model.portName ,modelData.portIcon ,modelData.cardDesc ,modelData.isActivePort
,model.streamName ,model.streamIconName ,model.streamVolume ,model.streamIndex)
switch(model.itemType) {
case UKUIAudioSinkModel.HeaderOutput:
case UKUIAudioSinkModel.HeaderAppVolume:
return headerComponent
case UKUIAudioSinkModel.EmptyDeviceItem:
case UKUIAudioSinkModel.EmptyStreamItem:
return emptyDelegateComponent
case UKUIAudioSinkModel.DeviceItem:
return deviceComponent
case UKUIAudioSinkModel.StreamItem:
return appVolumeComponent
}
}
}
// 标题组件
Component {
id: headerComponent
HeaderDelegate {
headerDelegateTextStr: modelData.title
headerDelegateTopMargin: 4
headerDelegateBtnVisible: modelData.itemType === UKUIAudioSinkModel.HeaderAppVolume ? true : false
headerDelegateBtnEnabled: modelData.itemType === UKUIAudioSinkModel.HeaderAppVolume ? true : false
headerDelegateBtnSource: modelData.itemType === UKUIAudioSinkModel.HeaderAppVolume ? "application-system-symbolic" : ""
onHeaderDelegateBtnClick: {
console.log("AudioListArea.qml onHeaderDelegateBtnClick")
UKUIAudioControl.startTask(Common.TaskID_JumpControlPanelAudio)
}
}
}
// 设备项组件
Component {
id: deviceComponent
DeviceDelegate {
deviceDelegateBtnSource: modelData.portIcon
deviceDelegatePortDesTextStr: modelData.portLabel + qsTr(" ( ") + modelData.cardDesc + qsTr(" )")
deviceDelegateBtnHighLighted: modelData.isActivePort
deviceDelegatePortEnabled: modelData.portEnabled
MouseArea {
anchors.fill: parent
onClicked: {
console.log("AudioListArea.qml onClicked portName cardName portIcon:", modelData.portName, modelData.portIcon, modelData.cardName)
UKUIAudioControl.startTask(Common.TaskID_SetSinkDefaultDevice, -1, modelData.portName, modelData.cardName)
}
}
}
}
// 应用音量项组件
Component {
id: appVolumeComponent
VolumeDelegate {
volumeValue: modelData.streamVolume
volumeDelegateImgSource: "image://imageProvider/" + modelData.streamIconName
onValueChanged: {
console.log("AudioListArea.qml onValueChanged value:",value)
UKUIAudioControl.startTask(Common.TaskID_SetSinkInputVolume, modelData.streamIndex, value)
UKUIAudioControl.startTask(Common.TaskID_SendSinkInputVolumeChanged, modelData.streamIconName, value, false)
}
}
}
// 空项组件
Component {
id: emptyDelegateComponent
EmptyDelegate {
emptyDelegateTextStr: modelData.title
}
}
}
Component.onCompleted: {
console.log("AudioListArea.qml onCompleted")
UKUIAudioControl.startTask(Common.TaskID_GetSinkVolume, -1)
UKUIAudioControl.startTask(Common.TaskID_GetSinkMute, -1)
UKUIAudioControl.startTask(Common.TaskID_GetSinkVolumeBoostStatus)
}
}
ukui-volume-control/ukui-shortcut-audio/qml/MoreAudioSettingArea.qml 0000664 0001750 0001750 00000003770 15171074712 024720 0 ustar feng feng /* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*-
* -*- coding: utf-8 -*-
*
* Copyright (C) 2025 KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
import org.ukui.audio.common 1.0
Item {
id: moreAudioSetting
width: moreAudioSettingWidth
height: moreAudioSettingHeight
property real moreAudioSettingWidth: 396
property real moreAudioSettingHeight: 56
signal moreAudioSettingClick()
Rectangle {
id: moreAudioSettingRec
width: parent.width
height: parent.height
color: "#00000000"
Label {
id: moreAudioSettingText
height: 22
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
anchors.leftMargin: 24
text: qsTr("More sound settings")
color: Common.getThemePropertyByName("kfont-strong")
MouseArea {
anchors.fill: parent
hoverEnabled: true
onEntered: parent.color = Common.getThemePropertyByName("highlight-active")
onExited: parent.color = Common.getThemePropertyByName("kfont-strong")
onClicked: {
console.log("MoreAudioSettingArea.qml onClicked")
moreAudioSetting.moreAudioSettingClick()
}
}
}
}
}
ukui-volume-control/ukui-shortcut-audio/qml/main.qml 0000664 0001750 0001750 00000004323 15171074677 021636 0 ustar feng feng /*
* Copyright (C) 2024, KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
* Authors: zhouyong
*
*/
import QtQuick 2.15
import QtQuick.Layouts 1.15
import org.ukui.quick.widgets 1.0
import org.ukui.shortcut.audio 1.0
import org.ukui.audio.common 1.0
WidgetItem {
Layout.fillWidth: true
Layout.fillHeight: true
clip: true
Loader {
id: mainPage
anchors.fill: parent
onStatusChanged: {
if (status === Loader.Ready) {
console.log("main.qml Loader onStatusChanged loaded suc")
} else if (status === Loader.Error) {
console.log("main.qml Loader onStatusChanged error loading")
}
}
}
Component.onCompleted: {
console.log("main.qml onCompleted")
UKUIAudioControl.initMainThreadEvent()
UKUIAudioControl.startTask(Common.TaskID_Init)
}
Component.onDestruction: {
console.log("main.qml onDestruction")
UKUIAudioControl.releaseSlots();
UKUIAudioControl.releaseData();
}
Connections {
target: UKUIAudioControl
function onTaskCompleted(taskID, retValue) {
if (taskID === Common.TaskID_Init) {
console.log("main.qml onTaskCompleted TaskID_Init")
if (mainPage.status !== Loader.Ready) {
mainPage.source = "AudioArea.qml"
}
}
}
function onTaskError(taskID) {
if (taskID === Common.TaskID_Init) {
console.log("main.qml onTaskError TaskID_Init")
}
}
}
}
ukui-volume-control/ukui-shortcut-audio/qml/DeviceDelegate.qml 0000664 0001750 0001750 00000005634 15171074712 023540 0 ustar feng feng /* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*-
* -*- coding: utf-8 -*-
*
* Copyright (C) 2025 KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
import org.ukui.quick.items 1.0 as UkuiItems
Item {
id: deviceDelegate
width: deviceDelegateWidth
height: deviceDelegateHeight
anchors.top: parent.top
anchors.topMargin: deviceDelegateTopMargin
property real deviceDelegateWidth: 396
property real deviceDelegateHeight: deviceDelegate.visible ? 56 : 0
property real deviceDelegateTopMargin: 0
property string deviceDelegateBtnSource: "audio-speakers-symbolic"
property alias deviceDelegateBtnHighLighted: deviceDelegateBtn.isHighLight
property alias deviceDelegatePortDesTextStr: deviceDelegatePortDesText.text
property alias deviceDelegatePortEnabled: deviceDelegate.visible
ItemDelegate {
anchors.fill: parent
background: Item {
}
contentItem: Item {
anchors.fill: parent
UkuiItems.IconButton {
id: deviceDelegateBtn
width: 36
height: 36
Layout.preferredWidth: 36
Layout.preferredHeight: 36
Layout.alignment: Qt.AlignVCenter
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
anchors.leftMargin: 24
radius: width/2
iconSource: deviceDelegateBtnSource
isHighLight: false
}
Label {
id: deviceDelegatePortDesText
width: 306
anchors.left: deviceDelegateBtn.right
anchors.leftMargin: 12
anchors.verticalCenter: parent.verticalCenter
elide: Text.ElideRight
wrapMode: Text.NoWrap
text: qsTr("")
ToolTip {
text: deviceDelegatePortDesText.text
visible: hoverHandler.hovered && deviceDelegatePortDesText.truncated
delay: 500
property var maxWidth: 500
property var wrapMode: Text.WrapAnywhere
}
HoverHandler { id: hoverHandler}
}
}
}
}
ukui-volume-control/ukui-shortcut-audio/qml/EmptyDelegate.qml 0000664 0001750 0001750 00000003257 15171074712 023436 0 ustar feng feng /* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*-
* -*- coding: utf-8 -*-
*
* Copyright (C) 2025 KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
import org.ukui.audio.common 1.0
Item {
id: emptyDelegate
width: emptyDelegateWidth
height: emptyDelegateHeight
property real emptyDelegateWidth: 396
property real emptyDelegateHeight: 64
property alias emptyDelegateTextStr: emptyDelegateText.text
Label {
id: emptyDelegateText
width: 306
anchors.centerIn: parent
elide: Text.ElideRight
horizontalAlignment: Text.AlignHCenter
wrapMode: Text.NoWrap
color: Common.getThemePropertyByName("kfont-secondary")
text: qsTr("")
ToolTip {
text: emptyDelegateText.text
visible: hoverHandler.hovered && emptyDelegateText.truncated
delay: 500
property var maxWidth: 500
property var wrapMode: Text.WrapAnywhere
}
HoverHandler { id: hoverHandler}
}
}
ukui-volume-control/ukui-shortcut-audio/qml/AudioArea.qml 0000664 0001750 0001750 00000021116 15171074712 022531 0 ustar feng feng /*
* Copyright (C) 2024, KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
* Authors: zhouyong
*
*/
import QtQuick 2.15
import QtQuick.Controls 2.15
import org.ukui.shortcut.audio 1.0
import org.ukui.audio.common 1.0
import org.ukui.audio.sinkcontrol 1.0
import org.ukui.audio.sourcecontrol 1.0
Item {
id: qmlAudioAreaItem
anchors.fill: parent
anchors.top: parent.top
anchors.topMargin: 56
property bool qml_sinkVolumeBoostStatus: false
SystemVolumeArea {
id: systemVolume
anchors.top: parent.top
onSystemVolumeBtnClick: {
console.log("AudioArea.qml onSystemVolumeBtnClick systemVolumeMuteStatus:",systemVolumeMuteStatus)
UKUIAudioControl.startTask(Common.TaskID_SetSinkMute, -1
, !systemVolumeMuteStatus)
}
onValueChanged: {
console.log("AudioArea.qml onValueChanged value:",value)
if (systemVolumeMuteStatus) {
UKUIAudioControl.startTask(Common.TaskID_SetSinkMute, -1, false)
}
UKUIAudioControl.startTask(Common.TaskID_SetSinkVolume, -1, value)
}
}
Rectangle {
id: lineTop
width: parent.width
height: 1
anchors.top: systemVolume.bottom
color: Common.getThemePropertyByName("kline-normal")
}
AudioListArea {
id: audioList
anchors.top: lineTop.bottom
audioListHeight: (parent.height - systemVolume.height - lineTop.height - lineBottom.height - moreAudioSetting.height)
}
Rectangle {
id: lineBottom
width: parent.width
height: 1
anchors.bottom: moreAudioSetting.top
color: Common.getThemePropertyByName("kline-normal")
}
MoreAudioSettingArea {
id: moreAudioSetting
anchors.bottom: parent.bottom
onMoreAudioSettingClick: {
console.log("AudioArea.qml onMoreAudioSettingClick")
UKUIAudioControl.startTask(Common.TaskID_JumpControlPanelAudio)
}
}
Component.onCompleted: {
console.log("AudioArea.qml onCompleted")
UKUIAudioControl.startTask(Common.TaskID_GetSinkAvailablePortList)
UKUIAudioControl.startTask(Common.TaskID_GetSinkInputList)
}
Connections {
target: UKUIAudioSinkControl
function onSinkVolumeValueChanged(sinkVolumeValue) {
console.log("AudioArea.qml onSinkVolumeValueChanged sinkVolumeValue:",sinkVolumeValue,systemVolume.systemVolumeValue)
if (sinkVolumeValue !== systemVolume.systemVolumeValue) {
systemVolume.systemVolumeValue = sinkVolumeValue
}
}
function onSinkMuteStatusChanged(sinkMuteStatus) {
console.log("AudioArea.qml onSinkMuteStatusChanged sinkMuteStatus:",sinkMuteStatus)
systemVolume.systemVolumeMuteStatus = sinkMuteStatus
}
function onSinkVolumeStatusIconChanged(sinkVolumeStatusIcon) {
console.log("AudioArea.qml onSinkVolumeStatusIconChanged sinkVolumeStatusIcon:",sinkVolumeStatusIcon)
systemVolume.systemVolumeBtnSource = sinkVolumeStatusIcon
}
function onSinkVolumeBoostValueChanged(sinkVolumeBoostValue) {
console.log("AudioArea.qml onSinkVolumeBoostValueChanged sinkVolumeBoostValue:"
,qml_sinkVolumeBoostStatus,sinkVolumeBoostValue)
if (qml_sinkVolumeBoostStatus) {
systemVolume.systemVolumeSliderRange = sinkVolumeBoostValue
UKUIAudioControl.startTask(Common.TaskID_GetSinkVolume)
}
}
function onSinkVolumeBoostStatusChanged(sinkVolumeBoostStatus) {
console.log("AudioArea.qml onSinkVolumeBoostStatusChanged sinkVolumeBoostStatus:",sinkVolumeBoostStatus)
qml_sinkVolumeBoostStatus = sinkVolumeBoostStatus;
if (sinkVolumeBoostStatus) {
UKUIAudioControl.startTask(Common.TaskID_GetSinkVolumeBoostValue)
}
}
function onSinkDeviceChanged(portName, cardName) {
console.log("AudioArea.qml onSinkDeviceChanged:",portName,cardName)
UKUIAudioSinkControl.updateSinkDefaultDevice(portName, cardName)
UKUIAudioControl.startTask(Common.TaskID_GetSinkVolume)
}
function onSinkDeviceAdjust() {
console.log("AudioArea.qml onSinkDeviceAdjust")
UKUIAudioControl.startTask(Common.TaskID_GetSinkAvailablePortList)
}
}
Connections {
target: UKUIAudioControl
function onTaskCompleted(taskID, retValue) {
console.log("AudioArea.qml onTaskCompleted taskID:",taskID)
if (taskID === Common.TaskID_Init) {
} else if (taskID === Common.TaskID_GetSinkVolume) {
UKUIAudioSinkControl.updateSinkVolume(retValue)
} else if (taskID === Common.TaskID_SetSinkVolume) {
} else if (taskID === Common.TaskID_GetSinkMute) {
UKUIAudioSinkControl.updateSinkMute(retValue)
} else if (taskID === Common.TaskID_SetSinkMute) {
} else if (taskID === Common.TaskID_SetSinkInputVolume) {
} else if (taskID === Common.TaskID_GetSourceVolume) {
} else if (taskID === Common.TaskID_SetSourceVolume) {
} else if (taskID === Common.TaskID_GetSinkAvailablePortList) {
UKUIAudioSinkControl.updateSinkAvailablePortList(retValue)
UKUIAudioControl.startTask(Common.TaskID_GetSinkDefaultDevice)
if (UKUIAudioSinkControl.getEnabledSinkDeviceCount() > 0) {
systemVolume.systemVolumeBtnEnabled = true
systemVolume.systemVolumeSliderEnabled = true
} else {
systemVolume.systemVolumeBtnEnabled = false
systemVolume.systemVolumeSliderEnabled = false
}
} else if (taskID === Common.TaskID_GetSourceAvailablePortList) {
} else if (taskID === Common.TaskID_GetSinkInputList) {
UKUIAudioSinkControl.updateSinkInputList(retValue)
} else if (taskID === Common.TaskID_GetSourceInputList) {
} else if (taskID === Common.TaskID_GetSinkDefaultDevice) {
UKUIAudioSinkControl.updateSinkDefaultDevice(retValue)
} else if (taskID === Common.TaskID_SetSinkDefaultDevice) {
} else if (taskID === Common.TaskID_GetSourceDefaultDevice) {
} else if (taskID === Common.TaskID_SetSourceDefaultDevice) {
} else if (taskID === Common.TaskID_JumpControlPanelAudio) {
} else if (taskID === Common.TaskID_GetSinkVolumeBoostValue) {
UKUIAudioSinkControl.updateSinkVolumeBoostValue(retValue)
} else if (taskID === Common.TaskID_GetSinkVolumeBoostStatus) {
UKUIAudioSinkControl.updateSinkVolumeBoostStatus(retValue)
}
}
function onTaskError(taskID) {
console.log("AudioArea.qml onTaskError taskID:",taskID)
if (taskID === Common.TaskID_Init) {
} else if (taskID === Common.TaskID_GetSinkVolume) {
} else if (taskID === Common.TaskID_SetSinkVolume) {
} else if (taskID === Common.TaskID_GetSourceVolume) {
} else if (taskID === Common.TaskID_SetSourceVolume) {
} else if (taskID === Common.TaskID_GetSinkAvailablePortList) {
} else if (taskID === Common.TaskID_GetSourceAvailablePortList) {
} else if (taskID === Common.TaskID_GetSinkInputList) {
} else if (taskID === Common.TaskID_GetSourceInputList) {
} else if (taskID === Common.TaskID_GetSinkDefaultDevice) {
} else if (taskID === Common.TaskID_SetSinkDefaultDevice) {
} else if (taskID === Common.TaskID_GetSourceDefaultDevice) {
} else if (taskID === Common.TaskID_SetSourceDefaultDevice) {
} else if (taskID === Common.TaskID_JumpControlPanelAudio) {
}
}
}
}
ukui-volume-control/ukui-shortcut-audio/qml/HeaderDelegate.qml 0000664 0001750 0001750 00000005605 15171074712 023527 0 ustar feng feng /* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*-
* -*- coding: utf-8 -*-
*
* Copyright (C) 2025 KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
import org.ukui.quick.items 1.0 as UkuiItems
import org.ukui.quick.platform 1.0 as Platform
Item {
id: headerDelegate
width: headerDelegateWidth
height: headerDelegateHeight
anchors.top: parent.top
anchors.topMargin: headerDelegateTopMargin
property real headerDelegateWidth: 396
property real headerDelegateHeight: 32
property real headerDelegateTopMargin: 0
property string headerDelegateBtnSource: ""
property alias headerDelegateBtnVisible: headerDelegateBtn.visible
property alias headerDelegateBtnEnabled: headerDelegateBtn.enabled
property alias headerDelegateTextStr: headerDelegateText.text
signal headerDelegateBtnClick()
Label {
id: headerDelegateText
anchors.left: parent.left
anchors.leftMargin: 24
anchors.verticalCenter: parent.verticalCenter
text: qsTr("")
}
UkuiItems.DtThemeButton {
id: headerDelegateBtn
width: 32
height: 32
Layout.preferredWidth: 32
Layout.preferredHeight: 32
Layout.alignment: Qt.AlignVCenter
anchors.verticalCenter: parent.verticalCenter
anchors.right: parent.right
anchors.rightMargin: 16
background.radius: 6
property var kTransparent : Platform.GradientColor {
gradientDeg : 0
gradientStart : Qt.rgba(0/255, 0/255, 0/255, 0)
gradientEnd : Qt.rgba(0/255, 0/255, 0/255, 0)
gradientBackground : Qt.rgba(0/255, 0/255, 0/255, 0)
}
background.backgroundColor: containsPress ? Platform.GlobalTheme.kContainAlphaClick
: containsMouse ? Platform.GlobalTheme.kContainAlphaHover
: kTransparent
icon.source: headerDelegateBtnSource
icon.mode: UkuiItems.Icon.AutoHighlight
visible: false
enabled: false
onClicked: {
console.log("HeaderDelegate.qml headerDelegateBtn onClicked")
headerDelegate.headerDelegateBtnClick()
}
}
}
ukui-volume-control/ukui-shortcut-audio/qml/metadata.json 0000775 0001750 0001750 00000000766 15171074677 022664 0 ustar feng feng {
"Authors": [
{
"Name": "zhouyong",
"Email": "zhouyong01@kylinos.cn"
}
],
"Id": "org.ukui.shortcut.audio",
"Icon": "",
"Name": "ukui-shortcut-audio",
"Name[zh_CN]": "快捷面板声音插件",
"Tooltip": "audio",
"Tooltip[zh_CN]": "声音",
"Description": "audio",
"Description[zh_CN]": "声音",
"Version": "1.0",
"ShowIn": "Shortcut",
"WidgetType": "Widget",
"Contents": {
"Main": "main.qml",
"I18n": "translations/ukui-shortcut-audio"
}
}
ukui-volume-control/README.md 0000664 0001750 0001750 00000007567 15171074712 014743 0 ustar feng feng # ukui-volume-control
`ukui-volume-control` provides the audio service and volume control components
used by UKUI. The project covers backend audio management, the UKUI Control
Center audio plugin, and the shortcut audio widget used by the desktop shell.
## Overview
The repository is organized into several functional parts:
- `backend/`
Builds `ukui-audio-service`, the background service that manages audio
devices, streams, volume, mute state, and session-related audio behavior.
- `audio/`
Builds the shared library used by the UKUI Control Center audio module.
- `tray/`
Contains the tray volume control application source code.
- `ukui-shortcut-audio/`
Provides the QML plugin and widget resources for the shortcut audio panel.
- `common/`
Shared helper code used by multiple components.
- `data/`
Desktop integration files such as the user service unit and autostart entry.
- `debian/`
Debian and Ubuntu Kylin packaging metadata.
## Features
- Audio device detection and stream management
- Volume and mute control for input and output devices
- Application stream control
- PipeWire and PulseAudio integration
- UKUI Control Center integration
- UKUI shortcut widget and desktop session integration
- Translation resources for multiple locales
## Build Requirements
The project is intended for UKUI desktop environments and depends on Qt 6 plus
several Linux desktop and audio libraries. On Debian-based systems, the package
set below matches the current packaging metadata closely:
```bash
sudo apt install \
cmake intltool \
libasound2-dev libcanberra-dev libdbus-1-dev libdconf-dev \
libglib2.0-dev libgsettings-qt6-dev libkf6windowsystem-dev \
libkysdk-applications-dev libkysdk-system-dev \
libpipewire-0.3-dev libpugixml-dev libpulse-dev libsndfile1-dev \
libukcc-dev libxml2-dev nlohmann-json3-dev \
qt6-base-dev qt6-base-dev-tools qt6-declarative-dev \
qt6-svg-dev qt6-tools-dev qt6-tools-dev-tools
```
If the source package is already known to your build environment, you can also
install dependencies from packaging metadata with:
```bash
sudo apt build-dep .
```
You will also need the UKUI runtime environment and related desktop libraries
when running the built binaries.
## Development Build
For local development and testing, configure and build the project with CMake:
```bash
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build -j"$(nproc)"
```
To install into the system prefix:
```bash
sudo cmake --install build
```
## Main Outputs
The current build installs these primary artifacts:
- `ukui-audio-service` to `/usr/bin`
- The control center audio plugin to `/usr/lib//ukui-control-center/`
- The shortcut audio QML plugin to
`/usr/lib//qt/qml/org/ukui/shortcut/audio`
- Widget resources to `/usr/share/ukui/widgets/org.ukui.shortcut.audio`
- Translation files under `/usr/share/ukui-media/translations/audio`
- A user service unit under `/usr/lib/systemd/user/`
## Debian Packaging
For Debian and Ubuntu Kylin package creation, packaging files are maintained in
`debian/`.
This package uses the `3.0 (quilt)` source format. When building a source
package, make sure the upstream tarball is available as:
```text
../ukui-volume-control_.orig.tar.gz
```
The upstream tarball can be fetched according to `debian/watch` with:
```bash
uscan --download-current-version --force-download --rename
```
To build a source package for review or upload:
```bash
debuild -S -sa
```
To build binary packages locally:
```bash
debuild -b -uc -us
```
You can also use `dpkg-buildpackage` directly if preferred.
Build artifacts such as `.dsc`, `.changes`, `.buildinfo`, and `.deb` files are
normally generated in the parent directory.
## License
Most of this project is licensed under GPL-3.0-or-later. See `COPYING` for the
full GPL text and `debian/copyright` for packaged copyright and third-party
license details.
ukui-volume-control/common/ 0000775 0001750 0001750 00000000000 15171074712 014735 5 ustar feng feng ukui-volume-control/common/DBusClient.cpp 0000664 0001750 0001750 00000012720 15171074712 017437 0 ustar feng feng /* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*-
* -*- coding: utf-8 -*-
*
* Copyright (C) 2025 KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#include "DBusClient.h"
#include
//#include "ClientMethod.h"
DBusClient& DBusClient::getInstance()
{
static DBusClient instance;
return instance;
}
void DBusClient::initDbusConnect()
{
if (!QDBusConnection::sessionBus().connect(AUDIO_OBJECT_SERVICE, AUDIO_OBJECT_PATH, AUDIO_INTERFACE,
"volumeChanged",
this, SLOT(volumeChangedSlots(int, int, const QDBusVariant&)))) {
qDebug() << "Audio framework interface error, connect " << "volumeChanged" << "failed!";
qDebug() << QDBusConnection::sessionBus().lastError().message();
}
if (!QDBusConnection::sessionBus().connect(AUDIO_OBJECT_SERVICE, AUDIO_OBJECT_PATH, AUDIO_INTERFACE,
"muteChanged",
this, SLOT(muteChangedSlots(int, int, bool)))) {
qDebug() << "Audio framework interface error, connect " << "muteChanged" << "failed!";
qDebug() << QDBusConnection::sessionBus().lastError().message();
}
if (!QDBusConnection::sessionBus().connect(AUDIO_OBJECT_SERVICE, AUDIO_OBJECT_PATH, AUDIO_INTERFACE,
"volumeChanged",
this, SLOT(volumeChangedSlots(int, int, const QDBusVariant&)))) {
qDebug() << "Audio framework interface error, connect " << "volumeChanged" << "failed!";
qDebug() << QDBusConnection::sessionBus().lastError().message();
}
if (!QDBusConnection::sessionBus().connect(AUDIO_OBJECT_SERVICE, AUDIO_OBJECT_PATH, AUDIO_INTERFACE,
"deviceChanged",
this, SLOT(deviceChangedSlots(int, const QString&, const QString&)))) {
qDebug() << "Audio framework interface error, connect " << "deviceChanged" << "failed!";
qDebug() << QDBusConnection::sessionBus().lastError().message();
}
if (!QDBusConnection::sessionBus().connect(AUDIO_OBJECT_SERVICE, AUDIO_OBJECT_PATH, AUDIO_INTERFACE,
"deviceAdjust",
this, SLOT(deviceAdjustSlots(int)))) {
qDebug() << "Audio framework interface error, connect " << "deviceChanged" << "failed!";
qDebug() << QDBusConnection::sessionBus().lastError().message();
}
if (!QDBusConnection::sessionBus().connect(AUDIO_OBJECT_SERVICE, AUDIO_OBJECT_PATH, SETTINGS_INTERFACE,
"changed",
this, SLOT(settingsChangedSlots(const QString&, const QDBusVariant&)))) {
qDebug() << "Audio framework interface error, connect " << "changed" << "failed!" ;
qDebug() << QDBusConnection::sessionBus().lastError().message();
}
if (!QDBusConnection::sessionBus().connect(AUDIO_OBJECT_SERVICE, AUDIO_OBJECT_PATH, AUDIO_INTERFACE,
"addStream",
this, SLOT(addStreamSlots(int, int, int, bool, const QString&, const QString&)))) {
qDebug() << "Audio framework interface error, connect " << "addStream" << "failed!" ;
qDebug() << QDBusConnection::sessionBus().lastError().message();
}
if (!QDBusConnection::sessionBus().connect(AUDIO_OBJECT_SERVICE, AUDIO_OBJECT_PATH, AUDIO_INTERFACE,
"removeStream",
this, SLOT(removeStreamSlots(int, int)))) {
qDebug() << "Audio framework interface error, connect " << "removeStream" << "failed!" ;
qDebug() << QDBusConnection::sessionBus().lastError().message();
}
}
void DBusClient::volumeChangedSlots(int type, int idx, const QDBusVariant& v)
{
Q_EMIT volumeChangedSignal(type, idx, v);
}
void DBusClient::muteChangedSlots(int type, int idx, bool mute)
{
Q_EMIT muteChangedSignal(type, idx, mute);
}
void DBusClient::deviceChangedSlots(int type, const QString& portName, const QString& cardName)
{
Q_EMIT deviceChangedSignal(type, portName, cardName);
}
void DBusClient::deviceAdjustSlots(int type)
{
Q_EMIT deviceAdjustSignal(type);
}
void DBusClient::settingsChangedSlots(const QString& key, const QDBusVariant& v)
{
qDebug() << "DBusClient::settingsChangedSlots, key:" << key << " value: " << v.variant();
Q_EMIT settingsChangedSignal(key, v);
}
void DBusClient::addStreamSlots(int dire, int idx, int value, bool mute, const QString& iconName, const QString& descName)
{
Q_EMIT addStreamSignal(dire, idx, value, mute, iconName, descName);
}
void DBusClient::removeStreamSlots(int dire, int idx)
{
Q_EMIT removeStreamSignal(dire, idx);
}
ukui-volume-control/common/Ukui4CustomControl.h 0000664 0001750 0001750 00000004657 15171074712 020657 0 ustar feng feng /* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*-
* -*- coding: utf-8 -*-
*
* Copyright (C) 2025 KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#ifndef UKUI4CUSTOMCONTROL_H
#define UKUI4CUSTOMCONTROL_H
#include
#include
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
#include
#endif
#include
//文本长自动省略并添加悬浮
class AutoOmitLabel : public QLabel
{
Q_OBJECT
public:
explicit AutoOmitLabel(QWidget* = nullptr);
explicit AutoOmitLabel(const QString&, QWidget* = nullptr);
~AutoOmitLabel() = default;
public:
void setText(const QString&, bool = true);
protected:
void paintEvent(QPaintEvent*) override;
private:
QString m_fullText;
};
class UkmediaVolumeSlider : public kdk::KSlider
{
Q_OBJECT
public:
UkmediaVolumeSlider(QWidget* = nullptr);
~UkmediaVolumeSlider();
Q_SIGNALS:
void silderPressSignal();
void silderReleaseSignal();
protected:
void mousePressEvent(QMouseEvent*) override;
void mouseReleaseEvent(QMouseEvent*) override;
void mouseMoveEvent(QMouseEvent*) override;
void wheelEvent(QWheelEvent*) override;
void keyReleaseEvent(QKeyEvent*) override;
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
void enterEvent(QEnterEvent*) override;
#else
void enterEvent(QEvent*) override;
#endif
void leaveEvent(QEvent*) override;
private:
void initStyleOption(QStyleOptionSlider*);
void updateValue(QMouseEvent*);
private:
bool m_bMousePress = false;
};
class UkBalanceVolumeSlider : public kdk::KSlider
{
Q_OBJECT
public:
UkBalanceVolumeSlider(QWidget* = nullptr);
~UkBalanceVolumeSlider();
protected:
virtual bool eventFilter(QObject*, QEvent*) override;
private:
void initStyleOption(QStyleOptionSlider*);
void showTooltip();
};
#endif // UKUI4CUSTOMCONTROL_H
ukui-volume-control/common/DBusClient.h 0000664 0001750 0001750 00000024652 15171074712 017113 0 ustar feng feng /* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*-
* -*- coding: utf-8 -*-
*
* Copyright (C) 2025 KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#ifndef DBUSCLIENT_H
#define DBUSCLIENT_H
#include
#include
#include
#include
#include
#include
#include
#include "Util.h"
// 注册 ClientDeviceInfo 类型
typedef struct ClientDeviceInfo
{
QString cardName; // 声卡名称
QString cardDesc; // 声卡描述
QString portName; // 设备端口名称
QString portLabel; // 设备端口描述
quint32 priority; // 设备端口优先级
quint32 direction; // 端口方向 input or output
quint32 available; // 端口可用状态
bool enabled; // 端口启用状态
friend const QDBusArgument& operator>>(const QDBusArgument& argument, ClientDeviceInfo& info) {
argument.beginStructure();
argument >> info.cardName;
argument >> info.cardDesc;
argument >> info.portName;
argument >> info.portLabel;
argument >> info.priority;
argument >> info.direction;
argument >> info.available;
argument >> info.enabled;
argument.endStructure();
return argument;
}
friend const QDBusArgument &operator<<(QDBusArgument& argument, const ClientDeviceInfo& info) {
argument.beginStructure();
argument << info.cardName;
argument << info.cardDesc;
argument << info.portName;
argument << info.portLabel;
argument << info.priority;
argument << info.direction;
argument << info.available;
argument << info.enabled;
argument.endStructure();
return argument;
}
} ClientDeviceInfo;
Q_DECLARE_METATYPE(ClientDeviceInfo)
// 注册 ClientDefaultDeviceInfo 类型
typedef struct ClientDefaultDeviceInfo
{
quint32 idx; // 默认设备的索引
QString name; // 默认设备的名称(sink/source 名称)
QString cardName; // 默认设备所在的声卡名称
// QString cardDesc; // 默认设备所在的声卡描述
QString activePortName; // 默认设备的活跃端口名称,可能为空
QString activePortDesc; // 默认设备的活跃端口描述
friend const QDBusArgument& operator>>(const QDBusArgument& argument, ClientDefaultDeviceInfo& info) {
argument.beginStructure();
argument >> info.idx;
argument >> info.name;
argument >> info.cardName;
// argument >> info.cardDesc;
argument >> info.activePortName;
argument >> info.activePortDesc;
argument.endStructure();
return argument;
}
friend const QDBusArgument &operator<<(QDBusArgument& argument, const ClientDefaultDeviceInfo& info) {
argument.beginStructure();
argument << info.idx;
argument << info.name;
argument << info.cardName;
// argument << info.cardDesc;
argument << info.activePortName;
argument << info.activePortDesc;
argument.endStructure();
return argument;
}
} ClientDefaultDeviceInfo;
Q_DECLARE_METATYPE(ClientDefaultDeviceInfo)
// 注册 StreamInfo 类型
typedef struct StreamInfo
{
QString name; // 流媒体名称
quint32 index; // 流媒体索引
uint32_t volume; // 流媒体音量
QString role; // 流媒体角色
QString iconName; // 流媒体图标名称
friend const QDBusArgument& operator>>(const QDBusArgument& argument, StreamInfo& info) {
argument.beginStructure();
argument >> info.name;
argument >> info.index;
argument >> info.volume;
argument >> info.role;
argument >> info.iconName;
argument.endStructure();
return argument;
}
friend const QDBusArgument &operator<<(QDBusArgument& argument, const StreamInfo& info) {
argument.beginStructure();
argument << info.name;
argument << info.index;
argument << info.volume;
argument << info.role;
argument << info.iconName;
argument.endStructure();
return argument;
}
} StreamInfo;
Q_DECLARE_METATYPE(StreamInfo)
typedef struct ClientMediaInfo
{
uint32_t direction; // 流媒体的direction, input or output
uint32_t index; // 流媒体索引
uint32_t volume; // 流媒体音量值
bool mute; // 流媒体静音状态
QString name; // 流媒体名称
friend const QDBusArgument& operator>>(const QDBusArgument& argument, ClientMediaInfo& info) {
argument.beginStructure();
argument >> info.direction;
argument >> info.index;
argument >> info.volume;
argument >> info.mute;
argument >> info.name;
argument.endStructure();
return argument;
}
friend const QDBusArgument &operator<<(QDBusArgument& argument, const ClientMediaInfo& info) {
argument.beginStructure();
argument << info.direction;
argument << info.index;
argument << info.volume;
argument << info.mute;
argument << info.name;
argument.endStructure();
return argument;
}
} ClientMediaInfo;
Q_DECLARE_METATYPE(ClientMediaInfo)
typedef struct ClientStreamMediaInfo
{
QString mediaRole; // 流媒体角色
QString iconName; // 流媒体应用图标名称
QString binary; // 流媒体对应的二进制名称
std::list mediaInfoList; // 流媒体信息
friend const QDBusArgument& operator>>(const QDBusArgument& argument, ClientStreamMediaInfo& info) {
argument.beginStructure();
argument >> info.mediaRole;
argument >> info.iconName;
argument >> info.binary;
argument.beginArray();
while (!argument.atEnd()) {
ClientMediaInfo element;
argument >> element;
info.mediaInfoList.push_back(element);
}
argument.endArray();
argument.endStructure();
return argument;
}
friend const QDBusArgument &operator<<(QDBusArgument& argument, const ClientStreamMediaInfo& info) {
argument.beginStructure();
argument << info.mediaRole;
argument << info.iconName;
argument << info.binary;
argument.beginArray();
for (const auto& media : info.mediaInfoList) {
argument << media;
}
argument.endArray();
argument.endStructure();
return argument;
}
} ClientStreamMediaInfo;
Q_DECLARE_METATYPE(ClientStreamMediaInfo)
// 注册 ClientSoundThemeInfo 类型
typedef struct ClientSoundThemeInfo
{
QString name; // 音效主题的名称
QString description; // 音效主题的描述
friend const QDBusArgument& operator>>(const QDBusArgument& argument, ClientSoundThemeInfo& info) {
argument.beginStructure();
argument >> info.name;
argument >> info.description;
argument.endStructure();
return argument;
}
friend const QDBusArgument &operator<<(QDBusArgument& argument, const ClientSoundThemeInfo& info) {
argument.beginStructure();
argument << info.name;
argument << info.description;
argument.endStructure();
return argument;
}
} ClientSoundThemeInfo;
Q_DECLARE_METATYPE(ClientSoundThemeInfo)
// 注册 ClientSoundEffectFileInfo 类型
typedef struct ClientSoundEffectFileInfo
{
QString name; // 音效主题的名称
QString description; // 音效主题的描述
friend const QDBusArgument& operator>>(const QDBusArgument& argument, ClientSoundEffectFileInfo& info) {
argument.beginStructure();
argument >> info.name;
argument >> info.description;
argument.endStructure();
return argument;
}
friend const QDBusArgument &operator<<(QDBusArgument& argument, const ClientSoundEffectFileInfo& info) {
argument.beginStructure();
argument << info.name;
argument << info.description;
argument.endStructure();
return argument;
}
} ClientSoundEffectFileInfo;
Q_DECLARE_METATYPE(ClientSoundEffectFileInfo)
class DBusClient : public QObject
{
Q_OBJECT
public:
static DBusClient& getInstance();
public:
void initDbusConnect();
template
QDBusMessage dbusMethodCall(const QString&, const QString&, const QString&, const QString&, Args &&...);
Q_SIGNALS:
void volumeChangedSignal(int, int, const QDBusVariant&);
void muteChangedSignal(int, int, bool);
void deviceChangedSignal(int, const QString&, const QString&);
void deviceAdjustSignal(int);
void settingsChangedSignal(const QString&, const QDBusVariant&);
void addStreamSignal(int, int, int, bool, const QString&, const QString&);
void removeStreamSignal(int, int);
private Q_SLOTS:
void volumeChangedSlots(int, int, const QDBusVariant&);
void muteChangedSlots(int, int, bool);
void deviceChangedSlots(int, const QString&, const QString&);
void deviceAdjustSlots(int);
void settingsChangedSlots(const QString&, const QDBusVariant&);
void addStreamSlots(int, int, int, bool, const QString&, const QString&);
void removeStreamSlots(int, int);
private:
DBusClient() = default;
DBusClient(const DBusClient&) = delete;
DBusClient(DBusClient&&) = delete;
DBusClient operator=(const DBusClient&) = delete;
DBusClient operator=(DBusClient&&) = delete;
~DBusClient() = default;
};
template
QDBusMessage DBusClient::dbusMethodCall(const QString& destination, const QString& path, const QString& interface, const QString& method, Args&&... args)
{
QDBusInterface mediaInterface(destination, path, interface);
return mediaInterface.call(method, std::forward(args)...);
}
#endif // DBUSCLIENT_H
ukui-volume-control/common/Ukui4CustomControl.cpp 0000664 0001750 0001750 00000012663 15171074712 021206 0 ustar feng feng /* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*-
* -*- coding: utf-8 -*-
*
* Copyright (C) 2025 KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#include "Ukui4CustomControl.h"
#include
#include
#include
#include
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
#include
#endif
AutoOmitLabel::AutoOmitLabel(QWidget* parent)
: QLabel(parent)
{
}
AutoOmitLabel::AutoOmitLabel(const QString& text, QWidget* parent)
: QLabel(parent)
{
setText(text);
}
void AutoOmitLabel::paintEvent(QPaintEvent* event)
{
QFontMetrics fontMetrics(font());
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
int fontSize = fontMetrics.horizontalAdvance(m_fullText);
#else
int fontSize = fontMetrics.width(m_fullText);
#endif
if (fontSize > width()) {
setText(fontMetrics.elidedText(m_fullText, Qt::ElideRight, width()), false);
setToolTip(m_fullText);
} else {
setText(m_fullText, false);
setToolTip("");
}
QLabel::paintEvent(event);
}
void AutoOmitLabel::setText(const QString& text, bool save)
{
if (save)
m_fullText = text;
QLabel::setText(text);
}
UkmediaVolumeSlider::UkmediaVolumeSlider(QWidget* parent)
: kdk::KSlider(parent)
{
Q_UNUSED(parent);
setSliderType(kdk::SmoothSlider);
setNodeVisible(false);
}
void UkmediaVolumeSlider::updateValue(QMouseEvent* e)
{
int value = 0;
int currentX = e->pos().x();
double per = currentX * 1.0 / this->width();
if ((this->maximum() - this->minimum()) >= 50) {
value = qRound(per*(this->maximum() - this->minimum())) + this->minimum();
if (value <= (this->maximum() / 2 - this->maximum() / 10 + this->minimum() / 10)) {
value = qRound(per*(this->maximum() - this->minimum() - 1)) + this->minimum();
} else if (value > (this->maximum() / 2 + this->maximum() / 10 + this->minimum() / 10)) {
value = qRound(per*(this->maximum() - this->minimum() + 1)) + this->minimum();
} else {
value = qRound(per*(this->maximum() - this->minimum())) + this->minimum();
}
} else {
value = qRound(per*(this->maximum() - this->minimum())) + this->minimum();
}
this->setValue(value);
}
void UkmediaVolumeSlider::mousePressEvent(QMouseEvent* e)
{
m_bMousePress = true;
// 向父窗口发送自定义事件event type,这样就可以在父窗口中捕获这个事件进行处理
QEvent evEvent(static_cast(QEvent::User + 1));
QCoreApplication::sendEvent(parentWidget(), &evEvent);
return KSlider::mousePressEvent(e);
}
void UkmediaVolumeSlider::mouseReleaseEvent(QMouseEvent* e)
{
m_bMousePress = false;
return KSlider::mouseReleaseEvent(e);
}
void UkmediaVolumeSlider::mouseMoveEvent(QMouseEvent* e)
{
return KSlider::mouseMoveEvent(e);
}
void UkmediaVolumeSlider::wheelEvent(QWheelEvent* e)
{
return KSlider::wheelEvent(e);
}
void UkmediaVolumeSlider::keyReleaseEvent(QKeyEvent* e)
{
return KSlider::keyReleaseEvent(e);
}
void UkmediaVolumeSlider::initStyleOption(QStyleOptionSlider* option)
{
return KSlider::initStyleOption(option);
}
void UkmediaVolumeSlider::leaveEvent(QEvent* e)
{
return KSlider::leaveEvent(e);
}
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
void UkmediaVolumeSlider::enterEvent(QEnterEvent* e)
{
return KSlider::enterEvent(e);
}
#else
void UkmediaVolumeSlider::enterEvent(QEvent* e)
{
return KSlider::enterEvent(e);
}
#endif
UkmediaVolumeSlider::~UkmediaVolumeSlider()
{
// delete m_pTiplabel;
}
UkBalanceVolumeSlider::UkBalanceVolumeSlider(QWidget* parent)
: kdk::KSlider(parent)
{
Q_UNUSED(parent);
setSliderType(kdk::SingleSelectSlider);
setRange(-100,100);
setSingleStep(100);
setTickInterval(100);
setOrientation(Qt::Horizontal);
setFocusPolicy(Qt::StrongFocus);
this->installEventFilter(this);
}
void UkBalanceVolumeSlider::showTooltip()
{
QString percent = QString::number(this->value());
percent.append("%");
QStyleOptionSlider opt;
this->initStyleOption(&opt);
QRect handleRect = this->style()->subControlRect(QStyle::CC_Slider, &opt, QStyle::SC_SliderHandle, this);
QPoint point = this->mapToGlobal(handleRect.topLeft());
QFontMetrics fontMetrics = QFontMetrics(this->font());
QRect fontRect = fontMetrics.boundingRect(percent);
QToolTip::showText(point - QPoint(fontRect.width()/2 +3, fontRect.height() + 40), percent);
return;
}
bool UkBalanceVolumeSlider::eventFilter(QObject* watched, QEvent* event)
{
if (watched == this) {
if (event->type() == QEvent::HoverEnter)
showTooltip();
}
return kdk::KSlider::eventFilter(watched, event);
}
void UkBalanceVolumeSlider::initStyleOption(QStyleOptionSlider* option)
{
kdk::KSlider::initStyleOption(option);
}
UkBalanceVolumeSlider::~UkBalanceVolumeSlider()
{
}
ukui-volume-control/backend/ 0000775 0001750 0001750 00000000000 15171074712 015034 5 ustar feng feng ukui-volume-control/backend/PipewireBackend.cpp 0000664 0001750 0001750 00000001666 15171074712 020605 0 ustar feng feng /* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*-
* -*- coding: utf-8 -*-
*
* Copyright (C) 2025 KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#include "PipewireBackend.h"
namespace UkuiAudioFramwork
{
PipewireBackend::PipewireBackend()
{
}
void PipewireBackend::init()
{
}
bool PipewireBackend::detect()
{
return {};
}
}
ukui-volume-control/backend/AudioMethod.cpp 0000664 0001750 0001750 00000117620 15171074712 017751 0 ustar feng feng /* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*-
* -*- coding: utf-8 -*-
*
* Copyright (C) 2025 KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#include "AudioMethod.h"
#include
#include
#include
#include
#include "InitVolumeModule.h"
#include "AudioContext.h"
#include "MediaControler.h"
#include "MediaAutoPauseModule.h"
#include "MultiAudioCombineModule.h"
#include "DeviceManagerModule.h"
#include "Util.h"
namespace UkuiAudioFramwork
{
AudioMethod& AudioMethod::getInstance()
{
static AudioMethod instance;
return instance;
}
void AudioMethod::setManager(std::shared_ptr manager)
{
m_pAudioManager = manager;
}
void AudioMethod::init()
{
// init dbus
m_dbus.initialize();
// init settings
for (auto& [k, v] : m_keys) {
switch (k) {
case SettingType::AUDIO_SETTING: {
v = std::make_shared();
break;
}
case SettingType::GLOBALTHEME_SETTING: {
v = std::make_shared();
break;
}
case SettingType::SESSIONMANAGER_SETTING: {
v = std::make_shared();
break;
}
case SettingType::SOUDNTHEMEPLAYER_SETTING: {
v = std::make_shared();
break;
}
default:
break;
}
}
// 初始化音量
auto initSystemVolume = [this]() {
auto inputDev = getDefaultDevice(NodeType::INPUT, -1);
initVolume(NodeType::INPUT, inputDev.activePortName, inputDev.cardName);
auto outputDev = getDefaultDevice(NodeType::OUTPUT, -1);
initVolume(NodeType::OUTPUT, outputDev.activePortName, outputDev.cardName);
};
std::thread(initSystemVolume).detach();
// auto initModule = [this]() {
// for (const auto& [key, value] : m_settingsMap) {
// const auto& [module, param] = value;
// bool status = m_statusFunctions[key]();
// if (status) {
// loadModule(module, param);
// }
// }
// };
// std::thread(initModule).detach();
initJson();
DeviceManagerModule::getInstance().setManager(m_pAudioManager);
DeviceManagerModule::getInstance().setJson(m_pRestoreVolumeJson);
MediaAutoPauseModule::getInstance().setJson(m_pRestoreVolumeJson);
MultiAudioCombineModule::getInstance().setJson(m_pMultiAudioJson);
}
void AudioMethod::run()
{
m_dbus.run();
}
std::optional AudioMethod::getFieldValue(const std::string& line, const std::string_view& fieldName)
{
if (line.find(fieldName) != std::string::npos) {
auto start = line.find('=') + 1;
if (line[start] == '"') {
++start;
auto end = line.find('"', start);
if (end != std::string::npos) {
return line.substr(start, end - start);
}
}
}
return std::nullopt;
}
void AudioMethod::initJson()
{
m_pRestoreVolumeJson = std::make_shared();
m_pMultiAudioJson = std::make_shared();
}
SystemVersionInfo AudioMethod::getSystemVersionInfo()
{
SystemVersionInfo info;
const auto filePath = std::filesystem::path("/etc/os-release");
try {
if (std::ifstream osReleaseFile(filePath); osReleaseFile.is_open()) {
std::string line;
while (std::getline(osReleaseFile, line)) {
if (!info.prettyName) {
info.prettyName = getFieldValue(line, "PRETTY_NAME");
}
if (info.prettyName && !info.releaseId) {
info.releaseId = getFieldValue(line, "KYLIN_RELEASE_ID");
}
}
} else {
std::cerr << "can not open " << filePath << std::endl;
}
} catch (const std::filesystem::filesystem_error& e) {
std::cerr << "file system error: " << e.what() << std::endl;
}
return info;
}
DesktopEnvironmentVersion AudioMethod::getTypeFromSystemVersionInfo(const SystemVersionInfo& info) const
{
if (auto prettyName = info.prettyName; prettyName) {
if (prettyName.value().find("openKylin") != std::string::npos) {
return DesktopEnvironmentVersion::DESKTOP_ENVIRONMENT_VERSION_UKUI4;
} else if (prettyName.value().find("Kylin") != std::string::npos) {
if (auto releaseId = info.releaseId; releaseId) {
if (releaseId.value().find("2107") != std::string_view::npos) {
return DesktopEnvironmentVersion::DESKTOP_ENVIRONMENT_VERSION_UKUI2;
} else if (releaseId.value().find("2203") != std::string_view::npos ||
releaseId.value().find("2303") != std::string_view::npos ||
releaseId.value().find("2403") != std::string_view::npos) {
return DesktopEnvironmentVersion::DESKTOP_ENVIRONMENT_VERSION_UKUI3;
}
}
}
}
return DesktopEnvironmentVersion::DESKTOP_ENVIRONMENT_VERSION_UNKNOWN;
}
DesktopEnvironmentVersion AudioMethod::getDesktopEnvironmentVersion()
{
return getTypeFromSystemVersionInfo(getSystemVersionInfo());
}
std::string AudioMethod::getStreamDescription(const std::string& streamName)
{
if ("" == streamName)
return {};
AUDIO_DEBUG("getStreamDescription streamName: {} .",streamName);
GError** error = nullptr;
GKeyFileFlags flags = G_KEY_FILE_NONE;
GKeyFile* keyfile = g_key_file_new();
std::string path = "/usr/share/applications/";
std::string kaimingPath = "/opt/kaiming/share/applications/";
std::string description = "";
//start adapter application
auto it = m_adapterStreamNameMap.find(streamName);
if (it != m_adapterStreamNameMap.end()) {
path += it->second;
kaimingPath += it->second;
} else {
path += streamName;
kaimingPath += streamName;
}
//end
path += ".desktop";
kaimingPath += ".desktop";
gboolean ret = g_key_file_load_from_file(keyfile, path.c_str(), flags, error);
AUDIO_DEBUG("getStreamDescription ret: {} , path: {} .",ret , path);
if (!ret) {
ret = g_key_file_load_from_file(keyfile, kaimingPath.c_str(), flags, error);
AUDIO_DEBUG("getStreamDescription ret: {} , kaimingPath: {} .",ret , kaimingPath);
}
char* name = g_key_file_get_locale_string(keyfile, "Desktop Entry", "Name", nullptr, nullptr);
description = name ? name : streamName;
g_key_file_free(keyfile);
return description;
}
void AudioMethod::initVolume(NodeType type, const std::string& portName, const std::string& cardName)
{
if (InitVolumeModule::getInstance().isNeedInitVolume(portName, cardName)) {
if (cardName.starts_with("bluez")) {
m_pAudioManager->waitBluezReady(3000);
m_pAudioManager->setBluezReadyStatus(false);
}
auto volume = 17;
if (NodeType::INPUT == type) {
volume = 100;
}
else if (NodeType::OUTPUT == type) {
auto portType = getDevicePortType(cardName, portName);
volume = m_outputVolumeMap[portType];
}
AUDIO_DEBUG("When the sound card: {} port: {} is connected for the first time, the initial volume is {}.", cardName, portName, volume);
InitVolumeModule::getInstance().insert(portName, cardName, volume);
setVolume(type, -1, volume);
}
}
void AudioMethod::loadModule(const std::string& name, const std::string& param)
{
AUDIO_DEBUG("load module: {} with param: {}", name, param);
m_pAudioManager->loadModule(name, param);
}
void AudioMethod::unloadModule(const std::string& name)
{
AUDIO_DEBUG("unload module: {}", name);
m_pAudioManager->unloadModule(name);
}
std::string AudioMethod::getBackend() const
{
// return getBackendName(BackendType::PULSEAUDIO);
return m_pAudioManager->getBackend();
}
void AudioMethod::setBackend(const BackendType& type)
{
m_pAudioManager->setBackend(type);
}
void AudioMethod::setDetailVolume(const NodeType& type, const std::string& name, const std::string& dev, int volume)
{
AUDIO_DEBUG("Set {} detail volume, card: {} port: {} valume changed to {}.", getNodeTypeName(type), dev, name, volume);
m_pAudioManager->setDetailVolume(type, name, dev, volume);
}
int AudioMethod::getDetailVolume(const NodeType& type, const std::string& name, const std::string& dev) const
{
auto volume = m_pAudioManager->getDetailVolume(type, name, dev);
AUDIO_DEBUG("Get {} detail volume, card: {} port: {} volume: {}", getNodeTypeName(type), dev, name, volume);
return volume;
}
void AudioMethod::setVolume(const NodeType& type, int idx, int volume)
{
AUDIO_DEBUG("Set {} volume, {} volume changed to {}.", getNodeTypeName(type), idx, volume);
m_pAudioManager->setVolume(type, idx, volume);
}
int AudioMethod::getVolume(const NodeType& type, int idx) const
{
auto volume = m_pAudioManager->getVolume(type, idx);
AUDIO_DEBUG("Get {} volume, {} volume: {}.", getNodeTypeName(type), idx, volume);
return volume;
}
void AudioMethod::setBalance(const NodeType& type, double v)
{
AUDIO_DEBUG("Set {} balance value to {}.", getNodeTypeName(type), v);
m_pAudioManager->setBalance(type, v);
}
double AudioMethod::getBalance(const NodeType& type) const
{
auto balance = m_pAudioManager->getBalance(type);
AUDIO_DEBUG("Get {} balance, balance {}.", getNodeTypeName(type), balance);
return balance;
}
void AudioMethod::setDetailMute(const NodeType& type, const std::string& name, const std::string& dev, bool mute)
{
AUDIO_DEBUG("Set {} detail mute, card: {} port: {} mute changed to {}.", getNodeTypeName(type), dev, name, mute);
m_pAudioManager->setDetailMute(type, name, dev, mute);
}
bool AudioMethod::getDetailMute(const NodeType& type, const std::string& name, const std::string& dev) const
{
auto mute = m_pAudioManager->getDetailMute(type, name, dev);
AUDIO_DEBUG("Get {} detail mute, card: {} port: {} mute: {}", getNodeTypeName(type), dev, name, mute);
return mute;
}
void AudioMethod::setMute(const NodeType& type, int idx, bool mute)
{
AUDIO_DEBUG("Set {} mute, {} mute changed to {}.", getNodeTypeName(type), idx, mute);
m_pAudioManager->setMute(type, idx, mute);
}
bool AudioMethod::getMute(const NodeType& type, int idx) const
{
auto mute = m_pAudioManager->getMute(type, idx);
AUDIO_DEBUG("Get {} mute, {} mute: {}.", getNodeTypeName(type), idx, mute);
return mute;
}
DefaultDeviceInfo AudioMethod::getDefaultDevice(const NodeType& type, int idx) const
{
auto defaultDevice = m_pAudioManager->getDefaultDevice(type, idx);
AUDIO_DEBUG("Get {} default device, idx: {}, default device: {}", getNodeTypeName(type), idx, defaultDevice.name);
return defaultDevice;
}
void AudioMethod::setDefaultDevice(const NodeType& type, int idx, const std::string& name, const std::string& dev)
{
AUDIO_DEBUG("Set {} default device, default device change to card: {} port: {}.", getNodeTypeName(type), dev, name);
m_pAudioManager->setDefaultDevice(type, idx, name, dev);
}
std::vector AudioMethod::getDeviceList(const NodeType& type) const
{
auto list = m_pAudioManager->getDeviceList(type);
AUDIO_DEBUG("Get {} device list.");
return list;
}
std::list AudioMethod::getSinkList() const
{
auto list = m_pAudioManager->getSinkList();
std::string sl = "[";
for (const auto& s : list) {
sl += "(";
sl += s.toString();
sl += "),";
}
sl += "]";
AUDIO_DEBUG("Get sink list, sinks: {}.", sl);
return list;
}
std::list AudioMethod::getSourceList() const
{
auto list = m_pAudioManager->getSourceList();
std::string sl = "[";
for (const auto& s : list) {
sl += "(";
sl += s.toString();
sl += "),";
}
sl += "]";
AUDIO_DEBUG("Get source list, sources: {}.", sl);
return list;
}
std::list> AudioMethod::getAvailablePortList(const NodeType& type) const
{
auto list = m_pAudioManager->getAvailablePortList(type);
std::string pl = "[";
for (const auto& p : list) {
pl += "(";
pl += p->toString();
pl += "),";
}
pl += "]";
AUDIO_DEBUG("Get {} available port, ports: {}.", getNodeTypeName(type), pl);
return list;
}
std::list AudioMethod::getSinkInputList() const
{
auto list = m_pAudioManager->getSinkInputList();
std::string sil = "[";
for (const auto& si : list) {
sil += "(";
sil += si.toString();
sil += "),";
}
sil += "]";
AUDIO_DEBUG("Get sink inputs, inputs: {}.", sil);
return list;
}
std::list AudioMethod::getSourceOutputList() const
{
auto list = m_pAudioManager->getSourceOutputList();
std::string sol = "[";
for (const auto& so : list) {
sol += "(";
sol += so.toString();
sol += "),";
}
sol += "]";
AUDIO_DEBUG("Get source outputs, outputs: {}.", sol);
return list;
}
std::list AudioMethod::getStreamMediaList() const
{
return m_pAudioManager->getStreamMediaList();
}
bool AudioMethod::isValidDevice(const NodeType& type) const
{
auto ret = m_pAudioManager->isValidDevice(type);
AUDIO_DEBUG("{} has {} device.", getNodeTypeName(type), ret ? "vaild" : "invaild");
return ret;
}
bool AudioMethod::getVolumeBoostStatus() const
{
if (auto key = m_keys.find(SettingType::AUDIO_SETTING); key != m_keys.end()) {
auto status = g_variant_get_boolean(key->second->getValue(VOLUME_BOOST_KEY));
AUDIO_DEBUG("Get volume boost status, status: {}.", status);
return status;
}
AUDIO_ERROR("Not found SettingType::AUDIO_SETTING keys, get volume boost status failed.");
return false;
}
void AudioMethod::setVolumeBoostStatus(bool status)
{
AUDIO_DEBUG("Set volume boost status to {}.", status);
if (auto key = m_keys.find(SettingType::AUDIO_SETTING); key != m_keys.end())
key->second->setValue(VOLUME_BOOST_KEY, g_variant_new("b", status));
else
AUDIO_ERROR("Not found SettingType::AUDIO_SETTING keys, set volume boost status failed.");
if (!status) {
auto sinkList = getSinkList();
std::for_each(sinkList.begin(), sinkList.end(), [this](const DefaultDeviceInfo& dev) {
if (dev.volume > PA_VOLUME_NORMAL) {
AUDIO_DEBUG("When Volume-Increase is turned off, device: {} needs to be set volume: {} to 65536", dev.name, dev.volume);
setVolume(NodeType::OUTPUT, dev.idx, UKMEDIA_VOLUME_NORMAL);
}
});
}
}
int AudioMethod::getVolumeBoostValue() const
{
if (auto key = m_keys.find(SettingType::AUDIO_SETTING); key != m_keys.end()) {
auto value = g_variant_get_int32(key->second->getValue(VOLUME_BOOST_VOLUME_KEY));
AUDIO_DEBUG("Get volume boost value, value: {}.", value);
return value;
}
AUDIO_ERROR("Not found SettingType::AUDIO_SETTING keys, get volume boost value failed.");
return DEFAULT_VOLUME_BOOST_VALUE;
}
void AudioMethod::setVolumeBoostValue(int value)
{
AUDIO_DEBUG("Set volume boost value to {}.", value);
if (auto key = m_keys.find(SettingType::AUDIO_SETTING); key != m_keys.end())
key->second->setValue(VOLUME_BOOST_VOLUME_KEY, g_variant_new("i", value));
else
AUDIO_ERROR("Not found SettingType::AUDIO_SETTING keys, set volume boost value failed.");
}
bool AudioMethod::getMonoStatus() const
{
if (auto key = m_keys.find(SettingType::AUDIO_SETTING); key != m_keys.end()) {
auto status = g_variant_get_boolean(key->second->getValue(MONO_AUDIO_KEY));
AUDIO_DEBUG("Get mono status, status: {}.", status);
return status;
}
AUDIO_ERROR("Not found SettingType::AUDIO_SETTING keys, get mono status failed.");
return false;
}
void AudioMethod::setMonoStatus(bool status)
{
AUDIO_DEBUG("Set mono status to {}.", status);
if (auto key = m_keys.find(SettingType::AUDIO_SETTING); key != m_keys.end())
key->second->setValue(MONO_AUDIO_KEY, g_variant_new("b", status));
else
AUDIO_ERROR("Not found SettingType::AUDIO_SETTING keys, set mono status failed.");
}
bool AudioMethod::getEchoCancelStatus() const
{
if (auto key = m_keys.find(SettingType::AUDIO_SETTING); key != m_keys.end()) {
auto status = g_variant_get_boolean(key->second->getValue(NOISE_REDUCTION_KEY));
AUDIO_DEBUG("Get echo cancel status, status: {}.", status);
return status;
}
AUDIO_ERROR("Not found SettingType::AUDIO_SETTING keys, get noise resduction status failed.");
return false;
}
void AudioMethod::setEchoCancelStatus(bool status)
{
AUDIO_DEBUG("Set echo cancel status to {}.", status);
if (auto key = m_keys.find(SettingType::AUDIO_SETTING); key != m_keys.end())
key->second->setValue(NOISE_REDUCTION_KEY, g_variant_new("b", status));
else
AUDIO_ERROR("Not found SettingType::AUDIO_SETTING keys, set noise resduction status failed.");
}
bool AudioMethod::getLoopbackStatus() const
{
if (auto key = m_keys.find(SettingType::AUDIO_SETTING); key != m_keys.end()) {
auto status = g_variant_get_boolean(key->second->getValue(LOOPBACK_KEY));
AUDIO_DEBUG("Get loopback status, status: {}.", status);
return status;
}
AUDIO_ERROR("Not found SettingType::AUDIO_SETTING keys, get loopback status failed.");
return false;
}
void AudioMethod::setLoopbackStatus(bool status)
{
AUDIO_DEBUG("Set loopback status to {}.", status);
if (auto key = m_keys.find(SettingType::AUDIO_SETTING); key != m_keys.end())
key->second->setValue(LOOPBACK_KEY, g_variant_new("b", status));
else
AUDIO_ERROR("Not found SettingType::AUDIO_SETTING keys, set loopback status failed.");
}
std::string AudioMethod::getSoundThemeName() const
{
if (auto key = m_keys.find(SettingType::AUDIO_SETTING); key != m_keys.end()) {
gsize length;
auto name = g_variant_get_string(key->second->getValue(THEME_NAME_KEY), &length);
AUDIO_DEBUG("Get sound theme name, name: {}.", name);
return name;
}
AUDIO_ERROR("Not found SettingType::AUDIO_SETTING keys, get theme name failed.");
return {};
}
void AudioMethod::setSoundThemeName(const std::string& name)
{
AUDIO_DEBUG("Set sound theme name to {}.", name);
if (auto key = m_keys.find(SettingType::AUDIO_SETTING); key != m_keys.end())
key->second->setValue(THEME_NAME_KEY, g_variant_new("s", name.c_str()));
else
AUDIO_ERROR("Not found SettingType::AUDIO_SETTING keys, set theme name failed.");
}
bool AudioMethod::getCustomThemeStatus() const
{
if (auto key = m_keys.find(SettingType::AUDIO_SETTING); key != m_keys.end()) {
auto status = g_variant_get_boolean(key->second->getValue(CUSTOM_THEME_KEY));
AUDIO_DEBUG("Get custom theme status, status: {}.", status);
return status;
}
AUDIO_ERROR("Not found SettingType::AUDIO_SETTING keys, get custom theme status failed.");
return {};
}
void AudioMethod::setCustomThemeStatus(bool status)
{
AUDIO_DEBUG("Set custom theme status to {}.", status);
if (auto key = m_keys.find(SettingType::AUDIO_SETTING); key != m_keys.end())
key->second->setValue(CUSTOM_THEME_KEY, g_variant_new("b", status));
else
AUDIO_ERROR("Not found SettingType::AUDIO_SETTING keys, set custom theme status failed.");
}
std::string AudioMethod::getNotifyGeneralName() const
{
if (auto key = m_keys.find(SettingType::AUDIO_SETTING); key != m_keys.end()) {
gsize length;
auto name = g_variant_get_string(key->second->getValue(NOTIFY_GENERAL_KEY), &length);
AUDIO_DEBUG("Get notify general name, name: {}.", name);
return name ? name : "";
}
AUDIO_ERROR("Not found SettingType::AUDIO_SETTING keys, get notify general failed.");
return {};
}
void AudioMethod::setNotifyGeneralName(const std::string& name)
{
AUDIO_DEBUG("Set notify geberal name to {}.", name);
if (auto key = m_keys.find(SettingType::AUDIO_SETTING); key != m_keys.end())
key->second->setValue(NOTIFY_GENERAL_KEY, g_variant_new("s", name.c_str()));
else
AUDIO_ERROR("Not found SettingType::AUDIO_SETTING keys, set notify general failed.");
}
std::string AudioMethod::getVolumeChangedName() const
{
if (auto key = m_keys.find(SettingType::AUDIO_SETTING); key != m_keys.end()) {
gsize length;
auto name = g_variant_get_string(key->second->getValue(VOLUME_CHANGED_KEY), &length);
AUDIO_DEBUG("Get volume changed name, name: {}.", name);
return name ? name : "";
}
AUDIO_ERROR("Not found SettingType::AUDIO_SETTING keys, get volume changed failed.");
return {};
}
void AudioMethod::setVolumeChangedName(const std::string& name)
{
AUDIO_DEBUG("Set volume changed name to {}.", name);
if (auto key = m_keys.find(SettingType::AUDIO_SETTING); key != m_keys.end())
key->second->setValue(VOLUME_CHANGED_KEY, g_variant_new("s", name.c_str()));
else
AUDIO_ERROR("Not found SettingType::AUDIO_SETTING keys, set volume changed failed.");
}
bool AudioMethod::getAlertStatus() const
{
if (auto key = m_keys.find(SettingType::AUDIO_SETTING); key != m_keys.end()) {
auto status = g_variant_get_boolean(key->second->getValue(EVENT_SOUND_KEY));
AUDIO_DEBUG("Get alert status, status: {}.", status);
return status;
}
AUDIO_ERROR("Not found SettingType::AUDIO_SETTING keys, get alert status failed.");
return false;
}
void AudioMethod::setAlertStatus(bool status)
{
AUDIO_DEBUG("Set alert status to {}.", status);
if (auto key = m_keys.find(SettingType::AUDIO_SETTING); key != m_keys.end())
key->second->setValue(EVENT_SOUND_KEY, g_variant_new("b", status));
else
AUDIO_ERROR("Not found SettingType::AUDIO_SETTING keys, set alert status failed.");
}
bool AudioMethod::getStartupStatus() const
{
if (auto key = m_keys.find(SettingType::SESSIONMANAGER_SETTING); key != m_keys.end()) {
auto status = g_variant_get_boolean(key->second->getValue(STARTUP_MUSIC_KEY));
AUDIO_DEBUG("Get startup status, status: {}.", status);
return status;
}
AUDIO_ERROR("Not found SettingType::SESSIONMANAGER_SETTING keys, get startup status failed.");
return false;
}
void AudioMethod::setStartupStatus(bool status)
{
AUDIO_DEBUG("Set startup status to {}.", status);
if (auto key = m_keys.find(SettingType::SESSIONMANAGER_SETTING); key != m_keys.end())
key->second->setValue(STARTUP_MUSIC_KEY, g_variant_new("b", status));
else
AUDIO_ERROR("Not found SettingType::SESSIONMANAGER_SETTING keys, set startup status failed.");
}
bool AudioMethod::getPoweroffStatus() const
{
if (auto key = m_keys.find(SettingType::SESSIONMANAGER_SETTING); key != m_keys.end()) {
auto status = g_variant_get_boolean(key->second->getValue(POWEROFF_MUSIC_KEY));
AUDIO_DEBUG("Get poweroff status, status: {}.", status);
return status;
}
AUDIO_ERROR("Not found SettingType::SESSIONMANAGER_SETTING keys, get poweroff status failed.");
return false;
}
void AudioMethod::setPoweroffStatus(bool status)
{
AUDIO_DEBUG("Set poweroff status to {}.", status);
if (auto key = m_keys.find(SettingType::SESSIONMANAGER_SETTING); key != m_keys.end())
key->second->setValue(POWEROFF_MUSIC_KEY, g_variant_new("b", status));
else
AUDIO_ERROR("Not found SettingType::SESSIONMANAGER_SETTING keys, set poweroff status failed.");
}
bool AudioMethod::getLogoutStatus() const
{
if (auto key = m_keys.find(SettingType::SESSIONMANAGER_SETTING); key != m_keys.end()) {
auto status = g_variant_get_boolean(key->second->getValue(LOGOUT_MUSIC_KEY));
AUDIO_DEBUG("Get logout status, status: {}.", status);
return status;
}
AUDIO_ERROR("Not found SettingType::SESSIONMANAGER_SETTING keys, get logout status failed.");
return false;
}
void AudioMethod::setLogoutStatus(bool status)
{
AUDIO_DEBUG("Set logout status to {}.", status);
if (auto key = m_keys.find(SettingType::SESSIONMANAGER_SETTING); key != m_keys.end())
key->second->setValue(LOGOUT_MUSIC_KEY, g_variant_new("b", status));
else
AUDIO_ERROR("Not found SettingType::SESSIONMANAGER_SETTING keys, set logout status failed.");
}
bool AudioMethod::getWakeupStatus() const
{
if (auto key = m_keys.find(SettingType::SESSIONMANAGER_SETTING); key != m_keys.end()) {
auto status = g_variant_get_boolean(key->second->getValue(WAKEUP_MUSIC_KEY));
AUDIO_DEBUG("Get wakeup status, status: {}.", status);
return status;
}
AUDIO_ERROR("Not found SettingType::SESSIONMANAGER_SETTING keys, get wakeup status failed.");
return false;
}
void AudioMethod::setWakeupStatus(bool status)
{
AUDIO_DEBUG("Set wakeup status to {}.", status);
if (auto key = m_keys.find(SettingType::SESSIONMANAGER_SETTING); key != m_keys.end())
key->second->setValue(WAKEUP_MUSIC_KEY, g_variant_new("b", status));
else
AUDIO_ERROR("Not found SettingType::SESSIONMANAGER_SETTING keys, set wakeup status failed.");
}
std::string AudioMethod::getGlobalThemeName() const
{
if (auto key = m_keys.find(SettingType::GLOBALTHEME_SETTING); key != m_keys.end()) {
gsize length;
auto name = g_variant_get_string(key->second->getValue(GLOBAL_THEME_NAME_KEY), &length);
AUDIO_DEBUG("Get global theme name, name: {}.", name);
return name;
}
AUDIO_ERROR("Not found SettingType::GLOBALTHEME_SETTING keys, get global theme name failed.");
return {};
}
void AudioMethod::setGlobalThemeName(const std::string& name)
{
AUDIO_DEBUG("Set global theme name to {}.", name);
if (auto key = m_keys.find(SettingType::GLOBALTHEME_SETTING); key != m_keys.end())
key->second->setValue(GLOBAL_THEME_NAME_KEY, g_variant_new("s", name.c_str()));
else
AUDIO_ERROR("Not found SettingType::GLOBALTHEME_SETTING keys, set global theme name failed.");
}
std::list AudioMethod::getSoundThemeList()
{
auto list = SoundThemeModule::getInstance().getSoundThemeList();
std::string stl = "[";
for (const auto& s : list) {
stl += "(";
stl += s.toString();
stl += "),";
}
stl += "]";
AUDIO_DEBUG("Get sound theme list, theme list: {}.", stl);
return list;
}
std::list AudioMethod::getSoundEffectFileList(const std::string& themeName)
{
auto list = SoundThemeModule::getInstance().getSoundEffectFileList(themeName);
std::string sefl = "[";
for (const auto& f : list) {
sefl += "(";
sefl += f.toString();
sefl += "),";
}
sefl += "]";
AUDIO_DEBUG("Get {} theme sound effect file list, list: {}.", themeName, sefl);
return list;
}
void AudioMethod::setEnabled(const std::string& card, const std::string& port, bool enabled)
{
AUDIO_DEBUG("Set card: {} port: {} enabled to {}.", card, port, enabled);
DeviceManagerModule::getInstance().setEnabled(card, port, enabled);
}
bool AudioMethod::isEnabled(const std::string& card, const std::string& port) const
{
auto enable = m_pAudioManager->isEnabled(card, port);
AUDIO_DEBUG("Get card: {} port: {} enable status, enable: {}.", card, port, enable);
return enable;
}
bool AudioMethod::getAutoPauseStatus() const
{
auto status = MediaAutoPauseModule::getInstance().getAutoPauseStatus();
AUDIO_DEBUG("Get auto pause status, status: {}", status);
return status;
}
void AudioMethod::setAutoPauseStatus(bool status)
{
AUDIO_DEBUG("Set auto pause status to {}.", status);
MediaAutoPauseModule::getInstance().setAutoPauseStatus(status);
}
bool AudioMethod::getMultiAudioCombineStatus(const NodeType& type) const
{
auto status = MultiAudioCombineModule::getInstance().getMultiAudioCombineStatus(type);
AUDIO_DEBUG("Get {} multi audio combine status, status: {}.", getNodeTypeName(type), status);
return status;
}
void AudioMethod::setMultiAudioCombine(const NodeType& type, bool status, const std::vector& devList)
{
std::string deviceList = "[";
for (const auto& d : deviceList) {
deviceList += d;
deviceList += ", ";
}
deviceList += "]";
AUDIO_DEBUG("Set multi audio combine status to {}, combine devices: {}", status, deviceList);
MultiAudioCombineModule::getInstance().setMultiAudioCombine(type, status, devList);
}
void AudioMethod::volumeChanged(const NodeType& type, int index, int volume)
{
AUDIO_DEBUG("{} volume changed to {}.", getNodeTypeName(type), volume);
m_dbus.sendSignal(AUDIO_OBJECT_PATH, AUDIO_INTERFACE, "volumeChanged", g_variant_new("(iiv)", type, index, g_variant_new("i", volume)));
}
void AudioMethod::muteChanged(const NodeType& type, int index, bool mute)
{
AUDIO_DEBUG("{} type mute changed to {}", EnumToInt(type), mute);
m_dbus.sendSignal(AUDIO_OBJECT_PATH, AUDIO_INTERFACE, "muteChanged", g_variant_new("(iib)", type, index, mute));
}
void AudioMethod::deviceChanged(const NodeType& type, const std::string& portName, const std::string& cardName, bool autoPause)
{
// 设备更改是可能需要初始化音量
std::thread([type, portName, cardName, this]() {
initVolume(type, portName, cardName);
}).join();
// 当默认输出设备发生更改时满足以下条件需要暂停播放
if (getAutoPauseStatus() && NodeType::OUTPUT == type && autoPause)
MediaControler::getInstance().pauseAllPlayers();
// 默认设备更改是可能存在模块需要加载或卸载的操作
if (NodeType::INPUT == type) {
auto status = getEchoCancelStatus();
auto defaultInput = getDefaultDevice(NodeType::INPUT, -1).name;
auto isLoaded = m_pAudioManager->isLoaded(ModuleType::MODULE_ECHO_CANCEL);
AUDIO_DEBUG("device changed getEchoCancelStatus:{} defaultInput:{} isLoaded:{} .", status, defaultInput, isLoaded);
if (status) {
if (isLoaded) {
if (std::string::npos != defaultInput.find("bluez_input") ||
std::string::npos != defaultInput.find("bluez_source") ||
std::string::npos != defaultInput.find("input.usb") ||
std::string::npos != defaultInput.find(".monitor")) {
AUDIO_DEBUG("The default input device is {} unload the module-echo-cancel.", defaultInput);
unloadModule("module-echo-cancel");
}
}
else {
if ((std::string::npos != defaultInput.find("alsa_input") &&
std::string::npos == defaultInput.find("input.usb"))) {
auto it = m_settingsMap.find(NOISE_REDUCTION_KEY);
if (it != m_settingsMap.end()) {
const auto& [module, param] = it->second;
loadModule(module, param);
}
}
else {
AUDIO_DEBUG("The default input device is {} and there is no need to "
"load the module-echo-cancel module.", defaultInput);
}
}
}
auto loopbackStatus = getLoopbackStatus();
auto devInfo = getDefaultDevice(NodeType::INPUT, -1);
const bool isNullorInternalDev =
(std::string::npos != devInfo.name.find("auto_null")) ||
(std::string::npos != devInfo.activePortName.find("internal")) ||
(std::string::npos != devInfo.activePortLabel.find("Digital"));
AUDIO_DEBUG("device changed loopbackStatus:{} isNullorInternalDev:{}.", loopbackStatus, isNullorInternalDev);
if (loopbackStatus && m_pAudioManager->isLoaded(ModuleType::MODULE_LOOPBACK)) {
AUDIO_DEBUG("device changed is loaded MODULE_LOOPBACK.");
if (isNullorInternalDev) {
unloadModule("module-loopback");
}
}
else if (loopbackStatus && !m_pAudioManager->isLoaded(ModuleType::MODULE_LOOPBACK)) {
AUDIO_DEBUG("device changed unloaded MODULE_LOOPBACK.");
if (!isNullorInternalDev) {
auto it = m_settingsMap.find(LOOPBACK_KEY);
if (it != m_settingsMap.end()) {
const auto& [module, param] = it->second;
loadModule(module, param);
}
}
}
}
else if (NodeType::OUTPUT == type) {
auto status = getMonoStatus();
auto defaultOutput = getDefaultDevice(NodeType::OUTPUT, -1).name;
auto isLoaded = m_pAudioManager->isLoaded(ModuleType::MODULE_REMAP_SINK);
if (status) {
if (isLoaded) {
if (std::string::npos != defaultOutput.find("auto_null")) {
AUDIO_DEBUG("The default output device is {} unload the module-remap-sink.", defaultOutput);
unloadModule("module-remap-sink");
}
}
else {
AUDIO_DEBUG("The default output device is {} load the module-remap-sink.", defaultOutput);
if (std::string::npos == defaultOutput.find("auto_null")) {
auto it = m_settingsMap.find(MONO_AUDIO_KEY);
if (it != m_settingsMap.end()) {
const auto& [module, param] = it->second;
loadModule(module, param);
}
}
}
}
}
AUDIO_DEBUG("{} device changed to card: {} port: {}.", getNodeTypeName(type), cardName, portName);
m_dbus.sendSignal(AUDIO_OBJECT_PATH, AUDIO_INTERFACE, "deviceChanged", g_variant_new("(iss)", type, portName.c_str(), cardName.c_str()));
}
void AudioMethod::deviceAdjust(const NodeType& type)
{
AUDIO_DEBUG("Device adjust.");
m_dbus.sendSignal(AUDIO_OBJECT_PATH, AUDIO_INTERFACE, "deviceAdjust", g_variant_new("(i)", type));
}
void AudioMethod::portChanged(const NodeType& type, const std::string& name)
{
AUDIO_DEBUG("{} prot change to {}", getNodeTypeName(type), name);
m_dbus.sendSignal(AUDIO_OBJECT_PATH, AUDIO_INTERFACE, "portChanged", g_variant_new("(is)", type, name.c_str()));
}
void AudioMethod::cardRemoved(const std::string& name)
{
AUDIO_DEBUG("Card: {} removed", name);
m_dbus.sendSignal(AUDIO_OBJECT_PATH, AUDIO_INTERFACE, "cardRemoved", g_variant_new("(s)", name.c_str()));
}
void AudioMethod::settingsChanged(const char* key, GVariant* v)
{
gsize length;
if (const auto& it = m_settingsMap.find(key); it != m_settingsMap.end()) {
const auto& [module, param] = it->second;
auto status = g_variant_get_boolean(v);
if (status) {
loadModule(module, param);
} else {
unloadModule(module);
}
}
AUDIO_DEBUG("Setting key : {} .", key);
if (0 == strcmp(key, GLOBAL_THEME_NAME_KEY)) {
gsize length;
auto name = g_variant_get_string(v, &length);
if (strcmp(name, "custom")) {
setSoundThemeName(name);
}
}
else if (0 == strcmp(key, THEME_NAME_KEY)) {
const std::string theme = g_variant_get_string(v, &length);
AUDIO_DEBUG("Setting theme : {} .", theme);
// 音效主题更改时需要更新音量更改和通知的音效
if (strcmp(theme.c_str(), "custom")) {
setCustomThemeStatus(false);
auto list = SoundThemeModule::getInstance().getSoundEffectFileList(theme);
AUDIO_DEBUG("Setting theme list: {} .", list.size());
if (auto it = findByName(list, "audio-volume-change"); it != list.end()) {
auto avcName = replaceThemeName(it->name, theme);
setVolumeChangedName(avcName);
}
if (auto it = findByName(list, "notification-general"); it != list.end()) {
auto ntfName = replaceThemeName(it->name, theme);
setNotifyGeneralName(ntfName);
}
}
auto globalName = getGlobalThemeName();
AUDIO_DEBUG("Setting globalName : {} .", globalName);
// 切换音效主题时,将系统全局主题切换成自定义
if (g_variant_get_string(v, &length) != globalName) {
setGlobalThemeName("custom");
}
}
else if (0 == strcmp(key, NOTIFY_GENERAL_KEY) || 0 == strcmp(key, VOLUME_CHANGED_KEY)) {
gsize lg;
const gchar* vName = g_variant_get_string(v, &lg);
std::string themeName = getSoundThemeName();
auto it = m_defaultThemeMap.find(themeName);
if (it != m_defaultThemeMap.end()) {
const auto [avcThemeName, ngThemeName] = it->second;
if ((0 == strcmp(key, NOTIFY_GENERAL_KEY) && 0 == strcmp(vName, ngThemeName.c_str()))
|| (0 == strcmp(key, VOLUME_CHANGED_KEY) && 0 == strcmp(vName, avcThemeName.c_str()))) {
setCustomThemeStatus(false);
} else {
setCustomThemeStatus(true);
setSoundThemeName("custom");
}
} else {
setCustomThemeStatus(true);
setSoundThemeName("custom");
}
}
AUDIO_DEBUG("Setting : {} change to {}.", key, v);
m_dbus.sendSignal(AUDIO_OBJECT_PATH, SETTINGS_INTERFACE, "changed", g_variant_new("(sv)", key, v));
}
void AudioMethod::addStream(int idx, int value, const std::string& iconName, const std::string& descName)
{
AUDIO_DEBUG("Stream {} added, index: {}, value: {}, iconName: {}.", descName, idx, value, iconName);
m_dbus.sendSignal(AUDIO_OBJECT_PATH, AUDIO_INTERFACE, "addStream", g_variant_new("(iiss)", idx, value, iconName.c_str(), descName.c_str()));
}
void AudioMethod::removeStream(int idx)
{
AUDIO_DEBUG("Stream {} removed.", idx);
m_dbus.sendSignal(AUDIO_OBJECT_PATH, AUDIO_INTERFACE, "removeStream", g_variant_new("(i)", idx));
}
void AudioMethod::addStream(int dir, int idx, int value, bool mute, const std::string& iconName, const std::string& descName)
{
AUDIO_DEBUG("Stream {} added, index: {}, value: {}, iconName: {}.", descName, idx, value, iconName);
m_dbus.sendSignal(AUDIO_OBJECT_PATH, AUDIO_INTERFACE, "addStream", g_variant_new("(iiibss)", dir, idx, value, mute, iconName.c_str(), descName.c_str()));
}
void AudioMethod::removeStream(int dire, int idx)
{
AUDIO_DEBUG("Stream {} removed.", idx);
m_dbus.sendSignal(AUDIO_OBJECT_PATH, AUDIO_INTERFACE, "removeStream", g_variant_new("(ii)", dire, idx));
}
std::string AudioMethod::extractThemeName(const std::string& name)
{
size_t soundsPos = name.find("/sounds/");
if (soundsPos == std::string::npos) {
return "";
}
size_t startThemePos = soundsPos + 8;
size_t endThemePos = name.find("/", startThemePos);
if (endThemePos == std::string::npos) {
endThemePos = name.length();
}
return name.substr(startThemePos, endThemePos - startThemePos);
}
std::string AudioMethod::replaceThemeName(const std::string& name, const std::string& themeName)
{
if (themeName.empty()) {
return name;
}
std::string currentThemeName = extractThemeName(name);
if (currentThemeName != themeName) {
size_t soundsPos = name.find("/sounds/");
if (soundsPos == std::string::npos) {
return name;
}
size_t startThemePos = soundsPos + 8;
size_t endThemePos = name.find("/", startThemePos);
if (endThemePos == std::string::npos) {
endThemePos = name.length();
}
std::string prefix = name.substr(0, startThemePos);
std::string suffix = name.substr(endThemePos);
return prefix + themeName + suffix;
}
return name;
}
bool AudioMethod::isLoaded(const ModuleType& type)
{
return m_pAudioManager->isLoaded(type);
}
}
ukui-volume-control/backend/ManagerFactory.h 0000664 0001750 0001750 00000002431 15171074712 020107 0 ustar feng feng /* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*-
* -*- coding: utf-8 -*-
*
* Copyright (C) 2025 KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#ifndef MANAGERFACTORY_H
#define MANAGERFACTORY_H
#include
#include "AudioManager.h"
namespace UkuiAudioFramwork
{
class ManagerFactory
{
public:
ManagerFactory() = default;
virtual ~ManagerFactory() = default;
public:
virtual std::shared_ptr createManager() = 0;
private:
ManagerFactory(const ManagerFactory&) = delete;
ManagerFactory(ManagerFactory&&) = delete;
void operator=(const ManagerFactory&) = delete;
void operator=(ManagerFactory&&) = delete;
};
}
#endif // MANAGERFACTORY_H
ukui-volume-control/backend/PipewireNodeListmodel.cpp 0000664 0001750 0001750 00000017027 15171074712 022016 0 ustar feng feng /* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*-
* -*- coding: utf-8 -*-
*
* Copyright (C) 2025 KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#include "PipewireNodeListmodel.h"
#include
namespace UkuiAudioFramwork
{
PipewireNodeListModel::PipewireNodeListModel(/*QObject *parent*/)
// : QAbstractListModel(parent)
{}
PipewireNodeListModel::~PipewireNodeListModel()
{}
void PipewireNodeListModel::sortList()
{
// emit layoutAboutToBeChanged();
std::vector old = m_nodes;
// std::sort(old.begin(), old.end(), [](QPipewireNode*a, QPipewireNode*b) {
// return a->nodeName() > b->nodeName();
// });
m_nodes.clear();
for (PipewireNode* device : old) {
if (device->driver() == nullptr) {
m_nodes.push_back(device);
for(PipewireNode* client : old) {
if (device == client->driver()) {
m_nodes.push_back(client);
}
}
}
}
// emit layoutChanged();
}
void PipewireNodeListModel::append(PipewireNode* node)
{
// qWarning() << "Adding new node " << node->name();
// beginInsertRows(QModelIndex(), m_nodes.size(), m_nodes.size());
// node->connect(node, &QPipewireNode::idChanged, this, [this, node]() {this->rowChanged(node, IDRole); });
// node->connect(node, &QPipewireNode::activeChanged, this, [this, node]() {this->rowChanged(node, ActiveRole);});
// node->connect(node, &QPipewireNode::rateChanged, this, [this, node]() {this->rowChanged(node, RateRole); });
// node->connect(node, &QPipewireNode::quantumChanged, this, [this, node]() {this->rowChanged(node, QuantumRole); });
// node->connect(node, &QPipewireNode::waitingChanged, this, [this, node]() {this->rowChanged(node, WaitRole); });
// node->connect(node, &QPipewireNode::busyChanged, this, [this, node]() {this->rowChanged(node, BusyRole); });
// node->connect(node, &QPipewireNode::nameChanged, this, [this, node]() {this->rowChanged(node, NameRole); });
// node->connect(node, &QPipewireNode::driverChanged, this, [this, node]() {this->rowChanged(node, DriverIDRole);});
// node->connect(node, &QPipewireNode::driverChanged, this, &QPipewireNodeListModel::sortList);
m_nodes.push_back(node);
// endInsertRows();
sortList();
}
bool PipewireNodeListModel::removeOne(PipewireNode* node)
{
// qWarning() << "Removing node" << node->name();
std::cout << "Removing node" << node->name() << std::endl;
// int index = m_nodes.indexOf(node);
// if (index != -1) {
// return removeAt(index);
// } else {
// return false;
// }
}
bool PipewireNodeListModel::removeAt(int index)
{
if (index >= 0 && index < m_nodes.size()) {
std::cout << "remove at : " << index << std::endl;
// beginRemoveRows(QModelIndex(), index, index);
// m_nodes.removeAt(index);
// endRemoveRows();
return true;
} else {
return false;
}
}
//int PipewireNodeListModel::rowCount(const QModelIndex &/*parent*/) const
//{
// return m_nodes.size();
//}
//QVariant QPipewireNodeListModel::data(const QModelIndex &index, int _role) const
//{
// int role = NodeRoles(_role);
// int i = index.row();
// QPipewireNode *node = m_nodes.at(i);
// switch (role) {
// case IndexRole:
// return i;
// case NodeRole:
// case Qt::DisplayRole:
// {
// if (node) {
// QVariant vNode;
// vNode.setValue(node);
// return vNode;
// } else {
// return QVariant(QVariant::Invalid);
// }
// }
// case IDRole:
// return node ? node->id() : QVariant("nullptr");
// case ActiveRole:
// return node ? node->active() : false;
// case RateRole:
// return node ? node->rate() : QVariant("nullptr");
// case QuantumRole:
// return node ? node->quantum() : QVariant("nullptr");
// case WaitRole:
// return node ? node->waiting() : 0.0;
// case BusyRole:
// return node ? node->busy() : 0.0;
// case NameRole:
// return node ? node->name() : "[deleted]";
// case DriverIDRole:
// if (node && node->driver()) {
// return node->driver()->id();
// } else {
// return -1;
// }
// default:
// qWarning() << "UNDEFINED ROLE" << _role;
// throw std::runtime_error("Undefined role");
// }
//}
//QVariant QPipewireNodeListModel::headerData(int section, Qt::Orientation orientation, int role) const
//{
// switch (role) {
// case IndexRole:
// return "Index";
// case NodeRole:
// case Qt::DisplayRole:
// return "Node";
// case IDRole:
// return QVariant("ID");
// case ActiveRole:
// return QVariant("Active");
// case RateRole:
// return QVariant("Rate");
// case QuantumRole:
// return QVariant("Quantum");
// case WaitRole:
// return QVariant("Wait");
// case BusyRole:
// return QVariant("Busy");
// case NameRole:
// return QVariant("Name");
// case DriverIDRole:
// return QVariant("Driver");
// default:
// qWarning() << "UNDEFINED ROLE" << role;
// throw std::runtime_error("Undefined role");
// }
//}
//bool QPipewireNodeListModel::insertRows(int position, int count, const QModelIndex& parent)
//{
// beginInsertRows(parent, position, position+count-1);
// for(int i=0; i QPipewireNodeListModel::roleNames() const
//{
// return {
// { IndexRole, "index" },
// { NodeRole, "node" },
// { Qt::DisplayRole, "display"},
// { IDRole, "id" },
// { ActiveRole, "active" },
// { RateRole, "rate" },
// { QuantumRole, "quantum" },
// { WaitRole, "wait" },
// { BusyRole, "busy" },
// { NameRole, "name" },
// { DriverIDRole, "driverID" },
// };
//}
//void QPipewireNodeListModel::rowChanged(QPipewireNode* node, int role)
//{
// int index = m_nodes.indexOf(node);
// QModelIndex topLeft = createIndex(index, 0);
// QModelIndex bottomRight = createIndex(index, 0);
// emit dataChanged(topLeft, bottomRight, {role});
//}
//void QPipewireNodeListModel::move(int from, int to)
//{
// if (from == to) return;
// int n=1;
// if (from > to) {
// // Only move forwards - flip if backwards moving
// int tfrom = from;
// int tto = to;
// from = tto;
// to = tto+n;
// n = tfrom-tto;
// }
// beginMoveRows(QModelIndex(), from, from+n-1, QModelIndex(), to+n);
// for (int i=n-1; i>=0; i--)
// m_nodes.move(from+i, to);
// endMoveRows();
//}
}
ukui-volume-control/backend/MediaAutoPauseModule.h 0000664 0001750 0001750 00000003032 15171074712 021217 0 ustar feng feng /* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*-
* -*- coding: utf-8 -*-
*
* Copyright (C) 2025 KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#ifndef MEDIAAUTOPAUSEMODULE_H
#define MEDIAAUTOPAUSEMODULE_H
#include "RestoreVolumeJson.h"
namespace UkuiAudioFramwork
{
class MediaAutoPauseModule
{
public:
static MediaAutoPauseModule& getInstance();
void setJson(std::shared_ptr);
bool getAutoPauseStatus();
void setAutoPauseStatus(bool);
private:
MediaAutoPauseModule() = default;
MediaAutoPauseModule(const MediaAutoPauseModule&) = delete;
MediaAutoPauseModule(MediaAutoPauseModule&&) = delete;
MediaAutoPauseModule operator=(const MediaAutoPauseModule&) = delete;
MediaAutoPauseModule operator=(MediaAutoPauseModule&&) = delete;
virtual ~MediaAutoPauseModule() = default;
private:
std::shared_ptr m_pJson = nullptr;
};
}
#endif // MEDIAAUTOPAUSEMODULE_H
ukui-volume-control/backend/PaSinkInputStream.h 0000664 0001750 0001750 00000010746 15171074712 020576 0 ustar feng feng /* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*-
* -*- coding: utf-8 -*-
*
* Copyright (C) 2025 KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#ifndef PASINKINPUTSTREAM_H
#define PASINKINPUTSTREAM_H
#include "IStream.h"
#include "AudioContext.h"
namespace UkuiAudioFramwork
{
class PaSinkInputStream : public IStream
{
public:
PaSinkInputStream(pa_context* ctx, PaDataInfo& info)
: IStream(ctx, info, StreamType::STREAM_TYPE_SINKINPUT) {}
~PaSinkInputStream() = default;
public:
void copy(const pa_sink_input_info&);
std::string getMediaRole() const;
std::string getAppIconName() const;
std::string getProcessBinary() const;
std::string getDriver() const;
uint32_t getSink() const;
virtual std::string toString() const override;
virtual NodeType getNodeType() const override;
virtual uint32_t getIndex() const override;
virtual std::string getName() const override;
virtual pa_proplist* getProplist() const override;
virtual uint32_t getCard() const override;
virtual void setVolume(int) override;
virtual const pa_cvolume getVolume() const override;
virtual void setBalance(double) override;
virtual double getBalance() const override;
virtual void setMute(bool) override;
virtual bool getMute() const override;
virtual DefaultDeviceInfo getDefaultDevice() const override;
virtual void setDefaultDevice(const std::string&, const std::string&) override;
virtual std::vector getDeviceList() const override;
virtual std::list> getAvailablePortList() const override;
virtual void volumeChanged(int) override;
virtual void muteChanged(bool) override;
virtual void portChanged(const std::string&) override;
virtual void deviceChanged(bool = false) override;
private:
uint32_t index {PA_INVALID_INDEX}; /**< Index of the sink input */
std::string name {""}; /**< Name of the sink input */
uint32_t owner_module {PA_INVALID_INDEX}; /**< Index of the module this sink input belongs to, or PA_INVALID_INDEX when it does not belong to any module. */
uint32_t client {PA_INVALID_INDEX}; /**< Index of the client this sink input belongs to, or PA_INVALID_INDEX when it does not belong to any client. */
uint32_t sink {PA_INVALID_INDEX}; /**< Index of the connected sink */
pa_sample_spec sample_spec; /**< The sample specification of the sink input. */
pa_channel_map channel_map; /**< Channel map */
pa_cvolume volume; /**< The volume of this sink input. */
pa_usec_t buffer_usec; /**< Latency due to buffering in sink input, see pa_timing_info for details. */
pa_usec_t sink_usec; /**< Latency of the sink device, see pa_timing_info for details. */
std::string resample_method {""}; /**< The resampling method used by this sink input. */
std::string driver {""}; /**< Driver name */
int mute {0}; /**< Stream muted \since 0.9.7 */
pa_proplist* proplist; /**< Property list \since 0.9.11 */
int corked {0}; /**< Stream corked \since 1.0 */
int has_volume {0}; /**< Stream has volume. If not set, then the meaning of this struct's volume member is unspecified. \since 1.0 */
int volume_writable {0}; /**< The volume can be set. If not set, the volume can still change even though clients can't control the volume. \since 1.0 */
pa_format_info *format {nullptr}; /**< Stream format information. \since 1.0 */
std::string role {""};
std::string m_appIconName {""}; /**< stream icon name */
std::string m_processBinary {""}; /**< stream process binary */
};
}
#endif // PASINKINPUTSTREAM_H
ukui-volume-control/backend/utils.h 0000664 0001750 0001750 00000002055 15171074712 016347 0 ustar feng feng /* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*-
* -*- coding: utf-8 -*-
*
* Copyright (C) 2025 KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#pragma once
#include
#include
#include
namespace UkuiAudioFramwork
{
void print_dict(const struct spa_dict* dictionary);
uint32_t spa_dict_get_u32(const spa_dict* props, const char* key);
std::ostream& operator<< (std::ostream& out, const spa_pod& pod);
}
ukui-volume-control/backend/RestoreVolumeJson.cpp 0000664 0001750 0001750 00000010516 15171074712 021210 0 ustar feng feng /* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*-
* -*- coding: utf-8 -*-
*
* Copyright (C) 2025 KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#include "RestoreVolumeJson.h"
#include "AudioContext.h"
namespace UkuiAudioFramwork
{
template
void updateField(nlohmann::json& jsonObj, const std::string& key, const T& value) {
if (jsonObj[key] != value) {
jsonObj[key] = value;
}
}
template
T getMemberValue(const RestoreVolumeInfo& info, T RestoreVolumeInfo::* memberPtr) {
return info.*memberPtr;
}
bool RestoreVolumeJson::getStatus(const std::string& cardName, const std::string& portName, const std::string& key) const
{
auto& ports = m_json[cardName]["ports"];
auto portIt = ports.find(portName);
if (portIt != ports.end()) {
return (*portIt)[key];
}
AUDIO_ERROR("Can not get the mute status of sound card: {} port: {}, the device does not exist", cardName, portName);
return true;
}
void RestoreVolumeJson::insert(const RestoreVolumeInfo& info) {
auto& ports = m_json[info.cardName]["ports"];
auto portIt = ports.find(info.portName);
if (portIt == ports.end()) {
ports[info.portName] = {
{"name", info.portName},
{"volume", info.volume},
{"priority", info.priority},
{"balance", info.balance},
{"enable", info.enable},
{"mute", info.muted}
};
} else {
nlohmann::json& portJson = *portIt;
for (const auto& [key, memberVar] : m_filedMap) {
std::visit([&](auto&& ptr) {
using T = std::decay_t;
if constexpr (std::is_same_v) {
updateField(portJson, key, info.*ptr);
} else if constexpr (std::is_same_v || std::is_same_v) {
updateField(portJson, key, info.*ptr);
}
}, memberVar);
}
}
writeToJson();
}
RestoreVolumeJson::RestoreVolumeJson()
{
m_fileName = getenv("HOME");
m_fileName += RESTORE_VOLUME_JSON;
loadJson();
initJson();
}
bool RestoreVolumeJson::isContain(const RestoreVolumeInfo& info) const
{
const auto& card = m_json.find(info.cardName);
if (card != m_json.end()) {
const auto& port = (*card)["ports"].find(info.portName);
return port != (*card)["ports"].end();
}
return false;
}
void RestoreVolumeJson::initJson()
{
auto autoPause = m_json.find("auto-pause");
if (autoPause == m_json.end()) {
m_json["auto-pause"] = false;
}
writeToJson();
}
//template
//std::optional RestoreVolumeJson::getValue(const std::string& cardName, const std::string& portName, const std::string& key) const {
// auto cardIt = m_json.find(cardName);
// if (cardIt != m_json.end()) {
// auto& cardJson = cardIt.second;
// auto portsIt = cardJson.find("ports");
// if (portsIt != cardJson.end()) {
// auto& portsJson = portsIt->second;
// auto portIt = portsJson.find(portName);
// if (portIt != portsJson.end()) {
// auto& portJson = portIt->second;
// if (portJson.contains(key)) {
// return portJson[key].get();
// }
// }
// }
// }
// return std::nullopt;
//}
std::optional RestoreVolumeJson::getValue(const std::string& key) const
{
auto it = m_json.find(key);
if (it != m_json.end()) {
return it->get();
}
return std::nullopt;
}
void RestoreVolumeJson::setValue(const std::string& key, bool status)
{
auto autoPause = m_json.find(key);
if (autoPause != m_json.end()) {
m_json[key] = status;
}
writeToJson();
}
}
ukui-volume-control/backend/SoundThemeModule.h 0000664 0001750 0001750 00000004570 15171074712 020434 0 ustar feng feng /* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*-
* -*- coding: utf-8 -*-
*
* Copyright (C) 2025 KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#ifndef SOUNDTHEME_H
#define SOUNDTHEME_H
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
namespace UkuiAudioFramwork
{
typedef struct SoundThemeInfo {
std::string name; // 音效主题的名称
std::string description; // 音效主题的描述
std::string toString() const;
} SoundThemeInfo;
typedef struct SoundEffectFileInfo {
std::string name;
std::string description;
std::string toString() const;
} SoundEffectFileInfo;
class SoundThemeModule
{
public:
static SoundThemeModule& getInstance();
public:
std::list getSoundThemeList();
std::list getSoundEffectFileList(const std::string&);
private:
std::string getIndexThemeName(const std::string&);
void soundThemeInDir(GHashTable*, const std::string&);
void setupThemeSelector();
std::vector getSoundThemeXmlFiles(const std::vector& soundDirs);
std::vector getSoundListFromXml(const std::string& xmlFilePath);
bool isExistDirPath(const std::string&);
private:
SoundThemeModule() = default;
SoundThemeModule(const SoundThemeModule&) = delete;
SoundThemeModule(SoundThemeModule&&) = delete;
SoundThemeModule operator=(const SoundThemeModule&) = delete;
SoundThemeModule operator=(SoundThemeModule&&) = delete;
virtual ~SoundThemeModule() = default;
private:
std::list m_soundThemeList {};
};
}
#endif // SOUNDTHEME_H
ukui-volume-control/backend/SoundThemePlayerSetting.h 0000664 0001750 0001750 00000003346 15171074712 022001 0 ustar feng feng /* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*-
* -*- coding: utf-8 -*-
*
* Copyright (C) 2025 KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#ifndef SOUNDTHEMEPLAYERSETTING_H
#define SOUNDTHEMEPLAYERSETTING_H
#include
#include
#include "ISetting.h"
namespace UkuiAudioFramwork
{
#define SOUND_THEME_PLAYER_SCHEMA "org.ukui.media.sound"
#define SOUND_THEME_PLAYER_PATH "/org/ukui/sound/keybindings/"
#define SOUND_FILENAME_KEY "filename"
#define SOUND_NAME_KEY "name"
class SoundThemePlayerSetting : public ISetting
{
public:
SoundThemePlayerSetting();
~SoundThemePlayerSetting();
public:
void initConnect();
virtual void initSettings() override;
virtual GVariant* getValue(const char*) const override;
virtual void setValue(const char*, GVariant*) override;
virtual bool isContainKeys(const char*) const override;
private:
static void onSettingsChanged(GSettings*, const gchar*);
private:
GSettings* m_pSettings = nullptr;
GSettingsSchema* m_pSchema = nullptr;
GSettingsSchemaSource* m_pSource = nullptr;
};
}
#endif // SOUNDTHEMEPLAYERSETTING_H
ukui-volume-control/backend/PipewireManagerFactory.cpp 0000664 0001750 0001750 00000002247 15171074712 022154 0 ustar feng feng /* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*-
* -*- coding: utf-8 -*-
*
* Copyright (C) 2025 KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#include "PipewireManagerFactory.h"
#include "PipewireManager.h"
#include "PipewireManager1.h"
namespace UkuiAudioFramwork
{
std::shared_ptr PipewireManagerFactory::createManager()
{
// return std::make_shared(5);
std::shared_ptr manager = std::make_shared(nullptr, nullptr);
std::dynamic_pointer_cast(manager)->round_trip();
return manager;
}
}
ukui-volume-control/backend/PaSourceStream.cpp 0000664 0001750 0001750 00000045152 15171074712 020444 0 ustar feng feng /* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*-
* -*- coding: utf-8 -*-
*
* Copyright (C) 2025 KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#include "PaSourceStream.h"
#include
#include "AudioMethod.h"
#include "PaSourceOutputStream.h"
namespace UkuiAudioFramwork
{
std::shared_ptr PaSourceStream::getActivePort() const
{
return active_port;
}
std::string PaSourceStream::getActivePortName() const
{
return (this && active_port) ? active_port->name : "";
}
std::string PaSourceStream::getActivePortDescription() const
{
return (this && active_port) ? active_port->description : "";
}
std::string PaSourceStream::getCardName() const
{
return cardName;
}
std::string PaSourceStream::getDeviceClass() const
{
return m_deviceClass;
}
void PaSourceStream::setMasterDevice(const std::string& master)
{
AUDIO_DEBUG("Set {} master device to {}.", name, master);
m_masterDevice = master;
}
std::string PaSourceStream::getMasterDevice() const
{
AUDIO_DEBUG("Get {} master device: {}.", name, m_masterDevice);
return m_masterDevice;
}
void PaSourceStream::copy(const pa_source_info& other)
{
auto it = std::find_if(m_info.cardInfoList.begin(), m_info.cardInfoList.end(),
[other](const std::shared_ptr c) {
return c->card.index == other.card;
});
if (it != m_info.cardInfoList.end()) {
cardName = (*it)->card.name;
}
else {
cardName = "";
}
if (PA_INVALID_INDEX != index) {
if (!pa_cvolume_equal(&volume, &other.volume) && index == other.index) {
volumeChanged(paCvolumeToValue(other.volume));
}
if (mute != other.mute && index == other.index) {
muteChanged(!mute);
}
if (active_port && other.active_port && g_strcmp0(active_port->name.c_str(), other.active_port->name)) {
portChanged(other.active_port->name);
}
}
name = other.name;
index = other.index;
description = other.description;
sample_spec = other.sample_spec;
channel_map = other.channel_map;
owner_module = other.owner_module;
volume = other.volume;
mute = other.mute;
monitor_of_sink = other.monitor_of_sink;
monitor_of_sink_name = other.monitor_of_sink_name ? other.monitor_of_sink_name : "";
latency = other.latency;
driver = other.driver;
flags = other.flags;
proplist = other.proplist;
configured_latency = other.configured_latency;
base_volume = other.base_volume;
state = other.state;
n_volume_steps = other.n_volume_steps;
card = other.card;
n_ports = other.n_ports;
n_formats = other.n_formats;
formats = other.formats;
//start
tmpMute = mute;
//end
AUDIO_DEBUG("copy this.mute: {} other.mute: {}.", this->mute, other.mute);
auto deviceClass = pa_proplist_gets(proplist, PA_PROP_DEVICE_CLASS);
m_deviceClass = deviceClass ? deviceClass : "";
if (std::string::npos != name.find("noiseReduceSource")) {
auto it = std::find_if(m_info.sourceOutputList.begin(), m_info.sourceOutputList.end(), [](const std::shared_ptr& s) {
auto driver = std::dynamic_pointer_cast(s)->getDriver();
return driver == "module-echo-cancel.c";
});
if (it != m_info.sourceOutputList.end()) {
auto sourceIdx = std::dynamic_pointer_cast(*it)->getSource();
for (const auto& c : m_info.cardInfoList) {
auto source = std::find_if(c->sources.begin(), c->sources.end(), [sourceIdx](const std::shared_ptr& s) {
return sourceIdx == s->getIndex();
});
if (source != c->sources.end()) {
setMasterDevice((*source)->getName());
//start synchronous masterdevice mute status
setMute((*source)->getMute());
//end
}
}
}
}
else {
auto masterDevice = pa_proplist_gets(proplist, PA_PROP_DEVICE_MASTER_DEVICE);
m_masterDevice = masterDevice ? masterDevice : "";
}
ports.clear();
for (int i = 0; i < n_ports; ++i) {
ports.push_back(std::make_shared(cardName, *other.ports[i]));
}
active_port = other.active_port ? std::make_shared(cardName, *other.active_port) : nullptr;
}
std::vector> PaSourceStream::getPorts() const
{
return ports;
}
std::string PaSourceStream::toString() const
{
std::string vol = "[";
for (int i = 0; i < volume.channels; ++i) {
vol += std::to_string(volume.values[i]);
vol += ", ";
}
vol += "]";
std::string activePortName = (active_port) ? active_port->name : "";
return FORMAT("name={}, index={}, description={}, card={}, n_ports={}, active_port={}, "
"volume={}, mute={}, state={}, monitor_of_sink={}, monitor_of_sink_name={}",
name, index, description, card, n_ports, activePortName,
vol, mute, state, monitor_of_sink, monitor_of_sink_name);
}
NodeType PaSourceStream::getNodeType() const
{
return NodeType::INPUT;
}
uint32_t PaSourceStream::getIndex() const
{
return index;
}
std::string PaSourceStream::getName() const
{
return name;
}
pa_proplist* PaSourceStream::getProplist() const
{
return proplist;
}
uint32_t PaSourceStream::getCard() const
{
return card;
}
void PaSourceStream::setVolume(int value)
{
auto v = volume;
for (int i = 0; i < v.channels; ++i) {
v.values[i] = value;
}
if (pa_cvolume_equal(&v, &volume))
return;
pa_context_set_source_volume_by_index(m_pContext, index, &v, nullptr, nullptr);
}
const pa_cvolume PaSourceStream::getVolume() const
{
return volume;
}
void PaSourceStream::setBalance(double v)
{
if (channel_map.channels == 1) {
AUDIO_ERROR("source {} is not support set balance.", name);
return;
}
pa_cvolume_set_balance(&volume, &channel_map, v);
pa_context_set_sink_volume_by_index(m_pContext, index, &volume, nullptr, nullptr);
}
double PaSourceStream::getBalance() const
{
return pa_cvolume_get_balance(&volume, &channel_map);
}
void PaSourceStream::setMute(bool mute)
{
AUDIO_DEBUG("setMute: mute: {} this.mute:{} tmpMute:{} .", mute, this->mute, tmpMute);
//start hand asynchronous time issues
tmpMute = mute;
//end
//start synchronous masterdevice mute status
if (std::string::npos != name.find("noiseReduceSource")) {
auto it = std::find_if(m_info.sourceOutputList.begin(), m_info.sourceOutputList.end(), [](const std::shared_ptr& s) {
auto driver = std::dynamic_pointer_cast(s)->getDriver();
return driver == "module-echo-cancel.c";
});
if (it != m_info.sourceOutputList.end()) {
auto sourceIdx = std::dynamic_pointer_cast(*it)->getSource();
for (const auto& c : m_info.cardInfoList) {
auto source = std::find_if(c->sources.begin(), c->sources.end(), [sourceIdx](const std::shared_ptr& s) {
return sourceIdx == s->getIndex();
});
if (source != c->sources.end()) {
AUDIO_DEBUG("setMute getName:{} .", (*source)->getName());
(*source)->setMute(mute);
}
}
}
}
//end
pa_context_set_source_mute_by_index(m_pContext, index, mute, nullptr, nullptr);
}
bool PaSourceStream::getMute() const
{
//start hand asynchronous time issues
return tmpMute;
//end
// return mute;
}
DefaultDeviceInfo PaSourceStream::getDefaultDevice() const
{
DefaultDeviceInfo info;
info.idx = m_info.defaultSource->index;
info.name = m_info.defaultSource->name;
if ("filter" == m_info.defaultSource->getDeviceClass()) {
std::string masterDevice = "";
for (const auto& c : m_info.cardInfoList) {
auto it = std::find_if(c->sources.begin(), c->sources.end(), [this](const std::shared_ptr& s) {
return m_info.defaultSource->getName() == s->getName();
});
if (it != c->sources.end()) {
auto source = std::dynamic_pointer_cast(*it);
masterDevice = source->getMasterDevice();
AUDIO_DEBUG("Get {} master device: {}.", m_info.defaultSource->getName(), masterDevice);
break;
}
}
for (const auto& c : m_info.cardInfoList) {
auto it = std::find_if(c->sources.begin(), c->sources.end(), [masterDevice](const std::shared_ptr& s) {
return masterDevice == s->getName();
});
if (it != c->sources.end()) {
info.cardName = c->card.name;
auto sourceStream = std::dynamic_pointer_cast(*it);
if (sourceStream) {
info.activePortName = sourceStream->getActivePortName();
info.activePortLabel = sourceStream->getActivePortDescription();
}
break;
}
}
}
else {
info.cardName = m_info.defaultSource->cardName;
info.activePortName = m_info.defaultSource->active_port ? m_info.defaultSource->active_port->name : "";
info.activePortLabel = m_info.defaultSource->active_port ? m_info.defaultSource->active_port->description : "";
}
return info;
}
void PaSourceStream::setDefaultDevice(const std::string& name, const std::string& dev)
{
bool found = false;
bool setPort = false;
bool setProfile = false;
std::string profileName = "";
std::string sourceName = "";
uint32_t sourceIdx = PA_INVALID_INDEX, cardIdx = PA_INVALID_INDEX;
for (const auto& c : m_info.cardInfoList) {
if (0 == strcmp(dev.c_str(), c->card.name.c_str())) {
cardIdx = c->card.index;
for (const auto& p : c->card.ports) {
if (PA_DIRECTION_OUTPUT == p->direction)
continue;
if (strcmp(name.c_str(), p->name.c_str()))
continue;
if (m_info.defaultSource->card == cardIdx && contains(m_info,
[name](PaDataInfo& data) -> std::vector> {
if (data.defaultSource) {
return data.defaultSource->ports;
}
return {};
},
name)) {
setPort = true;
sourceIdx = m_info.defaultSource->getIndex();
goto success;
}
else {
if (contains(m_info,
[&p] (PaDataInfo& data) -> std::vector> {
return p->profiles2;
},
c->card.active_profile->name)) {
for (const auto& s : c->sources) {
for (const auto &p : std::dynamic_pointer_cast(s)->ports) {
if (p->name == name) {
sourceName = s->getName();
goto success;
}
}
}
}
else {
int pri = 0;
for (const auto& profile : p->profiles2) {
if (0 == profile->available)
continue;
if (pri < profile->priority) {
setProfile = true;
pri = profile->priority;
profileName = profile->name;
}
}
}
}
}
}
}
if (!found)
AUDIO_DEBUG("Card: {} port: {} not found.", dev, name);
success:
if (setProfile) {
std::thread([cardIdx, profileName, this] () {
std::unique_lock lock(m_info.m_mtx);
m_info.m_operation = false;
pa_context_set_card_profile_by_index(m_pContext, cardIdx, profileName.c_str(), nullptr, this);
}).join();
// 设置default source线程,等待主线程cardInfoList更新完毕之后在去设置default source
std::thread([cardIdx, name, this] () {
std::unique_lock lock(m_info.m_mtx);
if (!m_info.m_operation)
m_info.m_cond.wait_for(lock, std::chrono::milliseconds(3000));
if (m_info.m_operation) {
m_info.m_operation = false;
for (const auto& c: m_info.cardInfoList) {
if (c->card.index == cardIdx) {
for (const auto& s : c->sources) {
for (const auto& p : std::dynamic_pointer_cast(s)->ports) {
if (p->name == name) {
AUDIO_DEBUG("Set deault source to {} port: {}.", s->getName(), name);
pa_context_set_source_port_by_name(m_pContext, s->getName().c_str(), name.c_str(), nullptr, nullptr);
pa_context_set_default_source(m_pContext, s->getName().c_str(), nullptr, nullptr);
return;
}
}
}
}
}
}
}).detach();
}
if (setPort)
pa_context_set_source_port_by_index(m_pContext, sourceIdx, name.c_str(), nullptr, nullptr);
if ("" != sourceName) {
AUDIO_DEBUG("Set default source to {}.", sourceName);
pa_context_set_default_source(m_pContext, sourceName.c_str(), nullptr, nullptr);
}
}
std::vector PaSourceStream::getDeviceList() const
{
}
std::list> PaSourceStream::getAvailablePortList() const
{
std::list> info;
for (const auto& c : m_info.cardInfoList) {
for (const auto& d : c->card.deviceList) {
if (PA_DIRECTION_INPUT == d->direction && PA_PORT_AVAILABLE_NO != d->available) {
info.push_back(d);
}
}
}
return info;
}
void PaSourceStream::volumeChanged(int volume)
{
AudioMethod::getInstance().volumeChanged(NodeType::INPUT, index, volume);
}
void PaSourceStream::muteChanged(bool mute)
{
AudioMethod::getInstance().muteChanged(NodeType::INPUT, index, mute);
}
void PaSourceStream::portChanged(const std::string& name)
{
AudioMethod::getInstance().portChanged(NodeType::INPUT, name);
}
void PaSourceStream::deviceChanged(bool autoPause)
{
std::string portName, deviceName;
if ("filter" == m_deviceClass) {
for (const auto& c : m_info.cardInfoList) {
auto it = std::find_if(c->sources.begin(), c->sources.end(), [this](const std::shared_ptr& s) {
return m_masterDevice == s->getName();
});
if (it != c->sources.end()) {
deviceName = c->card.name;
auto sourceStream = std::dynamic_pointer_cast(*it);
if (sourceStream) {
portName = sourceStream->getActivePortName();
}
break;
}
}
}
else {
portName = active_port ? active_port->name : "";
deviceName = cardName;
if (AudioMethod::getInstance().isLoaded(ModuleType::MODULE_ECHO_CANCEL)) {
auto it = std::find_if(m_info.sourceOutputList.begin(), m_info.sourceOutputList.end(), [](const std::shared_ptr& s) {
auto driver = std::dynamic_pointer_cast(s)->getDriver();
return driver == "module-echo-cancel.c";
});
if (it != m_info.sourceOutputList.end() && deviceName.find("alsa_card.usb") == std::string::npos
&& deviceName.find("bluez_card") == std::string::npos) {
AUDIO_DEBUG("prepare set {} default device, card: {}, port: {}.", (*it)->getName(), deviceName, portName);
(*it)->setDefaultDevice(portName, deviceName);
// 更新noiseReduceSource的master device
// std::unique_lock lock(m_info.m_mtx);
for (const auto& c : m_info.cardInfoList) {
auto source = std::find_if(c->sources.begin(), c->sources.end(), [](const std::shared_ptr& s) {
return std::string::npos != s->getName().find("noiseReduceSource");
});
if (source != c->sources.end()) {
auto masterDevice = m_info.defaultSource->getName();
// 同步default source的音量和静音状态
AUDIO_DEBUG("noiseReduceSource masterDevice defaultSource: {} getMute: {}, source getMute: {}."
, masterDevice, m_info.defaultSource->getMute(), (*source)->getMute());
(*source)->setMute(m_info.defaultSource->getMute());
auto volume = m_info.defaultSource->getVolume();
auto value = paCvolumeToPaValue(volume);
AUDIO_DEBUG("noiseReduceSource value:{} .", value);
(*source)->setVolume(value);
std::dynamic_pointer_cast(*source)->setMasterDevice(masterDevice);
break;
}
}
pa_context_set_default_source(m_pContext, "noiseReduceSource", nullptr, nullptr);
}
}
}
AudioMethod::getInstance().deviceChanged(NodeType::INPUT, portName, deviceName);
}
}
ukui-volume-control/backend/AudioSetting.cpp 0000664 0001750 0001750 00000007407 15171074712 020147 0 ustar feng feng /* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*-
* -*- coding: utf-8 -*-
*
* Copyright (C) 2025 KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#include "AudioSetting.h"
#include "AudioContext.h"
#include "AudioMethod.h"
namespace UkuiAudioFramwork
{
AudioSetting::AudioSetting()
{
initSettings();
initConnect();
}
AudioSetting::~AudioSetting()
{
if (m_pSchema)
g_settings_schema_unref(m_pSchema);
if (m_pSource)
g_settings_schema_source_unref(m_pSource);
if (m_pSettings)
g_object_unref(m_pSettings);
}
void AudioSetting::initSettings()
{
m_pSource = g_settings_schema_source_get_default();
m_pSchema = g_settings_schema_source_lookup(m_pSource, UKUI_SOUND_SCHEMA, true);
if (!m_pSchema) {
AUDIO_ERROR("schema error, failed to create {} settings", UKUI_SOUND_SCHEMA);
return;
}
m_pSettings = g_settings_new_with_path(UKUI_SOUND_SCHEMA, UKUI_SOUND_PATH);
}
void AudioSetting::onSettingsChanged(GSettings* settings, const gchar* key)
{
AudioMethod::getInstance().settingsChanged(key, g_settings_get_value(settings, key));
}
void AudioSetting::initConnect()
{
g_signal_connect(G_OBJECT(m_pSettings),
"changed",
G_CALLBACK(onSettingsChanged),
nullptr);
}
GVariant* AudioSetting::getValue(const char* key) const
{
if (!m_pSettings || !m_pSchema) return g_variant_new("");
if (!isContainKeys(key)) return g_variant_new("");
return g_settings_get_value(m_pSettings, key);
}
void AudioSetting::setValue(const char* key, GVariant* gvalue)
{
if (!m_pSettings || !m_pSchema) return;
if (!isContainKeys(key)) return;
GVariantClass variantClass = g_variant_classify(gvalue);
if (G_VARIANT_CLASS_STRING == variantClass) {
gsize length;
g_settings_set_string(m_pSettings, key, g_variant_get_string(gvalue, &length));
}
else if (G_VARIANT_CLASS_INT16 == variantClass) {
g_settings_set_int(m_pSettings, key, g_variant_get_int16(gvalue));
}
else if (G_VARIANT_CLASS_UINT16 == variantClass) {
g_settings_set_int(m_pSettings, key, g_variant_get_uint16(gvalue));
}
else if (G_VARIANT_CLASS_INT32 == variantClass) {
g_settings_set_int(m_pSettings, key, g_variant_get_int32(gvalue));
}
else if (G_VARIANT_CLASS_UINT32 == variantClass) {
g_settings_set_int(m_pSettings, key, g_variant_get_uint32(gvalue));
}
else if (G_VARIANT_CLASS_INT64 == variantClass) {
g_settings_set_int(m_pSettings, key, g_variant_get_int64(gvalue));
}
else if (G_VARIANT_CLASS_UINT64 == variantClass) {
g_settings_set_int(m_pSettings, key, g_variant_get_uint64(gvalue));
}
else if (G_VARIANT_CLASS_BOOLEAN == variantClass) {
g_settings_set_boolean(m_pSettings, key, g_variant_get_boolean(gvalue));
}
else {
AUDIO_DEBUG("Unknown variantClass");
}
}
bool AudioSetting::isContainKeys(const char* key) const
{
bool ret = false;
if (!m_pSettings || !m_pSchema) return ret;
gchar** keys = g_settings_schema_list_keys(m_pSchema);
if (g_strv_contains(keys, key))
ret = true;
g_strfreev(keys);
return ret;
}
}
ukui-volume-control/backend/AudioMethod.h 0000664 0001750 0001750 00000044607 15171074712 017422 0 ustar feng feng /* -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*-
* -*- coding: utf-8 -*-
*
* Copyright (C) 2025 KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#ifndef AUDIOMETHOD_H
#define AUDIOMETHOD_H
#include
#include
#include
#include "BaseType.h"
#include "ISetting.h"
#include "AudioSetting.h"
#include "GlobalThemeSettings.h"
#include "MediaAutoPauseModule.h"
#include "SoundThemeModule.h"
#include "SoundThemePlayerSetting.h"
#include "SessionManagerSetting.h"
#include "AudioManager.h"
#include "DbusServer.h"
#include "MultiAudioCombineJson.h"
namespace UkuiAudioFramwork
{
class AudioDBusServer;
class AudioMethod
{
public:
static AudioMethod& getInstance();
void setManager(std::shared_ptr);
void init();
void run();
/**
* @brief 获取当前桌面环境版本信息
*
* @return 返回当前桌面环境版本信息
*/
DesktopEnvironmentVersion getDesktopEnvironmentVersion();
/**
* @brief 获取音频流的描述
*
* @param name 对应的desktop名称
* @return 音频流的描述
*/
std::string getStreamDescription(const std::string&);
/**
* @brief 初始化音量
*
* @param type 设备类型
* portName 端口名称
* cardName 声卡名称
* @return 无
*/
void initVolume(NodeType, const std::string&, const std::string&);
// Interface
/**
* @brief 加载模块
*
* @param name 模块名称,例module-echo-cancel
* param 模块参数
* @return 无
*/
void loadModule(const std::string&, const std::string&);
/**
* @brief 卸载模块
*
* @param name 模块名称,例module-echo-cancel
* @return 无
*/
void unloadModule(const std::string&);
// Method
/**
* @brief 获取音频后端名称
*
* @return 返回后端名
*/
std::string getBackend() const;
/**
* @brief 设置音频后端
*
* @param type 后端类型
* @return 无
*/
void setBackend(const BackendType&);
/**
* @brief 设置音量
*
* @param type 设置音量的类型,类型包括INPUT, OUTPUT, SINK_INPUT, SOURCE_OUTPUT
* name 对应的名称(如果是设置INPUT和OUTPUT音量,该参数为需要获取端口的名称,例如analog-output-speaker;
* 如果是设置SINK_INPUT和SOURCE_OUTPUT的音量,则将该参数设置成当前应用的名称)
* dev 设备名称(如果是设置INPUT和OUTPUT音量,该参数为对应端口的声卡名称;
* 如果是设置SINK_INPUT和SOURCE_OUTPUT的音量,则该值可设置为任意值)
* volume 设置的音量值
* @return 无
*/
void setDetailVolume(const NodeType&, const std::string&, const std::string&, int);
/**
* @brief 获取音量
*
* @param type 获取音量的类型,类型包括INPUT, OUTPUT, SINK_INPUT, SOURCE_OUTPUT
* name 对应的名称(如果是获取INPUT和OUTPUT音量,该参数为需要获取端口的名称,例如analog-output-speaker;
* 如果是获取SINK_INPUT和SOURCE_OUTPUT的音量,则将该参数设置成当前应用的名称)
* dev 设备名称(如果是获取INPUT和OUTPUT音量,该参数为对应端口的声卡名称;
* 如果是获取SINK_INPUT和SOURCE_OUTPUT的音量,则该值可设置为任意值)
* volume 设置的音量值
* @return 无
*/
int getDetailVolume(const NodeType&, const std::string&, const std::string&) const;
/**
* @brief 设置音量
*
* @param type 设置音量的类型,类型包括INPUT, OUTPUT, SINK_INPUT, SOURCE_OUTPUT
* index 音频流的索引(如果是设置INPUT和OUTPUT音量,则该值可设置为任意值;
* 如果是设置SINK_INPUT和SOURCE_OUTPUT的音量,则该值可设置为应用的索引)
* volume 设置的音量值
* @return 无
*/
void setVolume(const NodeType&, int, int);
/**
* @brief 获取音量
*
* @param type 获取音量的类型,类型包括INPUT, OUTPUT, SINK_INPUT, SOURCE_OUTPUT
* index 音频流的索引(如果是设置INPUT和OUTPUT音量,则该值可设置为任意值;
* 如果是获取SINK_INPUT和SOURCE_OUTPUT的音量,则将该参数设置成应用的索引)
* @return 返回获取的音量
*/
int getVolume(const NodeType&, int = -1) const;
/**
* @brief 设置平衡音量
*
* @param type 设置音量的类型,类型包括INPUT, OUTPUT, SINK_INPUT, SOURCE_OUTPUT
* volume 设置的音量值
* @return 无
*/
void setBalance(const NodeType&, double);
/**
* @brief 获取平衡音量
*
* @param type 获取音量的类型,类型包括INPUT, OUTPUT, SINK_INPUT, SOURCE_OUTPUT
* @return 返回平衡音量
*/
double getBalance(const NodeType&) const;
/**
* @brief 设置静音状态
*
* @param type 设置静音状态的类型,类型包括INPUT, OUTPUT, SINK_INPUT, SOURCE_OUTPUT
* name 对应的名称(如果是设置INPUT和OUTPUT的静音状态,该参数可为任意值;
* 如果是设置SINK_INPUT和SOURCE_OUTPUT的静音状态,则将该参数设置成当前应用的名称)
* dev 设备名称(如果是设置INPUT和OUTPUT的静音状态,该参数为对应端口的声卡名称;
* 如果是设置SINK_INPUT和SOURCE_OUTPUT的静音状态,则该值可设置为任意值)
* mute 设置的静音状态
* @return 无
*/
void setDetailMute(const NodeType&, const std::string&, const std::string&, bool);
/**
* @brief 获取静音状态
*
* @param type 获取静音的类型,类型包括INPUT, OUTPUT, SINK_INPUT, SOURCE_OUTPUT
* name 对应的名称(如果是获取INPUT和OUTPUT的静音状态,该参数为需要获取端口的名称,例如analog-output-speaker;
* 如果是获取SINK_INPUT和SOURCE_OUTPUT的静音状态,则将该参数设置成当前应用的名称)
* dev 设备名称(如果是获取INPUT和OUTPUT的静音状态,该参数为对应端口的声卡名称;
* 如果是获取SINK_INPUT和SOURCE_OUTPUT的静音状态,则该值可设置为任意值)
* @return 返回对应的静音状态
*/
bool getDetailMute(const NodeType&, const std::string&, const std::string&) const;
/**
* @brief 设置默认设备或应用的静音状态
*
* @param type 设置静音状态的类型,类型包括INPUT, OUTPUT, SINK_INPUT, SOURCE_OUTPUT
* name 音频流的索引(如果是设置INPUT和OUTPUT音量,则该值可设置为任意值;
* 如果是设置SINK_INPUT和SOURCE_OUTPUT的静音状态,则将该参数设置成当前应用的索引)
* mute 设置的静音状态
* @return 无
*/
void setMute(const NodeType&, int, bool);
/**
* @brief 获取静音状态
*
* @param type 获取静音的类型,类型包括INPUT, OUTPUT, SINK_INPUT, SOURCE_OUTPUT
* index 音频流的索引(如果是设置INPUT和OUTPUT音量,则该值可设置为任意值;
* 如果是获取SINK_INPUT和SOURCE_OUTPUT的静音状态,则将该参数设置成当前应用的索引)
* @return 返回对应的静音状态
*/
bool getMute(const NodeType&, int = -1) const;
/**
* @brief 获取默认的设备
*
* @param type 获取设备的类型,类型包括INPUT, OUTPUT, SINK_INPUT, SOURCE_OUTPUT
* index 音频流的索引(如果是设置INPUT和OUTPUT的默认设备,则该值可设置成-1
* 如果是设置SINK_INPUT和SOURCE_OUTPUT的默认设备,则该值可设置为应用的索引)
* @return 返回获取的默认设备名称
*/
DefaultDeviceInfo getDefaultDevice(const NodeType&, int) const;
/**
* @brief 设置默认的设备
*
* @param type 设置默认设备的类型,类型包括INPUT, OUTPUT, SINK_INPUT, SOURCE_OUTPUT
* idx 音频流的索引(如果是设置INPUT和OUTPUT的默认设备,则该值可设置成-1
* 如果是设置SINK_INPUT和SOURCE_OUTPUT的默认设备,则该值可设置为应用的索引)
* name 端口名称(该参数为需要设置端口的名称,例如analog-output-speaker)
* dev 声卡名称(该参数为对应端口的声卡名称)
* @return 无
*/
void setDefaultDevice(const NodeType&, int idx, const std::string&, const std::string&);
std::vector getDeviceList(const NodeType&) const;
std::list getSinkList() const;
std::list getSourceList() const;
std::list> getAvailablePortList(const NodeType&) const;
std::list getSinkInputList() const;
std::list getSourceOutputList() const;
std::list getStreamMediaList() const;
bool isValidDevice(const NodeType&) const;
// settings method
/**
* @brief 获取音量增强状态
*
* @return 返回音量增强的开关状态
*/
bool getVolumeBoostStatus() const;
/**
* @brief 设置音量增强的状态
*
* @param status 设置的状态
*
* @return 无
*/
void setVolumeBoostStatus(bool);
/**
* @brief 获取开启音量增强状态下的最大音量值
*
* @return 返回开启音量增强状态的音量值
*/
int getVolumeBoostValue() const;
/**
* @brief 设置音量增强状态下的最大音量值
*
* @param value 设置的最大音量
*
* @return 无
*/
void setVolumeBoostValue(int);
/**
* @brief 获取单声道音频功能的开启状态
*
* @return 返回单声道音频的开启状态
*/
bool getMonoStatus() const;
/**
* @brief 设置单声道音频功能的开启状态
*
* @param status 设置的状态
*
* @return 无
*/
void setMonoStatus(bool);
/**
* @brief 获取智能降噪功能的开启状态
*
* @return 返回智能降噪功能的开启状态
*/
bool getEchoCancelStatus() const;
/**
* @brief 设置智能降噪功能的开启状态
*
* @param status 设置的状态
*
* @return 无
*/
void setEchoCancelStatus(bool);
/**
* @brief 获取侦听功能的开启状态
*
* @return 返回侦听功能的开启状态
*/
bool getLoopbackStatus() const;
/**
* @brief 设置侦听功能的开启状态
*
* @param status 设置的状态
*
* @return 无
*/
void setLoopbackStatus(bool);
/**
* @brief 获取当前音效主题名称
*
* @return 返回当前音效主题名称
*/
std::string getSoundThemeName() const;
/**
* @brief 设置当前音效主题名称
*
* @param 当前音效主题名称
*
* @return 无
*/
void setSoundThemeName(const std::string&);
/**
* @brief 获取自定义音效主题的状态
*
* @return 返回自定义音效主题的状态
*/
bool getCustomThemeStatus() const;
/**
* @brief 设置自定义音效主题的状态
*
* @param 自定义音效主题的状态
*
* @return 无
*/
void setCustomThemeStatus(bool);
/**
* @brief 获取通知音效的名称
*
* @return 返回通知音效的名称
*/
std::string getNotifyGeneralName() const;
/**
* @brief 设置通知音效的名称
*
* @param 通知音效的名称
*
* @return 无
*/
void setNotifyGeneralName(const std::string&);
/**
* @brief 获取音量调节的名称
*
* @return 返回音量调节的名称
*/
std::string getVolumeChangedName() const;
/**
* @brief 设置音量调节的名称
*
* @param 音量调节的名称
*
* @return 无
*/
void setVolumeChangedName(const std::string&);
/**
* @brief 获取提示音功能的开启状态
*
* @return 返回提示音功能的开启状态
*/
bool getAlertStatus() const;
/**
* @brief 设置提示音功能的开启状态
*
* @param status 设置的状态
*
* @return 无
*/
void setAlertStatus(bool);
bool getStartupStatus() const;
void setStartupStatus(bool);
bool getPoweroffStatus() const;
void setPoweroffStatus(bool);
bool getLogoutStatus() const;
void setLogoutStatus(bool);
bool getWakeupStatus() const;
void setWakeupStatus(bool);
std::string getGlobalThemeName() const;
void setGlobalThemeName(const std::string&);
// sound theme method
/**
* @brief 获取系统音效主题列表
*
* @return 返回音效主题列表
*/
std::list getSoundThemeList();
/**
* @brief 获取指定音效主题的音效文件列表
*
* @return 返回音效文件列表
*/
std::list getSoundEffectFileList(const std::string&);
void setEnabled(const std::string&, const std::string&, bool);
bool isEnabled(const std::string&, const std::string&) const;
bool getAutoPauseStatus() const;
void setAutoPauseStatus(bool);
bool getMultiAudioCombineStatus(const NodeType&) const;
void setMultiAudioCombine(const NodeType&, bool, const std::vector&);
bool isLoaded(const ModuleType&);
// signal
void volumeChanged(const NodeType&, int, int);
void muteChanged(const NodeType&, int, bool);
void deviceChanged(const NodeType&, const std::string&, const std::string&, bool = false);
void deviceAdjust(const NodeType&);
void portChanged(const NodeType&, const std::string&);
void cardRemoved(const std::string&);
void settingsChanged(const char*, GVariant*);
void addStream(int, int, const std::string&, const std::string&);
void removeStream(int);
void addStream(int, int, int, bool, const std::string&, const std::string&);
void removeStream(int, int);
private:
void initJson();
SystemVersionInfo getSystemVersionInfo();
std::optional getFieldValue(const std::string&, const std::string_view&);
DesktopEnvironmentVersion getTypeFromSystemVersionInfo(const SystemVersionInfo&) const;
std::string extractThemeName(const std::string&);
std::string replaceThemeName(const std::string&, const std::string&);
template
auto findByName(const Container& container, const std::string& name) {
return std::find_if(container.begin(), container.end(), [&name](const SoundEffectFileInfo& info) {
return info.name.find(name) != std::string::npos;
});
}
private:
AudioMethod() = default;
AudioMethod(const AudioMethod&) = delete;
AudioMethod(AudioMethod&&) = delete;
AudioMethod operator=(const AudioMethod&) = delete;
AudioMethod operator=(AudioMethod&&) = delete;
virtual ~AudioMethod() = default;
private:
AudioDBusServer m_dbus;
std::shared_ptr m_pAudioManager {};
std::shared_ptr m_pRestoreVolumeJson {};
std::shared_ptr m_pMultiAudioJson {};
std::unordered_map> m_settingsMap = {
{MONO_AUDIO_KEY, {"module-remap-sink", "sink_name=mono channels=1 channel_map=mono"}},
{NOISE_REDUCTION_KEY, {"module-echo-cancel", "use_master_format=1 aec_method=webrtc aec_args=analog_gain_control=0 source_name=noiseReduceSource"}},
{LOOPBACK_KEY, {"module-loopback", ""}}
};
std::unordered_map> m_statusFunctions = {
{MONO_AUDIO_KEY, [this]() { return getMonoStatus(); }},
{NOISE_REDUCTION_KEY, [this]() { return getEchoCancelStatus(); }},
{LOOPBACK_KEY, [this]() { return getLoopbackStatus(); }}
};
std::unordered_map> m_keys = {
{SettingType::AUDIO_SETTING, std::shared_ptr()},
{SettingType::GLOBALTHEME_SETTING, std::shared_ptr()},
{SettingType::SESSIONMANAGER_SETTING, std::shared_ptr()},
{SettingType::SOUDNTHEMEPLAYER_SETTING, std::shared_ptr