diff --git a/sflphone-client-gnome/src/config/audioconf.c b/sflphone-client-gnome/src/config/audioconf.c index 62abf5a4e247aa7f719f379586c0a66451bead96..29ec95f57ba570700c07a4e68e393b5ac0973426 100644 --- a/sflphone-client-gnome/src/config/audioconf.c +++ b/sflphone-client-gnome/src/config/audioconf.c @@ -35,9 +35,11 @@ GtkListStore *pluginlist; GtkListStore *outputlist; GtkListStore *inputlist; +GtkListStore *ringtonelist; GtkWidget *output; GtkWidget *input; +GtkWidget *ringtone; GtkWidget *plugin; GtkWidget *codecMoveUpButton; GtkWidget *codecMoveDownButton; @@ -103,7 +105,7 @@ void preferences_dialog_fill_codec_list (account_t **a) { * Fill store with output audio plugins */ void -preferences_dialog_fill_output_audio_plugin_list() +preferences_dialog_fill_audio_plugin_list() { GtkTreeIter iter; gchar** list; @@ -112,7 +114,7 @@ preferences_dialog_fill_output_audio_plugin_list() gtk_list_store_clear(pluginlist); // Call dbus to retreive list - list = dbus_get_output_audio_plugin_list(); + list = dbus_get_audio_plugin_list(); // For each API name included in list int c = 0; @@ -127,6 +129,7 @@ preferences_dialog_fill_output_audio_plugin_list() list = NULL; } + /** * Fill output audio device store */ @@ -155,6 +158,37 @@ preferences_dialog_fill_output_audio_device_list() } } + +/** + * Fill rigntone audio device store + */ + +void +preferences_dialog_fill_ringtone_audio_device_list() +{ + + GtkTreeIter iter; + gchar** list; + gchar** audioDevice; + int index; + + gtk_list_store_clear(ringtonelist); + + // Call dbus to retreive output device + list = dbus_get_audio_output_device_list(); + + // For each device name in the list + int c = 0; + for(audioDevice = list; *list; list++) { + index = dbus_get_audio_device_index( *list ); + gtk_list_store_append(ringtonelist, &iter); + gtk_list_store_set(ringtonelist, &iter, 0, *list, 1, index, -1); + c++; + } +} + + + /** * Select active output audio device */ @@ -194,6 +228,46 @@ select_active_output_audio_device() } } + +/** + * Select active output audio device + */ + void +select_active_ringtone_audio_device() +{ + if( SHOW_ALSA_CONF ) + { + + GtkTreeModel* model; + GtkTreeIter iter; + gchar** devices; + int currentDeviceIndex; + int deviceIndex; + + // Select active ringtone device on server + devices = dbus_get_current_audio_devices_index(); + currentDeviceIndex = atoi(devices[2]); + DEBUG("audio device index for ringtone = %d", currentDeviceIndex); + model = gtk_combo_box_get_model(GTK_COMBO_BOX(ringtone)); + + // Find the currently set ringtone 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(ringtone), &iter); + return; + } + } while(gtk_tree_model_iter_next(model, &iter)); + + // No index was found, select first one + WARN("Warning : No active ringtone device found"); + gtk_combo_box_set_active(GTK_COMBO_BOX(ringtone), 0); + } +} + /** * Fill input audio device store */ @@ -364,6 +438,29 @@ select_audio_input_device(GtkComboBox* comboBox, gpointer data UNUSED) } } +/** + * Set the audio ringtone device on the server with its index + */ +static void +select_audio_ringtone_device(GtkComboBox *comboBox, gpointer data UNUSED) +{ + GtkTreeModel *model; + GtkTreeIter iter; + int comboBoxIndex; + int deviceIndex; + + comboBoxIndex = gtk_combo_box_get_active(comboBox); + + if(comboBoxIndex >= 0) { + model = gtk_combo_box_get_model(comboBox); + gtk_combo_box_get_active_iter(comboBox, &iter); + + gtk_tree_model_get(model, &iter, 1, &deviceIndex, -1); + + dbus_set_audio_ringtone_device(deviceIndex); + } +} + /** * Toggle move buttons on if a codec is selected, off elsewise */ @@ -647,8 +744,7 @@ GtkWidget* codecs_box (account_t **a) void select_audio_manager( void ) { - - DEBUG("audio manager selected\n"); + DEBUG("audio manager selected"); if( !SHOW_ALSA_CONF && !gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON(pulse) ) ) { @@ -690,19 +786,19 @@ GtkWidget* alsa_box() ret = gtk_hbox_new(FALSE, 10); gtk_widget_show( ret ); - table = gtk_table_new(4, 3, FALSE); + table = gtk_table_new(5, 3, FALSE); gtk_table_set_col_spacing(GTK_TABLE(table), 0, 40); gtk_box_pack_start( GTK_BOX(ret) , table , TRUE , TRUE , 1); gtk_widget_show(table); - DEBUG("plugin"); + DEBUG("Audio: Configuration plugin"); 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); gtk_widget_show( item ); // Set choices of audio managers pluginlist = gtk_list_store_new(1, G_TYPE_STRING); - preferences_dialog_fill_output_audio_plugin_list(); + preferences_dialog_fill_audio_plugin_list(); plugin = gtk_combo_box_new_with_model(GTK_TREE_MODEL(pluginlist)); select_active_output_audio_plugin(); gtk_label_set_mnemonic_widget(GTK_LABEL(item), plugin); @@ -717,7 +813,7 @@ GtkWidget* alsa_box() // Device : Output device // Create title label - DEBUG("output"); + DEBUG("Audio: Configuration output"); 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); @@ -739,7 +835,7 @@ GtkWidget* alsa_box() // Device : Input device // Create title label - DEBUG("input"); + DEBUG("Audio: Configuration input"); 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); @@ -760,6 +856,27 @@ GtkWidget* alsa_box() gtk_table_attach(GTK_TABLE(table), input, 2, 3, 3, 4, GTK_FILL | GTK_EXPAND, GTK_SHRINK, 0, 0); gtk_widget_show(input); + + DEBUG("Audio: Configuration rintgtone"); + item = gtk_label_new(_("Ringtone")); + gtk_misc_set_alignment(GTK_MISC(item), 0, 0.5); + gtk_table_attach(GTK_TABLE(table), item, 1, 2, 4, 5, GTK_FILL | GTK_EXPAND, GTK_SHRINK, 0, 0); + gtk_widget_show(item); + // set choices of ringtone devices + ringtonelist = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_INT); + preferences_dialog_fill_ringtone_audio_device_list(); + ringtone = gtk_combo_box_new_with_model(GTK_TREE_MODEL(ringtonelist)); + select_active_ringtone_audio_device(); + gtk_label_set_mnemonic_widget(GTK_LABEL(item), output); + g_signal_connect(G_OBJECT(ringtone), "changed", G_CALLBACK(select_audio_ringtone_device), output); + + // Set rendering + renderer = gtk_cell_renderer_text_new(); + gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(ringtone), renderer, TRUE); + gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(ringtone), renderer, "text", 0, NULL); + gtk_table_attach(GTK_TABLE(table), ringtone, 2, 3, 4, 5, GTK_FILL | GTK_EXPAND, GTK_SHRINK, 0, 0); + gtk_widget_show(ringtone); + gtk_widget_show_all(ret); DEBUG("done"); diff --git a/sflphone-client-gnome/src/dbus/configurationmanager-introspec.xml b/sflphone-client-gnome/src/dbus/configurationmanager-introspec.xml index 8d8dcf9468526693cbaa6b74e668247fb0485919..8a0c59c8b2b1aa69d46519915f26228a9d27584b 100644 --- a/sflphone-client-gnome/src/dbus/configurationmanager-introspec.xml +++ b/sflphone-client-gnome/src/dbus/configurationmanager-introspec.xml @@ -105,8 +105,8 @@ <tp:docstring> </tp:docstring> <arg type="s" name="accountID" direction="in"> - <tp:docstring> - </tp:docstring> + <tp:docstring> + </tp:docstring> </arg> <arg type="i" name="number" direction="in"> <tp:docstring> @@ -118,8 +118,9 @@ <tp:docstring> </tp:docstring> <arg type="s" name="accountID" direction="in"> - <tp:docstring> - </tp:docstring> + <tp:docstring> + Account ID + </tp:docstring> </arg> </method> @@ -206,55 +207,55 @@ <method name="addAccount" tp:name-for-bindings="addAccount"> <tp:docstring> - Add a new account. When created, the signal <tp:member-ref>accountsChanged</tp:member-ref> is emitted. The clients must then call <tp:member-ref>getAccountList</tp:member-ref> to update their internal data structure. - <tp:rationale>If no details are specified, the default parameters are used.</tp:rationale> - <tp:rationale>The core tries to register the account as soon it is created.</tp:rationale> + Add a new account. When created, the signal <tp:member-ref>accountsChanged</tp:member-ref> is emitted. The clients must then call <tp:member-ref>getAccountList</tp:member-ref> to update their internal data structure. + <tp:rationale>If no details are specified, the default parameters are used.</tp:rationale> + <tp:rationale>The core tries to register the account as soon it is created.</tp:rationale> </tp:docstring> <annotation name="com.trolltech.QtDBus.QtTypeName.In0" value="MapStringString"/> <arg type="a{ss}" name="details" direction="in" tp:type="String_String_Map"> - <tp:docstring> - The new account settings - </tp:docstring> + <tp:docstring> + The new account settings + </tp:docstring> </arg> <arg type="s" name="createdAccountId" direction="out"> - <tp:docstring> - A new account ID - </tp:docstring> + <tp:docstring> + A new account ID + </tp:docstring> </arg> </method> <method name="setAccountsOrder" tp:name-for-bindings="setAccountsOrder"> <tp:docstring> - Update the accounts order. - <tp:rationale>When placing a call, the first registered account in the list is used.</tp:rationale> + Update the accounts order. + <tp:rationale>When placing a call, the first registered account in the list is used.</tp:rationale> </tp:docstring> <arg type="s" name="order" direction="in"> - <tp:docstring> - An ordered list of account IDs, delimited by '/' - </tp:docstring> + <tp:docstring> + An ordered list of account IDs, delimited by '/' + </tp:docstring> </arg> </method> <method name="removeAccount" tp:name-for-bindings="removeAccount"> - <tp:docstring> - Remove an existing account. When removed, the signal <tp:member-ref>accountsChanged</tp:member-ref> is emitted. The clients must then call <tp:member-ref>getAccountList</tp:member-ref> to update their internal data structure. - </tp:docstring> - <arg type="s" name="accoundID" direction="in"> - <tp:docstring> - The account to remove, identified by its ID - </tp:docstring> - </arg> + <tp:docstring> + Remove an existing account. When removed, the signal <tp:member-ref>accountsChanged</tp:member-ref> is emitted. The clients must then call <tp:member-ref>getAccountList</tp:member-ref> to update their internal data structure. + </tp:docstring> + <arg type="s" name="accoundID" direction="in"> + <tp:docstring> + The account to remove, identified by its ID + </tp:docstring> + </arg> </method> <method name="getAccountList" tp:name-for-bindings="getAccountList"> - <tp:docstring> - Get a list of all created accounts, as stored by the core. - </tp:docstring> + <tp:docstring> + Get a list of all created accounts, as stored by the core. + </tp:docstring> <annotation name="com.trolltech.QtDBus.QtTypeName.Out0" value="VectorString"/> <arg type="as" name="list" direction="out"> - <tp:docstring> - A list of account IDs - </tp:docstring> + <tp:docstring> + A list of account IDs + </tp:docstring> </arg> </method> @@ -267,15 +268,15 @@ @param[in] input accountID --> <arg type="s" name="accountID" direction="in"> - <tp:docstring> - The account ID - </tp:docstring> + <tp:docstring> + The account ID + </tp:docstring> </arg> <arg type="i" name="expire" direction="in"> - <tp:docstring> - <p>To register, expire must be 1.</p> - <p>To un-register, expire must be 0.</p> - </tp:docstring> + <tp:docstring> + <p>To register, expire must be 1.</p> + <p>To un-register, expire must be 0.</p> + </tp:docstring> </arg> </method> @@ -284,13 +285,14 @@ </tp:docstring> <annotation name="com.trolltech.QtDBus.QtTypeName.Out0" value="VectorString"/> <arg type="as" name="list" direction="out"> - <tp:docstring> - </tp:docstring> + <tp:docstring> + </tp:docstring> </arg> </method> <method name="getVersion" tp:name-for-bindings="getVersion"> <tp:docstring> + Return SFLphone-daemon version </tp:docstring> <arg type="s" name="version" direction="out"> <tp:docstring> @@ -300,16 +302,19 @@ <method name="getRingtoneList" tp:name-for-bindings="getRingtoneList"> <tp:docstring> + Return a list of valid Sun's .au sound file used + as ringtones. </tp:docstring> <annotation name="com.trolltech.QtDBus.QtTypeName.Out0" value="VectorString"/> <arg type="as" name="list" direction="out"> - <tp:docstring> - </tp:docstring> + <tp:docstring> + </tp:docstring> </arg> </method> <method name="getPlaybackDeviceList" tp:name-for-bindings="getPlaybackDeviceList"> <tp:docstring> + Provide a list of playback device from ALSA </tp:docstring> <annotation name="com.trolltech.QtDBus.QtTypeName.Out0" value="VectorString"/> <arg type="as" name="list" direction="out"> @@ -320,6 +325,7 @@ <method name="getRecordDeviceList" tp:name-for-bindings="getRecordDeviceList"> <tp:docstring> + Provide a list of record device from ALSA </tp:docstring> <annotation name="com.trolltech.QtDBus.QtTypeName.Out0" value="VectorString"/> <arg type="as" name="list" direction="out"> @@ -330,6 +336,7 @@ <method name="isRingtoneEnabled" tp:name-for-bindings="isRingtoneEnabled"> <tp:docstring> + Return true if ringtone is enabled, false otherwise </tp:docstring> <arg type="i" name="bool" direction="out"> <tp:docstring> @@ -339,24 +346,28 @@ <method name="ringtoneEnabled" tp:name-for-bindings="ringtoneEnabled"> <tp:docstring> + Unused </tp:docstring> </method> <method name="getRingtoneChoice" tp:name-for-bindings="getRingtoneChoice"> <tp:docstring> + Get current ringtone .au file selected </tp:docstring> <arg type="s" name="tone" direction="out"> - <tp:docstring> - </tp:docstring> + <tp:docstring> + </tp:docstring> </arg> </method> <method name="setRingtoneChoice" tp:name-for-bindings="setRingtoneChoice"> <tp:docstring> + Set current ringtone .au file from list acquired using <tp:member-ref>getAccountList</tp:member-ref> </tp:docstring> <arg type="s" name="tone" direction="in"> - <tp:docstring> - </tp:docstring> + <tp:docstring> + A valid .au file path + </tp:docstring> </arg> </method> @@ -455,17 +466,7 @@ <!-- Audio devices methods --> - <method name="getInputAudioPluginList" tp:name-for-bindings="getInputAudioPluginList"> - <tp:docstring> - </tp:docstring> - <annotation name="com.trolltech.QtDBus.QtTypeName.Out0" value="VectorString"/> - <arg type="as" name="list" direction="out"> - <tp:docstring> - </tp:docstring> - </arg> - </method> - - <method name="getOutputAudioPluginList" tp:name-for-bindings="getOutputAudioPluginList"> + <method name="getAudioPluginList" tp:name-for-bindings="getAudioPluginList"> <tp:docstring> </tp:docstring> <annotation name="com.trolltech.QtDBus.QtTypeName.Out0" value="VectorString"/> @@ -512,25 +513,35 @@ </arg> </method> - <method name="getAudioInputDeviceList" tp:name-for-bindings="getAudioInputDeviceList"> + <method name="setAudioInputDevice" tp:name-for-bindings="setAudioInputDevice"> <tp:docstring> </tp:docstring> - <annotation name="com.trolltech.QtDBus.QtTypeName.Out0" value="VectorString"/> - <arg type="as" name="list" direction="out"> + <arg type="i" name="index" direction="in"> <tp:docstring> </tp:docstring> </arg> </method> - <method name="setAudioInputDevice" tp:name-for-bindings="setAudioInputDevice"> - <tp:docstring> + <method name="setAudioRingtoneDevice" tp:name-for-binding="setAudioRingtoneDevice"> + <tp:docstring> </tp:docstring> <arg type="i" name="index" direction="in"> + <tp:docstring> + </tp:docstring> + </arg> + </method> + + <method name="getAudioInputDeviceList" tp:name-for-bindings="getAudioInputDeviceList"> + <tp:docstring> + </tp:docstring> + <annotation name="com.trolltech.QtDBus.QtTypeName.Out0" value="VectorString"/> + <arg type="as" name="list" direction="out"> <tp:docstring> </tp:docstring> </arg> </method> + <method name="getCurrentAudioDevicesIndex" tp:name-for-bindings="getCurrentAudioDevicesIndex"> <tp:docstring> </tp:docstring> @@ -732,6 +743,7 @@ <method name="getWindowWidth" tp:name-for-bindings="getWindowWidth"> <tp:docstring> + Unused </tp:docstring> <arg type="i" name="width" direction="out"> <tp:docstring> @@ -741,6 +753,7 @@ <method name="getWindowHeight" tp:name-for-bindings="getWindowHeight"> <tp:docstring> + Unused </tp:docstring> <arg type="i" name="height" direction="out"> <tp:docstring> @@ -750,6 +763,7 @@ <method name="setWindowWidth" tp:name-for-bindings="setWindowWidth"> <tp:docstring> + Unused </tp:docstring> <arg type="i" name="width" direction="in"> <tp:docstring> @@ -759,6 +773,7 @@ <method name="setWindowHeight" tp:name-for-bindings="setWindowHeight"> <tp:docstring> + Unused </tp:docstring> <arg type="i" name="height" direction="in"> <tp:docstring> @@ -768,6 +783,7 @@ <method name="getWindowPositionX" tp:name-for-bindings="getWindowPositionX"> <tp:docstring> + Unused </tp:docstring> <arg type="i" name="posX" direction="out"> <tp:docstring> @@ -777,6 +793,7 @@ <method name="setWindowPositionX" tp:name-for-bindings="setWindowPositionX"> <tp:docstring> + Unused </tp:docstring> <arg type="i" name="posX" direction="in"> <tp:docstring> @@ -786,6 +803,7 @@ <method name="getWindowPositionY" tp:name-for-bindings="getWindowPositionY"> <tp:docstring> + Unused </tp:docstring> <arg type="i" name="posY" direction="out"> <tp:docstring> @@ -795,28 +813,33 @@ <method name="setWindowPositionY" tp:name-for-bindings="setWindowPositionY"> <tp:docstring> + Unused </tp:docstring> <arg type="i" name="posY" direction="in"> - <tp:docstring> - </tp:docstring> + <tp:docstring> + </tp:docstring> </arg> </method> <method name="enableStatusIcon" tp:name-for-bindings="enableStatusIcon"> <tp:docstring> + Allow SFLphone icon to be displayed in system tray </tp:docstring> <arg type="s" name="value" direction="in"> - <tp:docstring> - </tp:docstring> + <tp:docstring> + true/false + </tp:docstring> </arg> </method> <method name="isStatusIconEnabled" tp:name-for-bindings="isStatusIconEnabled"> <tp:docstring> + Test if SFLphone icon is displayed in system tray. </tp:docstring> <arg type="s" name="value" direction="out"> - <tp:docstring> - </tp:docstring> + <tp:docstring> + true/false + </tp:docstring> </arg> </method> @@ -899,100 +922,144 @@ </tp:docstring> <annotation name="com.trolltech.QtDBus.QtTypeName.In0" value="MapStringString"/> <arg type="a{ss}" name="entries" direction="in"> - <tp:docstring> - </tp:docstring> + <tp:docstring> + </tp:docstring> </arg> </method> <signal name="accountsChanged" tp:name-for-bindings="accountsChanged"> + <tp:docstring> + Signal emited on account changes. Clients should update + all account status with <tp:member-ref>getAccountDetails</tp:member-ref> + iterating over the list provided by <tp:member-ref>getAccountList</tp:member-ref> + </tp:docstring> </signal> <signal name="errorAlert" tp:name-for-bindings="errorAlert"> <arg type="i" name="code"> - <tp:docstring> - </tp:docstring> + <tp:docstring> + </tp:docstring> </arg> </signal> <!-- TLS Methods --> <method name="getSupportedTlsMethod" tp:name-for-bindings="getSupportedTlsMethod"> <tp:docstring> + Provide a list of supported TLS method </tp:docstring> <annotation name="com.trolltech.QtDBus.QtTypeName.Out0" value="VectorString"/> <arg type="as" name="list" direction="out"> - <tp:docstring> - </tp:docstring> + <tp:docstring> + A list of TLS method: (TLSv1, SSLv1, SSLv2, + SSLv3, SSLv23) + </tp:docstring> </arg> </method> <method name="getTlsSettingsDefault" tp:name-for-bindings="getTlsSettingsDefault"> <annotation name="com.trolltech.QtDBus.QtTypeName.Out0" value="MapStringString"/> <tp:docstring> + Get default TLS setting for new accounts </tp:docstring> <arg type="a{ss}" name="details" direction="out"> - <tp:docstring> - </tp:docstring> + <tp:docstring> + A hash table containing details. Refer + to <tp:member-ref>getTlsSettings</tp:member-ref> + for possible keys + </tp:docstring> </arg> </method> <method name="getTlsSettings" tp:name-for-bindings="getTlsSettings"> <tp:docstring> + Get current TLS setting for a specific account </tp:docstring> <arg type="s" name="accountID" direction="in"> - <tp:docstring> - </tp:docstring> + <tp:docstring> + The account ID + </tp:docstring> </arg> <annotation name="com.trolltech.QtDBus.QtTypeName.Out0" value="MapStringString"/> <arg type="a{ss}" name="details" direction="out"> - <tp:docstring> - </tp:docstring> + <tp:docstring> + A hash table containing details with key: + <ul> + <li>"TLS.listenerPort": valid numerical port</li> + <li>"TLS.enable": true/false</li> + <li>"TLS.certificateListFile": A valid path to + a .pem file containing CA certificate</li> + <li>"TLS.certificateFile": A valid path to a + file containing the public end-point + certificate (optional)</li> + <li>"TLS.privateKeyFile": A valid path to a + file containing the public end-point private + key (optional)</li> + <li>"TLS.password": Public end-point private + key password (optional)</li> + <li>"TLS.method": (TLSv1, SSLv1, SSLv2, + SSLv3, SSLv23)</li> + </ul> + </tp:docstring> </arg> </method> <method name="setTlsSettings" tp:name-for-bindings="setTlsSettings"> <tp:docstring> + Update TLS setting for a specific account </tp:docstring> <annotation name="com.trolltech.QtDBus.QtTypeName.In1" value="MapStringString"/> <arg type="s" name="accountID" direction="in"> - <tp:docstring> - </tp:docstring> + <tp:docstring> + The account ID + </tp:docstring> </arg> <arg type="a{ss}" name="details" direction="in"> - <tp:docstring> - </tp:docstring> + <tp:docstring> + A hash table containing details. Refer + to <tp:member-ref>getTlsSettings</tp:member-ref> + for possible keys. + </tp:docstring> </arg> </method> <method name="getAddrFromInterfaceName" tp:name-for-bindings="getAddrFromInterfaceName"> <tp:docstring> + Resolve interface IPv4 address provided its name. </tp:docstring> <arg type="s" name="interface" direction="in"> - <tp:docstring> - </tp:docstring> + <tp:docstring> + Interface name + </tp:docstring> </arg> <arg type="s" name="address" direction="out"> - <tp:docstring> - </tp:docstring> + <tp:docstring> + Interface IPv4 address + </tp:docstring> </arg> </method> <method name="getAllIpInterface" tp:name-for-bindings="getAllIpInterface"> <tp:docstring> + Provide a list of IP interface's IPv4 address. </tp:docstring> <annotation name="com.trolltech.QtDBus.QtTypeName.Out0" value="VectorString"/> <arg type="as" name="list" direction="out"> - <tp:docstring> - </tp:docstring> + <tp:docstring> + A list of interface's IPv4 address + </tp:docstring> </arg> </method> <method name="getAllIpInterfaceByName" tp:name-for-bindings="getAllIpInterfaceByName"> <tp:docstring> + Provide a list of IP interface's name: default + (0.0.0.0), lo, eth0 ... </tp:docstring> <annotation name="com.trolltech.QtDBus.QtTypeName.Out0" value="VectorString"/> <arg type="as" name="list" direction="out"> - <tp:docstring> - </tp:docstring> + <tp:docstring> + A list of interface's name + </tp:docstring> </arg> </method> diff --git a/sflphone-client-gnome/src/dbus/dbus.c b/sflphone-client-gnome/src/dbus/dbus.c index b8c37a8fce6b2df850543205b96448f118c126ea..8e5cd1d18b0116dc581cc3d9ac90b1697cefaa38 100644 --- a/sflphone-client-gnome/src/dbus/dbus.c +++ b/sflphone-client-gnome/src/dbus/dbus.c @@ -1308,44 +1308,27 @@ dbus_set_active_codec_list(const gchar** list, const gchar *accountID) } } -/** - * Get a list of input supported audio plugins - */ -gchar** -dbus_get_input_audio_plugin_list() -{ - gchar** array; - GError* error = NULL; - org_sflphone_SFLphone_ConfigurationManager_get_input_audio_plugin_list( - configurationManagerProxy, &array, &error); - if (error) - { - ERROR("Failed to call get_input_audio_plugin_list() on ConfigurationManager: %s", error->message); - g_error_free(error); - } - return array; -} /** * Get a list of output supported audio plugins */ gchar** -dbus_get_output_audio_plugin_list() +dbus_get_audio_plugin_list() { gchar** array; GError* error = NULL; - if (!org_sflphone_SFLphone_ConfigurationManager_get_output_audio_plugin_list( + if (!org_sflphone_SFLphone_ConfigurationManager_get_audio_plugin_list( configurationManagerProxy, &array, &error)) { if (error->domain == DBUS_GERROR && error->code == DBUS_GERROR_REMOTE_EXCEPTION) { - ERROR ("Caught remote method (get_output_audio_plugin_list) exception %s: %s", dbus_g_error_get_name(error), error->message); + ERROR ("Caught remote method (get_output_plugin_list) exception %s: %s", dbus_g_error_get_name(error), error->message); } else { - ERROR("Error while calling get_out_audio_plugin_list: %s", error->message); + ERROR("Error while calling get_out_plugin_list: %s", error->message); } g_error_free(error); return NULL; @@ -1417,37 +1400,53 @@ dbus_set_audio_output_device(const int index) } /** - * Get all input devices index supported by current audio manager + * Set audio input device from its index */ -gchar** -dbus_get_audio_input_device_list() +void +dbus_set_audio_input_device(const int index) { - gchar** array; GError* error = NULL; - org_sflphone_SFLphone_ConfigurationManager_get_audio_input_device_list( - configurationManagerProxy, &array, &error); + org_sflphone_SFLphone_ConfigurationManager_set_audio_input_device( + configurationManagerProxy, index, &error); if (error) { - ERROR("Failed to call get_audio_input_device_list() on ConfigurationManager: %s", error->message); + ERROR("Failed to call set_audio_input_device() on ConfigurationManager: %s", error->message); g_error_free(error); } - return array; } /** - * Set audio input device from its index + * Set adio ringtone device from its index */ void -dbus_set_audio_input_device(const int index) +dbus_set_audio_ringtone_device(const int index) { GError* error = NULL; - org_sflphone_SFLphone_ConfigurationManager_set_audio_input_device( + org_sflphone_SFLphone_ConfigurationManager_set_audio_ringtone_device( configurationManagerProxy, index, &error); + if(error) + { + ERROR("Failed to call set_audio_ringtone_device() on ConfigurationManager: %s", error->message); + g_error_free(error); + } +} + +/** + * Get all input devices index supported by current audio manager + */ +gchar** +dbus_get_audio_input_device_list() +{ + gchar** array; + GError* error = NULL; + org_sflphone_SFLphone_ConfigurationManager_get_audio_input_device_list( + configurationManagerProxy, &array, &error); if (error) { - ERROR("Failed to call set_audio_input_device() on ConfigurationManager: %s", error->message); + ERROR("Failed to call get_audio_input_device_list() on ConfigurationManager: %s", error->message); g_error_free(error); } + return array; } /** diff --git a/sflphone-client-gnome/src/dbus/dbus.h b/sflphone-client-gnome/src/dbus/dbus.h index 53e4747cf975300324fe4d0135e2516bd80f6d5c..cf75d9ce98095092c525900676d5e20a1a05f606 100644 --- a/sflphone-client-gnome/src/dbus/dbus.h +++ b/sflphone-client-gnome/src/dbus/dbus.h @@ -251,17 +251,11 @@ void dbus_set_active_codec_list (const gchar** list, const gchar*); */ gchar* dbus_get_current_codec_name(const callable_obj_t * c); -/** - * ConfigurationManager - Get the list of available input audio plugins - * @return gchar** The list of plugins - */ -gchar** dbus_get_input_audio_plugin_list(); - /** * ConfigurationManager - Get the list of available output audio plugins * @return gchar** The list of plugins */ -gchar** dbus_get_output_audio_plugin_list(); +gchar** dbus_get_audio_plugin_list(); /** * ConfigurationManager - Select an input audio plugin diff --git a/sflphone-common/src/audio/alsa/alsalayer.cpp b/sflphone-common/src/audio/alsa/alsalayer.cpp index d20f3d09eafe2e3b3d469b7178657a579bf1cdbe..d5eea5aef0846869e9e64bef3325277e65d039f8 100644 --- a/sflphone-common/src/audio/alsa/alsalayer.cpp +++ b/sflphone-common/src/audio/alsa/alsalayer.cpp @@ -1,6 +1,7 @@ /* * Copyright (C) 2004, 2005, 2006, 2009, 2008, 2009, 2010 Savoir-Faire Linux Inc. * Author: Emmanuel Milou <emmanuel.milou@savoirfairelinux.com> + * Author: Alexandre Savard <alexandre.savard@savoirfairelinux.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -38,6 +39,7 @@ int framesPerBufferAlsa = 2048; AlsaLayer::AlsaLayer (ManagerImpl* manager) : AudioLayer (manager , ALSA) , _PlaybackHandle (NULL) + , _RingtoneHandle (NULL) , _CaptureHandle (NULL) , _periodSize() , _audioPlugin() @@ -97,60 +99,47 @@ AlsaLayer::closeLayer() /* Then close the audio devices */ closeCaptureStream(); - closePlaybackStream(); - _CaptureHandle = 0; - - _PlaybackHandle = 0; + _CaptureHandle = NULL; + _PlaybackHandle = NULL; + _RingtoneHandle = NULL; return true; } bool -AlsaLayer::openDevice (int indexIn, int indexOut, int sampleRate, int frameSize, int stream , std::string plugin) +AlsaLayer::openDevice (int indexIn, int indexOut, int indexRing, int sampleRate, int frameSize, int stream , std::string plugin) { /* Close the devices before open it */ if (stream == SFL_PCM_BOTH && is_capture_open() == true && is_playback_open() == true) { closeCaptureStream(); closePlaybackStream(); - } else if ( (stream == SFL_PCM_CAPTURE || stream == SFL_PCM_BOTH) && is_capture_open() == true) + } else if((stream == SFL_PCM_CAPTURE || stream == SFL_PCM_BOTH) && is_capture_open() == true) closeCaptureStream (); - else if ( (stream == SFL_PCM_PLAYBACK || stream == SFL_PCM_BOTH) && is_playback_open () == true) + else if((stream == SFL_PCM_PLAYBACK || stream == SFL_PCM_BOTH) && is_playback_open () == true) closePlaybackStream (); - _indexIn = indexIn; - _indexOut = indexOut; + _indexRing = indexRing; _audioSampleRate = sampleRate; - _frameSize = frameSize; _audioPlugin = std::string (plugin); - _debugAlsa (" Setting AlsaLayer: device in=%2d, out=%2d", _indexIn, _indexOut); - + _debugAlsa (" Setting AlsaLayer: device in=%2d, out=%2d, ring=%2d", _indexIn, _indexOut, _indexRing); _debugAlsa (" : alsa plugin=%s", _audioPlugin.c_str()); - _debugAlsa (" : nb channel in=%2d, out=%2d", _inChannel, _outChannel); - _debugAlsa (" : sample rate=%5d, format=%s", _audioSampleRate, SFLDataFormatString); _audioThread = NULL; - ost::MutexLock lock (_mutex); - - std::string pcmp = buildDeviceTopo (plugin, indexOut, 0); - - std::string pcmc = buildDeviceTopo (plugin, indexIn, 0); - // use 1 sec buffer for resampling _converter = new SamplerateConverter (_audioSampleRate, 1000); - // open_device (pcmp, pcmc, stream); - return true; // open_device (pcmp, pcmc, stream); + return true; } void @@ -158,20 +147,39 @@ AlsaLayer::startStream (void) { _debug ("AlsaLayer:: startStream"); - std::string pcmp = buildDeviceTopo (_audioPlugin, _indexOut, 0); - std::string pcmc = buildDeviceTopo (_audioPlugin, _indexIn, 0); + if(is_playback_running() && is_capture_running() ) + return; + + std::string pcmp; + std::string pcmr; + std::string pcmc; + + if(_audioPlugin == PCM_DMIX_DSNOOP) { + pcmp = buildDeviceTopo (PCM_DMIX, _indexOut, 0); + pcmr = buildDeviceTopo (PCM_DMIX, _indexRing, 0); + pcmc = buildDeviceTopo(PCM_DSNOOP, _indexIn, 0); + } + else { + pcmp = buildDeviceTopo (_audioPlugin, _indexOut, 0); + pcmr = buildDeviceTopo (_audioPlugin, _indexRing, 0); + pcmc = buildDeviceTopo(_audioPlugin, _indexIn, 0); + } + + _debug("pcmp: %s, index %d", pcmp.c_str(), _indexOut); + _debug("pcmr: %s, index %d", pcmr.c_str(), _indexRing); + _debug("pcmc: %s, index %d", pcmc.c_str(), _indexIn); if (!is_playback_open()) { - open_device (pcmp, pcmc, SFL_PCM_PLAYBACK); + open_device (pcmp, pcmc, pcmr, SFL_PCM_PLAYBACK); } if (!is_capture_open()) { - open_device (pcmp, pcmc, SFL_PCM_CAPTURE); + open_device (pcmp, pcmc, pcmr, SFL_PCM_CAPTURE); } prepareCaptureStream (); - preparePlaybackStream (); + startCaptureStream (); startPlaybackStream (); @@ -211,9 +219,12 @@ AlsaLayer::stopStream (void) } closeCaptureStream (); - closePlaybackStream (); + _PlaybackHandle = NULL; + _CaptureHandle = NULL; + _RingtoneHandle = NULL; + /* Flush the ring buffers */ flushUrgent (); flushMain (); @@ -299,11 +310,19 @@ void AlsaLayer::stopPlaybackStream (void) { int err; + if(_RingtoneHandle && is_playback_running()) { + _debug("Audio: Stop ALSA ringtone"); + + if( (err = snd_pcm_drop(_RingtoneHandle)) < 0) { + _debug("Audio: Error: Stop ALSA ringtone: %s", snd_strerror(err)); + } + } + if (_PlaybackHandle && is_playback_running()) { - _debug ("AlsaLayer:: stop ALSA playback"); + _debug ("Audio: Stop ALSA playback"); if ( (err = snd_pcm_drop (_PlaybackHandle)) < 0) - _debug ("Error stopping ALSA playback: %s", snd_strerror (err)); + _debug ("Audio: Error: Stopping ALSA playback: %s", snd_strerror (err)); else stop_playback (); } @@ -317,14 +336,22 @@ void AlsaLayer::closePlaybackStream (void) if (is_playback_prepared() == true && is_playback_running() == true) stopPlaybackStream (); + if (is_playback_open()) { - _debug ("AlsaLayer:: close ALSA playback"); + _debug("Audio: Close ALSA playback"); + + if(_RingtoneHandle) { + if((err = snd_pcm_close(_RingtoneHandle)) < 0) { + _warn("Audio: Error: Closing ALSA ringtone: %s", snd_strerror(err)); + } + } if ( (err = snd_pcm_close (_PlaybackHandle)) < 0) - _debug ("Error closing ALSA playback: %s", snd_strerror (err)); + _warn("Audio: Error: Closing ALSA playback: %s", snd_strerror (err)); else close_playback (); } + } void AlsaLayer::startPlaybackStream (void) @@ -508,46 +535,59 @@ bool AlsaLayer::alsa_set_params (snd_pcm_t *pcm_handle, int type, int rate) bool -AlsaLayer::open_device (std::string pcm_p, std::string pcm_c, int flag) +AlsaLayer::open_device (std::string pcm_p, std::string pcm_c, std::string pcm_r, int flag) { int err; if (flag == SFL_PCM_BOTH || flag == SFL_PCM_PLAYBACK) { - _debug ("AlsaLayer:: open playback device"); - // if((err = snd_pcm_open(&_PlaybackHandle, pcm_p.c_str(), SND_PCM_STREAM_PLAYBACK, 0 )) < 0){ + _debug ("Audio: Open playback device (and ringtone)"); - if ( (err = snd_pcm_open (&_PlaybackHandle, pcm_p.c_str(), SND_PCM_STREAM_PLAYBACK, 0)) < 0) { - _debugAlsa ("Error while opening playback device %s", pcm_p.c_str()); + if ((err = snd_pcm_open(&_PlaybackHandle, pcm_p.c_str(), SND_PCM_STREAM_PLAYBACK, 0)) < 0) { + _warn("Audio: Error while opening playback device %s", pcm_p.c_str()); setErrorMessage (ALSA_PLAYBACK_DEVICE); close_playback (); return false; } if (!alsa_set_params (_PlaybackHandle, 1, getSampleRate())) { - _debug ("playback failed"); + _warn ("Audio: Error: Playback failed"); snd_pcm_close (_PlaybackHandle); close_playback (); return false; } + if (getIndexOut() != getIndexRing()) { + + if((err = snd_pcm_open(&_RingtoneHandle, pcm_r.c_str(), SND_PCM_STREAM_PLAYBACK, 0)) < 0) { + _warn("Audio: Error: Opening ringtone device %s", pcm_r.c_str()); + // setErrorMessage(ALSA_RINGTONE_DEVICE); + } + + if(!alsa_set_params(_RingtoneHandle, 1, getSampleRate())) { + _warn("Audio: Error: Ringtone failed"); + snd_pcm_close(_RingtoneHandle); + + } + } + open_playback (); } if (flag == SFL_PCM_BOTH || flag == SFL_PCM_CAPTURE) { - _debug ("AlsaLayer:: open capture device"); + _debug ("Audio: Open capture device"); if ( (err = snd_pcm_open (&_CaptureHandle, pcm_c.c_str(), SND_PCM_STREAM_CAPTURE, 0)) < 0) { - _debugAlsa ("Error while opening capture device %s", pcm_c.c_str()); + _warn("Audio: Error: Opening capture device %s", pcm_c.c_str()); setErrorMessage (ALSA_CAPTURE_DEVICE); close_capture (); return false; } if (!alsa_set_params (_CaptureHandle, 0, 8000)) { - _debug ("capture failed"); + _warn("Audio: Error: Capture failed"); snd_pcm_close (_CaptureHandle); close_capture (); return false; @@ -558,32 +598,25 @@ AlsaLayer::open_device (std::string pcm_p, std::string pcm_c, int flag) // prepare_capture (); } - /* Start the secondary audio thread for callbacks */ - /* - try { - _audioThread->start(); - } catch (...) { - _debugException ("Fail to start audio thread"); - } - */ + return true; } //TODO first frame causes broken pipe (underrun) because not enough data are send --> make the handle wait to be ready int -AlsaLayer::write (void* buffer, int length) +AlsaLayer::write (void* buffer, int length, snd_pcm_t * handle) { if (_trigger_request == true) { _trigger_request = false; startPlaybackStream (); } - snd_pcm_uframes_t frames = snd_pcm_bytes_to_frames (_PlaybackHandle, length); + snd_pcm_uframes_t frames = snd_pcm_bytes_to_frames (handle, length); int err; - if ( (err=snd_pcm_writei (_PlaybackHandle , buffer , frames)) <0) { + if ( (err=snd_pcm_writei (handle, buffer , frames)) <0) { switch (err) { case -EPIPE: @@ -592,17 +625,17 @@ AlsaLayer::write (void* buffer, int length) case -EIO: //_debugAlsa(" XRUN playback ignored (%s)", snd_strerror(err)); - handle_xrun_playback(); + handle_xrun_playback(handle); - if (snd_pcm_writei (_PlaybackHandle , buffer , frames) <0) - _debugAlsa ("XRUN handling failed"); + if (snd_pcm_writei (handle, buffer , frames) <0) + _debugAlsa ("Audio: XRUN handling failed"); _trigger_request = true; break; default: - _debugAlsa ("Write error unknown - dropping frames **********************************: %s", snd_strerror (err)); + _debugAlsa ("Audio: Write error unknown - dropping frames: %s", snd_strerror (err)); stopPlaybackStream (); @@ -635,14 +668,14 @@ AlsaLayer::read (void* buffer, int toCopy) case -ESTRPIPE: case -EIO: - _debugAlsa (" XRUN capture ignored (%s)", snd_strerror (samples)); + _debugAlsa ("Audio: XRUN capture ignored (%s)", snd_strerror (samples)); handle_xrun_capture(); //samples = snd_pcm_readi( _CaptureHandle, buffer, frames); //if (samples<0) samples=0; break; case EPERM: - _debugAlsa (" Capture EPERM (%s)", snd_strerror (samples)); + _debugAlsa ("Audio: Capture EPERM (%s)", snd_strerror (samples)); prepareCaptureStream (); startCaptureStream (); break; @@ -662,7 +695,7 @@ AlsaLayer::read (void* buffer, int toCopy) void AlsaLayer::handle_xrun_capture (void) { - _debugAlsa ("handle_xrun_capture"); + _debugAlsa ("Audio: Handle xrun capture"); snd_pcm_status_t* status; snd_pcm_status_alloca (&status); @@ -676,23 +709,25 @@ AlsaLayer::handle_xrun_capture (void) startCaptureStream (); } } else - _debugAlsa (" Get status failed"); + _debugAlsa ("Audio: Get status failed"); } void -AlsaLayer::handle_xrun_playback (void) +AlsaLayer::handle_xrun_playback (snd_pcm_t *handle) { - _debugAlsa ("AlsaLayer:: handle_xrun_playback"); + _debugAlsa ("Audio: Handle xrun playback"); int state; snd_pcm_status_t* status; snd_pcm_status_alloca (&status); - if ( (state = snd_pcm_status (_PlaybackHandle, status)) < 0) _debugAlsa (" Error: Cannot get playback handle status (%s)" , snd_strerror (state)); + if ( (state = snd_pcm_status (handle, status)) < 0) + _debugAlsa ("Audio: Error: Cannot get playback handle status (%s)" , snd_strerror (state)); else { state = snd_pcm_status_get_state (status); if (state == SND_PCM_STATE_XRUN) { + _debug("Audio: audio device in state SND_PCM_STATE_XRUN, restart device"); stopPlaybackStream (); preparePlaybackStream (); @@ -705,10 +740,10 @@ AlsaLayer::handle_xrun_playback (void) std::string AlsaLayer::buildDeviceTopo (std::string plugin, int card, int subdevice) { - std::string pcm = plugin; std::stringstream ss,ss1; + std::string pcm = plugin; - if (pcm == "default" || pcm == "pulse") + if (pcm == PCM_DEFAULT) return pcm; ss << card; @@ -723,6 +758,8 @@ AlsaLayer::buildDeviceTopo (std::string plugin, int card, int subdevice) pcm.append (ss1.str()); } + _debug("Audio: Device topo: %s", pcm.c_str()); + return pcm; } @@ -732,6 +769,8 @@ AlsaLayer::getSoundCardsInfo (int stream) std::vector<std::string> cards_id; HwIDPair p; + _debug("Audio: Get sound cards info: "); + snd_ctl_t* handle; snd_ctl_card_info_t *info; snd_pcm_info_t* pcminfo; @@ -768,6 +807,7 @@ AlsaLayer::getSoundCardsInfo (int stream) // The number of the sound card is associated with a string description p = HwIDPair (numCard , description); IDSoundCards.push_back (p); + } } @@ -835,24 +875,32 @@ void AlsaLayer::audioCallback (void) spkrVolume = _manager->getSpkrVolume(); micVolume = _manager->getMicVolume(); - /* - int writeableSize = snd_pcm_avail_update(_PlaybackHandle); - _debug("writeableSize %i", writeableSize); - */ + tone = _manager->getTelephoneTone(); + file_tone = _manager->getTelephoneFile(); // AvailForGet tell the number of chars inside the buffer // framePerBuffer are the number of data for one channel (left) urgentAvailBytes = _urgentRingBuffer.AvailForGet(); + // toGet = framesPerBufferAlsa; + // maxBytes = toGet * sizeof (SFLDataFormat); + + if(!_PlaybackHandle) + return; + + int playbackAvailSmpl = snd_pcm_avail_update(_PlaybackHandle); + int playbackAvailBytes = playbackAvailSmpl*sizeof(SFLDataFormat); + // _debug("PLAYBACK: %d", playbackAvailSmpl); + if (urgentAvailBytes > 0) { // Urgent data (dtmf, incoming call signal) come first. - toGet = (urgentAvailBytes < (int) (framesPerBufferAlsa * sizeof (SFLDataFormat))) ? urgentAvailBytes : framesPerBufferAlsa * sizeof (SFLDataFormat); - out = (SFLDataFormat*) malloc (toGet * sizeof (SFLDataFormat)); + toGet = (urgentAvailBytes < (int) (playbackAvailBytes)) ? urgentAvailBytes : playbackAvailBytes; + out = (SFLDataFormat*) malloc (toGet); _urgentRingBuffer.Get (out, toGet, spkrVolume); /* Play the sound */ - write (out, toGet); + write (out, toGet, _PlaybackHandle); free (out); out=0; @@ -862,55 +910,44 @@ void AlsaLayer::audioCallback (void) } else { - tone = _manager->getTelephoneTone(); - file_tone = _manager->getTelephoneFile(); + if (tone) { - toGet = framesPerBufferAlsa; - maxBytes = toGet * sizeof (SFLDataFormat); - - if (tone != 0) { - - out = (SFLDataFormat*) malloc (maxBytes * sizeof (SFLDataFormat)); - tone->getNext (out, toGet, spkrVolume); - write (out , maxBytes); + out = (SFLDataFormat *) malloc (playbackAvailBytes); + tone->getNext (out, playbackAvailSmpl, spkrVolume); + write (out , playbackAvailBytes, _PlaybackHandle); free (out); out = 0; + + } + else if (file_tone && !_RingtoneHandle) { - } else if (file_tone != 0) { + out = (SFLDataFormat *) malloc (playbackAvailBytes); + file_tone->getNext (out, playbackAvailSmpl, spkrVolume); + write (out, playbackAvailBytes, _PlaybackHandle); - out = (SFLDataFormat*) malloc (maxBytes * sizeof (SFLDataFormat)); - file_tone->getNext (out, toGet, spkrVolume); - write (out , maxBytes); - - free (out); - out = 0; + free (out); + out = NULL; - } else { + } else { // If nothing urgent, play the regular sound samples int _mainBufferSampleRate = getMainBuffer()->getInternalSamplingRate(); - int maxNbSamplesToGet = 0; - int maxNbBytesToGet = 0; + int maxNbSamplesToGet = playbackAvailSmpl; + int maxNbBytesToGet = playbackAvailBytes; // Compute maximal value to get into the ring buffer if (_mainBufferSampleRate && ( (int) _audioSampleRate != _mainBufferSampleRate)) { double upsampleFactor = (double) _audioSampleRate / _mainBufferSampleRate; + maxNbSamplesToGet = (int) ( (double) playbackAvailSmpl / upsampleFactor); + maxNbBytesToGet = maxNbSamplesToGet * sizeof (SFLDataFormat); - maxNbSamplesToGet = (int) ( (double) framesPerBufferAlsa / upsampleFactor); - - - } else { + } - maxNbSamplesToGet = framesPerBufferAlsa; - - } - - maxNbBytesToGet = maxNbSamplesToGet * sizeof (SFLDataFormat); normalAvailBytes = getMainBuffer()->availForGet(); toGet = (normalAvailBytes < (int) maxNbBytesToGet) ? normalAvailBytes : maxNbBytesToGet; @@ -924,7 +961,7 @@ void AlsaLayer::audioCallback (void) if (_mainBufferSampleRate && ( (int) _audioSampleRate != _mainBufferSampleRate)) { - rsmpl_out = (SFLDataFormat*) malloc (framesPerBufferAlsa * sizeof (SFLDataFormat)); + rsmpl_out = (SFLDataFormat*) malloc (playbackAvailBytes*2); // Do sample rate conversion int nb_sample_down = toGet / sizeof (SFLDataFormat); @@ -933,25 +970,25 @@ void AlsaLayer::audioCallback (void) - write (rsmpl_out, nbSample*sizeof (SFLDataFormat)); + write (rsmpl_out, nbSample*sizeof (SFLDataFormat), _PlaybackHandle); free (rsmpl_out); rsmpl_out = 0; } else { - write (out, toGet); + write (out, toGet, _PlaybackHandle); } } else { - if ( (tone == 0) && (file_tone == 0)) { + if (!tone && !file_tone) { - SFLDataFormat* zeros = (SFLDataFormat*) malloc (framesPerBufferAlsa * sizeof (SFLDataFormat)); + SFLDataFormat *zeros = (SFLDataFormat*)malloc(playbackAvailBytes); - bzero (zeros, framesPerBufferAlsa * sizeof (SFLDataFormat)); - write (zeros, framesPerBufferAlsa * sizeof (SFLDataFormat)); + bzero (zeros, playbackAvailBytes); + write (zeros, playbackAvailBytes, _PlaybackHandle); free (zeros); } @@ -966,16 +1003,40 @@ void AlsaLayer::audioCallback (void) } + if (file_tone && _RingtoneHandle) { + + int ringtoneAvailSmpl = snd_pcm_avail_update(_RingtoneHandle); + int ringtoneAvailBytes = ringtoneAvailSmpl*sizeof(SFLDataFormat); + + // _debug("RINGTONE: %d", ringtoneAvailSmpl); + + out = (SFLDataFormat *) malloc(ringtoneAvailBytes); + file_tone->getNext (out, ringtoneAvailSmpl, spkrVolume); + write (out, ringtoneAvailBytes, _RingtoneHandle); + + free (out); + out = NULL; + + } else if (_RingtoneHandle) { + + int ringtoneAvailSmpl = snd_pcm_avail_update(_RingtoneHandle); + int ringtoneAvailBytes = ringtoneAvailSmpl*sizeof(SFLDataFormat); + + out = (SFLDataFormat *) malloc(ringtoneAvailBytes); + memset(out, 0, ringtoneAvailBytes); + write(out, ringtoneAvailBytes, _RingtoneHandle); + + free(out); + out = NULL; + } + // Additionally handle the mic's audio stream int micAvailBytes; - int micAvailPut; - int toPut; SFLDataFormat* in; - // snd_pcm_sframes_t micAvailAlsa; in = 0; diff --git a/sflphone-common/src/audio/alsa/alsalayer.h b/sflphone-common/src/audio/alsa/alsalayer.h index f2736a800a141558df2403f5af13e2a1f3f76f36..0346e6b98adb46813ca3e98794e9816b784a1086 100644 --- a/sflphone-common/src/audio/alsa/alsalayer.h +++ b/sflphone-common/src/audio/alsa/alsalayer.h @@ -1,6 +1,7 @@ /* * Copyright (C) 2004, 2005, 2006, 2009, 2008, 2009, 2010 Savoir-Faire Linux Inc. * Author: Emmanuel Milou <emmanuel.milou@savoirfairelinux.com> + * Author: Alexandre Savard <alexandre.savard@savoirfairelinux.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -76,7 +77,7 @@ class AlsaLayer : public AudioLayer { * SFL_PCM_BOTH * @param plugin The alsa plugin ( dmix , default , front , surround , ...) */ - bool openDevice(int indexIn, int indexOut, int sampleRate, int frameSize, int stream, std::string plugin); + bool openDevice(int indexIn, int indexOut, int indexRing, int sampleRate, int frameSize, int stream, std::string plugin); /** * Start the capture stream and prepare the playback stream. @@ -205,7 +206,7 @@ class AlsaLayer : public AudioLayer { * @return true if successful * false otherwise */ - bool open_device( std::string pcm_p, std::string pcm_c, int flag); + bool open_device( std::string pcm_p, std::string pcm_c, std::string pcm_r, int flag); bool alsa_set_params( snd_pcm_t *pcm_handle, int type, int rate ); @@ -216,7 +217,7 @@ class AlsaLayer : public AudioLayer { * @param length The size of the buffer * @return int The number of frames actually copied */ - int write( void* buffer, int length); + int write( void* buffer, int length, snd_pcm_t *handle); /** * Read data from the internal ring buffer @@ -226,8 +227,6 @@ class AlsaLayer : public AudioLayer { * @return int The number of frames actually read */ int read( void* buffer, int toCopy); - - /** * Recover from XRUN state for capture @@ -239,16 +238,22 @@ class AlsaLayer : public AudioLayer { * Recover from XRUN state for playback * ALSA Library API */ - void handle_xrun_playback( void ); - + void handle_xrun_playback( snd_pcm_t *handle ); + void* adjustVolume( void* buffer , int len, int stream ); -/** + /** * Handles to manipulate playback stream * ALSA Library API */ snd_pcm_t* _PlaybackHandle; + /** + * Handles to manipulate ringtone stream + * + */ + snd_pcm_t *_RingtoneHandle; + /** * Handles to manipulate capture stream * ALSA Library API @@ -268,7 +273,7 @@ class AlsaLayer : public AudioLayer { /** Vector to manage all soundcard index - description association of the system */ std::vector<HwIDPair> IDSoundCards; - bool _is_prepared_playback; + bool _is_prepared_playback; bool _is_prepared_capture; bool _is_running_playback; bool _is_running_capture; diff --git a/sflphone-common/src/audio/audiolayer.h b/sflphone-common/src/audio/audiolayer.h index 336e29f078ff2954161a81ed4f0d1937c5a31ebf..821e1ccde36d2d5e271bfe8df505b7c7975d783a 100644 --- a/sflphone-common/src/audio/audiolayer.h +++ b/sflphone-common/src/audio/audiolayer.h @@ -49,11 +49,9 @@ * @brief Main sound class. Manages the data transfers between the application and the hardware. */ - class Recordable; class ManagerImpl; - class AudioLayer { private: @@ -106,7 +104,7 @@ class AudioLayer { * SFL_PCM_BOTH * @param plugin The alsa plugin ( dmix , default , front , surround , ...) */ - virtual bool openDevice(int indexIn, int indexOut, int sampleRate, int frameSize, int stream , std::string plugin) = 0; + virtual bool openDevice(int indexIn, int indexOut, int indexRing, int sampleRate, int frameSize, int stream , std::string plugin) = 0; /** * Start the capture stream and prepare the playback stream. @@ -174,6 +172,13 @@ class AudioLayer { */ int getIndexOut() { return _indexOut; } + /** + * Get the index of the audio card for ringtone (could be differnet from playback) + * @return int The index of the card used for ringtone + * 0 for the first available card on the system, 1 ... + */ + int getIndexRing() {return _indexRing; } + /** * Get the sample rate of the audio layer * @return unsigned int The sample rate @@ -278,6 +283,11 @@ class AudioLayer { */ int _indexOut; + /** + * Number of audio cards on which ringtone stream has been opened + */ + int _indexRing; + /** * Sample Rate SFLphone should send sound data to the sound card * The value can be set in the user config file- now: 44100HZ diff --git a/sflphone-common/src/audio/pulseaudio/audiostream.cpp b/sflphone-common/src/audio/pulseaudio/audiostream.cpp index 8a246e5b38a46be146741ab3efa9b8182dc47c28..0b59c2e968ef5eb70a4d574fed00d6ac61af04e9 100644 --- a/sflphone-common/src/audio/pulseaudio/audiostream.cpp +++ b/sflphone-common/src/audio/pulseaudio/audiostream.cpp @@ -237,7 +237,7 @@ AudioStream::createStream (pa_context* c, std::string *deviceName) attributes->minreq = (uint32_t) -1; pa_threaded_mainloop_lock(_mainloop); - pa_stream_connect_playback(s, NULL, attributes, (pa_stream_flags_t) (PA_STREAM_NOFLAGS), NULL, NULL); + pa_stream_connect_playback(s, NULL, attributes, (pa_stream_flags_t) (PA_STREAM_ADJUST_LATENCY|PA_STREAM_AUTO_TIMING_UPDATE), NULL, NULL); pa_threaded_mainloop_unlock(_mainloop); } else if (_streamType == UPLOAD_STREAM) { diff --git a/sflphone-common/src/audio/pulseaudio/pulselayer.cpp b/sflphone-common/src/audio/pulseaudio/pulselayer.cpp index f3decdac51166b2481bbfc264f2f5c18e1cfc892..c6ecae78ad178d3354b063b46365b5d8750aee9b 100644 --- a/sflphone-common/src/audio/pulseaudio/pulselayer.cpp +++ b/sflphone-common/src/audio/pulseaudio/pulselayer.cpp @@ -262,42 +262,15 @@ PulseLayer::~PulseLayer (void) void PulseLayer::openLayer (void) { - if (!is_started) { + if (!is_started) { - _info("Audio: Open layer"); + _info("Audio: Open layer"); - if (!m) { + connectPulseAudioServer(); - _info("Audio: Creating PulseAudio mainloop"); - if (!(m = pa_threaded_mainloop_new())) - _warn ("Audio: Error: while creating pulseaudio mainloop"); + is_started = true; - if (pa_threaded_mainloop_start (m) < 0) { - _warn("Audio: Error: Failed to start pulseaudio mainloop"); - } - - assert(m); - } - - if (!context) { - - _info("Audio: Creating new PulseAudio Context"); - pa_threaded_mainloop_lock (m); - - // Instanciate a context - if (! (context = pa_context_new (pa_threaded_mainloop_get_api (m) , "SFLphone"))) - _warn ("Audio: Error: while creating pulseaudio context"); - - pa_threaded_mainloop_unlock (m); - - assert (context); - } - - // Create Streams - connectPulseAudioServer(); - - is_started = true; - } + } } @@ -336,12 +309,39 @@ PulseLayer::connectPulseAudioServer (void) pa_context_flags_t flag = PA_CONTEXT_NOAUTOSPAWN ; - pa_threaded_mainloop_lock (m); + if (!m) { + + // Instantiate a mainloop + _info("Audio: Creating PulseAudio mainloop"); + if (!(m = pa_threaded_mainloop_new())) + _warn ("Audio: Error: while creating pulseaudio mainloop"); + + assert(m); + } - _info("Audio: Connect the context to the server"); - pa_context_connect (context, NULL , flag , NULL); + if(!context) { + + // Instantiate a context + if (! (context = pa_context_new (pa_threaded_mainloop_get_api (m) , "SFLphone"))) + _warn ("Audio: Error: while creating pulseaudio context"); + + assert(context); + } + // set context state callback before starting the mainloop pa_context_set_state_callback (context, context_state_callback, this); + + _info("Audio: Connect the context to the server"); + if (pa_context_connect (context, NULL , flag , NULL) < 0) { + _warn("Audio: Error: Could not connect context to the server"); + } + + // Lock the loop before starting it + pa_threaded_mainloop_lock (m); + + if (pa_threaded_mainloop_start (m) < 0) + _warn("Audio: Error: Failed to start pulseaudio mainloop"); + pa_threaded_mainloop_wait(m); @@ -395,7 +395,7 @@ void PulseLayer::context_state_callback (pa_context* c, void* user_data) } } -bool PulseLayer::openDevice (int indexIn UNUSED, int indexOut UNUSED, int sampleRate, int frameSize , int stream UNUSED, std::string plugin UNUSED) +bool PulseLayer::openDevice (int indexIn UNUSED, int indexOut UNUSED, int indexRing UNUSED, int sampleRate, int frameSize , int stream UNUSED, std::string plugin UNUSED) { _audioSampleRate = sampleRate; _frameSize = frameSize; @@ -743,7 +743,6 @@ void PulseLayer::writeToSpeaker (void) } else { AudioLoop* tone = _manager->getTelephoneTone(); - AudioLoop* file_tone = _manager->getTelephoneFile(); // flush remaining samples in _urgentRingBuffer flushUrgent(); @@ -760,22 +759,6 @@ void PulseLayer::writeToSpeaker (void) pa_xfree (out); } - //} - - // else if (file_tone != 0) { - - /* - if (playback->getStreamState() == PA_STREAM_READY) { - - out = (SFLDataFormat*) pa_xmalloc (writeableSize); - int copied = file_tone->getNext (out, writeableSize / sizeof (SFLDataFormat), 100); - - pa_stream_write (playback->pulseStream(), out, copied * sizeof (SFLDataFormat), NULL, 0, PA_SEEK_RELATIVE); - - pa_xfree (out); - - } - */ } else { @@ -842,7 +825,7 @@ void PulseLayer::writeToSpeaker (void) } else { - if ( (tone == 0) && (file_tone == 0)) { + if (tone == 0) { SFLDataFormat* zeros = (SFLDataFormat*) pa_xmalloc (writeableSize); @@ -927,27 +910,29 @@ void PulseLayer::ringtoneToSpeaker(void) int writableSize = pa_stream_writable_size(ringtone->pulseStream()); - // _debug("writable size: %d", writableSize); + _debug("writable size: %d", writableSize); if (file_tone) { if(ringtone->getStreamState() == PA_STREAM_READY) { - out = (SFLDataFormat*)pa_xmalloc(writableSize); + out = (SFLDataFormat *)pa_xmalloc(writableSize); int copied = file_tone->getNext(out, writableSize/sizeof(SFLDataFormat), 100); pa_stream_write(ringtone->pulseStream(), out, copied*sizeof(SFLDataFormat), NULL, 0, PA_SEEK_RELATIVE); pa_xfree(out); - } } else { - out = (SFLDataFormat*)pa_xmalloc(writableSize); - memset(out, 0, writableSize); - pa_stream_write(ringtone->pulseStream(), out, writableSize, NULL, 0, PA_SEEK_RELATIVE); + if(ringtone->getStreamState() == PA_STREAM_READY) { + + out = (SFLDataFormat*)pa_xmalloc(writableSize); + memset(out, 0, writableSize); + pa_stream_write(ringtone->pulseStream(), out, writableSize, NULL, 0, PA_SEEK_RELATIVE); - pa_xfree(out); + pa_xfree(out); + } } diff --git a/sflphone-common/src/audio/pulseaudio/pulselayer.h b/sflphone-common/src/audio/pulseaudio/pulselayer.h index fd92103879cff11f1d12c4f24b901e3d9babe2a5..59ee2284d486c364ecfb3d363f5ea618214231da 100644 --- a/sflphone-common/src/audio/pulseaudio/pulselayer.h +++ b/sflphone-common/src/audio/pulseaudio/pulselayer.h @@ -76,7 +76,7 @@ class PulseLayer : public AudioLayer { * SFL_PCM_BOTH * @param plugin The alsa plugin ( dmix , default , front , surround , ...) */ - bool openDevice(int indexIn, int indexOut, int sampleRate, int frameSize , int stream, std::string plugin) ; + bool openDevice(int indexIn, int indexOut, int indexRing, int sampleRate, int frameSize , int stream, std::string plugin) ; DeviceList* getSinkList(void) { return &_sinkList; } diff --git a/sflphone-common/src/dbus/configurationmanager-introspec.xml b/sflphone-common/src/dbus/configurationmanager-introspec.xml index 9c0b6f1c4fb35ef45d58924dc885ae0ca9acbf48..8a0c59c8b2b1aa69d46519915f26228a9d27584b 100644 --- a/sflphone-common/src/dbus/configurationmanager-introspec.xml +++ b/sflphone-common/src/dbus/configurationmanager-introspec.xml @@ -466,17 +466,7 @@ <!-- Audio devices methods --> - <method name="getInputAudioPluginList" tp:name-for-bindings="getInputAudioPluginList"> - <tp:docstring> - </tp:docstring> - <annotation name="com.trolltech.QtDBus.QtTypeName.Out0" value="VectorString"/> - <arg type="as" name="list" direction="out"> - <tp:docstring> - </tp:docstring> - </arg> - </method> - - <method name="getOutputAudioPluginList" tp:name-for-bindings="getOutputAudioPluginList"> + <method name="getAudioPluginList" tp:name-for-bindings="getAudioPluginList"> <tp:docstring> </tp:docstring> <annotation name="com.trolltech.QtDBus.QtTypeName.Out0" value="VectorString"/> @@ -523,25 +513,35 @@ </arg> </method> - <method name="getAudioInputDeviceList" tp:name-for-bindings="getAudioInputDeviceList"> + <method name="setAudioInputDevice" tp:name-for-bindings="setAudioInputDevice"> <tp:docstring> </tp:docstring> - <annotation name="com.trolltech.QtDBus.QtTypeName.Out0" value="VectorString"/> - <arg type="as" name="list" direction="out"> + <arg type="i" name="index" direction="in"> <tp:docstring> </tp:docstring> </arg> </method> - <method name="setAudioInputDevice" tp:name-for-bindings="setAudioInputDevice"> - <tp:docstring> + <method name="setAudioRingtoneDevice" tp:name-for-binding="setAudioRingtoneDevice"> + <tp:docstring> </tp:docstring> <arg type="i" name="index" direction="in"> + <tp:docstring> + </tp:docstring> + </arg> + </method> + + <method name="getAudioInputDeviceList" tp:name-for-bindings="getAudioInputDeviceList"> + <tp:docstring> + </tp:docstring> + <annotation name="com.trolltech.QtDBus.QtTypeName.Out0" value="VectorString"/> + <arg type="as" name="list" direction="out"> <tp:docstring> </tp:docstring> </arg> </method> + <method name="getCurrentAudioDevicesIndex" tp:name-for-bindings="getCurrentAudioDevicesIndex"> <tp:docstring> </tp:docstring> diff --git a/sflphone-common/src/dbus/configurationmanager.cpp b/sflphone-common/src/dbus/configurationmanager.cpp index 798bdaf58c204cee82011f22c7049c981333df24..b928dd36554fbd15000f639d1b3a93364716c58f 100644 --- a/sflphone-common/src/dbus/configurationmanager.cpp +++ b/sflphone-common/src/dbus/configurationmanager.cpp @@ -516,28 +516,13 @@ void ConfigurationManager::setActiveCodecList( } -// Audio devices related methods -std::vector<std::string> ConfigurationManager::getInputAudioPluginList() { - - _debug("ConfigurationManager: Active codec list received"); - - std::vector<std::string> v; - - v.push_back("default"); - v.push_back("surround40"); - v.push_back("plug:hw"); - - return v; -} - - - -std::vector<std::string> ConfigurationManager::getOutputAudioPluginList() { +std::vector<std::string> ConfigurationManager::getAudioPluginList() { std::vector<std::string> v; v.push_back(PCM_DEFAULT); - v.push_back(PCM_DMIX); + // v.push_back(PCM_DMIX); + v.push_back(PCM_DMIX_DSNOOP); return v; } @@ -555,16 +540,20 @@ std::vector<std::string> ConfigurationManager::getAudioOutputDeviceList() { return Manager::instance().getAudioOutputDeviceList(); } -void ConfigurationManager::setAudioOutputDevice(const int32_t& index) { - return Manager::instance().setAudioOutputDevice(index); -} - std::vector<std::string> ConfigurationManager::getAudioInputDeviceList() { return Manager::instance().getAudioInputDeviceList(); } +void ConfigurationManager::setAudioOutputDevice(const int32_t& index) { + return Manager::instance().setAudioDevice(index, SFL_PCM_PLAYBACK); +} + void ConfigurationManager::setAudioInputDevice(const int32_t& index) { - return Manager::instance().setAudioInputDevice(index); + return Manager::instance().setAudioDevice(index, SFL_PCM_CAPTURE); +} + +void ConfigurationManager::setAudioRingtoneDevice(const int32_t& index) { + return Manager::instance().setAudioDevice(index, SFL_PCM_RINGTONE); } std::vector<std::string> ConfigurationManager::getCurrentAudioDevicesIndex() { diff --git a/sflphone-common/src/dbus/configurationmanager.h b/sflphone-common/src/dbus/configurationmanager.h index c21a2f85b8149c458043d1c215e530ffa975017e..cf711cf907c06e13daf27adc75e2429871b8c5c6 100644 --- a/sflphone-common/src/dbus/configurationmanager.h +++ b/sflphone-common/src/dbus/configurationmanager.h @@ -75,14 +75,14 @@ public: std::vector< std::string > getActiveCodecList (const std::string& accountID); void setActiveCodecList (const std::vector< std::string >& list, const std::string& accountID); - std::vector< std::string > getInputAudioPluginList(); - std::vector< std::string > getOutputAudioPluginList(); + std::vector< std::string > getAudioPluginList(); void setInputAudioPlugin(const std::string& audioPlugin); void setOutputAudioPlugin(const std::string& audioPlugin); std::vector< std::string > getAudioOutputDeviceList(); void setAudioOutputDevice(const int32_t& index); - std::vector< std::string > getAudioInputDeviceList(); void setAudioInputDevice(const int32_t& index); + void setAudioRingtoneDevice(const int32_t& index); + std::vector< std::string > getAudioInputDeviceList(); std::vector< std::string > getCurrentAudioDevicesIndex(); int32_t getAudioDeviceIndex(const std::string& name); std::string getCurrentAudioOutputPlugin( void ); diff --git a/sflphone-common/src/eventthread.cpp b/sflphone-common/src/eventthread.cpp index 93bca48010e8bbc022e74b81f4fca8acc3423fe5..cc16b5e77f45e448e13455b5ed99853c9b17fcda 100644 --- a/sflphone-common/src/eventthread.cpp +++ b/sflphone-common/src/eventthread.cpp @@ -65,7 +65,7 @@ void AudioThread::run (void) { while (!testCancel()) { _alsa->audioCallback(); - Thread::sleep (3); + Thread::sleep (20); } } diff --git a/sflphone-common/src/global.h b/sflphone-common/src/global.h index 3ed01299249a17df11fc469a886af17e12780893..552616d7851be88197c105e84c062d3c0b2710fc 100644 --- a/sflphone-common/src/global.h +++ b/sflphone-common/src/global.h @@ -97,6 +97,8 @@ static const SOUND_FORMAT INT32 = 0x8; #define PCM_PLUGHW "plughw" /** Alsa plugin */ #define PCM_DEFAULT "default" /** Default ALSA plugin */ #define PCM_DMIX "plug:dmix" /** Alsa plugin for software mixing */ +#define PCM_DSNOOP "plug:dsnoop" /** Alsa plugin for microphone sharing */ +#define PCM_DMIX_DSNOOP "dmix/dsnoop" /** Audio profile using Alsa dmix/dsnoop */ #define SFL_CODEC_VALID_PREFIX "libcodec_" /** Valid prefix for codecs shared library */ #define SFL_CODEC_VALID_EXTEN ".so" /** Valid extension for codecs shared library */ @@ -106,6 +108,7 @@ static const SOUND_FORMAT INT32 = 0x8; #define SFL_PCM_BOTH 0x0021 /** To open both playback and capture devices */ #define SFL_PCM_PLAYBACK 0x0022 /** To open playback device only */ #define SFL_PCM_CAPTURE 0x0023 /** To open capture device only */ +#define SFL_PCM_RINGTONE 0x0024 #ifdef USE_IAX #define IAX2_ENABLED true /** IAX2 support */ diff --git a/sflphone-common/src/managerimpl.cpp b/sflphone-common/src/managerimpl.cpp index c6057e93ec5f0d4c972aa9c5dec0b4134cf91348..34a8e7494c33a87aabb09e3529803fe687827e84 100644 --- a/sflphone-common/src/managerimpl.cpp +++ b/sflphone-common/src/managerimpl.cpp @@ -2112,6 +2112,8 @@ void ManagerImpl::initConfigFile (bool load_user_value, std::string alternate) { ALSA_CARD_ID_IN, ALSA_DFT_CARD), AUDIO); _config.addDefaultValue(std::pair<std::string, std::string>( ALSA_CARD_ID_OUT, ALSA_DFT_CARD), AUDIO); + _config.addDefaultValue(std::pair<std::string, std::string>( + ALSA_CARD_ID_RING, ALSA_DFT_CARD), AUDIO); _config.addDefaultValue(std::pair<std::string, std::string>( AUDIO_SAMPLE_RATE, DFT_SAMPLE_RATE), AUDIO); _config.addDefaultValue(std::pair<std::string, std::string>( @@ -2327,8 +2329,8 @@ void ManagerImpl::setInputAudioPlugin (const std::string& audioPlugin) { if (CHECK_INTERFACE (layer , ALSA)) { _debug ("Set input audio plugin"); _audiodriver -> setErrorMessage(-1); - _audiodriver -> openDevice(_audiodriver -> getIndexIn(), - _audiodriver -> getIndexOut(), _audiodriver -> getSampleRate(), + _audiodriver -> openDevice(_audiodriver->getIndexIn(), _audiodriver->getIndexOut(), + _audiodriver->getIndexRing(), _audiodriver -> getSampleRate(), _audiodriver -> getFrameSize(), SFL_PCM_CAPTURE, audioPlugin); if (_audiodriver -> getErrorMessage() != -1) @@ -2347,9 +2349,9 @@ void ManagerImpl::setOutputAudioPlugin (const std::string& audioPlugin) { _debug ("Manager: Set output audio plugin"); _audiodriver -> setErrorMessage(-1); - res = _audiodriver -> openDevice(_audiodriver -> getIndexIn(), - _audiodriver -> getIndexOut(), _audiodriver -> getSampleRate(), - _audiodriver -> getFrameSize(), SFL_PCM_BOTH, audioPlugin); + res = _audiodriver -> openDevice(_audiodriver->getIndexIn(), _audiodriver->getIndexOut(), + _audiodriver->getIndexRing(), _audiodriver -> getSampleRate(), + _audiodriver -> getFrameSize(), SFL_PCM_BOTH, audioPlugin); if (_audiodriver -> getErrorMessage() != -1) notifyErrClient(_audiodriver -> getErrorMessage()); @@ -2378,27 +2380,53 @@ std::vector<std::string> ManagerImpl::getAudioOutputDeviceList (void) { /** * Set audio output device */ -void ManagerImpl::setAudioOutputDevice (const int index) { - AlsaLayer *alsalayer; - std::string alsaplugin; - _debug ("Set audio output device: %i", index); - - _audiodriver -> setErrorMessage(-1); - - alsalayer = dynamic_cast<AlsaLayer*> (getAudioDriver()); - alsaplugin = alsalayer->getAudioPlugin(); +void ManagerImpl::setAudioDevice (const int index, int streamType) { + + AlsaLayer *alsalayer = NULL; + std::string alsaplugin; + _debug ("Manager: Set audio device: %i", index); - _debug (" set output plugin: %s", alsaplugin.c_str()); + _audiodriver -> setErrorMessage(-1); - _audiodriver->openDevice(_audiodriver->getIndexIn(), index, - _audiodriver->getSampleRate(), _audiodriver->getFrameSize(), - SFL_PCM_PLAYBACK, alsaplugin); + if(!(alsalayer = dynamic_cast<AlsaLayer*> (getAudioDriver()))) { + _warn("Manager: Error: No audio driver"); + return; + } + + alsaplugin = alsalayer->getAudioPlugin(); + + _debug ("Manager: Set ALSA plugin: %s", alsaplugin.c_str()); + + + switch(streamType) { + case SFL_PCM_PLAYBACK: + _debug("Manager: Set output device"); + _audiodriver->openDevice(_audiodriver->getIndexIn(), index, _audiodriver->getIndexRing(), + _audiodriver->getSampleRate(), _audiodriver->getFrameSize(), + SFL_PCM_PLAYBACK, alsaplugin); + setConfig(AUDIO, ALSA_CARD_ID_OUT, index); + break; + case SFL_PCM_CAPTURE: + _debug("Manager: Set input device"); + _audiodriver->openDevice(index, _audiodriver->getIndexOut(), _audiodriver->getIndexRing(), + _audiodriver->getSampleRate(), _audiodriver->getFrameSize(), + SFL_PCM_CAPTURE, alsaplugin); + setConfig(AUDIO, ALSA_CARD_ID_IN, index); + break; + case SFL_PCM_RINGTONE: + _debug("Manager: Set ringtone device"); + _audiodriver->openDevice(_audiodriver->getIndexOut(), _audiodriver->getIndexOut(), index, + _audiodriver->getSampleRate(), _audiodriver->getFrameSize(), + SFL_PCM_RINGTONE, alsaplugin); + setConfig(AUDIO, ALSA_CARD_ID_RING, index); + break; + default: + _warn("Unknown stream type"); + } - if (_audiodriver -> getErrorMessage() != -1) - notifyErrClient(_audiodriver -> getErrorMessage()); + if (_audiodriver -> getErrorMessage() != -1) + notifyErrClient(_audiodriver -> getErrorMessage()); - // set config - setConfig(AUDIO, ALSA_CARD_ID_OUT, index); } /** @@ -2416,44 +2444,19 @@ std::vector<std::string> ManagerImpl::getAudioInputDeviceList (void) { return devices; } -/** - * Set audio input device - */ -void ManagerImpl::setAudioInputDevice (const int index) { - AlsaLayer *alsalayer; - std::string alsaplugin; - - _debug ("Set audio input device %i", index); - - _audiodriver -> setErrorMessage(-1); - - alsalayer = dynamic_cast<AlsaLayer*> (getAudioDriver()); - alsaplugin = alsalayer->getAudioPlugin(); - - _debug (" set input plugin: %s", alsaplugin.c_str()); - - _audiodriver->openDevice(index, _audiodriver->getIndexOut(), - _audiodriver->getSampleRate(), _audiodriver->getFrameSize(), - SFL_PCM_CAPTURE, alsaplugin); - - if (_audiodriver -> getErrorMessage() != -1) - notifyErrClient(_audiodriver -> getErrorMessage()); - - // set config - setConfig(AUDIO, ALSA_CARD_ID_IN, index); -} - /** * Get string array representing integer indexes of output and input device */ std::vector<std::string> ManagerImpl::getCurrentAudioDevicesIndex () { _debug ("Get current audio devices index"); std::vector<std::string> v; - std::stringstream ssi, sso; + std::stringstream ssi, sso, ssr; sso << _audiodriver->getIndexOut(); v.push_back(sso.str()); ssi << _audiodriver->getIndexIn(); v.push_back(ssi.str()); + ssr << _audiodriver->getIndexRing(); + v.push_back(ssr.str()); return v; } @@ -2761,7 +2764,7 @@ bool ManagerImpl::initAudioDriver (void) { * Initialization: Main Thread and gui */ void ManagerImpl::selectAudioDriver (void) { - int layer, numCardIn, numCardOut, sampleRate, frameSize; + int layer, numCardIn, numCardOut, numCardRing, sampleRate, frameSize; std::string alsaPlugin; AlsaLayer *alsalayer; @@ -2772,6 +2775,8 @@ void ManagerImpl::selectAudioDriver (void) { alsaPlugin = getConfigString(AUDIO, ALSA_PLUGIN); numCardIn = getConfigInt(AUDIO, ALSA_CARD_ID_IN); numCardOut = getConfigInt(AUDIO, ALSA_CARD_ID_OUT); + numCardRing = getConfigInt(AUDIO, ALSA_CARD_ID_RING); + sampleRate = getConfigInt(AUDIO, AUDIO_SAMPLE_RATE); if (sampleRate <= 0 || sampleRate > 48000) { @@ -2783,25 +2788,31 @@ void ManagerImpl::selectAudioDriver (void) { /* Only for the ALSA layer, we check the sound card information */ if (layer == ALSA) { - alsalayer = dynamic_cast<AlsaLayer*> (getAudioDriver()); + alsalayer = dynamic_cast<AlsaLayer*> (getAudioDriver()); + + if (!alsalayer -> soundCardIndexExist(numCardIn, SFL_PCM_CAPTURE)) { + _debug (" Card with index %i doesn't exist or cannot capture. Switch to 0.", numCardIn); + numCardIn = ALSA_DFT_CARD_ID; + setConfig(AUDIO, ALSA_CARD_ID_IN, ALSA_DFT_CARD_ID); + } - if (!alsalayer -> soundCardIndexExist(numCardIn, SFL_PCM_CAPTURE)) { - _debug (" Card with index %i doesn't exist or cannot capture. Switch to 0.", numCardIn); - numCardIn = ALSA_DFT_CARD_ID; - setConfig(AUDIO, ALSA_CARD_ID_IN, ALSA_DFT_CARD_ID); - } + if (!alsalayer -> soundCardIndexExist(numCardOut, SFL_PCM_PLAYBACK)) { + _debug (" Card with index %i doesn't exist or cannot playback. Switch to 0.", numCardOut); + numCardOut = ALSA_DFT_CARD_ID; + setConfig(AUDIO, ALSA_CARD_ID_OUT, ALSA_DFT_CARD_ID); + } - if (!alsalayer -> soundCardIndexExist(numCardOut, SFL_PCM_PLAYBACK)) { - _debug (" Card with index %i doesn't exist or cannot playback . Switch to 0.", numCardOut); - numCardOut = ALSA_DFT_CARD_ID; - setConfig(AUDIO, ALSA_CARD_ID_OUT, ALSA_DFT_CARD_ID); - } + if (!alsalayer->soundCardIndexExist(numCardRing, SFL_PCM_RINGTONE)) { + _debug(" Card with index %i doesn't exist or cannot ringtone. Switch to 0.", numCardRing); + numCardRing = ALSA_DFT_CARD_ID; + setConfig(AUDIO, ALSA_CARD_ID_RING, ALSA_DFT_CARD_ID); + } } _audiodriver->setErrorMessage(-1); /* Open the audio devices */ - _audiodriver->openDevice(numCardIn, numCardOut, sampleRate, frameSize, + _audiodriver->openDevice(numCardIn, numCardOut, numCardRing, sampleRate, frameSize, SFL_PCM_BOTH, alsaPlugin); /* Notify the error if there is one */ @@ -2811,10 +2822,10 @@ void ManagerImpl::selectAudioDriver (void) { } void ManagerImpl::switchAudioManager (void) { - int type, samplerate, framesize, numCardIn, numCardOut; + int type, samplerate, framesize, numCardIn, numCardOut, numCardRing; std::string alsaPlugin; - _debug ("Switching audio manager "); + _debug ("Manager: Switching audio manager "); if (!_audiodriver) return; @@ -2822,18 +2833,17 @@ void ManagerImpl::switchAudioManager (void) { type = _audiodriver->getLayerType(); samplerate = getConfigInt(AUDIO, AUDIO_SAMPLE_RATE); - framesize = getConfigInt(AUDIO, ALSA_FRAME_SIZE); - _debug ("samplerate: %i, framesize %i\n", samplerate, framesize); + _debug ("Mnager: samplerate: %i, framesize %i\n", samplerate, framesize); alsaPlugin = getConfigString(AUDIO, ALSA_PLUGIN); numCardIn = getConfigInt(AUDIO, ALSA_CARD_ID_IN); - numCardOut = getConfigInt(AUDIO, ALSA_CARD_ID_OUT); + numCardRing = getConfigInt(AUDIO, ALSA_CARD_ID_RING); - _debug ("Deleting current layer... "); + _debug ("Manager: Deleting current layer... "); // ost::MutexLock lock (*getAudioLayerMutex()); getAudioLayerMutex()->enter(); @@ -2846,36 +2856,35 @@ void ManagerImpl::switchAudioManager (void) { switch (type) { case ALSA: - _debug ("Creating Pulseaudio layer..."); + _debug ("Manager: Creating Pulseaudio layer..."); _audiodriver = new PulseLayer(this); _audiodriver->setMainBuffer(&_mainBuffer); break; case PULSEAUDIO: - _debug ("Creating ALSA layer..."); + _debug ("Manager: Creating ALSA layer..."); _audiodriver = new AlsaLayer(this); _audiodriver->setMainBuffer(&_mainBuffer); break; default: - _debug ("Error: audio layer unknown"); + _warn("Manager: Error: audio layer unknown"); break; } _audiodriver->setErrorMessage(-1); - _audiodriver->openDevice(numCardIn, numCardOut, samplerate, framesize, + _audiodriver->openDevice(numCardIn, numCardOut, numCardRing, samplerate, framesize, SFL_PCM_BOTH, alsaPlugin); if (_audiodriver -> getErrorMessage() != -1) - notifyErrClient(_audiodriver -> getErrorMessage()); - - _debug ("Current device: %i ", type); + notifyErrClient(_audiodriver -> getErrorMessage()); - _debug ("has current call: %i ", hasCurrentCall()); + _debug ("Manager: Current device: %i ", type); + _debug ("Manager: Has current call: %i ", hasCurrentCall()); if (hasCurrentCall()) - _audiodriver->startStream(); + _audiodriver->startStream(); // ost::MutexLock unlock (*getAudioLayerMutex()); getAudioLayerMutex()->leave(); diff --git a/sflphone-common/src/managerimpl.h b/sflphone-common/src/managerimpl.h index 35e236c4fd4a18648bc3bd7f954257f120a9ce76..09acea4fd8a40c63d2c2c7f9a472a04b5c67455b 100644 --- a/sflphone-common/src/managerimpl.h +++ b/sflphone-common/src/managerimpl.h @@ -538,10 +538,11 @@ class ManagerImpl { std::vector<std::string> getAudioOutputDeviceList(void); /** - * Set audio output device + * Set audio device * @param index The index of the soundcard + * @param the type of stream, either SFL_PCM_PLAYBACK, SFL_PCM_CAPTURE, SFL_PCM_RINGTONE */ - void setAudioOutputDevice(const int index); + void setAudioDevice(const int index, const int streamType); /** * Get list of supported audio input device @@ -549,12 +550,6 @@ class ManagerImpl { */ std::vector<std::string> getAudioInputDeviceList(void); - /** - * Set audio input device - * @param index The index of the soundcard - */ - void setAudioInputDevice(const int index); - /** * Get string array representing integer indexes of output and input device * @return std::vector<std::string> A list of the current audio devices diff --git a/sflphone-common/src/sip/sipvoiplink.cpp b/sflphone-common/src/sip/sipvoiplink.cpp index 11d91ca9469118c6c6a476a11b68122291f8e7c4..a005ab44408ff388ebe41076eb77fd0ee2de9444 100644 --- a/sflphone-common/src/sip/sipvoiplink.cpp +++ b/sflphone-common/src/sip/sipvoiplink.cpp @@ -280,6 +280,7 @@ SIPVoIPLink::~SIPVoIPLink() _debug("UserAgent: SIPVoIPLink destructor called"); terminate(); + } SIPVoIPLink* SIPVoIPLink::instance (const AccountID& id) @@ -344,7 +345,6 @@ SIPVoIPLink::terminate() initDone (false); - _debug("Terminating"); } void @@ -1259,6 +1259,8 @@ SIPVoIPLink::refuse (const CallID& id) call->getInvSession()->mod_data[getModId() ] = NULL; + removeCall(id); + terminateOneCall (id); _debug("UserAgent: Refuse call completed"); diff --git a/sflphone-common/src/user_cfg.h b/sflphone-common/src/user_cfg.h index 6d45d53c6661785516c2d64ce7e02bc1cdff6239..910e3f9e15691e625918a4eab7920034ca078ca7 100644 --- a/sflphone-common/src/user_cfg.h +++ b/sflphone-common/src/user_cfg.h @@ -46,6 +46,7 @@ #define CODECS "ActiveCodecs" /** List of active codecs */ #define ALSA_CARD_ID_IN "Alsa.cardID_In" /** Soundcard index to use for capture */ #define ALSA_CARD_ID_OUT "Alsa.cardID_Out" /** Soundcard index to use for playback */ +#define ALSA_CARD_ID_RING "Alsa.cardID_Ring" /** Soundcard index to use for ringtone */ #define ALSA_FRAME_SIZE "Alsa.framesize" /** Audio layer frame size */ #define ALSA_PLUGIN "Alsa.plugin" /** Alsa plugin */ #define AUDIO_SAMPLE_RATE "Alsa.sampleRate" /** Audio layer sample rate */