Browse code

moved parts of SDP offer/answer generation into AmRtpStream

fixes support for multiple media lines in remote offers.

Raphael Coeffic authored on 13/12/2011 12:20:40
Showing 11 changed files
... ...
@@ -432,23 +432,23 @@ amci_inoutfmt_t* AmPlugIn::fileFormat(const string& fmt_name, const string& ext)
432 432
 
433 433
 amci_codec_t* AmPlugIn::codec(int id)
434 434
 {
435
-  std::map<int,amci_codec_t*>::iterator it = codecs.find(id);
435
+  std::map<int,amci_codec_t*>::const_iterator it = codecs.find(id);
436 436
   if(it != codecs.end())
437 437
     return it->second;
438 438
 
439 439
   return 0;
440 440
 }
441 441
 
442
-amci_payload_t*  AmPlugIn::payload(int payload_id)
442
+amci_payload_t*  AmPlugIn::payload(int payload_id) const
443 443
 {
444
-  std::map<int,amci_payload_t*>::iterator it = payloads.find(payload_id);
444
+  std::map<int,amci_payload_t*>::const_iterator it = payloads.find(payload_id);
445 445
   if(it != payloads.end())
446 446
     return it->second;
447 447
 
448 448
   return 0;
449 449
 }
450 450
 
451
-int AmPlugIn::getDynPayload(const string& name, int rate, int encoding_param) {
451
+int AmPlugIn::getDynPayload(const string& name, int rate, int encoding_param) const {
452 452
   // find a dynamic payload by name/rate and encoding_param (channels, if > 0)
453 453
   for(std::map<int, amci_payload_t*>::const_iterator pl_it = payloads.begin();
454 454
       pl_it != payloads.end(); ++pl_it)
... ...
@@ -465,7 +465,7 @@ int AmPlugIn::getDynPayload(const string& name, int rate, int encoding_param) {
465 465
 }
466 466
 
467 467
 /** return 0, or -1 in case of error. */
468
-void AmPlugIn::getPayloads(vector<SdpPayload>& pl_vec)
468
+void AmPlugIn::getPayloads(vector<SdpPayload>& pl_vec) const
469 469
 {
470 470
   pl_vec.clear();
471 471
   for (std::map<int,int>::const_iterator it = payload_order.begin(); it != payload_order.end(); ++it) {
... ...
@@ -65,19 +65,19 @@ class AmPayloadProviderInterface {
65 65
    * @param payload_id Payload ID.
66 66
    * @return NULL if failed .
67 67
    */
68
-  virtual amci_payload_t*  payload(int payload_id) = 0;
68
+  virtual amci_payload_t*  payload(int payload_id) const = 0;
69 69
 
70 70
   /** 
71 71
    * Payload lookup function by name & rate
72 72
    * @param name Payload ID.
73 73
    * @return -1 if failed, else the internal payload id.
74 74
    */
75
-  virtual int getDynPayload(const string& name, int rate, int encoding_param) = 0;
75
+  virtual int getDynPayload(const string& name, int rate, int encoding_param) const = 0;
76 76
   
77 77
   /**
78 78
    * List all the payloads available for a media type
79 79
    */
80
-  virtual void getPayloads(vector<SdpPayload>& pl_vec) = 0;
80
+  virtual void getPayloads(vector<SdpPayload>& pl_vec) const = 0;
81 81
 };
82 82
 
83 83
 /**
... ...
@@ -146,17 +146,17 @@ class AmPlugIn : public AmPayloadProviderInterface
146 146
    * @param payload_id Payload ID.
147 147
    * @return NULL if failed .
148 148
    */
149
-  amci_payload_t*  payload(int payload_id);
149
+  amci_payload_t*  payload(int payload_id) const;
150 150
 
151 151
   /** 
152 152
    * Payload lookup function by name & rate
153 153
    * @param name Payload ID.
154 154
    * @return -1 if failed, else the internal payload id.
155 155
    */
156
-  int getDynPayload(const string& name, int rate, int encoding_param);
156
+  int getDynPayload(const string& name, int rate, int encoding_param) const;
157 157
 
158 158
   /** return 0, or -1 in case of error. */
159
-  void getPayloads(vector<SdpPayload>& pl_vec);
159
+  void getPayloads(vector<SdpPayload>& pl_vec) const;
160 160
 
161 161
   /** @return the suported payloads. */
162 162
   const std::map<int,amci_payload_t*>& getPayloads() { return payloads; }
... ...
@@ -206,17 +206,17 @@ int AmPrecodedFile::open(const std::string& filename) {
206 206
   return 0; // OK
207 207
 }
208 208
 
209
-amci_payload_t* AmPrecodedFile::payload(int payload_id) {
210
-  std::map<int,precoded_payload_t>::iterator it = 
209
+amci_payload_t* AmPrecodedFile::payload(int payload_id) const {
210
+  std::map<int,precoded_payload_t>::const_iterator it = 
211 211
     payloads.find(payload_id);
212 212
 
213 213
   if(it != payloads.end())
214
-    return &it->second;
214
+    return (amci_payload_t*)&it->second;
215 215
 
216 216
   return NULL;
217 217
 }
218 218
 
219
-int AmPrecodedFile::getDynPayload(const string& name, int rate, int encoding_param) {
219
+int AmPrecodedFile::getDynPayload(const string& name, int rate, int encoding_param) const {
220 220
   // find a dynamic payload by name/rate and encoding_param (channels, if > 0)
221 221
   for(std::map<int, precoded_payload_t>::const_iterator pl_it = payloads.begin();
222 222
       pl_it != payloads.end(); ++pl_it)
... ...
@@ -234,9 +234,9 @@ int AmPrecodedFile::getDynPayload(const string& name, int rate, int encoding_par
234 234
 }
235 235
 
236 236
 
237
-void AmPrecodedFile::getPayloads(vector<SdpPayload>& pl_vec)
237
+void AmPrecodedFile::getPayloads(vector<SdpPayload>& pl_vec) const
238 238
 {
239
-  for(std::map<int,precoded_payload_t>::iterator pl_it = payloads.begin();
239
+  for(std::map<int,precoded_payload_t>::const_iterator pl_it = payloads.begin();
240 240
       pl_it != payloads.end(); ++pl_it) {
241 241
     pl_vec.push_back(SdpPayload(pl_it->first, pl_it->second.name, pl_it->second.sample_rate, 0));
242 242
   }
... ...
@@ -110,10 +110,10 @@ class AmPrecodedFile
110 110
 
111 111
   int open(const std::string& filename);
112 112
 
113
-  amci_payload_t*  payload(int payload_id);
114
-  int getDynPayload(const string& name, int rate, int encoding_param);
113
+  amci_payload_t*  payload(int payload_id) const;
114
+  int getDynPayload(const string& name, int rate, int encoding_param) const;
115 115
 
116
-  void getPayloads(vector<SdpPayload>& pl_vec);
116
+  void getPayloads(vector<SdpPayload>& pl_vec) const;
117 117
 
118 118
   AmPrecodedFileInstance* getFileInstance(int payload_id, const vector<SdpPayload*>&  m_payloads);
119 119
 };
... ...
@@ -139,10 +139,18 @@ int AmRtpAudio::write(unsigned int user_ts, unsigned int size)
139 139
   return send(user_ts,(unsigned char*)samples,size);
140 140
 }
141 141
 
142
-// int AmRtpAudio::init(AmPayloadProviderInterface* payload_provider,
143
-// 		     const SdpMedia& remote_media, 
144
-// 		     const SdpConnection& conn, 
145
-// 		     bool remote_active)
142
+void AmRtpAudio::getSdpOffer(SdpMedia& offer)
143
+{
144
+  offer.type = MT_AUDIO;
145
+  AmRtpStream::getSdpOffer(offer);
146
+}
147
+
148
+void AmRtpAudio::getSdpAnswer(const SdpMedia& offer, SdpMedia& answer)
149
+{
150
+  answer.type = MT_AUDIO;
151
+  AmRtpStream::getSdpAnswer(offer,answer);
152
+}
153
+
146 154
 int AmRtpAudio::init(AmPayloadProviderInterface* payload_provider,
147 155
 		      unsigned char media_i, 
148 156
 		      const AmSdp& local,
... ...
@@ -116,10 +116,9 @@ public:
116 116
 	  unsigned int nb_samples);
117 117
 
118 118
   // AmRtpStream interface
119
-  // int init(AmPayloadProviderInterface* payload_provider,
120
-  // 	   const SdpMedia& remote_media, 
121
-  // 	   const SdpConnection& conn, 
122
-  // 	   bool remote_active);
119
+  void getSdpOffer(SdpMedia& offer);
120
+  void getSdpAnswer(const SdpMedia& offer, SdpMedia& answer);
121
+
123 122
   int init(AmPayloadProviderInterface* payload_provider,
124 123
 	   unsigned char media_i, 
125 124
 	   const AmSdp& local,
... ...
@@ -550,6 +550,39 @@ 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::getSdpOffer(SdpMedia& offer)
554
+{
555
+  offer.port = getLocalPort();
556
+  offer.nports = 0;
557
+  offer.transport = TP_RTPAVP;
558
+  offer.dir = SdpMedia::DirBoth;
559
+
560
+  // TODO: transfer ownership of the payload provider also into AmRtpStream
561
+  session->getPayloadProvider()->getPayloads(offer.payloads);
562
+}
563
+
564
+void AmRtpStream::getSdpAnswer(const SdpMedia& offer, SdpMedia& answer)
565
+{
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
+  }
581
+
582
+  // TODO: transfer ownership of the payload provider also into AmRtpStream
583
+  offer.calcAnswer(session->getPayloadProvider(),answer);
584
+}
585
+
553 586
 int AmRtpStream::init(AmPayloadProviderInterface* payload_provider,
554 587
 		      unsigned char media_i, 
555 588
 		      const AmSdp& local,
... ...
@@ -287,6 +287,19 @@ public:
287 287
    */
288 288
   void sendDtmf(int event, unsigned int duration_ms);
289 289
 
290
+  /**
291
+   * Generate an SDP offer based on the stream capabilities.
292
+   * @param offer the local offer to be filled/completed.
293
+   */
294
+  virtual void getSdpOffer(SdpMedia& offer);
295
+
296
+  /**
297
+   * Generate an answer for the given SDP media based on the stream capabilities.
298
+   * @param offer the remote offer.
299
+   * @param answer the local answer to be filled/completed.
300
+   */
301
+  virtual void getSdpAnswer(const SdpMedia& offer, SdpMedia& answer);
302
+
290 303
   /**
291 304
    * Enables RTP stream.
292 305
    * @param sdp_payload payload from the SDP message.
... ...
@@ -294,10 +307,6 @@ public:
294 307
    * @warning It should be called only if the stream has been completly initialized,
295 308
    * @warning and only once per session. Use resume() then.
296 309
    */
297
-  // virtual int init(AmPayloadProviderInterface* payload_provider,
298
-  // 		   const SdpMedia& remote_media, 
299
-  // 		   const SdpConnection& conn, 
300
-  // 		   bool remote_active);
301 310
   virtual int init(AmPayloadProviderInterface* payload_provider,
302 311
 		   unsigned char media_i, 
303 312
 		   const AmSdp& local,
... ...
@@ -276,6 +276,38 @@ void AmSdp::clear()
276 276
   l_origin = SdpOrigin();
277 277
 }
278 278
 
279
+void SdpMedia::calcAnswer(const AmPayloadProviderInterface* payload_prov,
280
+			  SdpMedia& answer) const
281
+{
282
+  // Calculate the intersection with the offered set of payloads
283
+  vector<SdpPayload>::const_iterator it = payloads.begin();
284
+  for(; it!= payloads.end(); ++it) {
285
+    amci_payload_t* a_pl = NULL;
286
+    if(it->payload_type < DYNAMIC_PAYLOAD_TYPE_START) {
287
+      // try static payloads
288
+      a_pl = payload_prov->payload(it->payload_type);
289
+    }
290
+
291
+    if( a_pl) {
292
+      answer.payloads.push_back(SdpPayload(a_pl->payload_id,a_pl->name,a_pl->sample_rate,0));
293
+    }
294
+    else {
295
+      // Try dynamic payloads
296
+      // and give a chance to broken
297
+      // implementation using a static payload number
298
+      // for dynamic ones.
299
+
300
+      int int_pt = payload_prov->
301
+	getDynPayload(it->encoding_name,
302
+		      it->clock_rate,
303
+		      it->encoding_param);
304
+      if(int_pt != -1){
305
+	answer.payloads.push_back(SdpPayload(int_pt,
306
+		it->encoding_name,it->clock_rate,it->encoding_param));
307
+      }
308
+    }
309
+  }  
310
+}
279 311
 
280 312
 //parser
281 313
 static bool parse_sdp_line_ex(AmSdp* sdp_msg, char*& s)
... ...
@@ -146,6 +146,13 @@ struct SdpMedia
146 146
   std::vector<SdpAttribute> attributes; // unknown attributes
147 147
 
148 148
   SdpMedia() : conn() {}
149
+
150
+  /**
151
+   * Checks which payloads are compatible with the payload provider
152
+   * and inserts them into the answer.
153
+   */
154
+  void calcAnswer(const AmPayloadProviderInterface* payload_prov, 
155
+		  SdpMedia& answer) const;
149 156
 };
150 157
 
151 158
 /**
... ...
@@ -951,7 +951,6 @@ void AmSession::onSendReply(AmSipReply& reply, int flags)
951 951
 bool AmSession::getSdpOffer(AmSdp& offer)
952 952
 {
953 953
   DBG("AmSession::getSdpOffer(...) ...\n");
954
-  // TODO: move this code to AmRtpStream
955 954
 
956 955
   offer.version = 0;
957 956
   offer.origin.user = "sems";
... ...
@@ -962,21 +961,13 @@ bool AmSession::getSdpOffer(AmSdp& offer)
962 961
   offer.conn.addrType = AT_V4;
963 962
   offer.conn.address = advertisedIP();
964 963
 
965
-  // TODO: support mutiple media types
964
+  // TODO: support mutiple media types (needs multiples RTP streams)
965
+  // TODO: support update instead of clearing everything
966 966
   offer.media.clear();
967
-  offer.media.push_back(SdpMedia());
968
-  SdpMedia& offer_media = offer.media[0];
969
-
970
-  // TODO: move following code to AmRtpStream
971
-
972
-  offer_media.type = MT_AUDIO;
973
-  offer_media.port = RTPStream()->getLocalPort();
974
-  offer_media.nports = 0;
975
-  offer_media.transport = TP_RTPAVP;
976
-  offer_media.dir = SdpMedia::DirBoth;
977
-
978
-  getPayloadProvider()->getPayloads(offer_media.payloads);
979 967
 
968
+  offer.media.push_back(SdpMedia());
969
+  RTPStream()->getSdpOffer(offer.media.back());
970
+  
980 971
   return true;
981 972
 }
982 973
 
... ...
@@ -993,62 +984,28 @@ bool AmSession::getSdpAnswer(const AmSdp& offer, AmSdp& answer)
993 984
   answer.conn.network = NT_IN;
994 985
   answer.conn.addrType = AT_V4;
995 986
   answer.conn.address = advertisedIP();
996
-
997
-  // TODO: support multiple media types
998
-  const vector<SdpMedia>::const_iterator m_it = offer.media.begin();
999
-
1000 987
   answer.media.clear();
1001
-  answer.media.push_back(SdpMedia());
1002
-  SdpMedia& answer_media = answer.media[0];
1003
- 
1004
-  // TODO: move rest of the function to AmRtpStream
1005
-
1006
-  answer_media.type = MT_AUDIO;
1007
-  answer_media.port = RTPStream()->getLocalPort();
1008
-  answer_media.nports = 0;
1009
-  answer_media.transport = TP_RTPAVP;
1010
-
1011
-  switch(m_it->dir){
1012
-  case SdpMedia::DirBoth:
1013
-    answer_media.dir = SdpMedia::DirBoth;
1014
-    break;
1015
-  case SdpMedia::DirActive:
1016
-    answer_media.dir = SdpMedia::DirPassive;
1017
-    break;
1018
-  case SdpMedia::DirPassive:
1019
-    answer_media.dir = SdpMedia::DirActive;
1020
-    break;
1021
-  }
1022 988
 
1023
-  // Calculate the intersection with the offered set of payloads
989
+  bool audio_1st_stream = true;
990
+  for(vector<SdpMedia>::const_iterator m_it = offer.media.begin();
991
+      m_it != offer.media.end(); ++m_it) {
1024 992
 
1025
-  vector<SdpPayload>::const_iterator it = m_it->payloads.begin();
1026
-  for(; it!= m_it->payloads.end(); ++it) {
1027
-    amci_payload_t* a_pl = NULL;
1028
-    if(it->payload_type < DYNAMIC_PAYLOAD_TYPE_START) {
1029
-      // try static payloads
1030
-      a_pl = getPayloadProvider()->payload(it->payload_type);
1031
-    }
993
+    answer.media.push_back(SdpMedia());
994
+    SdpMedia& answer_media = answer.media.back();
1032 995
 
1033
-    if( a_pl) {
1034
-      answer_media.payloads.push_back(SdpPayload(a_pl->payload_id,a_pl->name,a_pl->sample_rate,0));
996
+    if(m_it->type == MT_AUDIO && audio_1st_stream) {
997
+
998
+      RTPStream()->getSdpAnswer(*m_it,answer_media);
999
+      audio_1st_stream = false;
1035 1000
     }
1036 1001
     else {
1037
-      // Try dynamic payloads
1038
-      // and give a chance to broken
1039
-      // implementation using a static payload number
1040
-      // for dynamic ones.
1041
-
1042
-      int int_pt = getPayloadProvider()->
1043
-	getDynPayload(it->encoding_name,
1044
-		      it->clock_rate,
1045
-		      it->encoding_param);
1046
-      if(int_pt != -1){
1047
-	answer_media.payloads.push_back(SdpPayload(int_pt,
1048
-						   it->encoding_name,
1049
-						   it->clock_rate,
1050
-						   it->encoding_param));
1051
-      }
1002
+      
1003
+      answer_media.type = m_it->type;
1004
+      answer_media.port = 0;
1005
+      answer_media.nports = 0;
1006
+      answer_media.transport = TP_RTPAVP;
1007
+      answer_media.payloads.clear();
1008
+      answer_media.attributes.clear();
1052 1009
     }
1053 1010
   }
1054 1011