added dialout in conferencing module.

git-svn-id: http://svn.berlios.de/svnroot/repos/sems/trunk@42 8eb893ce-cfd4-0310-b710-fb5ebe64c474
sayer/1.4-spce2.6
Raphael Coeffic 20 years ago
parent 75a8aa318a
commit 9421bbe432

@ -31,6 +31,9 @@
#include "AmConferenceStatus.h"
#include "AmConfig.h"
#include "AmSessionContainer.h"
#include "AmSessionScheduler.h"
#include "sems.h"
#include "log.h"
@ -46,6 +49,7 @@ ConferenceFactory::ConferenceFactory(const string& _app_name)
string ConferenceFactory::LonelyUserFile;
string ConferenceFactory::JoinSound;
string ConferenceFactory::DropSound;
string ConferenceFactory::DialoutSuffix;
int ConferenceFactory::onLoad()
{
@ -66,6 +70,12 @@ int ConferenceFactory::onLoad()
JoinSound = cfg.getParameter("join_sound");
DropSound = cfg.getParameter("drop_sound");
DialoutSuffix = cfg.getParameter("dialout_suffix");
if(DialoutSuffix.empty()){
WARN("No dialout_suffix has been configured in the conference plug-in:\n");
WARN("\t -> dial out will not be available\n");
}
return 0;
}
@ -74,13 +84,20 @@ AmSession* ConferenceFactory::onInvite(const AmSipRequest& req)
return new ConferenceDialog(req.user);
}
ConferenceDialog::ConferenceDialog(const string& conf_id)
: conf_id(conf_id), channel(0), play_list(this)
ConferenceDialog::ConferenceDialog(const string& conf_id,
AmConferenceChannel* dialout_channel)
: conf_id(conf_id),
channel(0),
play_list(this),
dialout_channel(dialout_channel),
state(CS_normal)
{
dialedout = this->dialout_channel.get() != 0;
}
ConferenceDialog::~ConferenceDialog()
{
DBG("ConferenceDialog::~ConferenceDialog()\n");
}
void ConferenceDialog::onStart()
@ -89,6 +106,16 @@ void ConferenceDialog::onStart()
}
void ConferenceDialog::onSessionStart(const AmSipRequest& req)
{
setupAudio();
}
void ConferenceDialog::onSessionStart(const AmSipReply& reply)
{
setupAudio();
}
void ConferenceDialog::setupAudio()
{
if(!ConferenceFactory::JoinSound.empty()) {
@ -106,29 +133,39 @@ void ConferenceDialog::onSessionStart(const AmSipRequest& req)
DropSound.reset(0);
}
channel.reset(AmConferenceStatus::getChannel(conf_id,getLocalTag()));
play_list.close();// !!!
if(dialout_channel.get()){
play_list.addToPlaylist(new AmPlaylistItem(dialout_channel.get(),
dialout_channel.get()));
}
else {
channel.reset(AmConferenceStatus::getChannel(conf_id,getLocalTag()));
play_list.addToPlaylist(new AmPlaylistItem(channel.get(),channel.get()));
play_list.addToPlaylist(new AmPlaylistItem(channel.get(),
channel.get()));
}
setInOut(&play_list,&play_list);
setCallgroup(conf_id);
//setInOut(channel.get(),channel.get());
}
void ConferenceDialog::onBye(const AmSipRequest& req)
{
play_list.close();
setInOut(NULL,NULL);
channel.reset(NULL);
if(dialout_channel.get())
disconnectDialout();
closeChannels();
setStopped();
}
void ConferenceDialog::process(AmEvent* ev)
{
ConferenceEvent* ce = dynamic_cast<ConferenceEvent*>(ev);
if(ce){
if(ce && (conf_id == ce->conf_id)){
switch(ce->event_id){
case ConfNewParticipant:
@ -172,5 +209,257 @@ void ConferenceDialog::process(AmEvent* ev)
return;
}
DialoutConfEvent* do_ev = dynamic_cast<DialoutConfEvent*>(ev);
if(do_ev){
if(dialedout){
switch(do_ev->event_id){
case DoConfConnect:
connectMainChannel();
break;
case DoConfDisconnect:
dlg.bye();
closeChannels();
setStopped();
break;
default:
break;
}
}
else {
switch(do_ev->event_id){
case DoConfDisconnect:
connectMainChannel();
break;
case DoConfConnect:
state = CS_dialout_connected;
break;
}
}
return;
}
AmSession::process(ev);
}
string dtmf2str(int event)
{
switch(event){
case 0: case 1: case 2:
case 3: case 4: case 5:
case 6: case 7: case 8:
case 9:
return int2str(event);
case 10: return "*";
case 11: return "#";
default: return "";
}
}
void ConferenceDialog::onDtmf(int event, int duration)
{
DBG("ConferenceDialog::onDtmf\n");
if(dialedout)
return;
switch(state){
case CS_normal:
dtmf_seq += dtmf2str(event);
if(dtmf_seq.length() == 2){
if(dtmf_seq == "#*")
state = CS_dialing_out;
dtmf_seq = "";
}
break;
case CS_dialing_out:{
string digit = dtmf2str(event);
if(digit == "*"){
if(!dtmf_seq.empty()){
createDialoutParticipant("sip:" + dtmf_seq +
ConferenceFactory::DialoutSuffix);
state = CS_dialed_out;
}
else {
state = CS_normal;
}
dtmf_seq = "";
}
else
dtmf_seq += digit;
} break;
case CS_dialout_connected:
if(event == 10){ // '*'
AmSessionContainer::instance()
->postEvent(dialout_id,
new DialoutConfEvent(DoConfConnect,
getLocalTag()));
connectMainChannel();
}
break;
case CS_dialed_out:
if(event == 11){ // '#'
disconnectDialout();
}
break;
}
}
void ConferenceDialog::createDialoutParticipant(const string& uri)
{
dialout_channel.reset(AmConferenceStatus::getChannel(getLocalTag(),getLocalTag()));
dialout_id = AmSession::getNewId();
ConferenceDialog* dialout_session =
new ConferenceDialog(conf_id,
AmConferenceStatus::getChannel(getLocalTag(),
dialout_id));
AmSipDialog& dialout_dlg = dialout_session->dlg;
dialout_dlg.local_tag = dialout_id;
dialout_dlg.callid = AmSession::getNewId() + "@" + AmConfig::LocalIP;
dialout_dlg.local_party = dlg.local_party;
dialout_dlg.remote_party = uri;
dialout_dlg.remote_uri = uri;
string body;
int local_port = dialout_session->rtp_str.getLocalPort();
dialout_session->sdp.genRequest(AmConfig::LocalIP,local_port,body);
dialout_dlg.sendRequest("INVITE","application/sdp",body,"");
play_list.close(); // !!!
play_list.addToPlaylist(new AmPlaylistItem(dialout_channel.get(),
dialout_channel.get()));
dialout_session->start();
AmSessionContainer* sess_cont = AmSessionContainer::instance();
sess_cont->addSession(dialout_id,dialout_session);
}
void ConferenceDialog::disconnectDialout()
{
if(dialedout){
if(dialout_channel.get()){
AmSessionContainer::instance()
->postEvent(dialout_channel->getConfID(),
new DialoutConfEvent(DoConfDisconnect,
dialout_channel->getConfID()));
}
}
else {
AmSessionContainer::instance()
->postEvent(dialout_id,
new DialoutConfEvent(DoConfDisconnect,
getLocalTag()));
connectMainChannel();
}
}
void ConferenceDialog::connectMainChannel()
{
dialout_id = "";
dialout_channel.reset(NULL);
play_list.close();
if(!channel.get())
channel.reset(AmConferenceStatus
::getChannel(conf_id,
getLocalTag()));
play_list.addToPlaylist(new AmPlaylistItem(channel.get(),
channel.get()));
}
void ConferenceDialog::closeChannels()
{
play_list.close();
setInOut(NULL,NULL);
channel.reset(NULL);
dialout_channel.reset(NULL);
}
void ConferenceDialog::onSipReply(const AmSipReply& reply)
{
int status = dlg.getStatus();
AmSession::onSipReply(reply);
if(status < AmSipDialog::Connected){
switch(dlg.getStatus()){
case AmSipDialog::Connected:
// connected!
if(acceptAudio(reply.body,reply.hdrs)){
ERROR("could not connect audio!!!\n");
dlg.bye();
setStopped();
}
else {
if(getDetached() && !getStopped()){
onSessionStart(reply);
if(getInput() || getOutput())
AmSessionScheduler::instance()->addSession(this,
getCallgroup());
else {
ERROR("missing audio input and/or ouput.\n");
}
// send connect event
AmSessionContainer::instance()
->postEvent(dialout_channel->getConfID(),
new DialoutConfEvent(DoConfConnect,
dialout_channel->getConfID()));
}
}
break;
case AmSipDialog::Pending:
switch(reply.code){
case 180: break;//TODO: local ring tone.
case 183: break;//TODO: remote ring tone.
default: break;// continue waiting.
}
}
}
}

@ -42,12 +42,33 @@ using std::string;
class ConferenceStatus;
class ConferenceStatusContainer;
enum { CS_normal=0,
CS_dialing_out,
CS_dialed_out,
CS_dialout_connected };
enum { DoConfConnect = 100,
DoConfDisconnect };
struct DialoutConfEvent : public AmEvent {
string conf_id;
DialoutConfEvent(int event_id,
const string& conf_id)
: AmEvent(event_id),
conf_id(conf_id)
{}
};
class ConferenceFactory : public AmSessionFactory
{
public:
static string LonelyUserFile;
static string JoinSound;
static string DropSound;
static string DialoutSuffix;
ConferenceFactory(const string& _app_name);
virtual AmSession* onInvite(const AmSipRequest&);
@ -62,17 +83,37 @@ class ConferenceDialog : public AmSession
auto_ptr<AmAudioFile> JoinSound;
auto_ptr<AmAudioFile> DropSound;
string conf_id;
auto_ptr<AmConferenceChannel> channel;
int state;
string dtmf_seq;
bool dialedout;
string dialout_id;
auto_ptr<AmConferenceChannel> dialout_channel;
void createDialoutParticipant(const string& uri);
void disconnectDialout();
void connectMainChannel();
void closeChannels();
void setupAudio();
public:
ConferenceDialog(const string& conf_id);
ConferenceDialog(const string& conf_id,
AmConferenceChannel* dialout_channel=0);
~ConferenceDialog();
void process(AmEvent* ev);
void onStart();
void onDtmf(int event, int duration);
void onSessionStart(const AmSipReply& reply);
void onSessionStart(const AmSipRequest& req);
void onBye(const AmSipRequest& req);
void onSipReply(const AmSipReply& reply);
};
#endif

@ -75,7 +75,7 @@ int EarlyAnnounceFactory::onLoad()
void EarlyAnnounceDialog::onInvite(const AmSipRequest& req)
{
string sdp_reply;
if(acceptAudio(req,sdp_reply)!=0)
if(acceptAudio(req.body,req.hdrs,&sdp_reply)!=0)
return;
if(dlg.reply(req,183,"Session Progress",

@ -1,5 +1,5 @@
subject: Voice message from: %from%
from: voicemail@%domain%
from:raf@samson
to: %email%
Hello %user%@%domain%,

@ -27,6 +27,7 @@ public:
~AmConferenceChannel();
string getConfID() { return conf_id; }
};

@ -97,6 +97,7 @@ AmConferenceStatus::AmConferenceStatus(const string& conference_id)
AmConferenceStatus::~AmConferenceStatus()
{
DBG("AmConferenceStatus::~AmConferenceStatus(): conf_id = %s\n",conf_id.c_str());
}
AmConferenceChannel* AmConferenceStatus::getChannel(const string& sess_id)
@ -119,14 +120,15 @@ AmConferenceChannel* AmConferenceStatus::getChannel(const string& sess_id)
AmSessionContainer::instance()->postEvent(
it->first,
new ConferenceEvent(ConfNewParticipant,
participants)
participants,conf_id)
);
}
}
else {
// The First participant gets its own NewParticipant message
AmSessionContainer::instance()->postEvent(
sess_id, new ConferenceEvent(ConfNewParticipant,1));
sess_id, new ConferenceEvent(ConfNewParticipant,1,
conf_id));
}
unsigned int ch_id = mixer.addChannel();
@ -165,7 +167,8 @@ int AmConferenceStatus::releaseChannel(unsigned int ch_id)
AmSessionContainer::instance()->postEvent(
s_it->first,
new ConferenceEvent(ConfParticipantLeft,
participants));
participants,
conf_id));
}
}

@ -46,10 +46,14 @@ enum { ConfNewParticipant = 1,
struct ConferenceEvent: public AmEvent
{
unsigned int participants;
string conf_id;
ConferenceEvent(int event_id, unsigned int participants)
ConferenceEvent(int event_id,
unsigned int participants,
const string& conf_id)
: AmEvent(event_id),
participants(participants)
participants(participants),
conf_id(conf_id)
{}
};

@ -197,6 +197,7 @@ int AmRtpStream::receive( unsigned char* buffer, unsigned int size,
{
AmRtpPacket rp;
int err = nextPacket(rp);
if(err <= 0)
return err;
@ -318,7 +319,6 @@ AmRtpStream::~AmRtpStream()
{
if(l_sd){
AmRtpReceiver::instance()->removeStream(l_sd);
//AmIcmpWatcher::instance()->removeStream(l_port);
close(l_sd);
}
}

@ -174,7 +174,7 @@ class AmSdp
* Generate an SDP offer.
* @return !=0 if error encountered.
*/
int genRequest(const string& dstip,int localport, string& out_buf);
int genRequest(const string& localip,int localport, string& out_buf);
/**
* Get a compatible payload from SDP offer/response.

@ -215,7 +215,7 @@ int AmSession::getRPort()
void AmSession::negotiate(const string& sdp_body,
bool force_symmetric_rtp,
string& sdp_reply)
string* sdp_reply)
{
string r_host = "";
int r_port = 0;
@ -266,7 +266,8 @@ void AmSession::negotiate(const string& sdp_body,
passive_mode = true;
}
sdp.genResponse(AmConfig::LocalIP,rtp_str.getLocalPort(),sdp_reply);
if(sdp_reply)
sdp.genResponse(AmConfig::LocalIP,rtp_str.getLocalPort(),*sdp_reply);
lockAudio();
rtp_str.setLocalIP(AmConfig::LocalIP);
@ -514,7 +515,7 @@ void AmSession::onSipReply(const AmSipReply& reply)
void AmSession::onInvite(const AmSipRequest& req)
{
string sdp_reply;
if(acceptAudio(req,sdp_reply)!=0)
if(acceptAudio(req.body,req.hdrs,&sdp_reply)!=0)
return;
if(dlg.reply(req,200,"OK",
@ -530,20 +531,21 @@ void AmSession::onBye(const AmSipRequest& req)
setStopped();
}
int AmSession::acceptAudio(const AmSipRequest& req,
string& sdp_reply)
int AmSession::acceptAudio(const string& body,
const string& hdrs,
string* sdp_reply)
{
try {
try {
// handle codec and send reply
string str_msg_flags = getHeader(req.hdrs,"P-MsgFlags");
string str_msg_flags = getHeader(hdrs,"P-MsgFlags");
unsigned int msg_flags = 0;
if(reverse_hex2int(str_msg_flags,msg_flags)){
ERROR("while parsing 'P-MsgFlags' header\n");
msg_flags = 0;
}
negotiate( req.body,
negotiate( body,
msg_flags & FL_FORCE_ACTIVE,
sdp_reply);
@ -568,9 +570,9 @@ int AmSession::acceptAudio(const AmSipRequest& req,
}
catch(const AmSession::Exception& e){
ERROR("%i %s\n",e.code,e.reason.c_str());
if(dlg.reply(req,e.code,e.reason, "")){
dlg.bye();
}
// if(dlg.reply(req,e.code,e.reason, "")){
// dlg.bye();
// }
setStopped();
}

@ -177,13 +177,15 @@ public:
* the session to the scheduler!
*/
void setCallgroup(const string& cg);
string getCallgroup() { return callgroup; }
/**
* Accept the INVITE proposal
* Accept the SDP proposal
* thus setting up audio stream
*/
int acceptAudio(const AmSipRequest& req,
string& sdp_reply);
int acceptAudio(const string& body,
const string& hdrs = "",
string* sdp_reply=0);
/**
* Lock and unlock audio input & output
@ -236,7 +238,7 @@ public:
/** handle SDP negotiation: only for INVITEs & re-INVITEs */
virtual void negotiate(const string& sdp_body,
bool force_symmetric_rtp,
string& sdp_reply);
string* sdp_reply);
void sendUpdate();
void sendReinvite();
@ -261,6 +263,8 @@ public:
*/
bool getStopped() { return sess_stopped.get(); }
bool getDetached() { return detached.get(); }
/**
* Creates a new Id which can be used within sessions.
*/

Loading…
Cancel
Save