Select Git revision
-
fix preferences set in first plugin loading small logic changes in libraries loading related to: https://review.jami.net/c/ring-project/+/14433 Change-Id: I4730f279ee38d337e3ef94dd9562a5dfc1a63c32
fix preferences set in first plugin loading small logic changes in libraries loading related to: https://review.jami.net/c/ring-project/+/14433 Change-Id: I4730f279ee38d337e3ef94dd9562a5dfc1a63c32
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
managerimpl.cpp 59.95 KiB
/*
* Copyright (C) 2004-2007 Savoir-Faire Linux inc.
* Author: Alexandre Bourget <alexandre.bourget@savoirfairelinux.com>
* Author: Yan Morin <yan.morin@savoirfairelinux.com>
* Author: Laurielle Lea <laurielle.lea@savoirfairelinux.com>
* Author: Emmanuel Milou <emmanuel.milou@savoirfairelinux.com>
* Author: Guillaume Carmel-Archambault <guillaume.carmel-archambault@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.
*/
#include <errno.h>
#include <time.h>
#include <cstdlib>
#include <iostream>
#include <fstream>
#include <sys/types.h> // mkdir(2)
#include <sys/stat.h> // mkdir(2)
#include <cc++/socket.h> // why do I need this here?
#include <ccrtp/channel.h> // why do I need this here?
#include <ccrtp/rtp.h> // why do I need this here?
#include <cc++/file.h>
#include "manager.h"
#include "account.h"
#include "audio/audiolayer.h"
#include "audio/tonelist.h"
#include "accountcreator.h" // create new account
#include "voiplink.h"
#include "user_cfg.h"
#include "contact/presencestatus.h"
#ifdef USE_ZEROCONF
#include "zeroconf/DNSService.h"
#include "zeroconf/DNSServiceTXTRecord.h"
#endif
#define fill_config_str(name, value) \
(_config.addConfigTreeItem(section, Conf::ConfigTreeItem(std::string(name), std::string(value), type_str)))
#define fill_config_int(name, value) \
(_config.addConfigTreeItem(section, Conf::ConfigTreeItem(std::string(name), std::string(value), type_int)))
ManagerImpl::ManagerImpl (void)
{
// Init private variables
_hasZeroconf = false;
#ifdef USE_ZEROCONF
_hasZeroconf = true;
_DNSService = new DNSService();
#endif
// setup
_path = "";
_exist = 0;
_setupLoaded = false;
_dbus = NULL;
// sound
_audiodriver = NULL;
_dtmfKey = 0;
_spkr_volume = 0; // Initialize after by init() -> initVolume()
_mic_volume = 0; // Initialize after by init() -> initVolume()
_mic_volume_before_mute = 0;
// Call
_nbIncomingWaitingCall=0;
_hasTriedToRegister = false;
// initialize random generator for call id
srand (time(NULL));
#ifdef TEST
testAccountMap();
loadAccountMap();
testCallAccountMap();
unloadAccountMap();
#endif
// should be call before initConfigFile
// loadAccountMap();, called in init() now.
}
// never call if we use only the singleton...
ManagerImpl::~ManagerImpl (void)
{
terminate();
#ifdef USE_ZEROCONF
delete _DNSService; _DNSService = 0;
#endif
//notifyErrClient( " done " );
_debug("%s stop correctly.\n", PROGNAME);
}
void
ManagerImpl::init()
{
// Load accounts, init map
loadAccountMap();
initVolume();
if (_exist == 0) {
_debug("Cannot create config file in your home directory\n");
}
initAudioDriver();
selectAudioDriver();
// Initialize the list of supported audio codecs
initAudioCodec();
getAudioInputDeviceList();
AudioLayer *audiolayer = getAudioDriver();
if (audiolayer!=0) {
unsigned int sampleRate = audiolayer->getSampleRate();
_debugInit("Load Telephone Tone");
std::string country = getConfigString(PREFERENCES, ZONE_TONE);
_telephoneTone = new TelephoneTone(country, sampleRate);
_debugInit("Loading DTMF key");
_dtmfKey = new DTMF(sampleRate);
}
// initRegisterAccounts was here, but we doing it after the gui loaded...
// the stun detection is long, so it's a better idea to do it after getEvents
initZeroconf();
}
void ManagerImpl::terminate()
{
saveConfig();
unloadAccountMap();
_debug("Unload DTMF Key\n");
delete _dtmfKey;
_debug("Unload Audio Driver\n");
delete _audiodriver; _audiodriver = NULL;
_debug("Unload Telephone Tone\n");
delete _telephoneTone; _telephoneTone = NULL;
_debug("Unload Audio Codecs\n");
_codecDescriptorMap.deleteHandlePointer();
}
bool
ManagerImpl::isCurrentCall(const CallID& callId) {
ost::MutexLock m(_currentCallMutex);
return (_currentCallId2 == callId ? true : false);
}
bool
ManagerImpl::hasCurrentCall() {
ost::MutexLock m(_currentCallMutex);
_debug("Current call ID = %s\n", _currentCallId2.c_str());
if ( _currentCallId2 != "") {
return true;
}
return false;
}
const CallID&
ManagerImpl::getCurrentCallId() {
ost::MutexLock m(_currentCallMutex);
return _currentCallId2;
}
void
ManagerImpl::switchCall(const CallID& id ) {
ost::MutexLock m(_currentCallMutex);
_currentCallId2 = id;
}
///////////////////////////////////////////////////////////////////////////////
// Management of events' IP-phone user
///////////////////////////////////////////////////////////////////////////////
/* Main Thread */
bool
ManagerImpl::outgoingCall(const std::string& accountid, const CallID& id, const std::string& to)
{
if (!accountExists(accountid)) {
_debug("! Manager Error: Outgoing Call: account doesn't exist\n");
return false;
}
if (getAccountFromCall(id) != AccountNULL) {
_debug("! Manager Error: Outgoing Call: call id already exists\n");
return false;
}
if (hasCurrentCall()) {
_debug("* Manager Info: there is currently a call, try to hold it\n");
onHoldCall(getCurrentCallId());
}
_debug("- Manager Action: Adding Outgoing Call %s on account %s\n", id.data(), accountid.data());
if ( getAccountLink(accountid)->newOutgoingCall(id, to) ) {
associateCallToAccount( id, accountid );
switchCall(id);
return true;
} else {
_debug("! Manager Error: An error occur, the call was not created\n");
}
return false;
}
//THREAD=Main : for outgoing Call
bool
ManagerImpl::answerCall(const CallID& id)
{
stopTone(false);
/*if (hasCurrentCall())
{
onHoldCall(getCurrentCallId());
}*/
AccountID accountid = getAccountFromCall( id );
if (accountid == AccountNULL) {
_debug("Answering Call: Call doesn't exists\n");
return false;
}
if (!getAccountLink(accountid)->answer(id)) {
// error when receiving...
removeCallAccount(id);
return false;
}
//Place current call on hold if it isn't
// if it was waiting, it's waiting no more
if (_dbus) _dbus->getCallManager()->callStateChanged(id, "CURRENT");
removeWaitingCall(id);
switchCall(id);
return true;
}
//THREAD=Main
bool
ManagerImpl::sendTextMessage(const AccountID& accountId, const std::string& to, const std::string& message)
{
if (accountExists(accountId)) {
return getAccountLink(accountId)->sendMessage(to, message);
}
return false;
}
//THREAD=Main
bool
ManagerImpl::hangupCall(const CallID& id)
{
stopTone(true);
if (_dbus) _dbus->getCallManager()->callStateChanged(id, "HUNGUP");
AccountID accountid = getAccountFromCall( id );
if (accountid == AccountNULL) {
/** @todo We should tell the GUI that the call doesn't exist, so
* it clears up. This can happen. */
_debug("! Manager Hangup Call: Call doesn't exists\n");
return false;
}
bool returnValue = getAccountLink(accountid)->hangup(id);
removeCallAccount(id);
switchCall("");
return returnValue;
}
//THREAD=Main
bool
ManagerImpl::cancelCall (const CallID& id)
{
stopTone(true);
AccountID accountid = getAccountFromCall( id );
if (accountid == AccountNULL) {
_debug("! Manager Cancel Call: Call doesn't exists\n");
return false;
}
bool returnValue = getAccountLink(accountid)->cancel(id);
// it could be a waiting call?
removeWaitingCall(id);
removeCallAccount(id);
switchCall("");
return returnValue;
}
//THREAD=Main
bool
ManagerImpl::onHoldCall(const CallID& id)
{
stopTone(true);
AccountID accountid = getAccountFromCall( id );
if (accountid == AccountNULL) {
_debug("5 Manager On Hold Call: Account ID %s or callid %s desn't exists\n", accountid.c_str(), id.c_str());
return false;
}
_debug("Setting ONHOLD, Account %s, callid %s\n", accountid.c_str(), id.c_str());
bool returnValue = getAccountLink(accountid)->onhold(id);
removeWaitingCall(id);
if (_dbus) _dbus->getCallManager()->callStateChanged(id, "HOLD");
switchCall("");
return returnValue;
}
//THREAD=Main
bool
ManagerImpl::offHoldCall(const CallID& id)
{
stopTone(false);
AccountID accountid = getAccountFromCall( id );
if (accountid == AccountNULL) {
_debug("5 Manager OffHold Call: Call doesn't exists\n");
return false;
}
//Place current call on hold if it isn't
if (hasCurrentCall())
{
onHoldCall(getCurrentCallId());
}
_debug("Setting OFFHOLD, Account %s, callid %s\n", accountid.c_str(), id.c_str());
bool returnValue = getAccountLink(accountid)->offhold(id);
if (_dbus) _dbus->getCallManager()->callStateChanged(id, "UNHOLD");
switchCall(id);
if (returnValue) {
try {
//getAudioDriver()->startStream();
} catch(...) {
_debugException("! Manager Off hold could not start audio stream");
}
}
return returnValue;
}
//THREAD=Main
bool
ManagerImpl::transferCall(const CallID& id, const std::string& to)
{
stopTone(true);
AccountID accountid = getAccountFromCall( id );
if (accountid == AccountNULL) {
_debug("! Manager Transfer Call: Call doesn't exists\n");
return false;
}
bool returnValue = getAccountLink(accountid)->transfer(id, to);
removeWaitingCall(id);
removeCallAccount(id);
if (_dbus) _dbus->getCallManager()->callStateChanged(id, "HUNGUP");
switchCall("");
return returnValue;
}
//THREAD=Main
void
ManagerImpl::mute() {
_mic_volume_before_mute = _mic_volume;
setMicVolume(0);
}
//THREAD=Main
void
ManagerImpl::unmute() {
if ( _mic_volume == 0 ) {
setMicVolume(_mic_volume_before_mute);
}
}
//THREAD=Main : Call:Incoming
bool
ManagerImpl::refuseCall (const CallID& id)
{
stopTone(true);
AccountID accountid = getAccountFromCall( id );
if (accountid == AccountNULL) {
_debug("! Manager OffHold Call: Call doesn't exists\n");
return false;
}
bool returnValue = getAccountLink(accountid)->refuse(id);
// if the call was outgoing or established, we didn't refuse it
// so the method did nothing
if (returnValue) {
removeWaitingCall(id);
removeCallAccount(id);
if (_dbus) _dbus->getCallManager()->callStateChanged(id, "HUNGUP");
switchCall("");
}
return returnValue;
}
//THREAD=Main
bool
ManagerImpl::saveConfig (void)
{
_debug("Saving Configuration...\n");
setConfig(AUDIO, VOLUME_SPKR, getSpkrVolume());
setConfig(AUDIO, VOLUME_MICRO, getMicVolume());
_setupLoaded = _config.saveConfigTree(_path.data());
return _setupLoaded;
}
//THREAD=Main
bool
ManagerImpl::initRegisterAccounts()
{
_debugInit("Initiate VoIP Links Registration");
AccountMap::iterator iter = _accountMap.begin();
while( iter != _accountMap.end() ) {
if ( iter->second) {
iter->second->loadConfig();
if ( iter->second->isEnabled() ) {
// NOW
iter->second->registerVoIPLink();
iter->second->loadContacts();
iter->second->publishPresence(PRESENCE_ONLINE);
iter->second->subscribeContactsPresence();
}
}
iter++;
}
// calls the client notification here in case of errors at startup...
if( _audiodriver -> getErrorMessage() != "" )
notifyErrClient( _audiodriver -> getErrorMessage() );
return true;
}
//THREAD=Main
// Currently unused
bool
ManagerImpl::registerAccount(const AccountID& accountId)
{
_debug("Register one VoIP Link\n");
// right now, we don't support two SIP account
// so we close everything before registring a new account
Account* account = getAccount(accountId);
if (account != 0) {
AccountMap::iterator iter = _accountMap.begin();
while ( iter != _accountMap.end() ) {
if ( iter->second ) {
iter->second->unregisterVoIPLink();
}
iter++;
}
// NOW
account->registerVoIPLink();
account->loadContacts();
account->publishPresence(PRESENCE_ONLINE);
account->subscribeContactsPresence();
}
return true;
}
//THREAD=Main
// Currently unused
bool
ManagerImpl::unregisterAccount(const AccountID& accountId)
{
_debug("Unregister one VoIP Link\n");
if (accountExists( accountId ) ) {
getAccount(accountId)->unregisterVoIPLink();
}
return true;
}
//THREAD=Main
bool
ManagerImpl::sendDtmf(const CallID& id, char code)
{
AccountID accountid = getAccountFromCall( id );
if (accountid == AccountNULL) {
//_debug("Send DTMF: call doesn't exists\n");
playDtmf(code, false);
return false;
}
int sendType = getConfigInt(SIGNALISATION, SEND_DTMF_AS);
bool returnValue = false;
switch (sendType) {
case 0: // SIP INFO
playDtmf(code , true);
returnValue = getAccountLink(accountid)->carryingDTMFdigits(id, code);
break;
case 1: // Audio way
break;
case 2: // rfc 2833
break;
default: // unknown - error config?
break;
}
return returnValue;
}
//THREAD=Main | VoIPLink
bool
ManagerImpl::playDtmf(char code, bool isTalking)
{
// HERE are the variable:
// - boolean variable to play or not (config)
// - length in milliseconds to play
// - sample of audiolayer
stopTone(false);
int hasToPlayTone = getConfigInt(SIGNALISATION, PLAY_DTMF);
if (!hasToPlayTone) return false;
// length in milliseconds
int pulselen = getConfigInt(SIGNALISATION, PULSE_LENGTH);
if (!pulselen) { return false; }
// numbers of int = length in milliseconds / 1000 (number of seconds)
// = number of seconds * SAMPLING_RATE by SECONDS
AudioLayer* audiolayer = getAudioDriver();
// fast return, no sound, so no dtmf
if (audiolayer==0 || _dtmfKey == 0) { return false; }
// number of data sampling in one pulselen depends on samplerate
// size (n sampling) = time_ms * sampling/s
// ---------------------
// ms/s
int size = (int)(pulselen * ((float)audiolayer->getSampleRate()/1000));
// this buffer is for mono
// TODO <-- this should be global and hide if same size
SFLDataFormat* _buf = new SFLDataFormat[size];
bool returnValue = false;
// Handle dtmf
_dtmfKey->startTone(code);
// copy the sound
if ( _dtmfKey->generateDTMF(_buf, size) ) {
// Put buffer to urgentRingBuffer
// put the size in bytes...
// so size * 1 channel (mono) * sizeof (bytes for the data)
audiolayer->playSamples(_buf, size * sizeof(SFLDataFormat), isTalking);
//audiolayer->putUrgent(_buf, size * sizeof(SFLDataFormat));
// We activate the stream if it's not active yet.
//if (!audiolayer->isStreamActive()) {
//audiolayer->startStream();
//} else {
//_debugAlsa("send dtmf - sleep\n");
//audiolayer->sleep(pulselen); // in milliseconds
//}
}
returnValue = true;
// TODO: add caching
delete[] _buf; _buf = 0;
return returnValue;
}
// Multi-thread
bool
ManagerImpl::incomingCallWaiting() {
ost::MutexLock m(_waitingCallMutex);
return (_nbIncomingWaitingCall > 0) ? true : false;
}
void
ManagerImpl::addWaitingCall(const CallID& id) {
ost::MutexLock m(_waitingCallMutex);
_waitingCall.insert(id);
_nbIncomingWaitingCall++;
}
void
ManagerImpl::removeWaitingCall(const CallID& id) {
ost::MutexLock m(_waitingCallMutex);
// should return more than 1 if it erase a call
if (_waitingCall.erase(id)) {
_nbIncomingWaitingCall--;
}
}
bool
ManagerImpl::isWaitingCall(const CallID& id) {
ost::MutexLock m(_waitingCallMutex);
CallIDSet::iterator iter = _waitingCall.find(id);
if (iter != _waitingCall.end()) {
return false;
}
return true;
}
///////////////////////////////////////////////////////////////////////////////
// Management of event peer IP-phone
////////////////////////////////////////////////////////////////////////////////
// SipEvent Thread
bool
ManagerImpl::incomingCall(Call* call, const AccountID& accountId)
{
_debug("Incoming call\n");
associateCallToAccount(call->getCallId(), accountId);
if ( !hasCurrentCall() ) {
call->setConnectionState(Call::Ringing);
ringtone();
switchCall(call->getCallId());
} else {
addWaitingCall(call->getCallId());
}
std::string from = call->getPeerName();
std::string number = call->getPeerNumber();
if (from != "" && number != "") {
from.append(" <");
from.append(number);
from.append(">");
} else if ( from.empty() ) {
from.append("<");
from.append(number);
from.append(">");
}
_dbus->getCallManager()->incomingCall(accountId, call->getCallId(), from);
return true;
}
//THREAD=VoIP
void
ManagerImpl::incomingMessage(const AccountID& accountId, const std::string& message) {
if (_dbus) {
_dbus->getCallManager()->incomingMessage(accountId, message);
}
}
//THREAD=VoIP CALL=Outgoing
void
ManagerImpl::peerAnsweredCall(const CallID& id)
{
if (isCurrentCall(id)) {
stopTone(false);
}
if (_dbus) _dbus->getCallManager()->callStateChanged(id, "CURRENT");
}
//THREAD=VoIP Call=Outgoing
void
ManagerImpl::peerRingingCall(const CallID& id)
{
if (isCurrentCall(id)) {
ringback();
}
if (_dbus) _dbus->getCallManager()->callStateChanged(id, "RINGING");
}
//THREAD=VoIP Call=Outgoing/Ingoing
void
ManagerImpl::peerHungupCall(const CallID& id)
{
AccountID accountid = getAccountFromCall( id );
if (accountid == AccountNULL) {
_debug("peerHungupCall: Call doesn't exists\n");
return;
}
if (_dbus) _dbus->getCallManager()->callStateChanged(id, "HUNGUP");
if (isCurrentCall(id)) {
stopTone(true);
switchCall("");
}
removeWaitingCall(id);
removeCallAccount(id);
}
//THREAD=VoIP
void
ManagerImpl::callBusy(const CallID& id) {
_debug("Call busy\n");
if (_dbus) _dbus->getCallManager()->callStateChanged(id, "BUSY");
if (isCurrentCall(id) ) {
playATone(Tone::TONE_BUSY);
switchCall("");
}
removeCallAccount(id);
removeWaitingCall(id);
}
//THREAD=VoIP
void
ManagerImpl::callFailure(const CallID& id)
{
if (_dbus) _dbus->getCallManager()->callStateChanged(id, "FAILURE");
_debug("CALL ID = %s\n" , id.c_str());
if (isCurrentCall(id) ) {
playATone(Tone::TONE_BUSY);
switchCall("");
}
removeCallAccount(id);
removeWaitingCall(id);
}
//THREAD=VoIP
void
ManagerImpl::displayTextMessage(const CallID& id, const std::string& message)
{
/*if(_gui) {
_gui->displayTextMessage(id, message);
}*/
}
//THREAD=VoIP
void
ManagerImpl::displayErrorText(const CallID& id, const std::string& message)
{
/*if(_gui) {
_gui->displayErrorText(id, message);
} else {
std::cerr << message << std::endl;
}*/
}
//THREAD=VoIP
void
ManagerImpl::displayError (const std::string& error)
{
/*if(_gui) {
_gui->displayError(error);
}*/
}
//THREAD=VoIP
void
ManagerImpl::displayStatus(const std::string& status)
{
/*if(_gui) {
_gui->displayStatus(status);
}*/
}
//THREAD=VoIP
void
ManagerImpl::displayConfigError (const std::string& message)
{
/*if(_gui) {
_gui->displayConfigError(message);
}*/
}
//THREAD=VoIP
void
ManagerImpl::startVoiceMessageNotification(const AccountID& accountId, const std::string& nb_msg)
{
if (_dbus) _dbus->getCallManager()->voiceMailNotify(accountId, atoi(nb_msg.c_str()) );
}
//THREAD=VoIP
void
ManagerImpl::stopVoiceMessageNotification(const AccountID& accountId)
{
if (_dbus) _dbus->getCallManager()->voiceMailNotify(accountId, 0 );
}
//THREAD=VoIP
void
ManagerImpl::registrationSucceed(const AccountID& accountid)
{
Account* acc = getAccount(accountid);
if ( acc ) {
//acc->setState(true);
if (_dbus) _dbus->getConfigurationManager()->accountsChanged();
}
}
//THREAD=VoIP
void
ManagerImpl::registrationFailed(const AccountID& accountid)
{
Account* acc = getAccount(accountid);
if ( acc ) {
//acc->setState(false);
if (_dbus) _dbus->getConfigurationManager()->accountsChanged();
}
}
/**
* Multi Thread
*/
bool
ManagerImpl::playATone(Tone::TONEID toneId) {
int hasToPlayTone = getConfigInt(SIGNALISATION, PLAY_TONES);
if (!hasToPlayTone) return false;
if (_telephoneTone != 0) {
_toneMutex.enterMutex();
_telephoneTone->setCurrentTone(toneId);
_toneMutex.leaveMutex();
AudioLoop* audioloop = getTelephoneTone();
unsigned int nbSampling = audioloop->getSize();
AudioLayer* audiolayer = getAudioDriver();
SFLDataFormat buf[nbSampling];
if ( audiolayer ) {
audiolayer->putUrgent( buf, nbSampling );
}
else
return false;
}
return true;
}
/**
* Multi Thread
*/
void
ManagerImpl::stopTone(bool stopAudio=true) {
int hasToPlayTone = getConfigInt(SIGNALISATION, PLAY_TONES);
if (!hasToPlayTone) return;
if (stopAudio) {
AudioLayer* audiolayer = getAudioDriver();
if (audiolayer) { audiolayer->stopStream(); }
}
_toneMutex.enterMutex();
if (_telephoneTone != 0) {
_telephoneTone->setCurrentTone(Tone::TONE_NULL);
}
_toneMutex.leaveMutex();
// for ringing tone..
_toneMutex.enterMutex();
_audiofile.stop();
_toneMutex.leaveMutex();
}
/**
* Multi Thread
*/
bool
ManagerImpl::playTone()
{
playATone(Tone::TONE_DIALTONE);
}
/**
* Multi Thread
*/
void
ManagerImpl::congestion () {
playATone(Tone::TONE_CONGESTION);
}
/**
* Multi Thread
*/
void
ManagerImpl::ringback () {
playATone(Tone::TONE_RINGTONE);
}
/**
* Multi Thread
*/
void
ManagerImpl::ringtone()
{
// int hasToPlayTone = getConfigInt(SIGNALISATION, PLAY_TONES);
if( isRingtoneEnabled() )
{
std::string ringchoice = getConfigString(AUDIO, RING_CHOICE);
//if there is no / inside the path
if ( ringchoice.find(DIR_SEPARATOR_CH) == std::string::npos ) {
// check inside global share directory
ringchoice = std::string(PROGSHAREDIR) + DIR_SEPARATOR_STR + RINGDIR + DIR_SEPARATOR_STR + ringchoice;
}
AudioLayer* audiolayer = getAudioDriver();
if (audiolayer==0) { return; }
int sampleRate = audiolayer->getSampleRate();
AudioCodec* codecForTone = _codecDescriptorMap.getFirstCodecAvailable();
_toneMutex.enterMutex();
bool loadFile = _audiofile.loadFile(ringchoice, codecForTone , sampleRate);
_toneMutex.leaveMutex();
if (loadFile) {
_toneMutex.enterMutex();
_audiofile.start();
_toneMutex.leaveMutex();
int size = _audiofile.getSize();
SFLDataFormat output[ size ];
_audiofile.getNext(output, size , 100);
audiolayer->putUrgent( output , size );
} else {
ringback();
}
}
else
{
ringback();
}
}
AudioLoop*
ManagerImpl::getTelephoneTone()
{
if(_telephoneTone != 0) {
ost::MutexLock m(_toneMutex);
return _telephoneTone->getCurrentTone();
}
else {
return 0;
}
}
AudioLoop*
ManagerImpl::getTelephoneFile()
{
ost::MutexLock m(_toneMutex);
if(_audiofile.isStarted()) {
return &_audiofile;
} else {
return 0;
}
}
/**
* Use Urgent Buffer
* By AudioRTP thread
*/
void
ManagerImpl::notificationIncomingCall(void) {
AudioLayer* audiolayer = getAudioDriver();
if (audiolayer != 0) {
unsigned int samplerate = audiolayer->getSampleRate();
std::ostringstream frequency;
frequency << "440/" << FRAME_PER_BUFFER;
Tone tone(frequency.str(), samplerate);
unsigned int nbSampling = tone.getSize();
SFLDataFormat buf[nbSampling];
tone.getNext(buf, tone.getSize());
audiolayer->playSamples(buf, sizeof(SFLDataFormat)*nbSampling, true);
}
}
/**
* Multi Thread
*/
bool
ManagerImpl::getStunInfo (StunAddress4& stunSvrAddr, int port)
{
StunAddress4 mappedAddr;
struct in_addr in;
char* addr;
//int fd3, fd4;
// bool ok = stunOpenSocketPair(stunSvrAddr, &mappedAddr, &fd3, &fd4, port);
int fd1 = stunOpenSocket(stunSvrAddr, &mappedAddr, port);
bool ok = (fd1 == -1 || fd1 == INVALID_SOCKET) ? false : true;
if (ok) {
closesocket(fd1);
//closesocket(fd3);
//closesocket(fd4);
_firewallPort = mappedAddr.port;
// Convert ipv4 address to host byte ordering
in.s_addr = ntohl (mappedAddr.addr);
addr = inet_ntoa(in);
_firewallAddr = std::string(addr);
_debug("STUN Firewall: [%s:%d]\n", _firewallAddr.data(), _firewallPort);
return true;
} else {
_debug("Opening a stun socket pair failed\n");
}
return false;
}
bool
ManagerImpl::behindNat(const std::string& svr, int port)
{
StunAddress4 stunSvrAddr;
stunSvrAddr.addr = 0;
// Convert char* to StunAddress4 structure
bool ret = stunParseServerName ((char*)svr.data(), stunSvrAddr);
if (!ret) {
_debug("SIP: Stun server address (%s) is not valid\n", svr.data());
return 0;
}
// Firewall address
//_debug("STUN server: %s\n", svr.data());
return getStunInfo(stunSvrAddr, port);
}
///////////////////////////////////////////////////////////////////////////////
// Private functions
///////////////////////////////////////////////////////////////////////////////
/**
* Initialization: Main Thread
* @return 1: ok
-1: error directory
*/
int
ManagerImpl::createSettingsPath (void) {
_path = std::string(HOMEDIR) + DIR_SEPARATOR_STR + "." + PROGDIR;
if (mkdir (_path.data(), 0755) != 0) {
// If directory creation failed
if (errno != EEXIST) {
_debug("Cannot create directory: %s\n", strerror(errno));
return -1;
}
}
// Load user's configuration
_path = _path + DIR_SEPARATOR_STR + PROGNAME + "rc";
return 1;
}
/**
* Initialization: Main Thread
*/
void
ManagerImpl::initConfigFile (void)
{
std::string mes = gettext("Init config file\n");
_debug("%s",mes.c_str());
std::string type_str("string");
std::string type_int("int");
std::string section;
section = SIGNALISATION;
// Default values, that will be overwritten by the call to
// 'populateFromFile' below.
fill_config_int(SYMMETRIC, YES_STR);
fill_config_int(PLAY_DTMF, YES_STR);
fill_config_int(PLAY_TONES, YES_STR);
fill_config_int(PULSE_LENGTH, DFT_PULSE_LENGTH_STR);
fill_config_int(SEND_DTMF_AS, SIP_INFO_STR);
section = AUDIO;
fill_config_int(ALSA_CARD_ID_IN, ALSA_DFT_CARD);
fill_config_int(ALSA_CARD_ID_OUT, ALSA_DFT_CARD);
fill_config_int(ALSA_SAMPLE_RATE, DFT_SAMPLE_RATE);
fill_config_int(ALSA_FRAME_SIZE, DFT_FRAME_SIZE);
fill_config_str(ALSA_PLUGIN, PCM_DEFAULT);
fill_config_str(RING_CHOICE, DFT_RINGTONE);
fill_config_int(VOLUME_SPKR, DFT_VOL_SPKR_STR);
fill_config_int(VOLUME_MICRO, DFT_VOL_MICRO_STR);
section = PREFERENCES;
fill_config_str(ZONE_TONE, DFT_ZONE);
fill_config_str(VOICEMAIL_NUM, DFT_VOICEMAIL);
fill_config_int(CONFIG_ZEROCONF, CONFIG_ZEROCONF_DEFAULT_STR);
fill_config_int(CONFIG_RINGTONE, YES_STR);
// Loads config from ~/.sflphone/sflphonedrc or so..
if (createSettingsPath() == 1) {
_exist = _config.populateFromFile(_path);
}
_setupLoaded = (_exist == 2 ) ? false : true;
}
/**
* Initialization: Main Thread
*/
void
ManagerImpl::initAudioCodec (void)
{
_debugInit("Active Codecs List");
// init list of all supported codecs
_codecDescriptorMap.init();
// if the user never set the codec list, use the default configuration
if(getConfigString(AUDIO, "ActiveCodecs") == ""){
_codecDescriptorMap.setDefaultOrder();
}
// else retrieve the one set in the user config file
else{
std::vector<std::string> active_list = retrieveActiveCodecs();
setActiveCodecList(active_list);
}
}
std::vector<std::string>
ManagerImpl::retrieveActiveCodecs()
{
std::vector<std::string> order;
std::string temp;
std::string s = getConfigString(AUDIO, "ActiveCodecs");
while (s.find("/", 0) != std::string::npos)
{
size_t pos = s.find("/", 0);
temp = s.substr(0, pos);
s.erase(0, pos + 1);
order.push_back(temp);
}
return order;
}
void
ManagerImpl::setActiveCodecList(const std::vector<std::string>& list)
{
_debug("Set active codecs list\n");
_codecDescriptorMap.saveActiveCodecs(list);
// setConfig
std::string s = serialize(list);
printf("%s\n", s.c_str());
setConfig("Audio", "ActiveCodecs", s);
}
std::string
ManagerImpl::serialize(std::vector<std::string> v)
{
int i;
std::string res;
for(i=0;i<v.size();i++)
{
res += v[i] + "/";
}
return res;
}
std::vector <std::string>
ManagerImpl::getActiveCodecList( void )
{
_debug("Get Active codecs list\n");
std::vector< std::string > v;
CodecOrder active = _codecDescriptorMap.getActiveCodecs();
int i=0;
size_t size = active.size();
while(i<size)
{
std::stringstream ss;
ss << active[i];
v.push_back((ss.str()).data());
i++;
}
return v;
}
/**
* Send the list of codecs to the client through DBus.
*/
std::vector< std::string >
ManagerImpl::getCodecList( void )
{
std::vector<std::string> list;
//CodecMap codecs = _codecDescriptorMap.getCodecMap();
CodecsMap codecs = _codecDescriptorMap.getCodecsMap();
CodecOrder order = _codecDescriptorMap.getActiveCodecs();
CodecsMap::iterator iter = codecs.begin();
while(iter!=codecs.end())
{
std::stringstream ss;
if( iter->second != NULL )
{
ss << iter->first;
list.push_back((ss.str()).data());
}
iter++;
}
return list;
}
std::vector<std::string>
ManagerImpl::getCodecDetails( const ::DBus::Int32& payload )
{
std::vector<std::string> v;
std::stringstream ss;
v.push_back(_codecDescriptorMap.getCodecName((AudioCodecType)payload));
ss << _codecDescriptorMap.getSampleRate((AudioCodecType)payload);
v.push_back((ss.str()).data());
ss.str("");
ss << _codecDescriptorMap.getBitRate((AudioCodecType)payload);
v.push_back((ss.str()).data());
ss.str("");
ss << _codecDescriptorMap.getBandwidthPerCall((AudioCodecType)payload);
v.push_back((ss.str()).data());
ss.str("");
return v;
}
/**
* Get list of supported input audio plugin
*/
std::vector<std::string>
ManagerImpl::getInputAudioPluginList(void)
{
std::vector<std::string> v;
_debug("Get input audio plugin list");
v.push_back("default");
v.push_back("surround40");
v.push_back("plug:hw");
return v;
}
/**
* Get list of supported output audio plugin
*/
std::vector<std::string>
ManagerImpl::getOutputAudioPluginList(void)
{
std::vector<std::string> v;
_debug("Get output audio plugin list");
v.push_back( PCM_DEFAULT );
v.push_back( PCM_PLUGHW );
v.push_back( PCM_DMIX );
return v;
}
/**
* Set input audio plugin
*/
void
ManagerImpl::setInputAudioPlugin(const std::string& audioPlugin)
{
_debug("Set input audio plugin\n");
_audiodriver -> setErrorMessage( "" );
_audiodriver -> openDevice( _audiodriver -> getIndexIn(),
_audiodriver -> getIndexOut(),
_audiodriver -> getSampleRate(),
_audiodriver -> getFrameSize(),
SFL_PCM_CAPTURE,
audioPlugin);
if( _audiodriver -> getErrorMessage() != "")
notifyErrClient( _audiodriver -> getErrorMessage() );
}
/**
* Set output audio plugin
*/
void
ManagerImpl::setOutputAudioPlugin(const std::string& audioPlugin)
{
_debug("Set output audio plugin\n");
_audiodriver -> setErrorMessage( "" );
_audiodriver -> openDevice( _audiodriver -> getIndexIn(),
_audiodriver -> getIndexOut(),
_audiodriver -> getSampleRate(),
_audiodriver -> getFrameSize(),
SFL_PCM_BOTH,
audioPlugin);
if( _audiodriver -> getErrorMessage() != "")
notifyErrClient( _audiodriver -> getErrorMessage() );
// set config
setConfig( AUDIO , ALSA_PLUGIN , audioPlugin );
}
/**
* Get list of supported audio output device
*/
std::vector<std::string>
ManagerImpl::getAudioOutputDeviceList(void)
{
_debug("Get audio output device list\n");
return _audiodriver -> getSoundCardsInfo(SFL_PCM_PLAYBACK);
}
/**
* Set audio output device
*/
void
ManagerImpl::setAudioOutputDevice(const int index)
{
_debug("Set audio output device: %i\n", index);
_audiodriver -> setErrorMessage( "" );
_audiodriver->openDevice(_audiodriver->getIndexIn(),
index,
_audiodriver->getSampleRate(),
_audiodriver->getFrameSize(),
SFL_PCM_PLAYBACK,
_audiodriver->getAudioPlugin());
if( _audiodriver -> getErrorMessage() != "")
notifyErrClient( _audiodriver -> getErrorMessage() );
// set config
setConfig( AUDIO , ALSA_CARD_ID_OUT , index );
}
/**
* Get list of supported audio input device
*/
std::vector<std::string>
ManagerImpl::getAudioInputDeviceList(void)
{
_debug("Get audio input device list\n");
return _audiodriver->getSoundCardsInfo(SFL_PCM_CAPTURE);
}
/**
* Set audio input device
*/
void
ManagerImpl::setAudioInputDevice(const int index)
{
_debug("Set audio input device %i\n", index);
_audiodriver -> setErrorMessage( "" );
_audiodriver->openDevice(index,
_audiodriver->getIndexOut(),
_audiodriver->getSampleRate(),
_audiodriver->getFrameSize(),
SFL_PCM_CAPTURE,
_audiodriver->getAudioPlugin());
if( _audiodriver -> getErrorMessage() != "")
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\n");
std::vector<std::string> v;
std::stringstream ssi , sso;
sso << _audiodriver->getIndexOut();
v.push_back( sso.str() );
ssi << _audiodriver->getIndexIn();
v.push_back( ssi.str() );
return v;
}
int
ManagerImpl::isIax2Enabled( void )
{
//return ( IAX2_ENABLED ) ? true : false;
#ifdef USE_IAX
return true;
#else
return false;
#endif
}
int
ManagerImpl::isRingtoneEnabled( void )
{
return getConfigInt( PREFERENCES , CONFIG_RINGTONE );
}
void
ManagerImpl::ringtoneEnabled( void )
{
( getConfigInt( PREFERENCES , CONFIG_RINGTONE ) == RINGTONE_ENABLED )? setConfig(PREFERENCES , CONFIG_RINGTONE , NO_STR ) : setConfig( PREFERENCES , CONFIG_RINGTONE , YES_STR );
}
std::string
ManagerImpl::getRingtoneChoice( void )
{
// we need the absolute path
std::string tone_name = getConfigString( AUDIO , RING_CHOICE );
std::string tone_path ;
if( tone_name.find( DIR_SEPARATOR_CH ) == std::string::npos )
{
// check in ringtone directory ($(PREFIX)/share/sflphone/ringtones)
tone_path = std::string(PROGSHAREDIR) + DIR_SEPARATOR_STR + RINGDIR + DIR_SEPARATOR_STR + tone_name ;
}
else
{
// the absolute has been saved; do nothing
tone_path = tone_name ;
}
_debug("%s\n", tone_path.c_str());
return tone_path;
}
void
ManagerImpl::setRingtoneChoice( const std::string& tone )
{
// we save the absolute path
setConfig( AUDIO , RING_CHOICE , tone );
}
void
ManagerImpl::notifyErrClient( const std::string& errMsg )
{
if( _dbus ) {
_debug("Call notifyErrClient: %s\n" , errMsg.c_str());
_dbus -> getConfigurationManager() -> errorAlert( errMsg , 0 );
}
}
int
ManagerImpl::getAudioDeviceIndex(const std::string name)
{
_debug("Get audio device index\n");
int num = _audiodriver -> soundCardGetIndex( name );
return num;
}
std::string
ManagerImpl::getCurrentAudioOutputPlugin( void )
{
_debug("Get alsa plugin\n");
return _audiodriver -> getAudioPlugin();
}
/**
* Initialization: Main Thread
*/
void
ManagerImpl::initAudioDriver(void)
{
_debugInit("AudioLayer Creation");
_audiodriver = new AudioLayer(this);
if (_audiodriver == 0) {
_debug("Init audio driver error\n");
} else {
std::string error = getAudioDriver()->getErrorMessage();
if (!error.empty()) {
_debug("Init audio driver: %s\n", error.c_str());
}
}
}
/**
* Initialization: Main Thread and gui
*/
void
ManagerImpl::selectAudioDriver (void)
{
std::string alsaPlugin = getConfigString( AUDIO , ALSA_PLUGIN );
int numCardIn = getConfigInt( AUDIO , ALSA_CARD_ID_IN );
int numCardOut = getConfigInt( AUDIO , ALSA_CARD_ID_OUT );
int sampleRate = getConfigInt( AUDIO , ALSA_SAMPLE_RATE );
if (sampleRate <=0 || sampleRate > 48000) {
sampleRate = 44100;
}
int frameSize = getConfigInt( AUDIO , ALSA_FRAME_SIZE );
if( !_audiodriver -> soundCardIndexExist( numCardIn , SFL_PCM_CAPTURE ) )
{
_debug(" Card with index %i doesn't exist or cannot capture. Switch to 0.\n", numCardIn);
numCardIn = ALSA_DFT_CARD_ID ;
setConfig( AUDIO , ALSA_CARD_ID_IN , ALSA_DFT_CARD_ID );
}
if( !_audiodriver -> soundCardIndexExist( numCardOut , SFL_PCM_PLAYBACK ) )
{
_debug(" Card with index %i doesn't exist or cannot playback . Switch to 0.\n", numCardOut);
numCardOut = ALSA_DFT_CARD_ID ;
setConfig( AUDIO , ALSA_CARD_ID_OUT , ALSA_DFT_CARD_ID );
}
_debugInit(" AudioLayer Opening Device");
_audiodriver->setErrorMessage("");
_audiodriver->openDevice( numCardIn , numCardOut, sampleRate, frameSize, SFL_PCM_BOTH, alsaPlugin );
if( _audiodriver -> getErrorMessage() != "")
notifyErrClient( _audiodriver -> getErrorMessage());
}
/**
* Initialize the Zeroconf scanning services loop
* Informations will be store inside a map DNSService->_services
* Initialization: Main Thread
*/
void
ManagerImpl::initZeroconf(void)
{
#ifdef USE_ZEROCONF
_debugInit("Zeroconf Initialization");
int useZeroconf = getConfigInt(PREFERENCES, CONFIG_ZEROCONF);
if (useZeroconf) {
_DNSService->startScanServices();
}
#endif
}
/**
* Init the volume for speakers/micro from 0 to 100 value
* Initialization: Main Thread
*/
void
ManagerImpl::initVolume()
{
_debugInit("Initiate Volume");
setSpkrVolume(getConfigInt(AUDIO, VOLUME_SPKR));
setMicVolume(getConfigInt(AUDIO, VOLUME_MICRO));
}
/**
* configuration function requests
* Main Thread
*/
bool
ManagerImpl::getZeroconf(const std::string& sequenceId)
{
bool returnValue = false;
#ifdef USE_ZEROCONF
int useZeroconf = getConfigInt(PREFERENCES, CONFIG_ZEROCONF);
if (useZeroconf && _dbus != NULL) {
TokenList arg;
TokenList argTXT;
std::string newService = "new service";
std::string newTXT = "new txt record";
if (!_DNSService->isStart()) { _DNSService->startScanServices(); }
DNSServiceMap services = _DNSService->getServices();
DNSServiceMap::iterator iter = services.begin();
arg.push_back(newService);
while(iter!=services.end()) {
arg.push_front(iter->first);
//_gui->sendMessage("100",sequenceId,arg);
arg.pop_front(); // remove the first, the name
TXTRecordMap record = iter->second.getTXTRecords();
TXTRecordMap::iterator iterTXT = record.begin();
while(iterTXT!=record.end()) {
argTXT.clear();
argTXT.push_back(iter->first);
argTXT.push_back(iterTXT->first);
argTXT.push_back(iterTXT->second);
argTXT.push_back(newTXT);
// _gui->sendMessage("101",sequenceId,argTXT);
iterTXT++;
}
iter++;
}
returnValue = true;
}
#else
(void)sequenceId;
#endif
return returnValue;
}
/**
* Main Thread
*/
bool
ManagerImpl::attachZeroconfEvents(const std::string& sequenceId, Pattern::Observer& observer)
{
bool returnValue = false;
// don't need the _gui like getZeroconf function
// because Observer is here
#ifdef USE_ZEROCONF
int useZeroconf = getConfigInt(PREFERENCES, CONFIG_ZEROCONF);
if (useZeroconf) {
if (!_DNSService->isStart()) { _DNSService->startScanServices(); }
_DNSService->attach(observer);
returnValue = true;
}
#else
(void)sequenceId;
(void)observer;
#endif
return returnValue;
}
bool
ManagerImpl::detachZeroconfEvents(Pattern::Observer& observer)
{
bool returnValue = false;
#ifdef USE_ZEROCONF
if (_DNSService) {
_DNSService->detach(observer);
returnValue = true;
}
#else
(void)observer;
#endif
return returnValue;
}
/**
* Main Thread
*
* @todo When is this called ? Why this name 'getEvents' ?
*/
/**
* DEPRECATED
bool
ManagerImpl::getEvents() {
initRegisterAccounts();
return true;
}
*/
// TODO: rewrite this
/**
* Main Thread
*/
bool
ManagerImpl::getCallStatus(const std::string& sequenceId)
{
if (!_dbus) { return false; }
ost::MutexLock m(_callAccountMapMutex);
CallAccountMap::iterator iter = _callAccountMap.begin();
TokenList tk;
std::string code;
std::string status;
std::string destination;
std::string number;
while (iter != _callAccountMap.end())
{
Call* call = getAccountLink(iter->second)->getCall(iter->first);
Call::ConnectionState state = call->getConnectionState();
if (state != Call::Connected) {
switch(state) {
case Call::Trying: code="110"; status = "Trying"; break;
case Call::Ringing: code="111"; status = "Ringing"; break;
case Call::Progressing: code="125"; status = "Progressing"; break;
case Call::Disconnected: code="125"; status = "Disconnected"; break;
default: code=""; status= "";
}
} else {
switch (call->getState()) {
case Call::Active: code="112"; status = "Established"; break;
case Call::Hold: code="114"; status = "Held"; break;
case Call::Busy: code="113"; status = "Busy"; break;
case Call::Refused: code="125"; status = "Refused"; break;
case Call::Error: code="125"; status = "Error"; break;
case Call::Inactive: code="125"; status = "Inactive"; break;
}
}
// No Congestion
// No Wrong Number
// 116 <CSeq> <call-id> <acc> <destination> Busy
destination = call->getPeerName();
number = call->getPeerNumber();
if (number!="") {
destination.append(" <");
destination.append(number);
destination.append(">");
}
tk.push_back(iter->second);
tk.push_back(destination);
tk.push_back(status);
//_gui->sendCallMessage(code, sequenceId, iter->first, tk);
tk.clear();
iter++;
}
return true;
}
//THREAD=Main
/* Unused, Deprecated */
bool
ManagerImpl::getConfigAll(const std::string& sequenceId)
{
bool returnValue = false;
Conf::ConfigTreeIterator iter = _config.createIterator();
TokenList tk = iter.begin();
if (tk.size()) {
returnValue = true;
}
while (tk.size()) {
//_gui->sendMessage("100", sequenceId, tk);
tk = iter.next();
}
return returnValue;
}
//THREAD=Main
bool
ManagerImpl::getConfig(const std::string& section, const std::string& name, TokenList& arg)
{
return _config.getConfigTreeItemToken(section, name, arg);
}
//THREAD=Main
// throw an Conf::ConfigTreeItemException if not found
int
ManagerImpl::getConfigInt(const std::string& section, const std::string& name)
{
try {
return _config.getConfigTreeItemIntValue(section, name);
} catch (Conf::ConfigTreeItemException& e) {
throw e;
}
return 0;
}
//THREAD=Main
std::string
ManagerImpl::getConfigString(const std::string& section, const std::string&
name)
{
try {
return _config.getConfigTreeItemValue(section, name);
} catch (Conf::ConfigTreeItemException& e) {
throw e;
}
return "";
}
//THREAD=Main
bool
ManagerImpl::setConfig(const std::string& section, const std::string& name, const std::string& value)
{
return _config.setConfigTreeItem(section, name, value);
}
//THREAD=Main
bool
ManagerImpl::setConfig(const std::string& section, const std::string& name, int value)
{
std::ostringstream valueStream;
valueStream << value;
return _config.setConfigTreeItem(section, name, valueStream.str());
}
//THREAD=Main
bool
ManagerImpl::getAudioDeviceList(const std::string& sequenceId, int ioDeviceMask)
{
AudioLayer* audiolayer = getAudioDriver();
if (audiolayer == 0) { return false; }
bool returnValue = false;
// TODO: test when there is an error on initializing...
TokenList tk;
AudioDevice* device = 0;
int nbDevice = audiolayer->getDeviceCount();
/*
for (int index = 0; index < nbDevice; index++ ) {
device = audiolayer->getAudioDeviceInfo(index, ioDeviceMask);
if (device != 0) {
tk.clear();
std::ostringstream str; str << index; tk.push_back(str.str());
tk.push_back(device->getName());
tk.push_back(device->getApiName());
std::ostringstream rate; rate << (int)(device->getRate()); tk.push_back(rate.str());
//_gui->sendMessage("100", sequenceId, tk);
// don't forget to delete it after
delete device; device = 0;
}
}*/
returnValue = true;
std::ostringstream rate;
rate << "VARIABLE";
tk.clear();
tk.push_back(rate.str());
//_gui->sendMessage("101", sequenceId, tk);
return returnValue;
}
//THREAD=Main
bool
ManagerImpl::getCountryTones(const std::string& sequenceId)
{
// see ToneGenerator for the list...
sendCountryTone(sequenceId, 1, "North America");
sendCountryTone(sequenceId, 2, "France");
sendCountryTone(sequenceId, 3, "Australia");
sendCountryTone(sequenceId, 4, "United Kingdom");
sendCountryTone(sequenceId, 5, "Spain");
sendCountryTone(sequenceId, 6, "Italy");
sendCountryTone(sequenceId, 7, "Japan");
return true;
}
//THREAD=Main
void
ManagerImpl::sendCountryTone(const std::string& sequenceId, int index, const std::string& name) {
TokenList tk;
std::ostringstream str; str << index; tk.push_back(str.str());
tk.push_back(name);
//_gui->sendMessage("100", sequenceId, tk);
}
//THREAD=Main
bool
ManagerImpl::getDirListing(const std::string& sequenceId, const std::string& path, int *nbFile) {
TokenList tk;
try {
ost::Dir dir(path.c_str());
const char *cFileName = 0;
std::string fileName;
std::string filePathName;
while ( (cFileName=dir++) != 0 ) {
fileName = cFileName;
filePathName = path + DIR_SEPARATOR_STR + cFileName;
if (fileName.length() && fileName[0]!='.' && !ost::isDir(filePathName.c_str())) {
tk.clear();
std::ostringstream str;
str << (*nbFile);
tk.push_back(str.str());
tk.push_back(filePathName);
//_gui->sendMessage("100", sequenceId, tk);
(*nbFile)++;
}
}
return true;
} catch (...) {
// error to open file dir
return false;
}
}
std::vector< std::string >
ManagerImpl::getAccountList()
{
std::vector< std::string > v;
AccountMap::iterator iter = _accountMap.begin();
while ( iter != _accountMap.end() ) {
if ( iter->second != 0 ) {
_debug("Account List: %s\n", iter->first.data());
v.push_back(iter->first.data());
}
iter++;
}
_debug("Size: %d\n", v.size());
return v;
}
std::map< std::string, std::string >
ManagerImpl::getAccountDetails(const AccountID& accountID)
{
std::map<std::string, std::string> a;
std::string accountType;
enum VoIPLink::RegistrationState state = _accountMap[accountID]->getRegistrationState();
accountType = getConfigString(accountID, CONFIG_ACCOUNT_TYPE);
a.insert(
std::pair<std::string, std::string>(
CONFIG_ACCOUNT_ALIAS,
getConfigString(accountID, CONFIG_ACCOUNT_ALIAS)
)
);
/*a.insert(
std::pair<std::string, std::string>(
CONFIG_ACCOUNT_AUTO_REGISTER,
getConfigString(accountID, CONFIG_ACCOUNT_AUTO_REGISTER)== "1" ? "TRUE": "FALSE"
)
);*/
a.insert(
std::pair<std::string, std::string>(
CONFIG_ACCOUNT_ENABLE,
getConfigString(accountID, CONFIG_ACCOUNT_ENABLE) == "1" ? "TRUE": "FALSE"
)
);
a.insert(
std::pair<std::string, std::string>(
"Status",
(state == VoIPLink::Registered ? "REGISTERED":
(state == VoIPLink::Unregistered ? "UNREGISTERED":
(state == VoIPLink::Trying ? "TRYING":
(state == VoIPLink::Error ? "ERROR": "ERROR"))))
)
);
a.insert(
std::pair<std::string, std::string>(
CONFIG_ACCOUNT_TYPE, accountType
)
);
if (accountType == "SIP") {
a.insert(
std::pair<std::string, std::string>(
SIP_FULL_NAME,
getConfigString(accountID, SIP_FULL_NAME)
)
);
a.insert(
std::pair<std::string, std::string>(
SIP_USER_PART,
getConfigString(accountID, SIP_USER_PART)
)
);
a.insert(
std::pair<std::string, std::string>(
SIP_AUTH_NAME,
getConfigString(accountID, SIP_AUTH_NAME)
)
);
a.insert(
std::pair<std::string, std::string>(
SIP_PASSWORD,
getConfigString(accountID, SIP_PASSWORD)
)
);
a.insert(
std::pair<std::string, std::string>(
SIP_HOST_PART,
getConfigString(accountID, SIP_HOST_PART)
)
);
a.insert(
std::pair<std::string, std::string>(
SIP_PROXY,
getConfigString(accountID, SIP_PROXY)
)
);
a.insert(
std::pair<std::string, std::string>(
SIP_STUN_SERVER,
getConfigString(accountID, SIP_STUN_SERVER)
)
);
a.insert(
std::pair<std::string, std::string>(
SIP_USE_STUN,
getConfigString(accountID, SIP_USE_STUN) == "1" ? "TRUE": "FALSE"
)
);
}
else if (accountType == "IAX") {
a.insert(
std::pair<std::string, std::string>(
IAX_FULL_NAME,
getConfigString(accountID, IAX_FULL_NAME)
)
);
a.insert(
std::pair<std::string, std::string>(
IAX_HOST,
getConfigString(accountID, IAX_HOST)
)
);
a.insert(
std::pair<std::string, std::string>(
IAX_USER,
getConfigString(accountID, IAX_USER)
)
);
a.insert(
std::pair<std::string, std::string>(
IAX_PASS,
getConfigString(accountID, IAX_PASS)
)
);
}
else {
// Unknown type
_debug("Unknown account type in getAccountDetails(): %s", accountType.c_str());
}
return a;
}
void
ManagerImpl::setAccountDetails( const ::DBus::String& accountID,
const std::map< ::DBus::String, ::DBus::String >& details )
{
std::string accountType = (*details.find(CONFIG_ACCOUNT_TYPE)).second;
setConfig(accountID, CONFIG_ACCOUNT_ALIAS, (*details.find(CONFIG_ACCOUNT_ALIAS)).second);
//setConfig(accountID, CONFIG_ACCOUNT_AUTO_REGISTER,
// (*details.find(CONFIG_ACCOUNT_AUTO_REGISTER)).second == "TRUE" ? "1": "0" );
setConfig(accountID, CONFIG_ACCOUNT_ENABLE,
(*details.find(CONFIG_ACCOUNT_ENABLE)).second == "TRUE" ? "1": "0" );
setConfig(accountID, CONFIG_ACCOUNT_TYPE, accountType);
if (accountType == "SIP") {
setConfig(accountID, SIP_FULL_NAME, (*details.find(SIP_FULL_NAME)).second);
setConfig(accountID, SIP_USER_PART, (*details.find(SIP_USER_PART)).second);
setConfig(accountID, SIP_AUTH_NAME, (*details.find(SIP_AUTH_NAME)).second);
setConfig(accountID, SIP_PASSWORD, (*details.find(SIP_PASSWORD)).second);
setConfig(accountID, SIP_HOST_PART, (*details.find(SIP_HOST_PART)).second);
//setConfig(accountID, SIP_PROXY, (*details.find(SIP_PROXY)).second);
setConfig(accountID, SIP_STUN_SERVER,(*details.find(SIP_STUN_SERVER)).second);
setConfig(accountID, SIP_USE_STUN,
(*details.find(SIP_USE_STUN)).second == "TRUE" ? "1" : "0");
}
else if (accountType == "IAX") {
setConfig(accountID, IAX_FULL_NAME, (*details.find(IAX_FULL_NAME)).second);
setConfig(accountID, IAX_HOST, (*details.find(IAX_HOST)).second);
setConfig(accountID, IAX_USER, (*details.find(IAX_USER)).second);
setConfig(accountID, IAX_PASS, (*details.find(IAX_PASS)).second);
} else {
_debug("Unknown account type in setAccountDetails(): %s\n", accountType.c_str());
}
saveConfig();
/*
* register if it was just enabled, and we hadn't registered
* unregister if it was enabled/registered, and we want it closed
*/
Account* acc = getAccount(accountID);
acc->loadConfig();
if (acc->isEnabled()) {
// Verify we aren't already registered, then register
if (acc->getRegistrationState() == VoIPLink::Unregistered) {
acc->registerVoIPLink();
}
} else {
// Verify we are already registered, then unregister
if (acc->getRegistrationState() == VoIPLink::Registered) {
acc->unregisterVoIPLink();
}
}
/** @todo Make the daemon use the new settings */
if (_dbus) _dbus->getConfigurationManager()->accountsChanged();
}
void
ManagerImpl::addAccount(const std::map< ::DBus::String, ::DBus::String >& details)
{
/** @todo Deal with both the _accountMap and the Configuration */
std::string accountType = (*details.find(CONFIG_ACCOUNT_TYPE)).second;
Account* newAccount;
std::stringstream accountID;
accountID << "Account:" << time(NULL);
AccountID newAccountID = accountID.str();
/** @todo Verify the uniqueness, in case a program adds accounts, two in a row. */
if (accountType == "SIP") {
newAccount = AccountCreator::createAccount(AccountCreator::SIP_ACCOUNT, newAccountID);
}
else if (accountType == "IAX") {
newAccount = AccountCreator::createAccount(AccountCreator::IAX_ACCOUNT, newAccountID);
}
else {
_debug("Unknown %s param when calling addAccount(): %s\n", CONFIG_ACCOUNT_TYPE, accountType.c_str());
return;
}
_accountMap[newAccountID] = newAccount;
setAccountDetails(accountID.str(), details);
saveConfig();
if (_dbus) _dbus->getConfigurationManager()->accountsChanged();
}
void
ManagerImpl::removeAccount(const AccountID& accountID)
{
// Get it down and dying
Account* remAccount = getAccount(accountID);
if (remAccount) {
remAccount->unregisterVoIPLink();
_accountMap.erase(accountID);
delete remAccount;
}
_config.removeSection(accountID);
saveConfig();
if (_dbus) _dbus->getConfigurationManager()->accountsChanged();
}
std::string
ManagerImpl::getDefaultAccount()
{
std::string id;
id = getConfigString(PREFERENCES, "DefaultAccount");
_debug("Default Account = %s\n",id.c_str());
return id;
}
void
ManagerImpl::setDefaultAccount(const AccountID& accountID)
{
// we write into the Preferences section the field Default
setConfig("Preferences", "DefaultAccount", accountID);
}
//THREAD=Main
/*
* Experimental...
*/
bool
ManagerImpl::setSwitch(const std::string& switchName, std::string& message) {
AudioLayer* audiolayer = 0;
if (switchName == "audiodriver" ) {
// hangup all call here
audiolayer = getAudioDriver();
int oldSampleRate = 0;
if (audiolayer) { oldSampleRate = audiolayer->getSampleRate(); }
selectAudioDriver();
audiolayer = getAudioDriver();
if (audiolayer) {
std::string error = audiolayer->getErrorMessage();
int newSampleRate = audiolayer->getSampleRate();
if (!error.empty()) {
message = error;
return false;
}
if (newSampleRate != oldSampleRate) {
_toneMutex.enterMutex();
_debug("Unload Telephone Tone\n");
delete _telephoneTone; _telephoneTone = NULL;
_debug("Unload DTMF Key\n");
delete _dtmfKey; _dtmfKey = NULL;
_debug("Load Telephone Tone\n");
std::string country = getConfigString(PREFERENCES, ZONE_TONE);
_telephoneTone = new TelephoneTone(country, newSampleRate);
_debugInit("Loading DTMF key");
_dtmfKey = new DTMF(newSampleRate);
_toneMutex.leaveMutex();
}
message = _("Change with success");
playDtmf('9', true);
//getAudioDriver()->sleep(300); // in milliseconds
playDtmf('1', true);
//getAudioDriver()->sleep(300); // in milliseconds
playDtmf('1', true);
return true;
}
} else if ( switchName == "echo" ) {
audiolayer = getAudioDriver();
if (audiolayer) {
audiolayer->toggleEchoTesting();
return true;
}
}
return false;
}
// ACCOUNT handling
bool
ManagerImpl::associateCallToAccount(const CallID& callID, const AccountID& accountID)
{
if (getAccountFromCall(callID) == AccountNULL) { // nothing with the same ID
if ( accountExists(accountID) ) { // account id exist in AccountMap
ost::MutexLock m(_callAccountMapMutex);
_callAccountMap[callID] = accountID;
return true;
} else {
return false;
}
} else {
return false;
}
}
AccountID
ManagerImpl::getAccountFromCall(const CallID& callID)
{
ost::MutexLock m(_callAccountMapMutex);
CallAccountMap::iterator iter = _callAccountMap.find(callID);
if ( iter == _callAccountMap.end()) {
return AccountNULL;
} else {
return iter->second;
}
}
bool
ManagerImpl::removeCallAccount(const CallID& callID)
{
ost::MutexLock m(_callAccountMapMutex);
if ( _callAccountMap.erase(callID) ) {
return true;
}
return false;
}
CallID
ManagerImpl::getNewCallID()
{
std::ostringstream random_id("s");
random_id << (unsigned)rand();
// when it's not found, it return ""
// generate, something like s10000s20000s4394040
while (getAccountFromCall(random_id.str()) != AccountNULL) {
random_id.clear();
random_id << "s";
random_id << (unsigned)rand();
}
return random_id.str();
}
short
ManagerImpl::loadAccountMap()
{
_debugStart("Load account:");
short nbAccount = 0;
TokenList sections = _config.getSections();
std::string accountType;
Account* tmpAccount;
// iter = std::string
TokenList::iterator iter = sections.begin();
while(iter != sections.end()) {
// Check if it starts with "Account:" (SIP and IAX pour le moment)
if (iter->find("Account:") == -1) {
iter++;
continue;
}
accountType = getConfigString(*iter, CONFIG_ACCOUNT_TYPE);
if (accountType == "SIP") {
tmpAccount = AccountCreator::createAccount(AccountCreator::SIP_ACCOUNT, *iter);
}
else if (accountType == "IAX") {
tmpAccount = AccountCreator::createAccount(AccountCreator::IAX_ACCOUNT, *iter);
}
else {
_debug("Unknown %s param in config file (%s)\n", CONFIG_ACCOUNT_TYPE, accountType.c_str());
}
if (tmpAccount != NULL) {
_debugMid(" %s ", iter->c_str());
_accountMap[iter->c_str()] = tmpAccount;
nbAccount++;
}
_debugEnd("\n");
iter++;
}
/*
// SIP Loading X account...
short nbAccountSIP = ACCOUNT_SIP_COUNT_DEFAULT;
for (short iAccountSIP = 0; iAccountSIP<nbAccountSIP; iAccountSIP++) {
std::ostringstream accountName;
accountName << "SIP" << iAccountSIP;
tmpAccount = AccountCreator::createAccount(AccountCreator::SIP_ACCOUNT, accountName.str());
if (tmpAccount!=0) {
_debugMid(" %s", accountName.str().data());
_accountMap[accountName.str()] = tmpAccount;
nbAccount++;
}
}
// IAX Loading X account...
short nbAccountIAX = ACCOUNT_IAX_COUNT_DEFAULT;
for (short iAccountIAX = 0; iAccountIAX<nbAccountIAX; iAccountIAX++) {
std::ostringstream accountName;
accountName << "IAX" << iAccountIAX;
tmpAccount = AccountCreator::createAccount(AccountCreator::IAX_ACCOUNT, accountName.str());
if (tmpAccount!=0) {
_debugMid(" %s", accountName.str().data());
_accountMap[accountName.str()] = tmpAccount;
nbAccount++;
}
}
_debugEnd("\n");
*/
return nbAccount;
}
void
ManagerImpl::unloadAccountMap()
{
_debug("Unloading account map...\n");
AccountMap::iterator iter = _accountMap.begin();
while ( iter != _accountMap.end() ) {
_debug("-> Deleting account %s\n", iter->first.c_str());
delete iter->second; iter->second = 0;
iter++;
}
_accountMap.clear();
}
bool
ManagerImpl::accountExists(const AccountID& accountID)
{
AccountMap::iterator iter = _accountMap.find(accountID);
if ( iter == _accountMap.end() ) {
return false;
}
return true;
}
Account*
ManagerImpl::getAccount(const AccountID& accountID)
{
AccountMap::iterator iter = _accountMap.find(accountID);
if ( iter == _accountMap.end() ) {
return 0;
}
return iter->second;
}
VoIPLink*
ManagerImpl::getAccountLink(const AccountID& accountID)
{
Account* acc = getAccount(accountID);
if ( acc ) {
return acc->getVoIPLink();
}
return 0;
}
#ifdef TEST
/**
* Test accountMap
*/
bool ManagerImpl::testCallAccountMap()
{
if ( getAccountFromCall(1) != AccountNULL ) {
_debug("TEST: getAccountFromCall with empty list failed\n");
}
if ( removeCallAccount(1) != false ) {
_debug("TEST: removeCallAccount with empty list failed\n");
}
CallID newid = getNewCallID();
if ( associateCallToAccount(newid, "acc0") == false ) {
_debug("TEST: associateCallToAccount with new CallID empty list failed\n");
}
if ( associateCallToAccount(newid, "acc1") == true ) {
_debug("TEST: associateCallToAccount with a known CallID failed\n");
}
if ( getAccountFromCall( newid ) != "acc0" ) {
_debug("TEST: getAccountFromCall don't return the good account id\n");
}
CallID secondnewid = getNewCallID();
if ( associateCallToAccount(secondnewid, "xxxx") == true ) {
_debug("TEST: associateCallToAccount with unknown account id failed\n");
}
if ( removeCallAccount( newid ) != true ) {
_debug("TEST: removeCallAccount don't remove the association\n");
}
return true;
}
/**
* Test AccountMap
*/
bool ManagerImpl::testAccountMap()
{
if (loadAccountMap() != 2) {
_debug("TEST: loadAccountMap didn't load 2 account\n");
}
if (accountExists("acc0") == false) {
_debug("TEST: accountExists didn't find acc0\n");
}
if (accountExists("accZ") != false) {
_debug("TEST: accountExists found an unknown account\n");
}
if (getAccount("acc0") == 0) {
_debug("TEST: getAccount didn't find acc0\n");
}
if (getAccount("accZ") != 0) {
_debug("TEST: getAccount found an unknown account\n");
}
unloadAccountMap();
if ( accountExists("acc0") == true ) {
_debug("TEST: accountExists found an account after unloadAccount\n");
}
return true;
}
#endif