diff options
-rw-r--r-- | src/main.c | 8 | ||||
-rw-r--r-- | src/volume-control-pulse.vala | 8 | ||||
-rw-r--r-- | src/volume-warning.vala | 208 |
3 files changed, 189 insertions, 35 deletions
@@ -22,6 +22,7 @@ #include "config.h" static IndicatorSoundService * service = NULL; +static pa_glib_mainloop * pgloop = NULL; static gboolean sigterm_handler (gpointer data) @@ -59,9 +60,10 @@ on_bus_acquired(GDBusConnection *connection, accounts = accounts_service_user_new(); } + pgloop = pa_glib_mainloop_new(NULL); options = indicator_sound_options_gsettings_new(); - volume = volume_control_pulse_new(options); - warning = volume_warning_new(options); + volume = volume_control_pulse_new(options, pgloop); + warning = volume_warning_new(options, pgloop); service = indicator_sound_service_new (playerlist, volume, accounts, options, warning); @@ -76,7 +78,6 @@ int main (int argc, char ** argv) { GMainLoop * loop = NULL; - bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); setlocale (LC_ALL, ""); bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR); @@ -101,6 +102,7 @@ main (int argc, char ** argv) g_main_loop_run(loop); g_clear_object(&service); + g_clear_pointer(&pgloop, pa_glib_mainloop_free); notify_uninit(); diff --git a/src/volume-control-pulse.vala b/src/volume-control-pulse.vala index 2179d7a..efbbb97 100644 --- a/src/volume-control-pulse.vala +++ b/src/volume-control-pulse.vala @@ -34,8 +34,7 @@ interface GreeterListInterface : Object public class VolumeControlPulse : VolumeControl { - /* this is static to ensure it being freed after @context (loop does not have ref counting) */ - private static PulseAudio.GLibMainLoop loop; + private unowned PulseAudio.GLibMainLoop loop = null; private uint _reconnect_timer = 0; @@ -72,15 +71,14 @@ public class VolumeControlPulse : VolumeControl /** true when a microphone is active **/ public override bool active_mic { get; private set; default = false; } - public VolumeControlPulse (IndicatorSound.Options options) + public VolumeControlPulse (IndicatorSound.Options options, PulseAudio.GLibMainLoop loop) { base(options); _volume.volume = 0.0; _volume.reason = VolumeControl.VolumeReasons.PULSE_CHANGE; - if (loop == null) - loop = new PulseAudio.GLibMainLoop (); + this.loop = loop; _mute_cancellable = new Cancellable (); _volume_cancellable = new Cancellable (); diff --git a/src/volume-warning.vala b/src/volume-warning.vala index 2ae3b9b..eb6b3d5 100644 --- a/src/volume-warning.vala +++ b/src/volume-warning.vala @@ -46,16 +46,17 @@ public class VolumeWarning : Object on_user_response(IndicatorSound.WarnNotification.Response.CANCEL); } - public VolumeWarning (IndicatorSound.Options options) { + public VolumeWarning (IndicatorSound.Options options, PulseAudio.GLibMainLoop pgloop) { _options = options; + _pgloop = pgloop; init_all_properties(); - connect_to_stream_restore.begin(); + pulse_start(); _notification = new IndicatorSound.WarnNotification(); _notification.user_responded.connect((n, response) => on_user_response(response)); - } + } /*** **** @@ -71,6 +72,7 @@ public class VolumeWarning : Object protected virtual async void set_pulse_multimedia_volume(PulseAudio.Volume volume) { +#if 0 var objp = _multimedia_objp; if (objp == null) return; @@ -90,6 +92,7 @@ public class VolumeWarning : Object } catch (GLib.Error e) { warning ("unable to set multimedia volume for stream obj path %s (%s)", objp, e.message); } +#endif } /*** @@ -99,8 +102,10 @@ public class VolumeWarning : Object // FIXME: what to do with this now? private bool _ignore_warning_this_time = false; +#if 0 /* Used by the pulseaudio stream restore extension */ private DBusConnection _pconn; +#endif private IndicatorSound.Options _options; @@ -113,6 +118,8 @@ public class VolumeWarning : Object ~VolumeWarning () { stop_all_timers(); + + pulse_stop(); } private void stop_all_timers() @@ -122,38 +129,184 @@ public class VolumeWarning : Object } /*** - **** Tracking multimedia volume via StreamRestore + **** PulseAudio: Tracking which sink input (if any) is active multimedia ***/ - private DBusMessage pulse_dbus_filter (DBusConnection connection, owned DBusMessage message, bool incoming) + private unowned PulseAudio.GLibMainLoop _pgloop = null; + private PulseAudio.Context _pulse_context = null; + private uint _pulse_reconnect_timer = 0; + private uint32 _multimedia_sink_input_index = PulseAudio.INVALID_INDEX; + + private bool is_active_multimedia (SinkInputInfo i) + { + if (i.corked != 0) + return false; + + GLib.message("proplist: %s", i.proplist.to_string()); + var media_role = i.proplist.gets(PulseAudio.Proplist.PROP_MEDIA_ROLE); + if (media_role != "multimedia") + return false; + + return true; + } + + private PulseAudio.Operation _sink_input_info_list_operation = null; + + private void pulse_on_sink_input_info (Context c, SinkInputInfo? i, int eol) { - if (message.get_message_type() == DBusMessageType.SIGNAL) + if (i == null) + return; + + bool active = is_active_multimedia(i); + + if (active) + _multimedia_sink_input_index = i.index; + else if (i.index == _multimedia_sink_input_index) + _multimedia_sink_input_index = PulseAudio.INVALID_INDEX; + + if (active) { + GLib.message("index %d", (int)i.index); + GLib.message("name %s", i.name); + GLib.message("sink %d", (int)i.sink); + GLib.message("has_volume %d", (int)i.has_volume); + GLib.message("volume %s", i.volume.to_string()); + GLib.message("driver %s", i.driver); + } + + if (eol != 0) + GLib.message("at end of list, _multimedia_sink_input_index is %d", (int)_multimedia_sink_input_index); + } + + private void pulse_update_sink_inputs_cancel() + { + if (_sink_input_info_list_operation != null) { - var member = message.get_member(); - var path = message.get_path(); - GLib.message ("path [%s] member [%s] _multimedia_objp [%s]", path, member, _multimedia_objp); - - if ((member == "VolumeUpdated") && (path == _multimedia_objp)) - { - Variant body = message.get_body (); - Variant varray = body.get_child_value (0); - uint32 type = 0, lvolume = 0; - VariantIter iter = varray.iterator (); - iter.next ("(uu)", &type, &lvolume); - if (multimedia_volume != lvolume) { - GLib.message("setting multimedia_volume to %d from VolumeUpdated signal %s", (int)lvolume, body.print(true)); - multimedia_volume = lvolume; - } - } - else if (((member == "NewEntry") || (member == "EntryRemoved")) && (path == "/org/pulseaudio/stream_restore1")) - { - update_multimedia_objp(); - } + _sink_input_info_list_operation.cancel(); + _sink_input_info_list_operation = null; + } + } + + private void pulse_update_sink_inputs() + { + GLib.message("list_input_sinks"); + + pulse_update_sink_inputs_cancel (); + + _sink_input_info_list_operation = _pulse_context.get_sink_input_info_list (pulse_on_sink_input_info); + } + + + private void context_events_cb (Context c, Context.SubscriptionEventType t, uint32 index) + { + GLib.message(""); + if ((t & Context.SubscriptionEventType.FACILITY_MASK) != Context.SubscriptionEventType.SINK_INPUT) + return; + + switch (t & Context.SubscriptionEventType.TYPE_MASK) + { + case Context.SubscriptionEventType.NEW: + GLib.message("Context.SubscriptionEventType.NEW"); + pulse_update_sink_inputs(); + break; + case Context.SubscriptionEventType.CHANGE: + GLib.message("Context.SubscriptionEventType.CHANGE"); + pulse_update_sink_inputs(); + break; + case Context.SubscriptionEventType.REMOVE: + GLib.message("Context.SubscriptionEventType.REMOVE"); + pulse_update_sink_inputs(); + break; + default: + GLib.message("Sink input event not known."); + break; } + } + + private void pulse_context_state_callback (Context c) + { + switch (c.get_state ()) { + case Context.State.READY: + c.subscribe (PulseAudio.Context.SubscriptionMask.SINK_INPUT); + c.set_subscribe_callback (context_events_cb); + pulse_update_sink_inputs(); + break; + + case Context.State.FAILED: + case Context.State.TERMINATED: + pulse_reconnect_soon(); + break; + + default: + break; + } + } + + private void pulse_disconnect() + { + if (_pulse_context != null) { + _pulse_context.disconnect (); + _pulse_context = null; + } + } - return message; + private void pulse_reconnect_soon () + { + if (_pulse_reconnect_timer == 0) + _pulse_reconnect_timer = Timeout.add_seconds (2, pulse_reconnect_timeout); } + private void pulse_reconnect_soon_cancel() + { + if (_pulse_reconnect_timer != 0) { + Source.remove(_pulse_reconnect_timer); + _pulse_reconnect_timer = 0; + } + } + + private bool pulse_reconnect_timeout () + { + _pulse_reconnect_timer = 0; + pulse_reconnect (); + return false; // G_SOURCE_REMOVE + } + + void pulse_reconnect () + { + pulse_disconnect(); + + var props = new Proplist (); + props.sets (Proplist.PROP_APPLICATION_NAME, "Ubuntu Audio Settings"); + props.sets (Proplist.PROP_APPLICATION_ID, "com.canonical.settings.sound"); + props.sets (Proplist.PROP_APPLICATION_ICON_NAME, "multimedia-volume-control"); + props.sets (Proplist.PROP_APPLICATION_VERSION, "0.1"); + + _pulse_context = new PulseAudio.Context (_pgloop.get_api(), null, props); + _pulse_context.set_state_callback (pulse_context_state_callback); + + var server_string = Environment.get_variable("PULSE_SERVER"); + if (_pulse_context.connect(server_string, Context.Flags.NOFAIL, null) < 0) + warning( "pa_context_connect() failed: %s\n", PulseAudio.strerror(_pulse_context.errno())); + } + + + private void pulse_start() + { + pulse_reconnect(); + } + + private void pulse_stop() + { + pulse_reconnect_soon_cancel(); + pulse_disconnect(); + pulse_update_sink_inputs_cancel(); + } + +#if 0 + /*** + **** Tracking multimedia volume via StreamRestore + ***/ + + private async void connect_to_stream_restore() { _pconn = VolumeControlPulse.create_pulse_dbus_connection(); @@ -240,6 +393,7 @@ public class VolumeWarning : Object warning ("unable to get volume for multimedia role %s (%s)", _multimedia_objp, e.message); } } +#endif /** HIGH VOLUME PROPERTY **/ |