diff --git a/daemon/src/Android.mk b/daemon/src/Android.mk index c395dc813ac73006ddaf8d2b2c9e66aca5bcc781..fd0a781d11b6bbf0d5331541711c3b0b89cba045 100644 --- a/daemon/src/Android.mk +++ b/daemon/src/Android.mk @@ -74,6 +74,7 @@ LOCAL_SRC_FILES := \ dbus/callmanager_wrap.cpp \ dbus/instance.cpp \ dbus/dbusmanager.cpp \ + android-jni/callmanagerJNI.cpp \ history/historyitem.cpp \ history/history.cpp \ history/historynamecache.cpp \ diff --git a/daemon/src/android-jni/callmanagerJNI.cpp b/daemon/src/android-jni/callmanagerJNI.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ec6d4661c1ee144b773606f2f2ba15747c7a8c1a --- /dev/null +++ b/daemon/src/android-jni/callmanagerJNI.cpp @@ -0,0 +1,424 @@ +/* + * Copyright (C) 2004-2012 Savoir-Faire Linux Inc. + * Author: Pierre-Luc Beaudoin <pierre-luc.beaudoin@savoirfairelinux.com> + * Author: Alexandre Bourget <alexandre.bourget@savoirfairelinux.com> + * Author: Emeric Vigier <emeric.vigier@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 + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Additional permission under GNU GPL version 3 section 7: + * + * If you modify this program, or any covered work, by linking or + * combining it with the OpenSSL project's OpenSSL library (or a + * modified version of that library), containing parts covered by the + * terms of the OpenSSL or SSLeay licenses, Savoir-Faire Linux Inc. + * grants you additional permission to convey the resulting work. + * Corresponding Source for a non-source form of such a combination + * shall include the source code for the parts of OpenSSL used as well + * as that of the covered work. + */ +#include <vector> + +#include "global.h" +#include "callmanagerJNI.h" + +#include "sip/sipcall.h" +#include "sip/sipvoiplink.h" +#include "audio/audiolayer.h" +#include "audio/audiortp/audio_rtp_factory.h" +#if HAVE_ZRTP +#include "audio/audiortp/audio_zrtp_session.h" +#endif + +#include "logger.h" +#include "manager.h" + +CallManagerJNI::CallManagerJNI() +{} + +void CallManagerJNI::placeCall(const std::string& accountID, + const std::string& callID, + const std::string& to) +{ + // Check if a destination number is available + if (to.empty()) + DEBUG("No number entered - Call stopped"); + else + Manager::instance().outgoingCall(accountID, callID, to); +} + +void CallManagerJNI::placeCallFirstAccount(const std::string& callID, + const std::string& to) +{ + using std::vector; + using std::string; + + if (to.empty()) { + WARN("CallManagerJNI: Warning: No number entered, call stopped"); + return; + } + + vector<string> accountList(Manager::instance().loadAccountOrder()); + + if (accountList.empty()) + accountList = Manager::instance().getAccountList(); + + for (vector<string>::const_iterator iter = accountList.begin(); iter != accountList.end(); ++iter) { + Account *account = Manager::instance().getAccount(*iter); + if (account && (*iter != SIPAccount::IP2IP_PROFILE) && account->isEnabled()) { + Manager::instance().outgoingCall(*iter, callID, to); + return; + } + } +} + +void +CallManagerJNI::refuse(const std::string& callID) +{ + Manager::instance().refuseCall(callID); +} + +void +CallManagerJNI::accept(const std::string& callID) +{ + Manager::instance().answerCall(callID); +} + +void +CallManagerJNI::hangUp(const std::string& callID) +{ + Manager::instance().hangupCall(callID); +} + +void +CallManagerJNI::hangUpConference(const std::string& confID) +{ + Manager::instance().hangupConference(confID); +} + +void +CallManagerJNI::hold(const std::string& callID) +{ + Manager::instance().onHoldCall(callID); +} + +void +CallManagerJNI::unhold(const std::string& callID) +{ + Manager::instance().offHoldCall(callID); +} + +void +CallManagerJNI::transfer(const std::string& callID, const std::string& to) +{ + Manager::instance().transferCall(callID, to); +} + +void CallManagerJNI::attendedTransfer(const std::string& transferID, const std::string& targetID) +{ + Manager::instance().attendedTransfer(transferID, targetID); +} + +void CallManagerJNI::setVolume(const std::string& device, const double& value) +{ + AudioLayer *audiolayer = Manager::instance().getAudioDriver(); + + if(!audiolayer) { + ERROR("Audio layer not valid while updating volume"); + return; + } + + DEBUG("DBUS set volume for %s: %f", device.c_str(), value); + + if (device == "speaker") { + audiolayer->setPlaybackGain((int)(value * 100.0)); + } else if (device == "mic") { + audiolayer->setCaptureGain((int)(value * 100.0)); + } + + //volumeChanged(device, value); +} + +double +CallManagerJNI::getVolume(const std::string& device) +{ + AudioLayer *audiolayer = Manager::instance().getAudioDriver(); + + if(!audiolayer) { + ERROR("Audio layer not valid while updating volume"); + return 0.0; + } + + if (device == "speaker") + return audiolayer->getPlaybackGain() / 100.0; + else if (device == "mic") + return audiolayer->getCaptureGain() / 100.0; + + return 0; +} + +void +CallManagerJNI::joinParticipant(const std::string& sel_callID, const std::string& drag_callID) +{ + Manager::instance().joinParticipant(sel_callID, drag_callID); +} + +void +CallManagerJNI::createConfFromParticipantList(const std::vector<std::string>& participants) +{ + Manager::instance().createConfFromParticipantList(participants); +} + +void +CallManagerJNI::addParticipant(const std::string& callID, const std::string& confID) +{ + Manager::instance().addParticipant(callID, confID); +} + +void +CallManagerJNI::addMainParticipant(const std::string& confID) +{ + Manager::instance().addMainParticipant(confID); +} + +void +CallManagerJNI::detachParticipant(const std::string& callID) +{ + Manager::instance().detachParticipant(callID, ""); +} + +void +CallManagerJNI::joinConference(const std::string& sel_confID, const std::string& drag_confID) +{ + Manager::instance().joinConference(sel_confID, drag_confID); +} + +void +CallManagerJNI::holdConference(const std::string& confID) +{ + Manager::instance().holdConference(confID); +} + +void +CallManagerJNI::unholdConference(const std::string& confID) +{ + Manager::instance().unHoldConference(confID); +} + +std::map<std::string, std::string> +CallManagerJNI::getConferenceDetails(const std::string& callID) +{ + return Manager::instance().getConferenceDetails(callID); +} + +std::vector<std::string> +CallManagerJNI::getConferenceList() +{ + return Manager::instance().getConferenceList(); +} + +std::vector<std::string> +CallManagerJNI::getParticipantList(const std::string& confID) +{ + return Manager::instance().getParticipantList(confID); +} + +std::string +CallManagerJNI::getConferenceId(const std::string& callID) +{ + return Manager::instance().getConferenceId(callID); +} + +bool +CallManagerJNI::startRecordedFilePlayback(const std::string& filepath) +{ + return Manager::instance().startRecordedFilePlayback(filepath); +} + +void +CallManagerJNI::stopRecordedFilePlayback(const std::string& filepath) +{ + Manager::instance().stopRecordedFilePlayback(filepath); +} + +void +CallManagerJNI::setRecording(const std::string& callID) +{ + Manager::instance().setRecordingCall(callID); +} + +void +CallManagerJNI::recordPlaybackSeek(const double& value) +{ + Manager::instance().recordingPlaybackSeek(value); +} + +bool +CallManagerJNI::getIsRecording(const std::string& callID) +{ + return Manager::instance().isRecording(callID); +} + +std::string CallManagerJNI::getCurrentAudioCodecName(const std::string& callID) +{ + return Manager::instance().getCurrentAudioCodecName(callID); +} + +std::map<std::string, std::string> +CallManagerJNI::getCallDetails(const std::string& callID) +{ + return Manager::instance().getCallDetails(callID); +} + +std::vector<std::string> +CallManagerJNI::getCallList() +{ + return Manager::instance().getCallList(); +} + +void +CallManagerJNI::playDTMF(const std::string& key) +{ + Manager::instance().sendDtmf(Manager::instance().getCurrentCallId(), key.data()[0]); +} + +void +CallManagerJNI::startTone(const int32_t& start , const int32_t& type) +{ + if (start) { + if (type == 0) + Manager::instance().playTone(); + else + Manager::instance().playToneWithMessage(); + } else + Manager::instance().stopTone(); +} + +// TODO: this will have to be adapted +// for conferencing in order to get +// the right pointer for the given +// callID. +#if HAVE_ZRTP +sfl::AudioZrtpSession * +CallManagerJNI::getAudioZrtpSession(const std::string& callID) +{ + // IP2IP profile is associated with IP2IP profile anyway + SIPVoIPLink * link = static_cast<SIPVoIPLink *>(Manager::instance().getAccountLink(SIPAccount::IP2IP_PROFILE)); + + if (!link) + throw CallManagerException("Failed to get sip link"); + + SIPCall *call; + + try { + call = link->getSIPCall(callID); + } catch (const VoipLinkException &e) { + throw CallManagerException("Call id " + callID + " is not valid"); + } + + sfl::AudioZrtpSession * zSession = call->getAudioRtp().getAudioZrtpSession(); + + if (!zSession) + throw CallManagerException("Failed to get AudioZrtpSession"); + + return zSession; +} +#endif + +void +CallManagerJNI::setSASVerified(const std::string& callID) +{ +#if HAVE_ZRTP + try { + sfl::AudioZrtpSession * zSession; + zSession = getAudioZrtpSession(callID); + zSession->SASVerified(); + } catch (...) { + } +#else + ERROR("No zrtp support for %s, please recompile SFLphone with zrtp", callID.c_str()); +#endif +} + +void +CallManagerJNI::resetSASVerified(const std::string& callID) +{ +#if HAVE_ZRTP + try { + sfl::AudioZrtpSession * zSession; + zSession = getAudioZrtpSession(callID); + zSession->resetSASVerified(); + } catch (...) { + } +#else + ERROR("No zrtp support for %s, please recompile SFLphone with zrtp", callID.c_str()); +#endif +} + +void +CallManagerJNI::setConfirmGoClear(const std::string& callID) +{ +#if HAVE_ZRTP + try { + sfl::AudioZrtpSession * zSession; + zSession = getAudioZrtpSession(callID); + zSession->goClearOk(); + } catch (...) { + } +#else + ERROR("No zrtp support for %s, please recompile SFLphone with zrtp", callID.c_str()); +#endif +} + +void +CallManagerJNI::requestGoClear(const std::string& callID) +{ +#if HAVE_ZRTP + try { + sfl::AudioZrtpSession * zSession; + zSession = getAudioZrtpSession(callID); + zSession->requestGoClear(); + } catch (...) { + } +#else + ERROR("No zrtp support for %s, please recompile SFLphone with zrtp", callID.c_str()); +#endif +} + +void +CallManagerJNI::acceptEnrollment(const std::string& callID, const bool& accepted) +{ +#if HAVE_ZRTP + try { + sfl::AudioZrtpSession * zSession; + zSession = getAudioZrtpSession(callID); + zSession->acceptEnrollment(accepted); + } catch (...) { + } +#else + ERROR("No zrtp support for %s, please recompile SFLphone with zrtp", callID.c_str()); +#endif +} + +void +CallManagerJNI::sendTextMessage(const std::string& callID, const std::string& message) +{ +#if HAVE_INSTANT_MESSAGING + if (!Manager::instance().sendTextMessage(callID, message, "Me")) + throw CallManagerException(); +#else + ERROR("Could not send \"%s\" text message to %s since SFLphone daemon does not support it, please recompile with instant messaging support", message.c_str(), callID.c_str()); +#endif +} diff --git a/daemon/src/android-jni/callmanagerJNI.h b/daemon/src/android-jni/callmanagerJNI.h new file mode 100644 index 0000000000000000000000000000000000000000..74255a89b3ad2ce218f891161f74bec61736bbe3 --- /dev/null +++ b/daemon/src/android-jni/callmanagerJNI.h @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2004-2012 Savoir-Faire Linux Inc. + * Author: Pierre-Luc Beaudoin <pierre-luc.beaudoin@savoirfairelinux.com> + * Author: Emeric Vigier <emeric.vigier@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 + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Additional permission under GNU GPL version 3 section 7: + * + * If you modify this program, or any covered work, by linking or + * combining it with the OpenSSL project's OpenSSL library (or a + * modified version of that library), containing parts covered by the + * terms of the OpenSSL or SSLeay licenses, Savoir-Faire Linux Inc. + * grants you additional permission to convey the resulting work. + * Corresponding Source for a non-source form of such a combination + * shall include the source code for the parts of OpenSSL used as well + * as that of the covered work. + */ + +#ifndef __SFL_CALLMANAGER_JNI_H__ +#define __SFL_CALLMANAGER_JNI_H__ + +#if __GNUC__ >= 4 && __GNUC_MINOR__ >= 6 +/* This warning option only exists for gcc 4.6.0 and greater. */ +#pragma GCC diagnostic ignored "-Wunused-but-set-variable" +#endif + +#pragma GCC diagnostic ignored "-Wignored-qualifiers" +#pragma GCC diagnostic ignored "-Wunused-parameter" +/* placeholder for the jni-glue */ +#pragma GCC diagnostic warning "-Wignored-qualifiers" +#pragma GCC diagnostic warning "-Wunused-parameter" + +#if __GNUC__ >= 4 && __GNUC_MINOR__ >= 6 +/* This warning option only exists for gcc 4.6.0 and greater. */ +#pragma GCC diagnostic warning "-Wunused-but-set-variable" +#endif + +namespace sfl { + class AudioZrtpSession; +} + +class CallManagerJNI { + public: + + CallManagerJNI(); + + /* methods exported by this interface, + * you will have to implement them + */ + + /* Call related methods */ + void placeCall(const std::string& accountID, const std::string& callID, const std::string& to); + void placeCallFirstAccount(const std::string& callID, const std::string& to); + + void refuse(const std::string& callID); + void accept(const std::string& callID); + void hangUp(const std::string& callID); + void hold(const std::string& callID); + void unhold(const std::string& callID); + void transfer(const std::string& callID, const std::string& to); + void attendedTransfer(const std::string& transferID, const std::string& targetID); + std::map< std::string, std::string > getCallDetails(const std::string& callID); + std::vector< std::string > getCallList(); + + /* Conference related methods */ + void joinParticipant(const std::string& sel_callID, const std::string& drag_callID); + void createConfFromParticipantList(const std::vector< std::string >& participants); + void addParticipant(const std::string& callID, const std::string& confID); + void addMainParticipant(const std::string& confID); + void detachParticipant(const std::string& callID); + void joinConference(const std::string& sel_confID, const std::string& drag_confID); + void hangUpConference(const std::string& confID); + void holdConference(const std::string& confID); + void unholdConference(const std::string& confID); + std::vector<std::string> getConferenceList(); + std::vector<std::string> getParticipantList(const std::string& confID); + std::string getConferenceId(const std::string& callID); + std::map<std::string, std::string> getConferenceDetails(const std::string& callID); + + /* File Playback methods */ + bool startRecordedFilePlayback(const std::string& filepath); + void stopRecordedFilePlayback(const std::string& filepath); + + /* General audio methods */ + void setVolume(const std::string& device, const double& value); + double getVolume(const std::string& device); + void setRecording(const std::string& callID); + void recordPlaybackSeek(const double& value); + bool getIsRecording(const std::string& callID); + std::string getCurrentAudioCodecName(const std::string& callID); + void playDTMF(const std::string& key); + void startTone(const int32_t& start, const int32_t& type); + + /* Security related methods */ + void setSASVerified(const std::string& callID); + void resetSASVerified(const std::string& callID); + void setConfirmGoClear(const std::string& callID); + void requestGoClear(const std::string& callID); + void acceptEnrollment(const std::string& callID, const bool& accepted); + + /* Instant messaging */ + void sendTextMessage(const std::string& callID, const std::string& message); + + private: + +#if HAVE_ZRTP + sfl::AudioZrtpSession * getAudioZrtpSession(const std::string& callID); +#endif +}; + +#endif//CALLMANAGER_JNI_H diff --git a/daemon/src/dbus/callmanager.i b/daemon/src/dbus/callmanager.i index cc9f049eb17e44977f1ca2eedb13c58cd9b23f1d..c77dfdc43b41c50f9044c72f736678391986d701 100644 --- a/daemon/src/dbus/callmanager.i +++ b/daemon/src/dbus/callmanager.i @@ -1,7 +1,36 @@ +/* + * Copyright (C) 2004-2012 Savoir-Faire Linux Inc. + * Author: Emeric Vigier <emeric.vigier@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 + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Additional permission under GNU GPL version 3 section 7: + * + * If you modify this program, or any covered work, by linking or + * combining it with the OpenSSL project's OpenSSL library (or a + * modified version of that library), containing parts covered by the + * terms of the OpenSSL or SSLeay licenses, Savoir-Faire Linux Inc. + * grants you additional permission to convey the resulting work. + * Corresponding Source for a non-source form of such a combination + * shall include the source code for the parts of OpenSSL used as well + * as that of the covered work. + */ /* File : callmanager.i */ -%module sflphoneservice +%module (directors="1") sflphoneservice +#define SWIG_JAVA_ATTACH_CURRENT_THREAD_AS_DAEMON %include "typemaps.i" %include "std_string.i" /* std::string typemaps */ %include "enums.swg" @@ -25,19 +54,61 @@ } /* not parsed by SWIG but needed by generated C files */ -%{ +%header %{ + #include <managerimpl.h> -#include <dbus/callmanager.h> +#include <android-jni/callmanagerJNI.h> + +typedef struct callmanager_callback +{ + void (*on_incoming_call)(const std::string& accountID, + const std::string& callID, + const std::string& from); +} callmanager_callback_t; namespace Manager { extern ManagerImpl& instance(); } + +class Callback { +public: + virtual ~Callback() {} + virtual void on_incoming_call(const std::string& arg1, + const std::string& arg2, + const std::string& arg3) {} + +}; + +static Callback* registeredCallbackObject = NULL; + +void on_incoming_call_wrapper (const std::string& accountID, + const std::string& callID, + const std::string& from) { + registeredCallbackObject->on_incoming_call(accountID, callID, from); +} + +static struct callmanager_callback wrapper_callback_struct = { + &on_incoming_call_wrapper +}; + +void setCallbackObject(Callback* callback) { + registeredCallbackObject = callback; +} + +%} + +%inline %{ +/* some functions that need to be declared in *_wrap.cpp + * that are not declared elsewhere in the c++ code + */ %} /* parsed by SWIG to generate all the glue */ /* %include "../managerimpl.h" */ /* %include <dbus/callmanager.h> */ +//%constant struct callmanager_callback* WRAPPER_CALLBACK_STRUCT = &wrapper_callback_struct; + /* %nodefaultctor ManagerImpl; %nodefaultdtor ManagerImpl; */ @@ -64,19 +135,35 @@ ManagerImpl& Manager::instance() } -//class CallManager { -//public: -// /* Manager::instance().outgoingCall */ -// void placeCall(const std::string& accountID, -// const std::string& callID, -// const std::string& to); -// /* Manager::instance().refuseCall */ -// void refuse(const std::string& callID); -// /* Manager::instance().answerCall */ -// void accept(const std::string& callID); -// /* Manager::instance().hangupCall */ -// void hangUp(const std::string& callID); -//}; +%feature("director") Callback; + +class CallManagerJNI { +public: + /* Manager::instance().outgoingCall */ + void placeCall(const std::string& accountID, + const std::string& callID, + const std::string& to); + /* Manager::instance().refuseCall */ + void refuse(const std::string& callID); + /* Manager::instance().answerCall */ + void accept(const std::string& callID); + /* Manager::instance().hangupCall */ + void hangUp(const std::string& callID); +}; + +class Callback { +public: + virtual ~Callback(); + virtual void on_incoming_call(const std::string& arg1, + const std::string& arg2, + const std::string& arg3); +}; + +static Callback* registeredCallbackObject = NULL; + +void setCallbackObject(Callback* callback) { + registeredCallbackObject = callback; +} #ifndef SWIG /* some bad declarations */ diff --git a/daemon/src/managerimpl.cpp b/daemon/src/managerimpl.cpp index 5db474beb65dfb02da00c877e0873ffcf42ba4db..d4ecdc3e353a904f7407ccae0e1ab927d826758c 100644 --- a/daemon/src/managerimpl.cpp +++ b/daemon/src/managerimpl.cpp @@ -95,6 +95,10 @@ extern JavaVM *gJavaVM; static jobject gManagerObject, gDataObject; +extern struct callmanager_callback wrapper_callback_struct; +extern void on_incoming_call_wrapper (const std::string& accountID, + const std::string& callID, + const std::string& from); ManagerImpl::ManagerImpl() : preferences(), voipPreferences(), addressbookPreference(), @@ -1644,7 +1648,8 @@ void ManagerImpl::incomingCall(Call &call, const std::string& accountId) #if HAVE_DBUS dbus_.getCallManager()->incomingCall(accountId, callID, call.getDisplayName() + " " + from); #else - incoming_call(accountId, callID, call.getDisplayName() + " " + from); + //incoming_call(accountId, callID, call.getDisplayName() + " " + from); + on_incoming_call_wrapper(accountId, callID, call.getDisplayName() + " " + from); #endif }