yktoo / indicator-sound-switcher

Sound input/output selector indicator for Linux
https://yktoo.com/en/software/sound-switcher-indicator/
GNU General Public License v3.0
369 stars 29 forks source link

[BUG] Regression: Failed to map card[0], port `analog-output-speaker` to a stream #132

Closed jmickelin closed 1 month ago

jmickelin commented 6 months ago

Describe the bug

This seems to be a regression introduced by 5fb737c.

I can no longer switch output ports when the ports reside in different profiles. The error I get is as follows (I have added some extra debugging lines to showcase what happens):

[...]
DEBUG    .activate_port(0, analog-output-speaker)
INFO     # Card[0], port `analog-output-speaker` selected
DEBUG    .find_stream_port(...)
DEBUG      * card_port = analog-output-speaker, stream.ports = ['hdmi-output-0']
DEBUG      * stream: None
DEBUG    * Switching card[0] to profile `output:analog-stereo+input:analog-stereo` with priority 39333
DEBUG    .find_stream_port(...)
DEBUG      * card_port = analog-output-speaker, stream.ports = ['hdmi-output-0']
DEBUG      * stream: None
ERROR    Failed to map card[0], port `analog-output-speaker` to a stream
[...]

To Reproduce Steps to reproduce the behavior:

  1. Switch between outputs in the systray icon's menu
  2. See error

Expected behavior Output should be switched correctly.

Desktop (please complete the following information):

Indicator log:

Here is the log. I have included some extra debug lines for context, as follows:

--- indicator-sound-switcher-master/lib/indicator_sound_switcher/indicator.py   2022-06-28 11:41:13.000000000 +0200
+++ /usr/local/lib/python3.11/site-packages/indicator_sound_switcher/indicator.py   2024-03-25 01:41:09.536517195 +0100
@@ -567,6 +567,7 @@
                 selected_profile.name.encode(),
                 self._pacb_context_success,
                 None))
+        self.update_all_pa_items()
         return True

     # ------------------------------------------------------------------------------------------------------------------
@@ -885,11 +886,13 @@

             # Try to find a matching stream
             stream = card.find_stream_port(port, self.sources, self.sinks)[0]
+            logging.debug('  * stream: %s', stream)

             # Switch profile if necessary
             if self.card_switch_profile(port, stream is not None):
                 # Profile is changed: retry searching for the stream
                 stream = card.find_stream_port(port, self.sources, self.sinks)[0]
+                logging.debug('  * stream: %s', stream)

             # If no stream found, that's an error
             if stream is None:
--- indicator-sound-switcher-master/lib/indicator_sound_switcher/card.py    2022-06-28 11:41:13.000000000 +0200
+++ /usr/local/lib/python3.11/site-packages/indicator_sound_switcher/card.py    2024-03-25 01:36:01.114521010 +0100
@@ -1,3 +1,4 @@
+import logging
 from gi.repository import GObject
 from . import lib_pulseaudio

@@ -57,6 +58,8 @@
         # Try to find a sink/source for this card (by matching card index)
         streams = sinks if card_port.is_output else sources
         for stream in streams.values():
+            logging.debug('.find_stream_port(...)')
+            logging.debug('  * card_port = %s, stream.ports = %s', card_port.name, list(stream.ports.keys()))
             if stream.card_index == self.index:
                 # Found a potential stream. Now try to find a corresponding stream's port (with the matching port name).
                 if card_port.name in stream.ports:

This produces the following:

$ indicator-sound-switcher -vv
INFO     Starting indicator application
INFO     Loaded configuration file /home/jmickelin/.config/indicator-sound-switcher.json
DEBUG    KeyboardManager.bind_keys()
DEBUG      - Bound keyboard shortcut `<Super>apostrophe` to `[('alsa_card.pci-0000_00_1f.3', 'analog-output-speaker'), ('alsa_card.pci-0000_00_1f.3', 'hdmi-output-0')]`
DEBUG    .menu_append_item(): appending item `Inputs`
DEBUG    .menu_append_item(): appending separator
DEBUG    .menu_append_item(): appending item `Outputs`
DEBUG    .menu_append_item(): appending separator
DEBUG    .menu_append_item(): appending item `_Refresh`
DEBUG    .menu_append_item(): appending item `_Preferences…`
DEBUG    .menu_append_item(): appending item `_About`
DEBUG    .menu_append_item(): appending item `_Quit`
DEBUG    Trying to connect to PulseAudio daemon, attempt #1
INFO     Context connected
DEBUG      + Card[0] added: `alsa_card.pci-0000_00_1f.3`, driver: `module-alsa-card.c`
DEBUG        + Card profile added: `input:analog-stereo` (`Analog Stereo Input`), 0 sinks, 1 sources, priority: 32833
DEBUG        + Card profile added: `output:analog-stereo` (`Analog Stereo Output`), 1 sinks, 0 sources, priority: 39268
DEBUG        + Card profile added: `output:analog-stereo+input:analog-stereo` (`Analog Stereo Duplex`), 1 sinks, 1 sources, priority: 39333
DEBUG        + Card profile added: `output:hdmi-stereo` (`Digital Stereo (HDMI) Output`), 1 sinks, 0 sources, priority: 38668
DEBUG        + Card profile added: `output:hdmi-stereo+input:analog-stereo` (`Digital Stereo (HDMI) Output + Analog Stereo Input`), 1 sinks, 1 sources, priority: 38733 -- Active
DEBUG        + Card profile added: `output:hdmi-surround` (`Digital Surround 5.1 (HDMI) Output`), 1 sinks, 0 sources, priority: 33568
DEBUG        + Card profile added: `output:hdmi-surround+input:analog-stereo` (`Digital Surround 5.1 (HDMI) Output + Analog Stereo Input`), 1 sinks, 1 sources, priority: 33633
DEBUG        + Card profile added: `output:hdmi-surround71` (`Digital Surround 7.1 (HDMI) Output`), 1 sinks, 0 sources, priority: 33568
DEBUG        + Card profile added: `output:hdmi-surround71+input:analog-stereo` (`Digital Surround 7.1 (HDMI) Output + Analog Stereo Input`), 1 sinks, 1 sources, priority: 33633
DEBUG        + Card profile added: `output:hdmi-stereo-extra1` (`Digital Stereo (HDMI 2) Output`), 1 sinks, 0 sources, priority: 5700
DEBUG        + Card profile added: `output:hdmi-stereo-extra1+input:analog-stereo` (`Digital Stereo (HDMI 2) Output + Analog Stereo Input`), 1 sinks, 1 sources, priority: 5765
DEBUG        + Card profile added: `output:hdmi-surround-extra1` (`Digital Surround 5.1 (HDMI 2) Output`), 1 sinks, 0 sources, priority: 600
DEBUG        + Card profile added: `output:hdmi-surround-extra1+input:analog-stereo` (`Digital Surround 5.1 (HDMI 2) Output + Analog Stereo Input`), 1 sinks, 1 sources, priority: 665
DEBUG        + Card profile added: `output:hdmi-surround71-extra1` (`Digital Surround 7.1 (HDMI 2) Output`), 1 sinks, 0 sources, priority: 600
DEBUG        + Card profile added: `output:hdmi-surround71-extra1+input:analog-stereo` (`Digital Surround 7.1 (HDMI 2) Output + Analog Stereo Input`), 1 sinks, 1 sources, priority: 665
DEBUG        + Card profile added: `output:hdmi-stereo-extra2` (`Digital Stereo (HDMI 3) Output`), 1 sinks, 0 sources, priority: 5700
DEBUG        + Card profile added: `output:hdmi-stereo-extra2+input:analog-stereo` (`Digital Stereo (HDMI 3) Output + Analog Stereo Input`), 1 sinks, 1 sources, priority: 5765
DEBUG        + Card profile added: `output:hdmi-surround-extra2` (`Digital Surround 5.1 (HDMI 3) Output`), 1 sinks, 0 sources, priority: 600
DEBUG        + Card profile added: `output:hdmi-surround-extra2+input:analog-stereo` (`Digital Surround 5.1 (HDMI 3) Output + Analog Stereo Input`), 1 sinks, 1 sources, priority: 665
DEBUG        + Card profile added: `output:hdmi-surround71-extra2` (`Digital Surround 7.1 (HDMI 3) Output`), 1 sinks, 0 sources, priority: 600
DEBUG        + Card profile added: `output:hdmi-surround71-extra2+input:analog-stereo` (`Digital Surround 7.1 (HDMI 3) Output + Analog Stereo Input`), 1 sinks, 1 sources, priority: 665
DEBUG        + Card profile added: `off` (`Off`), 0 sinks, 0 sources, priority: 0
DEBUG        + Card port added: `analog-input-internal-mic` (`Internal Microphone`); priority: 8900; direction: 2; available: Yes
DEBUG          . Supported profile: `input:analog-stereo`
DEBUG          . Supported profile: `output:analog-stereo+input:analog-stereo`
DEBUG          . Supported profile: `output:hdmi-stereo+input:analog-stereo`
DEBUG          . Supported profile: `output:hdmi-surround+input:analog-stereo`
DEBUG          . Supported profile: `output:hdmi-surround71+input:analog-stereo`
DEBUG          . Supported profile: `output:hdmi-stereo-extra1+input:analog-stereo`
DEBUG          . Supported profile: `output:hdmi-surround-extra1+input:analog-stereo`
DEBUG          . Supported profile: `output:hdmi-surround71-extra1+input:analog-stereo`
DEBUG          . Supported profile: `output:hdmi-stereo-extra2+input:analog-stereo`
DEBUG          . Supported profile: `output:hdmi-surround-extra2+input:analog-stereo`
DEBUG          . Supported profile: `output:hdmi-surround71-extra2+input:analog-stereo`
DEBUG        + Card port added: `analog-input-headphone-mic` (`Microphone`); priority: 8700; direction: 2; available: No
DEBUG          . Supported profile: `input:analog-stereo`
DEBUG          . Supported profile: `output:analog-stereo+input:analog-stereo`
DEBUG          . Supported profile: `output:hdmi-stereo+input:analog-stereo`
DEBUG          . Supported profile: `output:hdmi-surround+input:analog-stereo`
DEBUG          . Supported profile: `output:hdmi-surround71+input:analog-stereo`
DEBUG          . Supported profile: `output:hdmi-stereo-extra1+input:analog-stereo`
DEBUG          . Supported profile: `output:hdmi-surround-extra1+input:analog-stereo`
DEBUG          . Supported profile: `output:hdmi-surround71-extra1+input:analog-stereo`
DEBUG          . Supported profile: `output:hdmi-stereo-extra2+input:analog-stereo`
DEBUG          . Supported profile: `output:hdmi-surround-extra2+input:analog-stereo`
DEBUG          . Supported profile: `output:hdmi-surround71-extra2+input:analog-stereo`
DEBUG        + Card port added: `analog-input-headset-mic` (`Headset Microphone`); priority: 8800; direction: 2; available: No
DEBUG          . Supported profile: `input:analog-stereo`
DEBUG          . Supported profile: `output:analog-stereo+input:analog-stereo`
DEBUG          . Supported profile: `output:hdmi-stereo+input:analog-stereo`
DEBUG          . Supported profile: `output:hdmi-surround+input:analog-stereo`
DEBUG          . Supported profile: `output:hdmi-surround71+input:analog-stereo`
DEBUG          . Supported profile: `output:hdmi-stereo-extra1+input:analog-stereo`
DEBUG          . Supported profile: `output:hdmi-surround-extra1+input:analog-stereo`
DEBUG          . Supported profile: `output:hdmi-surround71-extra1+input:analog-stereo`
DEBUG          . Supported profile: `output:hdmi-stereo-extra2+input:analog-stereo`
DEBUG          . Supported profile: `output:hdmi-surround-extra2+input:analog-stereo`
DEBUG          . Supported profile: `output:hdmi-surround71-extra2+input:analog-stereo`
DEBUG        + Card port added: `analog-output-speaker` (`Speakers`); priority: 10000; direction: 1; available: Yes
DEBUG          . Supported profile: `output:analog-stereo`
DEBUG          . Supported profile: `output:analog-stereo+input:analog-stereo`
DEBUG        + Card port added: `analog-output-headphones` (`Headphones`); priority: 9900; direction: 1; available: No
DEBUG          . Supported profile: `output:analog-stereo`
DEBUG          . Supported profile: `output:analog-stereo+input:analog-stereo`
DEBUG        + Card port added: `hdmi-output-0` (`HDMI / DisplayPort`); priority: 5900; direction: 1; available: Yes
DEBUG          . Supported profile: `output:hdmi-stereo`
DEBUG          . Supported profile: `output:hdmi-stereo+input:analog-stereo`
DEBUG          . Supported profile: `output:hdmi-surround`
DEBUG          . Supported profile: `output:hdmi-surround+input:analog-stereo`
DEBUG          . Supported profile: `output:hdmi-surround71`
DEBUG          . Supported profile: `output:hdmi-surround71+input:analog-stereo`
DEBUG        + Card port added: `hdmi-output-1` (`HDMI / DisplayPort 2`); priority: 5800; direction: 1; available: No
DEBUG          . Supported profile: `output:hdmi-stereo-extra1`
DEBUG          . Supported profile: `output:hdmi-stereo-extra1+input:analog-stereo`
DEBUG          . Supported profile: `output:hdmi-surround-extra1`
DEBUG          . Supported profile: `output:hdmi-surround-extra1+input:analog-stereo`
DEBUG          . Supported profile: `output:hdmi-surround71-extra1`
DEBUG          . Supported profile: `output:hdmi-surround71-extra1+input:analog-stereo`
DEBUG        + Card port added: `hdmi-output-2` (`HDMI / DisplayPort 3`); priority: 5700; direction: 1; available: No
DEBUG          . Supported profile: `output:hdmi-stereo-extra2`
DEBUG          . Supported profile: `output:hdmi-stereo-extra2+input:analog-stereo`
DEBUG          . Supported profile: `output:hdmi-surround-extra2`
DEBUG          . Supported profile: `output:hdmi-surround-extra2+input:analog-stereo`
DEBUG          . Supported profile: `output:hdmi-surround71-extra2`
DEBUG          . Supported profile: `output:hdmi-surround71-extra2+input:analog-stereo`
DEBUG    .menu_insert_ordered_item(): inserting item `    Built-in Audio ‣ Internal Microphone` at index 1
DEBUG    .menu_insert_ordered_item(): inserting item `    Built-in Audio ‣ Microphone` at index 2 (hidden)
DEBUG    .menu_insert_ordered_item(): inserting item `    Built-in Audio ‣ Headset Microphone` at index 1 (hidden)
DEBUG    .menu_insert_ordered_item(): inserting item `    Built-in Audio ‣ Speakers` at index 6
DEBUG    .menu_insert_ordered_item(): inserting item `    Built-in Audio ‣ Headphones` at index 6 (hidden)
DEBUG    .menu_insert_ordered_item(): inserting item `    Built-in Audio ‣ HDMI` at index 6
DEBUG    .menu_insert_ordered_item(): inserting item `    Built-in Audio ‣ HDMI / DisplayPort 2` at index 7 (hidden)
DEBUG    .menu_insert_ordered_item(): inserting item `    Built-in Audio ‣ HDMI / DisplayPort 3` at index 8 (hidden)
DEBUG      + Source[1] added: `alsa_input.pci-0000_00_1f.3.analog-stereo`, card 0
DEBUG        + Source port added: `analog-input-internal-mic` (`Internal Microphone`); priority: 8900; available: Yes
DEBUG        + Source port added: `analog-input-headphone-mic` (`Microphone`); priority: 8700; available: No
DEBUG        + Source port added: `analog-input-headset-mic` (`Headset Microphone`); priority: 8800; available: No
DEBUG        * Activated source port `analog-input-internal-mic`
DEBUG    .find_stream_port(...)
DEBUG      * card_port = analog-input-internal-mic, stream.ports = ['analog-input-internal-mic', 'analog-input-headphone-mic', 'analog-input-headset-mic']
DEBUG    .find_stream_port(...)
DEBUG      * card_port = analog-input-headphone-mic, stream.ports = ['analog-input-internal-mic', 'analog-input-headphone-mic', 'analog-input-headset-mic']
DEBUG    .find_stream_port(...)
DEBUG      * card_port = analog-input-headset-mic, stream.ports = ['analog-input-internal-mic', 'analog-input-headphone-mic', 'analog-input-headset-mic']
DEBUG      + Source output[1] added: `record`
DEBUG      + Source output[2] added: `record`
DEBUG      + Source output[4] added: `record`
DEBUG      + Source output[5] added: `record`
DEBUG      + Source output[6] added: `record`
DEBUG      + Source output[7] added: `record`
DEBUG      + Source output[8] added: `record`
DEBUG      + Sink[330] added: `alsa_output.pci-0000_00_1f.3.hdmi-stereo`, card 0
DEBUG        + Sink port added: `hdmi-output-0` (`HDMI / DisplayPort`); priority: 5900; available: Yes
DEBUG        * Activated sink port `hdmi-output-0`
DEBUG    .find_stream_port(...)
DEBUG      * card_port = analog-input-internal-mic, stream.ports = ['analog-input-internal-mic', 'analog-input-headphone-mic', 'analog-input-headset-mic']
DEBUG    .find_stream_port(...)
DEBUG      * card_port = analog-input-headphone-mic, stream.ports = ['analog-input-internal-mic', 'analog-input-headphone-mic', 'analog-input-headset-mic']
DEBUG    .find_stream_port(...)
DEBUG      * card_port = analog-input-headset-mic, stream.ports = ['analog-input-internal-mic', 'analog-input-headphone-mic', 'analog-input-headset-mic']
DEBUG    .find_stream_port(...)
DEBUG      * card_port = analog-output-speaker, stream.ports = ['hdmi-output-0']
DEBUG    .find_stream_port(...)
DEBUG      * card_port = analog-output-headphones, stream.ports = ['hdmi-output-0']
DEBUG    .find_stream_port(...)
DEBUG      * card_port = hdmi-output-0, stream.ports = ['hdmi-output-0']
DEBUG    .find_stream_port(...)
DEBUG      * card_port = hdmi-output-1, stream.ports = ['hdmi-output-0']
DEBUG    .find_stream_port(...)
DEBUG      * card_port = hdmi-output-2, stream.ports = ['hdmi-output-0']
DEBUG      + Sink input[1] added: `playback` -> sink 330
DEBUG      + Sink input[2] added: `playback` -> sink 330
DEBUG      + Sink input[4] added: `playback` -> sink 330
DEBUG      + Sink input[5] added: `playback` -> sink 330
DEBUG      + Sink input[6] added: `playback` -> sink 330
DEBUG      + Sink input[7] added: `playback` -> sink 330
DEBUG      + Sink input[8] added: `playback` -> sink 330
DEBUG    * Activated sink: `alsa_output.pci-0000_00_1f.3.hdmi-stereo`
DEBUG    * Activated source: `alsa_input.pci-0000_00_1f.3.analog-stereo`
DEBUG    .find_stream_port(...)
DEBUG      * card_port = analog-input-internal-mic, stream.ports = ['analog-input-internal-mic', 'analog-input-headphone-mic', 'analog-input-headset-mic']
DEBUG    .find_stream_port(...)
DEBUG      * card_port = analog-input-headphone-mic, stream.ports = ['analog-input-internal-mic', 'analog-input-headphone-mic', 'analog-input-headset-mic']
DEBUG    .find_stream_port(...)
DEBUG      * card_port = analog-input-headset-mic, stream.ports = ['analog-input-internal-mic', 'analog-input-headphone-mic', 'analog-input-headset-mic']
DEBUG    .find_stream_port(...)
DEBUG      * card_port = analog-output-speaker, stream.ports = ['hdmi-output-0']
DEBUG    .find_stream_port(...)
DEBUG      * card_port = analog-output-headphones, stream.ports = ['hdmi-output-0']
DEBUG    .find_stream_port(...)
DEBUG      * card_port = hdmi-output-0, stream.ports = ['hdmi-output-0']
DEBUG    .find_stream_port(...)
DEBUG      * card_port = hdmi-output-1, stream.ports = ['hdmi-output-0']
DEBUG    .find_stream_port(...)
DEBUG      * card_port = hdmi-output-2, stream.ports = ['hdmi-output-0']

(indicator-sound-switcher:2573642): Gdk-CRITICAL **: 01:39:16.749: gdk_window_thaw_toplevel_updates: assertion 'window->update_and_descendants_freeze_count > 0' failed
DEBUG    .activate_port(0, analog-output-speaker)
INFO     # Card[0], port `analog-output-speaker` selected
DEBUG    .find_stream_port(...)
DEBUG      * card_port = analog-output-speaker, stream.ports = ['hdmi-output-0']
DEBUG      * stream: None
DEBUG    * Switching card[0] to profile `output:analog-stereo+input:analog-stereo` with priority 39333
DEBUG    .find_stream_port(...)
DEBUG      * card_port = analog-output-speaker, stream.ports = ['hdmi-output-0']
DEBUG      * stream: None
ERROR    Failed to map card[0], port `analog-output-speaker` to a stream
DEBUG    .do_context_subscribe(facility: 7, kind: 16, index: 4294967295)
DEBUG    * Activated sink: `alsa_output.pci-0000_00_1f.3.analog-stereo`
DEBUG    * Activated source: `alsa_input.pci-0000_00_1f.3.analog-stereo`
DEBUG    .do_context_subscribe(facility: 1, kind: 32, index: 331)
DEBUG    .do_context_subscribe(facility: 0, kind: 32, index: 330)
DEBUG      - Sink[330] removed: `alsa_output.pci-0000_00_1f.3.hdmi-stereo`
DEBUG    .do_context_subscribe(facility: 0, kind: 16, index: 332)
DEBUG      + Sink[332] added: `alsa_output.pci-0000_00_1f.3.analog-stereo`, card 0
DEBUG        + Sink port added: `analog-output-speaker` (`Speakers`); priority: 10000; available: Yes
DEBUG        + Sink port added: `analog-output-headphones` (`Headphones`); priority: 9900; available: No
DEBUG        * Activated sink port `analog-output-speaker`
DEBUG    .find_stream_port(...)
DEBUG      * card_port = analog-input-internal-mic, stream.ports = ['analog-input-internal-mic', 'analog-input-headphone-mic', 'analog-input-headset-mic']
DEBUG    .find_stream_port(...)
DEBUG      * card_port = analog-input-headphone-mic, stream.ports = ['analog-input-internal-mic', 'analog-input-headphone-mic', 'analog-input-headset-mic']
DEBUG    .find_stream_port(...)
DEBUG      * card_port = analog-input-headset-mic, stream.ports = ['analog-input-internal-mic', 'analog-input-headphone-mic', 'analog-input-headset-mic']
DEBUG    .find_stream_port(...)
DEBUG      * card_port = analog-output-speaker, stream.ports = ['analog-output-speaker', 'analog-output-headphones']
DEBUG    .find_stream_port(...)
DEBUG      * card_port = analog-output-headphones, stream.ports = ['analog-output-speaker', 'analog-output-headphones']
DEBUG    .find_stream_port(...)
DEBUG      * card_port = hdmi-output-0, stream.ports = ['analog-output-speaker', 'analog-output-headphones']
DEBUG    .find_stream_port(...)
DEBUG      * card_port = hdmi-output-1, stream.ports = ['analog-output-speaker', 'analog-output-headphones']
DEBUG    .find_stream_port(...)
DEBUG      * card_port = hdmi-output-2, stream.ports = ['analog-output-speaker', 'analog-output-headphones']
DEBUG    .do_context_subscribe(facility: 1, kind: 16, index: 333)
DEBUG    .do_context_subscribe(facility: 1, kind: 0, index: 333)
DEBUG    .do_context_subscribe(facility: 0, kind: 0, index: 332)
DEBUG      * Sink[332] updated: `alsa_output.pci-0000_00_1f.3.analog-stereo`, card 0
DEBUG        * Activated sink port `analog-output-speaker`
DEBUG    .find_stream_port(...)
DEBUG      * card_port = analog-input-internal-mic, stream.ports = ['analog-input-internal-mic', 'analog-input-headphone-mic', 'analog-input-headset-mic']
DEBUG    .find_stream_port(...)
DEBUG      * card_port = analog-input-headphone-mic, stream.ports = ['analog-input-internal-mic', 'analog-input-headphone-mic', 'analog-input-headset-mic']
DEBUG    .find_stream_port(...)
DEBUG      * card_port = analog-input-headset-mic, stream.ports = ['analog-input-internal-mic', 'analog-input-headphone-mic', 'analog-input-headset-mic']
DEBUG    .find_stream_port(...)
DEBUG      * card_port = analog-output-speaker, stream.ports = ['analog-output-speaker', 'analog-output-headphones']
DEBUG    .find_stream_port(...)
DEBUG      * card_port = analog-output-headphones, stream.ports = ['analog-output-speaker', 'analog-output-headphones']
DEBUG    .find_stream_port(...)
DEBUG      * card_port = hdmi-output-0, stream.ports = ['analog-output-speaker', 'analog-output-headphones']
DEBUG    .find_stream_port(...)
DEBUG      * card_port = hdmi-output-1, stream.ports = ['analog-output-speaker', 'analog-output-headphones']
DEBUG    .find_stream_port(...)
DEBUG      * card_port = hdmi-output-2, stream.ports = ['analog-output-speaker', 'analog-output-headphones']
DEBUG    .do_context_subscribe(facility: 2, kind: 16, index: 1)
DEBUG    .do_context_subscribe(facility: 2, kind: 16, index: 2)
DEBUG    .do_context_subscribe(facility: 2, kind: 16, index: 4)
DEBUG    .do_context_subscribe(facility: 2, kind: 16, index: 5)
DEBUG    .do_context_subscribe(facility: 2, kind: 16, index: 6)
DEBUG    .do_context_subscribe(facility: 2, kind: 16, index: 7)
DEBUG    .do_context_subscribe(facility: 2, kind: 16, index: 8)
DEBUG    .do_context_subscribe(facility: 9, kind: 16, index: 0)
DEBUG      * Card[0] updated
DEBUG        * Activated profile: `output:analog-stereo+input:analog-stereo` (`Analog Stereo Duplex`)
DEBUG    .do_context_subscribe(facility: 1, kind: 32, index: 332)
DEBUG    .do_context_subscribe(facility: 0, kind: 32, index: 331)
DEBUG    .find_stream_port(...)
DEBUG      * card_port = analog-input-internal-mic, stream.ports = ['analog-input-internal-mic', 'analog-input-headphone-mic', 'analog-input-headset-mic']
DEBUG    .find_stream_port(...)
DEBUG      * card_port = analog-input-headphone-mic, stream.ports = ['analog-input-internal-mic', 'analog-input-headphone-mic', 'analog-input-headset-mic']
DEBUG    .find_stream_port(...)
DEBUG      * card_port = analog-input-headset-mic, stream.ports = ['analog-input-internal-mic', 'analog-input-headphone-mic', 'analog-input-headset-mic']
DEBUG    .find_stream_port(...)
DEBUG      * card_port = analog-output-speaker, stream.ports = ['analog-output-speaker', 'analog-output-headphones']
DEBUG    .find_stream_port(...)
DEBUG      * card_port = analog-output-headphones, stream.ports = ['analog-output-speaker', 'analog-output-headphones']
DEBUG    .find_stream_port(...)
DEBUG      * card_port = hdmi-output-0, stream.ports = ['analog-output-speaker', 'analog-output-headphones']
DEBUG    .find_stream_port(...)
DEBUG      * card_port = hdmi-output-1, stream.ports = ['analog-output-speaker', 'analog-output-headphones']
DEBUG    .find_stream_port(...)
DEBUG      * card_port = hdmi-output-2, stream.ports = ['analog-output-speaker', 'analog-output-headphones']
DEBUG    .activate_port(0, hdmi-output-0)
INFO     # Card[0], port `hdmi-output-0` selected
DEBUG    .find_stream_port(...)
DEBUG      * card_port = hdmi-output-0, stream.ports = ['analog-output-speaker', 'analog-output-headphones']
DEBUG      * stream: None
DEBUG    * Switching card[0] to profile `output:hdmi-stereo+input:analog-stereo` with priority 38733
DEBUG    .find_stream_port(...)
DEBUG      * card_port = hdmi-output-0, stream.ports = ['analog-output-speaker', 'analog-output-headphones']
DEBUG      * stream: None
ERROR    Failed to map card[0], port `hdmi-output-0` to a stream
DEBUG    .do_context_subscribe(facility: 7, kind: 16, index: 4294967295)
DEBUG    * Activated sink: `alsa_output.pci-0000_00_1f.3.hdmi-stereo`
DEBUG    * Activated source: `alsa_input.pci-0000_00_1f.3.analog-stereo`
DEBUG    .do_context_subscribe(facility: 1, kind: 32, index: 333)
DEBUG    .do_context_subscribe(facility: 0, kind: 32, index: 332)
DEBUG      - Sink[332] removed: `alsa_output.pci-0000_00_1f.3.analog-stereo`
DEBUG    .do_context_subscribe(facility: 0, kind: 16, index: 334)
DEBUG      + Sink[334] added: `alsa_output.pci-0000_00_1f.3.hdmi-stereo`, card 0
DEBUG        + Sink port added: `hdmi-output-0` (`HDMI / DisplayPort`); priority: 5900; available: Yes
DEBUG        * Activated sink port `hdmi-output-0`
DEBUG    .find_stream_port(...)
DEBUG      * card_port = analog-input-internal-mic, stream.ports = ['analog-input-internal-mic', 'analog-input-headphone-mic', 'analog-input-headset-mic']
DEBUG    .find_stream_port(...)
DEBUG      * card_port = analog-input-headphone-mic, stream.ports = ['analog-input-internal-mic', 'analog-input-headphone-mic', 'analog-input-headset-mic']
DEBUG    .find_stream_port(...)
DEBUG      * card_port = analog-input-headset-mic, stream.ports = ['analog-input-internal-mic', 'analog-input-headphone-mic', 'analog-input-headset-mic']
DEBUG    .find_stream_port(...)
DEBUG      * card_port = analog-output-speaker, stream.ports = ['hdmi-output-0']
DEBUG    .find_stream_port(...)
DEBUG      * card_port = analog-output-headphones, stream.ports = ['hdmi-output-0']
DEBUG    .find_stream_port(...)
DEBUG      * card_port = hdmi-output-0, stream.ports = ['hdmi-output-0']
DEBUG    .find_stream_port(...)
DEBUG      * card_port = hdmi-output-1, stream.ports = ['hdmi-output-0']
DEBUG    .find_stream_port(...)
DEBUG      * card_port = hdmi-output-2, stream.ports = ['hdmi-output-0']
DEBUG    .do_context_subscribe(facility: 1, kind: 16, index: 335)
DEBUG    .do_context_subscribe(facility: 1, kind: 0, index: 335)
DEBUG    .do_context_subscribe(facility: 0, kind: 0, index: 334)
DEBUG      * Sink[334] updated: `alsa_output.pci-0000_00_1f.3.hdmi-stereo`, card 0
DEBUG        * Activated sink port `hdmi-output-0`
DEBUG    .find_stream_port(...)
DEBUG      * card_port = analog-input-internal-mic, stream.ports = ['analog-input-internal-mic', 'analog-input-headphone-mic', 'analog-input-headset-mic']
DEBUG    .find_stream_port(...)
DEBUG      * card_port = analog-input-headphone-mic, stream.ports = ['analog-input-internal-mic', 'analog-input-headphone-mic', 'analog-input-headset-mic']
DEBUG    .find_stream_port(...)
DEBUG      * card_port = analog-input-headset-mic, stream.ports = ['analog-input-internal-mic', 'analog-input-headphone-mic', 'analog-input-headset-mic']
DEBUG    .find_stream_port(...)
DEBUG      * card_port = analog-output-speaker, stream.ports = ['hdmi-output-0']
DEBUG    .find_stream_port(...)
DEBUG      * card_port = analog-output-headphones, stream.ports = ['hdmi-output-0']
DEBUG    .find_stream_port(...)
DEBUG      * card_port = hdmi-output-0, stream.ports = ['hdmi-output-0']
DEBUG    .find_stream_port(...)
DEBUG      * card_port = hdmi-output-1, stream.ports = ['hdmi-output-0']
DEBUG    .find_stream_port(...)
DEBUG      * card_port = hdmi-output-2, stream.ports = ['hdmi-output-0']
DEBUG    .do_context_subscribe(facility: 2, kind: 16, index: 1)
DEBUG    .do_context_subscribe(facility: 2, kind: 16, index: 2)
DEBUG    .do_context_subscribe(facility: 2, kind: 16, index: 4)
DEBUG    .do_context_subscribe(facility: 2, kind: 16, index: 5)
DEBUG    .do_context_subscribe(facility: 2, kind: 16, index: 6)
DEBUG    .do_context_subscribe(facility: 2, kind: 16, index: 7)
DEBUG    .do_context_subscribe(facility: 2, kind: 16, index: 8)
DEBUG    .do_context_subscribe(facility: 9, kind: 16, index: 0)
DEBUG      * Card[0] updated
DEBUG        * Activated profile: `output:hdmi-stereo+input:analog-stereo` (`Digital Stereo (HDMI) Output + Analog Stereo Input`)
DEBUG    .do_context_subscribe(facility: 1, kind: 32, index: 334)
DEBUG    .do_context_subscribe(facility: 0, kind: 32, index: 333)
DEBUG    .find_stream_port(...)
DEBUG      * card_port = analog-input-internal-mic, stream.ports = ['analog-input-internal-mic', 'analog-input-headphone-mic', 'analog-input-headset-mic']
DEBUG    .find_stream_port(...)
DEBUG      * card_port = analog-input-headphone-mic, stream.ports = ['analog-input-internal-mic', 'analog-input-headphone-mic', 'analog-input-headset-mic']
DEBUG    .find_stream_port(...)
DEBUG      * card_port = analog-input-headset-mic, stream.ports = ['analog-input-internal-mic', 'analog-input-headphone-mic', 'analog-input-headset-mic']
DEBUG    .find_stream_port(...)
DEBUG      * card_port = analog-output-speaker, stream.ports = ['hdmi-output-0']
DEBUG    .find_stream_port(...)
DEBUG      * card_port = analog-output-headphones, stream.ports = ['hdmi-output-0']
DEBUG    .find_stream_port(...)
DEBUG      * card_port = hdmi-output-0, stream.ports = ['hdmi-output-0']
DEBUG    .find_stream_port(...)
DEBUG      * card_port = hdmi-output-1, stream.ports = ['hdmi-output-0']
DEBUG    .find_stream_port(...)
DEBUG      * card_port = hdmi-output-2, stream.ports = ['hdmi-output-0']

Analysis The problem seems to be that my computer's sound card only lists the ports in question when the corresponding profiles are active. That is, hdmi-output-0 is only active when a profile like output:hdmi-stereo+input:analog-stereo is active, and conversely analog-output-speaker and analog-output-headphones are only available when output:analog-stereo+input:analog-stereo is active.

This already seems to be what was addressed by 5fb737c, with these lines:

            # Try to find a matching stream
            stream = card.find_stream_port(port, self.sources, self.sinks)[0]

            # Switch profile if necessary
            if self.card_switch_profile(port, stream is not None):
                # Profile is changed: retry searching for the stream
                stream = card.find_stream_port(port, self.sources, self.sinks)[0]

However, as shown by the logging I added to card.find_stream_port, the contents of self.sinks is never updated after switching profile! This stale information of course causes the second lookup to fail, just like the first one did.

It seems prudent to force a refresh of the Pulseaudio data from within card_switch_profile. I have confirmed that adding the following in that function resolves the issue:

--- indicator-sound-switcher-master/lib/indicator_sound_switcher/indicator.py   2022-06-28 11:41:13.000000000 +0200
+++ /usr/local/lib/python3.11/site-packages/indicator_sound_switcher/indicator.py   2024-03-25 02:03:06.654038395 +0100
@@ -567,6 +567,8 @@
                 selected_profile.name.encode(),
                 self._pacb_context_success,
                 None))
+        self.update_all_pa_items()
+
         return True

     # ------------------------------------------------------------------------------------------------------------------
alsimoneau commented 2 months ago

Any progress on this? This issue depreciated the AUR package.

yktoo commented 1 month ago

@jmickelin Thanks for investigating this and sorry for the late response. Here you refer to ports:

The problem seems to be that my computer's sound card only lists the ports in question when the corresponding profiles are active.

whereas further on you mention the sink list that doesn't get to be updated:

However, as shown by the logging I added to card.find_stream_port, the contents of self.sinks is never updated after switching profile!

Did I understand you correctly that in this second excerpt you refer to sink ports that are supposed to be re-read?

Besides, update_all_pa_items() updates each and every PA object. So should the problem indeed lie in the port list, I'd prefer to use a more targeted method for the update.

On a side note, PulseAudio issues like this one are extremely hard to properly analyse because they depend on specific devices, PA modules in use, and even on the PA version.

yktoo commented 1 month ago

@alsimoneau What do you mean with "depreciated the AUR package"? This issue doesn't seem to be package-specific, rather a device-specific one.

alsimoneau commented 1 month ago

Here's the link to the AUR package: https://aur.archlinux.org/packages/indicator-sound-switcher

As you can see here, it's flagged as out-of-date because of this issue.

yktoo commented 1 month ago

@alsimoneau The comment there states:

Need to change from legacy dependency 'libappindicator-gtk3' to 'libayatana-appindicator'; also revert a commit that introduced a regression: https://github.com/yktoo/indicator-sound-switcher/issues/132

Not sure we can call it a "regression", it's more of an incomplete fix.

As for the change "from legacy dependency 'libappindicator-gtk3' to 'libayatana-appindicator'", that doesn't seem to be correct as it Depends on gir1.2-ayatanaappindicator3-0.1 | gir1.2-appindicator3-0.1.

UPDATE: I see that the AUR package has a few incorrect dependencies indeed; however it's been submitted by someone else so I can't maintain it.

yktoo commented 1 month ago

I've (seemingly) resolved the issue by enforcing a stream update after a profile switch. However to be honest, the change doesn't sit right with me as it looks more like a workaround rather than a solution.

If we look closely to your logs, we can see that the streams and ports do get updated as a result of PulseAudio event handling. Here's an excerpt starting with an output item click:

DEBUG    .activate_port(0, hdmi-output-0)
INFO     # Card[0], port `hdmi-output-0` selected
DEBUG    .find_stream_port(...)
DEBUG      * card_port = hdmi-output-0, stream.ports = ['analog-output-speaker', 'analog-output-headphones']
DEBUG      * stream: None
DEBUG    * Switching card[0] to profile `output:hdmi-stereo+input:analog-stereo` with priority 38733
DEBUG    .find_stream_port(...)
DEBUG      * card_port = hdmi-output-0, stream.ports = ['analog-output-speaker', 'analog-output-headphones']
DEBUG      * stream: None
ERROR    Failed to map card[0], port `hdmi-output-0` to a stream
DEBUG    .do_context_subscribe(facility: 7, kind: 16, index: 4294967295)
DEBUG    * Activated sink: `alsa_output.pci-0000_00_1f.3.hdmi-stereo`
DEBUG    * Activated source: `alsa_input.pci-0000_00_1f.3.analog-stereo`
DEBUG    .do_context_subscribe(facility: 1, kind: 32, index: 333)
DEBUG    .do_context_subscribe(facility: 0, kind: 32, index: 332)
DEBUG      - Sink[332] removed: `alsa_output.pci-0000_00_1f.3.analog-stereo`
DEBUG    .do_context_subscribe(facility: 0, kind: 16, index: 334)
DEBUG      + Sink[334] added: `alsa_output.pci-0000_00_1f.3.hdmi-stereo`, card 0
DEBUG        + Sink port added: `hdmi-output-0` (`HDMI / DisplayPort`); priority: 5900; available: Yes
DEBUG        * Activated sink port `hdmi-output-0`
[...]

The problem is actually not so much in the (lack of) update, but rather that the app tries to find a stream/port immediately upon a profile switch; PulseAudio fires change events a short while later, and they get properly handled, resulting in registering a newly available port.

If I'm correct, the output will always be selected on a second click; and I can confirm it works that way for me indeed.

Hence the proper solution would be to wait until PA event handling is finished, and then to try remapping the streams. Will need to ponder a bit more over that...

yktoo commented 1 month ago

I decided to go ahead and release this in 2.3.10. The issue seems too complicated to be properly resolved without update duplication: PulseAudio issues events asynchronously and there's basically no way to know how many events to expect or if a certain event is the last one.