1 |
#include "basicClientCall.hxx" |
2 |
|
3 |
#include <resip/stack/SdpContents.hxx> |
4 |
#include <resip/stack/PlainContents.hxx> |
5 |
#include <resip/stack/SipMessage.hxx> |
6 |
#include <resip/stack/ShutdownMessage.hxx> |
7 |
#include <resip/stack/SipStack.hxx> |
8 |
#include <resip/dum/ClientAuthManager.hxx> |
9 |
#include <resip/dum/ClientInviteSession.hxx> |
10 |
#include <resip/dum/ClientSubscription.hxx> |
11 |
#include <resip/dum/DialogUsageManager.hxx> |
12 |
#include <resip/dum/InviteSessionHandler.hxx> |
13 |
#include <resip/dum/MasterProfile.hxx> |
14 |
#include <resip/dum/ServerInviteSession.hxx> |
15 |
#include <resip/dum/AppDialog.hxx> |
16 |
#include <resip/dum/AppDialogSet.hxx> |
17 |
#include <resip/dum/AppDialogSetFactory.hxx> |
18 |
#include <rutil/Log.hxx> |
19 |
#include <rutil/Logger.hxx> |
20 |
#include <rutil/Random.hxx> |
21 |
#include <rutil/WinLeakCheck.hxx> |
22 |
|
23 |
#include <sstream> |
24 |
#include <time.h> |
25 |
|
26 |
#define RESIPROCATE_SUBSYSTEM Subsystem::TEST |
27 |
|
28 |
using namespace resip; |
29 |
using namespace std; |
30 |
|
31 |
static unsigned int CallTimerTime = 30; // Time between call timer |
32 |
static unsigned int CallTimeCounterToByeOn = 6; // BYE the call after the call timer has expired 6 times |
33 |
|
34 |
namespace resip |
35 |
{ |
36 |
class CallTimer : public resip::DumCommand |
37 |
{ |
38 |
public: |
39 |
CallTimer(BasicClientUserAgent& userAgent, BasicClientCall* call) : mUserAgent(userAgent), mCall(call) {} |
40 |
CallTimer(const CallTimer& rhs) : mUserAgent(rhs.mUserAgent), mCall(rhs.mCall) {} |
41 |
~CallTimer() {} |
42 |
|
43 |
void executeCommand() { mUserAgent.onCallTimeout(mCall); } |
44 |
|
45 |
resip::Message* clone() const { return new CallTimer(*this); } |
46 |
EncodeStream& encode(EncodeStream& strm) const { strm << "CallTimer:"; return strm; } |
47 |
EncodeStream& encodeBrief(EncodeStream& strm) const { return encode(strm); } |
48 |
|
49 |
private: |
50 |
BasicClientUserAgent& mUserAgent; |
51 |
BasicClientCall* mCall; |
52 |
}; |
53 |
} |
54 |
|
55 |
BasicClientCall::BasicClientCall(BasicClientUserAgent& userAgent) |
56 |
: AppDialogSet(userAgent.getDialogUsageManager()), |
57 |
mUserAgent(userAgent), |
58 |
mTimerExpiredCounter(0), |
59 |
mPlacedCall(false), |
60 |
mUACConnectedDialogId(Data::Empty, Data::Empty, Data::Empty) |
61 |
{ |
62 |
mUserAgent.registerCall(this); |
63 |
} |
64 |
|
65 |
BasicClientCall::~BasicClientCall() |
66 |
{ |
67 |
mUserAgent.unregisterCall(this); |
68 |
} |
69 |
|
70 |
void |
71 |
BasicClientCall::initiateCall(const Uri& target, SharedPtr<UserProfile> profile) |
72 |
{ |
73 |
SdpContents offer; |
74 |
makeOffer(offer); |
75 |
SharedPtr<SipMessage> invite = mUserAgent.getDialogUsageManager().makeInviteSession(NameAddr(target), profile, &offer, this); |
76 |
mUserAgent.getDialogUsageManager().send(invite); |
77 |
mPlacedCall = true; |
78 |
} |
79 |
|
80 |
void |
81 |
BasicClientCall::terminateCall() |
82 |
{ |
83 |
AppDialogSet::end(); |
84 |
} |
85 |
|
86 |
void |
87 |
BasicClientCall::timerExpired() |
88 |
{ |
89 |
mTimerExpiredCounter++; |
90 |
if(mTimerExpiredCounter < CallTimeCounterToByeOn) |
91 |
{ |
92 |
// First few times, send a message to the other party |
93 |
if(mInviteSessionHandle.isValid()) |
94 |
{ |
95 |
PlainContents plain("test message"); |
96 |
mInviteSessionHandle->message(plain); |
97 |
} |
98 |
} |
99 |
else |
100 |
{ |
101 |
// Then hangup |
102 |
terminateCall(); |
103 |
} |
104 |
|
105 |
// start timer for next one |
106 |
auto_ptr<ApplicationMessage> timer(new CallTimer(mUserAgent, this)); |
107 |
mUserAgent.mStack->post(timer, CallTimerTime, &mUserAgent.getDialogUsageManager()); |
108 |
} |
109 |
|
110 |
SharedPtr<UserProfile> |
111 |
BasicClientCall::selectUASUserProfile(const SipMessage& msg) |
112 |
{ |
113 |
return mUserAgent.getIncomingUserProfile(msg); |
114 |
} |
115 |
|
116 |
bool |
117 |
BasicClientCall::isUACConnected() |
118 |
{ |
119 |
return !mUACConnectedDialogId.getCallId().empty(); |
120 |
} |
121 |
|
122 |
bool |
123 |
BasicClientCall::isStaleFork(const DialogId& dialogId) |
124 |
{ |
125 |
return (!mUACConnectedDialogId.getCallId().empty() && dialogId != mUACConnectedDialogId); |
126 |
} |
127 |
|
128 |
void |
129 |
BasicClientCall::makeOffer(SdpContents& offer) |
130 |
{ |
131 |
static Data txt("v=0\r\n" |
132 |
"o=- 0 0 IN IP4 0.0.0.0\r\n" |
133 |
"s=basicClient\r\n" |
134 |
"c=IN IP4 0.0.0.0\r\n" |
135 |
"t=0 0\r\n" |
136 |
"m=audio 8000 RTP/AVP 0 101\r\n" |
137 |
"a=rtpmap:0 pcmu/8000\r\n" |
138 |
"a=rtpmap:101 telephone-event/8000\r\n" |
139 |
"a=fmtp:101 0-15\r\n"); |
140 |
|
141 |
static HeaderFieldValue hfv(txt.data(), txt.size()); |
142 |
static Mime type("application", "sdp"); |
143 |
static SdpContents offerSdp(hfv, type); |
144 |
|
145 |
offer = offerSdp; |
146 |
|
147 |
// Set sessionid and version for this offer |
148 |
UInt64 currentTime = Timer::getTimeMicroSec(); |
149 |
offer.session().origin().getSessionId() = currentTime; |
150 |
offer.session().origin().getVersion() = currentTime; |
151 |
} |
152 |
|
153 |
//////////////////////////////////////////////////////////////////////////////// |
154 |
// InviteSessionHandler /////////////////////////////////////////////////// |
155 |
//////////////////////////////////////////////////////////////////////////////// |
156 |
|
157 |
void |
158 |
BasicClientCall::onNewSession(ClientInviteSessionHandle h, InviteSession::OfferAnswerType oat, const SipMessage& msg) |
159 |
{ |
160 |
InfoLog(<< "onNewSession(ClientInviteSessionHandle): msg=" << msg.brief()); |
161 |
mInviteSessionHandle = h->getSessionHandle(); // Note: each forked leg will update mInviteSession - need to set mInviteSessionHandle for final answering leg on 200 |
162 |
if(mInviteSessionHandleReplaced.isValid()) |
163 |
{ |
164 |
// See comment in flowTerminated for an explanation of this logic |
165 |
((BasicClientCall*)mInviteSessionHandleReplaced->getAppDialogSet().get())->terminateCall(); |
166 |
} |
167 |
} |
168 |
|
169 |
void |
170 |
BasicClientCall::onNewSession(ServerInviteSessionHandle h, InviteSession::OfferAnswerType oat, const SipMessage& msg) |
171 |
{ |
172 |
InfoLog(<< "onNewSession(ServerInviteSessionHandle): msg=" << msg.brief()); |
173 |
mInviteSessionHandle = h->getSessionHandle(); |
174 |
|
175 |
// First check if this INVITE is to replace an existing session |
176 |
if(msg.exists(h_Replaces)) |
177 |
{ |
178 |
pair<InviteSessionHandle, int> presult; |
179 |
presult = mDum.findInviteSession(msg.header(h_Replaces)); |
180 |
if(!(presult.first == InviteSessionHandle::NotValid())) |
181 |
{ |
182 |
BasicClientCall* callToReplace = dynamic_cast<BasicClientCall *>(presult.first->getAppDialogSet().get()); |
183 |
InfoLog(<< "onNewSession(ServerInviteSessionHandle): replacing existing call"); |
184 |
|
185 |
// Copy over flag that indicates if we placed the call or not |
186 |
mPlacedCall = callToReplace->mPlacedCall; |
187 |
|
188 |
if(mPlacedCall) |
189 |
{ |
190 |
// Restart Call Timer |
191 |
auto_ptr<ApplicationMessage> timer(new CallTimer(mUserAgent, this)); |
192 |
mUserAgent.mStack->post(timer, CallTimerTime, &mUserAgent.getDialogUsageManager()); |
193 |
} |
194 |
|
195 |
// Session to replace was found - end old session |
196 |
callToReplace->end(); |
197 |
} |
198 |
else |
199 |
{ |
200 |
// Session to replace not found - reject it |
201 |
h->reject(481 /* Call/Transaction Does Not Exist */); |
202 |
} |
203 |
} |
204 |
} |
205 |
|
206 |
void |
207 |
BasicClientCall::onFailure(ClientInviteSessionHandle h, const SipMessage& msg) |
208 |
{ |
209 |
WarningLog(<< "onFailure: msg=" << msg.brief()); |
210 |
|
211 |
if (msg.isResponse()) |
212 |
{ |
213 |
switch(msg.header(h_StatusLine).statusCode()) |
214 |
{ |
215 |
case 408: |
216 |
case 503: |
217 |
if(!msg.isFromWire()) |
218 |
{ |
219 |
// Try another flow? |
220 |
} |
221 |
default: |
222 |
break; |
223 |
} |
224 |
} |
225 |
} |
226 |
|
227 |
void |
228 |
BasicClientCall::onEarlyMedia(ClientInviteSessionHandle h, const SipMessage& msg, const SdpContents& sdp) |
229 |
{ |
230 |
InfoLog(<< "onEarlyMedia: msg=" << msg.brief() << ", sdp=" << sdp); |
231 |
} |
232 |
|
233 |
void |
234 |
BasicClientCall::onProvisional(ClientInviteSessionHandle h, const SipMessage& msg) |
235 |
{ |
236 |
InfoLog(<< "onProvisional: msg=" << msg.brief()); |
237 |
|
238 |
if(isStaleFork(h->getDialogId())) |
239 |
{ |
240 |
// If we receive a response from a stale fork (ie. after someone sends a 200), then we want to ignore it |
241 |
InfoLog(<< "onProvisional: from stale fork, msg=" << msg.brief()); |
242 |
return; |
243 |
} |
244 |
InfoLog(<< "onProvisional: msg=" << msg.brief()); |
245 |
} |
246 |
|
247 |
void |
248 |
BasicClientCall::onConnected(ClientInviteSessionHandle h, const SipMessage& msg) |
249 |
{ |
250 |
InfoLog(<< "onConnected: msg=" << msg.brief()); |
251 |
if(!isUACConnected()) |
252 |
{ |
253 |
// It is possible in forking scenarios to get multiple 200 responses, if this is |
254 |
// our first 200 response, then this is the leg we accept, store the connected DialogId |
255 |
mUACConnectedDialogId = h->getDialogId(); |
256 |
// Note: each forked leg will update mInviteSessionHandle (in onNewSession call) - need to set mInviteSessionHandle for final answering leg on 200 |
257 |
mInviteSessionHandle = h->getSessionHandle(); |
258 |
|
259 |
// start call timer |
260 |
auto_ptr<ApplicationMessage> timer(new CallTimer(mUserAgent, this)); |
261 |
mUserAgent.mStack->post(timer, CallTimerTime, &mUserAgent.getDialogUsageManager()); |
262 |
} |
263 |
else |
264 |
{ |
265 |
// We already have a connected leg - end this one with a BYE |
266 |
h->end(); |
267 |
} |
268 |
} |
269 |
|
270 |
void |
271 |
BasicClientCall::onConnected(InviteSessionHandle h, const SipMessage& msg) |
272 |
{ |
273 |
InfoLog(<< "onConnected: msg=" << msg.brief()); |
274 |
} |
275 |
|
276 |
void |
277 |
BasicClientCall::onStaleCallTimeout(ClientInviteSessionHandle h) |
278 |
{ |
279 |
WarningLog(<< "onStaleCallTimeout"); |
280 |
} |
281 |
|
282 |
void |
283 |
BasicClientCall::onTerminated(InviteSessionHandle h, InviteSessionHandler::TerminatedReason reason, const SipMessage* msg) |
284 |
{ |
285 |
Data reasonData; |
286 |
|
287 |
switch(reason) |
288 |
{ |
289 |
case InviteSessionHandler::RemoteBye: |
290 |
reasonData = "received a BYE from peer"; |
291 |
break; |
292 |
case InviteSessionHandler::RemoteCancel: |
293 |
reasonData = "received a CANCEL from peer"; |
294 |
break; |
295 |
case InviteSessionHandler::Rejected: |
296 |
reasonData = "received a rejection from peer"; |
297 |
break; |
298 |
case InviteSessionHandler::LocalBye: |
299 |
reasonData = "ended locally via BYE"; |
300 |
break; |
301 |
case InviteSessionHandler::LocalCancel: |
302 |
reasonData = "ended locally via CANCEL"; |
303 |
break; |
304 |
case InviteSessionHandler::Replaced: |
305 |
reasonData = "ended due to being replaced"; |
306 |
break; |
307 |
case InviteSessionHandler::Referred: |
308 |
reasonData = "ended due to being referred"; |
309 |
break; |
310 |
case InviteSessionHandler::Error: |
311 |
reasonData = "ended due to an error"; |
312 |
break; |
313 |
case InviteSessionHandler::Timeout: |
314 |
reasonData = "ended due to a timeout"; |
315 |
break; |
316 |
default: |
317 |
assert(false); |
318 |
break; |
319 |
} |
320 |
|
321 |
if(isStaleFork(h->getDialogId())) |
322 |
{ |
323 |
// If we receive a response from a stale fork (ie. after someone sends a 200), then we want to ignore it |
324 |
if(msg) |
325 |
{ |
326 |
InfoLog(<< "onTerminated: from stale fork, reason=" << reasonData << ", msg=" << msg->brief()); |
327 |
} |
328 |
else |
329 |
{ |
330 |
InfoLog(<< "onTerminated: from stale fork, reason=" << reasonData); |
331 |
} |
332 |
return; |
333 |
} |
334 |
|
335 |
if(msg) |
336 |
{ |
337 |
InfoLog(<< "onTerminated: reason=" << reasonData << ", msg=" << msg->brief()); |
338 |
} |
339 |
else |
340 |
{ |
341 |
InfoLog(<< "onTerminated: reason=" << reasonData); |
342 |
} |
343 |
} |
344 |
|
345 |
void |
346 |
BasicClientCall::onRedirected(ClientInviteSessionHandle h, const SipMessage& msg) |
347 |
{ |
348 |
// DUM will recurse on redirect requests, so nothing to do here |
349 |
InfoLog(<< "onRedirected: msg=" << msg.brief()); |
350 |
} |
351 |
|
352 |
void |
353 |
BasicClientCall::onAnswer(InviteSessionHandle h, const SipMessage& msg, const SdpContents& sdp) |
354 |
{ |
355 |
if(isStaleFork(h->getDialogId())) |
356 |
{ |
357 |
// If we receive a response from a stale fork (ie. after someone sends a 200), then we want to ignore it |
358 |
InfoLog(<< "onAnswer: from stale fork, msg=" << msg.brief() << ", sdp=" << sdp); |
359 |
return; |
360 |
} |
361 |
InfoLog(<< "onAnswer: msg=" << msg.brief() << ", sdp=" << sdp); |
362 |
|
363 |
// Process Answer here |
364 |
} |
365 |
|
366 |
void |
367 |
BasicClientCall::onOffer(InviteSessionHandle h, const SipMessage& msg, const SdpContents& sdp) |
368 |
{ |
369 |
if(isStaleFork(h->getDialogId())) |
370 |
{ |
371 |
// If we receive a response from a stale fork (ie. after someone sends a 200), then we want to ignore it |
372 |
InfoLog(<< "onOffer: from stale fork, msg=" << msg.brief() << ", sdp=" << sdp); |
373 |
return; |
374 |
} |
375 |
InfoLog(<< "onOffer: msg=" << msg.brief() << ", sdp=" << sdp); |
376 |
|
377 |
// Provide Answer here - for test client just echo back same SDP as received for now |
378 |
h->provideAnswer(sdp); |
379 |
ServerInviteSession* uas = dynamic_cast<ServerInviteSession*>(h.get()); |
380 |
if(uas && !uas->isAccepted()) |
381 |
{ |
382 |
uas->accept(); |
383 |
} |
384 |
} |
385 |
|
386 |
void |
387 |
BasicClientCall::onOfferRequired(InviteSessionHandle h, const SipMessage& msg) |
388 |
{ |
389 |
if(isStaleFork(h->getDialogId())) |
390 |
{ |
391 |
// If we receive a response from a stale fork (ie. after someone sends a 200), then we want to ignore it |
392 |
InfoLog(<< "onOfferRequired: from stale fork, msg=" << msg.brief()); |
393 |
return; |
394 |
} |
395 |
InfoLog(<< "onOfferRequired: msg=" << msg.brief()); |
396 |
|
397 |
// Provide Offer Here |
398 |
SdpContents offer; |
399 |
makeOffer(offer); |
400 |
|
401 |
h->provideOffer(offer); |
402 |
} |
403 |
|
404 |
void |
405 |
BasicClientCall::onOfferRejected(InviteSessionHandle h, const SipMessage* msg) |
406 |
{ |
407 |
if(isStaleFork(h->getDialogId())) |
408 |
{ |
409 |
// If we receive a response from a stale fork (ie. after someone sends a 200), then we want to ignore it |
410 |
if(msg) |
411 |
{ |
412 |
WarningLog(<< "onOfferRejected: from stale fork, msg=" << msg->brief()); |
413 |
} |
414 |
else |
415 |
{ |
416 |
WarningLog(<< "onOfferRejected: from stale fork"); |
417 |
} |
418 |
return; |
419 |
} |
420 |
if(msg) |
421 |
{ |
422 |
WarningLog(<< "onOfferRejected: msg=" << msg->brief()); |
423 |
} |
424 |
else |
425 |
{ |
426 |
WarningLog(<< "onOfferRejected"); |
427 |
} |
428 |
} |
429 |
|
430 |
void |
431 |
BasicClientCall::onOfferRequestRejected(InviteSessionHandle h, const SipMessage& msg) |
432 |
{ |
433 |
InfoLog(<< "onOfferRequestRejected: msg=" << msg.brief()); |
434 |
// This is called when we are waiting to resend a INVITE with no sdp after a glare condition, and we |
435 |
// instead receive an inbound INVITE or UPDATE |
436 |
} |
437 |
|
438 |
void |
439 |
BasicClientCall::onRemoteSdpChanged(InviteSessionHandle h, const SipMessage& msg, const SdpContents& sdp) |
440 |
{ |
441 |
/// called when a modified SDP is received in a 2xx response to a |
442 |
/// session-timer reINVITE. Under normal circumstances where the response |
443 |
/// SDP is unchanged from current remote SDP no handler is called |
444 |
/// There is not much we can do about this. If session timers are used then they are managed seperately per leg |
445 |
/// and we have no real mechanism to notify the other peer of new SDP without starting a new offer/answer negotiation |
446 |
InfoLog(<< "onRemoteSdpChanged: msg=" << msg << ", sdp=" << sdp); |
447 |
|
448 |
// Process SDP Answer here |
449 |
} |
450 |
|
451 |
void |
452 |
BasicClientCall::onInfo(InviteSessionHandle h, const SipMessage& msg) |
453 |
{ |
454 |
InfoLog(<< "onInfo: msg=" << msg.brief()); |
455 |
|
456 |
// Handle message here |
457 |
h->acceptNIT(); |
458 |
} |
459 |
|
460 |
void |
461 |
BasicClientCall::onInfoSuccess(InviteSessionHandle h, const SipMessage& msg) |
462 |
{ |
463 |
InfoLog(<< "onInfoSuccess: msg=" << msg.brief()); |
464 |
} |
465 |
|
466 |
void |
467 |
BasicClientCall::onInfoFailure(InviteSessionHandle h, const SipMessage& msg) |
468 |
{ |
469 |
WarningLog(<< "onInfoFailure: msg=" << msg.brief()); |
470 |
} |
471 |
|
472 |
void |
473 |
BasicClientCall::onRefer(InviteSessionHandle h, ServerSubscriptionHandle ss, const SipMessage& msg) |
474 |
{ |
475 |
InfoLog(<< "onRefer: msg=" << msg.brief()); |
476 |
|
477 |
// Handle Refer request here |
478 |
} |
479 |
|
480 |
void |
481 |
BasicClientCall::onReferAccepted(InviteSessionHandle h, ClientSubscriptionHandle csh, const SipMessage& msg) |
482 |
{ |
483 |
InfoLog(<< "onReferAccepted: msg=" << msg.brief()); |
484 |
} |
485 |
|
486 |
void |
487 |
BasicClientCall::onReferRejected(InviteSessionHandle h, const SipMessage& msg) |
488 |
{ |
489 |
WarningLog(<< "onReferRejected: msg=" << msg.brief()); |
490 |
} |
491 |
|
492 |
void |
493 |
BasicClientCall::onReferNoSub(InviteSessionHandle h, const SipMessage& msg) |
494 |
{ |
495 |
InfoLog(<< "onReferNoSub: msg=" << msg.brief()); |
496 |
|
497 |
// Handle Refer request with (no-subscription indication) here |
498 |
} |
499 |
|
500 |
void |
501 |
BasicClientCall::onMessage(InviteSessionHandle h, const SipMessage& msg) |
502 |
{ |
503 |
InfoLog(<< "onMessage: msg=" << msg.brief()); |
504 |
|
505 |
// Handle message here |
506 |
h->acceptNIT(); |
507 |
|
508 |
if(!mPlacedCall) |
509 |
{ |
510 |
// If we didn't place the call - answer the message with another message |
511 |
PlainContents plain("test message answer"); |
512 |
h->message(plain); |
513 |
} |
514 |
} |
515 |
|
516 |
void |
517 |
BasicClientCall::onMessageSuccess(InviteSessionHandle h, const SipMessage& msg) |
518 |
{ |
519 |
InfoLog(<< "onMessageSuccess: msg=" << msg.brief()); |
520 |
} |
521 |
|
522 |
void |
523 |
BasicClientCall::onMessageFailure(InviteSessionHandle h, const SipMessage& msg) |
524 |
{ |
525 |
WarningLog(<< "onMessageFailure: msg=" << msg.brief()); |
526 |
} |
527 |
|
528 |
void |
529 |
BasicClientCall::onForkDestroyed(ClientInviteSessionHandle h) |
530 |
{ |
531 |
InfoLog(<< "onForkDestroyed:"); |
532 |
} |
533 |
|
534 |
void |
535 |
BasicClientCall::onReadyToSend(InviteSessionHandle h, SipMessage& msg) |
536 |
{ |
537 |
} |
538 |
|
539 |
void |
540 |
BasicClientCall::onFlowTerminated(InviteSessionHandle h) |
541 |
{ |
542 |
if(h->isConnected()) |
543 |
{ |
544 |
NameAddr inviteWithReplacesTarget; |
545 |
if(h->remoteTarget().uri().exists(p_gr)) |
546 |
{ |
547 |
// If remote contact is a GRUU then use it |
548 |
inviteWithReplacesTarget.uri() = h->remoteTarget().uri(); |
549 |
} |
550 |
else |
551 |
{ |
552 |
//.Use remote AOR |
553 |
inviteWithReplacesTarget.uri() = h->peerAddr().uri(); |
554 |
} |
555 |
InfoLog(<< "BasicClientCall::onFlowTerminated: trying INVITE w/replaces to " << inviteWithReplacesTarget); |
556 |
// The flow terminated - try an Invite (with Replaces) to recover the call |
557 |
BasicClientCall *replacesCall = new BasicClientCall(mUserAgent); |
558 |
|
559 |
// Copy over flag that indicates wether original call was placed or received |
560 |
replacesCall->mPlacedCall = mPlacedCall; |
561 |
|
562 |
// Note: We want to end this call since it is to be replaced. Normally the endpoint |
563 |
// receiving the INVITE with replaces would send us a BYE for the session being replaced. |
564 |
// However, since the old flow is dead, we will never see this BYE. We need this call to |
565 |
// go away somehow, however we cannot just end it directly here via terminateCall. |
566 |
// Since the flow to other party is likely fine - if we terminate this call now the BYE |
567 |
// is very likely to make it to the far end, before the above INVITE - if this happens then |
568 |
// the replaces logic of the INVITE will have no effect. We want to delay the release of |
569 |
// this call, by passing our handle to the new INVITE call and have it terminate this call, |
570 |
// once we know the far end has processed our new INVITE. |
571 |
replacesCall->mInviteSessionHandleReplaced = mInviteSessionHandle; |
572 |
|
573 |
SdpContents offer; |
574 |
replacesCall->makeOffer(offer); |
575 |
SharedPtr<SipMessage> invite = mUserAgent.getDialogUsageManager().makeInviteSession(inviteWithReplacesTarget, h, getUserProfile(), &offer, replacesCall); |
576 |
mUserAgent.getDialogUsageManager().send(invite); |
577 |
} |
578 |
} |
579 |
|
580 |
//////////////////////////////////////////////////////////////////////////////// |
581 |
// DialogSetHandler /////////////////////////////////////////////////// |
582 |
//////////////////////////////////////////////////////////////////////////////// |
583 |
void |
584 |
BasicClientCall::onTrying(AppDialogSetHandle h, const SipMessage& msg) |
585 |
{ |
586 |
InfoLog(<< "onTrying: msg=" << msg.brief()); |
587 |
if(isUACConnected()) return; // Ignore 100's if already connected |
588 |
|
589 |
// Handle message here |
590 |
} |
591 |
|
592 |
void |
593 |
BasicClientCall::onNonDialogCreatingProvisional(AppDialogSetHandle h, const SipMessage& msg) |
594 |
{ |
595 |
InfoLog(<< "onNonDialogCreatingProvisional: msg=" << msg.brief()); |
596 |
if(isUACConnected()) return; // Ignore provionals if already connected |
597 |
|
598 |
// Handle message here |
599 |
} |
600 |
|
601 |
//////////////////////////////////////////////////////////////////////////////// |
602 |
// ClientSubscriptionHandler /////////////////////////////////////////////////// |
603 |
//////////////////////////////////////////////////////////////////////////////// |
604 |
void |
605 |
BasicClientCall::onUpdatePending(ClientSubscriptionHandle h, const SipMessage& msg, bool outOfOrder) |
606 |
{ |
607 |
InfoLog(<< "onUpdatePending(ClientSubscriptionHandle): " << msg.brief()); |
608 |
if (msg.exists(h_Event) && msg.header(h_Event).value() == "refer") |
609 |
{ |
610 |
//process Refer Notify Here |
611 |
} |
612 |
h->acceptUpdate(); |
613 |
} |
614 |
|
615 |
void |
616 |
BasicClientCall::onUpdateActive(ClientSubscriptionHandle h, const SipMessage& msg, bool outOfOrder) |
617 |
{ |
618 |
InfoLog(<< "onUpdateActive(ClientSubscriptionHandle): " << msg.brief()); |
619 |
if (msg.exists(h_Event) && msg.header(h_Event).value() == "refer") |
620 |
{ |
621 |
//process Refer Notify Here |
622 |
} |
623 |
h->acceptUpdate(); |
624 |
} |
625 |
|
626 |
void |
627 |
BasicClientCall::onUpdateExtension(ClientSubscriptionHandle h, const SipMessage& msg, bool outOfOrder) |
628 |
{ |
629 |
InfoLog(<< "onUpdateExtension(ClientSubscriptionHandle): " << msg.brief()); |
630 |
if (msg.exists(h_Event) && msg.header(h_Event).value() == "refer") |
631 |
{ |
632 |
//process Refer Notify Here |
633 |
} |
634 |
h->acceptUpdate(); |
635 |
} |
636 |
|
637 |
void |
638 |
BasicClientCall::onNotifyNotReceived(resip::ClientSubscriptionHandle h) |
639 |
{ |
640 |
InfoLog(<< "onNotifyNotReceived(ClientSubscriptionHandle)"); |
641 |
h->end(); |
642 |
} |
643 |
|
644 |
void |
645 |
BasicClientCall::onTerminated(ClientSubscriptionHandle h, const SipMessage* msg) |
646 |
{ |
647 |
if(msg) |
648 |
{ |
649 |
InfoLog(<< "onTerminated(ClientSubscriptionHandle): " << msg->brief()); |
650 |
//Note: Final notify is sometimes only passed in the onTerminated callback |
651 |
if (msg->isRequest() && msg->exists(h_Event) && msg->header(h_Event).value() == "refer") |
652 |
{ |
653 |
//process Refer Notify Here |
654 |
} |
655 |
} |
656 |
else |
657 |
{ |
658 |
InfoLog(<< "onTerminated(ClientSubscriptionHandle)"); |
659 |
} |
660 |
} |
661 |
|
662 |
void |
663 |
BasicClientCall::onNewSubscription(ClientSubscriptionHandle h, const SipMessage& msg) |
664 |
{ |
665 |
InfoLog(<< "onNewSubscription(ClientSubscriptionHandle): " << msg.brief()); |
666 |
} |
667 |
|
668 |
int |
669 |
BasicClientCall::onRequestRetry(ClientSubscriptionHandle h, int retrySeconds, const SipMessage& msg) |
670 |
{ |
671 |
InfoLog(<< "onRequestRetry(ClientSubscriptionHandle): " << msg.brief()); |
672 |
return -1; |
673 |
} |
674 |
|
675 |
void |
676 |
BasicClientCall::onRedirectReceived(AppDialogSetHandle h, const SipMessage& msg) |
677 |
{ |
678 |
InfoLog(<< "onRedirectReceived: msg=" << msg.brief()); |
679 |
} |
680 |
|
681 |
|
682 |
/* ==================================================================== |
683 |
|
684 |
Copyright (c) 2011, SIP Spectrum, Inc. |
685 |
All rights reserved. |
686 |
|
687 |
Redistribution and use in source and binary forms, with or without |
688 |
modification, are permitted provided that the following conditions are |
689 |
met: |
690 |
|
691 |
1. Redistributions of source code must retain the above copyright |
692 |
notice, this list of conditions and the following disclaimer. |
693 |
|
694 |
2. Redistributions in binary form must reproduce the above copyright |
695 |
notice, this list of conditions and the following disclaimer in the |
696 |
documentation and/or other materials provided with the distribution. |
697 |
|
698 |
3. Neither the name of SIP Spectrum nor the names of its contributors |
699 |
may be used to endorse or promote products derived from this |
700 |
software without specific prior written permission. |
701 |
|
702 |
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
703 |
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
704 |
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
705 |
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
706 |
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
707 |
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
708 |
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
709 |
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
710 |
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
711 |
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
712 |
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
713 |
|
714 |
==================================================================== */ |