fix: broadcast external volume/mute changes + fix browser stream volume

Issue 1 - Volume/mute changes from external apps (browser YT player, pulsemixer)
not reflected in the frontend:
- on_node_param and on_node_info updated node state but never called notifyChanged(),
  so the SSE broadcast was never triggered for external changes.
- Add engine_ref back-pointer to Object (set in create_proxy_for_object).
- Call notifyChanged() at the end of on_node_info and after updating Props
  in on_node_param, so any external volume/mute change immediately broadcasts.

Issue 2 - Volume slider has no audible effect on browser/app streams:
- setNodeVolume only set SPA_PROP_volume (single float). Browser streams
  (Chromium, Firefox) use SPA_PROP_channelVolumes (per-channel float array)
  and ignore the single-float property.
- Now set both SPA_PROP_volume AND SPA_PROP_channelVolumes (using the node's
  known channel count, defaulting to stereo if unknown). ALSA hardware nodes
  respond to SPA_PROP_volume; app streams respond to SPA_PROP_channelVolumes.

Note: wires auto-reconnecting is WirePlumber session policy (by design) —
WirePlumber re-links any stream that loses its connection to the default sink.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
joren
2026-03-30 12:30:56 +02:00
parent b3c81623f1
commit 0d3cfb5f86
2 changed files with 29 additions and 11 deletions

View File

@@ -72,15 +72,16 @@ public:
// Object management (called from C callbacks)
struct Object {
enum Type { ObjNode, ObjPort, ObjLink };
uint32_t id;
Type type;
void *proxy;
void *info;
void (*destroy_info)(void*);
spa_hook proxy_listener;
spa_hook object_listener;
int pending_seq;
spa_list pending_link;
uint32_t id;
Type type;
void *proxy;
void *info;
void (*destroy_info)(void*);
spa_hook proxy_listener;
spa_hook object_listener;
int pending_seq;
spa_list pending_link;
GraphEngine *engine_ref; // back-pointer set in create_proxy_for_object
Object(uint32_t id, Type type);
virtual ~Object();