mirror of
https://git.jami.net/savoirfairelinux/jami-daemon.git
synced 2025-08-12 22:09:25 +08:00
1554 lines
34 KiB
C++
1554 lines
34 KiB
C++
/**
|
|
* Copyright (C) 2004-2005 Savoir-Faire Linux inc.
|
|
* Author: Yan Morin <yan.morin@savoirfairelinux.com>
|
|
* Author : Laurielle Lea <laurielle.lea@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 2 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 <sys/types.h> // mkdir(2)
|
|
#include <sys/stat.h> // mkdir(2)
|
|
|
|
#include <cc++/thread.h>
|
|
#include <cc++/file.h>
|
|
|
|
#include <cstdlib>
|
|
#include <iostream>
|
|
#include <fstream>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
#include "sipvoiplink.h"
|
|
#include "manager.h"
|
|
#include "audio/audiocodec.h"
|
|
#include "audio/audiolayer.h"
|
|
#include "audio/ringbuffer.h"
|
|
#include "audio/tonegenerator.h"
|
|
#include "call.h"
|
|
#include "error.h"
|
|
#include "user_cfg.h"
|
|
#include "voIPLink.h"
|
|
#include "gui/guiframework.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)))
|
|
|
|
#define DFT_VOIP_LINK 0
|
|
|
|
ManagerImpl::ManagerImpl (void)
|
|
{
|
|
// initialize random generator
|
|
srand (time(NULL));
|
|
|
|
// Init private variables
|
|
_error = new Error();
|
|
_tone = new ToneGenerator();
|
|
_hasZeroconf = false;
|
|
#ifdef USE_ZEROCONF
|
|
_hasZeroconf = true;
|
|
_DNSService = new DNSService();
|
|
#endif
|
|
|
|
_nCodecs = 0;
|
|
_currentCallId = 0;
|
|
_startTime = 0;
|
|
_endTime = 0;
|
|
_path = "";
|
|
_exist = 0;
|
|
_setupLoaded = false;
|
|
_loaded = false;
|
|
_gui = NULL;
|
|
_audiodriverPA = NULL;
|
|
|
|
// Initialize after by init() -> initVolume()
|
|
_spkr_volume = 0;
|
|
_mic_volume = 0;
|
|
_mic_volume_before_mute = 0;
|
|
|
|
_toneType = ZT_TONE_NULL;
|
|
|
|
_nbIncomingWaitingCall=0;
|
|
|
|
_codecMap = CodecDescriptorMap().getMap();
|
|
|
|
_registerState = UNREGISTERED;
|
|
}
|
|
|
|
// never call if we use only the singleton...
|
|
ManagerImpl::~ManagerImpl (void)
|
|
{
|
|
terminate();
|
|
#ifdef USE_ZEROCONF
|
|
delete _DNSService; _DNSService = NULL;
|
|
#endif
|
|
|
|
delete _tone; _tone = NULL;
|
|
delete _error; _error = NULL;
|
|
|
|
_debug("%s stop correctly\n", PROGNAME);
|
|
}
|
|
|
|
void
|
|
ManagerImpl::init()
|
|
{
|
|
_debugInit("Volume Initialisation");
|
|
initVolume();
|
|
|
|
if (_exist == 0) {
|
|
_debug("Cannot create config file in your home directory\n");
|
|
}
|
|
|
|
try {
|
|
_debugInit("Audio Driver Selection");
|
|
selectAudioDriver();
|
|
loaded(true);
|
|
}
|
|
catch (const portaudio::PaException &e)
|
|
{
|
|
displayError(e.paErrorText());
|
|
throw e;
|
|
}
|
|
catch (const portaudio::PaCppException &e)
|
|
{
|
|
displayError(e.what());
|
|
throw e;
|
|
}
|
|
catch (const std::runtime_error &e)
|
|
{
|
|
displayError(e.what());
|
|
throw e;
|
|
}
|
|
catch (...)
|
|
{
|
|
displayError("An unknown exception occured.");
|
|
throw;
|
|
}
|
|
_debugInit("Audio Codec Initialization");
|
|
initAudioCodec();
|
|
|
|
_debugInit("Adding new VoIP Link");
|
|
// Set a sip voip link by default
|
|
_voIPLinkVector.push_back(new SipVoIPLink());
|
|
|
|
// initRegisterVoIP 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()
|
|
{
|
|
for(VoIPLinkVector::iterator pos = _voIPLinkVector.begin();
|
|
pos != _voIPLinkVector.end();
|
|
pos++) {
|
|
delete *pos;
|
|
*pos = NULL;
|
|
}
|
|
_voIPLinkVector.clear();
|
|
|
|
_mutex.enterMutex();
|
|
for(CallVector::iterator pos = _callVector.begin();
|
|
pos != _callVector.end();
|
|
pos++) {
|
|
delete *pos; *pos = NULL;
|
|
}
|
|
_callVector.clear();
|
|
_mutex.leaveMutex();
|
|
|
|
unloadAudioCodec();
|
|
|
|
delete _audiodriverPA; _audiodriverPA = NULL;
|
|
}
|
|
|
|
void
|
|
ManagerImpl::setGui (GuiFramework* gui)
|
|
{
|
|
_gui = gui;
|
|
}
|
|
|
|
/**
|
|
* Multi Thread with _mutex for callVector
|
|
*/
|
|
Call *
|
|
ManagerImpl::pushBackNewCall (CALLID id, enum CallType type)
|
|
{
|
|
Call* call = new Call(id, type, _voIPLinkVector.at(DFT_VOIP_LINK));
|
|
// Set the wanted voip-link (first of the list)
|
|
ost::MutexLock m(_mutex);
|
|
_callVector.push_back(call);
|
|
return call;
|
|
}
|
|
|
|
/**
|
|
* Multi Thread with _mutex for callVector
|
|
*/
|
|
Call*
|
|
ManagerImpl::getCall (CALLID id)
|
|
{
|
|
Call* call = NULL;
|
|
unsigned int size = _callVector.size();
|
|
for (unsigned int i = 0; i < size; i++) {
|
|
call = _callVector.at(i);
|
|
if (call && call->getId() == id) {
|
|
break;
|
|
} else {
|
|
call = NULL;
|
|
}
|
|
}
|
|
return call;
|
|
}
|
|
|
|
/**
|
|
* Multi Thread with _mutex for callVector
|
|
*/
|
|
void
|
|
ManagerImpl::deleteCall (CALLID id)
|
|
{
|
|
CallVector::iterator iter = _callVector.begin();
|
|
while(iter!=_callVector.end()) {
|
|
Call *call = *iter;
|
|
if (call != NULL && call->getId() == id) {
|
|
if (call->isIncomingType() && call->isNotAnswered()) {
|
|
decWaitingCall();
|
|
}
|
|
delete (*iter); *iter = NULL;
|
|
call = NULL;
|
|
_callVector.erase(iter);
|
|
return;
|
|
}
|
|
iter++;
|
|
}
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// Management of events' IP-phone user
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
/**
|
|
* Main thread
|
|
*/
|
|
int
|
|
ManagerImpl::outgoingCall (const std::string& to)
|
|
{
|
|
CALLID id = generateNewCallId();
|
|
Call *call = pushBackNewCall(id, Outgoing);
|
|
_debug("Outgoing Call with identifiant %d\n", id);
|
|
|
|
call->setState(Call::Progressing);
|
|
call->setCallerIdNumber(to);
|
|
if (call->outgoingCall(to) == 0) {
|
|
return id;
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* User action (main thread)
|
|
* Every Call
|
|
*/
|
|
int
|
|
ManagerImpl::hangupCall (CALLID id)
|
|
{
|
|
ost::MutexLock m(_mutex);
|
|
Call* call = getCall(id);
|
|
if (call == NULL) {
|
|
return -1;
|
|
}
|
|
int result = -1;
|
|
if (call->getState() != Call::Error) {
|
|
result = call->hangup();
|
|
}
|
|
deleteCall(id);
|
|
stopTone(); // stop tone, like a 700 error: number not found Not Found
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* User action (main thread)
|
|
* Every Call
|
|
* -1 : call not found
|
|
* 0 : already in this state...
|
|
*/
|
|
int
|
|
ManagerImpl::cancelCall (CALLID id)
|
|
{
|
|
ost::MutexLock m(_mutex);
|
|
Call* call = getCall(id);
|
|
if (call == NULL) {
|
|
return -1;
|
|
}
|
|
int result = call->cancel();
|
|
deleteCall(id);
|
|
stopTone();
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* User action (main thread)
|
|
* Incoming Call
|
|
*/
|
|
int
|
|
ManagerImpl::answerCall (CALLID id)
|
|
{
|
|
ost::MutexLock m(_mutex);
|
|
Call* call = getCall(id);
|
|
if (call == NULL) {
|
|
return -1;
|
|
}
|
|
if (call->isIncomingType()) {
|
|
decWaitingCall();
|
|
}
|
|
switchCall(id);
|
|
stopTone(); // before answer, don't stop the audio stream after open it...
|
|
return call->answer();
|
|
}
|
|
|
|
/**
|
|
* User action (main thread)
|
|
* Every Call
|
|
* @return 0 if it fails, -1 if not present
|
|
*/
|
|
int
|
|
ManagerImpl::onHoldCall (CALLID id)
|
|
{
|
|
ost::MutexLock m(_mutex);
|
|
Call* call = getCall(id);
|
|
if (call == NULL) {
|
|
return -1;
|
|
}
|
|
if ( call->getState() == Call::OnHold || call->isNotAnswered()) {
|
|
return 1;
|
|
}
|
|
setCurrentCallId(0);
|
|
return call->onHold();
|
|
}
|
|
|
|
/**
|
|
* User action (main thread)
|
|
* Every Call
|
|
*/
|
|
int
|
|
ManagerImpl::offHoldCall (CALLID id)
|
|
{
|
|
stopTone();
|
|
ost::MutexLock m(_mutex);
|
|
Call* call = getCall(id);
|
|
if (call == NULL) {
|
|
return -1;
|
|
}
|
|
if (call->getState() == Call::OffHold) {
|
|
return 1;
|
|
}
|
|
setCurrentCallId(id);
|
|
int returnValue = call->offHold();
|
|
if (returnValue) {
|
|
getAudioDriver()->startStream();
|
|
}
|
|
return returnValue;
|
|
}
|
|
|
|
/**
|
|
* User action (main thread)
|
|
* Every Call
|
|
*/
|
|
int
|
|
ManagerImpl::transferCall (CALLID id, const std::string& to)
|
|
{
|
|
ost::MutexLock m(_mutex);
|
|
Call* call = getCall(id);
|
|
if (call == NULL) {
|
|
return -1;
|
|
}
|
|
setCurrentCallId(0);
|
|
return call->transfer(to);
|
|
}
|
|
|
|
/**
|
|
* User action (main thread)
|
|
* All Call
|
|
*/
|
|
void
|
|
ManagerImpl::mute() {
|
|
_mic_volume_before_mute = _mic_volume;
|
|
setMicVolume(0);
|
|
}
|
|
|
|
/**
|
|
* User action (main thread)
|
|
* All Call
|
|
*/
|
|
void
|
|
ManagerImpl::unmute() {
|
|
setMicVolume(_mic_volume_before_mute);
|
|
}
|
|
|
|
/**
|
|
* User action (main thread)
|
|
* Call Incoming
|
|
*/
|
|
int
|
|
ManagerImpl::refuseCall (CALLID id)
|
|
{
|
|
ost::MutexLock m(_mutex);
|
|
Call *call = getCall(id);
|
|
if (call == NULL) {
|
|
return -1;
|
|
}
|
|
|
|
if ( call->getState() != Call::Progressing ) {
|
|
return -1;
|
|
}
|
|
int refuse = call->refuse();
|
|
|
|
setCurrentCallId(0);
|
|
deleteCall(id);
|
|
stopTone();
|
|
return refuse;
|
|
}
|
|
|
|
/**
|
|
* User action (main thread)
|
|
*/
|
|
bool
|
|
ManagerImpl::saveConfig (void)
|
|
{
|
|
setConfig(AUDIO, VOLUME_SPKR, getSpkrVolume());
|
|
setConfig(AUDIO, VOLUME_MICRO, getMicVolume());
|
|
|
|
_setupLoaded = _config.saveConfigTree(_path.data());
|
|
return _setupLoaded;
|
|
}
|
|
|
|
/**
|
|
* Main Thread
|
|
*/
|
|
void
|
|
ManagerImpl::initRegisterVoIPLink()
|
|
{
|
|
if (_hasTriedToRegister == false) {
|
|
_voIPLinkVector.at(DFT_VOIP_LINK)->init(); // we call here, because it's long...
|
|
if (_voIPLinkVector.at(DFT_VOIP_LINK)->checkNetwork()) {
|
|
// If network is available
|
|
|
|
if (getConfigInt(SIGNALISATION, AUTO_REGISTER) && _exist == 1) {
|
|
registerVoIPLink();
|
|
}
|
|
}
|
|
_hasTriedToRegister = true;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Initialize action (main thread)
|
|
* Note that Registration is only send if STUN is not activated
|
|
* @return 1 if setRegister is call without failure, else return 0
|
|
*/
|
|
int
|
|
ManagerImpl::registerVoIPLink (void)
|
|
{
|
|
int returnValue = 0;
|
|
if ( !useStun() ) {
|
|
if (_voIPLinkVector.at(DFT_VOIP_LINK)->setRegister() >= 0) {
|
|
returnValue = 1;
|
|
_registerState = REGISTERED;
|
|
} else {
|
|
_registerState = FAILED;
|
|
}
|
|
} else {
|
|
_registerState = UNREGISTERED;
|
|
}
|
|
return returnValue;
|
|
}
|
|
|
|
/**
|
|
* Terminate action (main thread)
|
|
* @return 1 if the unregister method is send correctly
|
|
*/
|
|
int
|
|
ManagerImpl::unregisterVoIPLink (void)
|
|
{
|
|
if (_voIPLinkVector.at(DFT_VOIP_LINK)->setUnregister() == 0) {
|
|
return 1;
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* User action (main thread)
|
|
*/
|
|
bool
|
|
ManagerImpl::sendDtmf (CALLID id, char code)
|
|
{
|
|
int sendType = getConfigInt(SIGNALISATION, SEND_DTMF_AS);
|
|
int returnValue = false;
|
|
switch (sendType) {
|
|
case 0: // SIP INFO
|
|
playDtmf(code);
|
|
_voIPLinkVector.at(DFT_VOIP_LINK)->carryingDTMFdigits(id, code);
|
|
returnValue = true;
|
|
break;
|
|
|
|
case 1: // Audio way
|
|
break;
|
|
case 2: // rfc 2833
|
|
break;
|
|
default: // unknown - error config?
|
|
break;
|
|
}
|
|
return returnValue;
|
|
}
|
|
|
|
/**
|
|
* User action (main thread)
|
|
*/
|
|
bool
|
|
ManagerImpl::playDtmf(char code)
|
|
{
|
|
stopTone();
|
|
|
|
// 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
|
|
int size = pulselen * (SAMPLING_RATE/1000);
|
|
|
|
// this buffer is for mono
|
|
int16* _buf = new int16[size];
|
|
bool returnValue = false;
|
|
|
|
// Handle dtmf
|
|
_key.startTone(code);
|
|
|
|
// copy the sound...
|
|
if ( _key.generateDTMF(_buf, size) ) {
|
|
int k;
|
|
|
|
// allocation of more space, for stereo conversion
|
|
int16* buf_ctrl_vol = new int16[size*CHANNELS];
|
|
|
|
// Control volume and format mono->stereo
|
|
for (int j = 0; j < size; j++) {
|
|
k = j<<1; // fast multiplication by two
|
|
buf_ctrl_vol[k] = buf_ctrl_vol[k+1] = _buf[j];
|
|
}
|
|
|
|
AudioLayer *audiolayer = getAudioDriver();
|
|
|
|
_toneMutex.enterMutex();
|
|
audiolayer->urgentRingBuffer().flush();
|
|
|
|
// Put buffer to urgentRingBuffer
|
|
// put the size in bytes...
|
|
// so size * CHANNELS * 2 (bytes for the int16)
|
|
int nbInt16InChar = sizeof(int16)/sizeof(char);
|
|
audiolayer->urgentRingBuffer().Put(buf_ctrl_vol, size * CHANNELS * nbInt16InChar);
|
|
|
|
// We activate the stream if it's not active yet.
|
|
if (!audiolayer->isStreamActive()) {
|
|
audiolayer->startStream();
|
|
audiolayer->sleep(pulselen);
|
|
audiolayer->urgentRingBuffer().flush();
|
|
audiolayer->stopStream();
|
|
} else {
|
|
audiolayer->sleep(pulselen); // in milliseconds
|
|
}
|
|
_toneMutex.leaveMutex();
|
|
//setZonetone(false);
|
|
delete[] buf_ctrl_vol; buf_ctrl_vol = 0;
|
|
returnValue = true;
|
|
}
|
|
delete[] _buf; _buf = 0;
|
|
return returnValue;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// Management of event peer IP-phone
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/**
|
|
* Multi-thread
|
|
*/
|
|
bool
|
|
ManagerImpl::incomingCallWaiting() {
|
|
ost::MutexLock m(_incomingCallMutex);
|
|
return (_nbIncomingWaitingCall > 0) ? true : false;
|
|
}
|
|
|
|
void
|
|
ManagerImpl::incWaitingCall() {
|
|
ost::MutexLock m(_incomingCallMutex);
|
|
_nbIncomingWaitingCall++;
|
|
_debug("incWaitingCall: %d\n", _nbIncomingWaitingCall);
|
|
}
|
|
|
|
void
|
|
ManagerImpl::decWaitingCall() {
|
|
ost::MutexLock m(_incomingCallMutex);
|
|
_nbIncomingWaitingCall--;
|
|
_debug("decWaitingCall: %d\n", _nbIncomingWaitingCall);
|
|
}
|
|
|
|
|
|
/**
|
|
* SipEvent Thread
|
|
* Set the call info for incoming call
|
|
*/
|
|
void
|
|
ManagerImpl::callSetInfo(CALLID id, const std::string& name, const std::string& number)
|
|
{
|
|
ost::MutexLock m(_mutex);
|
|
Call* call = getCall(id);
|
|
if (call != NULL) {
|
|
call->setCallerIdName(name);
|
|
call->setCallerIdNumber(number);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* SipEvent Thread
|
|
* ask if it can close the call
|
|
*/
|
|
bool
|
|
ManagerImpl::callCanBeClosed(CALLID id) {
|
|
bool returnValue = false;
|
|
ost::MutexLock m(_mutex);
|
|
Call* call = getCall(id);
|
|
if (call != NULL && call->getState() != Call::Progressing) {
|
|
returnValue = true;
|
|
}
|
|
return returnValue;
|
|
}
|
|
|
|
/**
|
|
* SipEvent Thread
|
|
* ask if it can answer the call
|
|
*/
|
|
bool
|
|
ManagerImpl::callCanBeAnswered(CALLID id) {
|
|
bool returnValue = false;
|
|
ost::MutexLock m(_mutex);
|
|
Call* call = getCall(id);
|
|
if (call != NULL &&
|
|
call->getState() != Call::OnHold &&
|
|
call->getState() != Call::OffHold) {
|
|
returnValue = true;
|
|
}
|
|
return returnValue;
|
|
}
|
|
|
|
/**
|
|
* SipEvent Thread
|
|
*/
|
|
int
|
|
ManagerImpl::incomingCall (CALLID id)
|
|
{
|
|
ost::MutexLock m(_mutex);
|
|
Call* call = getCall(id);
|
|
if (call == NULL) {
|
|
return -1;
|
|
}
|
|
call->setType(Incoming);
|
|
call->setState(Call::Progressing);
|
|
|
|
switchCall(id);
|
|
|
|
incWaitingCall();
|
|
ringtone();
|
|
|
|
// TODO: Account not yet implemented
|
|
std::string accountId = "acc1";
|
|
std::string from = call->getCallerIdName();
|
|
std::string number = call->getCallerIdNumber();
|
|
if ( number.length() ) {
|
|
from.append(" <");
|
|
from.append(number);
|
|
from.append(">");
|
|
}
|
|
return _gui->incomingCall(id, accountId, from);
|
|
}
|
|
|
|
/**
|
|
* SipEvent Thread
|
|
* for outgoing call, send by SipEvent
|
|
*/
|
|
void
|
|
ManagerImpl::peerAnsweredCall (CALLID id)
|
|
{
|
|
ost::MutexLock m(_mutex);
|
|
Call* call = getCall(id);
|
|
call->setState(Call::Answered);
|
|
|
|
stopTone();
|
|
// switch current call
|
|
switchCall(id);
|
|
if (_gui) _gui->peerAnsweredCall(id);
|
|
}
|
|
|
|
/**
|
|
* SipEvent Thread
|
|
* for outgoing call, send by SipEvent
|
|
*/
|
|
int
|
|
ManagerImpl::peerRingingCall (CALLID id)
|
|
{
|
|
ost::MutexLock m(_mutex);
|
|
Call* call = getCall(id);
|
|
call->setState(Call::Ringing);
|
|
|
|
// ring
|
|
ringback();
|
|
if (_gui) _gui->peerRingingCall(id);
|
|
return 1;
|
|
}
|
|
|
|
/**
|
|
* SipEvent Thread
|
|
* for outgoing call, send by SipEvent
|
|
*/
|
|
int
|
|
ManagerImpl::peerHungupCall (CALLID id)
|
|
{
|
|
ost::MutexLock m(_mutex);
|
|
Call* call = getCall(id);
|
|
if ( call == NULL ) {
|
|
return -1;
|
|
}
|
|
if ( _currentCallId == id ) {
|
|
stopTone();
|
|
}
|
|
|
|
if (_gui) _gui->peerHungupCall(id);
|
|
deleteCall(id);
|
|
call->setState(Call::Hungup);
|
|
|
|
setCurrentCallId(0);
|
|
return 1;
|
|
}
|
|
|
|
/**
|
|
* SipEvent Thread
|
|
* for outgoing call, send by SipEvent
|
|
*/
|
|
void
|
|
ManagerImpl::displayTextMessage (CALLID id, const std::string& message)
|
|
{
|
|
if(_gui) {
|
|
_gui->displayTextMessage(id, message);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* SipEvent Thread
|
|
* for outgoing call, send by SipEvent
|
|
*/
|
|
void
|
|
ManagerImpl::displayErrorText (CALLID id, const std::string& message)
|
|
{
|
|
if(_gui) {
|
|
_gui->displayErrorText(id, message);
|
|
} else {
|
|
std::cerr << message << std::endl;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* SipEvent Thread
|
|
* for outgoing call, send by SipEvent
|
|
*/
|
|
void
|
|
ManagerImpl::displayError (const std::string& voIPError)
|
|
{
|
|
if(_gui) {
|
|
_gui->displayError(voIPError);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* SipEvent Thread
|
|
* for outgoing call, send by SipEvent
|
|
*/
|
|
void
|
|
ManagerImpl::displayStatus (const std::string& status)
|
|
{
|
|
if(_gui) {
|
|
_gui->displayStatus(status);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* SipEvent Thread
|
|
* for outgoing call, send by SipEvent
|
|
*/
|
|
void
|
|
ManagerImpl::displayConfigError (const std::string& message)
|
|
{
|
|
if(_gui) {
|
|
_gui->displayConfigError(message);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* SipEvent Thread
|
|
* for outgoing call, send by SipEvent
|
|
*/
|
|
void
|
|
ManagerImpl::startVoiceMessageNotification (const std::string& nb_msg)
|
|
{
|
|
if (_gui) _gui->sendVoiceNbMessage(nb_msg);
|
|
}
|
|
|
|
/**
|
|
* SipEvent Thread
|
|
* for outgoing call, send by SipEvent
|
|
*/
|
|
void
|
|
ManagerImpl::stopVoiceMessageNotification (void)
|
|
{
|
|
if (_gui) _gui->sendVoiceNbMessage(std::string("0"));
|
|
}
|
|
|
|
/**
|
|
* Multi Thread
|
|
*/
|
|
bool
|
|
ManagerImpl::playATone(unsigned int tone) {
|
|
if (isDriverLoaded()) {
|
|
ost::MutexLock m(_toneMutex);
|
|
_toneType = tone;
|
|
_tone->toneHandle(_toneType, getConfigString(PREFERENCES, ZONE_TONE));
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Multi Thread
|
|
*/
|
|
void
|
|
ManagerImpl::stopTone() {
|
|
if (isDriverLoaded()) {
|
|
_toneMutex.enterMutex();
|
|
if ( _toneType != ZT_TONE_NULL ) {
|
|
_toneType = ZT_TONE_NULL;
|
|
_tone->stopTone();
|
|
}
|
|
_toneMutex.leaveMutex();
|
|
getAudioDriver()->stopStream();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Multi Thread
|
|
*/
|
|
bool
|
|
ManagerImpl::playTone()
|
|
{
|
|
return playATone(ZT_TONE_DIALTONE);
|
|
}
|
|
|
|
/**
|
|
* Multi Thread
|
|
*/
|
|
void
|
|
ManagerImpl::congestion () {
|
|
playATone(ZT_TONE_CONGESTION);
|
|
}
|
|
|
|
/**
|
|
* Multi Thread
|
|
*/
|
|
void
|
|
ManagerImpl::ringback () {
|
|
playATone(ZT_TONE_RINGTONE);
|
|
}
|
|
|
|
/**
|
|
* Multi Thread
|
|
*/
|
|
void
|
|
ManagerImpl::callBusy(CALLID id) {
|
|
playATone(ZT_TONE_BUSY);
|
|
Call* call = getCall(id);
|
|
if (call != NULL) {
|
|
call->setState(Call::Busy);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Multi Thread
|
|
*/
|
|
void
|
|
ManagerImpl::callFailure(CALLID id) {
|
|
playATone(ZT_TONE_BUSY);
|
|
Call* call = getCall(id);
|
|
if (call != NULL) {
|
|
getCall(id)->setState(Call::Error);
|
|
}
|
|
|
|
if (_gui) {
|
|
_gui->callFailure(id);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Multi Thread
|
|
*/
|
|
void
|
|
ManagerImpl::ringtone()
|
|
{
|
|
if (isDriverLoaded()) {
|
|
_toneMutex.enterMutex();
|
|
_toneType = ZT_TONE_FILE;
|
|
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;
|
|
}
|
|
int play = _tone->playRingtone(ringchoice.c_str());
|
|
_toneMutex.leaveMutex();
|
|
if (play!=1) {
|
|
ringback();
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Use Urgent Buffer
|
|
* By AudioRTP thread
|
|
*/
|
|
void
|
|
ManagerImpl::notificationIncomingCall (void) {
|
|
int16* buf_ctrl_vol;
|
|
int16* buffer = new int16[SAMPLING_RATE];
|
|
int size = SAMPLES_SIZE(FRAME_PER_BUFFER);//SAMPLING_RATE/2;
|
|
int k;
|
|
//int spkrVolume;
|
|
|
|
_tone->generateSin(440, 0, buffer);
|
|
|
|
// Volume Control
|
|
buf_ctrl_vol = new int16[size*CHANNELS];
|
|
// spkrVolume = getSpkrVolume();
|
|
for (int j = 0; j < size; j++) {
|
|
k = j<<1; // fast multiply by two
|
|
buf_ctrl_vol[k] = buf_ctrl_vol[k+1] = buffer[j];
|
|
// * spkrVolume/100;
|
|
}
|
|
getAudioDriver()->putUrgent(buf_ctrl_vol, SAMPLES_SIZE(FRAME_PER_BUFFER));
|
|
|
|
delete[] buf_ctrl_vol; buf_ctrl_vol = NULL;
|
|
delete[] buffer; buffer = NULL;
|
|
}
|
|
|
|
/**
|
|
* Multi Thread
|
|
*/
|
|
void
|
|
ManagerImpl::getStunInfo (StunAddress4& stunSvrAddr)
|
|
{
|
|
StunAddress4 mappedAddr;
|
|
struct in_addr in;
|
|
char* addr;
|
|
char to[16];
|
|
bzero (to, 16);
|
|
|
|
int fd3, fd4;
|
|
bool ok = stunOpenSocketPair(stunSvrAddr,
|
|
&mappedAddr,
|
|
&fd3,
|
|
&fd4);
|
|
if (ok) {
|
|
closesocket(fd3);
|
|
closesocket(fd4);
|
|
_debug("Got port pair at %d\n", mappedAddr.port);
|
|
_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("address firewall = %s\n",_firewallAddr.data());
|
|
} else {
|
|
_debug("Opened a stun socket pair FAILED\n");
|
|
}
|
|
}
|
|
|
|
bool
|
|
ManagerImpl::useStun (void)
|
|
{
|
|
if (getConfigInt(SIGNALISATION, USE_STUN)) {
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// Private functions
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
/**
|
|
* Multi Thread
|
|
*/
|
|
CALLID
|
|
ManagerImpl::generateNewCallId (void)
|
|
{
|
|
CALLID random_id = (unsigned)rand();
|
|
|
|
// Check if already a call with this id exists
|
|
while (getCall(random_id) != NULL && random_id != 0) {
|
|
random_id = rand();
|
|
}
|
|
// If random_id is not attributed, returns it.
|
|
return random_id;
|
|
}
|
|
|
|
/**
|
|
* Initialization: Main Thread
|
|
* @return 1: ok
|
|
-1: error directory
|
|
0: unable to load the setting
|
|
2: file doesn't exist yet
|
|
*/
|
|
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 _config.populateFromFile(_path);
|
|
}
|
|
|
|
/**
|
|
* Initialization: Main Thread
|
|
*/
|
|
void
|
|
ManagerImpl::initConfigFile (void)
|
|
{
|
|
std::string type_str("string");
|
|
std::string type_int("int");
|
|
|
|
std::string section;
|
|
section = SIGNALISATION;
|
|
fill_config_int(SYMMETRIC, YES_STR);
|
|
fill_config_str(FULL_NAME, EMPTY_FIELD);
|
|
fill_config_str(USER_PART, EMPTY_FIELD);
|
|
fill_config_str(AUTH_USER_NAME, EMPTY_FIELD);
|
|
fill_config_str(PASSWORD, EMPTY_FIELD);
|
|
fill_config_str(HOST_PART, EMPTY_FIELD);
|
|
fill_config_str(PROXY, EMPTY_FIELD);
|
|
fill_config_int(AUTO_REGISTER, 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);
|
|
fill_config_str(STUN_SERVER, DFT_STUN_SERVER);
|
|
fill_config_int(USE_STUN, NO_STR);
|
|
|
|
section = AUDIO;
|
|
fill_config_int(DRIVER_NAME, DFT_DRIVER_STR);
|
|
fill_config_str(CODEC1, DFT_CODEC);
|
|
fill_config_str(CODEC2, DFT_CODEC);
|
|
fill_config_str(CODEC3, DFT_CODEC);
|
|
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(SKIN_CHOICE, DFT_SKIN);
|
|
fill_config_int(CONFIRM_QUIT, YES_STR);
|
|
fill_config_str(ZONE_TONE, DFT_ZONE);
|
|
fill_config_int(CHECKED_TRAY, NO_STR);
|
|
fill_config_str(VOICEMAIL_NUM, DFT_VOICEMAIL);
|
|
fill_config_int(CONFIG_ZEROCONF, CONFIG_ZEROCONF_DEFAULT_STR);
|
|
|
|
_exist = createSettingsPath();
|
|
_setupLoaded = (_exist == 2 ) ? false : true;
|
|
}
|
|
|
|
/**
|
|
* Initialization: Main Thread
|
|
*/
|
|
void
|
|
ManagerImpl::initAudioCodec (void)
|
|
{
|
|
// TODO: need to be more dynamic...
|
|
_codecDescVector.push_back(new CodecDescriptor(getConfigString(AUDIO, CODEC1)));
|
|
_codecDescVector.push_back(new CodecDescriptor(getConfigString(AUDIO, CODEC2)));
|
|
_codecDescVector.push_back(new CodecDescriptor(getConfigString(AUDIO, CODEC3)));
|
|
}
|
|
|
|
/**
|
|
* Terminate: Main Thread
|
|
*/
|
|
void
|
|
ManagerImpl::unloadAudioCodec()
|
|
{
|
|
CodecDescriptorVector::iterator iter = _codecDescVector.begin();
|
|
while(iter!=_codecDescVector.end()) {
|
|
delete *iter; *iter = NULL;
|
|
iter++;
|
|
}
|
|
_codecDescVector.clear();
|
|
}
|
|
|
|
|
|
/**
|
|
* Initialization: Main Thread
|
|
*/
|
|
void
|
|
ManagerImpl::selectAudioDriver (void)
|
|
{
|
|
#if defined(AUDIO_PORTAUDIO)
|
|
try {
|
|
_debugInit(" AudioLayer Creation");
|
|
_audiodriverPA = new AudioLayer(*this);
|
|
int noDevice = getConfigInt(AUDIO, DRIVER_NAME);
|
|
_debugInit(" AudioLayer Device Count");
|
|
int nbDevice = portaudio::System::instance().deviceCount();
|
|
if (nbDevice == 0) {
|
|
_debug("Portaudio detect no sound cart.");
|
|
throw std::runtime_error("Portaudio detect no sound card.");
|
|
} else if (noDevice >= nbDevice) {
|
|
_debug("Portaudio auto-select device #0 because device #%d is not found\n", noDevice);
|
|
_setupLoaded = false;
|
|
noDevice = 0;
|
|
}
|
|
_debugInit(" AudioLayer Opening Device");
|
|
_audiodriverPA->openDevice(noDevice);
|
|
} catch(...) {
|
|
throw;
|
|
}
|
|
#else
|
|
# error You must define one AUDIO driver to use.
|
|
#endif
|
|
}
|
|
|
|
/**
|
|
* 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()
|
|
{
|
|
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 && _gui != 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;
|
|
}
|
|
#endif
|
|
return returnValue;
|
|
}
|
|
|
|
/**
|
|
* Main Thread
|
|
*/
|
|
bool
|
|
ManagerImpl::attachZeroconfEvents(const std::string& , 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;
|
|
}
|
|
#endif
|
|
return returnValue;
|
|
}
|
|
bool
|
|
ManagerImpl::detachZeroconfEvents(Pattern::Observer& observer)
|
|
{
|
|
bool returnValue = false;
|
|
#ifdef USE_ZEROCONF
|
|
if (_DNSService) {
|
|
_DNSService->detach(observer);
|
|
returnValue = true;
|
|
}
|
|
#endif
|
|
return returnValue;
|
|
}
|
|
|
|
/**
|
|
* Main Thread
|
|
*/
|
|
bool
|
|
ManagerImpl::getEvents() {
|
|
initRegisterVoIPLink();
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Main Thread
|
|
*/
|
|
bool
|
|
ManagerImpl::getCallStatus(const std::string& sequenceId)
|
|
{
|
|
ost::MutexLock m(_mutex);
|
|
// TODO: implement account
|
|
std::string accountId = "acc1";
|
|
std::string code;
|
|
std::string status;
|
|
TokenList tk;
|
|
Call* call;
|
|
|
|
if (_gui!=NULL) {
|
|
CallVector::iterator iter = _callVector.begin();
|
|
while(iter!=_callVector.end()){
|
|
call = (*iter);
|
|
switch( call->getState() ) {
|
|
case Call::Progressing:
|
|
code="110";
|
|
status="Trying";
|
|
break;
|
|
|
|
case Call::Ringing:
|
|
code="111";
|
|
status = "Ringing";
|
|
break;
|
|
|
|
case Call::Answered:
|
|
code="112";
|
|
status = "Established";
|
|
break;
|
|
|
|
case Call::Busy:
|
|
code="113";
|
|
status = "Busy";
|
|
break;
|
|
|
|
case Call::OnHold:
|
|
code="114";
|
|
status = "Holded";
|
|
break;
|
|
|
|
case Call::OffHold:
|
|
code="115";
|
|
status = "Unholded";
|
|
break;
|
|
|
|
default:
|
|
code="125";
|
|
status="Other";
|
|
}
|
|
// No Congestion
|
|
// No Wrong Number
|
|
// 116 <CSeq> <call-id> <acc> <destination> Busy
|
|
std::string destination = call->getCallerIdName();
|
|
std::string number = call->getCallerIdNumber();
|
|
if (number!="") {
|
|
destination.append(" <");
|
|
destination.append(number);
|
|
destination.append(">");
|
|
}
|
|
tk.push_back(accountId);
|
|
tk.push_back(destination);
|
|
tk.push_back(status);
|
|
_gui->sendCallMessage(code, sequenceId, (*iter)->getId(), tk);
|
|
iter++;
|
|
tk.clear();
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Main Thread
|
|
*/
|
|
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;
|
|
}
|
|
|
|
/**
|
|
* Main Thread
|
|
*/
|
|
bool
|
|
ManagerImpl::getConfig(const std::string& section, const std::string& name, TokenList& arg)
|
|
{
|
|
return _config.getConfigTreeItemToken(section, name, arg);
|
|
}
|
|
|
|
/**
|
|
* Main Thread
|
|
*/
|
|
// 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;
|
|
}
|
|
|
|
/**
|
|
* Main Thread
|
|
*/
|
|
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 "";
|
|
}
|
|
|
|
/**
|
|
* Main Thread
|
|
*/
|
|
bool
|
|
ManagerImpl::setConfig(const std::string& section, const std::string& name, const std::string& value)
|
|
{
|
|
return _config.setConfigTreeItem(section, name, value);
|
|
}
|
|
|
|
/**
|
|
* Main Thread
|
|
*/
|
|
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());
|
|
}
|
|
|
|
/**
|
|
* Main Thread
|
|
*/
|
|
bool
|
|
ManagerImpl::getConfigList(const std::string& sequenceId, const std::string& name)
|
|
{
|
|
bool returnValue = false;
|
|
TokenList tk;
|
|
if (name=="codecdescriptor") {
|
|
|
|
CodecMap::iterator iter = _codecMap.begin();
|
|
while( iter != _codecMap.end() ) {
|
|
tk.clear();
|
|
std::ostringstream strType;
|
|
strType << iter->first;
|
|
tk.push_back(strType.str());
|
|
tk.push_back(iter->second);
|
|
_gui->sendMessage("100", sequenceId, tk);
|
|
iter++;
|
|
}
|
|
returnValue = true;
|
|
} else if (name=="ringtones") {
|
|
std::string path = std::string(PROGSHAREDIR) + DIR_SEPARATOR_STR + RINGDIR;
|
|
int nbFile = 0;
|
|
returnValue = getDirListing(sequenceId, path, &nbFile);
|
|
|
|
path = std::string(HOMEDIR) + DIR_SEPARATOR_STR + "." + PROGDIR + DIR_SEPARATOR_STR + RINGDIR;
|
|
getDirListing(sequenceId, path, &nbFile);
|
|
} else if (name=="audiodevice") {
|
|
returnValue = getAudioDeviceList(sequenceId);
|
|
} else if (name=="countrytones") {
|
|
returnValue = getCountryTones(sequenceId);
|
|
}
|
|
return returnValue;
|
|
}
|
|
|
|
/**
|
|
* User request Main Thread (list)
|
|
*/
|
|
bool
|
|
ManagerImpl::getAudioDeviceList(const std::string& sequenceId)
|
|
{
|
|
TokenList tk;
|
|
portaudio::AutoSystem autoSys;
|
|
portaudio::System& sys = portaudio::System::instance();
|
|
|
|
const char *hostApiName;
|
|
const char *deviceName;
|
|
|
|
for (int index = 0; index < sys.deviceCount(); index++ ) {
|
|
portaudio::Device& device = sys.deviceByIndex(index);
|
|
hostApiName = device.hostApi().name();
|
|
deviceName = device.name();
|
|
|
|
tk.clear();
|
|
std::ostringstream str; str << index; tk.push_back(str.str());
|
|
tk.push_back(deviceName);
|
|
tk.push_back(std::string(hostApiName));
|
|
_gui->sendMessage("100", sequenceId, tk);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
/**
|
|
* User action : main thread
|
|
*/
|
|
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 = NULL;
|
|
std::string fileName;
|
|
std::string filePathName;
|
|
while ( (cFileName=dir++) != NULL ) {
|
|
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;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Multi Thread
|
|
*/
|
|
void
|
|
ManagerImpl::switchCall(CALLID id)
|
|
{
|
|
CALLID currentCallId = getCurrentCallId();
|
|
if (currentCallId!=0 && id!=currentCallId) {
|
|
onHoldCall(currentCallId);
|
|
}
|
|
setCurrentCallId(id);
|
|
}
|
|
|
|
// EOF
|