Browse code

symmetrical B2B legs: body filtering moved into SBCCallLeg class

Václav Kubart authored on 01/08/2012 18:17:04
Showing 2 changed files
... ...
@@ -18,6 +18,8 @@
18 18
 
19 19
 using namespace std;
20 20
 
21
+#define TRACE INFO
22
+
21 23
 // helper functions
22 24
 
23 25
 /** count active and inactive media streams in given SDP */
... ...
@@ -76,200 +78,6 @@ static void savePayloadIDs(AmSdp &sdp, MediaType mtype,
76 78
   }
77 79
 }
78 80
 
79
-static void appendTranscoderCodecs(AmSdp &sdp, MediaType mtype, std::vector<SdpPayload> &transcoder_codecs, 
80
-    PayloadIdMapping &transcoder_payload_mapping)
81
-{
82
-  // append codecs for transcoding, remember the added ones to be able to filter
83
-  // them out from relayed reply!
84
-
85
-  // important: normalized SDP should get here
86
-
87
-  DBG("going to append transcoder codecs into SDP\n");
88
-
89
-  unsigned stream_idx = 0;
90
-  vector<SdpPayload>::const_iterator p;
91
-  for (vector<SdpMedia>::iterator m = sdp.media.begin(); m != sdp.media.end(); ++m) {
92
-
93
-    // handle audio transcoder codecs
94
-    if (m->type == mtype) {
95
-      // transcoder codecs can be added only if there are common payloads with
96
-      // the remote (only those allowed for transcoder)
97
-      // if there are no such common payloads adding transcoder codecs can't help
98
-      // because we won't be able to transcode later on!
99
-      // (we have to check for each media stream independently)
100
-
101
-      // find first unused dynamic payload number & detect transcodable codecs
102
-      // in original SDP
103
-      int id = 96;
104
-      bool transcodable = false;
105
-      PayloadMask used_payloads;
106
-      for (p = m->payloads.begin(); p != m->payloads.end(); ++p) {
107
-        if (p->payload_type >= id) id = p->payload_type + 1;
108
-        if (containsPayload(transcoder_codecs, *p)) transcodable = true;
109
-        used_payloads.set(p->payload_type);
110
-      }
111
-
112
-      if (transcodable) {
113
-        // there are some transcodable codecs present in the SDP, we can safely
114
-        // add the other transcoder codecs to the SDP
115
-        unsigned idx = 0;
116
-        for (p = transcoder_codecs.begin(); p != transcoder_codecs.end(); ++p, ++idx) {
117
-          // add all payloads which are not already there
118
-          if (!containsPayload(m->payloads, *p)) {
119
-            m->payloads.push_back(*p);
120
-            int &pid = m->payloads.back().payload_type;
121
-            if (pid < 0) {
122
-              // try to use remembered ID
123
-              pid = transcoder_payload_mapping.get(stream_idx, idx);
124
-            }
125
-
126
-            if ((pid < 0) || used_payloads.get(pid)) {
127
-              // payload ID is not set or is already used in current SDP, we
128
-              // need to assign a new one
129
-              pid = id++;
130
-            }
131
-          }
132
-        }
133
-        if (id > 128) ERROR("assigned too high payload type number (%d), see RFC 3551\n", id);
134
-      }
135
-      else {
136
-        // no compatible codecs found
137
-        DBG("can not transcode stream %d - no compatible codecs with transcoder_codecs found\n", stream_idx + 1);
138
-      }
139
-    
140
-      stream_idx++; // count chosen media type only
141
-    }
142
-  }
143
-
144
-  // remembered payload IDs should be used just once, in SDP answer
145
-  // unfortunatelly the SDP answer might be present in 1xx and in 2xx as well so
146
-  // we can't clear it here
147
-  // on other hand it might be useful to use the same payload ID if offer/answer
148
-  // is repeated in the other direction next time
149
-}
150
-
151
-// do the filtering, returns true if SDP was changed
152
-static bool doFiltering(AmSdp &sdp, SBCCallProfile &call_profile, bool a_leg, PayloadIdMapping &transcoder_payload_mapping)
153
-{
154
-  bool changed = false;
155
-
156
-  bool prefer_existing_codecs = call_profile.codec_prefs.preferExistingCodecs(a_leg);
157
-
158
-  if (prefer_existing_codecs) {
159
-    // We have to order payloads before adding transcoder codecs to leave
160
-    // transcoding as the last chance (existing codecs are preferred thus
161
-    // relaying will be used if possible).
162
-    if (call_profile.codec_prefs.shouldOrderPayloads(a_leg)) {
163
-      normalizeSDP(sdp, call_profile.anonymize_sdp);
164
-      call_profile.codec_prefs.orderSDP(sdp, a_leg);
165
-      changed = true;
166
-    }
167
-  }
168
-
169
-  // Add transcoder codecs before filtering because otherwise SDP filter could
170
-  // inactivate some media lines which shouldn't be inactivated.
171
-
172
-  if (call_profile.transcoder.isActive()) {
173
-    if (!changed) // otherwise already normalized
174
-      normalizeSDP(sdp, call_profile.anonymize_sdp);
175
-    appendTranscoderCodecs(sdp, MT_AUDIO, call_profile.transcoder.audio_codecs, transcoder_payload_mapping);
176
-    changed = true;
177
-  }
178
-  
179
-  if (!prefer_existing_codecs) {
180
-    // existing codecs are not preferred - reorder AFTER adding transcoder
181
-    // codecs so it might happen that transcoding will be forced though relaying
182
-    // would be possible
183
-    if (call_profile.codec_prefs.shouldOrderPayloads(a_leg)) {
184
-      if (!changed) normalizeSDP(sdp, call_profile.anonymize_sdp);
185
-      call_profile.codec_prefs.orderSDP(sdp, a_leg);
186
-      changed = true;
187
-    }
188
-  }
189
-  
190
-  // It doesn't make sense to filter out codecs allowed for transcoding and thus
191
-  // if the filter filters them out it can be considered as configuration
192
-  // problem, right? 
193
-  // => So we wouldn't try to avoid filtering out transcoder codecs what would
194
-  // just complicate things.
195
-
196
-  if (call_profile.sdpfilter_enabled) {
197
-    if (!changed) // otherwise already normalized
198
-      normalizeSDP(sdp, call_profile.anonymize_sdp);
199
-    if (isActiveFilter(call_profile.sdpfilter)) {
200
-      filterSDP(sdp, call_profile.sdpfilter, call_profile.sdpfilter_list);
201
-    }
202
-    changed = true;
203
-  }
204
-  if (call_profile.sdpalinesfilter_enabled &&
205
-      isActiveFilter(call_profile.sdpalinesfilter)) {
206
-    // filter SDP "a=lines"
207
-    filterSDPalines(sdp, call_profile.sdpalinesfilter, call_profile.sdpalinesfilter_list);
208
-    changed = true;
209
-  }
210
-
211
-  return changed;
212
-}
213
-
214
-static int filterBody(AmMimeBody *body, AmSdp& sdp, SBCCallProfile &call_profile, bool a_leg, 
215
-    PayloadIdMapping &transcoder_payload_mapping) 
216
-{
217
-  int res = sdp.parse((const char *)body->getPayload());
218
-  if (0 != res) {
219
-    DBG("SDP parsing failed!\n");
220
-    return res;
221
-  }
222
-
223
-  if (doFiltering(sdp, call_profile, a_leg, transcoder_payload_mapping)) {
224
-    string n_body;
225
-    sdp.print(n_body);
226
-    body->setPayload((const unsigned char*)n_body.c_str(),
227
-			 n_body.length());
228
-  }
229
-  return 0;
230
-}
231
-
232
-static int filterBody(AmSipRequest &req, AmSdp &sdp, SBCCallProfile &call_profile, bool a_leg, 
233
-    PayloadIdMapping &transcoder_payload_mapping)
234
-{
235
-  AmMimeBody* body = req.body.hasContentType(SIP_APPLICATION_SDP);
236
-
237
-  DBG("filtering SDP for request '%s'\n",
238
-      req.method.c_str());
239
-  if (body && 
240
-      (req.method == SIP_METH_INVITE || 
241
-       req.method == SIP_METH_UPDATE ||
242
-       req.method == SIP_METH_ACK)) {
243
-
244
-    // todo: handle filtering errors
245
-    filterBody(body, sdp, call_profile, a_leg, transcoder_payload_mapping);
246
-
247
-    // temporary hack - will be migrated deeper inside
248
-    int active, inactive;
249
-    countStreams(sdp, active, inactive);
250
-    if ((inactive > 0) && (active == 0)) {
251
-      // no active streams remaining => reply 488 (FIXME: does it matter if we
252
-      // filtered them out or they were already inactive?)
253
-
254
-      DBG("all streams are marked as inactive, reply 488 "
255
-          SIP_REPLY_NOT_ACCEPTABLE_HERE"\n");
256
-      return -488;
257
-    }
258
-  }
259
-  return 0;
260
-}
261
-
262
-static void filterBody(AmSipReply &reply, AmSdp &sdp, SBCCallProfile &call_profile, bool a_leg, 
263
-    PayloadIdMapping &transcoder_payload_mapping)
264
-{
265
-  AmMimeBody* body = reply.body.hasContentType(SIP_APPLICATION_SDP);
266
-
267
-  DBG("filtering body of relayed reply %d\n", reply.code);
268
-  if (body &&
269
-      (reply.cseq_method == SIP_METH_INVITE || reply.cseq_method == SIP_METH_UPDATE)) {
270
-    filterBody(body, sdp, call_profile, a_leg, transcoder_payload_mapping);
271
-  }
272
-}
273 81
 
274 82
 ///////////////////////////////////////////////////////////////////////////////////////////
275 83
 
... ...
@@ -286,7 +94,7 @@ class SBCRelayController: public RelayController {
286 94
 
287 95
 void SBCRelayController::computeRelayMask(const SdpMedia &m, bool &enable, PayloadMask &mask)
288 96
 {
289
-  DBG("entering SBCRelayController::computeRelayMask(%s)\n", aleg ? "A leg" : "B leg");
97
+  TRACE("entering SBCRelayController::computeRelayMask(%s)\n", aleg ? "A leg" : "B leg");
290 98
 
291 99
   PayloadMask m1, m2;
292 100
   bool use_m1 = false;
... ...
@@ -311,13 +119,13 @@ void SBCRelayController::computeRelayMask(const SdpMedia &m, bool &enable, Paylo
311 119
     if(strcasecmp("telephone-event",p->encoding_name.c_str()) == 0) continue;
312 120
 
313 121
     // mark every codec for relay in m2
314
-    DBG("m2: marking payload %d for relay\n", p->payload_type);
122
+    TRACE("m2: marking payload %d for relay\n", p->payload_type);
315 123
     m2.set(p->payload_type);
316 124
 
317 125
     if (!containsPayload(norelay_payloads, *p)) {
318 126
       // this payload can be relayed
319 127
 
320
-      DBG("m1: marking payload %d for relay\n", p->payload_type);
128
+      TRACE("m1: marking payload %d for relay\n", p->payload_type);
321 129
       m1.set(p->payload_type);
322 130
 
323 131
       if (!use_m1 && containsPayload(transcoder_settings->audio_codecs, *p)) {
... ...
@@ -329,7 +137,7 @@ void SBCRelayController::computeRelayMask(const SdpMedia &m, bool &enable, Paylo
329 137
     }
330 138
   }
331 139
 
332
-  DBG("using %s\n", use_m1 ? "m1" : "m2");
140
+  TRACE("using %s\n", use_m1 ? "m1" : "m2");
333 141
   if (use_m1) mask = m1;
334 142
   else mask = m2;
335 143
 }
... ...
@@ -480,8 +288,7 @@ int SBCCallLeg::relayEvent(AmEvent* ev)
480 288
               req_ev->req.method.c_str(), req_ev->req.body.getCTStr().c_str());
481 289
           // todo: handle filtering errors
482 290
 
483
-          AmSdp sdp;
484
-          int res = filterBody(req_ev->req, sdp, call_profile, a_leg, transcoder_payload_mapping);
291
+          int res = filterSdp(req_ev->req.body, req_ev->req.method);
485 292
           if (res < 0) return res;
486 293
         }
487 294
         break;
... ...
@@ -515,8 +322,7 @@ int SBCCallLeg::relayEvent(AmEvent* ev)
515 322
           DBG("filtering body for reply '%s' (c/t '%s')\n",
516 323
               reply_ev->trans_method.c_str(), reply_ev->reply.body.getCTStr().c_str());
517 324
 
518
-          AmSdp sdp;
519
-          filterBody(reply_ev->reply, sdp, call_profile, a_leg, transcoder_payload_mapping);
325
+          filterSdp(reply_ev->reply.body, reply_ev->reply.cseq_method);
520 326
         }
521 327
 
522 328
         break;
... ...
@@ -946,8 +752,7 @@ void SBCCallLeg::onInvite(const AmSipRequest& req)
946 752
     invite_req.hdrs+=append_headers;
947 753
   }
948 754
   
949
-  AmSdp sdp;
950
-  int res = filterBody(invite_req, sdp, call_profile, a_leg, transcoder_payload_mapping);
755
+  int res = filterSdp(invite_req.body, invite_req.method);
951 756
   if (res < 0) {
952 757
     // FIXME: quick hack, throw the exception from the filtering function for
953 758
     // requests
... ...
@@ -1360,6 +1165,180 @@ void SBCCallLeg::CCEnd(const CCInterfaceListIteratorT& end_interface) {
1360 1165
   }
1361 1166
 }
1362 1167
 
1168
+//////////////////////////////////////////////////////////////////////////////////////////
1169
+// body filtering
1170
+
1171
+// do the filtering, returns true if SDP was changed
1172
+bool SBCCallLeg::doFiltering(AmSdp &sdp)
1173
+{
1174
+  bool changed = false;
1175
+
1176
+  bool prefer_existing_codecs = call_profile.codec_prefs.preferExistingCodecs(a_leg);
1177
+
1178
+  if (prefer_existing_codecs) {
1179
+    // We have to order payloads before adding transcoder codecs to leave
1180
+    // transcoding as the last chance (existing codecs are preferred thus
1181
+    // relaying will be used if possible).
1182
+    if (call_profile.codec_prefs.shouldOrderPayloads(a_leg)) {
1183
+      normalizeSDP(sdp, call_profile.anonymize_sdp);
1184
+      call_profile.codec_prefs.orderSDP(sdp, a_leg);
1185
+      changed = true;
1186
+    }
1187
+  }
1188
+
1189
+  // Add transcoder codecs before filtering because otherwise SDP filter could
1190
+  // inactivate some media lines which shouldn't be inactivated.
1191
+
1192
+  if (call_profile.transcoder.isActive()) {
1193
+    if (!changed) // otherwise already normalized
1194
+      normalizeSDP(sdp, call_profile.anonymize_sdp);
1195
+    appendTranscoderCodecs(sdp);
1196
+    changed = true;
1197
+  }
1198
+
1199
+  if (!prefer_existing_codecs) {
1200
+    // existing codecs are not preferred - reorder AFTER adding transcoder
1201
+    // codecs so it might happen that transcoding will be forced though relaying
1202
+    // would be possible
1203
+    if (call_profile.codec_prefs.shouldOrderPayloads(a_leg)) {
1204
+      if (!changed) normalizeSDP(sdp, call_profile.anonymize_sdp);
1205
+      call_profile.codec_prefs.orderSDP(sdp, a_leg);
1206
+      changed = true;
1207
+    }
1208
+  }
1209
+
1210
+  // It doesn't make sense to filter out codecs allowed for transcoding and thus
1211
+  // if the filter filters them out it can be considered as configuration
1212
+  // problem, right?
1213
+  // => So we wouldn't try to avoid filtering out transcoder codecs what would
1214
+  // just complicate things.
1215
+
1216
+  if (call_profile.sdpfilter_enabled) {
1217
+    if (!changed) // otherwise already normalized
1218
+      normalizeSDP(sdp, call_profile.anonymize_sdp);
1219
+    if (isActiveFilter(call_profile.sdpfilter)) {
1220
+      filterSDP(sdp, call_profile.sdpfilter, call_profile.sdpfilter_list);
1221
+    }
1222
+    changed = true;
1223
+  }
1224
+  if (call_profile.sdpalinesfilter_enabled &&
1225
+      isActiveFilter(call_profile.sdpalinesfilter)) {
1226
+    // filter SDP "a=lines"
1227
+    filterSDPalines(sdp, call_profile.sdpalinesfilter, call_profile.sdpalinesfilter_list);
1228
+    changed = true;
1229
+  }
1230
+
1231
+  return changed;
1232
+}
1233
+
1234
+int SBCCallLeg::filterSdp(AmMimeBody &body, const string &method)
1235
+{
1236
+  AmMimeBody* sdp_body = body.hasContentType(SIP_APPLICATION_SDP);
1237
+
1238
+  DBG("filtering body\n");
1239
+  if (sdp_body &&
1240
+      (method == SIP_METH_INVITE ||
1241
+       method == SIP_METH_UPDATE ||
1242
+       //method == SIP_METH_PRACK || //FIXME
1243
+       method == SIP_METH_ACK))
1244
+  {
1245
+    AmSdp sdp;
1246
+    int res = sdp.parse((const char *)sdp_body->getPayload());
1247
+    if (0 != res) {
1248
+      DBG("SDP parsing failed!\n");
1249
+      return res;
1250
+    }
1363 1251
 
1252
+    if (doFiltering(sdp)) {
1253
+      string n_body;
1254
+      sdp.print(n_body);
1255
+      sdp_body->setPayload((const unsigned char*)n_body.c_str(), n_body.length());
1256
+    }
1364 1257
 
1258
+    // temporary hack - will be migrated deeper inside
1259
+    int active, inactive;
1260
+    countStreams(sdp, active, inactive);
1261
+    if ((inactive > 0) && (active == 0)) {
1262
+      // no active streams remaining => reply 488 (FIXME: does it matter if we
1263
+      // filtered them out or they were already inactive?)
1264
+
1265
+      DBG("all streams are marked as inactive, reply 488 "
1266
+          SIP_REPLY_NOT_ACCEPTABLE_HERE"\n");
1267
+      return -488;
1268
+    }
1269
+  }
1270
+  return 0;
1271
+}
1272
+
1273
+void SBCCallLeg::appendTranscoderCodecs(AmSdp &sdp)
1274
+{
1275
+  // append codecs for transcoding, remember the added ones to be able to filter
1276
+  // them out from relayed reply!
1277
+
1278
+  // important: normalized SDP should get here
1279
+
1280
+  TRACE("going to append transcoder codecs into SDP\n");
1281
+  const std::vector<SdpPayload> &transcoder_codecs = call_profile.transcoder.audio_codecs;
1282
+
1283
+  unsigned stream_idx = 0;
1284
+  vector<SdpPayload>::const_iterator p;
1285
+  for (vector<SdpMedia>::iterator m = sdp.media.begin(); m != sdp.media.end(); ++m) {
1286
+
1287
+    // handle audio transcoder codecs
1288
+    if (m->type == MT_AUDIO) {
1289
+      // transcoder codecs can be added only if there are common payloads with
1290
+      // the remote (only those allowed for transcoder)
1291
+      // if there are no such common payloads adding transcoder codecs can't help
1292
+      // because we won't be able to transcode later on!
1293
+      // (we have to check for each media stream independently)
1294
+
1295
+      // find first unused dynamic payload number & detect transcodable codecs
1296
+      // in original SDP
1297
+      int id = 96;
1298
+      bool transcodable = false;
1299
+      PayloadMask used_payloads;
1300
+      for (p = m->payloads.begin(); p != m->payloads.end(); ++p) {
1301
+        if (p->payload_type >= id) id = p->payload_type + 1;
1302
+        if (containsPayload(transcoder_codecs, *p)) transcodable = true;
1303
+        used_payloads.set(p->payload_type);
1304
+      }
1305
+
1306
+      if (transcodable) {
1307
+        // there are some transcodable codecs present in the SDP, we can safely
1308
+        // add the other transcoder codecs to the SDP
1309
+        unsigned idx = 0;
1310
+        for (p = transcoder_codecs.begin(); p != transcoder_codecs.end(); ++p, ++idx) {
1311
+          // add all payloads which are not already there
1312
+          if (!containsPayload(m->payloads, *p)) {
1313
+            m->payloads.push_back(*p);
1314
+            int &pid = m->payloads.back().payload_type;
1315
+            if (pid < 0) {
1316
+              // try to use remembered ID
1317
+              pid = transcoder_payload_mapping.get(stream_idx, idx);
1318
+            }
1319
+
1320
+            if ((pid < 0) || used_payloads.get(pid)) {
1321
+              // payload ID is not set or is already used in current SDP, we
1322
+              // need to assign a new one
1323
+              pid = id++;
1324
+            }
1325
+          }
1326
+        }
1327
+        if (id > 128) ERROR("assigned too high payload type number (%d), see RFC 3551\n", id);
1328
+      }
1329
+      else {
1330
+        // no compatible codecs found
1331
+        TRACE("can not transcode stream %d - no compatible codecs with transcoder_codecs found\n", stream_idx + 1);
1332
+      }
1333
+
1334
+      stream_idx++; // count chosen media type only
1335
+    }
1336
+  }
1337
+
1338
+  // remembered payload IDs should be used just once, in SDP answer
1339
+  // unfortunatelly the SDP answer might be present in 1xx and in 2xx as well so
1340
+  // we can't clear it here
1341
+  // on other hand it might be useful to use the same payload ID if offer/answer
1342
+  // is repeated in the other direction next time
1343
+}
1365 1344
 
... ...
@@ -88,6 +88,9 @@ class SBCCallLeg : public CallLeg, public CredentialHolder
88 88
   void CCEnd(const CCInterfaceListIteratorT& end_interface);
89 89
 
90 90
   void connectCallee(const string& remote_party, const string& remote_uri, const string &from, const AmSipRequest &invite_req);
91
+  bool doFiltering(AmSdp &sdp);
92
+  int filterSdp(AmMimeBody &body, const string &method);
93
+  void appendTranscoderCodecs(AmSdp &sdp);
91 94
 
92 95
  public:
93 96