2
#include <sdp/SdpCodec.h>
3
#include <os/OsConfigDb.h>
4
#include <mp/MpCodecFactory.h>
5
#include <mp/MprBridge.h>
6
#include <mp/MpResourceTopology.h>
7
#include <mi/CpMediaInterfaceFactoryFactory.h>
8
#include <mi/CpMediaInterface.h>
11
#include <rutil/Log.hxx>
12
#include <rutil/Logger.hxx>
13
#include <rutil/Lock.hxx>
14
#include <rutil/Random.hxx>
15
#include <resip/dum/DialogUsageManager.hxx>
16
#include <resip/dum/ClientInviteSession.hxx>
17
#include <resip/dum/ServerInviteSession.hxx>
18
#include <resip/dum/ClientSubscription.hxx>
19
#include <resip/dum/ServerOutOfDialogReq.hxx>
21
#include "ReconSubsystem.hxx"
22
#include "UserAgent.hxx"
23
#include "ConversationManager.hxx"
24
#include "ConversationManagerCmds.hxx"
25
#include "Conversation.hxx"
26
#include "Participant.hxx"
27
#include "BridgeMixer.hxx"
28
#include "DtmfEvent.hxx"
29
#include <rutil/WinLeakCheck.hxx>
31
#if defined(WIN32) && !defined(__GNUC__)
32
#pragma warning( disable : 4355 )
35
using namespace recon;
36
using namespace resip;
39
#define RESIPROCATE_SUBSYSTEM ReconSubsystem::RECON
41
ConversationManager::ConversationManager(bool localAudioEnabled, MediaInterfaceMode mediaInterfaceMode)
43
mCurrentConversationHandle(1),
44
mCurrentParticipantHandle(1),
45
mLocalAudioEnabled(localAudioEnabled),
46
mMediaInterfaceMode(mediaInterfaceMode),
52
UtlString codecPaths[] = {".", "../../../../sipXtapi/sipXmediaLib/bin"};
54
UtlString codecPaths[] = {"."};
56
int codecPathsNum = sizeof(codecPaths)/sizeof(codecPaths[0]);
57
OsStatus rc = CpMediaInterfaceFactory::addCodecPaths(codecPathsNum, codecPaths);
58
assert(OS_SUCCESS == rc);
60
if(mMediaInterfaceMode == sipXConversationMediaInterfaceMode)
62
OsConfigDb sipXconfig;
63
sipXconfig.set("PHONESET_MAX_ACTIVE_CALLS_ALLOWED",300); // This controls the maximum number of flowgraphs allowed - default is 16
64
mMediaFactory = sipXmediaFactoryFactory(&sipXconfig, 0, 0, 0, mLocalAudioEnabled);
68
mMediaFactory = sipXmediaFactoryFactory(NULL, 0, 0, 0, mLocalAudioEnabled);
71
// Create MediaInterface
72
MpCodecFactory *pCodecFactory = MpCodecFactory::getMpCodecFactory();
73
unsigned int count = 0;
74
const MppCodecInfoV1_1 **codecInfoArray;
75
pCodecFactory->getCodecInfoArray(count, codecInfoArray);
79
ErrLog( << "No codec plugins found. Cannot start.");
83
InfoLog( << "Loaded codecs are:");
84
for(unsigned int i =0; i < count; i++)
86
InfoLog( << " " << codecInfoArray[i]->codecName
87
<< "(" << codecInfoArray[i]->codecManufacturer << ") "
88
<< codecInfoArray[i]->codecVersion
89
<< " MimeSubtype: " << codecInfoArray[i]->mimeSubtype
90
<< " Rate: " << codecInfoArray[i]->sampleRate
91
<< " Channels: " << codecInfoArray[i]->numChannels);
94
if(mMediaInterfaceMode == sipXGlobalMediaInterfaceMode)
96
createMediaInterfaceAndMixer(mLocalAudioEnabled /* giveFocus?*/, // This is the one and only media interface - give it focus
103
ConversationManager::~ConversationManager()
105
assert(mConversations.empty());
106
assert(mParticipants.empty());
108
if(mMediaInterface) mMediaInterface.reset(); // Make sure inteface is destroyed before factory
109
sipxDestroyMediaFactoryFactory();
113
ConversationManager::setUserAgent(UserAgent* userAgent)
115
mUserAgent = userAgent;
117
// Note: This is not really required, since we are managing the port allocation - but no harm done
118
// Really not needed now - since FlowManager integration
119
//mMediaFactory->getFactoryImplementation()->setRtpPortRange(mUserAgent->getUserAgentMasterProfile()->rtpPortRangeMin(),
120
// mUserAgent->getUserAgentMasterProfile()->rtpPortRangeMax());
122
initRTPPortFreeList();
126
ConversationManager::shutdown()
128
// Destroy each Conversation
129
ConversationMap tempConvs = mConversations; // Create copy for safety, since ending conversations can immediately remove themselves from map
130
ConversationMap::iterator i;
131
for(i = tempConvs.begin(); i != tempConvs.end(); i++)
133
InfoLog(<< "Destroying conversation: " << i->second->getHandle());
134
i->second->destroy();
137
// End each Participant
138
ParticipantMap tempParts = mParticipants;
139
ParticipantMap::iterator j;
141
for(j = tempParts.begin(); j != tempParts.end(); j++, j2++)
143
InfoLog(<< "Destroying participant: " << j->second->getParticipantHandle());
144
j->second->destroyParticipant();
149
ConversationManager::createConversation(bool broadcastOnly)
151
ConversationHandle convHandle = getNewConversationHandle();
153
CreateConversationCmd* cmd = new CreateConversationCmd(this, convHandle, broadcastOnly);
159
ConversationManager::destroyConversation(ConversationHandle convHandle)
161
DestroyConversationCmd* cmd = new DestroyConversationCmd(this, convHandle);
166
ConversationManager::joinConversation(ConversationHandle sourceConvHandle, ConversationHandle destConvHandle)
168
JoinConversationCmd* cmd = new JoinConversationCmd(this, sourceConvHandle, destConvHandle);
173
ConversationManager::createRemoteParticipant(ConversationHandle convHandle, const NameAddr& destination, ParticipantForkSelectMode forkSelectMode)
175
ParticipantHandle partHandle = getNewParticipantHandle();
177
CreateRemoteParticipantCmd* cmd = new CreateRemoteParticipantCmd(this, partHandle, convHandle, destination, forkSelectMode);
184
ConversationManager::createMediaResourceParticipant(ConversationHandle convHandle, const Uri& mediaUrl)
186
ParticipantHandle partHandle = getNewParticipantHandle();
188
CreateMediaResourceParticipantCmd* cmd = new CreateMediaResourceParticipantCmd(this, partHandle, convHandle, mediaUrl);
195
ConversationManager::createLocalParticipant()
197
ParticipantHandle partHandle = 0;
198
if(mLocalAudioEnabled)
200
partHandle = getNewParticipantHandle();
202
CreateLocalParticipantCmd* cmd = new CreateLocalParticipantCmd(this, partHandle);
207
WarningLog(<< "createLocalParticipant called when local audio support is disabled.");
214
ConversationManager::destroyParticipant(ParticipantHandle partHandle)
216
DestroyParticipantCmd* cmd = new DestroyParticipantCmd(this, partHandle);
221
ConversationManager::addParticipant(ConversationHandle convHandle, ParticipantHandle partHandle)
223
AddParticipantCmd* cmd = new AddParticipantCmd(this, convHandle, partHandle);
228
ConversationManager::removeParticipant(ConversationHandle convHandle, ParticipantHandle partHandle)
230
RemoveParticipantCmd* cmd = new RemoveParticipantCmd(this, convHandle, partHandle);
235
ConversationManager::moveParticipant(ParticipantHandle partHandle, ConversationHandle sourceConvHandle, ConversationHandle destConvHandle)
237
MoveParticipantCmd* cmd = new MoveParticipantCmd(this, partHandle, sourceConvHandle, destConvHandle);
242
ConversationManager::modifyParticipantContribution(ConversationHandle convHandle, ParticipantHandle partHandle, unsigned int inputGain, unsigned int outputGain)
244
ModifyParticipantContributionCmd* cmd = new ModifyParticipantContributionCmd(this, convHandle, partHandle, inputGain, outputGain);
249
ConversationManager::outputBridgeMatrix()
251
if(mMediaInterfaceMode == sipXGlobalMediaInterfaceMode)
253
OutputBridgeMixWeightsCmd* cmd = new OutputBridgeMixWeightsCmd(this);
258
WarningLog(<< "ConversationManager::outputBridgeMatrix not supported in current Media Interface Mode");
263
ConversationManager::alertParticipant(ParticipantHandle partHandle, bool earlyFlag)
265
AlertParticipantCmd* cmd = new AlertParticipantCmd(this, partHandle, earlyFlag);
270
ConversationManager::answerParticipant(ParticipantHandle partHandle)
272
AnswerParticipantCmd* cmd = new AnswerParticipantCmd(this, partHandle);
277
ConversationManager::rejectParticipant(ParticipantHandle partHandle, unsigned int rejectCode)
279
RejectParticipantCmd* cmd = new RejectParticipantCmd(this, partHandle, rejectCode);
284
ConversationManager::redirectParticipant(ParticipantHandle partHandle, const NameAddr& destination)
286
RedirectParticipantCmd* cmd = new RedirectParticipantCmd(this, partHandle, destination);
291
ConversationManager::redirectToParticipant(ParticipantHandle partHandle, ParticipantHandle destPartHandle)
293
RedirectToParticipantCmd* cmd = new RedirectToParticipantCmd(this, partHandle, destPartHandle);
298
ConversationManager::getNewConversationHandle()
300
Lock lock(mConversationHandleMutex);
301
return mCurrentConversationHandle++;
305
ConversationManager::registerConversation(Conversation *conversation)
307
mConversations[conversation->getHandle()] = conversation;
311
ConversationManager::unregisterConversation(Conversation *conversation)
313
mConversations.erase(conversation->getHandle());
317
ConversationManager::getNewParticipantHandle()
319
Lock lock(mParticipantHandleMutex);
320
return mCurrentParticipantHandle++;
324
ConversationManager::registerParticipant(Participant *participant)
326
mParticipants[participant->getParticipantHandle()] = participant;
330
ConversationManager::unregisterParticipant(Participant *participant)
332
InfoLog(<< "participant unregistered, handle=" << participant->getParticipantHandle());
333
mParticipants.erase(participant->getParticipantHandle());
337
ConversationManager::post(resip::Message *msg)
339
mUserAgent->getDialogUsageManager().post(msg);
343
ConversationManager::post(resip::ApplicationMessage& message, unsigned int ms)
345
mUserAgent->post(message, ms);
349
ConversationManager::initRTPPortFreeList()
351
mRTPPortFreeList.clear();
352
for(unsigned int i = mUserAgent->getUserAgentMasterProfile()->rtpPortRangeMin(); i <= mUserAgent->getUserAgentMasterProfile()->rtpPortRangeMax();)
354
mRTPPortFreeList.push_back(i);
355
i=i+2; // only add even ports - note we are assuming rtpPortRangeMin is even
360
ConversationManager::allocateRTPPort()
362
unsigned int port = 0;
363
if(!mRTPPortFreeList.empty())
365
port = mRTPPortFreeList.front();
366
mRTPPortFreeList.pop_front();
372
ConversationManager::freeRTPPort(unsigned int port)
374
assert(port >= mUserAgent->getUserAgentMasterProfile()->rtpPortRangeMin() && port <= mUserAgent->getUserAgentMasterProfile()->rtpPortRangeMax());
375
mRTPPortFreeList.push_back(port);
379
ConversationManager::buildSdpOffer(ConversationProfile* profile, SdpContents& offer)
381
// copy over session capabilities
382
offer = profile->sessionCaps();
384
// Set sessionid and version for this offer
385
UInt64 currentTime = Timer::getTimeMicroSec();
386
offer.session().origin().getSessionId() = currentTime;
387
offer.session().origin().getVersion() = currentTime;
389
// Set local port in offer
390
// for now we only allow 1 audio media
391
assert(offer.session().media().size() == 1);
392
assert(offer.session().media().front().name() == "audio");
396
ConversationManager::setSpeakerVolume(int volume)
398
OsStatus status = mMediaFactory->getFactoryImplementation()->setSpeakerVolume(volume);
399
if(status != OS_SUCCESS)
401
WarningLog(<< "setSpeakerVolume failed: status=" << status);
406
ConversationManager::setMicrophoneGain(int gain)
408
OsStatus status = mMediaFactory->getFactoryImplementation()->setMicrophoneGain(gain);
409
if(status != OS_SUCCESS)
411
WarningLog(<< "setMicrophoneGain failed: status=" << status);
416
ConversationManager::muteMicrophone(bool mute)
418
OsStatus status = mMediaFactory->getFactoryImplementation()->muteMicrophone(mute? TRUE : FALSE);
419
if(status != OS_SUCCESS)
421
WarningLog(<< "muteMicrophone failed: status=" << status);
426
ConversationManager::enableEchoCancel(bool enable)
428
OsStatus status = mMediaFactory->getFactoryImplementation()->setAudioAECMode(enable ? MEDIA_AEC_CANCEL : MEDIA_AEC_DISABLED);
429
if(status != OS_SUCCESS)
431
WarningLog(<< "enableEchoCancel failed: status=" << status);
433
if(mMediaInterfaceMode == sipXGlobalMediaInterfaceMode) // Note for sipXConversationMediaInterfaceMode - setting will apply on next conversation given focus
435
mMediaInterface->getInterface()->defocus(); // required to apply changes
436
mMediaInterface->getInterface()->giveFocus();
441
ConversationManager::enableAutoGainControl(bool enable)
443
OsStatus status = mMediaFactory->getFactoryImplementation()->enableAGC(enable ? TRUE : FALSE);
444
if(status != OS_SUCCESS)
446
WarningLog(<< "enableAutoGainControl failed: status=" << status);
448
if(mMediaInterfaceMode == sipXGlobalMediaInterfaceMode) // Note for sipXConversationMediaInterfaceMode - setting will apply on next conversation given focus
450
mMediaInterface->getInterface()->defocus(); // required to apply changes
451
mMediaInterface->getInterface()->giveFocus();
456
ConversationManager::enableNoiseReduction(bool enable)
458
OsStatus status = mMediaFactory->getFactoryImplementation()->setAudioNoiseReductionMode(enable ? MEDIA_NOISE_REDUCTION_MEDIUM /* arbitrary */ : MEDIA_NOISE_REDUCTION_DISABLED);
459
if(status != OS_SUCCESS)
461
WarningLog(<< "enableAutoGainControl failed: status=" << status);
463
if(mMediaInterfaceMode == sipXGlobalMediaInterfaceMode) // Note for sipXConversationMediaInterfaceMode - setting will apply on next conversation given focus
465
mMediaInterface->getInterface()->defocus(); // required to apply changes
466
mMediaInterface->getInterface()->giveFocus();
471
ConversationManager::getParticipant(ParticipantHandle partHandle)
473
ParticipantMap::iterator i = mParticipants.find(partHandle);
474
if(i != mParticipants.end())
485
ConversationManager::getConversation(ConversationHandle convHandle)
487
ConversationMap::iterator i = mConversations.find(convHandle);
488
if(i != mConversations.end())
499
ConversationManager::addBufferToMediaResourceCache(const resip::Data& name, const resip::Data& buffer, int type)
501
mMediaResourceCache.addToCache(name, buffer, type);
505
ConversationManager::buildSessionCapabilities(const resip::Data& ipaddress, unsigned int numCodecIds,
506
unsigned int codecIds[], resip::SdpContents& sessionCaps)
508
sessionCaps = SdpContents::Empty; // clear out passed in SdpContents
510
// Check if ipaddress is V4 or V6
512
if(!ipaddress.empty())
514
Tuple testTuple(ipaddress, 0, UDP);
515
if(testTuple.ipVersion() == V6)
521
// Create Session Capabilities
522
// Note: port, sessionId and version will be replaced in actual offer/answer
523
// Build s=, o=, t=, and c= lines
524
SdpContents::Session::Origin origin("-", 0 /* sessionId */, 0 /* version */, v6 ? SdpContents::IP6 : SdpContents::IP4, ipaddress.empty() ? "0.0.0.0" : ipaddress); // o=
525
SdpContents::Session session(0, origin, "-" /* s= */);
526
session.connection() = SdpContents::Session::Connection(v6 ? SdpContents::IP6 : SdpContents::IP4, ipaddress.empty() ? "0.0.0.0" : ipaddress); // c=
527
session.addTime(SdpContents::Session::Time(0, 0));
529
MpCodecFactory *pCodecFactory = MpCodecFactory::getMpCodecFactory();
530
SdpCodecList codecList;
531
pCodecFactory->addCodecsToList(codecList);
532
codecList.bindPayloadTypes();
535
//codecList.toString(output);
536
//InfoLog( << "Codec List: " << output.data());
538
// Auto-Create Session Codec Capabilities
539
// Note: port, and potentially payloadid will be replaced in actual offer/answer
541
// Build Codecs and media offering
542
SdpContents::Session::Medium medium("audio", 0, 1, "RTP/AVP");
544
bool firstCodecAdded = false;
545
for(unsigned int idIter = 0; idIter < numCodecIds; idIter++)
547
const SdpCodec* sdpcodec = codecList.getCodec((SdpCodec::SdpCodecTypes)codecIds[idIter]);
551
sdpcodec->getMediaType(mediaType);
552
// Ensure this codec is an audio codec
553
if(mediaType.compareTo("audio", UtlString::ignoreCase) == 0)
555
UtlString mimeSubType;
556
sdpcodec->getEncodingName(mimeSubType);
557
//mimeSubType.toUpper();
559
SdpContents::Session::Codec codec(mimeSubType.data(), sdpcodec->getSampleRate());
560
codec.payloadType() = sdpcodec->getCodecPayloadFormat();
562
// Check for telephone-event and add fmtp manually
563
if(mimeSubType.compareTo("telephone-event", UtlString::ignoreCase) == 0)
565
codec.parameters() = Data("0-15");
570
sdpcodec->getSdpFmtpField(fmtpField);
571
if(fmtpField.length() != 0)
573
codec.parameters() = Data(fmtpField.data());
577
DebugLog(<< "Added codec to session capabilites: id=" << codecIds[idIter]
578
<< " type=" << mimeSubType.data()
579
<< " rate=" << sdpcodec->getSampleRate()
580
<< " plen=" << sdpcodec->getPacketLength()
581
<< " payloadid=" << sdpcodec->getCodecPayloadFormat()
582
<< " fmtp=" << codec.parameters());
584
medium.addCodec(codec);
587
firstCodecAdded = true;
589
// 20 ms of speech per frame (note G711 has 10ms samples, so this is 2 samples per frame)
590
// Note: There are known problems with SDP and the ptime attribute. For now we will choose an
591
// appropriate ptime from the first codec
592
medium.addAttribute("ptime", Data(sdpcodec->getPacketLength() / 1000));
598
session.addMedium(medium);
599
sessionCaps.session() = session;
603
ConversationManager::notifyMediaEvent(ConversationHandle conversationHandle, int mediaConnectionId, MediaEvent::MediaEventType eventType)
605
assert(eventType == MediaEvent::PLAY_FINISHED);
607
if(conversationHandle == 0) // sipXGlobalMediaInterfaceMode
609
if(eventType == MediaEvent::PLAY_FINISHED)
611
// Using sipXGlobalMediaInterfaceMode it is only possible to have one active media participant
612
// actually playing a file (or from cache) at a time, so for now it is sufficient to have
613
// this event indicate that any active media participants (playing a file/cache) should be destroyed.
614
ParticipantMap::iterator it;
615
for(it = mParticipants.begin(); it != mParticipants.end();)
617
MediaResourceParticipant* mrPart = dynamic_cast<MediaResourceParticipant*>(it->second);
618
it++; // increment iterator here, since destroy may end up calling unregisterParticipant
621
if(mrPart->getResourceType() == MediaResourceParticipant::File ||
622
mrPart->getResourceType() == MediaResourceParticipant::Cache)
624
mrPart->destroyParticipant();
632
Conversation* conversation = getConversation(conversationHandle);
635
conversation->notifyMediaEvent(mediaConnectionId, eventType);
641
ConversationManager::notifyDtmfEvent(ConversationHandle conversationHandle, int mediaConnectionId, int dtmf, int duration, bool up)
643
if(conversationHandle == 0) // sipXGlobalMediaInterfaceMode
645
ParticipantMap::iterator i = mParticipants.begin();
646
for(; i != mParticipants.end(); i++)
648
RemoteParticipant* remoteParticipant = dynamic_cast<RemoteParticipant*>(i->second);
649
if(remoteParticipant)
651
if(remoteParticipant->getMediaConnectionId() == mediaConnectionId)
653
onDtmfEvent(remoteParticipant->getParticipantHandle(), dtmf, duration, up);
660
Conversation* conversation = getConversation(conversationHandle);
663
conversation->notifyDtmfEvent(mediaConnectionId, dtmf, duration, up);
669
ConversationManager::createMediaInterfaceAndMixer(bool giveFocus,
670
ConversationHandle ownerConversationHandle,
671
SharedPtr<MediaInterface>& mediaInterface,
672
BridgeMixer** bridgeMixer)
674
UtlString localRtpInterfaceAddress("127.0.0.1"); // Will be overridden in RemoteParticipantDialogSet, when connection is created anyway
676
// Note: STUN and TURN capabilities of the sipX media stack are not used - the FlowManager is responsible for STUN/TURN
677
mediaInterface = SharedPtr<MediaInterface>(new MediaInterface(*this, ownerConversationHandle, mMediaFactory->createMediaInterface(NULL,
678
localRtpInterfaceAddress,
679
0, /* numCodecs - not required at this point */
680
0, /* codecArray - not required at this point */
682
mSipXTOSValue, /* TOS Options */
683
NULL, /* STUN Server Address */
684
0, /* STUN Options */
685
25, /* STUN Keepalive period (seconds) */
686
NULL, /* TURN Server Address */
688
NULL, /* TURN User */
689
NULL, /* TURN Password */
690
25, /* TURN Keepalive period (seconds) */
691
false))); /* enable ICE? */
693
// Register the NotificationDispatcher class (derived from OsMsgDispatcher)
694
// as the sipX notification dispatcher
695
mediaInterface->getInterface()->setNotificationDispatcher(mediaInterface.get());
697
// Turn on notifications for all resources...
698
mediaInterface->getInterface()->setNotificationsEnabled(true);
702
mediaInterface->getInterface()->giveFocus();
705
*bridgeMixer = new BridgeMixer(*(mediaInterface->getInterface()));
709
ConversationManager::onNewSession(ClientInviteSessionHandle h, InviteSession::OfferAnswerType oat, const SipMessage& msg)
711
dynamic_cast<RemoteParticipant *>(h->getAppDialog().get())->onNewSession(h, oat, msg);
715
ConversationManager::onNewSession(ServerInviteSessionHandle h, InviteSession::OfferAnswerType oat, const SipMessage& msg)
717
dynamic_cast<RemoteParticipant *>(h->getAppDialog().get())->onNewSession(h, oat, msg);
721
ConversationManager::onFailure(ClientInviteSessionHandle h, const SipMessage& msg)
723
dynamic_cast<RemoteParticipant *>(h->getAppDialog().get())->onFailure(h, msg);
727
ConversationManager::onEarlyMedia(ClientInviteSessionHandle h, const SipMessage& msg, const SdpContents& sdp)
729
dynamic_cast<RemoteParticipant *>(h->getAppDialog().get())->onEarlyMedia(h, msg, sdp);
733
ConversationManager::onProvisional(ClientInviteSessionHandle h, const SipMessage& msg)
735
dynamic_cast<RemoteParticipant *>(h->getAppDialog().get())->onProvisional(h, msg);
739
ConversationManager::onConnected(ClientInviteSessionHandle h, const SipMessage& msg)
741
dynamic_cast<RemoteParticipant *>(h->getAppDialog().get())->onConnected(h, msg);
745
ConversationManager::onConnected(InviteSessionHandle h, const SipMessage& msg)
747
dynamic_cast<RemoteParticipant *>(h->getAppDialog().get())->onConnected(h, msg);
751
ConversationManager::onConnectedConfirmed(InviteSessionHandle h, const SipMessage &msg)
753
dynamic_cast<RemoteParticipant *>(h->getAppDialog().get())->onConnectedConfirmed(h, msg);
757
ConversationManager::onStaleCallTimeout(ClientInviteSessionHandle h)
759
dynamic_cast<RemoteParticipant *>(h->getAppDialog().get())->onStaleCallTimeout(h);
763
ConversationManager::onTerminated(InviteSessionHandle h, InviteSessionHandler::TerminatedReason reason, const SipMessage* msg)
765
dynamic_cast<RemoteParticipant *>(h->getAppDialog().get())->onTerminated(h, reason, msg);
769
ConversationManager::onRedirected(ClientInviteSessionHandle h, const SipMessage& msg)
771
dynamic_cast<RemoteParticipant *>(h->getAppDialog().get())->onRedirected(h, msg);
775
ConversationManager::onAnswer(InviteSessionHandle h, const SipMessage& msg, const SdpContents& sdp)
777
dynamic_cast<RemoteParticipant *>(h->getAppDialog().get())->onAnswer(h, msg, sdp);
781
ConversationManager::onOffer(InviteSessionHandle h, const SipMessage& msg, const SdpContents& sdp)
783
dynamic_cast<RemoteParticipant *>(h->getAppDialog().get())->onOffer(h, msg, sdp);
787
ConversationManager::onOfferRequired(InviteSessionHandle h, const SipMessage& msg)
789
dynamic_cast<RemoteParticipant *>(h->getAppDialog().get())->onOfferRequired(h, msg);
793
ConversationManager::onOfferRejected(InviteSessionHandle h, const SipMessage* msg)
795
dynamic_cast<RemoteParticipant *>(h->getAppDialog().get())->onOfferRejected(h, msg);
799
ConversationManager::onOfferRequestRejected(InviteSessionHandle h, const SipMessage& msg)
801
dynamic_cast<RemoteParticipant *>(h->getAppDialog().get())->onOfferRequestRejected(h, msg);
805
ConversationManager::onRemoteSdpChanged(InviteSessionHandle h, const SipMessage& msg, const SdpContents& sdp)
807
dynamic_cast<RemoteParticipant *>(h->getAppDialog().get())->onRemoteSdpChanged(h, msg, sdp);
811
ConversationManager::onInfo(InviteSessionHandle h, const SipMessage& msg)
813
dynamic_cast<RemoteParticipant *>(h->getAppDialog().get())->onInfo(h, msg);
817
ConversationManager::onInfoSuccess(InviteSessionHandle h, const SipMessage& msg)
819
dynamic_cast<RemoteParticipant *>(h->getAppDialog().get())->onInfoSuccess(h, msg);
823
ConversationManager::onInfoFailure(InviteSessionHandle h, const SipMessage& msg)
825
dynamic_cast<RemoteParticipant *>(h->getAppDialog().get())->onInfoFailure(h, msg);
829
ConversationManager::onRefer(InviteSessionHandle h, ServerSubscriptionHandle ssh, const SipMessage& msg)
831
dynamic_cast<RemoteParticipant *>(h->getAppDialog().get())->onRefer(h, ssh, msg);
835
ConversationManager::onReferAccepted(InviteSessionHandle h, ClientSubscriptionHandle csh, const SipMessage& msg)
837
dynamic_cast<RemoteParticipant *>(h->getAppDialog().get())->onReferAccepted(h, csh, msg);
841
ConversationManager::onReferRejected(InviteSessionHandle h, const SipMessage& msg)
843
dynamic_cast<RemoteParticipant *>(h->getAppDialog().get())->onReferRejected(h, msg);
847
ConversationManager::onReferNoSub(InviteSessionHandle h, const SipMessage& msg)
849
dynamic_cast<RemoteParticipant *>(h->getAppDialog().get())->onReferNoSub(h, msg);
853
ConversationManager::onMessage(InviteSessionHandle h, const SipMessage& msg)
855
dynamic_cast<RemoteParticipant *>(h->getAppDialog().get())->onMessage(h, msg);
859
ConversationManager::onMessageSuccess(InviteSessionHandle h, const SipMessage& msg)
861
dynamic_cast<RemoteParticipant *>(h->getAppDialog().get())->onMessageSuccess(h, msg);
865
ConversationManager::onMessageFailure(InviteSessionHandle h, const SipMessage& msg)
867
dynamic_cast<RemoteParticipant *>(h->getAppDialog().get())->onMessageFailure(h, msg);
871
ConversationManager::onForkDestroyed(ClientInviteSessionHandle h)
873
dynamic_cast<RemoteParticipant *>(h->getAppDialog().get())->onForkDestroyed(h);
876
////////////////////////////////////////////////////////////////////////////////
877
// DialogSetHandler ///////////////////////////////////////////////////
878
////////////////////////////////////////////////////////////////////////////////
880
ConversationManager::onTrying(AppDialogSetHandle h, const SipMessage& msg)
882
RemoteParticipantDialogSet *remoteParticipantDialogSet = dynamic_cast<RemoteParticipantDialogSet *>(h.get());
883
if(remoteParticipantDialogSet)
885
remoteParticipantDialogSet->onTrying(h, msg);
889
InfoLog(<< "onTrying(AppDialogSetHandle): " << msg.brief());
894
ConversationManager::onNonDialogCreatingProvisional(AppDialogSetHandle h, const SipMessage& msg)
896
RemoteParticipantDialogSet *remoteParticipantDialogSet = dynamic_cast<RemoteParticipantDialogSet *>(h.get());
897
if(remoteParticipantDialogSet)
899
remoteParticipantDialogSet->onNonDialogCreatingProvisional(h, msg);
903
InfoLog(<< "onNonDialogCreatingProvisional(AppDialogSetHandle): " << msg.brief());
907
////////////////////////////////////////////////////////////////////////////////
908
// ClientSubscriptionHandler ///////////////////////////////////////////////////
909
////////////////////////////////////////////////////////////////////////////////
911
ConversationManager::onUpdatePending(ClientSubscriptionHandle h, const SipMessage& msg, bool outOfOrder)
913
dynamic_cast<RemoteParticipant *>(h->getAppDialog().get())->onUpdatePending(h, msg, outOfOrder);
917
ConversationManager::onUpdateActive(ClientSubscriptionHandle h, const SipMessage& msg, bool outOfOrder)
919
dynamic_cast<RemoteParticipant *>(h->getAppDialog().get())->onUpdateActive(h, msg, outOfOrder);
923
ConversationManager::onUpdateExtension(ClientSubscriptionHandle h, const SipMessage& msg, bool outOfOrder)
925
dynamic_cast<RemoteParticipant *>(h->getAppDialog().get())->onUpdateExtension(h, msg, outOfOrder);
929
ConversationManager::onTerminated(ClientSubscriptionHandle h, const SipMessage* msg)
931
dynamic_cast<RemoteParticipant *>(h->getAppDialog().get())->onTerminated(h, msg);
935
ConversationManager::onNewSubscription(ClientSubscriptionHandle h, const SipMessage& msg)
937
dynamic_cast<RemoteParticipant *>(h->getAppDialog().get())->onNewSubscription(h, msg);
941
ConversationManager::onRequestRetry(ClientSubscriptionHandle h, int retryMinimum, const SipMessage& msg)
943
return dynamic_cast<RemoteParticipant *>(h->getAppDialog().get())->onRequestRetry(h, retryMinimum, msg);
947
////////////////////////////////////////////////////////////////////////////////
948
// ServerSubscriptionHandler ///////////////////////////////////////////////////
949
////////////////////////////////////////////////////////////////////////////////
951
ConversationManager::onNewSubscription(ServerSubscriptionHandle, const SipMessage& msg)
953
InfoLog(<< "onNewSubscription(ServerSubscriptionHandle): " << msg.brief());
957
ConversationManager::onNewSubscriptionFromRefer(ServerSubscriptionHandle ss, const SipMessage& msg)
959
InfoLog(<< "onNewSubscriptionFromRefer(ServerSubscriptionHandle): " << msg.brief());
960
// Received an out-of-dialog refer request with implicit subscription
963
if(msg.exists(h_ReferTo))
965
// Check if TargetDialog header is present
966
if(msg.exists(h_TargetDialog))
968
pair<InviteSessionHandle, int> presult;
969
presult = mUserAgent->getDialogUsageManager().findInviteSession(msg.header(h_TargetDialog));
970
if(!(presult.first == InviteSessionHandle::NotValid()))
972
RemoteParticipant* participantToRefer = (RemoteParticipant*)presult.first->getAppDialog().get();
974
participantToRefer->onRefer(presult.first, ss, msg);
979
// Create new Participant
980
RemoteParticipantDialogSet *participantDialogSet = new RemoteParticipantDialogSet(*this);
981
RemoteParticipant *participant = participantDialogSet->createUACOriginalRemoteParticipant(getNewParticipantHandle());
983
// Set pending OOD info in Participant - causes accept or reject to be called later
984
participant->setPendingOODReferInfo(ss, msg);
986
// Notify application
987
ConversationProfile* profile = dynamic_cast<ConversationProfile*>(ss->getUserProfile().get());
989
onRequestOutgoingParticipant(participant->getParticipantHandle(), msg, *profile);
993
WarningLog (<< "Received refer w/out a Refer-To: " << msg.brief());
994
ss->send(ss->reject(400));
997
catch(BaseException &e)
999
WarningLog(<< "onNewSubscriptionFromRefer exception: " << e);
1003
WarningLog(<< "onNewSubscriptionFromRefer unknown exception");
1008
ConversationManager::onRefresh(ServerSubscriptionHandle, const SipMessage& msg)
1010
InfoLog(<< "onRefresh(ServerSubscriptionHandle): " << msg.brief());
1014
ConversationManager::onTerminated(ServerSubscriptionHandle)
1016
InfoLog(<< "onTerminated(ServerSubscriptionHandle)");
1020
ConversationManager::onReadyToSend(ServerSubscriptionHandle, SipMessage&)
1025
ConversationManager::onNotifyRejected(ServerSubscriptionHandle, const SipMessage& msg)
1027
WarningLog(<< "onNotifyRejected(ServerSubscriptionHandle): " << msg.brief());
1031
ConversationManager::onError(ServerSubscriptionHandle, const SipMessage& msg)
1033
WarningLog(<< "onError(ServerSubscriptionHandle): " << msg.brief());
1037
ConversationManager::onExpiredByClient(ServerSubscriptionHandle, const SipMessage& sub, SipMessage& notify)
1039
InfoLog(<< "onExpiredByClient(ServerSubscriptionHandle): " << notify.brief());
1043
ConversationManager::onExpired(ServerSubscriptionHandle, SipMessage& msg)
1045
InfoLog(<< "onExpired(ServerSubscriptionHandle): " << msg.brief());
1049
ConversationManager::hasDefaultExpires() const
1055
ConversationManager::getDefaultExpires() const
1060
////////////////////////////////////////////////////////////////////////////////
1061
// OutOfDialogHandler //////////////////////////////////////////////////////////
1062
////////////////////////////////////////////////////////////////////////////////
1064
ConversationManager::onSuccess(ClientOutOfDialogReqHandle, const SipMessage& msg)
1066
InfoLog(<< "onSuccess(ClientOutOfDialogReqHandle): " << msg.brief());
1070
ConversationManager::onFailure(ClientOutOfDialogReqHandle, const SipMessage& msg)
1072
InfoLog(<< "onFailure(ClientOutOfDialogReqHandle): " << msg.brief());
1076
ConversationManager::onReceivedRequest(ServerOutOfDialogReqHandle ood, const SipMessage& msg)
1078
InfoLog(<< "onReceivedRequest(ServerOutOfDialogReqHandle): " << msg.brief());
1080
switch(msg.method())
1084
SharedPtr<SipMessage> optionsAnswer = ood->answerOptions();
1086
// Attach an offer to the options request
1088
buildSdpOffer(mUserAgent->getIncomingConversationProfile(msg).get(), sdp);
1089
optionsAnswer->setContents(&sdp);
1090
ood->send(optionsAnswer);
1095
// Received an OOD refer request with no refer subscription
1098
if(msg.exists(h_ReferTo))
1100
// Check if TargetDialog header is present
1101
if(msg.exists(h_TargetDialog))
1103
pair<InviteSessionHandle, int> presult;
1104
presult = mUserAgent->getDialogUsageManager().findInviteSession(msg.header(h_TargetDialog));
1105
if(!(presult.first == InviteSessionHandle::NotValid()))
1107
RemoteParticipant* participantToRefer = (RemoteParticipant*)presult.first->getAppDialog().get();
1110
ood->send(ood->accept(202 /* Refer Accepted */));
1112
participantToRefer->doReferNoSub(msg);
1117
// Create new Participant
1118
RemoteParticipantDialogSet *participantDialogSet = new RemoteParticipantDialogSet(*this);
1119
RemoteParticipant *participant = participantDialogSet->createUACOriginalRemoteParticipant(getNewParticipantHandle());
1121
// Set pending OOD info in Participant - causes accept or reject to be called later
1122
participant->setPendingOODReferInfo(ood, msg);
1124
// Notify application
1125
ConversationProfile* profile = dynamic_cast<ConversationProfile*>(ood->getUserProfile().get());
1127
onRequestOutgoingParticipant(participant->getParticipantHandle(), msg, *profile);
1131
WarningLog (<< "onReceivedRequest(ServerOutOfDialogReqHandle): Received refer w/out a Refer-To: " << msg.brief());
1132
ood->send(ood->reject(400));
1135
catch(BaseException &e)
1137
WarningLog(<< "onReceivedRequest(ServerOutOfDialogReqHandle): exception " << e);
1141
WarningLog(<< "onReceivedRequest(ServerOutOfDialogReqHandle): unknown exception");
1151
////////////////////////////////////////////////////////////////////////////////
1152
// RedirectHandler /////////////////////////////////////////////////////////////
1153
////////////////////////////////////////////////////////////////////////////////
1155
ConversationManager::onRedirectReceived(AppDialogSetHandle, const SipMessage& msg)
1157
InfoLog(<< "onRedirectReceived(AppDialogSetHandle): " << msg.brief());
1161
ConversationManager::onTryingNextTarget(AppDialogSetHandle, const SipMessage& msg)
1163
InfoLog(<< "onTryingNextTarget(AppDialogSetHandle): " << msg.brief());
1164
// Always allow redirection for now
1169
/* ====================================================================
1171
Copyright (c) 2007-2008, Plantronics, Inc.
1172
All rights reserved.
1174
Redistribution and use in source and binary forms, with or without
1175
modification, are permitted provided that the following conditions are
1178
1. Redistributions of source code must retain the above copyright
1179
notice, this list of conditions and the following disclaimer.
1181
2. Redistributions in binary form must reproduce the above copyright
1182
notice, this list of conditions and the following disclaimer in the
1183
documentation and/or other materials provided with the distribution.
1185
3. Neither the name of Plantronics nor the names of its contributors
1186
may be used to endorse or promote products derived from this
1187
software without specific prior written permission.
1189
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
1190
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
1191
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
1192
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
1193
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
1194
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
1195
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
1196
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
1197
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
1198
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
1199
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1201
==================================================================== */