Browse code

B2B call cleanup: more precise call state handling and simplified call termination

Václav Kubart authored on 08/11/2012 13:28:12
Showing 5 changed files
... ...
@@ -6,13 +6,14 @@
6 6
 #include "AmUtils.h"
7 7
 #include "AmRtpReceiver.h"
8 8
 
9
-#define TRACE INFO
9
+#define TRACE DBG
10 10
 
11 11
 // helper functions
12 12
 
13 13
 static const char *callStatus2str(const CallLeg::CallStatus state)
14 14
 {
15 15
   static const char *disconnected = "Disconnected";
16
+  static const char *disconnecting = "Disconnecting";
16 17
   static const char *noreply = "NoReply";
17 18
   static const char *ringing = "Ringing";
18 19
   static const char *connected = "Connected";
... ...
@@ -20,6 +21,7 @@ static const char *callStatus2str(const CallLeg::CallStatus state)
20 21
 
21 22
   switch (state) {
22 23
     case CallLeg::Disconnected: return disconnected;
24
+    case CallLeg::Disconnecting: return disconnecting;
23 25
     case CallLeg::NoReply: return noreply;
24 26
     case CallLeg::Ringing: return ringing;
25 27
     case CallLeg::Connected: return connected;
... ...
@@ -46,17 +48,6 @@ ReliableB2BEvent::~ReliableB2BEvent()
46 48
 
47 49
 ////////////////////////////////////////////////////////////////////////////////
48 50
 
49
-#if 0
50
-// callee
51
-CallLeg::CallLeg(const string& other_local_tag): 
52
-  AmB2BSession(other_local_tag),
53
-  call_status(Disconnected)
54
-{
55
-  a_leg = false;
56
-  // TODO: copy RTP settings
57
-}
58
-#endif
59
-
60 51
 // callee
61 52
 CallLeg::CallLeg(const CallLeg* caller):
62 53
   AmB2BSession(caller->getLocalTag()),
... ...
@@ -65,7 +56,7 @@ CallLeg::CallLeg(const CallLeg* caller):
65 56
 {
66 57
   a_leg = !caller->a_leg; // we have to be the complement
67 58
 
68
-  set_sip_relay_only(false); // will be changed later on
59
+  set_sip_relay_only(false); // will be changed later on (for now we have no peer so we can't relay)
69 60
 
70 61
   // code below taken from createCalleeSession
71 62
 
... ...
@@ -127,23 +118,10 @@ void CallLeg::terminateOtherLeg()
127 118
   
128 119
   AmB2BSession::terminateOtherLeg();
129 120
 
121
+  // FIXME: call disconnect if connected (to put remote on hold)?
130 122
   updateCallStatus(Disconnected); // no B legs should be remaining
131 123
 }
132 124
 
133
-void CallLeg::terminateOtherLeg(const string &id)
134
-{
135
-  // remove the call leg from list of B legs
136
-  for (vector<OtherLegInfo>::iterator i = other_legs.begin(); i != other_legs.end(); ++i) {
137
-    if (i->id == id) {
138
-      i->releaseMediaSession();
139
-      other_legs.erase(i);
140
-      AmSessionContainer::instance()->postEvent(id, new B2BEvent(B2BTerminateLeg));
141
-      return;
142
-    }
143
-  }
144
-  DBG("trying to terminate other leg which is not in the list of legs, might be terminated already\n");
145
-}
146
-
147 125
 void CallLeg::terminateNotConnectedLegs()
148 126
 {
149 127
   bool found = false;
... ...
@@ -174,9 +152,11 @@ void CallLeg::removeOtherLeg(const string &id)
174 152
     if (i->id == id) {
175 153
       i->releaseMediaSession();
176 154
       other_legs.erase(i);
177
-      return;
155
+      break;
178 156
     }
179 157
   }
158
+
159
+  /*if (terminate) AmSessionContainer::instance()->postEvent(id, new B2BEvent(B2BTerminateLeg));*/
180 160
 }
181 161
 
182 162
 // composed for caller and callee already
... ...
@@ -205,7 +185,7 @@ void CallLeg::onB2BEvent(B2BEvent* ev)
205 185
       break;
206 186
 
207 187
     case DisconnectLeg:
208
-      onB2BDisconnect(dynamic_cast<DisconnectLegEvent *>(ev));
188
+      if (dynamic_cast<DisconnectLegEvent*>(ev)) disconnect(true);
209 189
       break;
210 190
 
211 191
     case B2BSipRequest:
... ...
@@ -252,13 +232,6 @@ int CallLeg::relaySipReply(AmSipReply &reply)
252 232
   return res;
253 233
 }
254 234
 
255
-void CallLeg::terminateCall()
256
-{
257
-  terminateNotConnectedLegs();
258
-  terminateOtherLeg();
259
-  terminateLeg();
260
-}
261
-
262 235
 // was for caller only
263 236
 void CallLeg::onB2BReply(B2BSipReplyEvent *ev)
264 237
 {
... ...
@@ -295,8 +268,8 @@ void CallLeg::onB2BReply(B2BSipReplyEvent *ev)
295 268
 #endif
296 269
 
297 270
   // handle relayed initial replies specific way
298
-  // FIXME: testing est_invite_cseq is wrong! (checking in what direction would
299
-  // be needed)
271
+  // testing est_invite_cseq is wrong! (checking in what direction or what role
272
+  // would be needed)
300 273
   if (reply.cseq_method == SIP_METH_INVITE &&
301 274
       (call_status == NoReply || call_status == Ringing) &&
302 275
       ((reply.cseq == est_invite_cseq && ev->forward) ||
... ...
@@ -311,14 +284,14 @@ void CallLeg::onB2BReply(B2BSipReplyEvent *ev)
311 284
     if (reply.code < 200) { // 1xx replies
312 285
       if (call_status == NoReply) {
313 286
         if (ev->forward && relaySipReply(reply) != 0) {
314
-          terminateCall();
287
+          stopCall();
315 288
           return;
316 289
         }
317 290
         if (!reply.to_tag.empty()) {
318 291
           other_id = reply.from_tag;
319 292
           TRACE("1xx reply with to-tag received in NoReply state, changing status to Ringing and remembering the other leg ID (%s)\n", other_id.c_str());
320 293
           if (ev->forward && relaySipReply(reply) != 0) {
321
-            terminateCall();
294
+            stopCall();
322 295
             return;
323 296
           }
324 297
           updateCallStatus(Ringing);
... ...
@@ -344,7 +317,7 @@ void CallLeg::onB2BReply(B2BSipReplyEvent *ev)
344 317
           reply.body = empty_body;
345 318
         }
346 319
         if (ev->forward && relaySipReply(reply) != 0) {
347
-          terminateCall();
320
+          stopCall();
348 321
           return;
349 322
         }
350 323
       }
... ...
@@ -357,7 +330,7 @@ void CallLeg::onB2BReply(B2BSipReplyEvent *ev)
357 330
 
358 331
       if (other_legs.empty()) {
359 332
         ERROR("BUG: connected but there is no B leg remaining\n");
360
-        setStopped();
333
+        stopCall();
361 334
         return;
362 335
       }
363 336
 
... ...
@@ -376,38 +349,28 @@ void CallLeg::onB2BReply(B2BSipReplyEvent *ev)
376 349
       set_sip_relay_only(true); // relay only from now on
377 350
 
378 351
       if (!ev->forward) {
379
-        // TODO: we need to generate re-INVITE based on received SDP
352
+        // we need to generate re-INVITE based on received SDP
380 353
         saveSessionDescription(reply.body);
381 354
         sendEstablishedReInvite();
382 355
       }
383 356
       else if (relaySipReply(reply) != 0) {
384
-        terminateCall();
357
+        stopCall();
385 358
         return;
386 359
       }
387 360
       updateCallStatus(Connected);
388 361
     } else { // 3xx-6xx replies
389
-      if (other_id == reply.from_tag) other_id.clear();
390
-
391
-      // clean up the other leg; 
392
-      // eventually do serial fork, handle redirect or whatever else
393
-      terminateOtherLeg(reply.from_tag);
362
+      removeOtherLeg(reply.from_tag); // we don't care about this leg any more
363
+      onBLegRefused(reply); // possible serial fork here
394 364
 
395
-      onBLegRefused(reply);
396
-
397
-      if (!other_legs.empty()) {
398
-        // there are other B legs for us, wait for their responses and do not
399
-        // relay current response
400
-        return;
401
-      }
365
+      // there are other B legs for us => wait for their responses and do not
366
+      // relay current response
367
+      if (!other_legs.empty()) return;
402 368
 
403
-      // FIXME: call this from ternimateLeg or let the successors override terminateLeg instead?
404
-      onCallStopped();
369
+      if (ev->forward) relaySipReply(reply);
405 370
 
406 371
       // no other B legs, terminate
407
-      setStopped(); // would be called in onOtherReply
408
-
409
-      if (ev->forward) relaySipReply(reply);
410 372
       updateCallStatus(Disconnected);
373
+      stopCall();
411 374
     }
412 375
 
413 376
     return; // relayed reply to initial request is processed
... ...
@@ -419,9 +382,6 @@ void CallLeg::onB2BReply(B2BSipReplyEvent *ev)
419 382
     return;
420 383
   }
421 384
 
422
-  // TODO: handle call transfers (i.e. the other leg is reINVITing and we should
423
-  // reINVITE as well according to its result)
424
-
425 385
   // handle replies to other requests than the initial one
426 386
   DBG("handling reply via AmB2BSession\n");
427 387
   AmB2BSession::onB2BEvent(ev);
... ...
@@ -479,7 +439,7 @@ void CallLeg::onB2BConnect(ConnectLegEvent* co_ev)
479 439
     DBG("sending INVITE failed, relaying back error reply\n");
480 440
     relayError(SIP_METH_INVITE, co_ev->r_cseq, true, res);
481 441
 
482
-    setStopped();
442
+    stopCall();
483 443
     return;
484 444
   }
485 445
 
... ...
@@ -556,11 +516,10 @@ void CallLeg::onB2BReconnect(ReconnectLegEvent* ev)
556 516
     DBG("sending re-INVITE failed, relaying back error reply\n");
557 517
     relayError(SIP_METH_INVITE, ev->r_cseq, true, res);
558 518
 
559
-    setStopped();
519
+    stopCall();
560 520
     return;
561 521
   }
562 522
 
563
-  // always relayed INVITE - store it
564 523
   if (ev->relayed_invite) {
565 524
     relayed_req[dlg.cseq - 1] = AmSipTransaction(SIP_METH_INVITE, ev->r_cseq, trans_ticket());
566 525
     est_invite_other_cseq = ev->r_cseq;
... ...
@@ -609,7 +568,7 @@ void CallLeg::onB2BReplace(ReplaceLegEvent *e)
609 568
   removeOtherLeg(id);
610 569
 
611 570
   // commit suicide if our last B leg is stolen
612
-  if (other_legs.empty() && other_id.empty()) terminateLeg();
571
+  if (other_legs.empty() && other_id.empty()) stopCall();
613 572
 }
614 573
 
615 574
 void CallLeg::onB2BReplaceInProgress(ReplaceInProgressEvent *e)
... ...
@@ -623,23 +582,45 @@ void CallLeg::onB2BReplaceInProgress(ReplaceInProgressEvent *e)
623 582
   }
624 583
 }
625 584
 
626
-void CallLeg::onB2BDisconnect(DisconnectLegEvent* ev)
585
+void CallLeg::disconnect(bool hold_remote)
627 586
 {
628
-  if (!ev) {
629
-    ERROR("BUG: invalid argument given\n");
630
-    return;
587
+  TRACE("disconnecting call leg %s from the other\n", getLocalTag().c_str());
588
+
589
+  switch (call_status) {
590
+    case Disconnecting:
591
+    case Disconnected:
592
+      DBG("trying to disconnect already disconnected (or disconnecting) call leg\n");
593
+      return;
594
+
595
+    case NoReply:
596
+    case Ringing:
597
+      WARN("trying to disconnect in not connected state, terminating not connected legs in advance (was it intended?)\n");
598
+      terminateNotConnectedLegs();
599
+      break;
600
+
601
+    case Connected:
602
+      clearRtpReceiverRelay(); // we can't stay connected (at media level) with the other leg
603
+      break; // this is OK
631 604
   }
632 605
 
633
-  TRACE("disconnecting call %s leg from the other\n", getLocalTag().c_str());
634 606
   clear_other();
635
-
636 607
   set_sip_relay_only(false); // we can't relay once disconnected
637 608
 
638 609
   // put the remote on hold (we have no 'other leg', we can do what we want)
610
+  if (!hold_remote) {
611
+    updateCallStatus(Disconnected);
612
+    return;
613
+  }
614
+
615
+  // FIXME: throw this out?
616
+  if (media_session && media_session->isOnHold(a_leg)) {
617
+    updateCallStatus(Disconnected);
618
+    return; // already on hold
619
+  }
639 620
 
640
-  if (media_session && media_session->isOnHold(a_leg)) return; // already on hold
621
+  TRACE("putting remote on hold\n");
641 622
 
642
-  TRACE("putting %s on hold\n", getLocalTag().c_str());
623
+  updateCallStatus(Disconnecting);
643 624
 
644 625
   if (getRtpRelayMode() != AmB2BSession::RTP_Relay)
645 626
     setRtpRelayMode(RTP_Relay);
... ...
@@ -661,7 +642,7 @@ void CallLeg::onB2BDisconnect(DisconnectLegEvent* ev)
661 642
   if (dlg.reinvite("", &body, SIP_FLAGS_VERBATIM) != 0) {
662 643
     ERROR("re-INVITE failed\n");
663 644
   }
664
-  hold_request_cseq = dlg.cseq - 1;
645
+  else hold_request_cseq = dlg.cseq - 1;
665 646
 }
666 647
 
667 648
 // was for caller only
... ...
@@ -698,8 +679,6 @@ void CallLeg::onSipRequest(const AmSipRequest& req)
698 679
       getLocalTag().c_str(),
699 680
       req.cseq, req.method.c_str(), callStatus2str(call_status));
700 681
 
701
-  TRACE("established CSeq: %d\n", est_invite_cseq);
702
-
703 682
   // we need to handle cases if there is no other leg (for example call parking)
704 683
   // Note that setting sip_relay_only to false in this case doesn't solve the
705 684
   // problem because AmB2BSession always tries to relay the request into the
... ...
@@ -708,7 +687,7 @@ void CallLeg::onSipRequest(const AmSipRequest& req)
708 687
     TRACE("handling request %s in disconnected state", req.method.c_str());
709 688
     // this is not correct but what is?
710 689
     AmSession::onSipRequest(req);
711
-    if (req.method == SIP_METH_BYE) terminateLeg(); // is this needed?
690
+    if (req.method == SIP_METH_BYE) stopCall(); // is this needed?
712 691
   }
713 692
   else AmB2BSession::onSipRequest(req);
714 693
 }
... ...
@@ -732,36 +711,27 @@ void CallLeg::onSipReply(const AmSipReply& reply, AmSipDialog::Status old_dlg_st
732 711
     (call_status == NoReply || call_status == Ringing)) {
733 712
     // reply to the initial request
734 713
     if ((reply.code > 100) && (reply.code < 200)) {
735
-      if (((call_status == Disconnected) || (call_status == NoReply)) && (!reply.to_tag.empty()))
714
+      if (((call_status == NoReply)) && (!reply.to_tag.empty()))
736 715
         updateCallStatus(Ringing);
737 716
     }
738 717
     else if ((reply.code >= 200) && (reply.code < 300)) {
739
-      if (call_status != Connected) {
740
-        onCallConnected(reply);
741
-        updateCallStatus(Connected);
742
-      }
718
+      onCallConnected(reply);
719
+      updateCallStatus(Connected);
743 720
     }
744 721
     else if (reply.code >= 300) {
745
-      if ((call_status != Disconnected) || (dlg.getStatus() != old_dlg_status)) {
746
-        // in case of canceling it happens that B leg is already in Disconnected
747
-        // status (terminateLeg called) but later comes the 487 reply and
748
-        // updates dlg, we need to call callbacks on that change!
749
-        updateCallStatus(Disconnected);
750
-      }
722
+      terminateLeg(); // commit suicide (don't let the master to kill us)
751 723
     }
752 724
   }
753 725
 
754
-  // we are created on the fly (not based on initial INIVITE), we have to
755
-  // ACK the reply by ourselves
756
-/*  if (!relayed_request && reply.cseq_method == SIP_METH_INVITE && SIP_IS_200_CLASS(reply.code)) {
757
-    DBG("generating ACK for non-relayed INVITE\n");
758
-    dlg.send_200_ack(reply.cseq);
759
-  }*/
760
-
761 726
   if ((reply.cseq == hold_request_cseq) && (reply.cseq_method == SIP_METH_INVITE)) {
727
+    // hold request replied
762 728
     if (reply.code < 200) { return; /* wait for final reply */ }
763
-    if (reply.code < 300) { hold_request_cseq = 0; }
764
-    else { hold_request_cseq = 0; }
729
+    else {
730
+      // ignore the result (if hold request is not accepted that's a pitty but
731
+      // we are Disconnected anyway)
732
+      if (call_status == Disconnecting) updateCallStatus(Disconnected);
733
+      hold_request_cseq = 0;
734
+    }
765 735
   }
766 736
 }
767 737
 
... ...
@@ -789,9 +759,7 @@ void CallLeg::onCancel(const AmSipRequest& req)
789 759
   if ((call_status == Ringing) || (call_status == NoReply)) {
790 760
     if (a_leg) {
791 761
       // terminate whole B2B call if the caller receives CANCEL
792
-      terminateNotConnectedLegs();
793
-      terminateOtherLeg();
794
-      terminateLeg();
762
+      stopCall();
795 763
     }
796 764
     // else { } ... ignore for B leg
797 765
   }
... ...
@@ -802,7 +770,7 @@ void CallLeg::onCancel(const AmSipRequest& req)
802 770
 void CallLeg::terminateLeg()
803 771
 {
804 772
   AmB2BSession::terminateLeg();
805
-  if (call_status != Disconnected) updateCallStatus(Disconnected);
773
+  onCallStopped();
806 774
 }
807 775
 
808 776
 // was for caller only
... ...
@@ -823,7 +791,6 @@ void CallLeg::onBye(const AmSipRequest& req)
823 791
 {
824 792
   clearRtpReceiverRelay(); // FIXME: shouldn't be cleared in AmB2BSession as well?
825 793
   AmB2BSession::onBye(req);
826
-  updateCallStatus(Disconnected); // shouldn't we wait for BYE response?
827 794
 }
828 795
 
829 796
 void CallLeg::addNewCallee(CallLeg *callee, ConnectLegEvent *e)
... ...
@@ -984,11 +951,10 @@ void CallLeg::clear_other()
984 951
 {
985 952
   removeOtherLeg(other_id);
986 953
   AmB2BSession::clear_other();
987
-  // we need to set correct call status
988
-  if (other_legs.empty()) {
989
-    updateCallStatus(Disconnected);
990
-    set_sip_relay_only(false); // we have no other leg
991
-  }
992
-  else updateCallStatus(NoReply);
993 954
 }
994 955
 
956
+void CallLeg::stopCall() {
957
+  terminateNotConnectedLegs();
958
+  terminateOtherLeg();
959
+  terminateLeg();
960
+}
... ...
@@ -168,12 +168,17 @@ struct DisconnectLegEvent: public B2BEvent
168 168
 class CallLeg: public AmB2BSession
169 169
 {
170 170
   public:
171
+    /** B2B call status.
172
+     *
173
+     * This status need not to be related directly to SIP dialog status in
174
+     * appropriate call legs - for example the B2B call status can be
175
+     * "Connected" though the legs have received BYE replies. */
171 176
     enum CallStatus {
172 177
       Disconnected, //< there is no other call leg we are connected to
173 178
       NoReply,      //< there is at least one call leg we are connected to but without any response
174 179
       Ringing,      //< this leg or one of legs we are connected to rings
175
-      Connected     //< there is exactly one call leg we are connected to, in this case AmB2BSession::other_id holds the other leg id
176
-      //Disconnecting //< we were connected and now going to be disconnected (waiting for reINVITE reply for example)
180
+      Connected,    //< there is exactly one call leg we are connected to, in this case AmB2BSession::other_id holds the other leg id
181
+      Disconnecting //< we were connected and now going to be disconnected (waiting for reINVITE reply for example)
177 182
     };
178 183
 
179 184
   private:
... ...
@@ -215,7 +220,6 @@ class CallLeg: public AmB2BSession
215 220
     void onB2BReconnect(ReconnectLegEvent *e);
216 221
     void onB2BReplace(ReplaceLegEvent *e);
217 222
     void onB2BReplaceInProgress(ReplaceInProgressEvent *e);
218
-    void onB2BDisconnect(DisconnectLegEvent* ev);
219 223
 
220 224
     int relaySipReply(AmSipReply &reply);
221 225
 
... ...
@@ -223,15 +227,9 @@ class CallLeg: public AmB2BSession
223 227
      * directly by successors, right?) */
224 228
     void terminateNotConnectedLegs();
225 229
 
226
-    /** terminate given leg and remove it from list of other legs  (should not
227
-     * be used directly by successors, right?) */
228
-    void terminateOtherLeg(const string &id);
229
-
230 230
     /** remove given leg from the list of other legs */
231 231
     void removeOtherLeg(const string &id);
232 232
 
233
-    void terminateCall();
234
-
235 233
     void updateCallStatus(CallStatus new_status);
236 234
 
237 235
     //////////////////////////////////////////////////////////////////////
... ...
@@ -241,10 +239,12 @@ class CallLeg: public AmB2BSession
241 239
     /* handler called when call status changes */
242 240
     virtual void onCallStatusChange() { }
243 241
 
244
-    /** handler called when the second leg is connected */
242
+    /** handler called when the second leg is connected (FIXME: this is a hack,
243
+     * use this method in SBCCallLeg only) */
245 244
     virtual void onCallConnected(const AmSipReply& reply) { }
246 245
 
247
-    /** handler called when call is stopped */
246
+    /** handler called when call is stopped (FIXME: this is a hack, use this
247
+     * method in SBCCallLeg only)  */
248 248
     virtual void onCallStopped() { }
249 249
 
250 250
     /** Method called if given B leg couldn't establish the call (refused with
... ...
@@ -258,6 +258,12 @@ class CallLeg: public AmB2BSession
258 258
 
259 259
     void addExistingCallee(const string &session_tag, ReconnectLegEvent *e);
260 260
 
261
+    /** Clears other leg, eventually removes it from the list of other legs if
262
+     * it is there. It neither updates call state nor sip_relay_only flag! */
263
+    virtual void clear_other();
264
+    virtual void terminateLeg();
265
+    virtual void terminateOtherLeg();
266
+
261 267
   protected:
262 268
 
263 269
     // functions offered to successors
... ...
@@ -284,14 +290,6 @@ class CallLeg: public AmB2BSession
284 290
 
285 291
     CallStatus getCallStatus() { return call_status; }
286 292
 
287
-    virtual void clear_other();
288
-
289
-  public:
290
-    // @see AmB2BSession
291
-    virtual void terminateLeg();
292
-    virtual void terminateOtherLeg();
293
-    virtual void onB2BEvent(B2BEvent* ev);
294
-
295 293
     // @see AmSession
296 294
     virtual void onInvite(const AmSipRequest& req);
297 295
     virtual void onInvite2xx(const AmSipReply& reply);
... ...
@@ -302,7 +300,20 @@ class CallLeg: public AmB2BSession
302 300
     virtual void onSipRequest(const AmSipRequest& req);
303 301
     virtual void onSipReply(const AmSipReply& reply, AmSipDialog::Status old_dlg_status);
304 302
 
305
-    //int reinviteCaller(const AmSipReply& callee_reply);
303
+  public:
304
+    virtual void onB2BEvent(B2BEvent* ev);
305
+
306
+    /** does all the job around disconnecting from the other leg (updates call
307
+     * status, disconnects RTP from the other, puts remote on hold (if
308
+     * requested)
309
+     *
310
+     * The other leg is not affected by disconnect - it is neither terminated
311
+     * nor informed about the peer disconnection. */
312
+    virtual void disconnect(bool hold_remote);
313
+
314
+    /** Terminate the whole B2B call (if there is no other leg only this one is
315
+     * stopped). */
316
+    virtual void stopCall();
306 317
 
307 318
   public:
308 319
     /** creates A leg */
... ...
@@ -310,7 +321,6 @@ class CallLeg: public AmB2BSession
310 321
 
311 322
     /** creates B leg using given session as A leg */
312 323
     CallLeg(const CallLeg* caller);
313
-
314 324
 };
315 325
 
316 326
 
... ...
@@ -38,8 +38,6 @@ class ExtendedCCInterface
38 38
 
39 39
     virtual void onStateChange(SBCCallLeg *call) { };
40 40
 
41
-    virtual void onTerminateLeg(SBCCallLeg *call) { }
42
-
43 41
     /** called when the call leg is being destroyed, useful to cleanup used resources */
44 42
     virtual void onDestroyLeg(SBCCallLeg *call) { }
45 43
 
... ...
@@ -359,7 +359,10 @@ SBCCallLeg::~SBCCallLeg()
359 359
 {
360 360
   if (auth)
361 361
     delete auth;
362
+}
362 363
 
364
+void SBCCallLeg::onBeforeDestroy()
365
+{
363 366
   for (vector<ExtendedCCInterface*>::iterator i = cc_ext.begin(); i != cc_ext.end(); ++i) {
364 367
     (*i)->onDestroyLeg(this);
365 368
   }
... ...
@@ -914,12 +917,6 @@ void SBCCallLeg::onSystemEvent(AmSystemEvent* ev) {
914 917
   CallLeg::onSystemEvent(ev);
915 918
 }
916 919
 
917
-void SBCCallLeg::stopCall() {
918
-  terminateOtherLeg();
919
-  terminateLeg();
920
-  onCallStopped();
921
-}
922
-
923 920
 void SBCCallLeg::saveCallTimer(int timer, double timeout) {
924 921
   call_timers[timer] = timeout;
925 922
 }
... ...
@@ -1386,15 +1383,6 @@ void SBCCallLeg::savePayloadIDs(AmSdp &sdp)
1386 1383
   }
1387 1384
 }
1388 1385
 
1389
-void SBCCallLeg::terminateLeg()
1390
-{
1391
-  CallLeg::terminateLeg();
1392
-
1393
-  for (vector<ExtendedCCInterface*>::iterator i = cc_ext.begin(); i != cc_ext.end(); ++i) {
1394
-    (*i)->onTerminateLeg(this);
1395
-  }
1396
-}
1397
-
1398 1386
 bool SBCCallLeg::reinvite(const AmSdp &sdp, unsigned &request_cseq)
1399 1387
 {
1400 1388
   request_cseq = 0;
... ...
@@ -115,6 +115,7 @@ class SBCCallLeg : public CallLeg, public CredentialHolder
115 115
   void onSystemEvent(AmSystemEvent* ev);
116 116
 
117 117
   virtual void onStart();
118
+  virtual void onBeforeDestroy();
118 119
 
119 120
   UACAuthCred* getCredentials();
120 121
 
... ...
@@ -143,7 +144,6 @@ class SBCCallLeg : public CallLeg, public CredentialHolder
143 144
   SBCCallProfile &getCallProfile() { return call_profile; }
144 145
   CallStatus getCallStatus() { return CallLeg::getCallStatus(); }
145 146
   const string &getOtherId() { return other_id; }
146
-  void clearOther() { clear_other(); }
147 147
 
148 148
   // media interface must be accessible from CC modules
149 149
   AmB2BMedia *getMediaSession() { return media_session; }
... ...
@@ -153,9 +153,6 @@ class SBCCallLeg : public CallLeg, public CredentialHolder
153 153
 
154 154
   bool reinvite(const AmSdp &sdp, unsigned &request_cseq);
155 155
 
156
-  virtual void terminateLeg();
157
-  void stopCall(); /** stop call (both legs, CC) */
158
-
159 156
   int relayEvent(AmEvent* ev);
160 157
   void onSipRequest(const AmSipRequest& req);
161 158
   bool isALeg() { return a_leg; }