diff --git a/sflphone-client-gnome/src/callable_obj.c b/sflphone-client-gnome/src/callable_obj.c index 8cd5877b3cb955510485cdb76fbc45e5e7ff0094..7994766e1f50fd10b5ced939b1e85321b0c577c5 100644 --- a/sflphone-client-gnome/src/callable_obj.c +++ b/sflphone-client-gnome/src/callable_obj.c @@ -235,12 +235,12 @@ void create_new_call (callable_type_t type, call_state_t state, gchar* callID , obj->_peer_number = g_strdup (peer_number); obj->_peer_info = g_strdup (get_peer_info (peer_name, peer_number)); obj->_recordfile = NULL; + obj->_record_is_playing = FALSE; obj->_trsft_to = ""; set_timestamp (& (obj->_time_start)); set_timestamp (& (obj->_time_current)); set_timestamp (& (obj->_time_stop)); - // g_snprintf(obj->_timestr, 20, "00:00"); if (g_strcasecmp (callID, "") == 0) call_id = generate_call_id (); diff --git a/sflphone-client-gnome/src/callable_obj.h b/sflphone-client-gnome/src/callable_obj.h index 71e75aaffd0f723d57bd3561a49fff013e8a0974..34be817e23f9c78457e2580aad05d699142b1170 100644 --- a/sflphone-client-gnome/src/callable_obj.h +++ b/sflphone-client-gnome/src/callable_obj.h @@ -157,6 +157,12 @@ typedef struct { */ gchar *_recordfile; + /** + * This boolean value is used to determine if the audio file + * is currently played back. + */ + gboolean _record_is_playing; + /* Associated IM widget */ GtkWidget *_im_widget; diff --git a/sflphone-client-gnome/src/conference_obj.h b/sflphone-client-gnome/src/conference_obj.h index a9523fc6191f3959fa189d7f72d56b076e8162a0..02208140ed81d35491aa6275ab1f91e55379cce4 100644 --- a/sflphone-client-gnome/src/conference_obj.h +++ b/sflphone-client-gnome/src/conference_obj.h @@ -68,6 +68,7 @@ typedef struct { time_t _time_stop; time_t _time_current; gchar *_recordfile; + gboolean _record_is_playing; } conference_obj_t; void create_new_conference (conference_state_t, const gchar*, conference_obj_t **); diff --git a/sflphone-client-gnome/src/dbus/callmanager-introspec.xml b/sflphone-client-gnome/src/dbus/callmanager-introspec.xml index bf9bb10c09293d93e8c1633a911c6b5749423bb8..cde5e2d644021210317a30bdb86f0a46a046a7a9 100644 --- a/sflphone-client-gnome/src/dbus/callmanager-introspec.xml +++ b/sflphone-client-gnome/src/dbus/callmanager-introspec.xml @@ -349,6 +349,12 @@ <arg type="s" name="filepath"/> </signal> + <signal name="recordPlaybackResult" tp:name-for-bindings="recordPlaybackResult"> + <tp:docstring/> + <arg type="b" name="callID" /> + </signal> + + <method name="getCallDetails" tp:name-for-bindings="getCallDetails"> <tp:docstring> Get all the details about a specific call. @@ -605,6 +611,7 @@ <tp:docstring> </tp:docstring> <arg type="s" name="filepath" direction="in"/> + <arg type="b" name="result" direction="out"/> </method> <method name="stopRecordedFilePlayback" tp:name-for-bindings="stopRecordedFilePlayback"> diff --git a/sflphone-client-gnome/src/dbus/dbus.c b/sflphone-client-gnome/src/dbus/dbus.c index 0ab683b2c7a7a8fb13514a6dfe8782372fe832d3..18dcbc463affd8133c3c775537b50b3925f6d086 100644 --- a/sflphone-client-gnome/src/dbus/dbus.c +++ b/sflphone-client-gnome/src/dbus/dbus.c @@ -86,13 +86,16 @@ static void conference_changed_cb (DBusGProxy *, const gchar *, const gchar *, void *); static void -conference_created_cb (DBusGProxy *proxy UNUSED, const gchar* confID, void * foo UNUSED); +conference_created_cb (DBusGProxy *, const gchar *, void *); static void -conference_removed_cb (DBusGProxy *proxy UNUSED, const gchar* confID, void * foo UNUSED); +conference_removed_cb (DBusGProxy *, const gchar *, void *); static void -record_playback_filepath_cb (DBusGProxy *proxy UNUSED, const gchar *id, const gchar *filepath); +record_playback_filepath_cb (DBusGProxy *, const gchar *, const gchar *); + +static void +record_playback_result_cb (DBusGProxy *, const gchar *, const gboolean); static void accounts_changed_cb (DBusGProxy *, void *); @@ -492,11 +495,21 @@ record_playback_filepath_cb (DBusGProxy *proxy UNUSED, const gchar *id, const gc callable_obj_t *call = NULL; conference_obj_t *conf = NULL; - DEBUG("DBUS: Filepath for call %s: %s", id, filepath); + DEBUG("DBUS: Filepath for %s: %s", id, filepath); call = calllist_get_call(current_calls, id); conf = conferencelist_get(current_calls, id); + if(call && conf) { + ERROR("DBUS: Two object for this callid"); + return; + } + + if(!call && !conf) { + ERROR("DBUS: Could not get object"); + return; + } + if(call) { if(call->_recordfile == NULL) call->_recordfile = g_strdup(filepath); @@ -508,6 +521,36 @@ record_playback_filepath_cb (DBusGProxy *proxy UNUSED, const gchar *id, const gc } +static void +record_playback_result_cb (DBusGProxy *proxy UNUSED, const gchar *id, const gboolean result) +{ + callable_obj_t *call = NULL; + conference_obj_t *conf = NULL; + + DEBUG("DBUS: Result for %s: %s", id, result ? "ok" : "bad"); + + call = calllist_get_call(history, id); + conf = conferencelist_get(history, id); + + if(call && conf) { + ERROR("DBUS: Two object for this ID"); + return; + } + + if(!call && !conf) { + ERROR("DBUS: Could not get object"); + return; + } + + if(call) { + call->_record_is_playing = result; + } + else if(conf) { + conf->_record_is_playing = result; + } + + update_actions(); +} static void accounts_changed_cb (DBusGProxy *proxy UNUSED, void * foo UNUSED) @@ -772,6 +815,10 @@ dbus_connect (GError **error) G_TYPE_STRING, G_TYPE_INVALID); dbus_g_proxy_connect_signal (callManagerProxy, "recordPlaybackFilepath", G_CALLBACK (record_playback_filepath_cb), NULL, NULL); + dbus_g_proxy_add_signal (callManagerProxy, "recordPlaybackResult", G_TYPE_BOOLEAN, + G_TYPE_STRING, G_TYPE_INVALID); + dbus_g_proxy_add_signal(callManagerProxy, "recordPlaybackResult", + G_CALLBACK (record_playback_result_cb), NULL, NULL); /* Security related callbacks */ @@ -925,19 +972,23 @@ dbus_unhold_conference (const conference_obj_t * c) } } -void +gboolean dbus_start_recorded_file_playback(const gchar *filepath) { DEBUG("DBUS: Start recorded file playback %s", filepath); GError *error = NULL; + gboolean result; + org_sflphone_SFLphone_CallManager_start_recorded_file_playback(callManagerProxy, - filepath, &error); + filepath, &result, &error); if(error) { ERROR("Failed to call recorded file playback: %s", error->message); g_error_free(error); } + + return result; } void diff --git a/sflphone-client-gnome/src/dbus/dbus.h b/sflphone-client-gnome/src/dbus/dbus.h index 174888dd2f94a89150e75b5c20660c217c9ffb5e..740c90e016f5d7396a0b84671171ff9d1d9737ad 100644 --- a/sflphone-client-gnome/src/dbus/dbus.h +++ b/sflphone-client-gnome/src/dbus/dbus.h @@ -638,7 +638,7 @@ void dbus_send_text_message (const gchar* callID, const gchar *message); * Start playback of a recorded * @param The recorded file to start playback with */ -void dbus_start_recorded_file_playback(const gchar *); +gboolean dbus_start_recorded_file_playback(const gchar *); /** * Stop playback of a recorded filie diff --git a/sflphone-client-gnome/src/ui.xml b/sflphone-client-gnome/src/ui.xml index 43c4f4799ef48fea0bada93193538fc0bb10fc13..170665086346f4dfd52a6c6f781ceda0229662cb 100644 --- a/sflphone-client-gnome/src/ui.xml +++ b/sflphone-client-gnome/src/ui.xml @@ -54,7 +54,8 @@ <separator/> <toolitem name="VoicemailToolbar" action="Voicemail"/> <toolitem name="HistoryToolbar" action="History"/> - <toolitem name="PlayRecordToolbar" action="PlayRecord"/> + <toolitem name="StartPlaybackRecordToolbar" action="StartPlaybackRecord"/> + <toolitem name="StopPlaybackRecordToolbar" action="StopPlaybackRecord" /> </toolbar> <popup name="PopupMenu"> diff --git a/sflphone-client-gnome/src/uimanager.c b/sflphone-client-gnome/src/uimanager.c index 63b890d8cef7642f9b03d3001a478e6460b2038a..1d3a5be2705827ea20d472eb500f754ab4635abb 100644 --- a/sflphone-client-gnome/src/uimanager.c +++ b/sflphone-client-gnome/src/uimanager.c @@ -79,7 +79,9 @@ static GtkWidget * voicemailToolbar; static GtkWidget * imToolbar; static GtkAction * imAction; static GtkWidget * playRecordWidget; -static GtkWidget * playRecordAction; +static GtkAction * playRecordAction; +static GtkWidget * stopRecordWidget; +static GtkAction * stopRecordAction; static GtkWidget * editable_num; static GtkDialog * edit_dialog; @@ -185,6 +187,8 @@ update_actions() if(is_inserted(GTK_WIDGET (playRecordWidget), GTK_WIDGET(toolbar))) gtk_container_remove(GTK_CONTAINER(toolbar), GTK_WIDGET(playRecordWidget)); + if(is_inserted(GTK_WIDGET (stopRecordWidget), GTK_WIDGET(toolbar))) + gtk_container_remove(GTK_CONTAINER(toolbar), GTK_WIDGET(stopRecordWidget)); } // If addressbook support has been enabled and all addressbooks are loaded, display the icon @@ -279,7 +283,10 @@ update_actions() gtk_toolbar_insert (GTK_TOOLBAR (toolbar), GTK_TOOL_ITEM (hangUpWidget), 1); else if(active_calltree == history) { if(selectedCall->_recordfile && (g_strcmp0(selectedCall->_recordfile, "") != 0)) { - gtk_toolbar_insert(GTK_TOOLBAR (toolbar), GTK_TOOL_ITEM(playRecordWidget), 3); + if(selectedCall->_record_is_playing) + gtk_toolbar_insert(GTK_TOOLBAR (toolbar), GTK_TOOL_ITEM(stopRecordWidget), 3); + else + gtk_toolbar_insert(GTK_TOOLBAR (toolbar), GTK_TOOL_ITEM(playRecordWidget), 3); } } break; @@ -715,9 +722,11 @@ call_record (void) } static void -playback_record_cb(void) +start_playback_record_cb(void) { - DEBUG("UIManager: Playback button pressed"); + gboolean result; + + DEBUG("UIManager: Start playback button pressed"); callable_obj_t *selectedCall = calltab_get_selected_call (history); conference_obj_t *selectedConf = calltab_get_selected_conf (history); @@ -727,10 +736,46 @@ playback_record_cb(void) return; } - if(selectedCall) - dbus_start_recorded_file_playback(selectedCall->_recordfile); - else if(selectedConf) - dbus_start_recorded_file_playback(selectedConf->_recordfile); + if(selectedCall) { + result = dbus_start_recorded_file_playback(selectedCall->_recordfile); + selectedCall->_record_is_playing = result; + } + else if(selectedConf) { + result = dbus_start_recorded_file_playback(selectedConf->_recordfile); + selectedConf->_record_is_playing = result; + } + + update_actions(); +} + +static void +stop_playback_record_cb(void) +{ + DEBUG("UIManager: Stop playback button pressed"); + + callable_obj_t *selectedCall = calltab_get_selected_call (history); + conference_obj_t *selectedConf = calltab_get_selected_conf(history); + + if(selectedCall && selectedConf) { + ERROR("UIManager: Error: Two selected object in history treeview"); + return; + } + + if((selectedCall == NULL) && (selectedConf == NULL)) { + ERROR("UIManager: Error: No selected object in history treeview"); + return; + } + + if(selectedCall) { + dbus_stop_recorded_file_playback(selectedCall->_recordfile); + selectedCall->_record_is_playing = FALSE; + } + else if(selectedConf) { + dbus_stop_recorded_file_playback(selectedConf->_recordfile); + selectedConf->_record_is_playing = FALSE; + } + + update_actions(); } static void @@ -1000,8 +1045,10 @@ static const GtkActionEntry menu_entries[] = { N_ ("Minimize to system tray"), G_CALLBACK (call_minimize) }, { "Quit", GTK_STOCK_CLOSE, N_ ("_Quit"), "<control>Q", N_ ("Quit the program"), G_CALLBACK (call_quit) }, - { "PlayRecord", GTK_STOCK_MEDIA_PLAY, N_ ("_Playback record"), NULL, - N_ ("Playback recorded file"), G_CALLBACK (playback_record_cb) }, + { "StartPlaybackRecord", GTK_STOCK_MEDIA_PLAY, N_ ("_Playback record"), NULL, + N_ ("Playback recorded file"), G_CALLBACK (start_playback_record_cb) }, + { "StopPlaybackRecord", GTK_STOCK_MEDIA_PAUSE, N_ ("_Stop playback"), NULL, + N_ ("Stop recorded file playback"), G_CALLBACK (stop_playback_record_cb) }, // Edit Menu { "Edit", NULL, N_ ("_Edit"), NULL, NULL, NULL }, @@ -1752,9 +1799,13 @@ create_toolbar_actions (GtkUIManager *ui_manager, GtkWidget **widget) historyButton = gtk_ui_manager_get_widget (ui_manager, "/ToolbarActions/HistoryToolbar"); playRecordWidget = gtk_ui_manager_get_widget(ui_manager, - "/ToolbarActions/PlayRecordToolbar"); + "/ToolbarActions/StartPlaybackRecordToolbar"); playRecordAction = gtk_ui_manager_get_action(ui_manager, - "/ToolbarActions/PlayRecord"); + "/ToolbarActions/StartPlaybackRecord"); + stopRecordWidget = gtk_ui_manager_get_widget(ui_manager, + "/ToolbarActions/StopPlaybackRecordToolbar"); + stopRecordAction = gtk_ui_manager_get_action(ui_manager, + "/ToolbarActions/StopPlaybackRecord"); if(abookfactory_is_addressbook_loaded()) { contactButton = gtk_ui_manager_get_widget (ui_manager, "/ToolbarActions/AddressbookToolbar"); } diff --git a/sflphone-common/src/dbus/callmanager-introspec.xml b/sflphone-common/src/dbus/callmanager-introspec.xml index bf9bb10c09293d93e8c1633a911c6b5749423bb8..cde5e2d644021210317a30bdb86f0a46a046a7a9 100644 --- a/sflphone-common/src/dbus/callmanager-introspec.xml +++ b/sflphone-common/src/dbus/callmanager-introspec.xml @@ -349,6 +349,12 @@ <arg type="s" name="filepath"/> </signal> + <signal name="recordPlaybackResult" tp:name-for-bindings="recordPlaybackResult"> + <tp:docstring/> + <arg type="b" name="callID" /> + </signal> + + <method name="getCallDetails" tp:name-for-bindings="getCallDetails"> <tp:docstring> Get all the details about a specific call. @@ -605,6 +611,7 @@ <tp:docstring> </tp:docstring> <arg type="s" name="filepath" direction="in"/> + <arg type="b" name="result" direction="out"/> </method> <method name="stopRecordedFilePlayback" tp:name-for-bindings="stopRecordedFilePlayback"> diff --git a/sflphone-common/src/dbus/callmanager.cpp b/sflphone-common/src/dbus/callmanager.cpp index 31251ad8a0b67f2da23a474c1b2c18195349cd88..aaafcf6f2985ab0f4f688fd29cb0e6bc8420e041 100644 --- a/sflphone-common/src/dbus/callmanager.cpp +++ b/sflphone-common/src/dbus/callmanager.cpp @@ -283,10 +283,10 @@ CallManager::getParticipantList (const std::string& confID) return Manager::instance().getParticipantList (confID); } -void +bool CallManager::startRecordedFilePlayback(const std::string& filepath) { - Manager::instance().startRecordedFilePlayback(filepath); + return Manager::instance().startRecordedFilePlayback(filepath); } void diff --git a/sflphone-common/src/dbus/callmanager.h b/sflphone-common/src/dbus/callmanager.h index 752ea9cba34698574d0c11b5fcb1631bd50062dc..daca254d9e97e58b6303c03e5f4914f88ff4c522 100644 --- a/sflphone-common/src/dbus/callmanager.h +++ b/sflphone-common/src/dbus/callmanager.h @@ -101,7 +101,7 @@ class CallManager std::map< std::string, std::string > getConferenceDetails (const std::string& callID); /* File Playback methods */ - void startRecordedFilePlayback(const std::string& filepath); + bool startRecordedFilePlayback(const std::string& filepath); void stopRecordedFilePlayback(const std::string& filepath); /* General audio methods */ diff --git a/sflphone-common/src/managerimpl.cpp b/sflphone-common/src/managerimpl.cpp index f6230446b9b21a67c4d778805944ebc0679eaaed..31d299085cfb115636f12e636ad21722a281db63 100644 --- a/sflphone-common/src/managerimpl.cpp +++ b/sflphone-common/src/managerimpl.cpp @@ -1863,13 +1863,13 @@ bool ManagerImpl::incomingCall (Call* call, const AccountID& accountId) } if (!hasCurrentCall()) { - _debug ("Manager: Has no current call"); + _debug ("Manager: Has no current call start ringing"); call->setConnectionState (Call::Ringing); ringtone (accountId); } else { - _debug ("Manager: has current call"); + _debug ("Manager: has current call, beep in current audio stream"); } addWaitingCall (call->getCallId()); @@ -2359,7 +2359,7 @@ void ManagerImpl::ringtone (const AccountID& accountID) { std::string ringchoice; sfl::AudioCodec *codecForTone; - int layer, samplerate; + int samplerate; _debug ("Manager: Ringtone"); @@ -2394,8 +2394,6 @@ void ManagerImpl::ringtone (const AccountID& accountID) return; } - layer = _audiodriver->getLayerType(); - samplerate = _audiodriver->getSampleRate(); codecForTone = static_cast<sfl::AudioCodec *>(_audioCodecFactory.getFirstCodecAvailable()); @@ -3012,14 +3010,65 @@ bool ManagerImpl::isRecording (const CallID& id) return ret; } -void ManagerImpl::startRecordedFilePlayback(const std::string& filepath) +bool ManagerImpl::startRecordedFilePlayback(const std::string& filepath) { + int sampleRate; + _debug("Manager: Start recorded file playback %s", filepath.c_str()); + + audioLayerMutexLock(); + + if(!_audiodriver) { + _error("Manager: Error: No audio layer in start recorded file playback"); + } + + sampleRate = _audiodriver->getSampleRate(); + + audioLayerMutexUnlock(); + + _toneMutex.enterMutex(); + + if(_audiofile) { + delete _audiofile; + _audiofile = NULL; + } + + try { + _audiofile = static_cast<AudioFile *>(new WaveFile()); + + _audiofile->loadFile(filepath, NULL, sampleRate); + } + catch(AudioFileException &e) { + _error("Manager: Exception: %s", e.what()); + } + + _audiofile->start(); + + _toneMutex.leaveMutex(); + + audioLayerMutexLock(); + _audiodriver->startStream(); + audioLayerMutexUnlock(); + + return true; } + void ManagerImpl::stopRecordedFilePlayback(const std::string& filepath) { _debug("Manager: Stop recorded file playback %s", filepath.c_str()); + + audioLayerMutexLock(); + _audiodriver->stopStream(); + audioLayerMutexUnlock(); + + _toneMutex.enterMutex(); + if(_audiofile != NULL) { + _audiofile->stop(); + delete _audiofile; + _audiofile = NULL; + } + _toneMutex.leaveMutex(); } void ManagerImpl::setHistoryLimit (const int& days) diff --git a/sflphone-common/src/managerimpl.h b/sflphone-common/src/managerimpl.h index 3017babd326bc43c3dfbd1e09aedd314c236a773..e34fc262dc3453315f350c936074ec33c77d5e21 100644 --- a/sflphone-common/src/managerimpl.h +++ b/sflphone-common/src/managerimpl.h @@ -759,7 +759,7 @@ class ManagerImpl * Start playback fo a recorded file if and only if audio layer is not already started. * @param File path of the file to play */ - void startRecordedFilePlayback(const std::string&); + bool startRecordedFilePlayback(const std::string&); /** * Stop playback of recorded file