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/ini_parser.hpp>
|
||||
#include <boost/format.hpp>
|
||||
#include <boost/foreach.hpp>
|
||||
|
||||
using namespace config;
|
||||
|
||||
@ -50,4 +51,15 @@ std::string config::Configuration::getString(const std::string &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 <string>
|
||||
#include <stdexcept>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace config {
|
||||
|
||||
@ -31,6 +32,8 @@ namespace config {
|
||||
|
||||
std::string getString(const std::string &property);
|
||||
|
||||
std::unordered_map<std::string, std::string> getChildren(const std::string &property);
|
||||
|
||||
private:
|
||||
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 maybeJoinChannel(mumble::MumbleCommunicator *mc);
|
||||
void findJoinChannel(mumble::MumbleCommunicator *mc);
|
||||
void joinOtherChannel(mumble::MumbleCommunicator *mc, std::string channelNameRegex);
|
||||
|
||||
private:
|
||||
log4cpp::Category &logger;
|
||||
|
@ -121,8 +121,8 @@ namespace sip {
|
||||
|
||||
class _Account : public pj::Account {
|
||||
public:
|
||||
_Account(sip::PjsuaCommunicator &comm)
|
||||
: communicator(comm) { }
|
||||
_Account(sip::PjsuaCommunicator &comm, int max_calls)
|
||||
: communicator(comm) { this->max_calls = max_calls; }
|
||||
|
||||
virtual void onRegState(pj::OnRegStateParam &prm) override;
|
||||
|
||||
@ -131,7 +131,8 @@ namespace sip {
|
||||
private:
|
||||
sip::PjsuaCommunicator &communicator;
|
||||
|
||||
bool available = true;
|
||||
int active_calls = 0;
|
||||
int max_calls;
|
||||
|
||||
friend class _Call;
|
||||
};
|
||||
@ -166,7 +167,7 @@ namespace sip {
|
||||
* if no pin is set, go ahead and turn off mute/deaf
|
||||
* 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
|
||||
communicator.dtmf_mode = DTMF_MODE_ROOT;
|
||||
// turning off mute automatically turns off deaf
|
||||
@ -185,7 +186,11 @@ namespace sip {
|
||||
} else if (ci.state == PJSIP_INV_STATE_DISCONNECTED) {
|
||||
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.";
|
||||
|
||||
communicator.calls[ci.id].mixer->clear();
|
||||
@ -198,8 +203,9 @@ namespace sip {
|
||||
|
||||
communicator.calls[ci.id].onDisconnect();
|
||||
|
||||
acc.available = true;
|
||||
}
|
||||
//acc.available = true;
|
||||
acc.active_calls--;
|
||||
//}
|
||||
|
||||
delete this;
|
||||
} else {
|
||||
@ -221,7 +227,7 @@ namespace sip {
|
||||
communicator.calls[ci.id].media->startTransmit(*aud_med);
|
||||
aud_med->startTransmit(*communicator.calls[ci.id].media);
|
||||
} 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;
|
||||
|
||||
auto ci = getInfo();
|
||||
std::string chanName;
|
||||
|
||||
/*
|
||||
* DTMF CALLER MENU
|
||||
@ -308,11 +315,15 @@ namespace sip {
|
||||
/*
|
||||
* When user presses '#', test PIN entry
|
||||
*/
|
||||
if ( communicator.caller_pin.length() > 0 ) {
|
||||
if ( communicator.got_dtmf == communicator.caller_pin ) {
|
||||
if ( communicator.pins.size() > 0 ) {
|
||||
if ( communicator.pins.count(communicator.got_dtmf) > 0 ) {
|
||||
communicator.logger.info("Caller entered correct PIN");
|
||||
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);
|
||||
communicator.calls[ci.id].sendUserState(mumlib::UserState::SELF_MUTE, false);
|
||||
@ -386,12 +397,23 @@ namespace sip {
|
||||
this->playAudioFile(communicator.file_mute_off);
|
||||
communicator.calls[ci.id].sendUserState(mumlib::UserState::SELF_MUTE, false);
|
||||
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
|
||||
communicator.logger.info("Unsupported DTMF digit '%s' in state STAR", prm.digit.c_str());
|
||||
this->playAudioFile(communicator.file_menu);
|
||||
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
|
||||
@ -422,17 +444,13 @@ namespace sip {
|
||||
|
||||
if (communicator.uriValidator.validateUri(uri)) {
|
||||
|
||||
if (available) {
|
||||
if (active_calls < max_calls) {
|
||||
param.statusCode = PJSIP_SC_OK;
|
||||
available = false;
|
||||
active_calls++;
|
||||
} else {
|
||||
/*
|
||||
* EXPERIMENT WITH MULTI-LINE
|
||||
*/
|
||||
communicator.logger.info("MULTI-LINE Incoming call from %s.", uri.c_str());
|
||||
communicator.logger.notice("BUSY - reject incoming call from %s.", uri.c_str());
|
||||
param.statusCode = PJSIP_SC_OK;
|
||||
available = false;
|
||||
//param.statusCode = PJSIP_SC_BUSY_EVERYWHERE;
|
||||
param.statusCode = PJSIP_SC_BUSY_EVERYWHERE;
|
||||
}
|
||||
|
||||
call->answer(param);
|
||||
@ -450,6 +468,7 @@ sip::PjsuaCommunicator::PjsuaCommunicator(IncomingConnectionValidator &validator
|
||||
uriValidator(validator) {
|
||||
|
||||
logWriter.reset(new sip::_LogWriter(pjsuaLogger));
|
||||
max_calls = maxCalls;
|
||||
|
||||
|
||||
endpoint.libCreate();
|
||||
@ -551,7 +570,7 @@ void sip::PjsuaCommunicator::registerAccount(string host, string user, string pa
|
||||
accountConfig.sipConfig.authCreds.push_back(cred);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -80,7 +80,8 @@ namespace sip {
|
||||
std::function<void()> onConnect;
|
||||
std::function<void()> onDisconnect;
|
||||
std::function<void()> onCallerAuth;
|
||||
std::function<void()> joinAuthChannel;
|
||||
std::function<void()> joinAuthChannel; // DEPRECATE ?
|
||||
std::function<void(std::string channelNameRegex)> joinOtherChannel;
|
||||
std::function<void()> joinDefaultChannel;
|
||||
};
|
||||
|
||||
@ -114,6 +115,7 @@ namespace sip {
|
||||
std::string file_mute_on;
|
||||
std::string file_mute_off;
|
||||
std::string file_menu;
|
||||
int max_calls;
|
||||
|
||||
// TODO: move these to private?
|
||||
std::string got_dtmf;
|
||||
@ -126,6 +128,8 @@ namespace sip {
|
||||
|
||||
call calls[MY_MAX_CALLS];
|
||||
|
||||
std::unordered_map<std::string, std::string> pins;
|
||||
|
||||
private:
|
||||
log4cpp::Category &logger;
|
||||
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);
|
||||
|
||||
try {
|
||||
pjsuaCommunicator.pins = conf.getChildren("pins");
|
||||
} catch (...) {
|
||||
}
|
||||
|
||||
mumble::MumbleCommunicatorConfig mumbleConf;
|
||||
mumbleConf.host = conf.getString("mumble.host");
|
||||
mumbleConf.port = conf.getInt("mumble.port");
|
||||
@ -79,19 +84,6 @@ int main(int argc, char *argv[]) {
|
||||
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");
|
||||
} catch (...) {
|
||||
pjsuaCommunicator.file_welcome = "welcome.wav";
|
||||
@ -137,23 +129,10 @@ int main(int argc, char *argv[]) {
|
||||
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 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 mumbleAuthChannelJoiner(authChan);
|
||||
mumble::MumbleChannelJoiner mumbleOtherChannelJoiner(defaultChan);
|
||||
|
||||
for (int i = 0; i<max_calls; i++) {
|
||||
|
||||
@ -223,11 +202,12 @@ int main(int argc, char *argv[]) {
|
||||
&mumbleChannelJoiner,
|
||||
mumcom);
|
||||
|
||||
// PJ notifies Mumble that Caller Auth is done
|
||||
pjsuaCommunicator.calls[i].joinAuthChannel = std::bind(
|
||||
&mumble::MumbleChannelJoiner::findJoinChannel,
|
||||
&mumbleAuthChannelJoiner,
|
||||
mumcom);
|
||||
// PJ notifies Mumble to join other channel
|
||||
pjsuaCommunicator.calls[i].joinOtherChannel = std::bind(
|
||||
&mumble::MumbleChannelJoiner::joinOtherChannel,
|
||||
&mumbleOtherChannelJoiner,
|
||||
mumcom,
|
||||
_1);
|
||||
|
||||
// Passing audio from Mumble to SIP
|
||||
mumcom->onIncomingPcmSamples = std::bind(
|
||||
|
@ -1,3 +1,3 @@
|
||||
Press star one for status.
|
||||
Press star five to 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