From 536bc482cf4664773e216ecc266237ee0b792c6d Mon Sep 17 00:00:00 2001 From: Emmanuel Milou <emmanuel.milou@savoirfairelinux.com> Date: Fri, 30 May 2008 10:37:15 -0400 Subject: [PATCH] Reduce volume of all audio streams connected to Pulseaudio on incoming calls Reduce volume to 10% TODO: restore volume when hangup --- sflphone-gtk/src/audioconf.c | 91 ++++++++++++++++++++---------------- src/audio/alsalayer.cpp | 6 ++- src/audio/alsalayer.h | 2 +- src/audio/audiolayer.h | 2 + src/audio/audiostream.h | 76 ++++++++++++++++++++++++++++-- src/audio/pulselayer.cpp | 72 +++++++++++++++++++++++++--- src/audio/pulselayer.h | 9 +++- src/managerimpl.cpp | 6 ++- 8 files changed, 210 insertions(+), 54 deletions(-) diff --git a/sflphone-gtk/src/audioconf.c b/sflphone-gtk/src/audioconf.c index b983a328e3..374a4f33c6 100644 --- a/sflphone-gtk/src/audioconf.c +++ b/sflphone-gtk/src/audioconf.c @@ -137,35 +137,37 @@ config_window_fill_output_audio_device_list() void select_active_output_audio_device() { + if( SHOW_ALSA_CONF ) + { - GtkTreeModel* model; - GtkTreeIter iter; - gchar** devices; - int currentDeviceIndex; - int deviceIndex; - - // Select active output device on server - //devices = dbus_get_current_audio_devices_index(); - currentDeviceIndex = 0;//atoi(devices[0]); - printf(_("audio device index for output = %d\n"), currentDeviceIndex); - model = gtk_combo_box_get_model(GTK_COMBO_BOX(output)); - - // Find the currently set output 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(output), &iter); - return; - } - } while(gtk_tree_model_iter_next(model, &iter)); - - // No index was found, select first one - g_print("Warning : No active output device found"); - gtk_combo_box_set_active(GTK_COMBO_BOX(output), 0); - + GtkTreeModel* model; + GtkTreeIter iter; + gchar** devices; + int currentDeviceIndex; + int deviceIndex; + + // Select active output device on server + devices = dbus_get_current_audio_devices_index(); + currentDeviceIndex = atoi(devices[0]); + printf(_("audio device index for output = %d\n"), currentDeviceIndex); + model = gtk_combo_box_get_model(GTK_COMBO_BOX(output)); + + // Find the currently set output 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(output), &iter); + return; + } + } while(gtk_tree_model_iter_next(model, &iter)); + + // No index was found, select first one + g_print("Warning : No active output device found"); + gtk_combo_box_set_active(GTK_COMBO_BOX(output), 0); + } } /** @@ -188,7 +190,6 @@ config_window_fill_input_audio_device_list() //int c = 0; for(audioDevice = list; *list; list++) { - g_print("dbasbasdfbzfb\n"); index = dbus_get_audio_device_index( *list ); gtk_list_store_append(inputlist, &iter); gtk_list_store_set(inputlist, &iter, 0, *list, 1, index, -1); @@ -203,7 +204,9 @@ config_window_fill_input_audio_device_list() void select_active_input_audio_device() { - + if( SHOW_ALSA_CONF) +{ + GtkTreeModel* model; GtkTreeIter iter; gchar** devices; @@ -230,7 +233,7 @@ select_active_input_audio_device() // 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); - +} } /** @@ -264,19 +267,19 @@ select_active_output_audio_plugin() { GtkTreeModel* model; GtkTreeIter iter; - gchar* plugin; + gchar* pluginname; gchar* tmp; // Select active output device on server - plugin = dbus_get_current_audio_output_plugin(); - tmp = plugin; + pluginname = dbus_get_current_audio_output_plugin(); + tmp = pluginname; model = gtk_combo_box_get_model(GTK_COMBO_BOX(plugin)); // Find the currently alsa plugin gtk_tree_model_get_iter_first(model, &iter); do { - gtk_tree_model_get(model, &iter, 0, &plugin , -1); - if( g_strcasecmp( tmp , plugin ) == 0 ) + gtk_tree_model_get(model, &iter, 0, &pluginname , -1); + if( g_strcasecmp( tmp , pluginname ) == 0 ) { // Set current iteration the active one gtk_combo_box_set_active_iter(GTK_COMBO_BOX(plugin), &iter); @@ -600,16 +603,22 @@ GtkWidget* codecs_box() void select_audio_manager( void ) { + g_print("audio manager selected\n"); if( !SHOW_ALSA_CONF && !gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON(pulse) ) ) { + g_print(" display alsa conf panel\n"); alsabox = alsa_box(); gtk_container_add( GTK_CONTAINER(alsa_conf ) , alsabox); gtk_widget_show( alsa_conf ); } else if( SHOW_ALSA_CONF && gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON(pulse) )) { + g_print(" remove alsa conf panel\n"); gtk_container_remove( GTK_CONTAINER(alsa_conf) , alsabox ); } + else + g_print("alsa conf panel...nothing\n"); + gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON(pulse) )? dbus_set_audio_manager( PULSEAUDIO ):dbus_set_audio_manager( ALSA ); } @@ -649,6 +658,7 @@ GtkWidget* alsa_box() gtk_box_pack_start( GTK_BOX(ret) , table , TRUE , TRUE , 1); gtk_widget_show(table); + g_print("plugin\n"); item = gtk_label_new(_("ALSA plugin")); gtk_misc_set_alignment(GTK_MISC(item), 0, 0.5); gtk_table_attach(GTK_TABLE(table), item, 1, 2, 1, 2, GTK_FILL | GTK_EXPAND, GTK_SHRINK, 0, 0); @@ -657,7 +667,7 @@ GtkWidget* alsa_box() pluginlist = gtk_list_store_new(1, G_TYPE_STRING); config_window_fill_output_audio_plugin_list(); plugin = gtk_combo_box_new_with_model(GTK_TREE_MODEL(pluginlist)); - //select_active_output_audio_plugin(); + select_active_output_audio_plugin(); gtk_label_set_mnemonic_widget(GTK_LABEL(item), plugin); g_signal_connect(G_OBJECT(plugin), "changed", G_CALLBACK(select_output_audio_plugin), plugin); @@ -670,6 +680,7 @@ GtkWidget* alsa_box() // Device : Output device // Create title label + g_print("output\n"); item = gtk_label_new(_("Output")); gtk_misc_set_alignment(GTK_MISC(item), 0, 0.5); gtk_table_attach(GTK_TABLE(table), item, 1, 2, 2, 3, GTK_FILL | GTK_EXPAND, GTK_SHRINK, 0, 0); @@ -678,7 +689,7 @@ GtkWidget* alsa_box() outputlist = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_INT); config_window_fill_output_audio_device_list(); output = gtk_combo_box_new_with_model(GTK_TREE_MODEL(outputlist)); - //select_active_output_audio_device(); + select_active_output_audio_device(); gtk_label_set_mnemonic_widget(GTK_LABEL(item), output); g_signal_connect(G_OBJECT(output), "changed", G_CALLBACK(select_audio_output_device), output); @@ -691,6 +702,7 @@ GtkWidget* alsa_box() // Device : Input device // Create title label + g_print("input\n"); item = gtk_label_new(_("Input")); gtk_misc_set_alignment(GTK_MISC(item), 0, 0.5); gtk_table_attach(GTK_TABLE(table), item, 1, 2, 3, 4, GTK_FILL | GTK_EXPAND, GTK_SHRINK, 0, 0); @@ -699,7 +711,7 @@ GtkWidget* alsa_box() inputlist = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_INT); config_window_fill_input_audio_device_list(); input = gtk_combo_box_new_with_model(GTK_TREE_MODEL(inputlist)); - //select_active_input_audio_device(); + select_active_input_audio_device(); gtk_label_set_mnemonic_widget(GTK_LABEL(item), input); g_signal_connect(G_OBJECT(input), "changed", G_CALLBACK(select_audio_input_device), input); @@ -712,6 +724,7 @@ GtkWidget* alsa_box() gtk_widget_show_all(ret); + g_print("done\n"); return ret; } diff --git a/src/audio/alsalayer.cpp b/src/audio/alsalayer.cpp index 2763246187..c1ea3e63e0 100644 --- a/src/audio/alsalayer.cpp +++ b/src/audio/alsalayer.cpp @@ -220,6 +220,10 @@ AlsaLayer::isStreamStopped (void) return !(isStreamActive()); } + +void +AlsaLayer::reducePulseAppsVolume( void ){} + ////////////////////////////////////////////////////////////////////////////////////////////// ///////////////// ALSA PRIVATE FUNCTIONS //////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////// @@ -334,7 +338,7 @@ AlsaLayer::open_device(std::string pcm_p, std::string pcm_c, int flag) _debugAlsa(" Opening playback device %s\n", pcm_p.c_str()); if(err = snd_pcm_open(&_PlaybackHandle, pcm_p.c_str(), SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK ) < 0){ - _debugAlsa("Error while opening playback device %s\n", pcm_c.c_str()); + _debugAlsa("Error while opening playback device %s\n", pcm_p.c_str()); setErrorMessage( ALSA_PLAYBACK_DEVICE ); return false; } diff --git a/src/audio/alsalayer.h b/src/audio/alsalayer.h index 858e0bba45..2b82bbe11c 100644 --- a/src/audio/alsalayer.h +++ b/src/audio/alsalayer.h @@ -183,7 +183,7 @@ class AlsaLayer : public AudioLayer { int putInCache( char code, void *buffer, int toCopy ); int putMain(void* buffer, int toCopy); - + void reducePulseAppsVolume( void ); private: /** diff --git a/src/audio/audiolayer.h b/src/audio/audiolayer.h index 2f51adcb10..0b0f768167 100644 --- a/src/audio/audiolayer.h +++ b/src/audio/audiolayer.h @@ -183,6 +183,8 @@ class AudioLayer { */ virtual std::string getAudioPlugin( void ) = 0; + virtual void reducePulseAppsVolume( void ) = 0; + /** * Write accessor to the error state * @param error The error code diff --git a/src/audio/audiostream.h b/src/audio/audiostream.h index c420628d9b..d31c2df930 100644 --- a/src/audio/audiostream.h +++ b/src/audio/audiostream.h @@ -27,6 +27,9 @@ #include "ringbuffer.h" #include "audioloop.h" +/** + * This data structure contains the different king of audio streams available + */ enum STREAM_TYPE { PLAYBACK_STREAM, CAPTURE_STREAM, @@ -36,30 +39,95 @@ enum STREAM_TYPE { class AudioStream { public: + /** + * Constructor + * @param context The pulseaudio context + * @param type The type of audio stream + * @param desc The stream name + */ AudioStream(pa_context* context , int type, std::string desc); + + /** + * Destructor + */ ~AudioStream(); + /** + * Write data to the main abstraction ring buffer. + * @param buffer The buffer containing the data to be played + * @param toCopy The number of samples, in bytes + * @return int The number of bytes played + */ int putMain( void* buffer , int toCopy ); + + /** + * Write data to the urgent abstraction ring buffer. ( dtmf , double calls ) + * @param buffer The buffer containing the data to be played + * @param toCopy The number of samples, in bytes + * @return int The number of bytes played + */ int putUrgent( void* buffer , int toCopy ); + /** + * Disconnect the pulseaudio stream + */ void disconnect(); + + /** + * Accessor: Get the pulseaudio stream object + * @return pa_stream* The stream + */ pa_stream* pulseStream(){ return _audiostream; } + /** + * Accessor + * @return std::string The stream name + */ + std::string getStreamName( void ) { return _streamDescription; } + private: + /** + * Create the audio stream into the given context + * @param c The pulseaudio context + * @return pa_stream* The newly created audio stream + */ pa_stream* createStream( pa_context* c ); + /** + * Mandatory asynchronous callback on the audio stream state + */ static void stream_state_callback( pa_stream* s, void* user_data ); + + /** + * Asynchronous callback on data processing ( write and read ) + */ static void audioCallback ( pa_stream* s, size_t bytes, void* userdata ); + + /** + * Write data to the sound device + */ void write( void ); + /** + * The pulse audio object + */ + pa_stream* _audiostream; + + /** + * The type of the stream + */ int _streamType; + + /** + * The name of the stream + */ std::string _streamDescription; - - - pa_stream* _audiostream; + + /** + * Streams parameters + */ pa_stream_flags_t flag; pa_sample_spec sample_spec ; - //pa_channel_map channel_map; pa_volume_t volume; }; diff --git a/src/audio/pulselayer.cpp b/src/audio/pulselayer.cpp index e783d91682..6dfd1fe27c 100644 --- a/src/audio/pulselayer.cpp +++ b/src/audio/pulselayer.cpp @@ -19,11 +19,6 @@ #include "pulselayer.h" -/*static pa_channel_map channel_map ; - static pa_stream_flags_t flag; - static pa_sample_spec sample_spec ; - static pa_volume_t volume; - */ int framesPerBuffer = 2048; PulseLayer::PulseLayer(ManagerImpl* manager) @@ -73,7 +68,8 @@ PulseLayer::connectPulseServer( void ) } pa_threaded_mainloop_unlock( m ); - + serverinfo(); + //muteAudioApps(99); _debug("Context creation done\n"); } @@ -331,3 +327,67 @@ PulseLayer::putInCache( char code, void *buffer, int toCopy ) //pa_stream_finish_upload( cache->pulseStream() ); } +static void retrieve_server_info(pa_context *c, const pa_server_info *i, void *userdata) +{ + _debug("Server Info: Process owner : %s\n" , i->user_name); + _debug("\t\tServer name : %s - Server version = %s\n" , i->server_name, i->server_version); + _debug("\t\tDefault sink name : %s\n" , i->default_sink_name); + _debug("\t\tDefault source name : %s\n" , i->default_source_name); +} + +static void retrieve_client_list(pa_context *c, const pa_client_info *i, int eol, void *userdata) +{ + _debug("end of list = %i\n", eol); + _debug("Clients Info: index : %i\n" , i->index); + _debug("\t\tClient name : %s\n" , i->name); + _debug("\t\tOwner module : %i\n" , i->owner_module); + _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) +{ + 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->reduceAppVolume( i->index , i->volume.channels); + } +} + +void +PulseLayer::reducePulseAppsVolume( void ) +{ + pa_context_get_sink_input_info_list( context , retrieve_sink_list , this ); +} + +void +PulseLayer::serverinfo( void ) +{ + pa_context_get_server_info( context , retrieve_server_info , NULL ); +} + +static void on_success(pa_context *c, int success, void *userdata) +{ + _debug("Operation successfull \n"); +} + +void +PulseLayer::reduceAppVolume( int index , int channels ) +{ + pa_cvolume volume; + pa_volume_t vol = PA_VOLUME_NORM; + vol /= 10; + + pa_cvolume_set( &volume , channels , vol); + _debug("Mute 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 7a6bea3562..9ce53a0d11 100644 --- a/src/audio/pulselayer.h +++ b/src/audio/pulselayer.h @@ -80,7 +80,6 @@ class PulseLayer : public AudioLayer { static void overflow ( pa_stream* s, void* userdata ); static void underflow ( pa_stream* s, void* userdata ); static void stream_state_callback( pa_stream* s, void* user_data ); - static void context_state_callback( pa_context* c, void* user_data ); /** @@ -121,6 +120,11 @@ class PulseLayer : public AudioLayer { */ std::string getAudioPlugin( void ) { return "default"; } + void reducePulseAppsVolume( void ); + void reduceAppVolume( int index , int channels ); + + AudioStream* getPlaybackStream(){ return playback;} + AudioStream* getRecordStream(){ return record;} private: /** @@ -137,6 +141,8 @@ class PulseLayer : public AudioLayer { void connectPulseServer( void ); + void serverinfo( void ); + /** Ringbuffers for data */ RingBuffer _mainSndRingBuffer; RingBuffer _urgentRingBuffer; @@ -145,7 +151,6 @@ class PulseLayer : public AudioLayer { /** PulseAudio streams and context */ pa_context* context; pa_threaded_mainloop* m; - AudioStream* playback; AudioStream* record; AudioStream* cache; diff --git a/src/managerimpl.cpp b/src/managerimpl.cpp index eb92a78c16..61c81f1235 100644 --- a/src/managerimpl.cpp +++ b/src/managerimpl.cpp @@ -580,6 +580,10 @@ ManagerImpl::incomingCall(Call* call, const AccountID& accountId) from.append(">"); } _dbus->getCallManager()->incomingCall(accountId, call->getCallId(), from); + + // Reduce volume of the other pulseaudio-connected audio applications + _audiodriver->reducePulseAppsVolume(); + return true; } @@ -1592,7 +1596,7 @@ ManagerImpl::switchAudioManager( void ) int numCardIn = getConfigInt( AUDIO , ALSA_CARD_ID_IN ); int numCardOut = getConfigInt( AUDIO , ALSA_CARD_ID_OUT ); - _debug("Deleting current layer...\n"); + _debug("Deleting current layer... \n" ); _audiodriver->closeLayer(); delete _audiodriver; _audiodriver = NULL; -- GitLab