diff --git a/audio1/audio.go b/audio1/audio.go index 58d3452d5..4b9285858 100644 --- a/audio1/audio.go +++ b/audio1/audio.go @@ -15,10 +15,12 @@ import ( dbus "github.com/godbus/dbus/v5" "github.com/linuxdeepin/dde-daemon/common/dsync" + notifications "github.com/linuxdeepin/go-dbus-factory/session/org.freedesktop.notifications" systemd1 "github.com/linuxdeepin/go-dbus-factory/system/org.freedesktop.systemd1" gio "github.com/linuxdeepin/go-gir/gio-2.0" "github.com/linuxdeepin/go-lib/dbusutil" "github.com/linuxdeepin/go-lib/dbusutil/gsprop" + . "github.com/linuxdeepin/go-lib/gettext" "github.com/linuxdeepin/go-lib/pulse" "golang.org/x/xerrors" ) @@ -52,6 +54,10 @@ const ( dsgKeyAutoSwitchPort = "autoSwitchPort" dsgKeyBluezModeFilterList = "bluezModeFilterList" dsgKeyPortFilterList = "portFilterList" + + localeIconStart = "notification-change-language-start" + localeIconFailed = "notification-change-language-failed" + localeIconFinished = "notification-change-language-finished" ) var ( @@ -61,6 +67,20 @@ var ( gMaxUIVolume float64 ) +var ( + // 切换音频的提示 + notifyTxtStart = Tr("Changing system language, please wait...") + notifyTxtDone = Tr("Audio Server changed, please log out and then log in") + notifyTxtFailed = Tr("Failed to change Audio Server, please try later") +) + +const ( + // 音频服务更改状态:已经完成 + AudioStateChanged = true + // 音频服务更改状态:正在修改中 + AudioStateChanging = false +) + //go:generate dbusutil-gen -type Audio,Sink,SinkInput,Source,Meter -import github.com/godbus/dbus/v5 audio.go sink.go sinkinput.go source.go meter.go //go:generate dbusutil-gen em -type Audio,Sink,SinkInput,Source,Meter @@ -108,6 +128,8 @@ type Audio struct { BluetoothAudioMode string // 蓝牙模式 // dbusutil-gen: equal=isStrvEqual BluetoothAudioModeOpts []string // 可用的蓝牙模式 + CurrentAudioServer string // 当前使用的音频服务 + AudioServerState bool // 音频服务状态 // dbusutil-gen: ignore IncreaseVolume gsprop.Bool `prop:"access:rw"` @@ -184,10 +206,11 @@ type Audio struct { func newAudio(service *dbusutil.Service) *Audio { a := &Audio{ - service: service, - meters: make(map[string]*Meter), - MaxUIVolume: pulse.VolumeUIMax, - enableSource: true, + service: service, + meters: make(map[string]*Meter), + MaxUIVolume: pulse.VolumeUIMax, + enableSource: true, + AudioServerState: AudioStateChanged, } a.settings = gio.NewSettings(gsSchemaAudio) @@ -196,6 +219,7 @@ func newAudio(service *dbusutil.Service) *Audio { a.IncreaseVolume.Bind(a.settings, gsKeyVolumeIncrease) a.PausePlayer = false a.ReduceNoise = false + // a.CurrentAudioServer = a.getCurrentAudioServer() a.emitPropChangedReduceNoise(a.ReduceNoise) a.headphoneUnplugAutoPause = a.settings.GetBoolean(gsKeyHeadphoneUnplugAutoPause) a.outputAutoSwitchCountMax = int(a.settings.GetInt(gsKeyOutputAutoSwitchCountMax)) @@ -214,9 +238,83 @@ func newAudio(service *dbusutil.Service) *Audio { return a } -func startAudioServer(service *dbusutil.Service) error { +func (a *Audio) setAudioServerFailed(oldAudioServer string) { + sendNotify(localeIconFailed, "", + Tr("Failed to change system language, please try later")) + // restore CurrentLocale + a.PropsMu.Lock() + a.setPropCurrentAudioServer(oldAudioServer) + a.setPropAudioServerState(AudioStateChanged) + a.PropsMu.Unlock() +} + +func (a *Audio) SetCurrentAudioServer(serverName string) (err *dbus.Error) { + a.PropsMu.Lock() + oldAudioServer := a.CurrentAudioServer + a.setPropAudioServerState(AudioStateChanging) + a.setPropCurrentAudioServer(serverName) + a.PropsMu.Unlock() + + sendNotify(localeIconStart, "", notifyTxtStart) + + var activeServers, deactiveServers []string + if serverName == "pulseaudio" { + activeServers = []string{"pulseaudio.service"} + deactiveServers = []string{"pipewire-pulse.service", "pipewire.service"} + } else { + activeServers = []string{"pipewire-pulse.service", "pipewire.service"} + deactiveServers = []string{"pulseaudio.service"} + } + + systemd := systemd1.NewManager(a.service.Conn()) + _, e := systemd.UnmaskUnitFiles(0, activeServers, false) + if e != nil { + logger.Warning("Failed to unmask unit files", activeServers, "\nError:", e) + a.setAudioServerFailed(oldAudioServer) + sendNotify(localeIconFinished, "", notifyTxtDone) + } + + _, e = systemd.MaskUnitFiles(0, deactiveServers, false, true) + if e != nil { + logger.Warning("Failed to mask unit files", deactiveServers, "\nError:", e) + a.setAudioServerFailed(oldAudioServer) + sendNotify(localeIconFinished, "", notifyTxtDone) + } + + e = systemd.Reload(0) + if e != nil { + logger.Warning("Failed to reload unit files. Error:", e) + } + + sendNotify(localeIconFinished, "", notifyTxtDone) + + a.PropsMu.Lock() + a.setPropAudioServerState(AudioStateChanged) + a.PropsMu.Unlock() + return nil +} + +func sendNotify(icon, summary, body string) { + sessionBus, err := dbus.SessionBus() + if err != nil { + logger.Warning(err) + return + } + n := notifications.NewNotifications(sessionBus) + _, err = n.Notify(0, "dde-control-center", 0, + icon, summary, body, + nil, nil, -1) + logger.Debugf("send notification icon: %q, summary: %q, body: %q", + icon, summary, body) + + if err != nil { + logger.Warning(err) + } +} + +func (a *Audio) startAudioServer(service *dbusutil.Service) error { var serverPath dbus.ObjectPath - audioServers := []string{"pipewire-pulse.service", "pulseaudio.service"} + audioServers := []string{"pulseaudio.service", "pipewire-pulse.service"} systemd := systemd1.NewManager(service.Conn()) @@ -224,6 +322,7 @@ func startAudioServer(service *dbusutil.Service) error { path, err := systemd.GetUnit(0, server) if err == nil { serverPath = path + a.CurrentAudioServer = strings.Split(server, ".")[0] break } } diff --git a/audio1/audio_dbusutil.go b/audio1/audio_dbusutil.go index 2ea040d98..798866dd8 100644 --- a/audio1/audio_dbusutil.go +++ b/audio1/audio_dbusutil.go @@ -123,6 +123,32 @@ func (v *Audio) emitPropChangedBluetoothAudioModeOpts(value []string) error { return v.service.EmitPropertyChanged(v, "BluetoothAudioModeOpts", value) } +func (v *Audio) setPropCurrentAudioServer(value string) (changed bool) { + if v.CurrentAudioServer != value { + v.CurrentAudioServer = value + v.emitPropChangedCurrentAudioServer(value) + return true + } + return false +} + +func (v *Audio) emitPropChangedCurrentAudioServer(value string) error { + return v.service.EmitPropertyChanged(v, "CurrentAudioServer", value) +} + +func (v *Audio) setPropAudioServerState(value bool) (changed bool) { + if v.AudioServerState != value { + v.AudioServerState = value + v.emitPropChangedAudioServerState(value) + return true + } + return false +} + +func (v *Audio) emitPropChangedAudioServerState(value bool) error { + return v.service.EmitPropertyChanged(v, "AudioServerState", value) +} + func (v *Audio) setPropPausePlayer(value bool) (changed bool) { if v.PausePlayer != value { v.PausePlayer = value diff --git a/audio1/exported_methods_auto.go b/audio1/exported_methods_auto.go index a2ea024e6..1263869d6 100644 --- a/audio1/exported_methods_auto.go +++ b/audio1/exported_methods_auto.go @@ -37,6 +37,11 @@ func (v *Audio) GetExportedMethods() dbusutil.ExportedMethods { Fn: v.SetPortEnabled, InArgs: []string{"cardId", "portName", "enabled"}, }, + { + Name: "SetCurrentAudioServer", + Fn: v.SetCurrentAudioServer, + InArgs: []string{"serverName"}, + }, } } func (v *Meter) GetExportedMethods() dbusutil.ExportedMethods {