1
#include "AppSubsystem.hxx"
2
#include "MOHManager.hxx"
4
#include "../UserAgent.hxx"
6
#include <resip/stack/ExtensionParameter.hxx>
7
#include <rutil/Log.hxx>
8
#include <rutil/Logger.hxx>
9
#include <rutil/WinLeakCheck.hxx>
11
using namespace recon;
12
using namespace resip;
15
#define RESIPROCATE_SUBSYSTEM AppSubsystem::MOHPARKSERVER
17
static const resip::ExtensionParameter p_automaton("automaton");
18
static const resip::ExtensionParameter p_byeless("+sip.byeless");
19
static const resip::ExtensionParameter p_rendering("+sip.rendering");
21
namespace mohparkserver
24
MOHManager::MOHManager(Server& server) :
26
mConversationProfileHandle(0),
27
mMusicFilenameChanged(false)
31
MOHManager::~MOHManager()
38
// Initialize settings
39
initializeSettings(mServer.mConfig.mMOHFilenameUrl);
41
// Setup ConversationProfile
42
initializeConversationProfile(mServer.mConfig.mMOHUri, mServer.mConfig.mMOHPassword, mServer.mConfig.mMOHRegistrationTime, mServer.mConfig.mOutboundProxy);
44
// Create an initial conversation and start music
45
ConversationHandle convHandle = mServer.createConversation(true /* broadcast only*/);
46
mServer.createMediaResourceParticipant(convHandle, mServer.mConfig.mMOHFilenameUrl); // Play Music
47
mConversations[convHandle];
48
mMusicFilenameChanged = false;
52
MOHManager::initializeConversationProfile(const NameAddr& uri, const Data& password, unsigned long registrationTime, const resip::NameAddr& outboundProxy)
54
if(mConversationProfileHandle)
56
mServer.mMyUserAgent->destroyConversationProfile(mConversationProfileHandle);
57
mConversationProfileHandle = 0;
60
// Setup ConversationProfile
61
SharedPtr<ConversationProfile> mohConversationProfile = SharedPtr<ConversationProfile>(new ConversationProfile(mServer.mUserAgentMasterProfile));
62
mohConversationProfile->setDefaultRegistrationTime(registrationTime);
63
mohConversationProfile->setDefaultRegistrationRetryTime(120); // 2 mins
64
mohConversationProfile->setDefaultFrom(uri);
65
mohConversationProfile->setDigestCredential(uri.uri().host(), uri.uri().user(), password);
66
if(!outboundProxy.uri().host().empty())
68
mohConversationProfile->setOutboundProxy(outboundProxy.uri());
70
mohConversationProfile->challengeOODReferRequests() = false;
71
mohConversationProfile->setExtraHeadersInReferNotifySipFragEnabled(true); // Enable dialog identifying headers in SipFrag bodies of Refer Notifies - required for a music on hold server
72
NameAddr capabilities;
73
capabilities.param(p_automaton);
74
capabilities.param(p_byeless);
75
capabilities.param(p_rendering) = "\"no\"";
76
mohConversationProfile->setUserAgentCapabilities(capabilities);
77
mohConversationProfile->natTraversalMode() = ConversationProfile::NoNatTraversal;
78
mohConversationProfile->secureMediaMode() = ConversationProfile::NoSecureMedia;
79
mServer.buildSessionCapabilities(mohConversationProfile->sessionCaps());
80
mConversationProfileHandle = mServer.mMyUserAgent->addConversationProfile(mohConversationProfile);
84
MOHManager::initializeSettings(const resip::Uri& musicFilename)
87
mMusicFilename = musicFilename;
88
// If there is a single conversation with no participants, then there are no
89
// current parties on hold - re-create the conversation with new music
90
if(mConversations.size() == 1 && mConversations.begin()->second.size() == 0)
92
mServer.destroyConversation(mConversations.begin()->first);
93
mConversations.clear();
95
// re-create an initial conversation and start music
96
ConversationHandle convHandle = mServer.createConversation(true /* broadcast only*/);
97
mServer.createMediaResourceParticipant(convHandle, mMusicFilename); // Play Music
98
mConversations[convHandle];
102
mMusicFilenameChanged = true;
107
MOHManager::shutdown(bool shuttingDownServer)
110
// Destroy all conversations
111
ConversationMap::iterator it = mConversations.begin();
112
for(; it != mConversations.end(); it++)
114
// Clean up participant memory
115
ParticipantMap::iterator partIt = it->second.begin();
116
for(;partIt!= it->second.end(); partIt++)
118
delete partIt->second;
122
mServer.destroyConversation(it->first);
124
mConversations.clear();
126
// If shutting down server, then we shouldn't remove the conversation profiles here
127
// shutting down the ConversationManager will take care of this. We need to be sure
128
// we don't remove all conversation profiles when we are still processing SipMessages,
129
// since recon requires at least one to be present for inbound processing.
130
if(mConversationProfileHandle && !shuttingDownServer)
132
mServer.mMyUserAgent->destroyConversationProfile(mConversationProfileHandle);
133
mConversationProfileHandle = 0;
138
MOHManager::isMyProfile(recon::ConversationProfile& profile)
141
return profile.getHandle() == mConversationProfileHandle;
145
MOHManager::addParticipant(ParticipantHandle participantHandle, const Uri& heldUri, const Uri& holdingUri)
148
ConversationHandle conversationToUse = 0;
149
// Check if we have an existing conversation with room to add this party
150
ConversationMap::iterator it = mConversations.begin();
151
for(; it != mConversations.end(); it++)
153
if(it->second.size() < DEFAULT_BRIDGE_MAX_IN_OUTPUTS-3)
155
// Found an existing conversation with room - add the participant here
156
conversationToUse = it->first;
161
// No conversation found that we can use - create a new one
162
if(!conversationToUse)
164
conversationToUse = mServer.createConversation(true /* broadcast only*/);
165
InfoLog(<< "MOHManager::addParticipant created new conversation for music on hold, id=" << conversationToUse);
168
mServer.createMediaResourceParticipant(conversationToUse, mMusicFilename);
171
assert(conversationToUse);
173
mServer.addParticipant(conversationToUse, participantHandle);
174
mServer.modifyParticipantContribution(conversationToUse, participantHandle, 100, 0 /* Mute participant */);
175
mServer.answerParticipant(participantHandle);
176
mConversations[conversationToUse].insert(std::make_pair(participantHandle, new ParticipantMOHInfo(participantHandle, heldUri, holdingUri)));
180
MOHManager::removeParticipant(ParticipantHandle participantHandle)
183
// Find Conversation that participant is in
184
ConversationMap::iterator it = mConversations.begin();
185
for(; it != mConversations.end(); it++)
187
ParticipantMap::iterator partIt = it->second.find(participantHandle);
188
if(partIt != it->second.end())
190
InfoLog(<< "MOHManager::removeParticipant found in conversation id=" << it->first << ", size=" << it->second.size());
192
// Found! Remove from conversation
193
delete partIt->second;
194
it->second.erase(partIt);
196
// Check if conversation is now empty, and it's not the last conversation
197
if(it->second.size() == 0)
199
if(mConversations.size() > 1)
201
// Destroy conversation (and containing media participant)
202
mServer.destroyConversation(it->first);
204
// Remove Conversation from Map
205
mConversations.erase(it);
207
InfoLog(<< "MOHManager::removeParticipant last participant in conversation, destroying conversation, num conversations now=" << mConversations.size());
209
else if(mConversations.size() == 1 && mMusicFilenameChanged) // If the initial conversation is empty, and the music filename setting changed, then restart it
211
mServer.destroyConversation(mConversations.begin()->first);
212
mConversations.clear();
214
// re-create an initial conversation and start music
215
ConversationHandle convHandle = mServer.createConversation(true /* broadcast only*/);
216
mServer.createMediaResourceParticipant(convHandle, mMusicFilename); // Play Music
217
mConversations[convHandle];
218
mMusicFilenameChanged = false;
228
MOHManager::getActiveCallsInfo(CallInfoList& callInfos)
231
// Find Conversation that participant is in
232
ConversationMap::iterator it = mConversations.begin();
233
for(; it != mConversations.end(); it++)
235
ParticipantMap::iterator partIt = it->second.begin();
236
for(; partIt != it->second.end(); partIt++)
238
callInfos.push_back(ActiveCallInfo(partIt->second->mHeldUri, partIt->second->mHoldingUri, "MOH", partIt->first, it->first));
245
/* ====================================================================
247
Copyright (c) 2010, SIP Spectrum, Inc.
250
Redistribution and use in source and binary forms, with or without
251
modification, are permitted provided that the following conditions are
254
1. Redistributions of source code must retain the above copyright
255
notice, this list of conditions and the following disclaimer.
257
2. Redistributions in binary form must reproduce the above copyright
258
notice, this list of conditions and the following disclaimer in the
259
documentation and/or other materials provided with the distribution.
261
3. Neither the name of SIP Spectrum nor the names of its contributors
262
may be used to endorse or promote products derived from this
263
software without specific prior written permission.
265
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
266
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
267
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
268
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
269
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
270
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
271
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
272
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
273
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
274
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
275
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
277
==================================================================== */