Skip to content

Commit

Permalink
fix: 适配pipewire,解决音频切换无声音,切换失败的问题
Browse files Browse the repository at this point in the history
适配pipewire,解决音频切换无声音,切换失败的问题

Log: 适配pipewire,解决音频切换无声音,切换失败的问题
pms: BUG-294121
  • Loading branch information
fly602 committed Dec 20, 2024
1 parent 5678554 commit afa272d
Show file tree
Hide file tree
Showing 5 changed files with 81 additions and 44 deletions.
98 changes: 72 additions & 26 deletions audio1/audio.go
Original file line number Diff line number Diff line change
Expand Up @@ -826,19 +826,51 @@ func (a *Audio) autoPause() {
func (a *Audio) refreshDefaultSinkSource() {
defaultSink := a.ctx.GetDefaultSink()
defaultSource := a.ctx.GetDefaultSource()
firstSinkPort := GetPriorityManager().Output.GetTheFirstPort()

if a.defaultSink != nil && a.defaultSink.Name != defaultSink {
logger.Debugf("update default sink to %s", defaultSink)
if a.misc != 0 {
a.misc = 0
go pauseAllPlayers()
} else if a.defaultSink.pluggable {
// 异步状况下,可能整个card不存在(比如蓝牙),可插拔sink切换, 需再判断下card信息。
if _, err := a.ctx.GetCard(a.defaultSink.Card); err != nil {
// pipewire设置的时候,sink会变,在refresh的时候重新设置profile的activeport
sinkInfo := a.getSinkInfoByName(defaultSink)
if sinkInfo == nil {
logger.Warningf("refresh defaultSink failed, defaultSink %v not found,", defaultSink)
return
}
card, err := a.cards.getByName(firstSinkPort.CardName)
if err != nil || card == nil {
logger.Warningf("card not found %v, cards:%v", firstSinkPort.CardName, a.cards)
return
}

// GetPriorityManager中的port是refresh之后的,正常情况下一定存在的
// pipewire sink变化的时候,可能其sink列表中不存在当前设置的端口所对应的sink,说明pipewire的切换还未完成
if sinkInfo.Card != card.Id || sinkInfo.ActivePort.Name != firstSinkPort.PortName {
// 查找声卡所对应的sink是否存在
var sink *Sink = nil
for _, tmpSink := range a.sinks {
if tmpSink.Card == card.Id {
sink = tmpSink
_, found := getPortByName(tmpSink.Ports, firstSinkPort.PortName)
if found {
sink = tmpSink
break
}
}
}
if sink != nil && sink.Name != defaultSink {
logger.Debugf("update default sink to %s with port %v", sink.Name, firstSinkPort.PortName)
if a.misc != 0 {
a.misc = 0
go pauseAllPlayers()
} else if sink.pluggable {
// 异步状况下,可能整个card不存在(比如蓝牙),可插拔sink切换, 需再判断下card信息。
if _, err := a.ctx.GetCard(a.defaultSink.Card); err != nil {
go pauseAllPlayers()
}
}
a.ctx.SetDefaultSink(sink.Name)
a.updateDefaultSink(sink.Name)
} else {
logger.Warningf("not found available sink with first port %v", firstSinkPort.PortName)
}
a.updateDefaultSink(defaultSink)
} else {
logger.Debugf("keep default as %s", defaultSink)
if a.misc != 0 {
Expand Down Expand Up @@ -1341,13 +1373,9 @@ func (a *Audio) setPort(cardId uint32, portName string, direction int) error {
return a.setDefaultSourceWithPort(cardId, portName)
}

// 蓝牙特殊情况下会出错,导致profile为off, 需要重新寻找合适的
if targetPortInfo.Profiles != nil && targetPortInfo.Profiles.Exists(card.ActiveProfile.Name) && card.ActiveProfile.Name != "off" {
// no need to change profile
return setDefaultPort()
}
if portName == dndVirtualSinkName || cardId == math.MaxUint32 {
return setDefaultPort()
a.ctx.SetDefaultSink(portName)
return nil
}

// match the common profile contain sinkPort and sourcePort
Expand All @@ -1363,13 +1391,17 @@ func (a *Audio) setPort(cardId uint32, portName string, direction int) error {
}
targetProfile = name
}
// workaround for bluetooth, set profile to 'a2dp_sink' when port direction is output
if direction == pulse.DirectionSink && targetPortInfo.Profiles.Exists("a2dp_sink") {
targetProfile = "a2dp_sink"
}
card.core.SetProfile(targetProfile)

// 如果声卡的当前使用的配置文件对应不上,当切换配置文件时,sink会改变,则在refresh的时候设置defaultSink
logger.Debug("set profile", targetProfile)
return setDefaultPort()
if card.ActiveProfile.Name != targetProfile {
card.core.SetProfile(targetProfile)
} else {
// 如果是一致的
return setDefaultPort()
}

return nil
}

func (a *Audio) resetSinksVolume() {
Expand Down Expand Up @@ -1554,8 +1586,22 @@ func (a *Audio) refreshBluetoothOpts() {
return
}

a.setPropBluetoothAudioModeOpts(card.BluezModeOpts())
a.setPropBluetoothAudioMode(card.BluezMode())
// 蓝牙音频的模式应该显示为端口下的profile的列表
port, err := card.Ports.Get(a.defaultSink.ActivePort.Name, pulse.DirectionSink)
if err != nil {
logger.Warning(err)
return
}

var opts []string
for _, profile := range port.Profiles {
if profile.Available == 0 {
continue
}
opts = append(opts, profile.Name)
}
a.setPropBluetoothAudioModeOpts(opts)
a.setPropBluetoothAudioMode(card.ActiveProfile.Name)
}

func (a *Audio) updateDefaultSink(sinkName string) {
Expand Down Expand Up @@ -1604,7 +1650,7 @@ func (a *Audio) updateDefaultSink(sinkName string) {
a.setPropDefaultSink(defaultSinkPath)
a.PropsMu.Unlock()

logger.Debug("set prop default sink:", defaultSinkPath)
logger.Debug("set prop default sink:", defaultSinkPath, a.defaultSink.ActivePort.Name)
}

func (a *Audio) updateSources(index uint32) (source *Source) {
Expand Down Expand Up @@ -1890,8 +1936,8 @@ func (a *Audio) SetBluetoothAudioMode(mode string) *dbus.Error {
logger.Debugf("set profile %s", profile.Name)
card.core.SetProfile(profile.Name)

// 手动切换蓝牙模式为headset,
if mode == bluezModeHeadset || mode == bluezModeHandsfree {
// 手动切换蓝牙模式为headset,Profiles是排序之后的,按照优先级先后来设置
if strings.Contains(strings.ToLower(mode), bluezModeHeadset) || strings.Contains(strings.ToLower(mode), bluezModeHandsfree) {
a.inputAutoSwitchCount = 0
GetPriorityManager().Input.SetTheFirstType(PortTypeBluetooth)
}
Expand Down
10 changes: 3 additions & 7 deletions audio1/audio_events.go
Original file line number Diff line number Diff line change
Expand Up @@ -315,12 +315,8 @@ func (a *Audio) handleCardChanged(idx uint32) {
}

// 如果发生变化的是当前输出所用的声卡,且是蓝牙声卡
if a.defaultSink != nil && idx == a.defaultSink.Card && isBluetoothCard(card.core) {
if strings.Contains(strings.ToLower(card.ActiveProfile.Name), bluezModeA2dp) {
a.setPropBluetoothAudioMode(bluezModeA2dp)
} else if strings.Contains(strings.ToLower(card.ActiveProfile.Name), bluezModeHeadset) {
a.setPropBluetoothAudioMode(bluezModeHeadset)
}
if a.defaultSink != nil && idx == a.defaultSink.Card && isBluezAudio(card.core.Name) {
a.setPropBluetoothAudioMode(card.ActiveProfile.Name)
}
}

Expand Down Expand Up @@ -361,7 +357,7 @@ func (a *Audio) handleSinkChanged(idx uint32) {
if a.defaultSink != nil && a.defaultSink.index == idx && isBluezAudio(a.defaultSink.Name) {
card, err := a.cards.get(a.defaultSink.Card)
if err == nil {
a.setPropBluetoothAudioMode(card.BluezMode())
a.setPropBluetoothAudioMode(card.ActiveProfile.Name)
} else {
logger.Warningf("%d card not found", a.defaultSink.Card)
}
Expand Down
3 changes: 2 additions & 1 deletion audio1/bluez_audio.go
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,8 @@ func (card *Card) BluezModeOpts() []string {

v := strings.ToLower(profile.Name)

if filterList.Contains(v) {
// pulseaudio和pipewier返回的端口、profile的名称的风格不一样,一个使用中横线一个使用下划线
if filterList.Contains(strings.ReplaceAll(v, "-", "_")) {
logger.Debug("filter bluez mode", v)
continue
}
Expand Down
7 changes: 3 additions & 4 deletions audio1/card.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,15 +97,14 @@ func (c *Card) update(card *pulse.Card) {
sort.Sort(card.Profiles)
c.Profiles = newProfileList(card.Profiles)
c.filterProfile(card)

filterList := strv.Strv(portFilterList)
for _, port := range card.Ports {
if filterList.Contains(port.Name) {
logger.Debug("filter port", port.Name)
port.Available = pulse.AvailableTypeNo
} else {
/* 蓝牙声卡的端口需要过滤 */
if isBluetoothCard(card) {
if isBluezAudio(card.Name) {
if c.BluezMode() == bluezModeA2dp && port.Direction == pulse.DirectionSource {
// a2dp模式过滤输入端口
logger.Debugf("filter bluez input port %s", port.Name)
Expand Down Expand Up @@ -168,7 +167,7 @@ func (cards CardList) string() string {
ports = append(ports, CardPortExport{
Name: portInfo.Name,
Enabled: portConfig.Enabled,
Bluetooth: isBluetoothCard(cardInfo.core),
Bluetooth: isBluezAudio(cardInfo.core.Name),
Description: portInfo.Description,
Direction: portInfo.Direction,
PortType: GetIconPortType(cardInfo.Name, portInfo.Name),
Expand Down Expand Up @@ -197,7 +196,7 @@ func (cards CardList) stringWithoutUnavailable() string {
ports = append(ports, CardPortExport{
Name: portInfo.Name,
Enabled: portConfig.Enabled,
Bluetooth: isBluetoothCard(cardInfo.core),
Bluetooth: isBluezAudio(cardInfo.core.Name),
Description: portInfo.Description,
Direction: portInfo.Direction,
PortType: GetIconPortType(cardInfo.Name, portInfo.Name),
Expand Down
7 changes: 1 addition & 6 deletions audio1/card_profile_workaround.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ func selectNewCardProfile(c *pulse.Card) {
// if card is bluetooth device, switch to profile a2dp_sink
// only 'a2dp_sink' in bluetooth profiles because of blacklist
if len(profiles) > 0 {
if isBluetoothCard(c) {
if isBluezAudio(c.Name) {
// Some bluetooth device services not resolved after connected, then denied to set profile to a2dp_sink.
// If connect device again, the services resolved work right. The devices such as: SONY MDR-1ABT
if c.ActiveProfile.Name == "off" {
Expand All @@ -88,11 +88,6 @@ func selectNewCardProfile(c *pulse.Card) {
}
}

func isBluetoothCard(c *pulse.Card) bool {
_, ok := c.PropList["bluez.path"]
return ok
}

func tryConnectBluetooth(c *pulse.Card) error {
bluePath, ok := c.PropList["bluez.path"]
if !ok {
Expand Down

0 comments on commit afa272d

Please sign in to comment.