Browse code

adds support for sendrecv/sendonly/recvonly/inactive SDP attributes

Also re-enabled support for 'hold' and 'mute'
- 'hold' in set by application via setOnHold(). It is not touched by any attribute received in SDP.
- 'mute' is set according to attributes received in SDP.

'send' and 'recv' attributes in SDP are mirrored based on SDP received and overridden by application settings.

For example:
- if remote SDP says 'sendrecv', but local is 'on_hold', we reply with 'sendonly'.
- if remote SDP says 'sendonly', but local is NOT 'on_hold', we reply with 'recvonly'.

Raphael Coeffic authored on 13/12/2011 14:06:36
Showing 5 changed files
... ...
@@ -550,12 +550,19 @@ void AmRtpStream::setPassiveMode(bool p)
550 550
   DBG("The other UA is NATed: switched to passive mode.\n");
551 551
 }
552 552
 
553
+void AmRtpStream::getSdp(SdpMedia& m)
554
+{
555
+  m.port = getLocalPort();
556
+  m.nports = 0;
557
+  m.transport = TP_RTPAVP;
558
+  m.send = !hold;
559
+  m.recv = receiving;
560
+  m.dir = SdpMedia::DirBoth;
561
+}
562
+
553 563
 void AmRtpStream::getSdpOffer(SdpMedia& offer)
554 564
 {
555
-  offer.port = getLocalPort();
556
-  offer.nports = 0;
557
-  offer.transport = TP_RTPAVP;
558
-  offer.dir = SdpMedia::DirBoth;
565
+  getSdp(offer);
559 566
 
560 567
   // TODO: transfer ownership of the payload provider also into AmRtpStream
561 568
   session->getPayloadProvider()->getPayloads(offer.payloads);
... ...
@@ -563,21 +570,7 @@ void AmRtpStream::getSdpOffer(SdpMedia& offer)
563 570
 
564 571
 void AmRtpStream::getSdpAnswer(const SdpMedia& offer, SdpMedia& answer)
565 572
 {
566
-  answer.port = getLocalPort();
567
-  answer.nports = 0;
568
-  answer.transport = TP_RTPAVP;
569
-
570
-  switch(offer.dir){
571
-  case SdpMedia::DirBoth:
572
-    answer.dir = SdpMedia::DirBoth;
573
-    break;
574
-  case SdpMedia::DirActive:
575
-    answer.dir = SdpMedia::DirPassive;
576
-    break;
577
-  case SdpMedia::DirPassive:
578
-    answer.dir = SdpMedia::DirActive;
579
-    break;
580
-  }
573
+  getSdp(answer);
581 574
 
582 575
   // TODO: transfer ownership of the payload provider also into AmRtpStream
583 576
   offer.calcAnswer(session->getPayloadProvider(),answer);
... ...
@@ -682,7 +675,24 @@ int AmRtpStream::init(AmPayloadProviderInterface* payload_provider,
682 675
 
683 676
   local_telephone_event_pt.reset(local.telephoneEventPayload());
684 677
 
685
-  resume();
678
+  if(remote_media.send) {
679
+    resume();
680
+  }
681
+  else {
682
+    pause();
683
+  }
684
+
685
+  if(remote_media.recv && !hold
686
+     && (remote_media.port != 0)
687
+#ifndef SUPPORT_IPV6
688
+     && (r_saddr.sin_addr.s_addr != 0)
689
+#endif
690
+     ) {
691
+    mute = false;
692
+  }
693
+  else {
694
+    mute = true;
695
+  }
686 696
 
687 697
 #ifdef WITH_ZRTP  
688 698
   if( session->zrtp_audio  ) {
... ...
@@ -198,6 +198,9 @@ protected:
198 198
 
199 199
   void relay(AmRtpPacket* p);
200 200
 
201
+  /** Sets generic parameters on SDP media */
202
+  void getSdp(SdpMedia& m);
203
+
201 204
 public:
202 205
 
203 206
   AmRtpPacket* newPacket();
... ...
@@ -223,6 +223,23 @@ void AmSdp::print(string& body) const
223 223
       default: break;
224 224
       }
225 225
 
226
+      if(media_it->send){
227
+	if(media_it->recv){
228
+	  out_buf += "a=sendrecv\r\n";
229
+	}
230
+	else {
231
+	  out_buf += "a=sendonly\r\n";
232
+	}
233
+      }
234
+      else {
235
+	if(media_it->recv){
236
+	  out_buf += "a=recvonly\r\n";
237
+	}
238
+	else {
239
+	  out_buf += "a=inactive\r\n";
240
+	}
241
+      }
242
+
226 243
       // add attributes (media level)
227 244
       for (std::vector<SdpAttribute>::const_iterator a_it=
228 245
 	     media_it->attributes.begin(); a_it != media_it->attributes.end(); a_it++) {
... ...
@@ -279,6 +296,21 @@ void AmSdp::clear()
279 296
 void SdpMedia::calcAnswer(const AmPayloadProviderInterface* payload_prov,
280 297
 			  SdpMedia& answer) const
281 298
 {
299
+  if(!recv) answer.send = false;
300
+  if(!send) answer.recv = false;
301
+
302
+  switch(dir){
303
+  case SdpMedia::DirBoth:
304
+    answer.dir = SdpMedia::DirBoth;
305
+    break;
306
+  case SdpMedia::DirActive:
307
+    answer.dir = SdpMedia::DirPassive;
308
+    break;
309
+  case SdpMedia::DirPassive:
310
+    answer.dir = SdpMedia::DirActive;
311
+    break;
312
+  }
313
+
282 314
   // Calculate the intersection with the offered set of payloads
283 315
   vector<SdpPayload>::const_iterator it = payloads.begin();
284 316
   for(; it!= payloads.end(); ++it) {
... ...
@@ -306,7 +338,7 @@ void SdpMedia::calcAnswer(const AmPayloadProviderInterface* payload_prov,
306 338
 		it->encoding_name,it->clock_rate,it->encoding_param));
307 339
       }
308 340
     }
309
-  }  
341
+  }
310 342
 }
311 343
 
312 344
 //parser
... ...
@@ -883,8 +915,19 @@ static void parse_sdp_attr(AmSdp* sdp_msg, char* s)
883 915
 	    DBG("found media attr 'direction', but value is not"
884 916
 		" followed by cr\n");
885 917
 	}
886
-
887
-    }else{
918
+    } else if (attr == "sendrecv") {
919
+      media.send = true;
920
+      media.recv = true;
921
+    } else if (attr == "sendonly") {
922
+      media.send = true;
923
+      media.recv = false;
924
+    } else if (attr == "recvonly") {
925
+      media.send = false;
926
+      media.recv = true;
927
+    } else if (attr == "inactive") {
928
+      media.send = false;
929
+      media.recv = false;
930
+    } else {
888 931
       attr_check(attr);
889 932
       next = parse_until(attr_line, '\r');
890 933
       if(next < line_end){
... ...
@@ -141,15 +141,20 @@ struct SdpMedia
141 141
   SdpConnection conn; // c=
142 142
   Direction     dir;  // a=direction
143 143
 
144
+  // sendrecv|sendonly|recvonly|inactive
145
+  bool          send;
146
+  bool          recv;
147
+
144 148
   std::vector<SdpPayload> payloads;
145 149
 
146 150
   std::vector<SdpAttribute> attributes; // unknown attributes
147 151
 
148
-  SdpMedia() : conn() {}
152
+  SdpMedia() : conn(),send(true),recv(true) {}
149 153
 
150 154
   /**
151
-   * Checks which payloads are compatible with the payload provider
152
-   * and inserts them into the answer.
155
+   * Checks which payloads are compatible with the payload provider,
156
+   * inserts them into the answer, compute send/recv attributes
157
+   * and direction according to the offer.
153 158
    */
154 159
   void calcAnswer(const AmPayloadProviderInterface* payload_prov, 
155 160
 		  SdpMedia& answer) const;
... ...
@@ -993,7 +993,9 @@ bool AmSession::getSdpAnswer(const AmSdp& offer, AmSdp& answer)
993 993
     answer.media.push_back(SdpMedia());
994 994
     SdpMedia& answer_media = answer.media.back();
995 995
 
996
-    if(m_it->type == MT_AUDIO && audio_1st_stream) {
996
+    if( m_it->type == MT_AUDIO 
997
+        && audio_1st_stream 
998
+        && (m_it->port != 0) ) {
997 999
 
998 1000
       RTPStream()->getSdpAnswer(*m_it,answer_media);
999 1001
       audio_1st_stream = false;
... ...
@@ -1004,7 +1006,11 @@ bool AmSession::getSdpAnswer(const AmSdp& offer, AmSdp& answer)
1004 1006
       answer_media.port = 0;
1005 1007
       answer_media.nports = 0;
1006 1008
       answer_media.transport = TP_RTPAVP;
1009
+      answer_media.send = false;
1010
+      answer_media.recv = false;
1007 1011
       answer_media.payloads.clear();
1012
+      if(!m_it->payloads.empty())
1013
+	answer_media.payloads.push_back(m_it->payloads.front());
1008 1014
       answer_media.attributes.clear();
1009 1015
     }
1010 1016
   }