Thanks a lot for your input, Stefan. I managed to make it work :-) It
was acceptAudio I was looking for, but where connectSession() was my
futile attempts :-)
By adding onB2ABEvent to both legs (and of course clean up the
connectSession stuff), it worked.
If there's an interest, feel free to add it as an example app (but maybe
verify it first?!). I attach it in case others are looking for a
combined media and signaling b2bua.
BTW, I have ser+rtpproxy+sems running on the same server. Just made sure
that rtpproxy and sems don't use the same media ports.
g-)
Stefan Sayer wrote:
Hi,
I haven't tried your b2b_connect plugin, but your use of
connectSession() in both caller and callee session seems strange to
me. If you look at AmB2ABSession, it calls connectSession in both
caller and callee session at the right place, so if everything goes up
to the logic of that base classes, then you don't need to call it in
your dialog class.
Also, note that onSessionStart is called right after onInvite - so it
tries to connect the session right after processing the invite, but
there is no connector (callee session not yet there), so this will fail.
I think, you are missing to call acceptAudio (which sets up RTP
stream); this needs to be called when the positive reply comes from
callee leg (see how it is done in AmSession::onInvite, which you are
correctly overriding). That would be if you receive a B2ABConnectAudio
event. maybe like this:
void b2b_connectDialog::onB2ABEvent(B2ABEvent* ev)
{
if (ev->event_id == B2ABConnectAudio) {
// delayed processing of first INVITE request
onInvite(invite_req);
}
AmB2ABCallerSession::onB2ABEvent(B2ABEvent* ev);
}
I have used this b2b with media only in the way to first accept the
call, play something to the caller, and then call the callee with
connectCallee. But, if you tweak it a little further, it should work
in your way as well.
Stefan
o Greger V. Teigre [11/22/08 13:46]:
Hi guys,
I have been trying to start out with auth_b2b and create a b2bua that
handles both signaling and media. I have looked at the serviceline
and jukebox applications and tried to pull together something that
works. Everything seems to work up to receiving callee's 200 OK and
audio is supposed to get started...
I believe I do something wrong when connecting the audio of the two
legs and I get the error message below telling me that RTP send is
trying to send on a non-socket. Further up in the log, I can see
that a port has ed out been allocated locally and the error seems to
be within the callee leg, i.e. I suspect sems is trying to write rtp
to callee (a cisco pstn gw).
I have stared myself blind (and must admit that I don't really
understand all the mechanics...)
I attach my new plugin, b2b_connect.
Can anybody see som claring mistakes?!
Cheers,
Greger
Nov 22 13:35:29 cleo sems[25269]: ERROR: [b75f4b90] send
(AmRtpPacket.cpp:212): while sending RTP packet: Socket operation on
non-socket
Nov 22 13:35:29 cleo sems[25269]: ERROR: [b75f4b90] send
(AmRtpStream.cpp:241): while sending RTP packet.
------------------------------------------------------------------------
_______________________________________________
Semsdev mailing list
[email protected]
http://lists.iptel.org/mailman/listinfo/semsdev
/*
* $Id: AuthB2B.h 1048 2008-07-15 18:48:07Z sayer $
*
* Copyright (C) 2008 iptego GmbH
* Based on the concept of sw_prepaid_sip, Copyright (C) 2007 Sipwise GmbH
* Based on the concept of mycc, Copyright (C) 2002-2003 Fhg Fokus
*
* This file is part of sems, a free SIP media server.
*
* sems 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.
*
* For a license to use the sems software under conditions
* other than those described here, or to purchase support for this
* software, please contact iptel.org by e-mail at the following addresses:
* [EMAIL PROTECTED]
*
* sems 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _B2B_CONNECT_H
#define _B2B_CONNECT_H
#include "AmB2ABSession.h"
#include "ampi/UACAuthAPI.h"
using std::string;
class b2b_connectFactory: public AmSessionFactory
{
/* AmDynInvokeFactory* user_timer_fact; */
public:
b2b_connectFactory(const string& _app_name);
int onLoad();
AmSession* onInvite(const AmSipRequest& req);
};
class b2b_connectDialog : public AmB2ABCallerSession
{
enum {
BB_Init = 0,
BB_Dialing,
BB_Connected,
BB_Teardown
} CallerState;
int m_state;
string domain;
string user;
string password;
string from;
string to;
AmSipRequest invite_req;
/* AmDynInvoke* m_user_timer; */
public:
b2b_connectDialog(); //AmDynInvoke* user_timer);
~b2b_connectDialog();
void onSessionStart(const AmSipRequest& req);
void onB2ABEvent(B2ABEvent* ev);
void process(AmEvent* ev);
void onDtmf(int event, int duration);
void onBye(const AmSipRequest& req);
void onInvite(const AmSipRequest& req);
void onCancel();
protected:
AmB2ABCalleeSession* createCalleeSession();
};
class b2b_connectCalleeSession
: public AmB2ABCalleeSession, public CredentialHolder
{
UACAuthCred credentials;
AmSessionEventHandler* auth;
AmSipRequest invite_req;
protected:
void onSipReply(const AmSipReply& reply);
void onSendRequest(const string& method, const string& content_type,
const string& body, string& hdrs, int flags, unsigned int
cseq);
public:
b2b_connectCalleeSession(const string& other_tag, const string& user, const
string& pwd);
~b2b_connectCalleeSession();
void onB2ABEvent(B2ABEvent* ev);
void process(AmEvent* ev);
inline UACAuthCred* getCredentials();
void setAuthHandler(AmSessionEventHandler* h) { auth = h; }
};
#endif
/*
* $Id: b2b_connect.cpp 1048 2008-07-15 18:48:07Z sayer $
*
* Copyright (C) 2008 iptego GmbH
* Based on the concept of mycc, Copyright (C) 2007 Sipwise GmbH
* Based on the concept of sw_prepaid_sip, Copyright (C) 2002-2003 Fhg Fokus
*
* This file is part of sems, a free SIP media server.
*
* sems 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.
*
* For a license to use the sems software under conditions
* other than those described here, or to purchase support for this
* software, please contact iptel.org by e-mail at the following addresses:
* [EMAIL PROTECTED]
*
* sems 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "b2b_connect.h"
#include "log.h"
#include "AmUtils.h"
#include "AmAudio.h"
#include "AmPlugIn.h"
#include "AmMediaProcessor.h"
//#include "AmConfigReader.h"
#include "AmSessionContainer.h"
EXPORT_SESSION_FACTORY(b2b_connectFactory,MOD_NAME);
b2b_connectFactory::b2b_connectFactory(const string& _app_name)
: AmSessionFactory(_app_name)
// , user_timer_fact(NULL)
{
}
int b2b_connectFactory::onLoad()
{
// AmConfigReader cfg;
// if(cfg.loadFile(AmConfig::ModConfigPath + string(MOD_NAME ".conf")))
// return -1;
// user_timer_fact = AmPlugIn::instance()->getFactory4Di("user_timer");
// if(!user_timer_fact) {
// ERROR("could not load user_timer from session_timer plug-in\n");
// return -1;
// }
return 0;
}
AmSession* b2b_connectFactory::onInvite(const AmSipRequest& req)
{
// AmDynInvoke* user_timer = user_timer_fact->getInstance();
// if(!user_timer) {
// ERROR("could not get a user timer reference\n");
// throw AmSession::Exception(500,"could not get a user timer reference");
// }
return new b2b_connectDialog(); //user_timer);
}
b2b_connectDialog::b2b_connectDialog() // AmDynInvoke* user_timer)
: m_state(BB_Init),
//m_user_timer(user_timer),
AmB2ABCallerSession()
{
}
b2b_connectDialog::~b2b_connectDialog()
{
}
void b2b_connectDialog::onInvite(const AmSipRequest& req)
{
// TODO: do reinvites get here? if so, don't set a timer then
// -> yes, they do.
// TODO: errors thrown as exception don't seem to trigger a reply?
// -> only in SessionFactory::onInvite they do. todo: move the logic to
// session factory
//setReceiving(false);
//AmMediaProcessor::instance()->removeSession(this);
string app_param = getHeader(req.hdrs, PARAM_HDR);
if (!app_param.length()) {
AmSession::Exception(500, "auth_b2b: parameters not found");
}
domain = get_header_keyvalue(app_param,"d");
user = get_header_keyvalue(app_param,"u");
password = get_header_keyvalue(app_param,"p");
from = "sip:"+user+"@"+domain;
to = "sip:"+req.user+"@"+domain;
// DBG("-----------------------------------------------------------------\n");
// DBG("domain = %s, user = %s, pwd = %s, from = %s, to = %s;",
// domain.c_str(), user.c_str(), password.c_str(), from.c_str(),
to.c_str());
// DBG("-----------------------------------------------------------------\n");
m_state = BB_Dialing;
if(dlg.reply(req, 100, "Connecting") != 0) {
throw AmSession::Exception(500,"Failed to reply 100");
}
invite_req = req;
size_t pos1, pos2, hdr_start;
if (findHeader(invite_req.hdrs,PARAM_HDR, pos1, pos2,
hdr_start)) {
while (invite_req.hdrs[pos2]=='\r' ||invite_req.hdrs[pos2]=='\n')
pos2++;
hdr_start -= 11; //"P-App-Param"
invite_req.hdrs.erase(hdr_start, pos2-hdr_start);
}
if (findHeader(invite_req.hdrs,"P-App-Name", pos1, pos2,
hdr_start)) {
while (invite_req.hdrs[pos2]=='\r' ||invite_req.hdrs[pos2]=='\n')
pos2++;
hdr_start -= 10; //"P-App-Name"
invite_req.hdrs.erase(hdr_start, pos2-hdr_start);
}
dlg.updateStatus(req);
recvd_req.insert(std::make_pair(req.cseq,req));
connectCallee("<" + to + ">", to, from, from);
}
void b2b_connectDialog::onSessionStart(const AmSipRequest& req)
{
AmB2ABCallerSession::onSessionStart(req);
}
void b2b_connectDialog::onB2ABEvent(B2ABEvent* ev)
{
if (ev->event_id == B2ABConnectAudio) {
// delayed processing of first INVITE request
AmSession::onInvite(invite_req);
}
AmB2ABCallerSession::onB2ABEvent(ev);
}
void b2b_connectDialog::process(AmEvent* ev)
{
// AmPluginEvent* plugin_event = dynamic_cast<AmPluginEvent*>(ev);
// if(plugin_event && plugin_event->name == "timer_timeout") {
// int timer_id = plugin_event->data.get(0).asInt();
// if (timer_id == TIMERID_CREDIT_TIMEOUT) {
// DBG("timer timeout, no more credit\n");
// stopAccounting();
// terminateOtherLeg();
// terminateLeg();
// ev->processed = true;
// return;
// }
// }
AmAudioEvent* audio_event = dynamic_cast<AmAudioEvent*>(ev);
if(audio_event && (audio_event->event_id == AmAudioEvent::cleared)){
DBG("ignoring end of prompt.\n");
return;
}
AmB2ABCallerSession::process(ev);
}
void b2b_connectDialog::onDtmf(int event, int duration)
{
DBG("DTMF event %d duration %d\n", event, duration);
return;
}
void b2b_connectDialog::onBye(const AmSipRequest& req)
{
if (m_state == BB_Connected) {
// stopAccounting();
}
terminateOtherLeg();
setStopped();
}
void b2b_connectDialog::onCancel()
{
if(dlg.getStatus() == AmSipDialog::Pending) {
DBG("Wait for leg B to terminate");
}
else {
DBG("Canceling leg A on CANCEL since dialog is not pending");
dlg.reply(invite_req, 487, "Request terminated");
setStopped();
}
}
AmB2ABCalleeSession* b2b_connectDialog::createCalleeSession()
{
b2b_connectCalleeSession* sess = new b2b_connectCalleeSession(getLocalTag(),
user, password);
AmSessionEventHandlerFactory* uac_auth_f =
AmPlugIn::instance()->getFactory4Seh("uac_auth");
if (NULL != uac_auth_f) {
DBG("UAC Auth enabled for new b2b_connect session.\n");
AmSessionEventHandler* h = uac_auth_f->getHandler(sess);
if (h != NULL )
sess->addHandler(h);
else {
ERROR("unable to set SIP UAC auth for new session.");
}
} else {
ERROR("unable to get SIP UAC auth."
"(uac_auth module loaded?)\n");
}
AmSipDialog& callee_dlg = sess->dlg;
other_id = AmSession::getNewId();
callee_dlg.local_tag = other_id;
callee_dlg.callid = AmSession::getNewId() + "@" + AmConfig::LocalIP;
// this will be overwritten by ConnectLeg event
callee_dlg.remote_party = dlg.local_party;
callee_dlg.remote_uri = dlg.local_uri;
// if given as parameters, use these
callee_dlg.local_party = from;
callee_dlg.local_uri = from;
DBG("Created B2BUA callee leg, From: %s\n",
from.c_str());
sess->start();
AmSessionContainer* sess_cont = AmSessionContainer::instance();
sess_cont->addSession(other_id,sess);
return sess;
}
b2b_connectCalleeSession::b2b_connectCalleeSession(const string& other_tag,
const string& user, const string&
pwd)
: auth(NULL),
credentials("", user, pwd), // domain (realm) is unused in credentials
AmB2ABCalleeSession(other_tag) {
//rtp_str.setPlayoutType(ADAPTIVE_PLAYOUT);
setDtmfDetectionEnabled(false);
}
b2b_connectCalleeSession::~b2b_connectCalleeSession() {
if (auth)
delete auth;
}
inline UACAuthCred* b2b_connectCalleeSession::getCredentials() {
return &credentials;
}
void b2b_connectCalleeSession::onSipReply(const AmSipReply& reply) {
AmB2ABCalleeSession::onSipReply(reply);
}
void b2b_connectCalleeSession::onSendRequest(const string& method, const
string& content_type,
const string& body, string& hdrs, int
flags, unsigned int cseq)
{
AmB2ABCalleeSession::onSendRequest(method, content_type,
body, hdrs, flags, cseq);
}
void b2b_connectCalleeSession::onB2ABEvent(B2ABEvent* ev)
{
if (ev->event_id == B2ABConnectAudio) {
// delayed processing of first INVITE request
AmSession::onInvite(invite_req);
}
AmB2ABCalleeSession::onB2ABEvent(ev);
}
void b2b_connectCalleeSession::process(AmEvent* ev)
{
AmAudioEvent* audio_event = dynamic_cast<AmAudioEvent*>(ev);
if(audio_event && (audio_event->event_id == AmAudioEvent::noAudio)){
DBG("connecting audio\n");
connectSession();
return;
}
AmB2ABCalleeSession::process(ev);
}
_______________________________________________
Semsdev mailing list
[email protected]
http://lists.iptel.org/mailman/listinfo/semsdev