aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLars Uebernickel <lars.uebernickel@canonical.com>2013-06-18 15:00:27 -0400
committerLars Uebernickel <lars.uebernickel@canonical.com>2013-06-18 15:00:27 -0400
commite2d1ed2cb0b066a7b34db15e42af0a4b49626ec8 (patch)
tree134c39e677f4c75e79fa975227978dea03050bfb
parentcb8cb6ef16fc0884d2499421fbeeca12e3288b56 (diff)
downloadayatana-indicator-sound-e2d1ed2cb0b066a7b34db15e42af0a4b49626ec8.tar.gz
ayatana-indicator-sound-e2d1ed2cb0b066a7b34db15e42af0a4b49626ec8.tar.bz2
ayatana-indicator-sound-e2d1ed2cb0b066a7b34db15e42af0a4b49626ec8.zip
Allow setting the microphone volume if an app using it is running
-rw-r--r--src/service.vala38
-rw-r--r--src/volume-control.vala93
2 files changed, 126 insertions, 5 deletions
diff --git a/src/service.vala b/src/service.vala
index 269ddd7..83d0d17 100644
--- a/src/service.vala
+++ b/src/service.vala
@@ -25,6 +25,7 @@ public class IndicatorSound.Service {
this.settings = new Settings ("com.canonical.indicator.sound");
this.volume_control = new VolumeControl ();
+ this.volume_control.notify["active-mic"].connect (active_mic_changed);
this.players = new MediaPlayerList ();
this.players.player_added.connect (this.player_added);
@@ -34,6 +35,7 @@ public class IndicatorSound.Service {
this.actions.add_entries (action_entries, this);
this.actions.add_action (this.create_mute_action ());
this.actions.add_action (this.create_volume_action ());
+ this.actions.add_action (this.create_mic_volume_action ());
this.menu = create_menu ();
this.root_menu = create_root_menu (this.menu);
@@ -112,6 +114,26 @@ public class IndicatorSound.Service {
return menu;
}
+ void active_mic_changed () {
+ var volume_section = this.menu.get_item_link (0, "section") as Menu;
+ if (this.volume_control.active_mic) {
+ if (volume_section.get_n_items () < 3) {
+ var slider = new MenuItem (null, "indicator.mic-volume");
+ slider.set_attribute ("x-canonical-type", "s", "com.canonical.unity.slider");
+ slider.set_attribute_value ("min-icon", g_icon_serialize (new ThemedIcon ("audio-input-microphone-low-zero-panel")));
+ slider.set_attribute_value ("max-icon", g_icon_serialize (new ThemedIcon ("audio-input-microphone-high-panel")));
+ slider.set_attribute ("min-value", "d", 0.0);
+ slider.set_attribute ("max-value", "d", 1.0);
+ slider.set_attribute ("step", "d", 0.01);
+ volume_section.append_item (slider);
+ }
+ }
+ else {
+ if (volume_section.get_n_items () > 2)
+ volume_section.remove (2);
+ }
+ }
+
Action create_mute_action () {
var mute_action = new SimpleAction.stateful ("mute", null, this.volume_control.mute);
@@ -146,6 +168,22 @@ public class IndicatorSound.Service {
return volume_action;
}
+ Action create_mic_volume_action () {
+ var volume_action = new SimpleAction.stateful ("mic-volume", null, this.volume_control.get_mic_volume ());
+
+ volume_action.change_state.connect ( (action, val) => {
+ volume_control.set_mic_volume (val.get_double ());
+ });
+
+ this.volume_control.mic_volume_changed.connect ( (volume) => {
+ volume_action.set_state (volume);
+ });
+
+ this.volume_control.bind_property ("ready", volume_action, "enabled", BindingFlags.SYNC_CREATE);
+
+ return volume_action;
+ }
+
void bus_acquired (DBusConnection connection, string name) {
try {
connection.export_action_group ("/com/canonical/indicator/sound", this.actions);
diff --git a/src/volume-control.vala b/src/volume-control.vala
index 5ce5a05..9475f53 100644
--- a/src/volume-control.vala
+++ b/src/volume-control.vala
@@ -30,12 +30,17 @@ public class VolumeControl : Object
private PulseAudio.Context context;
private bool _mute = true;
private double _volume = 0.0;
+ private double _mic_volume = 0.0;
public signal void volume_changed (double v);
+ public signal void mic_volume_changed (double v);
/** true when connected to the pulse server */
public bool ready { get; set; }
+ /** true when a microphone is active **/
+ public bool active_mic { get; private set; default = false; }
+
public VolumeControl ()
{
if (loop == null)
@@ -61,9 +66,28 @@ public class VolumeControl : Object
/* PulseAudio logic*/
private void context_events_cb (Context c, Context.SubscriptionEventType t, uint32 index)
{
- if ((t & Context.SubscriptionEventType.FACILITY_MASK) == Context.SubscriptionEventType.SINK)
+ switch (t & Context.SubscriptionEventType.FACILITY_MASK)
{
- get_properties ();
+ case Context.SubscriptionEventType.SINK:
+ update_sink ();
+ break;
+
+ case Context.SubscriptionEventType.SOURCE:
+ update_source ();
+ break;
+
+ case Context.SubscriptionEventType.SOURCE_OUTPUT:
+ switch (t & Context.SubscriptionEventType.TYPE_MASK)
+ {
+ case Context.SubscriptionEventType.NEW:
+ c.get_source_output_info (index, source_output_info_cb);
+ break;
+
+ case Context.SubscriptionEventType.REMOVE:
+ this.active_mic = false;
+ break;
+ }
+ break;
}
}
@@ -85,6 +109,18 @@ public class VolumeControl : Object
}
}
+ private void source_info_cb (Context c, SourceInfo? i, int eol)
+ {
+ if (i == null)
+ return;
+
+ if (_mic_volume != volume_to_double (i.volume.values[0]))
+ {
+ _mic_volume = volume_to_double (i.volume.values[0]);
+ mic_volume_changed (_mic_volume);
+ }
+ }
+
private void server_info_cb_for_props (Context c, ServerInfo? i)
{
if (i == null)
@@ -92,18 +128,39 @@ public class VolumeControl : Object
context.get_sink_info_by_name (i.default_sink_name, sink_info_cb_for_props);
}
- private void get_properties ()
+ private void update_sink ()
{
context.get_server_info (server_info_cb_for_props);
}
+ private void update_source ()
+ {
+ context.get_server_info ( (c, i) => {
+ if (i != null)
+ context.get_source_info_by_name (i.default_source_name, source_info_cb);
+ });
+ }
+
+ private void source_output_info_cb (Context c, SourceOutputInfo? i, int eol)
+ {
+ if (i == null)
+ return;
+
+ var role = i.proplist.gets (PulseAudio.Proplist.PROP_MEDIA_ROLE);
+ if (role == "phone" || role == "production")
+ this.active_mic = true;
+ }
+
private void context_state_callback (Context c)
{
if (c.get_state () == Context.State.READY)
{
- c.subscribe (PulseAudio.Context.SubscriptionMask.SINK);
+ c.subscribe (PulseAudio.Context.SubscriptionMask.SINK |
+ PulseAudio.Context.SubscriptionMask.SOURCE |
+ PulseAudio.Context.SubscriptionMask.SOURCE_OUTPUT);
c.set_subscribe_callback (context_events_cb);
- get_properties ();
+ update_sink ();
+ update_source ();
this.ready = true;
}
else
@@ -182,8 +239,34 @@ public class VolumeControl : Object
context.get_server_info (server_info_cb_for_set_volume);
}
+ void set_mic_volume_success_cb (Context c, int success)
+ {
+ if ((bool)success)
+ mic_volume_changed (_mic_volume);
+ }
+
+ public void set_mic_volume (double volume)
+ {
+ return_if_fail (context.get_state () == Context.State.READY);
+
+ _mic_volume = volume;
+
+ context.get_server_info ( (c, i) => {
+ if (i != null) {
+ unowned CVolume cvol = CVolume ();
+ cvol = vol_set (cvol, 1, double_to_volume (_mic_volume));
+ c.set_source_volume_by_name (i.default_source_name, cvol, set_mic_volume_success_cb);
+ }
+ });
+ }
+
public double get_volume ()
{
return _volume;
}
+
+ public double get_mic_volume ()
+ {
+ return _mic_volume;
+ }
}