Add support for multiple caller pins
In config.ini, add the [pins] section, with key/value entries for the expected pin and the channel regex to switch to when the caller enters the pin. Here's an example: [pins] 12345 = DevOps Team 23456 = Sales Team
This commit is contained in:
parent
d3213be149
commit
75cafbfefe
@ -3,6 +3,7 @@
|
|||||||
#include <boost/property_tree/ptree.hpp>
|
#include <boost/property_tree/ptree.hpp>
|
||||||
#include <boost/property_tree/ini_parser.hpp>
|
#include <boost/property_tree/ini_parser.hpp>
|
||||||
#include <boost/format.hpp>
|
#include <boost/format.hpp>
|
||||||
|
#include <boost/foreach.hpp>
|
||||||
|
|
||||||
using namespace config;
|
using namespace config;
|
||||||
|
|
||||||
@ -50,4 +51,15 @@ std::string config::Configuration::getString(const std::string &property) {
|
|||||||
return get<std::string>(impl->ptree, property);
|
return get<std::string>(impl->ptree, property);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: return set
|
||||||
|
std::unordered_map<std::string, std::string> config::Configuration::getChildren(const std::string &property) {
|
||||||
|
std::unordered_map<std::string, std::string> pins;
|
||||||
|
BOOST_FOREACH(boost::property_tree::ptree::value_type &v,
|
||||||
|
impl->ptree.get_child(property)) {
|
||||||
|
//pins[v.first.data()] = get<std::string>(impl->ptree, property + "." + v.second.data());
|
||||||
|
pins[v.first.data()] = v.second.data();
|
||||||
|
}
|
||||||
|
return pins;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
namespace config {
|
namespace config {
|
||||||
|
|
||||||
@ -31,6 +32,8 @@ namespace config {
|
|||||||
|
|
||||||
std::string getString(const std::string &property);
|
std::string getString(const std::string &property);
|
||||||
|
|
||||||
|
std::unordered_map<std::string, std::string> getChildren(const std::string &property);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ConfigurationImpl *impl;
|
ConfigurationImpl *impl;
|
||||||
};
|
};
|
||||||
|
@ -50,3 +50,9 @@ void mumble::MumbleChannelJoiner::findJoinChannel(mumble::MumbleCommunicator *mc
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void mumble::MumbleChannelJoiner::joinOtherChannel(mumble::MumbleCommunicator *mc, std::string channelNameRegex) {
|
||||||
|
this->channelNameRegex = boost::regex(channelNameRegex);
|
||||||
|
findJoinChannel(mc);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -22,6 +22,7 @@ namespace mumble {
|
|||||||
void checkChannel(std::string channel_name, int channel_id);
|
void checkChannel(std::string channel_name, int channel_id);
|
||||||
void maybeJoinChannel(mumble::MumbleCommunicator *mc);
|
void maybeJoinChannel(mumble::MumbleCommunicator *mc);
|
||||||
void findJoinChannel(mumble::MumbleCommunicator *mc);
|
void findJoinChannel(mumble::MumbleCommunicator *mc);
|
||||||
|
void joinOtherChannel(mumble::MumbleCommunicator *mc, std::string channelNameRegex);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
log4cpp::Category &logger;
|
log4cpp::Category &logger;
|
||||||
|
@ -121,8 +121,8 @@ namespace sip {
|
|||||||
|
|
||||||
class _Account : public pj::Account {
|
class _Account : public pj::Account {
|
||||||
public:
|
public:
|
||||||
_Account(sip::PjsuaCommunicator &comm)
|
_Account(sip::PjsuaCommunicator &comm, int max_calls)
|
||||||
: communicator(comm) { }
|
: communicator(comm) { this->max_calls = max_calls; }
|
||||||
|
|
||||||
virtual void onRegState(pj::OnRegStateParam &prm) override;
|
virtual void onRegState(pj::OnRegStateParam &prm) override;
|
||||||
|
|
||||||
@ -131,7 +131,8 @@ namespace sip {
|
|||||||
private:
|
private:
|
||||||
sip::PjsuaCommunicator &communicator;
|
sip::PjsuaCommunicator &communicator;
|
||||||
|
|
||||||
bool available = true;
|
int active_calls = 0;
|
||||||
|
int max_calls;
|
||||||
|
|
||||||
friend class _Call;
|
friend class _Call;
|
||||||
};
|
};
|
||||||
@ -166,7 +167,7 @@ namespace sip {
|
|||||||
* if no pin is set, go ahead and turn off mute/deaf
|
* if no pin is set, go ahead and turn off mute/deaf
|
||||||
* otherwise, wait for pin to be entered
|
* otherwise, wait for pin to be entered
|
||||||
*/
|
*/
|
||||||
if ( communicator.caller_pin.length() == 0 ) {
|
if ( communicator.pins.size() == 0 ) {
|
||||||
// No PIN set... enter DTMF root menu and turn off mute/deaf
|
// No PIN set... enter DTMF root menu and turn off mute/deaf
|
||||||
communicator.dtmf_mode = DTMF_MODE_ROOT;
|
communicator.dtmf_mode = DTMF_MODE_ROOT;
|
||||||
// turning off mute automatically turns off deaf
|
// turning off mute automatically turns off deaf
|
||||||
@ -185,7 +186,11 @@ namespace sip {
|
|||||||
} else if (ci.state == PJSIP_INV_STATE_DISCONNECTED) {
|
} else if (ci.state == PJSIP_INV_STATE_DISCONNECTED) {
|
||||||
auto &acc = dynamic_cast<_Account &>(account);
|
auto &acc = dynamic_cast<_Account &>(account);
|
||||||
|
|
||||||
if (not acc.available) {
|
/*
|
||||||
|
* Not sure why we check acc.available, but with multi-call
|
||||||
|
* functionality, this check doesn't work.
|
||||||
|
*/
|
||||||
|
//if (not acc.available) {
|
||||||
auto msgText = "Call from " + address + " finished.";
|
auto msgText = "Call from " + address + " finished.";
|
||||||
|
|
||||||
communicator.calls[ci.id].mixer->clear();
|
communicator.calls[ci.id].mixer->clear();
|
||||||
@ -198,8 +203,9 @@ namespace sip {
|
|||||||
|
|
||||||
communicator.calls[ci.id].onDisconnect();
|
communicator.calls[ci.id].onDisconnect();
|
||||||
|
|
||||||
acc.available = true;
|
//acc.available = true;
|
||||||
}
|
acc.active_calls--;
|
||||||
|
//}
|
||||||
|
|
||||||
delete this;
|
delete this;
|
||||||
} else {
|
} else {
|
||||||
@ -221,7 +227,7 @@ namespace sip {
|
|||||||
communicator.calls[ci.id].media->startTransmit(*aud_med);
|
communicator.calls[ci.id].media->startTransmit(*aud_med);
|
||||||
aud_med->startTransmit(*communicator.calls[ci.id].media);
|
aud_med->startTransmit(*communicator.calls[ci.id].media);
|
||||||
} else if (ci.media[0].status == PJSUA_CALL_MEDIA_NONE) {
|
} else if (ci.media[0].status == PJSUA_CALL_MEDIA_NONE) {
|
||||||
dynamic_cast<_Account &>(account).available = true;
|
dynamic_cast<_Account &>(account).active_calls++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -293,6 +299,7 @@ namespace sip {
|
|||||||
pj::CallOpParam param;
|
pj::CallOpParam param;
|
||||||
|
|
||||||
auto ci = getInfo();
|
auto ci = getInfo();
|
||||||
|
std::string chanName;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* DTMF CALLER MENU
|
* DTMF CALLER MENU
|
||||||
@ -308,11 +315,15 @@ namespace sip {
|
|||||||
/*
|
/*
|
||||||
* When user presses '#', test PIN entry
|
* When user presses '#', test PIN entry
|
||||||
*/
|
*/
|
||||||
if ( communicator.caller_pin.length() > 0 ) {
|
if ( communicator.pins.size() > 0 ) {
|
||||||
if ( communicator.got_dtmf == communicator.caller_pin ) {
|
if ( communicator.pins.count(communicator.got_dtmf) > 0 ) {
|
||||||
communicator.logger.info("Caller entered correct PIN");
|
communicator.logger.info("Caller entered correct PIN");
|
||||||
communicator.dtmf_mode = DTMF_MODE_ROOT;
|
communicator.dtmf_mode = DTMF_MODE_ROOT;
|
||||||
communicator.calls[ci.id].joinAuthChannel();
|
communicator.logger.notice("MYDEBUG: %s:%s",
|
||||||
|
communicator.got_dtmf.c_str(),
|
||||||
|
communicator.pins[communicator.got_dtmf].c_str());
|
||||||
|
communicator.calls[ci.id].joinOtherChannel(
|
||||||
|
communicator.pins[communicator.got_dtmf]);
|
||||||
|
|
||||||
this->playAudioFile(communicator.file_entering_channel);
|
this->playAudioFile(communicator.file_entering_channel);
|
||||||
communicator.calls[ci.id].sendUserState(mumlib::UserState::SELF_MUTE, false);
|
communicator.calls[ci.id].sendUserState(mumlib::UserState::SELF_MUTE, false);
|
||||||
@ -386,12 +397,23 @@ namespace sip {
|
|||||||
this->playAudioFile(communicator.file_mute_off);
|
this->playAudioFile(communicator.file_mute_off);
|
||||||
communicator.calls[ci.id].sendUserState(mumlib::UserState::SELF_MUTE, false);
|
communicator.calls[ci.id].sendUserState(mumlib::UserState::SELF_MUTE, false);
|
||||||
break;
|
break;
|
||||||
case '0':
|
case '9':
|
||||||
|
if ( communicator.pins.size() > 0 ) {
|
||||||
|
communicator.dtmf_mode = DTMF_MODE_UNAUTH;
|
||||||
|
communicator.calls[ci.id].sendUserState(mumlib::UserState::SELF_DEAF, true);
|
||||||
|
communicator.calls[ci.id].joinDefaultChannel();
|
||||||
|
this->playAudioFile(communicator.file_prompt_pin);
|
||||||
|
} else {
|
||||||
|
// we should have a 'not supported' message
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case '0': // block these for the menu itself
|
||||||
|
case '*':
|
||||||
|
default:
|
||||||
// play menu
|
// play menu
|
||||||
|
communicator.logger.info("Unsupported DTMF digit '%s' in state STAR", prm.digit.c_str());
|
||||||
this->playAudioFile(communicator.file_menu);
|
this->playAudioFile(communicator.file_menu);
|
||||||
break;
|
break;
|
||||||
default:
|
|
||||||
communicator.logger.info("Unsupported DTMF digit '%s' in state STAR", prm.digit.c_str());
|
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
* In any case, switch back to root after one digit
|
* In any case, switch back to root after one digit
|
||||||
@ -422,17 +444,13 @@ namespace sip {
|
|||||||
|
|
||||||
if (communicator.uriValidator.validateUri(uri)) {
|
if (communicator.uriValidator.validateUri(uri)) {
|
||||||
|
|
||||||
if (available) {
|
if (active_calls < max_calls) {
|
||||||
param.statusCode = PJSIP_SC_OK;
|
param.statusCode = PJSIP_SC_OK;
|
||||||
available = false;
|
active_calls++;
|
||||||
} else {
|
} else {
|
||||||
/*
|
communicator.logger.notice("BUSY - reject incoming call from %s.", uri.c_str());
|
||||||
* EXPERIMENT WITH MULTI-LINE
|
|
||||||
*/
|
|
||||||
communicator.logger.info("MULTI-LINE Incoming call from %s.", uri.c_str());
|
|
||||||
param.statusCode = PJSIP_SC_OK;
|
param.statusCode = PJSIP_SC_OK;
|
||||||
available = false;
|
param.statusCode = PJSIP_SC_BUSY_EVERYWHERE;
|
||||||
//param.statusCode = PJSIP_SC_BUSY_EVERYWHERE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
call->answer(param);
|
call->answer(param);
|
||||||
@ -450,6 +468,7 @@ sip::PjsuaCommunicator::PjsuaCommunicator(IncomingConnectionValidator &validator
|
|||||||
uriValidator(validator) {
|
uriValidator(validator) {
|
||||||
|
|
||||||
logWriter.reset(new sip::_LogWriter(pjsuaLogger));
|
logWriter.reset(new sip::_LogWriter(pjsuaLogger));
|
||||||
|
max_calls = maxCalls;
|
||||||
|
|
||||||
|
|
||||||
endpoint.libCreate();
|
endpoint.libCreate();
|
||||||
@ -551,7 +570,7 @@ void sip::PjsuaCommunicator::registerAccount(string host, string user, string pa
|
|||||||
accountConfig.sipConfig.authCreds.push_back(cred);
|
accountConfig.sipConfig.authCreds.push_back(cred);
|
||||||
|
|
||||||
logger.info("Registering account for URI: %s.", uri.c_str());
|
logger.info("Registering account for URI: %s.", uri.c_str());
|
||||||
account.reset(new _Account(*this));
|
account.reset(new _Account(*this, max_calls));
|
||||||
account->create(accountConfig);
|
account->create(accountConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -80,7 +80,8 @@ namespace sip {
|
|||||||
std::function<void()> onConnect;
|
std::function<void()> onConnect;
|
||||||
std::function<void()> onDisconnect;
|
std::function<void()> onDisconnect;
|
||||||
std::function<void()> onCallerAuth;
|
std::function<void()> onCallerAuth;
|
||||||
std::function<void()> joinAuthChannel;
|
std::function<void()> joinAuthChannel; // DEPRECATE ?
|
||||||
|
std::function<void(std::string channelNameRegex)> joinOtherChannel;
|
||||||
std::function<void()> joinDefaultChannel;
|
std::function<void()> joinDefaultChannel;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -114,6 +115,7 @@ namespace sip {
|
|||||||
std::string file_mute_on;
|
std::string file_mute_on;
|
||||||
std::string file_mute_off;
|
std::string file_mute_off;
|
||||||
std::string file_menu;
|
std::string file_menu;
|
||||||
|
int max_calls;
|
||||||
|
|
||||||
// TODO: move these to private?
|
// TODO: move these to private?
|
||||||
std::string got_dtmf;
|
std::string got_dtmf;
|
||||||
@ -126,6 +128,8 @@ namespace sip {
|
|||||||
|
|
||||||
call calls[MY_MAX_CALLS];
|
call calls[MY_MAX_CALLS];
|
||||||
|
|
||||||
|
std::unordered_map<std::string, std::string> pins;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
log4cpp::Category &logger;
|
log4cpp::Category &logger;
|
||||||
log4cpp::Category &pjsuaLogger;
|
log4cpp::Category &pjsuaLogger;
|
||||||
|
44
main.cpp
44
main.cpp
@ -60,6 +60,11 @@ int main(int argc, char *argv[]) {
|
|||||||
|
|
||||||
sip::PjsuaCommunicator pjsuaCommunicator(connectionValidator, conf.getInt("sip.frameLength"), max_calls);
|
sip::PjsuaCommunicator pjsuaCommunicator(connectionValidator, conf.getInt("sip.frameLength"), max_calls);
|
||||||
|
|
||||||
|
try {
|
||||||
|
pjsuaCommunicator.pins = conf.getChildren("pins");
|
||||||
|
} catch (...) {
|
||||||
|
}
|
||||||
|
|
||||||
mumble::MumbleCommunicatorConfig mumbleConf;
|
mumble::MumbleCommunicatorConfig mumbleConf;
|
||||||
mumbleConf.host = conf.getString("mumble.host");
|
mumbleConf.host = conf.getString("mumble.host");
|
||||||
mumbleConf.port = conf.getInt("mumble.port");
|
mumbleConf.port = conf.getInt("mumble.port");
|
||||||
@ -79,19 +84,6 @@ int main(int argc, char *argv[]) {
|
|||||||
mumbleConf.comment = "";
|
mumbleConf.comment = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
|
||||||
mumbleConf.authchan = conf.getString("mumble.channelAuthExpression");
|
|
||||||
} catch (...) {
|
|
||||||
mumbleConf.authchan = "";
|
|
||||||
}
|
|
||||||
|
|
||||||
/* default to <no pin> */
|
|
||||||
try {
|
|
||||||
pjsuaCommunicator.caller_pin = conf.getString("app.caller_pin");
|
|
||||||
} catch (...) {
|
|
||||||
pjsuaCommunicator.caller_pin = "";
|
|
||||||
}
|
|
||||||
|
|
||||||
try { pjsuaCommunicator.file_welcome = conf.getString("files.welcome");
|
try { pjsuaCommunicator.file_welcome = conf.getString("files.welcome");
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
pjsuaCommunicator.file_welcome = "welcome.wav";
|
pjsuaCommunicator.file_welcome = "welcome.wav";
|
||||||
@ -137,23 +129,10 @@ int main(int argc, char *argv[]) {
|
|||||||
pjsuaCommunicator.file_menu = "menu.wav";
|
pjsuaCommunicator.file_menu = "menu.wav";
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If the channelUnauthExpression is set, use this as the default
|
|
||||||
* channel and use channelNameExpression for the authchan. Otherwise,
|
|
||||||
* use the channelNameExpression for the default.
|
|
||||||
*/
|
|
||||||
std::string defaultChan = conf.getString("mumble.channelNameExpression");
|
std::string defaultChan = conf.getString("mumble.channelNameExpression");
|
||||||
std::string authChan = "";
|
|
||||||
|
|
||||||
if ( pjsuaCommunicator.caller_pin.size() > 0 ) {
|
|
||||||
try {
|
|
||||||
authChan = conf.getString("mumble.channelAuthExpression");
|
|
||||||
} catch (...) {
|
|
||||||
// defaultChan = conf.getString("mumble.channelNameExpression");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mumble::MumbleChannelJoiner mumbleChannelJoiner(defaultChan);
|
mumble::MumbleChannelJoiner mumbleChannelJoiner(defaultChan);
|
||||||
mumble::MumbleChannelJoiner mumbleAuthChannelJoiner(authChan);
|
mumble::MumbleChannelJoiner mumbleOtherChannelJoiner(defaultChan);
|
||||||
|
|
||||||
for (int i = 0; i<max_calls; i++) {
|
for (int i = 0; i<max_calls; i++) {
|
||||||
|
|
||||||
@ -223,11 +202,12 @@ int main(int argc, char *argv[]) {
|
|||||||
&mumbleChannelJoiner,
|
&mumbleChannelJoiner,
|
||||||
mumcom);
|
mumcom);
|
||||||
|
|
||||||
// PJ notifies Mumble that Caller Auth is done
|
// PJ notifies Mumble to join other channel
|
||||||
pjsuaCommunicator.calls[i].joinAuthChannel = std::bind(
|
pjsuaCommunicator.calls[i].joinOtherChannel = std::bind(
|
||||||
&mumble::MumbleChannelJoiner::findJoinChannel,
|
&mumble::MumbleChannelJoiner::joinOtherChannel,
|
||||||
&mumbleAuthChannelJoiner,
|
&mumbleOtherChannelJoiner,
|
||||||
mumcom);
|
mumcom,
|
||||||
|
_1);
|
||||||
|
|
||||||
// Passing audio from Mumble to SIP
|
// Passing audio from Mumble to SIP
|
||||||
mumcom->onIncomingPcmSamples = std::bind(
|
mumcom->onIncomingPcmSamples = std::bind(
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
Press star one for status.
|
|
||||||
Press star five to mute.
|
Press star five to mute.
|
||||||
Press star six to un-mute.
|
Press star six to un-mute.
|
||||||
|
Press star nine to change channel.
|
||||||
|
BIN
media/menu.wav
BIN
media/menu.wav
Binary file not shown.
Loading…
Reference in New Issue
Block a user