From fa62fcd320feb6486b86acfab930efc5f5f584e4 Mon Sep 17 00:00:00 2001
From: Emmanuel Milou <emmanuel.milou@savoirfairelinux.com>
Date: Fri, 30 May 2008 17:29:01 -0400
Subject: [PATCH] Enable/Disable pulseaudio volume control from the GUI

---
 sflphone-gtk/src/audioconf.c                 |  60 +++---
 sflphone-gtk/src/audioconf.h                 |   1 +
 sflphone-gtk/src/configurationmanager-glue.h |  75 +++++++
 sflphone-gtk/src/configwindow.c              | 215 ++++---------------
 sflphone-gtk/src/dbus.c                      |  26 +++
 sflphone-gtk/src/dbus.h                      |  11 +
 src/audio/alsalayer.cpp                      |   4 +-
 src/audio/alsalayer.h                        |  17 ++
 src/audio/audiolayer.h                       |   1 +
 src/audio/audiostream.cpp                    |   8 +-
 src/audio/audiostream.h                      |   7 +-
 src/audio/pulselayer.cpp                     |  48 ++++-
 src/audio/pulselayer.h                       | 134 +++++++++---
 src/dbus/configurationmanager-glue.h         |  33 +++
 src/dbus/configurationmanager-introspec.xml  |   7 +
 src/dbus/configurationmanager.cpp            |  13 ++
 src/dbus/configurationmanager.h              |   2 +
 src/managerimpl.cpp                          |  21 +-
 src/managerimpl.h                            |   4 +
 src/user_cfg.h                               |   2 +
 20 files changed, 431 insertions(+), 258 deletions(-)

diff --git a/sflphone-gtk/src/audioconf.c b/sflphone-gtk/src/audioconf.c
index 374a4f33c6..3e194d2f79 100644
--- a/sflphone-gtk/src/audioconf.c
+++ b/sflphone-gtk/src/audioconf.c
@@ -19,7 +19,6 @@
 
 #include <audioconf.h>
 
-
 GtkListStore *pluginlist;
 GtkListStore *outputlist;
 GtkListStore *inputlist;
@@ -128,7 +127,6 @@ config_window_fill_output_audio_device_list()
     gtk_list_store_set(outputlist, &iter, 0, *list, 1, index, -1);
     c++;
   }
-
 }
 
 /**
@@ -205,35 +203,35 @@ config_window_fill_input_audio_device_list()
 select_active_input_audio_device()
 {
   if( SHOW_ALSA_CONF)
-{
-  
-  GtkTreeModel* model;
-  GtkTreeIter iter;
-  gchar** devices;
-  int currentDeviceIndex;
-  int deviceIndex;
+  {
 
-  // Select active input device on server
-  devices = dbus_get_current_audio_devices_index();
-  currentDeviceIndex = atoi(devices[1]);
-  model = gtk_combo_box_get_model(GTK_COMBO_BOX(input));
+    GtkTreeModel* model;
+    GtkTreeIter iter;
+    gchar** devices;
+    int currentDeviceIndex;
+    int deviceIndex;
 
-  // Find the currently set input device
-  gtk_tree_model_get_iter_first(model, &iter);
-  do {
-    gtk_tree_model_get(model, &iter, 1, &deviceIndex, -1);
-    if(deviceIndex == currentDeviceIndex)
-    {
-      // Set current iteration the active one
-      gtk_combo_box_set_active_iter(GTK_COMBO_BOX(input), &iter);
-      return;
-    }
-  } while(gtk_tree_model_iter_next(model, &iter));
+    // Select active input device on server
+    devices = dbus_get_current_audio_devices_index();
+    currentDeviceIndex = atoi(devices[1]);
+    model = gtk_combo_box_get_model(GTK_COMBO_BOX(input));
 
-  // No index was found, select first one
-  g_print("Warning : No active input device found");
-  gtk_combo_box_set_active(GTK_COMBO_BOX(input), 0);
-}
+    // Find the currently set input device
+    gtk_tree_model_get_iter_first(model, &iter);
+    do {
+      gtk_tree_model_get(model, &iter, 1, &deviceIndex, -1);
+      if(deviceIndex == currentDeviceIndex)
+      {
+	// Set current iteration the active one
+	gtk_combo_box_set_active_iter(GTK_COMBO_BOX(input), &iter);
+	return;
+      }
+    } while(gtk_tree_model_iter_next(model, &iter));
+
+    // No index was found, select first one
+    g_print("Warning : No active input device found");
+    gtk_combo_box_set_active(GTK_COMBO_BOX(input), 0);
+  }
 }
 
 /**
@@ -291,7 +289,6 @@ select_active_output_audio_plugin()
   // No index was found, select first one
   g_print("Warning : No active output device found\n");
   gtk_combo_box_set_active(GTK_COMBO_BOX(plugin), 0);
-  //update_combo_box("default");
 }
 
 
@@ -407,7 +404,6 @@ codec_active_toggled(GtkCellRendererToggle *renderer, gchar *path, gpointer data
   codec_list_update_to_daemon();
 }
 
-
 /**
  * Move codec in list depending on direction and selected codec and
  * update changes in the daemon list and the configuration files
@@ -756,7 +752,6 @@ GtkWidget* ringtones_box()
   return ret;
 }
 
-
 GtkWidget* create_audio_configuration()
 {
   // Main widget
@@ -787,10 +782,11 @@ GtkWidget* create_audio_configuration()
     alsabox = alsa_box();
     gtk_container_add( GTK_CONTAINER(alsa_conf) , alsabox );
   }
-
+  
   // Box for the codecs
   codecs_conf = gtk_frame_new(_("Codecs"));
   gtk_box_pack_start(GTK_BOX(ret), codecs_conf, FALSE, FALSE, 0);
+  gtk_widget_set_size_request(GTK_WIDGET(codecs_conf), -1, 200);
   gtk_widget_show( codecs_conf );
   box = codecs_box();
   gtk_container_add( GTK_CONTAINER(codecs_conf) , box );
diff --git a/sflphone-gtk/src/audioconf.h b/sflphone-gtk/src/audioconf.h
index ab1f8411be..26e28aa771 100644
--- a/sflphone-gtk/src/audioconf.h
+++ b/sflphone-gtk/src/audioconf.h
@@ -26,6 +26,7 @@ GtkWidget* create_audio_configuration();
 
 GtkWidget* api_box();
 GtkWidget* alsa_box();
+GtkWidget* pulse_box();
 GtkWidget* codecs_box();
 GtkWidget* ringtone_box();
 
diff --git a/sflphone-gtk/src/configurationmanager-glue.h b/sflphone-gtk/src/configurationmanager-glue.h
index 54d2b22e17..9e54d25286 100644
--- a/sflphone-gtk/src/configurationmanager-glue.h
+++ b/sflphone-gtk/src/configurationmanager-glue.h
@@ -1851,6 +1851,81 @@ org_sflphone_SFLphone_ConfigurationManager_switch_popup_mode_async (DBusGProxy *
   stuff->userdata = userdata;
   return dbus_g_proxy_begin_call (proxy, "switchPopupMode", org_sflphone_SFLphone_ConfigurationManager_switch_popup_mode_async_callback, stuff, g_free, G_TYPE_INVALID);
 }
+static
+#ifdef G_HAVE_INLINE
+inline
+#endif
+gboolean
+org_sflphone_SFLphone_ConfigurationManager_set_pulse_app_volume_control (DBusGProxy *proxy, GError **error)
+
+{
+  return dbus_g_proxy_call (proxy, "setPulseAppVolumeControl", error, G_TYPE_INVALID, G_TYPE_INVALID);
+}
+
+typedef void (*org_sflphone_SFLphone_ConfigurationManager_set_pulse_app_volume_control_reply) (DBusGProxy *proxy, GError *error, gpointer userdata);
+
+static void
+org_sflphone_SFLphone_ConfigurationManager_set_pulse_app_volume_control_async_callback (DBusGProxy *proxy, DBusGProxyCall *call, void *user_data)
+{
+  DBusGAsyncData *data = (DBusGAsyncData*) user_data;
+  GError *error = NULL;
+  dbus_g_proxy_end_call (proxy, call, &error, G_TYPE_INVALID);
+  (*(org_sflphone_SFLphone_ConfigurationManager_set_pulse_app_volume_control_reply)data->cb) (proxy, error, data->userdata);
+  return;
+}
+
+static
+#ifdef G_HAVE_INLINE
+inline
+#endif
+DBusGProxyCall*
+org_sflphone_SFLphone_ConfigurationManager_set_pulse_app_volume_control_async (DBusGProxy *proxy, org_sflphone_SFLphone_ConfigurationManager_set_pulse_app_volume_control_reply callback, gpointer userdata)
+
+{
+  DBusGAsyncData *stuff;
+  stuff = g_new (DBusGAsyncData, 1);
+  stuff->cb = G_CALLBACK (callback);
+  stuff->userdata = userdata;
+  return dbus_g_proxy_begin_call (proxy, "setPulseAppVolumeControl", org_sflphone_SFLphone_ConfigurationManager_set_pulse_app_volume_control_async_callback, stuff, g_free, G_TYPE_INVALID);
+}
+static
+#ifdef G_HAVE_INLINE
+inline
+#endif
+gboolean
+org_sflphone_SFLphone_ConfigurationManager_get_pulse_app_volume_control (DBusGProxy *proxy, gint* OUT_state, GError **error)
+
+{
+  return dbus_g_proxy_call (proxy, "getPulseAppVolumeControl", error, G_TYPE_INVALID, G_TYPE_INT, OUT_state, G_TYPE_INVALID);
+}
+
+typedef void (*org_sflphone_SFLphone_ConfigurationManager_get_pulse_app_volume_control_reply) (DBusGProxy *proxy, gint OUT_state, GError *error, gpointer userdata);
+
+static void
+org_sflphone_SFLphone_ConfigurationManager_get_pulse_app_volume_control_async_callback (DBusGProxy *proxy, DBusGProxyCall *call, void *user_data)
+{
+  DBusGAsyncData *data = (DBusGAsyncData*) user_data;
+  GError *error = NULL;
+  gint OUT_state;
+  dbus_g_proxy_end_call (proxy, call, &error, G_TYPE_INT, &OUT_state, G_TYPE_INVALID);
+  (*(org_sflphone_SFLphone_ConfigurationManager_get_pulse_app_volume_control_reply)data->cb) (proxy, OUT_state, error, data->userdata);
+  return;
+}
+
+static
+#ifdef G_HAVE_INLINE
+inline
+#endif
+DBusGProxyCall*
+org_sflphone_SFLphone_ConfigurationManager_get_pulse_app_volume_control_async (DBusGProxy *proxy, org_sflphone_SFLphone_ConfigurationManager_get_pulse_app_volume_control_reply callback, gpointer userdata)
+
+{
+  DBusGAsyncData *stuff;
+  stuff = g_new (DBusGAsyncData, 1);
+  stuff->cb = G_CALLBACK (callback);
+  stuff->userdata = userdata;
+  return dbus_g_proxy_begin_call (proxy, "getPulseAppVolumeControl", org_sflphone_SFLphone_ConfigurationManager_get_pulse_app_volume_control_async_callback, stuff, g_free, G_TYPE_INVALID);
+}
 #endif /* defined DBUS_GLIB_CLIENT_WRAPPERS_org_sflphone_SFLphone_ConfigurationManager */
 
 G_END_DECLS
diff --git a/sflphone-gtk/src/configwindow.c b/sflphone-gtk/src/configwindow.c
index 471dcb1b58..090c4d6551 100644
--- a/sflphone-gtk/src/configwindow.c
+++ b/sflphone-gtk/src/configwindow.c
@@ -323,7 +323,11 @@ account_move_down(GtkButton *button, gpointer data)
   account_move(FALSE, data);
 }
 
-
+static void
+set_pulse_app_volume_control( void )
+{
+  dbus_set_pulse_app_volume_control();
+}
 
 /**
  * Account settings tab
@@ -442,165 +446,6 @@ create_accounts_tab()
 	return ret;
 }
 
-/**
- * Audio settings tab
- */
-GtkWidget*
-create_audio_tab ()
-{
-/*	GtkWidget *ret;
-	
-	GtkWidget *deviceFrame;
-	GtkWidget *deviceBox;
-	GtkWidget *deviceTable;
-	GtkWidget *codecFrame;
-	GtkWidget *codecBox;
-	GtkWidget *enableTone;
-	GtkWidget *fileChooser;
-	
-	GtkWidget *titleLabel;
-	GtkWidget *refreshButton;
-	GtkCellRenderer *renderer;
-	
-	GtkWidget *codecTable;
-	
-	// Main widget
-	ret = gtk_vbox_new(FALSE, 10);
-    gtk_container_set_border_width(GTK_CONTAINER(ret), 10);
-    
-    // Device section label
-    deviceFrame = gtk_frame_new(_("Devices"));
-    gtk_box_pack_start(GTK_BOX(ret), deviceFrame, FALSE, FALSE, 0);
-    gtk_widget_show( deviceFrame );
-
-	
-    // Main device widget
-    deviceBox = gtk_hbox_new(FALSE, 10);
-    gtk_widget_show( deviceBox );
-
-    gtk_container_add( GTK_CONTAINER(deviceFrame) , deviceBox);
-
-    // Main device widget
-	deviceTable = gtk_table_new(4, 3, FALSE);
-	gtk_table_set_col_spacing(GTK_TABLE(deviceTable), 0, 40);
-	gtk_box_pack_start(GTK_BOX(deviceBox), deviceTable, TRUE, TRUE, 0);
-	gtk_widget_show(deviceTable);
-	
-	// Device : Audio manager
-	// Create title label
-	
-	titleLabel = gtk_label_new("Alsa plug-IN:");
-	gtk_misc_set_alignment(GTK_MISC(titleLabel), 0, 0.5);
-	gtk_table_attach(GTK_TABLE(deviceTable), titleLabel, 0, 1, 0, 1, GTK_FILL | GTK_EXPAND, GTK_SHRINK, 0, 0);
-	gtk_widget_show(titleLabel);
-	// Set choices of audio managers
-	inputAudioPluginStore = gtk_list_store_new(1, G_TYPE_STRING);
-	config_window_fill_input_audio_plugin_list();
-	comboBox = gtk_combo_box_new_with_model(GTK_TREE_MODEL(inputAudioPluginStore));
-	gtk_combo_box_set_active(GTK_COMBO_BOX(comboBox), 0);
-	gtk_label_set_mnemonic_widget(GTK_LABEL(titleLabel), comboBox);
-	g_signal_connect(G_OBJECT(comboBox), "changed", G_CALLBACK(select_input_audio_plugin), comboBox);
-	
-  	// Set rendering
-	renderer = gtk_cell_renderer_text_new();
-	gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(comboBox), renderer, TRUE);
-	gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(comboBox), renderer, "text", 0, NULL);
-	gtk_table_attach(GTK_TABLE(deviceTable), comboBox, 1, 2, 0, 1, GTK_FILL | GTK_EXPAND, GTK_SHRINK, 0, 0);
-	gtk_widget_show(comboBox);
-	
-	// Create title label
-	titleLabel = gtk_label_new(_("ALSA plugin"));
-	gtk_misc_set_alignment(GTK_MISC(titleLabel), 0, 0.5);
-	gtk_table_attach(GTK_TABLE(deviceTable), titleLabel, 1, 2, 0, 1, GTK_FILL | GTK_EXPAND, GTK_SHRINK, 0, 0);
-	gtk_widget_show(titleLabel);
-	// Set choices of audio managers
-	outputAudioPluginStore = gtk_list_store_new(1, G_TYPE_STRING);
-	config_window_fill_output_audio_plugin_list();
-	pluginComboBox = gtk_combo_box_new_with_model(GTK_TREE_MODEL(outputAudioPluginStore));
-	select_active_output_audio_plugin();
-	gtk_label_set_mnemonic_widget(GTK_LABEL(titleLabel), pluginComboBox);
-	g_signal_connect(G_OBJECT(pluginComboBox), "changed", G_CALLBACK(select_output_audio_plugin), pluginComboBox);
-	
-  	// Set rendering
-	renderer = gtk_cell_renderer_text_new();
-	gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(pluginComboBox), renderer, TRUE);
-	gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(pluginComboBox), renderer, "text", 0, NULL);
-	gtk_table_attach(GTK_TABLE(deviceTable), pluginComboBox, 2, 3, 0, 1, GTK_FILL | GTK_EXPAND, GTK_SHRINK, 0, 0);
-	gtk_widget_show(pluginComboBox);
-	
-	// Device : Output device
-	// Create title label
-	titleLabel = gtk_label_new(_("Output peripheral"));
-    gtk_misc_set_alignment(GTK_MISC(titleLabel), 0, 0.5);
-    gtk_table_attach(GTK_TABLE(deviceTable), titleLabel, 1, 2, 1, 2, GTK_FILL | GTK_EXPAND, GTK_SHRINK, 0, 0);
-    gtk_widget_show(titleLabel);
-	// Set choices of output devices
-	outputAudioDeviceManagerStore = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_INT);
-	config_window_fill_output_audio_device_list();
-	outputDeviceComboBox = gtk_combo_box_new_with_model(GTK_TREE_MODEL(outputAudioDeviceManagerStore));
-	select_active_output_audio_device();
-  	gtk_label_set_mnemonic_widget(GTK_LABEL(titleLabel), outputDeviceComboBox);
-	//g_signal_connect(G_OBJECT(outputDeviceComboBox), "changed", G_CALLBACK(select_audio_output_device), outputDeviceComboBox);
-
-	// Set rendering
-	renderer = gtk_cell_renderer_text_new();
-	gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(outputDeviceComboBox), renderer, TRUE);
-	gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(outputDeviceComboBox), renderer, "text", 0, NULL);
-	gtk_table_attach(GTK_TABLE(deviceTable), outputDeviceComboBox, 2, 3, 1, 2, GTK_FILL | GTK_EXPAND, GTK_SHRINK, 0, 0);
-	gtk_widget_show(outputDeviceComboBox);
-	
-	// Device : Input device
-	// Create title label
-	titleLabel = gtk_label_new(_("Input peripheral"));
-    gtk_misc_set_alignment(GTK_MISC(titleLabel), 0, 0.5);
-    gtk_table_attach(GTK_TABLE(deviceTable), titleLabel, 1, 2, 2, 3, GTK_FILL | GTK_EXPAND, GTK_SHRINK, 0, 0);
-	gtk_widget_show(titleLabel);
-	// Set choices of output devices
-	inputAudioDeviceManagerStore = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_INT);
-	config_window_fill_input_audio_device_list();
-	inputDeviceComboBox = gtk_combo_box_new_with_model(GTK_TREE_MODEL(inputAudioDeviceManagerStore));
-	select_active_input_audio_device();
-	gtk_label_set_mnemonic_widget(GTK_LABEL(titleLabel), inputDeviceComboBox);
-	//g_signal_connect(G_OBJECT(inputDeviceComboBox), "changed", G_CALLBACK(select_audio_input_device), inputDeviceComboBox);
-
-	// Set rendering
-	renderer = gtk_cell_renderer_text_new();
-	gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(inputDeviceComboBox), renderer, TRUE);
-	gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(inputDeviceComboBox), renderer, "text", 0, NULL);
-    gtk_table_attach(GTK_TABLE(deviceTable), inputDeviceComboBox, 2, 3, 2, 3, GTK_FILL | GTK_EXPAND, GTK_SHRINK, 0, 0);
-	gtk_widget_show(inputDeviceComboBox);
-	
-	// Create detect button
-	refreshButton = gtk_button_new_with_label(_("Detect all"));
-	gtk_button_set_image(GTK_BUTTON(refreshButton), gtk_image_new_from_stock(GTK_STOCK_REFRESH, GTK_ICON_SIZE_BUTTON));
-	gtk_table_attach(GTK_TABLE(deviceTable), refreshButton, 2, 3, 3, 4, GTK_EXPAND, GTK_EXPAND, 0, 0);
-	// Set event on selection
-	g_signal_connect(G_OBJECT(refreshButton), "clicked", G_CALLBACK(detect_all_audio_settings), NULL);
-	
-	//select_active_output_audio_plugin();
-    // Codec section label
-    codecFrame = gtk_frame_new(_("Codecs"));
-    gtk_box_pack_start(GTK_BOX(ret), codecFrame, FALSE, FALSE, 0);
-    gtk_widget_show(codecFrame);
-
-    // Main codec widget
-	codecBox = gtk_hbox_new(FALSE, 10);
-	gtk_widget_show(codecBox);
-	
-	gtk_container_add( GTK_CONTAINER( codecFrame ) , codecBox );
-	// Codec : List
-	codecTable = create_codec_table();
-	gtk_widget_set_size_request(GTK_WIDGET(codecTable), -1, 150);
-	gtk_box_pack_start(GTK_BOX(codecBox), codecTable, TRUE, TRUE, 0);
-	gtk_widget_show(codecTable);
-*/
-
-    	// Show all
-	//gtk_widget_show_all(ret);
-
-	//return ret;
-}
-
 GtkWidget*
 create_general_settings ()
 {
@@ -609,14 +454,14 @@ create_general_settings ()
   GtkWidget *notifFrame;
   GtkWidget *notifBox;
   GtkWidget *notifAll;
-  GtkWidget *notifMails;
+  GtkWidget *widg;
 
   GtkWidget *trayFrame;
   GtkWidget *trayBox;
   GtkWidget *trayItem;
 
-  GtkWidget *historyFrame;
-  GtkWidget *historyBox;
+  GtkWidget *frame;
+  GtkWidget *vbox;
   GtkWidget *value;
   GtkWidget *label;
   GtkWidget *cleanButton;
@@ -639,10 +484,10 @@ create_general_settings ()
   gtk_box_pack_start( GTK_BOX(notifBox) , notifAll , TRUE , TRUE , 1);
   g_signal_connect(G_OBJECT( notifAll ) , "clicked" , G_CALLBACK( set_notif_level ) , NULL );
 
-  notifMails = gtk_check_button_new_with_mnemonic(  _("_Notify voice mails"));
-  gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(notifMails), dbus_get_mail_notify() );
-  gtk_box_pack_start( GTK_BOX(notifBox) , notifMails , TRUE , TRUE , 1);
-  g_signal_connect(G_OBJECT( notifMails ) , "clicked" , G_CALLBACK( set_mail_notif ) , NULL);
+  widg = gtk_check_button_new_with_mnemonic(  _("_Notify voice mails"));
+  gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(widg), dbus_get_mail_notify() );
+  gtk_box_pack_start( GTK_BOX(notifBox) , widg , TRUE , TRUE , 1);
+  g_signal_connect(G_OBJECT( widg ) , "clicked" , G_CALLBACK( set_mail_notif ) , NULL);
 
   // System Tray option frame
   trayFrame = gtk_frame_new(_("System Tray Icon"));
@@ -667,29 +512,44 @@ create_general_settings ()
   gtk_box_pack_start( GTK_BOX(trayBox) , trayItem , TRUE , TRUE , 1);
   g_signal_connect(G_OBJECT( trayItem ) , "clicked" , G_CALLBACK( start_hidden ) , NULL);
 
-  historyFrame = gtk_frame_new(_("Calls History"));
-  gtk_box_pack_start(GTK_BOX(ret), historyFrame, FALSE, FALSE, 0);
-  gtk_widget_show( historyFrame );
+  /** HISTORY CONFIGURATION */
+  frame = gtk_frame_new(_("Calls History"));
+  gtk_box_pack_start(GTK_BOX(ret), frame, FALSE, FALSE, 0);
+  gtk_widget_show( frame );
 
-  historyBox = gtk_vbox_new(FALSE, 10);
-  gtk_widget_show( historyBox );
-  gtk_container_add( GTK_CONTAINER(historyFrame) , historyBox);
+  vbox = gtk_vbox_new(FALSE, 10);
+  gtk_widget_show( vbox );
+  gtk_container_add( GTK_CONTAINER(frame) , vbox);
   
   label = gtk_label_new_with_mnemonic(_("_Maximum number of calls"));
-  gtk_box_pack_start( GTK_BOX(historyBox) , label , TRUE , TRUE , 0);
+  gtk_box_pack_start( GTK_BOX(vbox) , label , TRUE , TRUE , 0);
   
   value = gtk_hscale_new_with_range(0.0 , 50.0 , 5.0);
   gtk_label_set_mnemonic_widget (GTK_LABEL (label), value);
   gtk_scale_set_digits( GTK_SCALE(value) , 0);
   gtk_scale_set_value_pos( GTK_SCALE(value) , GTK_POS_RIGHT); 
   gtk_range_set_value( GTK_RANGE( value ) , dbus_get_max_calls());
-  gtk_box_pack_start( GTK_BOX(historyBox) , value , TRUE , TRUE , 0);
+  gtk_box_pack_start( GTK_BOX(vbox) , value , TRUE , TRUE , 0);
   g_signal_connect( G_OBJECT( value) , "value-changed" , G_CALLBACK( update_max_value ) , NULL);
 
   cleanButton = gtk_button_new_from_stock( GTK_STOCK_CLEAR );
-  gtk_box_pack_end( GTK_BOX(historyBox) , cleanButton , FALSE , TRUE , 0);
+  gtk_box_pack_end( GTK_BOX(vbox) , cleanButton , FALSE , TRUE , 0);
   g_signal_connect( G_OBJECT( cleanButton ) , "clicked" , G_CALLBACK( clean_history ) , NULL);
   
+  /** PULSEAUDIO CONFIGURATION */
+  frame = gtk_frame_new( _("PulseAudio sound server"));
+  gtk_box_pack_start(GTK_BOX(ret), frame, FALSE, FALSE, 0);
+  gtk_widget_show( frame );
+
+  vbox = gtk_vbox_new(FALSE, 10);
+  gtk_widget_show( vbox );
+  gtk_container_add( GTK_CONTAINER(frame) , vbox);
+
+  widg = gtk_check_button_new_with_mnemonic(  _("_Control running applications's volume"));
+  gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(widg), dbus_get_pulse_app_volume_control() );
+  gtk_box_pack_start( GTK_BOX(vbox) , widg , TRUE , TRUE , 1);
+  g_signal_connect(G_OBJECT( widg ) , "clicked" , G_CALLBACK( set_pulse_app_volume_control ) , NULL);
+
   gtk_widget_show_all(ret);
   
   return ret;
@@ -732,7 +592,6 @@ show_config_window ()
 	gtk_notebook_page_num(GTK_NOTEBOOK(notebook), tab);
 	
 	// Audio tab
-	//tab = create_audio_tab();	
 	tab = create_audio_configuration();	
 	gtk_notebook_append_page(GTK_NOTEBOOK(notebook), tab, gtk_label_new(_("Audio Settings")));
 	gtk_notebook_page_num(GTK_NOTEBOOK(notebook), tab);
@@ -740,8 +599,6 @@ show_config_window ()
 	gtk_notebook_set_current_page( GTK_NOTEBOOK( notebook) ,  1);
 
 	gtk_dialog_run(dialog);
-	//gtk_widget_show( GTK_WIDGET(dialog) );
-	//g_signal_connect_swapped( dialog , "response" , G_CALLBACK( gtk_widget_destroy ), dialog );
 
 	dialogOpen = FALSE;
 
diff --git a/sflphone-gtk/src/dbus.c b/sflphone-gtk/src/dbus.c
index b1487c896e..0d42a41e6b 100644
--- a/sflphone-gtk/src/dbus.c
+++ b/sflphone-gtk/src/dbus.c
@@ -1456,3 +1456,29 @@ dbus_get_audio_manager( void )
 	
 	return api;
 }
+
+void
+dbus_set_pulse_app_volume_control( void )
+{
+	GError* error = NULL;
+	org_sflphone_SFLphone_ConfigurationManager_set_pulse_app_volume_control(
+			configurationManagerProxy,
+			&error);
+	if(error)
+	{
+		g_error_free(error);
+	}
+}
+
+int
+dbus_get_pulse_app_volume_control( void )
+{
+  int state;
+	GError* error = NULL;
+	org_sflphone_SFLphone_ConfigurationManager_get_pulse_app_volume_control(
+			configurationManagerProxy,
+			&state,
+			&error);
+	return state;
+}
+
diff --git a/sflphone-gtk/src/dbus.h b/sflphone-gtk/src/dbus.h
index af5ebe51e3..34e6b5f000 100644
--- a/sflphone-gtk/src/dbus.h
+++ b/sflphone-gtk/src/dbus.h
@@ -267,6 +267,17 @@ int dbus_is_ringtone_enabled( void );
  */
 void dbus_ringtone_enabled( void );
 
+/**
+ * ConfigurationManager - Set PA behaviour for the other sound streams 
+ * Inverse current value
+ */
+void dbus_set_pulse_app_volume_control( void );
+
+/**
+ * ConfigurationManager - Get PA behaviour for the other sound streams 
+ */
+int dbus_get_pulse_app_volume_control( void );
+
 /**
  * ConfigurationManager - Get the ringtone 
  * @return gchar* The file name selected as a ringtone
diff --git a/src/audio/alsalayer.cpp b/src/audio/alsalayer.cpp
index c1ea3e63e0..c8d735969d 100644
--- a/src/audio/alsalayer.cpp
+++ b/src/audio/alsalayer.cpp
@@ -221,8 +221,8 @@ AlsaLayer::isStreamStopped (void)
 }
 
 
-void 
-AlsaLayer::reducePulseAppsVolume( void ){}
+void AlsaLayer::reducePulseAppsVolume( void ){}
+void AlsaLayer::restorePulseAppsVolume( void ){}
 
 //////////////////////////////////////////////////////////////////////////////////////////////
 /////////////////   ALSA PRIVATE FUNCTIONS   ////////////////////////////////////////////////
diff --git a/src/audio/alsalayer.h b/src/audio/alsalayer.h
index 2b82bbe11c..efa6125748 100644
--- a/src/audio/alsalayer.h
+++ b/src/audio/alsalayer.h
@@ -181,9 +181,26 @@ class AlsaLayer : public AudioLayer {
      */
     std::string getAudioPlugin( void ) { return _audioPlugin; }
 
+    /**
+     * UNUSED in ALSA layer
+     */
     int putInCache( char code, void *buffer, int toCopy );
+
+    /**
+     * UNUSED in ALSA layer
+     */
     int putMain(void* buffer, int toCopy);
+
+    /**
+     * UNUSED in ALSA layer
+     */
     void reducePulseAppsVolume( void );
+
+    /**
+     * UNUSED in ALSA layer
+     */
+    void restorePulseAppsVolume( void ); 
+
   private:
 
     /**
diff --git a/src/audio/audiolayer.h b/src/audio/audiolayer.h
index 0b0f768167..f162ff6e50 100644
--- a/src/audio/audiolayer.h
+++ b/src/audio/audiolayer.h
@@ -184,6 +184,7 @@ class AudioLayer {
     virtual std::string getAudioPlugin( void ) = 0; 
 
     virtual void reducePulseAppsVolume( void ) = 0;
+    virtual void restorePulseAppsVolume( void ) = 0;
   
     /**
      * Write accessor to the error state
diff --git a/src/audio/audiostream.cpp b/src/audio/audiostream.cpp
index 1f57b2f174..a9f6e7345a 100644
--- a/src/audio/audiostream.cpp
+++ b/src/audio/audiostream.cpp
@@ -21,7 +21,7 @@
 
 static pa_channel_map channel_map ;
 
-AudioStream::AudioStream( pa_context* context, int type, std::string desc )
+AudioStream::AudioStream( pa_context* context, int type, std::string desc, double vol )
 { 
   _streamType = type;
   _streamDescription = desc; 
@@ -30,8 +30,8 @@ AudioStream::AudioStream( pa_context* context, int type, std::string desc )
   sample_spec.channels = 1; 
   channel_map.channels = 1; 
   flag = PA_STREAM_AUTO_TIMING_UPDATE ;
-  volume = PA_VOLUME_NORM;
-
+  _volume = PA_VOLUME_NORM * vol / 100 ;
+  
   _audiostream =  createStream( context );
 } 
 
@@ -87,7 +87,7 @@ AudioStream::createStream( pa_context* c )
   if( _streamType == PLAYBACK_STREAM ){
     pa_stream_connect_playback( s , NULL , NULL , 
 				PA_STREAM_INTERPOLATE_TIMING,
-				pa_cvolume_set(&cv, sample_spec.channels , volume) , NULL );
+				pa_cvolume_set(&cv, sample_spec.channels , _volume) , NULL );
   }
   else if( _streamType == CAPTURE_STREAM ){
     pa_stream_connect_record( s , NULL , NULL , PA_STREAM_START_CORKED );
diff --git a/src/audio/audiostream.h b/src/audio/audiostream.h
index d31c2df930..16bab21ec4 100644
--- a/src/audio/audiostream.h
+++ b/src/audio/audiostream.h
@@ -45,7 +45,7 @@ class AudioStream {
      * @param type    The type of audio stream
      * @param desc    The stream name
      */ 
-    AudioStream(pa_context* context , int type, std::string desc);
+    AudioStream(pa_context* context , int type, std::string desc, double vol);
     
     /**
      * Destructor
@@ -85,6 +85,9 @@ class AudioStream {
      */
     std::string getStreamName( void ) { return _streamDescription; }
 
+    void setVolume( double pc );
+    pa_volume_t getVolume( void ) { return _volume; }
+
   private:
     /**
      * Create the audio stream into the given context
@@ -128,7 +131,7 @@ class AudioStream {
      */
     pa_stream_flags_t flag;
     pa_sample_spec sample_spec ;
-    pa_volume_t volume;
+    pa_volume_t _volume;
 
 };
 
diff --git a/src/audio/pulselayer.cpp b/src/audio/pulselayer.cpp
index 6dfd1fe27c..a34f1f99c5 100644
--- a/src/audio/pulselayer.cpp
+++ b/src/audio/pulselayer.cpp
@@ -102,13 +102,13 @@ void PulseLayer::context_state_callback( pa_context* c, void* user_data )
   void
 PulseLayer::createStreams( pa_context* c )
 {
-  playback = new AudioStream(c, PLAYBACK_STREAM, "SFLphone out");
+  playback = new AudioStream(c, PLAYBACK_STREAM, "SFLphone out", _manager->getSpkrVolume());
   pa_stream_set_write_callback( playback->pulseStream() , audioCallback, this);
   //pa_stream_set_overflow_callback( playback , overflow , this);
-  record = new AudioStream(c, CAPTURE_STREAM, "SFLphone in");
+  record = new AudioStream(c, CAPTURE_STREAM, "SFLphone in", _manager->getMicVolume());
   pa_stream_set_read_callback( record->pulseStream() , audioCallback, this);
   //pa_stream_set_underflow_callback( record , underflow , this);
-  cache = new AudioStream(c, UPLOAD_STREAM, "Cache samples");
+  cache = new AudioStream(c, UPLOAD_STREAM, "Cache samples", _manager->getSpkrVolume());
 
   pa_threaded_mainloop_signal(m , 0);
 }
@@ -119,10 +119,6 @@ PulseLayer::openDevice(int indexIn, int indexOut, int sampleRate, int frameSize
   _sampleRate = sampleRate;
   _frameSize = frameSize;	
 
-  _debug(" Setting PulseLayer: device     in=%2d, out=%2d\n", indexIn, indexOut);
-  _debug("                   : nb channel in=%2d, out=%2d\n", _inChannel, _outChannel);
-  _debug("                   : sample rate=%5d\n", _sampleRate );
-
   m = pa_threaded_mainloop_new();
   assert(m);
 
@@ -267,6 +263,8 @@ PulseLayer::processData( void )
   int urgentAvail; // number of data right and data left  
   int normalAvail; // number of data right and data left
 
+  
+
   // Handle the mic also
   if( (record->pulseStream()) && pa_stream_get_state( record->pulseStream()) == PA_STREAM_READY) {
 
@@ -344,7 +342,7 @@ static void retrieve_client_list(pa_context *c, const pa_client_info *i, int eol
   _debug("\t\tDriver : %s\n" , i->driver);  
 }
 
-static void retrieve_sink_list(pa_context *c, const pa_sink_input_info *i, int eol, void *userdata)
+static void reduce_sink_list(pa_context *c, const pa_sink_input_info *i, int eol, void *userdata)
 {
   PulseLayer* pulse = (PulseLayer*) userdata;
   AudioStream* s = pulse->getPlaybackStream();
@@ -360,10 +358,32 @@ static void retrieve_sink_list(pa_context *c, const pa_sink_input_info *i, int e
   }  
 }
 
+static void restore_sink_list(pa_context *c, const pa_sink_input_info *i, int eol, void *userdata)
+{
+  PulseLayer* pulse = (PulseLayer*) userdata;
+  AudioStream* s = pulse->getPlaybackStream();
+  //_debug("my app index = %d\n",pa_stream_get_index(pulse->getPlaybackStream()->pulseStream()));
+  if( !eol ){
+    _debug("Sink Info: index : %i\n" , i->index);  
+    _debug("\t\tSink name : -%s-\n" , i->name);  
+    _debug("\t\tClient : %i\n" , i->client); 
+    _debug("\t\tVolume : %i\n" , i->volume.values[0]); 
+    _debug("\t\tChannels : %i\n" , i->volume.channels); 
+    if( strcmp( i->name ,  s->getStreamName().c_str()) != 0)
+      pulse->restoreAppVolume( i->index , i->volume.channels);
+  }  
+}
+
 void
 PulseLayer::reducePulseAppsVolume( void )
 {
-  pa_context_get_sink_input_info_list( context , retrieve_sink_list , this );
+  pa_context_get_sink_input_info_list( context , reduce_sink_list , this );
+}
+
+void
+PulseLayer::restorePulseAppsVolume( void )
+{
+  pa_context_get_sink_input_info_list( context , restore_sink_list , this );
 }
 
 void
@@ -387,7 +407,17 @@ PulseLayer::reduceAppVolume( int index , int channels )
   pa_cvolume_set( &volume , channels , vol);
   _debug("Mute Index %i\n" , index);
   pa_context_set_sink_input_volume( context, index, &volume, on_success, this) ;
+}
+
+void
+PulseLayer::restoreAppVolume( int index, int channels )
+{
+  pa_cvolume volume;
+  pa_volume_t vol = PA_VOLUME_NORM;
   
+  pa_cvolume_set( &volume , channels , vol);
+  _debug("Restore Index %i\n" , index);
+  pa_context_set_sink_input_volume( context, index, &volume, on_success, this) ;
 }
 
 
diff --git a/src/audio/pulselayer.h b/src/audio/pulselayer.h
index 9ce53a0d11..17fb909007 100644
--- a/src/audio/pulselayer.h
+++ b/src/audio/pulselayer.h
@@ -49,30 +49,54 @@ class PulseLayer : public AudioLayer {
     bool openDevice(int indexIn, int indexOut, int sampleRate, int frameSize , int stream, std::string plugin) ;
 
     void startStream(void);
+
     void stopStream(void);
 
     /**
-     * Check if the capture is running
-     * @return true if the state of the capture handle equals SND_PCM_STATE_RUNNING
-     *	       false otherwise
+     * UNUSED in pulseaudio layer
      */
     bool isCaptureActive( void ) { return true; }
+
+    /**
+     * UNUSED in pulseaudio layer
+     */
     bool isStreamActive (void); 
 
+    /**
+     * Flush the main ringbuffer, reserved for the voice
+     */
     void flushMain();
+    
     int putMain(void* buffer, int toCopy);
+    
     int putUrgent(void* buffer, int toCopy);
+
+    /**
+     * UNUSED in pulseaudio layer
+     */
     int putInCache( char code, void* buffer , int toCopy );
+
+    /**
+     * Query the capture device for number of bytes available in the hardware ring buffer
+     * @return int The number of bytes available
+     */
     int canGetMic();
+    
+    /**
+     * Get data from the capture device
+     * @param buffer The buffer for data
+     * @param toCopy The number of bytes to get
+     * @return int The number of bytes acquired ( 0 if an error occured)
+     */
     int getMic(void *, int);
+    
+    /**
+     * Flush the mic ringbuffer
+     */
     void flushMic();
 
     /**
-     * Send samples to the audio device. 
-     * @param buffer The buffer containing the data to be played ( voice and DTMF )
-     * @param toCopy The number of samples, in bytes
-     * @param isTalking	If whether or not the conversation is running
-     * @return int The number of bytes played
+     * UNUSED in pulseaudio layer
      */
     int playSamples(void* buffer, int toCopy, bool isTalking) ;
 
@@ -83,12 +107,7 @@ class PulseLayer : public AudioLayer {
     static void context_state_callback( pa_context* c, void* user_data );	
 
     /**
-     * Scan the sound card available on the system
-     * @param stream To indicate whether we are looking for capture devices or playback devices
-     *		   SFL_PCM_CAPTURE
-     *		   SFL_PCM_PLAYBACK
-     *		   SFL_PCM_BOTH
-     * @return std::vector<std::string> The vector containing the string description of the card
+     * UNUSED in pulseaudio layer
      */
     std::vector<std::string> getSoundCardsInfo( int stream ) { 
       std::vector<std::string> tmp;
@@ -96,34 +115,54 @@ class PulseLayer : public AudioLayer {
     }
 
     /**
-     * Check if the given index corresponds to an existing sound card and supports the specified streaming mode
-     * @param card   An index
-     * @param stream  The stream mode
-     *		  SFL_PCM_CAPTURE
-     *		  SFL_PCM_PLAYBACK
-     *		  SFL_PCM_BOTH
-     * @return bool True if it exists and supports the mode
-     *		    false otherwise
+     * UNUSED in pulseaudio layer
      */
     bool soundCardIndexExist( int card , int stream ) { return true; }
     
     /**
-     * An index is associated with its string description
-     * @param description The string description
-     * @return	int	  Its index
+     * UNUSED in pulseaudio layer
      */
     int soundCardGetIndex( std::string description ) { return 0;}
 
     /**
-     * Get the current audio plugin.
-     * @return std::string  The name of the audio plugin
+     * UNUSED in pulseaudio layer
      */
     std::string getAudioPlugin( void ) { return "default"; }
     
+    /**
+     * Reduce volume of every audio applications connected to the same sink
+     */
     void reducePulseAppsVolume( void );
+    
+    /**
+     * Restore the volume of every audio applications connected to the same sink to PA_VOLUME_NORM
+     */
+    void restorePulseAppsVolume( void );
+    
+    /**
+     * Reduce volume of one particular application
+     * @param index The index of the stream 
+     * @param channels	The stream's number of channels
+     */
     void reduceAppVolume( int index , int channels ); 
+  
+    /**
+     * Restore to PA_VOLUME_NORM the volume of one particular application
+     * @param index The index of the stream 
+     * @param channels	The stream's number of channels
+     */
+    void restoreAppVolume( int index , int channels ); 
 
+    /**
+     * Accessor
+     * @return AudioStream* The pointer on the playback AudioStream object
+     */
     AudioStream* getPlaybackStream(){ return playback;}
+
+    /**
+     * Accessor
+     * @return AudioStream* The pointer on the record AudioStream object
+     */
     AudioStream* getRecordStream(){ return record;}
 
   private:
@@ -132,27 +171,64 @@ class PulseLayer : public AudioLayer {
      */
     void closeCaptureStream( void );
 
+    /**
+     * Write data from the ring buffer to the harware and read data from the hardware
+     */
     void processData( void );
+    
+    /**
+     * Create the audio streams into the given context
+     * @param c	The pulseaudio context
+     */ 
     void createStreams( pa_context* c );
+
     /**
      * Drop the pending frames and close the playback device
      */
     void closePlaybackStream( void );
 
+    /**
+     * Establishes the connection with the local pulseaudio server
+     */
     void connectPulseServer( void );
 
+    /**
+     * Get some information about the pulseaudio server
+     */
     void serverinfo( void );
 
-    /** Ringbuffers for data */
+    /** 
+     * Ringbuffer for incoming voice data (playback)
+     */
     RingBuffer _mainSndRingBuffer;
+
+    /** 
+     * Ringbuffer for dtmf data
+     */
     RingBuffer _urgentRingBuffer;
+
+    /** 
+     * Ringbuffer for outgoing voice data (mic)
+     */
     RingBuffer _micRingBuffer;
 
-    /** PulseAudio streams and context */
+    /** PulseAudio context and asynchronous loop */
     pa_context* context;
     pa_threaded_mainloop* m;
+    
+    /**
+     * A stream object to handle the pulseaudio playback stream
+     */
     AudioStream* playback;
+
+    /**
+     * A stream object to handle the pulseaudio capture stream
+     */
     AudioStream* record;
+
+    /**
+     * A stream object to handle the pulseaudio upload stream
+     */
     AudioStream* cache;
 };
 
diff --git a/src/dbus/configurationmanager-glue.h b/src/dbus/configurationmanager-glue.h
index f2cbbbeb89..5defe82eb7 100644
--- a/src/dbus/configurationmanager-glue.h
+++ b/src/dbus/configurationmanager-glue.h
@@ -69,6 +69,8 @@ public:
         register_method(ConfigurationManager, isStartHidden, _isStartHidden_stub);
         register_method(ConfigurationManager, popupMode, _popupMode_stub);
         register_method(ConfigurationManager, switchPopupMode, _switchPopupMode_stub);
+        register_method(ConfigurationManager, setPulseAppVolumeControl, _setPulseAppVolumeControl_stub);
+        register_method(ConfigurationManager, getPulseAppVolumeControl, _getPulseAppVolumeControl_stub);
     }
 
     ::DBus::IntrospectedInterface* const introspect() const 
@@ -315,6 +317,15 @@ public:
         {
             { 0, 0, 0 }
         };
+        static ::DBus::IntrospectedArgument setPulseAppVolumeControl_args[] = 
+        {
+            { 0, 0, 0 }
+        };
+        static ::DBus::IntrospectedArgument getPulseAppVolumeControl_args[] = 
+        {
+            { "state", "i", false },
+            { 0, 0, 0 }
+        };
         static ::DBus::IntrospectedArgument parametersChanged_args[] = 
         {
             { "list", "a{ss}", false },
@@ -380,6 +391,8 @@ public:
             { "isStartHidden", isStartHidden_args },
             { "popupMode", popupMode_args },
             { "switchPopupMode", switchPopupMode_args },
+            { "setPulseAppVolumeControl", setPulseAppVolumeControl_args },
+            { "getPulseAppVolumeControl", getPulseAppVolumeControl_args },
             { 0, 0 }
         };
         static ::DBus::IntrospectedMethod ConfigurationManager_signals[] = 
@@ -463,6 +476,8 @@ public:
     virtual ::DBus::Int32 isStartHidden(  ) = 0;
     virtual ::DBus::Int32 popupMode(  ) = 0;
     virtual void switchPopupMode(  ) = 0;
+    virtual void setPulseAppVolumeControl(  ) = 0;
+    virtual ::DBus::Int32 getPulseAppVolumeControl(  ) = 0;
 
 public:
 
@@ -959,6 +974,24 @@ private:
         ::DBus::ReturnMessage reply(call);
         return reply;
     }
+    ::DBus::Message _setPulseAppVolumeControl_stub( const ::DBus::CallMessage& call )
+    {
+        ::DBus::MessageIter ri = call.reader();
+
+        setPulseAppVolumeControl();
+        ::DBus::ReturnMessage reply(call);
+        return reply;
+    }
+    ::DBus::Message _getPulseAppVolumeControl_stub( const ::DBus::CallMessage& call )
+    {
+        ::DBus::MessageIter ri = call.reader();
+
+        ::DBus::Int32 argout1 = getPulseAppVolumeControl();
+        ::DBus::ReturnMessage reply(call);
+        ::DBus::MessageIter wi = reply.writer();
+        wi << argout1;
+        return reply;
+    }
 };
 
 } } } 
diff --git a/src/dbus/configurationmanager-introspec.xml b/src/dbus/configurationmanager-introspec.xml
index 9a8c87455e..624260b763 100644
--- a/src/dbus/configurationmanager-introspec.xml
+++ b/src/dbus/configurationmanager-introspec.xml
@@ -203,6 +203,13 @@
     <method name="switchPopupMode">
     </method>
 
+    <method name="setPulseAppVolumeControl">
+    </method>
+
+    <method name="getPulseAppVolumeControl">
+      <arg type="i" name="state" direction="out"/>
+    </method>
+
   <!--        /////////////////////////////       -->
     <signal name="parametersChanged">
       <arg type="a{ss}" name="list" direction="out"/>
diff --git a/src/dbus/configurationmanager.cpp b/src/dbus/configurationmanager.cpp
index 26ea486dae..2e6a8c6ee1 100644
--- a/src/dbus/configurationmanager.cpp
+++ b/src/dbus/configurationmanager.cpp
@@ -362,3 +362,16 @@ ConfigurationManager::getMailNotify( void )
   _debug("Manager received getMailNotify\n");
   return Manager::instance().getMailNotify(  ); 
 }
+
+::DBus::Int32 
+ConfigurationManager::getPulseAppVolumeControl( void )
+{
+  return Manager::instance().getPulseAppVolumeControl();
+}
+    
+void 
+ConfigurationManager::setPulseAppVolumeControl( void )
+{
+  Manager::instance().setPulseAppVolumeControl();
+}
+
diff --git a/src/dbus/configurationmanager.h b/src/dbus/configurationmanager.h
index 8dda655d95..82f9c7f237 100644
--- a/src/dbus/configurationmanager.h
+++ b/src/dbus/configurationmanager.h
@@ -93,6 +93,8 @@ public:
     void setNotify( void );
     ::DBus::Int32 getMailNotify( void );
     void setMailNotify( void );
+    ::DBus::Int32 getPulseAppVolumeControl( void );
+    void setPulseAppVolumeControl( void );
 
 };
 
diff --git a/src/managerimpl.cpp b/src/managerimpl.cpp
index 61c81f1235..b7f595cab2 100644
--- a/src/managerimpl.cpp
+++ b/src/managerimpl.cpp
@@ -276,6 +276,9 @@ ManagerImpl::hangupCall(const CallID& id)
   removeCallAccount(id);
   switchCall("");
 
+  if( getConfigInt( PREFERENCES , CONFIG_PA_VOLUME_CTRL ) )
+    _audiodriver->restorePulseAppsVolume();
+
   return returnValue;
 }
 
@@ -582,7 +585,8 @@ ManagerImpl::incomingCall(Call* call, const AccountID& accountId)
   _dbus->getCallManager()->incomingCall(accountId, call->getCallId(), from);
 
   // Reduce volume of the other pulseaudio-connected audio applications
-  _audiodriver->reducePulseAppsVolume();
+  if( getConfigInt( PREFERENCES , CONFIG_PA_VOLUME_CTRL ) )
+    _audiodriver->reducePulseAppsVolume();
   
   return true;
 }
@@ -633,6 +637,8 @@ ManagerImpl::peerHungupCall(const CallID& id)
   removeWaitingCall(id);
   removeCallAccount(id);
   
+  if( getConfigInt( PREFERENCES , CONFIG_PA_VOLUME_CTRL ) )
+    _audiodriver->restorePulseAppsVolume();
 }
 
 //THREAD=VoIP
@@ -1020,6 +1026,7 @@ ManagerImpl::initConfigFile (void)
   fill_config_int(CONFIG_HISTORY , DFT_MAX_CALLS);
   fill_config_int(REGISTRATION_EXPIRE , DFT_EXPIRE_VALUE);
   fill_config_int(CONFIG_AUDIO , DFT_AUDIO_MANAGER);
+  fill_config_int(CONFIG_PA_VOLUME_CTRL , YES_STR);
 
   // Loads config from ~/.sflphone/sflphonedrc or so..
   if (createSettingsPath() == 1) {
@@ -1451,6 +1458,18 @@ ManagerImpl::getMailNotify( void )
   return getConfigInt( PREFERENCES , CONFIG_MAIL_NOTIFY );
 }
 
+::DBus::Int32
+ManagerImpl::getPulseAppVolumeControl( void )
+{
+  return getConfigInt( PREFERENCES , CONFIG_PA_VOLUME_CTRL );
+}
+
+void
+ManagerImpl::setPulseAppVolumeControl( void )
+{
+  (getConfigInt( PREFERENCES , CONFIG_PA_VOLUME_CTRL ) == 1)? setConfig( PREFERENCES , CONFIG_PA_VOLUME_CTRL , NO_STR) : setConfig( PREFERENCES , CONFIG_PA_VOLUME_CTRL , YES_STR) ;
+}
+
 void
 ManagerImpl::setAudioManager( const DBus::Int32& api )
 {
diff --git a/src/managerimpl.h b/src/managerimpl.h
index 94212b4009..ac765583e2 100644
--- a/src/managerimpl.h
+++ b/src/managerimpl.h
@@ -559,6 +559,10 @@ class ManagerImpl {
     void setAudioManager( const DBus::Int32& api );
 
     void switchAudioManager( void );
+    
+    void setPulseAppVolumeControl( void ); 
+    ::DBus::Int32 getPulseAppVolumeControl( void ); 
+
     /**
      * Get the desktop mail notification level
      * @return int The mail notification level
diff --git a/src/user_cfg.h b/src/user_cfg.h
index 9597b094ed..25a0cc953b 100644
--- a/src/user_cfg.h
+++ b/src/user_cfg.h
@@ -60,6 +60,7 @@
 #define CONFIG_ZEROCONF		"Zeroconf.enable"	  /** Zero configuration networking module */
 #define REGISTRATION_EXPIRE	"Registration.expire"	  /** Registration expire value */
 #define CONFIG_AUDIO		"Audio.api"		  /** Audio manager (ALSA or pulseaudio) */
+#define CONFIG_PA_VOLUME_CTRL	"Pulseaudio.volumeCtrl"	  /** Whether or not PA should modify volume of other applications on the same sink */
 
 #define SIGNALISATION		"VoIPLink"	      /** Section Signalisation */
 #define PLAY_DTMF		"DTMF.playDtmf"	      /** Whether or not should play dtmf */
@@ -87,6 +88,7 @@
 #define DFT_EXPIRE_VALUE	"180"			/** Default expire value for registration */
 #define DFT_AUDIO_MANAGER	"1"			/** Default audio manager */
 
+
 #ifdef USE_ZEROCONF
 #define CONFIG_ZEROCONF_DEFAULT_STR "1"			/** Default Zero configuration networking module value */
 #else
-- 
GitLab