diff options
author | charles kerr <charlesk@canonical.com> | 2015-12-20 16:18:57 -0600 |
---|---|---|
committer | charles kerr <charlesk@canonical.com> | 2015-12-20 16:18:57 -0600 |
commit | ace782578de3c7d895070d20d61d5fbf5b869633 (patch) | |
tree | 4d5589908157431235fa8f9cd82f50feb67298d9 /src | |
parent | 60cd7ac64849bfc21be1a85063f5730ad22f9d72 (diff) | |
download | ayatana-indicator-sound-ace782578de3c7d895070d20d61d5fbf5b869633.tar.gz ayatana-indicator-sound-ace782578de3c7d895070d20d61d5fbf5b869633.tar.bz2 ayatana-indicator-sound-ace782578de3c7d895070d20d61d5fbf5b869633.zip |
remove code duplication between volume-warning and volume-control-pulse
let volume-warning's 'multimedia_active' and 'headphones_active' be
bound to volume-control's 'active-stream' and 'active-output' properties.
Service manages the bindings.
This lets us remove all the pacontext code from volume-warning.
Diffstat (limited to 'src')
-rw-r--r-- | src/service.vala | 22 | ||||
-rw-r--r-- | src/volume-warning.vala | 323 |
2 files changed, 36 insertions, 309 deletions
diff --git a/src/service.vala b/src/service.vala index acaf639..fbeb886 100644 --- a/src/service.vala +++ b/src/service.vala @@ -49,8 +49,26 @@ public class IndicatorSound.Service: Object { this.notify["visible"].connect ( () => this.update_root_icon () ); this.volume_control = volume; - this.volume_control.active_output_changed.connect(() => this.update_root_icon()); - this.volume_control.active_output_changed.connect(() => this.update_notification()); + this.volume_control.notify["active-stream"].connect(() => { + _volume_warning.multimedia_active = + VolumeControl.Stream.MULTIMEDIA == volume_control.active_stream; + }); + this.volume_control.active_output_changed.connect(() => { + switch(volume_control.active_output) { + case VolumeControl.ActiveOutput.HEADPHONES: + case VolumeControl.ActiveOutput.USB_HEADPHONES: + case VolumeControl.ActiveOutput.HDMI_HEADPHONES: + case VolumeControl.ActiveOutput.BLUETOOTH_HEADPHONES: + _volume_warning.headphones_active = true; + break; + + default: + _volume_warning.headphones_active = false; + break; + } + update_root_icon(); + update_notification(); + }); this.accounts_service = accounts; /* If we're on the greeter, don't export */ diff --git a/src/volume-warning.vala b/src/volume-warning.vala index 869020e..d8b0040 100644 --- a/src/volume-warning.vala +++ b/src/volume-warning.vala @@ -27,8 +27,14 @@ extern unowned PulseAudio.CVolume? vol_set2 (PulseAudio.CVolume? cv, uint channe public class VolumeWarning : Object { + // true if the active sink input has its role property set to multimedia + public bool multimedia_active { get; set; default = false; } + + // true if headphones are currently in use + public bool headphones_active { get; set; default = false; } + // true if the warning dialog is currently active - public bool active { get; public set; default = false; } + public bool active { get; protected set; default = false; } // true if we're playing unapproved loud multimedia over headphones public bool high_volume { get; protected set; default = false; } @@ -46,12 +52,9 @@ public class VolumeWarning : Object public VolumeWarning (IndicatorSound.Options options) { _options = options; - if (loop == null) - loop = new PulseAudio.GLibMainLoop (); - init_all_properties(); - this.reconnect_to_pulse (); + connect_to_stream_restore.begin(); _notification = new IndicatorSound.WarnNotification(); _notification.user_responded.connect((n, response) => on_user_response(response)); @@ -64,15 +67,9 @@ public class VolumeWarning : Object // true if the user has approved high volumes recently protected bool high_volume_approved { get; set; default = false; } - // true if the active sink input has its role property set to multimedia - protected bool multimedia_active { get; set; default = false; } - // the multimedia volume protected PulseAudio.Volume multimedia_volume { get; set; default = PulseAudio.Volume.MUTED; } - // true if headphones are currently in use - protected bool headphones_active { get; set; default = false; } - protected virtual async void set_pulse_multimedia_volume(PulseAudio.Volume volume) { var objp = _multimedia_objp; @@ -98,31 +95,12 @@ public class VolumeWarning : Object **** ***/ - /* this is static to ensure it being freed after @context (loop does not have ref counting) */ - private static PulseAudio.GLibMainLoop loop; - - private PulseAudio.Context context; // FIXME: what to do with this now? private bool _ignore_warning_this_time = false; - private Settings _settings = new Settings ("com.canonical.indicator.sound"); /* Used by the pulseaudio stream restore extension */ private DBusConnection _pconn; - /* Need both the list and hash so we can retrieve the last known sink-input after - * releasing the current active one (restoring back to the previous known role) */ - private Gee.ArrayList<uint32> _sink_input_list = new Gee.ArrayList<uint32> (); - private HashMap<uint32, string> _sink_input_hash = new HashMap<uint32, string> (); - private bool _pulse_use_stream_restore = false; - private int32 _active_sink_input = -1; - private string[] _valid_roles = {"multimedia", "alert", "alarm", "phone"}; - - private string? _objp_role_multimedia = null; - private string? _objp_role_alert = null; - private string? _objp_role_alarm = null; - private string? _objp_role_phone = null; - private uint _pa_volume_sig_count = 0; - - private VolumeControl.ActiveOutput _active_output = VolumeControl.ActiveOutput.SPEAKERS; + private IndicatorSound.Options _options; private void init_all_properties() @@ -138,85 +116,13 @@ public class VolumeWarning : Object private void stop_all_timers() { - stop_reconnect_timer(); stop_high_volume_approved_timer(); stop_clamp_to_loud_timeout(); } - /* PulseAudio logic*/ - private void context_events_cb (Context c, Context.SubscriptionEventType t, uint32 index) - { - switch (t & Context.SubscriptionEventType.FACILITY_MASK) - { - case Context.SubscriptionEventType.SINK: - update_sink (); - break; - - case Context.SubscriptionEventType.SINK_INPUT: - switch (t & Context.SubscriptionEventType.TYPE_MASK) - { - case Context.SubscriptionEventType.NEW: - c.get_sink_input_info (index, handle_new_sink_input_cb); - break; - - case Context.SubscriptionEventType.CHANGE: - c.get_sink_input_info (index, handle_changed_sink_input_cb); - break; - - case Context.SubscriptionEventType.REMOVE: - remove_sink_input_from_list (index); - break; - default: - debug ("Sink input event not known."); - break; - } - break; - - case Context.SubscriptionEventType.SOURCE: - case Context.SubscriptionEventType.SOURCE_OUTPUT: - break; - } - } - - private void sink_info_cb_for_props (Context c, SinkInfo? i, int eol) - { - if (i == null) - return; - - var old_active_output = active_output; - var new_active_output = VolumeControlPulse.calculate_active_output(i); - - _active_output = new_active_output; - - switch (new_active_output) { - case VolumeControl.ActiveOutput.HEADPHONES: - case VolumeControl.ActiveOutput.USB_HEADPHONES: - case VolumeControl.ActiveOutput.HDMI_HEADPHONES: - case VolumeControl.ActiveOutput.BLUETOOTH_HEADPHONES: - headphones_active = true; - break; - - default: - headphones_active = false; - break; - } - - if ((new_active_output != old_active_output) - && (new_active_output != VolumeControl.ActiveOutput.CALL_MODE) - && (old_active_output != VolumeControl.ActiveOutput.CALL_MODE)) - update_high_volume(); - } - - private void server_info_cb_for_props (Context c, ServerInfo? i) - { - if (i != null) - context.get_sink_info_by_name (i.default_sink_name, sink_info_cb_for_props); - } - - private void update_sink () - { - context.get_server_info (server_info_cb_for_props); - } + /*** + **** Tracking multimedia volume via StreamRestore + ***/ private DBusMessage pulse_dbus_filter (DBusConnection connection, owned DBusMessage message, bool incoming) { @@ -224,6 +130,7 @@ public class VolumeWarning : Object { var member = message.get_member(); var path = message.get_path(); + GLib.message ("path [%s] member [%s]", path, member); if ((member == "VolumeUpdated") && (path == _multimedia_objp)) { @@ -244,202 +151,14 @@ public class VolumeWarning : Object return message; } - private async void update_active_sink_input (int32 index) - { - if ((index == -1) || (index != _active_sink_input && index in _sink_input_list)) { - string sink_input_objp = _objp_role_alert; - if (index != -1) - sink_input_objp = _sink_input_hash.get (index); - _active_sink_input = index; - - multimedia_active = (index != -1) - && (_sink_input_hash.get(index) == _objp_role_multimedia); - - } - } - - private void add_sink_input_into_list (SinkInputInfo sink_input) - { - /* We're only adding ones that are not corked and with a valid role */ - var role = sink_input.proplist.gets (PulseAudio.Proplist.PROP_MEDIA_ROLE); - - if (role != null && role in _valid_roles) { - if (sink_input.corked == 0 || role == "phone") { - _sink_input_list.insert (0, sink_input.index); - switch (role) - { - case "multimedia": - _sink_input_hash.set (sink_input.index, _objp_role_multimedia); - break; - case "alert": - _sink_input_hash.set (sink_input.index, _objp_role_alert); - break; - case "alarm": - _sink_input_hash.set (sink_input.index, _objp_role_alarm); - break; - case "phone": - _sink_input_hash.set (sink_input.index, _objp_role_phone); - break; - } - /* Only switch the active sink input in case a phone one is not active */ - if (_active_sink_input == -1 || - _sink_input_hash.get (_active_sink_input) != _objp_role_phone) - update_active_sink_input.begin ((int32)sink_input.index); - } - } - } - - private void remove_sink_input_from_list (uint32 index) - { - if (index in _sink_input_list) { - _sink_input_list.remove (index); - _sink_input_hash.unset (index); - if (index == _active_sink_input) { - if (_sink_input_list.size != 0) - update_active_sink_input.begin ((int32)_sink_input_list.get (0)); - else - update_active_sink_input.begin (-1); - } - } - } - - private void handle_new_sink_input_cb (Context c, SinkInputInfo? i, int eol) - { - if (i == null) - return; - - add_sink_input_into_list (i); - } - - private void handle_changed_sink_input_cb (Context c, SinkInputInfo? i, int eol) - { - if (i == null) - return; - - if (i.index in _sink_input_list) { - /* Phone stream is always corked, so handle it differently */ - if (i.corked == 1 && _sink_input_hash.get (i.index) != _objp_role_phone) - remove_sink_input_from_list (i.index); - } else { - if (i.corked == 0) - add_sink_input_into_list (i); - } - } - - private bool _connected_to_pulse = false; - - private uint _reconnect_timer = 0; - - private void context_state_callback (Context c) - { - switch (c.get_state ()) { - case Context.State.READY: - if (_pulse_use_stream_restore) { - c.subscribe (PulseAudio.Context.SubscriptionMask.SINK | - PulseAudio.Context.SubscriptionMask.SINK_INPUT | - PulseAudio.Context.SubscriptionMask.SOURCE | - PulseAudio.Context.SubscriptionMask.SOURCE_OUTPUT); - } else { - c.subscribe (PulseAudio.Context.SubscriptionMask.SINK | - PulseAudio.Context.SubscriptionMask.SOURCE | - PulseAudio.Context.SubscriptionMask.SOURCE_OUTPUT); - } - c.set_subscribe_callback (context_events_cb); - update_sink (); - _connected_to_pulse = true; - break; - - case Context.State.FAILED: - case Context.State.TERMINATED: - if (_reconnect_timer == 0) - _reconnect_timer = Timeout.add_seconds (2, reconnect_timeout); - break; - - default: - _connected_to_pulse = false; - break; - } - } - - private void stop_reconnect_timer() - { - if (_reconnect_timer != 0) { - Source.remove (_reconnect_timer); - _reconnect_timer = 0; - } - } - - bool reconnect_timeout () + private async void connect_to_stream_restore() { - _reconnect_timer = 0; - reconnect_to_pulse (); - return false; // G_SOURCE_REMOVE - } - - private void reconnect_to_pulse () - { - if (_connected_to_pulse) { - this.context.disconnect (); - this.context = null; - _connected_to_pulse = false; - } - - reconnect_pulse_dbus (); - - 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"); - this.context = new PulseAudio.Context (loop.get_api(), null, props); - this.context.set_state_callback (context_state_callback); - - var server_string = Environment.get_variable("PULSE_SERVER"); - if (context.connect(server_string, Context.Flags.NOFAIL, null) < 0) - warning( "pa_context_connect() failed: %s\n", PulseAudio.strerror(context.errno())); - } - - private void reconnect_pulse_dbus () - { - /* In case of a reconnect */ - _pulse_use_stream_restore = false; - _pa_volume_sig_count = 0; - _pconn = VolumeControlPulse.create_pulse_dbus_connection(); if (_pconn == null) return; - /* For pulse dbus related events */ _pconn.add_filter (pulse_dbus_filter); - // track the multimedia object path - init_stream_restore.begin(); - - /* Check if the 4 currently supported media roles are already available in StreamRestore - * Roles: multimedia, alert, alarm and phone */ - _objp_role_multimedia = VolumeControlPulse.stream_restore_get_object_path (_pconn, "sink-input-by-media-role:multimedia"); - _objp_role_alert = VolumeControlPulse.stream_restore_get_object_path (_pconn, "sink-input-by-media-role:alert"); - _objp_role_alarm = VolumeControlPulse.stream_restore_get_object_path (_pconn, "sink-input-by-media-role:alarm"); - _objp_role_phone = VolumeControlPulse.stream_restore_get_object_path (_pconn, "sink-input-by-media-role:phone"); - - /* Only use stream restore if every used role is available */ - if (_objp_role_multimedia != null && _objp_role_alert != null && _objp_role_alarm != null && _objp_role_phone != null) { - debug ("Using PulseAudio DBUS Stream Restore module"); - /* Restore volume and update default entry */ - update_active_sink_input.begin (-1); - _pulse_use_stream_restore = true; - } - } - - /*** - **** Tracking the Multimedia Volume - ***/ - - private async void init_stream_restore() - { - if (_pconn == null) - return; - update_multimedia_objp(); // listen for StreamRestore1's NewEntry and EntryRemoved signals @@ -518,18 +237,6 @@ public class VolumeWarning : Object } } - /*** - **** Tracking the Active Output - ***/ - - private VolumeControl.ActiveOutput active_output - { - get - { - return _active_output; - } - } - /** HIGH VOLUME PROPERTY **/ public bool ignore_high_volume { @@ -564,6 +271,8 @@ public class VolumeWarning : Object /** HIGH VOLUME APPROVED PROPERTY **/ + private Settings _settings = new Settings ("com.canonical.indicator.sound"); + private void approve_high_volume() { _high_volume_approved_at = GLib.get_monotonic_time(); update_high_volume_approved(); |