Browse code

Merge remote-tracking branch 'frafos/b2b_use_oa' into 1.6-dev-ccdsm

* frafos/b2b_use_oa: (24 commits)
b2b calls q/f: handle OA locally only if the local RTP stream is initialized
b2b calls: use dialog's OA to update media streams
b2b media q/f: do correct mute detection from SDP
OA: store local sdp sent in reply
OA: ignore repeated SDP in sent 2xx replies to INVITE
core: AmRtpStream: do not report unknown codecs as error
b2b media: code cleanup
OA: ignore repeated SDP in sent 1xx replies to INVITE
b2b media: re-initialize streams on every SDP change
sbc b/f: use dialog for offer-answer detection
SIP dialog: allow access to oa's SDPs
sbc: do not change OA mode in SBCCallLeg
b2b media q/f: SDP changes need to be handled independently for each call leg
sbc b/f: debug info fixed
b2b media: debug OA exchange
sbc: debug OA exchange
sbc: added method for call leg debugging
b2b media: debugging improved a bit
core: AmRtpStream: added method for debugging
b2b media q/f: do not mix input with relayed data
...

Stefan Sayer authored on 03/12/2013 12:49:44
Showing 13 changed files
... ...
@@ -188,12 +188,17 @@ static bool isHoldRequest(AmSdp &sdp, HoldMethod &method)
188 188
 CallLeg::CallLeg(const CallLeg* caller, AmSipDialog* p_dlg, AmSipSubscription* p_subs)
189 189
   : AmB2BSession(caller->getLocalTag(),p_dlg,p_subs),
190 190
     call_status(Disconnected),
191
-    on_hold(false)
191
+    on_hold(false),
192
+    hold(PreserveHoldStatus)
192 193
 {
193 194
   a_leg = !caller->a_leg; // we have to be the complement
194 195
 
195 196
   set_sip_relay_only(false); // will be changed later on (for now we have no peer so we can't relay)
196 197
 
198
+  // enable OA for the purpose of hold request detection
199
+  if (dlg) dlg->setOAEnabled(true);
200
+  else WARN("can't enable OA!\n");
201
+
197 202
   // code below taken from createCalleeSession
198 203
 
199 204
   const AmSipDialog* caller_dlg = caller->dlg;
... ...
@@ -231,7 +236,8 @@ CallLeg::CallLeg(const CallLeg* caller, AmSipDialog* p_dlg, AmSipSubscription* p
231 236
 CallLeg::CallLeg(AmSipDialog* p_dlg, AmSipSubscription* p_subs)
232 237
   : AmB2BSession("",p_dlg,p_subs),
233 238
     call_status(Disconnected),
234
-    on_hold(false)
239
+    on_hold(false),
240
+    hold(PreserveHoldStatus)
235 241
 {
236 242
   a_leg = true;
237 243
 
... ...
@@ -241,6 +247,10 @@ CallLeg::CallLeg(AmSipDialog* p_dlg, AmSipSubscription* p_subs)
241 247
   // It is possible to start relaying before call is established if we have
242 248
   // exactly one B leg (i.e. no parallel fork happened).
243 249
   set_sip_relay_only(false);
250
+
251
+  // enable OA for the purpose of hold request detection
252
+  if (dlg) dlg->setOAEnabled(true);
253
+  else WARN("can't enable OA!\n");
244 254
 }
245 255
     
246 256
 CallLeg::~CallLeg()
... ...
@@ -400,7 +410,7 @@ int CallLeg::relaySipReply(AmSipReply &reply)
400 410
   return res;
401 411
 }
402 412
 
403
-bool CallLeg::setOther(const string &id, bool use_initial_sdp)
413
+bool CallLeg::setOther(const string &id, bool forward)
404 414
 {
405 415
   if (getOtherId() == id) return true; // already set (needed when processing 2xx after 1xx)
406 416
   for (vector<OtherLegInfo>::iterator i = other_legs.begin(); i != other_legs.end(); ++i) {
... ...
@@ -408,6 +418,11 @@ bool CallLeg::setOther(const string &id, bool use_initial_sdp)
408 418
       setOtherId(id);
409 419
       clearRtpReceiverRelay(); // release old media session if set
410 420
       setMediaSession(i->media_session);
421
+      if (forward && dlg->getOAState() == AmOfferAnswer::OA_Completed) {
422
+        // reset OA state to offer_recived if already completed to accept new
423
+        // B leg's SDP
424
+        dlg->setOAState(AmOfferAnswer::OA_OfferRecved);
425
+      }
411 426
       if (i->media_session) {
412 427
         TRACE("connecting media session: %s to %s\n", 
413 428
             dlg->getLocalTag().c_str(), getOtherId().c_str());
... ...
@@ -417,7 +432,6 @@ bool CallLeg::setOther(const string &id, bool use_initial_sdp)
417 432
         // media session not set, set direct mode if not set already
418 433
         if (rtp_relay_mode != AmB2BSession::RTP_Direct) setRtpRelayMode(AmB2BSession::RTP_Direct);
419 434
       }
420
-      if (use_initial_sdp) updateRemoteSdp(initial_sdp);
421 435
       set_sip_relay_only(true); // relay only from now on
422 436
       return true;
423 437
     }
... ...
@@ -439,7 +453,7 @@ void CallLeg::b2bInitial1xx(AmSipReply& reply, bool forward)
439 453
     DBG("1xx reply with to-tag received in NoReply state,"
440 454
         " changing status to Ringing and remembering the"
441 455
         " other leg ID (%s)\n", getOtherId().c_str());
442
-    if (setOther(reply.from_tag, initial_sdp_stored && forward)) {
456
+    if (setOther(reply.from_tag, forward)) {
443 457
       updateCallStatus(Ringing, &reply);
444 458
       if (forward && relaySipReply(reply) != 0) stopCall(StatusChangeCause::InternalError);
445 459
     }
... ...
@@ -460,7 +474,7 @@ void CallLeg::b2bInitial1xx(AmSipReply& reply, bool forward)
460 474
 
461 475
 void CallLeg::b2bInitial2xx(AmSipReply& reply, bool forward)
462 476
 {
463
-  if (!setOther(reply.from_tag, initial_sdp_stored && forward)) {
477
+  if (!setOther(reply.from_tag, forward)) {
464 478
     // ignore reply which comes from non-our-peer leg?
465 479
     DBG("2xx reply received from unknown B leg, ignoring\n");
466 480
     return;
... ...
@@ -790,7 +804,7 @@ void CallLeg::putOnHold()
790 804
   if (on_hold) return;
791 805
 
792 806
   TRACE("putting remote on hold\n");
793
-  oa.hold = OA::HoldRequested;
807
+  hold = HoldRequested;
794 808
 
795 809
   holdRequested();
796 810
 
... ...
@@ -817,7 +831,7 @@ void CallLeg::resumeHeld(/*bool send_reinvite*/)
817 831
 
818 832
   try {
819 833
     TRACE("resume held remote\n");
820
-    oa.hold = OA::ResumeRequested;
834
+    hold = ResumeRequested;
821 835
 
822 836
     resumeRequested();
823 837
 
... ...
@@ -869,6 +883,7 @@ void CallLeg::resumeAccepted()
869 883
   on_hold = false;
870 884
   AmB2BMedia *ms = getMediaSession();
871 885
   if (ms) ms->unmute(!a_leg); // unmute the stream in other (!) leg
886
+  DBG("%s: resuming held, unmuting media session %p(%s)\n", getLocalTag().c_str(), ms, !a_leg ? "A" : "B");
872 887
 }
873 888
 
874 889
 // was for caller only
... ...
@@ -886,14 +901,6 @@ void CallLeg::onInvite(const AmSipRequest& req)
886 901
     // relayed INVITE - we need to add the original INVITE to
887 902
     // list of received (relayed) requests
888 903
     recvd_req.insert(std::make_pair(req.cseq, req));
889
-
890
-    initial_sdp_stored = false;
891
-    const AmMimeBody* sdp_body = req.body.hasContentType(SIP_APPLICATION_SDP);
892
-    DBG("SDP %sfound in initial INVITE\n", sdp_body ? "": "not ");
893
-    if (sdp_body && (initial_sdp.parse((const char *)sdp_body->getPayload()) == 0)) {
894
-      DBG("storing remote SDP for later\n");
895
-      initial_sdp_stored = true;
896
-    }
897 904
   }
898 905
 }
899 906
 
... ...
@@ -1353,22 +1360,24 @@ void CallLeg::changeRtpMode(RTPRelayMode new_mode)
1353 1360
       break;
1354 1361
   }
1355 1362
 
1356
-  switch (oa.status) {
1357
-    case OA::None:
1363
+  switch (dlg->getOAState()) {
1364
+    case AmOfferAnswer::OA_Completed:
1365
+    case AmOfferAnswer::OA_None:
1358 1366
       // must be followed by OA exchange because we can't updateLocalSdp
1359 1367
       // (reINVITE would be needed)
1360 1368
       break;
1361 1369
 
1362
-    case OA::OfferSent:
1370
+    case AmOfferAnswer::OA_OfferSent:
1363 1371
       TRACE("changing RTP mode after offer was sent: reINVITE needed\n");
1364 1372
       // TODO: plan a reINVITE
1365 1373
       ERROR("not implemented\n");
1366 1374
       break;
1367 1375
 
1368
-    case OA::OfferReceived:
1369
-      TRACE("changing RTP mode after offer was received, needed to updateRemoteSdp again\n");
1370
-      AmB2BSession::updateRemoteSdp(oa.remote_sdp); // hack
1376
+    case AmOfferAnswer::OA_OfferRecved:
1377
+      TRACE("changing RTP mode after offer was received\n");
1371 1378
       break;
1379
+
1380
+    case AmOfferAnswer::__max_OA: break; // grrrr
1372 1381
   }
1373 1382
 }
1374 1383
 
... ...
@@ -1407,22 +1416,24 @@ void CallLeg::changeRtpMode(RTPRelayMode new_mode, AmB2BMedia *new_media)
1407 1416
   AmB2BMedia *m = getMediaSession();
1408 1417
   if (m) m->changeSession(a_leg, this);
1409 1418
 
1410
-  switch (oa.status) {
1411
-    case OA::None:
1419
+  switch (dlg->getOAState()) {
1420
+    case AmOfferAnswer::OA_Completed:
1421
+    case AmOfferAnswer::OA_None:
1412 1422
       // must be followed by OA exchange because we can't updateLocalSdp
1413 1423
       // (reINVITE would be needed)
1414 1424
       break;
1415 1425
 
1416
-    case OA::OfferSent:
1426
+    case AmOfferAnswer::OA_OfferSent:
1417 1427
       TRACE("changing RTP mode/media session after offer was sent: reINVITE needed\n");
1418 1428
       // TODO: plan a reINVITE
1419 1429
       ERROR("%s: not implemented\n", getLocalTag().c_str());
1420 1430
       break;
1421 1431
 
1422
-    case OA::OfferReceived:
1423
-      TRACE("changing RTP mode/media session after offer was received, needed to updateRemoteSdp again\n");
1424
-      AmB2BSession::updateRemoteSdp(oa.remote_sdp); // hack
1432
+    case AmOfferAnswer::OA_OfferRecved:
1433
+      TRACE("changing RTP mode/media session after offer was received\n");
1425 1434
       break;
1435
+
1436
+    case AmOfferAnswer::__max_OA: break; // grrrr
1426 1437
   }
1427 1438
 
1428 1439
 }
... ...
@@ -1534,7 +1545,8 @@ void CallLeg::reinvite(const string &hdrs, const AmMimeBody &body, bool relayed,
1534 1545
 
1535 1546
 void CallLeg::adjustOffer(AmSdp &sdp)
1536 1547
 {
1537
-  if (oa.hold != OA::PreserveHoldStatus) {
1548
+  if (hold != PreserveHoldStatus) {
1549
+    DBG("local hold/unhold request");
1538 1550
     // locally generated hold/unhold requests that already contain correct
1539 1551
     // hold/resume bodies and need not to be altered via createHoldRequest
1540 1552
     // hold/resumeRequested is already called
... ...
@@ -1546,15 +1558,17 @@ void CallLeg::adjustOffer(AmSdp &sdp)
1546 1558
     // if hold request, transform to requested kind of hold and remember that hold
1547 1559
     // was requested with this offer
1548 1560
     if (isHoldRequest(sdp, hm)) {
1561
+      DBG("B2b hold request");
1549 1562
       holdRequested();
1550 1563
       alterHoldRequest(sdp);
1551
-      oa.hold = OA::HoldRequested;
1564
+      hold = HoldRequested;
1552 1565
     }
1553 1566
     else {
1554 1567
       if (on_hold) {
1568
+        DBG("B2b resume request");
1555 1569
         resumeRequested();
1556 1570
         alterResumeRequest(sdp);
1557
-        oa.hold = OA::ResumeRequested;
1571
+        hold = ResumeRequested;
1558 1572
       }
1559 1573
     }
1560 1574
   }
... ...
@@ -1562,29 +1576,20 @@ void CallLeg::adjustOffer(AmSdp &sdp)
1562 1576
 
1563 1577
 void CallLeg::updateLocalSdp(AmSdp &sdp)
1564 1578
 {
1565
-  TRACE("%s: updateLocalSdp\n", getLocalTag().c_str());
1579
+  TRACE("%s: updateLocalSdp (OA: %d)\n", getLocalTag().c_str(), dlg->getOAState());
1566 1580
   // handle the body based on current offer-answer status
1567 1581
   // (possibly update the body before sending to remote)
1568 1582
 
1569
-  switch (oa.status) {
1570
-    case OA::None:
1571
-      adjustOffer(sdp);
1572
-      oa.status = OA::OfferSent;
1573
-      //FIXME: oa.offer_cseq = dlg->cseq;
1574
-      break;
1575
-
1576
-    case OA::OfferSent:
1577
-      ERROR("BUG: another SDP offer to be sent before answer/reject");
1578
-      oa.clear(); // or call offerRejected?
1579
-      break;
1580
-
1581
-    case OA::OfferReceived:
1582
-      // sending the answer
1583
-      oaCompleted();
1584
-      break;
1583
+  // FIXME: repeated SDP (183, 200) will cause false match in OA_Completed
1584
+  // (need not to be expected with re-INVITEs asking for hold)
1585
+  if (dlg->getOAState() == AmOfferAnswer::OA_None ||
1586
+      dlg->getOAState() == AmOfferAnswer::OA_Completed)
1587
+  {
1588
+    // handling offer
1589
+    adjustOffer(sdp);
1585 1590
   }
1586 1591
 
1587
-  if (oa.hold == OA::PreserveHoldStatus && !on_hold) {
1592
+  if (hold == PreserveHoldStatus && !on_hold) {
1588 1593
     // store non-hold SDP to be able to resumeHeld
1589 1594
     non_hold_sdp = sdp;
1590 1595
   }
... ...
@@ -1592,50 +1597,13 @@ void CallLeg::updateLocalSdp(AmSdp &sdp)
1592 1597
   AmB2BSession::updateLocalSdp(sdp);
1593 1598
 }
1594 1599
 
1595
-void CallLeg::updateRemoteSdp(AmSdp &sdp)
1596
-{
1597
-  TRACE("%s: updateRemoteSdp\n", getLocalTag().c_str());
1598
-  switch (oa.status) {
1599
-    case OA::None:
1600
-      oa.status = OA::OfferReceived;
1601
-      oa.remote_sdp = sdp;
1602
-      break;
1603
-
1604
-    case OA::OfferSent:
1605
-      oaCompleted();
1606
-      break;
1607
-
1608
-    case OA::OfferReceived:
1609
-      ERROR("BUG: another SDP offer received before answer/reject");
1610
-      oa.clear(); // or call offerRejected?
1611
-      break;
1612
-  }
1613
-
1614
-  AmB2BSession::updateRemoteSdp(sdp);
1615
-}
1616
-
1617
-void CallLeg::oaCompleted()
1618
-{
1619
-  TRACE("%s: oaCompleted\n", getLocalTag().c_str());
1620
-  switch (oa.hold) {
1621
-    case OA::HoldRequested: holdAccepted(); break;
1622
-    case OA::ResumeRequested: resumeAccepted(); break;
1623
-    case OA::PreserveHoldStatus: break;
1624
-  }
1625
-
1626
-  // call a callback here?
1627
-  oa.clear();
1628
-}
1629
-
1630 1600
 void CallLeg::offerRejected()
1631 1601
 {
1632
-  switch (oa.hold) {
1633
-    case OA::HoldRequested: holdRejected(); break;
1634
-    case OA::ResumeRequested: resumeRejected(); break;
1635
-    case OA::PreserveHoldStatus: break;
1602
+  switch (hold) {
1603
+    case HoldRequested: holdRejected(); break;
1604
+    case ResumeRequested: resumeRejected(); break;
1605
+    case PreserveHoldStatus: break;
1636 1606
   }
1637
-
1638
-  oa.clear();
1639 1607
 }
1640 1608
 
1641 1609
 void CallLeg::createResumeRequest(AmSdp &sdp)
... ...
@@ -1655,3 +1623,28 @@ void CallLeg::createResumeRequest(AmSdp &sdp)
1655 1623
   // do not touch the sdp otherwise (use directly B2B SDP)
1656 1624
 }
1657 1625
 
1626
+void CallLeg::debug()
1627
+{
1628
+  DBG("call leg: %s", getLocalTag().c_str());
1629
+  DBG("\tother: %s\n", getOtherId().c_str());
1630
+  DBG("\tstatus: %s\n", callStatus2str(getCallStatus()));
1631
+  DBG("\tRTP relay mode: %d\n", rtp_relay_mode);
1632
+  DBG("\ton hold: %s\n", on_hold ? "yes" : "no");
1633
+  DBG("\toffer/answer status: %d, hold: %d\n", dlg->getOAState(), hold);
1634
+
1635
+  AmB2BMedia *ms = getMediaSession();
1636
+  if (ms) ms->debug();
1637
+}
1638
+
1639
+int CallLeg::onSdpCompleted(const AmSdp& offer, const AmSdp& answer)
1640
+{
1641
+  TRACE("%s: oaCompleted\n", getLocalTag().c_str());
1642
+  switch (hold) {
1643
+    case HoldRequested: holdAccepted(); break;
1644
+    case ResumeRequested: resumeAccepted(); break;
1645
+    case PreserveHoldStatus: break;
1646
+  }
1647
+
1648
+  hold = PreserveHoldStatus;
1649
+  return AmB2BSession::onSdpCompleted(offer, answer);
1650
+}
... ...
@@ -120,9 +120,6 @@ class CallLeg: public AmB2BSession
120 120
 
121 121
     CallStatus call_status; //< status of the call (replaces callee's status)
122 122
 
123
-    AmSdp initial_sdp;
124
-    bool initial_sdp_stored;
125
-
126 123
     /** information needed in A leg for a B leg */
127 124
     struct OtherLegInfo {
128 125
       /** local tag of the B leg */
... ...
@@ -152,20 +149,10 @@ class CallLeg: public AmB2BSession
152 149
 
153 150
     bool on_hold; // remote is on hold
154 151
     AmSdp non_hold_sdp;
152
+    enum { HoldRequested, ResumeRequested, PreserveHoldStatus } hold;
155 153
 
156 154
     std::queue<PendingReinvite> pending_reinvites;
157 155
 
158
-    // offer-answer related stuff
159
-    struct OA {
160
-      enum { None, OfferSent, OfferReceived } status;
161
-      enum { HoldRequested, ResumeRequested, PreserveHoldStatus } hold;
162
-      OA(): status(None), hold(PreserveHoldStatus) { }
163
-      void clear() { status = None; hold = PreserveHoldStatus; remote_sdp.clear(); }
164
-
165
-      /* SDP of remote end. Needed because of the possibility of RTP relay mode
166
-       * change during offer-answer exchange. */
167
-      AmSdp remote_sdp;
168
-    } oa;
169 156
 
170 157
     // generate re-INVITE with given parameters (establishing means that the
171 158
     // INVITE is establishing a connection between two legs)
... ...
@@ -241,7 +228,6 @@ class CallLeg: public AmB2BSession
241 228
 
242 229
     // offer-answer handling
243 230
     void adjustOffer(AmSdp &sdp);
244
-    void oaCompleted(); // offer-answer exchange completed, both SDPs are handled
245 231
 
246 232
      /* offer was rejected (called just for negative replies to an request
247 233
       * carying offer (not always correct?), answer with disabled streams
... ...
@@ -318,7 +304,6 @@ class CallLeg: public AmB2BSession
318 304
     void changeRtpMode(RTPRelayMode new_mode);
319 305
 
320 306
     virtual void updateLocalSdp(AmSdp &sdp);
321
-    virtual void updateRemoteSdp(AmSdp &sdp);
322 307
 
323 308
   public:
324 309
     virtual void onB2BEvent(B2BEvent* ev);
... ...
@@ -371,6 +356,9 @@ class CallLeg: public AmB2BSession
371 356
     void replaceExistingLeg(const string &session_tag, const AmSipRequest &relayed_invite);
372 357
     void replaceExistingLeg(const string &session_tag, const string &hdrs);
373 358
 
359
+    /** generate debug information into log with overall call leg status */
360
+    void debug();
361
+
374 362
     const char* getCallStatusStr();
375 363
 
376 364
     // AmMediaSession interface from AmMediaProcessor
... ...
@@ -386,6 +374,14 @@ class CallLeg: public AmB2BSession
386 374
 	    AmSipSubscription* p_subs=NULL);
387 375
 
388 376
     virtual ~CallLeg();
377
+
378
+    // OA callbacks
379
+    virtual int onSdpCompleted(const AmSdp& local, const AmSdp& remote);
380
+    virtual bool getSdpOffer(AmSdp& offer) { return false; }
381
+    virtual bool getSdpAnswer(const AmSdp& offer, AmSdp& answer) { return false; }
382
+    virtual void onEarlySessionStart() { }
383
+    virtual void onSessionStart() { }
384
+
389 385
 };
390 386
 
391 387
 
... ...
@@ -130,10 +130,6 @@ SBCCallLeg::SBCCallLeg(const SBCCallProfile& call_profile, AmSipDialog* p_dlg,
130 130
   set_sip_relay_only(false);
131 131
   dlg->setRel100State(Am100rel::REL100_IGNORED);
132 132
 
133
-  // better here than in onInvite
134
-  // or do we really want to start with OA when handling initial INVITE?
135
-  dlg->setOAEnabled(false);
136
-
137 133
   memset(&call_start_ts, 0, sizeof(struct timeval));
138 134
   memset(&call_connect_ts, 0, sizeof(struct timeval));
139 135
   memset(&call_end_ts, 0, sizeof(struct timeval));
... ...
@@ -165,7 +161,6 @@ SBCCallLeg::SBCCallLeg(SBCCallLeg* caller, AmSipDialog* p_dlg,
165 161
   // call_profile.cc_vars.clear();
166 162
 
167 163
   dlg->setRel100State(Am100rel::REL100_IGNORED);
168
-  dlg->setOAEnabled(false);
169 164
 
170 165
   // we need to apply it here instead of in applyBProfile because we have caller
171 166
   // here (FIXME: do it on better place and better way than accessing internals
... ...
@@ -651,11 +646,6 @@ void SBCCallLeg::updateLocalSdp(AmSdp &sdp)
651 646
   CallLeg::updateLocalSdp(sdp);
652 647
 }
653 648
 
654
-void SBCCallLeg::updateRemoteSdp(AmSdp &sdp)
655
-{
656
-  CallLeg::updateRemoteSdp(sdp);
657
-}
658
-
659 649
 void SBCCallLeg::onControlCmd(string& cmd, AmArg& params) {
660 650
   if (cmd == "teardown") {
661 651
     if (a_leg) {
... ...
@@ -187,7 +187,6 @@ class SBCCallLeg : public CallLeg, public CredentialHolder
187 187
   // media interface must be accessible from CC modules
188 188
   AmB2BMedia *getMediaSession() { return AmB2BSession::getMediaSession(); }
189 189
   virtual void updateLocalSdp(AmSdp &sdp);
190
-  virtual void updateRemoteSdp(AmSdp &sdp);
191 190
   void changeRtpMode(RTPRelayMode new_mode) { CallLeg::changeRtpMode(new_mode); }
192 191
 
193 192
   bool reinvite(const AmSdp &sdp, unsigned &request_cseq);
... ...
@@ -246,16 +246,7 @@ void AudioStreamData::resumeStreamProcessing()
246 246
 
247 247
 void AudioStreamData::setRelayStream(AmRtpStream *other)
248 248
 {
249
-  if (!stream) {
250
-    ERROR("BUG: trying to set relay for NULL stream\n");
251
-    return;
252
-  }
253
-
254
-  // FIXME: muted stream should not relay to the other?
255
-  /* if (muted) {
256
-    stream->disableRtpRelay();
257
-    return;
258
-  }*/
249
+  if (!stream) return;
259 250
 
260 251
   if (relay_address.empty()) {
261 252
     DBG("not setting relay for empty relay address\n");
... ...
@@ -316,6 +307,7 @@ void AudioStreamData::clearDtmfSink()
316 307
 
317 308
 void AudioStreamData::setDtmfSink(AmDtmfSink *dtmf_sink)
318 309
 {
310
+  // TODO: optimize: clear & create the dtmf_detector only if the dtmf_sink changed
319 311
   clearDtmfSink();
320 312
 
321 313
   if (dtmf_sink && stream) {
... ...
@@ -345,17 +337,14 @@ bool AudioStreamData::initStream(PlayoutType playout_type,
345 337
   resetStats();
346 338
 
347 339
   if (!stream) {
348
-    // we have no stream so normal audio processing is not possible
349
-    // FIXME: if we have no stream here (i.e. no session) how we got the local
350
-    // and remote SDP?
351
-    ERROR("BUG: trying to initialize stream before creation\n");
352 340
     initialized = false;
353
-    return false; // it is bug with current AmB2BMedia implementation
341
+    return false;
354 342
   }
355 343
 
356 344
   // TODO: try to init only in case there are some payloads which can't be relayed
357 345
   stream->forceSdpMediaIndex(media_idx);
358 346
 
347
+  stream->setOnHold(false); // just hack to do correctly mute detection in stream->init
359 348
   if (stream->init(local_sdp, remote_sdp, force_symmetric_rtp) == 0) {
360 349
     stream->setPlayoutType(playout_type);
361 350
     initialized = true;
... ...
@@ -502,7 +491,6 @@ AmB2BMedia::AmB2BMedia(AmB2BSession *_a, AmB2BSession *_b):
502 491
   callgroup(AmSession::getNewId()),
503 492
   have_a_leg_local_sdp(false), have_a_leg_remote_sdp(false),
504 493
   have_b_leg_local_sdp(false), have_b_leg_remote_sdp(false),
505
-  processing_started(false),
506 494
   playout_type(ADAPTIVE_PLAYOUT),
507 495
   //playout_type(SIMPLE_PLAYOUT),
508 496
   a_leg_muted(false), b_leg_muted(false),
... ...
@@ -560,10 +548,8 @@ void AmB2BMedia::changeSessionUnsafe(bool a_leg, AmB2BSession *new_session)
560 548
   // update all streams
561 549
   for (AudioStreamIterator i = audio.begin(); i != audio.end(); ++i) {
562 550
     // stop processing first to avoid unexpected results
563
-    if (processing_started) {
564
-      i->a.stopStreamProcessing();
565
-      i->b.stopStreamProcessing();
566
-    }
551
+    i->a.stopStreamProcessing();
552
+    i->b.stopStreamProcessing();
567 553
 
568 554
     // replace session
569 555
     if (a_leg) {
... ...
@@ -573,33 +559,7 @@ void AmB2BMedia::changeSessionUnsafe(bool a_leg, AmB2BSession *new_session)
573 559
       i->b.changeSession(new_session);
574 560
     }
575 561
 
576
-    if (processing_started) {
577
-      // needed to reinitialize relay streams because the streams could change
578
-      // and they are in use already (FIXME: ugly here, needs explicit knowledge
579
-      // what AudioStreamData::changeSesion does)
580
-      if (a) i->a.setRelayStream(i->b.getStream());
581
-      if (b) i->b.setRelayStream(i->a.getStream());
582
-
583
-      // needed to reinitialize audio processing in case the stream itself has
584
-      // changed (FIXME: ugly again - see above and local/remote SDP might
585
-      // already change since previous initialization!)
586
-      if (a_leg) {
587
-        if (a) { // we have the session
588
-          TRACE("init A stream stuff\n");
589
-          i->a.initStream(playout_type, a_leg_local_sdp, a_leg_remote_sdp, i->media_idx);
590
-          i->a.setDtmfSink(b);
591
-          i->b.setDtmfSink(new_session);
592
-        }
593
-      }
594
-      else {
595
-        if (b) { // we have the session
596
-          TRACE("init B stream stuff\n");
597
-          i->b.initStream(playout_type, b_leg_local_sdp, b_leg_remote_sdp, i->media_idx);
598
-          i->b.setDtmfSink(a);
599
-          i->a.setDtmfSink(new_session);
600
-        }
601
-      }
602
-    }
562
+    updateStreamPair(*i);
603 563
 
604 564
     if (i->requiresProcessing()) needs_processing = true;
605 565
 
... ...
@@ -607,28 +567,18 @@ void AmB2BMedia::changeSessionUnsafe(bool a_leg, AmB2BSession *new_session)
607 567
     i->setLogger(logger);
608 568
 
609 569
     // return back for processing if needed
610
-    if (processing_started) {
611
-      i->a.resumeStreamProcessing();
612
-      i->b.resumeStreamProcessing();
613
-    }
570
+    i->a.resumeStreamProcessing();
571
+    i->b.resumeStreamProcessing();
614 572
   }
615 573
 
616 574
   for (RelayStreamIterator j = relay_streams.begin(); j != relay_streams.end(); ++j) {
617 575
     AmRtpStream &a = (*j)->a;
618 576
     AmRtpStream &b = (*j)->a;
619 577
 
620
-    /*if (a.hasLocalSocket())
621
-      AmRtpReceiver::instance()->removeStream(a.getLocalSocket());
622
-    if (b.hasLocalSocket())
623
-      AmRtpReceiver::instance()->removeStream(b.getLocalSocket());*/
624
-
578
+    // FIXME: is stop & resume receiving needed here?
625 579
     a.changeSession(new_session);
626 580
     b.changeSession(new_session);
627 581
 
628
-    /*if (a.hasLocalSocket())
629
-      AmRtpReceiver::instance()->addStream(a.getLocalSocket(), &a);
630
-    if (b.hasLocalSocket())
631
-      AmRtpReceiver::instance()->addStream(b.getLocalSocket(), &b);*/
632 582
   }
633 583
 
634 584
   if (needs_processing) {
... ...
@@ -895,7 +845,27 @@ _rtp_relay_mode_str(const AmB2BSession::RTPRelayMode& relay_mode)
895 845
   return "";
896 846
 }
897 847
 
898
-void AmB2BMedia::onSdpUpdate()
848
+void AmB2BMedia::updateStreamPair(AudioStreamPair &pair)
849
+{
850
+  bool have_a = have_a_leg_local_sdp && have_a_leg_remote_sdp;
851
+  bool have_b = have_b_leg_local_sdp && have_b_leg_remote_sdp;
852
+
853
+  TRACE("updating stream in A leg\n");
854
+  pair.a.setDtmfSink(b);
855
+  if (pair.b.getInput()) pair.a.setRelayStream(NULL); // don't mix relayed RTP into the other's input
856
+  else pair.a.setRelayStream(pair.b.getStream());
857
+  if (have_a) pair.a.initStream(playout_type, a_leg_local_sdp, a_leg_remote_sdp, pair.media_idx);
858
+
859
+  TRACE("updating stream in B leg\n");
860
+  pair.b.setDtmfSink(a);
861
+  if (pair.a.getInput()) pair.b.setRelayStream(NULL); // don't mix relayed RTP into the other's input
862
+  else pair.b.setRelayStream(pair.a.getStream());
863
+  if (have_b) pair.b.initStream(playout_type, b_leg_local_sdp, b_leg_remote_sdp, pair.media_idx);
864
+
865
+  TRACE("audio streams updated\n");
866
+}
867
+
868
+void AmB2BMedia::updateAudioStreams()
899 869
 {
900 870
   // SDP was updated
901 871
   TRACE("handling SDP change, A leg: %c%c, B leg: %c%c\n",
... ...
@@ -912,22 +882,9 @@ void AmB2BMedia::onSdpUpdate()
912 882
   bool have_b = have_b_leg_local_sdp && have_b_leg_remote_sdp;
913 883
 
914 884
   if (!(
915
-      (have_a && have_b) ||
916
-      (have_a && !audio.empty() && audio[0].a.getInput() && (!b)) ||
917
-      (have_b && !audio.empty() && audio[0].b.getInput() && (!a))
885
+      (have_a || have_b)
918 886
       )) return;
919 887
 
920
-  // clear all the stored flags (re-INVITEs or UPDATEs will negotiate new remote
921
-  // & local SDPs so the current ones are not interesting later)
922
-  have_a_leg_local_sdp = false;
923
-  have_a_leg_remote_sdp = false;
924
-  have_b_leg_local_sdp = false;
925
-  have_b_leg_remote_sdp = false;
926
-
927
-  processing_started = true;
928
-
929
-  TRACE("starting media processing\n");
930
-
931 888
   bool needs_processing = a && b && a->getRtpRelayMode() == AmB2BSession::RTP_Transcoding;
932 889
 
933 890
   // initialize streams to be able to relay & transcode (or use local audio)
... ...
@@ -935,19 +892,7 @@ void AmB2BMedia::onSdpUpdate()
935 892
     i->a.stopStreamProcessing();
936 893
     i->b.stopStreamProcessing();
937 894
 
938
-    if (have_a) {
939
-      TRACE("initializing stream in A leg\n");
940
-      i->a.setDtmfSink(b);
941
-      i->a.setRelayStream(i->b.getStream());
942
-      i->a.initStream(playout_type, a_leg_local_sdp, a_leg_remote_sdp, i->media_idx);
943
-    }
944
-
945
-    if (have_b) {
946
-      TRACE("initializing stream in B leg\n");
947
-      i->b.setDtmfSink(a);
948
-      i->b.setRelayStream(i->a.getStream());
949
-      i->b.initStream(playout_type, b_leg_local_sdp, b_leg_remote_sdp, i->media_idx);
950
-    }
895
+    updateStreamPair(*i);
951 896
 
952 897
     if (i->requiresProcessing()) needs_processing = true;
953 898
 
... ...
@@ -997,22 +942,38 @@ void AmB2BMedia::updateRelayStream(AmRtpStream *stream, AmB2BSession *session,
997 942
   }
998 943
 }
999 944
 
1000
-void AmB2BMedia::updateRemoteSdp(bool a_leg, const AmSdp &remote_sdp, RelayController *ctrl)
945
+void AmB2BMedia::updateStreams(bool a_leg, const AmSdp &local_sdp, const AmSdp &remote_sdp, RelayController *ctrl)
1001 946
 {
947
+  TRACE("%s (%c): updating streams with local & remote SDP\n",
948
+      a_leg ? a->getLocalTag().c_str() : b->getLocalTag().c_str(),
949
+      a_leg ? 'A': 'B');
950
+
951
+  /*string s;
952
+  local_sdp.print(s);
953
+  INFO("local SDP: %s\n", s.c_str());
954
+  remote_sdp.print(s);
955
+  INFO("remote SDP: %s\n", s.c_str());*/
956
+
1002 957
   AmLock lock(mutex);
958
+  // streams should be created already (replaceConnectionAddress called
959
+  // before updateLocalSdp uses/assignes their port numbers)
1003 960
 
1004
-  // save SDP
961
+  // save SDP: FIXME: really needed to store instead of just to use?
1005 962
   if (a_leg) {
963
+    a_leg_local_sdp = local_sdp;
1006 964
     a_leg_remote_sdp = remote_sdp;
965
+    have_a_leg_local_sdp = true;
1007 966
     have_a_leg_remote_sdp = true;
1008 967
   }
1009 968
   else {
969
+    b_leg_local_sdp = local_sdp;
1010 970
     b_leg_remote_sdp = remote_sdp;
971
+    have_b_leg_local_sdp = true;
1011 972
     have_b_leg_remote_sdp = true;
1012 973
   }
1013 974
 
1014 975
   // create missing streams
1015
-  createStreams(remote_sdp);
976
+  createStreams(local_sdp); // FIXME: remote_sdp?
1016 977
 
1017 978
   // compute relay mask for every stream
1018 979
   // Warning: do not apply the new mask unless the offer answer succeeds?
... ...
@@ -1056,29 +1017,9 @@ void AmB2BMedia::updateRemoteSdp(bool a_leg, const AmSdp &remote_sdp, RelayContr
1056 1017
     }
1057 1018
   }
1058 1019
 
1059
-  onSdpUpdate();
1060
-}
1061
-    
1062
-void AmB2BMedia::updateLocalSdp(bool a_leg, const AmSdp &local_sdp)
1063
-{
1064
-  AmLock lock(mutex);
1065
-  // streams should be created already (replaceConnectionAddress called
1066
-  // before updateLocalSdp uses/assignes their port numbers)
1020
+  updateAudioStreams();
1067 1021
 
1068
-  // save SDP
1069
-  if (a_leg) {
1070
-    a_leg_local_sdp = local_sdp;
1071
-    have_a_leg_local_sdp = true;
1072
-  }
1073
-  else {
1074
-    b_leg_local_sdp = local_sdp;
1075
-    have_b_leg_local_sdp = true;
1076
-  }
1077
-
1078
-  // create missing streams
1079
-  createStreams(local_sdp);
1080
-
1081
-  onSdpUpdate();
1022
+  TRACE("streams updated with SDP\n");
1082 1023
 }
1083 1024
 
1084 1025
 void AmB2BMedia::stop(bool a_leg)
... ...
@@ -1087,7 +1028,6 @@ void AmB2BMedia::stop(bool a_leg)
1087 1028
   clearAudio(a_leg);
1088 1029
   // remove from processor only if both A and B leg stopped
1089 1030
   if (isProcessingMedia() && (!a) && (!b)) {
1090
-    processing_started = false;
1091 1031
     AmMediaProcessor::instance()->removeSession(this);
1092 1032
   }
1093 1033
 }
... ...
@@ -1095,7 +1035,6 @@ void AmB2BMedia::stop(bool a_leg)
1095 1035
 void AmB2BMedia::onMediaProcessingTerminated()
1096 1036
 {
1097 1037
   AmMediaSession::onMediaProcessingTerminated();
1098
-  processing_started = false;
1099 1038
 
1100 1039
   // release reference held by AmMediaProcessor
1101 1040
   releaseReference();
... ...
@@ -1156,13 +1095,13 @@ void AmB2BMedia::setFirstStreamInput(bool a_leg, AmAudio *in)
1156 1095
     AudioStreamIterator i = audio.begin();
1157 1096
     if (a_leg) i->a.setInput(in);
1158 1097
     else i->b.setInput(in);
1159
-    if (!processing_started) {
1160
-      // try to start it
1161
-      onSdpUpdate();
1098
+    updateAudioStreams();
1099
+  }
1100
+  else {
1101
+    if (in) {
1102
+      ERROR("BUG: can't set %s leg's first stream input, no streams\n", a_leg ? "A": "B");
1162 1103
     }
1163 1104
   }
1164
-  else ERROR("BUG: can't set %s leg's first stream input, no streams\n", a_leg ? "A": "B");
1165
-  // FIXME: start processing if not started and streams in this leg are fully initialized ?
1166 1105
 }
1167 1106
 
1168 1107
 void AmB2BMedia::createHoldAnswer(bool a_leg, const AmSdp &offer, AmSdp &answer, bool use_zero_con)
... ...
@@ -1304,14 +1243,9 @@ void AmB2BMedia::restartRelay() {
1304 1243
 
1305 1244
 void AudioStreamData::debug()
1306 1245
 {
1246
+  DBG("\tmuted: %s\n", muted ? "yes" : "no");
1307 1247
   if(stream) {
1308
-    if(stream->hasLocalSocket() > 0)
1309
-      DBG("\t<%i> <-> <%s:%i>", stream->getLocalPort(),
1310
-	  stream->getRHost().c_str(), stream->getRPort());
1311
-    else
1312
-      DBG("\t<unbound> <-> <%s:%i>",
1313
-	  stream->getRHost().c_str(),
1314
-	  stream->getLocalPort());
1248
+    stream->debug();
1315 1249
   }
1316 1250
   else
1317 1251
     DBG("\t<null> <-> <null>");
... ...
@@ -1321,34 +1255,29 @@ void AudioStreamData::debug()
1321 1255
 void AmB2BMedia::debug()
1322 1256
 {
1323 1257
   // walk through all the streams
1324
-  DBG("B2B media session ('%s' <-> '%s'):",
1325
-      a->getLocalTag().c_str(),
1326
-      b->getLocalTag().c_str());
1258
+  DBG("B2B media session %p ('%s' <-> '%s'):",
1259
+      this,
1260
+      a ? a->getLocalTag().c_str() : "?",
1261
+      b ? b->getLocalTag().c_str() : "?");
1262
+  DBG("\tOA status: %c%c / %c%c",
1263
+      have_a_leg_local_sdp ? 'X' : '-',
1264
+      have_a_leg_remote_sdp ? 'X' : '-',
1265
+      have_b_leg_local_sdp ? 'X' : '-',
1266
+      have_b_leg_remote_sdp ? 'X' : '-');
1327 1267
 
1328 1268
   for (AudioStreamIterator i = audio.begin(); i != audio.end(); ++i) {
1329
-    DBG("relay stream:\n");
1269
+    DBG(" - audio stream (A):\n");
1330 1270
     i->a.debug();
1271
+    DBG(" - audio stream (B):\n");
1331 1272
     i->b.debug();
1332 1273
   }
1333 1274
 
1334 1275
   for (RelayStreamIterator j = relay_streams.begin(); 
1335 1276
        j != relay_streams.end(); ++j) {
1336 1277
 
1337
-    DBG("relay stream:\n");
1338
-    if((*j)->a.hasLocalSocket() > 0)
1339
-      DBG("\t<%i> <-> <%s:%i>", (*j)->a.getLocalPort(),
1340
-	  (*j)->a.getRHost().c_str(), (*j)->a.getRPort());
1341
-    else
1342
-      DBG("\t<unbound> <-> <%s:%i>",
1343
-	  (*j)->a.getRHost().c_str(),
1344
-	  (*j)->a.getRPort());
1345
-
1346
-    if((*j)->b.hasLocalSocket() > 0)
1347
-      DBG("\t<%i> <-> <%s:%i>", (*j)->b.getLocalPort(),
1348
-	  (*j)->b.getRHost().c_str(), (*j)->b.getRPort());
1349
-    else
1350
-      DBG("\t<unbound> <-> <%s:%i>",
1351
-	  (*j)->b.getRHost().c_str(),
1352
-	  (*j)->b.getRPort());
1278
+    DBG(" - relay stream (A):\n");
1279
+    (*j)->a.debug();
1280
+    DBG(" - relay stream (B):\n");
1281
+    (*j)->b.debug();
1353 1282
   }
1354 1283
 }
... ...
@@ -322,11 +322,6 @@ class AmB2BMedia: public AmMediaSession
322 322
     bool have_a_leg_local_sdp, have_a_leg_remote_sdp;
323 323
     bool have_b_leg_local_sdp, have_b_leg_remote_sdp;
324 324
 
325
-    /** RTP streams were activated (i.e. are processed by AmRtpReceiver)
326
-     * Note that they need NOT to be processed by MediaProcessor
327
-     * (isProcessingMedia). */
328
-    bool processing_started;
329
-
330 325
     AmMutex mutex;
331 326
     int ref_cnt;
332 327
 
... ...
@@ -348,7 +343,8 @@ class AmB2BMedia: public AmMediaSession
348 343
     bool relay_paused;
349 344
 
350 345
     void createStreams(const AmSdp &sdp);
351
-    void onSdpUpdate();
346
+    void updateStreamPair(AudioStreamPair &pair);
347
+    void updateAudioStreams();
352 348
     void updateRelayStream(AmRtpStream *stream, AmB2BSession *session,
353 349
 			   const string& connection_address,
354 350
 			   const SdpMedia &m, AmRtpStream *relay_to);
... ...
@@ -415,11 +411,8 @@ class AmB2BMedia: public AmMediaSession
415 411
      * etc must be initialised like in case replaceConnectionAddress) */
416 412
     bool replaceOffer(AmSdp &sdp, bool a_leg);
417 413
 
418
-    /** Store remote SDP for given leg and update media session appropriately. */
419
-    void updateRemoteSdp(bool a_leg, const AmSdp &remote_sdp, RelayController *ctrl);
420
-    
421
-    /** Store local SDP for given leg and update media session appropriately. */
422
-    void updateLocalSdp(bool a_leg, const AmSdp &local_sdp);
414
+    /** Update media session with local & remote SDP. */
415
+    void updateStreams(bool a_leg, const AmSdp &local_sdp, const AmSdp &remote_sdp, RelayController *ctrl);
423 416
 
424 417
     /** Clear audio for given leg and stop processing if both legs stopped. 
425 418
      *
... ...
@@ -373,11 +373,6 @@ void AmB2BSession::onSipRequest(const AmSipRequest& req)
373 373
     return;
374 374
   }
375 375
 
376
-  AmSdp sdp;
377
-  // We have to update media session before filtering because we may want to
378
-  // use the codec later filtered out for transcoding.
379
-  if (parseSdp(sdp, req)) updateRemoteSdp(sdp);
380
-
381 376
   if(!fwd)
382 377
     AmSession::onSipRequest(req);
383 378
   else {
... ...
@@ -446,18 +441,6 @@ void AmB2BSession::onRequestSent(const AmSipRequest& req)
446 441
   AmSession::onRequestSent(req);
447 442
 }
448 443
 
449
-void AmB2BSession::updateRemoteSdp(AmSdp &sdp)
450
-{
451
-  if (rtp_relay_mode == RTP_Direct) return; // nothing to do
452
-
453
-  if (!media_session) {
454
-    // report missing media session (here we get for rtp_relay_mode == RTP_Relay)
455
-    ERROR("BUG: media session is missing, can't update remote SDP\n");
456
-    return; // FIXME: throw an exception here?
457
-  }
458
-  media_session->updateRemoteSdp(a_leg, sdp, this);
459
-}
460
-
461 444
 void AmB2BSession::updateLocalSdp(AmSdp &sdp)
462 445
 {
463 446
   if (rtp_relay_mode == RTP_Direct) return; // nothing to do
... ...
@@ -469,12 +452,6 @@ void AmB2BSession::updateLocalSdp(AmSdp &sdp)
469 452
   }
470 453
 
471 454
   media_session->replaceConnectionAddress(sdp, a_leg, localMediaIP(), advertisedIP());
472
-
473
-  // We are handling relayed request or reply.  The SDP in request/reply being
474
-  // relayed describes local side of current leg (doesn't matter if it was offer
475
-  // or answer) of the RTP stream. We need to update media session with it.
476
-
477
-  media_session->updateLocalSdp(a_leg, sdp);
478 455
 }
479 456
 
480 457
 void AmB2BSession::updateLocalBody(AmMimeBody& body)
... ...
@@ -538,14 +515,6 @@ void AmB2BSession::onSipReply(const AmSipRequest& req, const AmSipReply& reply,
538 515
     return;
539 516
   }
540 517
 
541
-  if (reply.code >= 180  && reply.code < 300)
542
-  {
543
-    AmSdp sdp;
544
-    // We have to update media session before filtering because we may want to
545
-    // use the codec later filtered out for transcoding.
546
-    if (parseSdp(sdp, reply)) updateRemoteSdp(sdp);
547
-  }
548
-
549 518
   if(fwd) {
550 519
     updateRefreshMethod(reply.hdrs);
551 520
 
... ...
@@ -628,11 +597,23 @@ void AmB2BSession::onInvite2xx(const AmSipReply& reply)
628 597
 
629 598
 int AmB2BSession::onSdpCompleted(const AmSdp& local_sdp, const AmSdp& remote_sdp)
630 599
 {
631
-  if(!sip_relay_only){
632
-    return AmSession::onSdpCompleted(local_sdp,remote_sdp);
600
+  if (rtp_relay_mode != RTP_Direct) {
601
+    if (!media_session) {
602
+      // report missing media session (here we get for rtp_relay_mode == RTP_Relay)
603
+      ERROR("BUG: media session is missing, can't update SDP\n");
604
+    }
605
+    else {
606
+      media_session->updateStreams(a_leg, local_sdp, remote_sdp, this);
607
+    }
633 608
   }
634
-  
635
-  DBG("sip_relay_only = true: doing nothing!\n");
609
+
610
+  if(hasRtpStream() && RTPStream()->getSdpMediaIndex() >= 0) {
611
+    if(!sip_relay_only){
612
+      return AmSession::onSdpCompleted(local_sdp,remote_sdp);
613
+    }
614
+    DBG("sip_relay_only = true: doing nothing!\n");
615
+  }
616
+
636 617
   return 0;
637 618
 }
638 619
 
... ...
@@ -1315,12 +1296,6 @@ void AmB2BCallerSession::initializeRTPRelay(AmB2BCalleeSession* callee_session)
1315 1296
     setMediaSession(new AmB2BMedia(this, callee_session)); // we need to add our reference
1316 1297
     callee_session->setMediaSession(getMediaSession());
1317 1298
   }
1318
-
1319
-  // Misusing invite_req here, but seems to be better than misusing
1320
-  // invite_sdp. The best way would be to propagate SDP as parameter of
1321
-  // initializeRTPRelay method.
1322
-  AmSdp sdp;
1323
-  if (parseSdp(sdp, invite_req)) updateRemoteSdp(sdp);
1324 1299
 }
1325 1300
 
1326 1301
 AmB2BCalleeSession::AmB2BCalleeSession(const string& other_local_tag)
... ...
@@ -299,10 +299,6 @@ private:
299 299
    * Default implementation updates connection address and ports. */
300 300
   virtual void updateLocalSdp(AmSdp &sdp);
301 301
 
302
-  /** Passes remote SDP to AmB2BMediaSession, might be redefined to provide
303
-   * another functionality than just simply passing SDP */
304
-  virtual void updateRemoteSdp(AmSdp &sdp);
305
-
306 302
   /**
307 303
    * Returns true and sets mapped_id if refer_id corresponds to an existing
308 304
    * refer event subscription which has been relayed.
... ...
@@ -360,7 +360,17 @@ int AmOfferAnswer::onReplyOut(AmSipReply& reply)
360 360
       }
361 361
     }
362 362
   }
363
-  
363
+
364
+  if (reply.cseq_method == SIP_METH_INVITE && reply.code < 300) {
365
+    // ignore SDP repeated in 1xx and 2xx replies (183, 180, ... 2xx)
366
+    if (has_sdp &&
367
+        (state == OA_Completed || state == OA_OfferSent) &&
368
+        reply.cseq == cseq)
369
+    {
370
+      has_sdp = false;
371
+    }
372
+  }
373
+
364 374
   saveState();
365 375
 
366 376
   if (generate_sdp) {
... ...
@@ -382,6 +392,11 @@ int AmOfferAnswer::onReplyOut(AmSipReply& reply)
382 392
     sdp_body->setPayload((const unsigned char*)sdp_buf.c_str(),
383 393
 			 sdp_buf.length());
384 394
     has_sdp = true;
395
+  } else if (sdp_body && has_sdp) {
396
+    // update local SDP copy
397
+    if (sdp_local.parse((const char*)sdp_body->getPayload())) {
398
+      ERROR("parser failed on Tx SDP: '%s'\n", (const char*)sdp_body->getPayload());
399
+    }
385 400
   }
386 401
 
387 402
   if (has_sdp && (onTxSdp(reply.cseq,reply.body) != 0)) {
... ...
@@ -616,7 +616,7 @@ int AmRtpStream::init(const AmSdp& local,
616 616
         ++sdp_it;
617 617
         continue;
618 618
       } else {
619
-        ERROR("No internal payload corresponding to type %s/%i (ignoring)\n",
619
+        DBG("No internal payload corresponding to type %s/%i (ignoring)\n",
620 620
               sdp_it->encoding_name.c_str(),
621 621
               sdp_it->clock_rate);
622 622
 	// ignore this payload
... ...
@@ -1283,3 +1283,27 @@ void AmRtpStream::setLogger(msg_logger* _logger)
1283 1283
   logger = _logger;
1284 1284
   if (logger) inc_ref(logger);
1285 1285
 }
1286
+
1287
+void AmRtpStream::debug()
1288
+{
1289
+#define BOOL_STR(b) ((b) ? "yes" : "no")
1290
+
1291
+  if(hasLocalSocket() > 0) {
1292
+    DBG("\t<%i> <-> <%s:%i>", getLocalPort(),
1293
+        getRHost().c_str(), getRPort());
1294
+  } else {
1295
+    DBG("\t<unbound> <-> <%s:%i>",
1296
+        getRHost().c_str(), getLocalPort());
1297
+  }
1298
+
1299
+  if (relay_stream) {
1300
+    DBG("\tinternal relay to stream %p (local port %i)",
1301
+      relay_stream, relay_stream->getLocalPort());
1302
+  }
1303
+  else DBG("\tno relay");
1304
+
1305
+  DBG("\tmute: %s, hold: %s, receiving: %s",
1306
+      BOOL_STR(mute), BOOL_STR(hold), BOOL_STR(receiving));
1307
+
1308
+#undef BOOL_STR
1309
+}
... ...
@@ -509,6 +509,8 @@ public:
509 509
 
510 510
   /** set destination for logging all received/sent RTP and RTCP packets */
511 511
   void setLogger(msg_logger *_logger);
512
+
513
+  void debug();
512 514
 };
513 515
 
514 516
 #endif
... ...
@@ -184,6 +184,7 @@ public:
184 184
   void updateRefreshMethod(const string& headers);
185 185
 
186 186
   AmRtpAudio* RTPStream();
187
+  bool hasRtpStream() { return _rtp_str.get() != NULL; }
187 188
 
188 189
 #ifdef WITH_ZRTP
189 190
   zrtp_conn_ctx_t*    zrtp_session; // ZRTP session
... ...
@@ -98,6 +98,8 @@ protected:
98 98
   AmOfferAnswer::OAState getOAState();
99 99
   void setOAState(AmOfferAnswer::OAState n_st);
100 100
   void setOAEnabled(bool oa_enabled);
101
+  const AmSdp& getLocalSdp() { return oa.getLocalSdp(); }
102
+  const AmSdp& getRemoteSdp() { return oa.getRemoteSdp(); }
101 103
 
102 104
   void setRel100State(Am100rel::State rel100_state);
103 105