1 /* ------------------------------------------------------------------
2 * Copyright (C) 1998-2009 PacketVideo
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
13 * express or implied.
14 * See the License for the specific language governing permissions
15 * and limitations under the License.
16 * -------------------------------------------------------------------
17 */
18 #include "base_media_info_parser.h"
19 #include "oscl_string_utils.h"
20 #include "oscl_string_containers.h"
21 #include "rtsp_range_utils.h"
22
23
24 /* Function to allocate temporary buffer, OSCL_TRY() put here to avoid */
25 /* compiler warnings */
newTmpBuf(uint32 len,char ** buf)26 static void newTmpBuf(uint32 len, char** buf)
27 {
28 int32 err;
29 *buf = NULL;
30
31 OSCL_TRY(err, *buf = OSCL_ARRAY_NEW(char, len));
32
33 if (err != OsclErrNone)
34 {
35 *buf = NULL;
36 }
37 }
38
39 SDP_ERROR_CODE
baseMediaInfoParser(const char * buff,mediaInfo * mediaStr,const int index,const int alt_id,bool alt_def_id,bool isSipSdp)40 SDPBaseMediaInfoParser::baseMediaInfoParser(const char* buff,
41 mediaInfo* mediaStr,
42 const int index,
43 const int alt_id,
44 bool alt_def_id,
45 bool isSipSdp)
46 {
47 const char *current_start = buff; //Pointer to the beginning of the media text
48 const char *end = buff + index; //Pointer to the end of the media text
49 const char *line_start_ptr, *line_end_ptr;
50
51
52 bool a_range_found = false;
53
54 bool a_rtpmap_found = false;
55 bool a_control_found = false;
56 bool a_control_set = false;
57
58 OsclMemoryFragment memFrag;
59
60 while (get_next_line(current_start, end,
61 line_start_ptr, line_end_ptr))
62 {
63 if ((!alt_def_id && !alt_id) || (alt_def_id) ||
64 ((!alt_def_id) && !oscl_strncmp(line_start_ptr, "a=alt:", oscl_strlen("a=alt:"))))
65 {
66 if (!alt_def_id && !oscl_strncmp(line_start_ptr, "a=alt:", oscl_strlen("a=alt:")))
67 {
68 line_start_ptr += oscl_strlen("a=alt:");
69 const char *end1 = line_start_ptr;
70 for (; *end1 != ':'; end1++);
71 uint32 id;
72 if (!PV_atoi(line_start_ptr, 'd' , end1 - line_start_ptr, id))
73 return SDP_BAD_MEDIA_ALT_ID;
74 if ((int)id != alt_id)
75 {
76 //check if id is already present
77 Oscl_Vector<int, SDPParserAlloc> alt_track = mediaStr->getalternateTrackId();
78 bool found = false;
79
80 for (int ss = 0; ss < (int)alt_track.size(); ss++)
81 {
82 if (alt_track[ss] == (int)id)
83 found = true;
84 }
85
86 if (!found)
87 mediaStr->setalternateTrackId(id);
88
89 current_start = line_end_ptr;
90 continue;
91 }
92
93 line_start_ptr = end1 + 1;
94 line_start_ptr = skip_whitespace(line_start_ptr, line_end_ptr);
95
96 }
97
98 switch (*line_start_ptr)
99 {
100 case 'm':
101 {
102 if (*(line_start_ptr + 1) != '=')
103 {
104 PVMF_SDP_PARSER_LOGERROR((0, "SDPBaseMediaInfoParser::parseMediaInfo - Bad m= line format"));
105 return SDP_BAD_MEDIA_FORMAT;
106 }
107
108 // parse through each field
109 const char *sptr, *eptr;
110
111 //line_start_ptr+2 since we need to start looking beyond the '=' sign
112
113 //get the media type (audio, video, application)
114 sptr = skip_whitespace(line_start_ptr + 2, line_end_ptr);
115 if (sptr >= line_end_ptr)
116 {
117 PVMF_SDP_PARSER_LOGERROR((0, "SDPBaseMediaInfoParser::parseMediaInfo - Bad m= line format for media type"));
118 return SDP_BAD_MEDIA_FORMAT;
119 }
120
121 eptr = skip_to_whitespace(sptr, line_end_ptr);
122 if (eptr <= sptr)
123 {
124 PVMF_SDP_PARSER_LOGERROR((0, "SDPBaseMediaInfoParser::parseMediaInfo - Bad m= line format"));
125 return SDP_BAD_MEDIA_FORMAT;
126 }
127
128 memFrag.ptr = (void*)sptr;
129 memFrag.len = (eptr - sptr);
130
131 mediaStr->setType(memFrag);
132
133 //get the suggested port number
134 sptr = skip_whitespace(eptr, line_end_ptr);
135 if (sptr >= line_end_ptr)
136 {
137 PVMF_SDP_PARSER_LOGERROR((0, "SDPBaseMediaInfoParser::parseMediaInfo - Bad m= line format for suggested port"));
138 return SDP_BAD_MEDIA_FORMAT;
139 }
140
141 eptr = skip_to_whitespace(sptr, line_end_ptr);
142 if (eptr <= sptr)
143 {
144 PVMF_SDP_PARSER_LOGERROR((0, "SDPBaseMediaInfoParser::parseMediaInfo - Bad m= line format"));
145 return SDP_BAD_MEDIA_FORMAT;
146 }
147
148 uint32 suggestedPort;
149
150 OSCL_HeapString<SDPParserAlloc> restOfLine(sptr, eptr - sptr);
151 const char *slash = oscl_strstr(restOfLine.get_cstr(), "/");
152 if (slash)
153 {
154 if (PV_atoi(restOfLine.get_cstr(), 'd', (slash - restOfLine.get_cstr()), suggestedPort) == true)
155 {
156 mediaStr->setSuggestedPort(suggestedPort);
157 // There must be number of ports info after the slash
158 uint32 numOfPorts;
159 const char *ports = oscl_strstr(sptr, "/");
160 ports++;
161 if (ports == NULL)
162 {
163 PVMF_SDP_PARSER_LOGERROR((0, "SDPBaseMediaInfoParser::parseMediaInfo - Bad m= line format for ports info"));
164 return SDP_BAD_MEDIA_FORMAT;
165 }
166 if (PV_atoi(ports, 'd', (eptr - ports), numOfPorts) == true)
167 {
168 mediaStr->setNumOfPorts(numOfPorts);
169 }
170 else
171 {
172 PVMF_SDP_PARSER_LOGERROR((0, "SDPBaseMediaInfoParser::parseMediaInfo - Bad m= line format for ports info"));
173 return SDP_BAD_MEDIA_FORMAT;
174 }
175 }
176 else
177 {
178 PVMF_SDP_PARSER_LOGERROR((0, "SDPBaseMediaInfoParser::parseMediaInfo - Bad m= line format for ports info"));
179 return SDP_BAD_MEDIA_FORMAT;
180 }
181 }
182 else
183 {
184 if (PV_atoi(sptr, 'd', (eptr - sptr), suggestedPort) == true)
185 {
186 mediaStr->setSuggestedPort(suggestedPort);
187 }
188 else
189 {
190 PVMF_SDP_PARSER_LOGERROR((0, "SDPBaseMediaInfoParser::parseMediaInfo - Bad m= line format for ports info"));
191 return SDP_BAD_MEDIA_FORMAT;
192 }
193 }
194 //get the transport profile
195 sptr = skip_whitespace(eptr, line_end_ptr);
196 if (sptr >= line_end_ptr)
197 {
198 PVMF_SDP_PARSER_LOGERROR((0, "SDPBaseMediaInfoParser::parseMediaInfo - Bad m= line format for tranport profile"));
199 return SDP_BAD_MEDIA_FORMAT;
200 }
201
202 eptr = skip_to_whitespace(sptr, line_end_ptr);
203 if (eptr <= sptr)
204 {
205 PVMF_SDP_PARSER_LOGERROR((0, "SDPBaseMediaInfoParser::parseMediaInfo - Bad m= line format for tranport profile"));
206 return SDP_BAD_MEDIA_FORMAT;
207 }
208
209 memFrag.ptr = (void*)sptr;
210 memFrag.len = (eptr - sptr);
211
212 if (oscl_strncmp(sptr, "RTP/AVP", (eptr - sptr)) && oscl_strncmp(sptr, "RTP/AVPF", (eptr - sptr)) && oscl_strncmp(sptr, "RTP/SAVP", (eptr - sptr)))
213 {
214 PVMF_SDP_PARSER_LOGERROR((0, "SDPBaseMediaInfoParser::parseMediaInfo - Bad m= line format for tranport profile"));
215 return SDP_BAD_MEDIA_FORMAT;
216 }
217 else if ((suggestedPort % 2)) // port number should be even
218 {
219 PVMF_SDP_PARSER_LOGERROR((0, "SDPBaseMediaInfoParser::parseMediaInfo - Bad m= line format - port number is not even"));
220 return SDP_BAD_MEDIA_FORMAT;
221 }
222
223 mediaStr->setTransportProfile(memFrag);
224
225 //get the payload number
226 sptr = skip_whitespace(eptr, line_end_ptr);
227 if (sptr >= line_end_ptr)
228 {
229 PVMF_SDP_PARSER_LOGERROR((0, "SDPBaseMediaInfoParser::parseMediaInfo - Bad m= line format for payload number"));
230 return SDP_BAD_MEDIA_FORMAT;
231 }
232
233 while (eptr < line_end_ptr)
234 {
235 eptr = skip_to_whitespace(sptr, line_end_ptr);
236 if (eptr <= sptr)
237 {
238 PVMF_SDP_PARSER_LOGERROR((0, "SDPBaseMediaInfoParser::parseMediaInfo - Bad m= line format for payload number"));
239 return SDP_BAD_MEDIA_FORMAT;
240 }
241
242 uint32 payloadNumber; ;
243 if (PV_atoi(sptr, 'd', (eptr - sptr), payloadNumber) == true)
244 {
245 // Parse the payload number info only and see if there
246 // is any payload number in static range if yes rtpmap
247 // field may not be present for this
248 for (uint32 ii = 0; ii < mediaStr->getPayloadSpecificInfoVector().size(); ii++)
249 {
250 if (payloadNumber == mediaStr->getPayloadSpecificInfoVector()[ii]->getPayloadNumber())
251 {
252 // check if (FIRST_STATIC_PAYLOAD <= payloadNumber <= LAST_STATIC_PAYLOAD)
253 // since payloadNumber is unsigned and FIRST_STATIC_PAYLOAD == 0, only the upper
254 // boundary needs to be checked. Adding the lower boundary causes compiler warning.
255 if (payloadNumber <= LAST_STATIC_PAYLOAD)
256 a_rtpmap_found = true;
257 }
258 }
259 }
260 else
261 {
262 PVMF_SDP_PARSER_LOGERROR((0, "SDPBaseMediaInfoParser::parseMediaInfo - Bad m= line format for payload number"));
263 return SDP_BAD_MEDIA_FORMAT;
264 }
265
266 sptr = skip_whitespace(eptr, line_end_ptr);
267 eptr = sptr;
268 }
269 // No rtpmap will come if port is 0 in sip sdp
270 if (isSipSdp && suggestedPort == 0)
271 {
272 a_rtpmap_found = true;
273 }
274
275 }
276 break;
277 case 'a':
278 {
279 if (*(line_start_ptr + 1) != '=')
280 {
281 PVMF_SDP_PARSER_LOGERROR((0, "SDPBaseMediaInfoParser::parseMediaInfo - Bad a= line format - '=' missing"));
282 return SDP_BAD_MEDIA_FORMAT;
283 }
284
285 // parse through each field
286 const char *sptr1, *eptr1;
287 if (!oscl_strncmp(line_start_ptr, "a=rtpmap:", oscl_strlen("a=rtpmap:")))
288 {
289 //get the payload number
290 sptr1 = line_start_ptr + oscl_strlen("a=rtpmap:");
291 sptr1 = skip_whitespace(sptr1, line_end_ptr);
292
293 a_rtpmap_found = true;
294
295 if (sptr1 >= line_end_ptr)
296 {
297 PVMF_SDP_PARSER_LOGERROR((0, "SDPBaseMediaInfoParser::parseMediaInfo - Bad a=rtpmap line format"));
298 return SDP_BAD_MEDIA_RTP_MAP;
299 }
300 eptr1 = skip_to_whitespace(sptr1, line_end_ptr);
301 if (eptr1 <= sptr1)
302 {
303 PVMF_SDP_PARSER_LOGERROR((0, "SDPBaseMediaInfoParser::parseMediaInfo - Bad a=rtpmap line format"));
304 return SDP_BAD_MEDIA_RTP_MAP;
305 }
306 uint32 payloadNumber;
307 if (PV_atoi(sptr1, 'd', (eptr1 - sptr1), payloadNumber) == true)
308 {
309 int p;
310 if (!mediaStr->lookupPayloadNumber(payloadNumber, p))
311 {
312 break;
313 }
314 }
315 else
316 {
317 PVMF_SDP_PARSER_LOGERROR((0, "SDPBaseMediaInfoParser::parseMediaInfo - Bad a=rtpmap line format for payload number"));
318 return SDP_BAD_MEDIA_RTP_MAP;
319 }
320
321 // payloadNumber is present in the mediaInfo. get the payload
322 // Specific pointer corresponding to this payload
323 PayloadSpecificInfoTypeBase* payloadPtr =
324 mediaStr->getPayloadSpecificInfoTypePtr(payloadNumber);
325 if (payloadPtr == NULL)
326 {
327 PVMF_SDP_PARSER_LOGERROR((0, "SDPBaseMediaInfoParser::parseMediaInfo - Unable to get payload pointer for the payload"));
328 return SDP_PAYLOAD_MISMATCH;
329 }
330 PVMF_SDP_PARSER_LOGINFO((0, "SDPBaseMediaInfoParser::parseMediaInfo - processing payload number : %d", payloadNumber));
331
332 //get the MIME type and sample rate
333 sptr1 = skip_whitespace(eptr1, line_end_ptr);
334 if (sptr1 >= line_end_ptr)
335 {
336 PVMF_SDP_PARSER_LOGERROR((0, "SDPBaseMediaInfoParser::parseMediaInfo - Bad a=rtpmap line format for MIME Type & Sample rate"));
337 return SDP_BAD_MEDIA_RTP_MAP;
338 }
339
340 eptr1 = skip_to_whitespace(sptr1, line_end_ptr);
341 if (eptr1 <= sptr1)
342 {
343 PVMF_SDP_PARSER_LOGERROR((0, "SDPBaseMediaInfoParser::parseMediaInfo - Bad a=rtpmap line format"));
344 return SDP_BAD_MEDIA_RTP_MAP;
345 }
346 //int ii = 0;
347 const char *tmp_end_ptr = NULL;
348 /*
349 for( ii = 0; ii < (eptr1-sptr1); ii++ )
350 {
351 if(sptr1[ii] == '/')
352 {
353 tmp_end_ptr = sptr1 + ii;
354 break;
355 }
356 }
357 */
358 const char SDP_FWD_SLASH[] = "/";
359 tmp_end_ptr = oscl_strstr(sptr1, SDP_FWD_SLASH);
360 if (tmp_end_ptr == NULL)
361 {
362 PVMF_SDP_PARSER_LOGERROR((0, "SDPBaseMediaInfoParser::parseMediaInfo - Bad a=rtpmap line format - nothing after '/' "));
363 return SDP_BAD_MEDIA_RTP_MAP;
364 }
365 //The below mentioned code converts the non standard MIME type to standard MIME type.
366 //For eg. earlier we have MIME type "AMR" and according to standard it should be
367 //like "audio/AMR". so tho whole logic implements the same.
368 uint32 tempBufLen = 0;
369 char *tmpBuf = NULL;
370 const char SDP_NULL[] = "\0";
371
372 tempBufLen = oscl_strlen(mediaStr->getType()) + (tmp_end_ptr - sptr1) + 2;
373
374 // "OSCL_TRY(err, OSCL_ARRAY_NEW(char, tempBufLen)" is in separate function to avoid warnings
375 newTmpBuf(tempBufLen, &tmpBuf);
376 if (NULL == tmpBuf)
377 {
378 return SDP_NO_MEMORY;
379 }
380
381 oscl_strncpy(tmpBuf, mediaStr->getType(), (oscl_strlen(mediaStr->getType()) + 1));
382 oscl_strcat(tmpBuf, SDP_FWD_SLASH);
383 oscl_strncat(tmpBuf, sptr1, (tmp_end_ptr - sptr1));
384 oscl_strcat(tmpBuf, SDP_NULL);
385
386
387 memFrag.ptr = (void*)tmpBuf;
388 memFrag.len = oscl_strlen(tmpBuf);
389
390 mediaStr->setMIMEType(memFrag);
391 OSCL_ARRAY_DELETE(tmpBuf);
392 tmpBuf = NULL;
393 //Till here
394 tmp_end_ptr++;
395 if (tmp_end_ptr >= eptr1)
396 {
397 return SDP_BAD_MEDIA_RTP_MAP;
398 }
399 tmp_end_ptr = skip_whitespace(tmp_end_ptr, eptr1);
400 if (tmp_end_ptr >= eptr1)
401 {
402 return SDP_BAD_MEDIA_RTP_MAP;
403 }
404
405 OSCL_HeapString<SDPParserAlloc> restOfLine(tmp_end_ptr, eptr1 - tmp_end_ptr);
406 const char *another_slash = oscl_strstr(restOfLine.get_cstr(), SDP_FWD_SLASH);
407
408 uint32 sampleRate;
409 if (another_slash)
410 {
411 if (PV_atoi(restOfLine.get_cstr(), 'd', (another_slash - restOfLine.get_cstr()), sampleRate) == true)
412 {
413 payloadPtr->setSampleRate(sampleRate);
414 // There must be channel numbers after the 2nd forward slash
415 uint32 channels;
416 tmp_end_ptr = oscl_strstr(tmp_end_ptr, SDP_FWD_SLASH);
417 if (tmp_end_ptr == NULL)
418 {
419 PVMF_SDP_PARSER_LOGERROR((0, "SDPBaseMediaInfoParser::parseMediaInfo - Bad a=rtpmap line format for channel info"));
420 return SDP_BAD_MEDIA_RTP_MAP;
421 }
422 tmp_end_ptr++;
423 if (PV_atoi(tmp_end_ptr, 'd', (eptr1 - tmp_end_ptr), channels) == true)
424 {
425 payloadPtr->setNoOfChannels(channels);
426 }
427 else
428 {
429 PVMF_SDP_PARSER_LOGERROR((0, "SDPBaseMediaInfoParser::parseMediaInfo - Bad a=rtpmap line format for channel info"));
430 return SDP_BAD_MEDIA_RTP_MAP;
431 }
432 }
433 else
434 {
435 PVMF_SDP_PARSER_LOGERROR((0, "SDPBaseMediaInfoParser::parseMediaInfo - Bad a=rtpmap line format for channel info"));
436 return SDP_BAD_MEDIA_RTP_MAP;
437 }
438 }
439 else
440 {
441 if (PV_atoi(tmp_end_ptr, 'd', (eptr1 - tmp_end_ptr), sampleRate) == true)
442 {
443 payloadPtr->setSampleRate(sampleRate);
444 }
445 else
446 {
447 return SDP_BAD_MEDIA_RTP_MAP;
448 }
449 }
450 }
451 if (!oscl_strncmp(line_start_ptr, "a=control:", oscl_strlen("a=control:")))
452 {
453 sptr1 = line_start_ptr + oscl_strlen("a=control:");
454 sptr1 = skip_whitespace(sptr1, line_end_ptr);
455 a_control_found = true;
456 if (sptr1 >= line_end_ptr)
457 {
458 return SDP_BAD_MEDIA_CONTROL_FIELD;
459 }
460
461 memFrag.ptr = (void*)sptr1;
462 memFrag.len = (line_end_ptr - sptr1);
463 mediaStr->setControlURL(memFrag);
464
465 for (int ii = 0; ii < (line_end_ptr - sptr1); ii++)
466 {
467 if (sptr1[ii] == '=')
468 {
469 uint32 trackID;
470 sptr1 = skip_whitespace((sptr1 + ii + 1), line_end_ptr);
471 if (sptr1 >= line_end_ptr)
472 {
473 break;
474 }
475
476 if ((PV_atoi(sptr1, 'd', 1, trackID) == true))
477 {
478 mediaStr->setControlTrackID(trackID);
479 }
480 break;
481 }
482 }
483 }
484 if (!oscl_strncmp(line_start_ptr, "a=range:", oscl_strlen("a=range:")))
485 {
486 sptr1 = line_start_ptr + oscl_strlen("a=range:");
487 sptr1 = skip_whitespace(sptr1, line_end_ptr);
488
489 a_range_found = true;
490
491 if (sptr1 >= line_end_ptr)
492 {
493 return SDP_BAD_MEDIA_RANGE_FIELD;
494 }
495 parseRtspRange(sptr1, line_end_ptr - sptr1, *(mediaStr->getRtspRange()));
496 }
497 if (!oscl_strncmp(line_start_ptr, "a=depends_on:", oscl_strlen("a=depends_on:")))
498 {
499 sptr1 = line_start_ptr + oscl_strlen("a=depends_on:");
500 memFrag.ptr = (void*)sptr1;
501 memFrag.len = (line_end_ptr - sptr1);
502 mediaStr->setDependsonURL(memFrag);
503
504 for (int ii = 0; ii < (line_end_ptr - sptr1); ii++)
505 {
506 if (sptr1[ii] == '=')
507 {
508 uint32 trackID;
509 sptr1 = skip_whitespace((sptr1 + ii + 1), line_end_ptr);
510 if (sptr1 >= line_end_ptr)
511 {
512 break;
513 }
514
515 if ((PV_atoi(sptr1, 'd', 1, trackID) == true))
516 {
517 mediaStr->setDependsOnTrackID(trackID);
518 }
519 break;
520 }
521 }
522 }
523
524 //Random access denied added for 3rd party content random positioning - 01/08/02
525 StrPtrLen random_access("a=random_access_denied");
526 if (!oscl_strncmp(line_start_ptr, random_access.c_str(), random_access.length()))
527 {
528 mediaStr->setRandomAccessDenied(true);
529 }
530
531 StrPtrLen qoe_metrics("a=3GPP-QoE-Metrics:");
532 if (!oscl_strncmp(line_start_ptr, qoe_metrics.c_str(), qoe_metrics.length()))
533 {
534 const char *sptr;
535 sptr = line_start_ptr + qoe_metrics.length();
536 QoEMetricsType qMetrics;
537 oscl_memset(qMetrics.name, 0, 7);
538 qMetrics.rateFmt = QoEMetricsType::VAL;
539 qMetrics.rateVal = 0;
540 qMetrics.paramFmt = QoEMetricsType::IDIGIT;
541 qMetrics.paramExtIdigit = 0;
542
543 if (!parseQoEMetrics(sptr, line_end_ptr, qMetrics))
544 {
545 PVMF_SDP_PARSER_LOGERROR((0, "SDPBaseMediaInfoParser::parseMediaInfo - Bad a=3GPP-QoE-Metrics: line format"));
546 return SDP_BAD_MEDIA_FORMAT;
547 }
548 mediaStr->setQoEMetrics(qMetrics);
549
550
551 }
552 StrPtrLen predec("a=X-predecbufsize:");
553 if (!oscl_strncmp(line_start_ptr, predec.c_str(), predec.length()))
554 {
555 const char *sptr;
556 sptr = line_start_ptr + predec.length();
557 uint32 size;
558 if (!PV_atoi(sptr, 'd', (line_end_ptr - sptr), size))
559 {
560 PVMF_SDP_PARSER_LOGERROR((0, "SDPBaseMediaInfoParser::parseMediaInfo - Bad a=X-predecbufsize: line format"));
561 return SDP_BAD_MEDIA_FORMAT;
562 }
563 mediaStr->setPreDecBuffSize(size);
564 }
565
566 StrPtrLen initpredec("a=X-initpredecbufperiod:");
567 if (!oscl_strncmp(line_start_ptr, initpredec.c_str(), initpredec.length()))
568 {
569 const char *sptr;
570 sptr = line_start_ptr + initpredec.length();
571 uint32 period;
572 if (!PV_atoi(sptr, 'd', (line_end_ptr - sptr), period))
573 {
574 PVMF_SDP_PARSER_LOGERROR((0, "SDPBaseMediaInfoParser::parseMediaInfo - Bad a=X-initpredecbufperiod: line format"));
575 return SDP_BAD_MEDIA_FORMAT;
576 }
577 mediaStr->setInitPreDecBuffPeriod(period);
578 }
579
580 StrPtrLen initpostdec("a=X-initpostdecbufperiod:");
581 if (!oscl_strncmp(line_start_ptr, initpostdec.c_str(), initpostdec.length()))
582 {
583 const char *sptr;
584 sptr = line_start_ptr + initpostdec.length();
585 uint32 period;
586 if (!PV_atoi(sptr, 'd', (line_end_ptr - sptr), period))
587 {
588 PVMF_SDP_PARSER_LOGERROR((0, "SDPBaseMediaInfoParser::parseMediaInfo - Bad a=X-initpostdecbufperiod: line format"));
589 return SDP_BAD_MEDIA_FORMAT;
590 }
591 mediaStr->setInitPostDecBuffPeriod(period);
592 }
593
594 StrPtrLen decbyterate("a=X-decbyterate:");
595 if (!oscl_strncmp(line_start_ptr, decbyterate.c_str(),
596 decbyterate.length()))
597 {
598 const char *sptr;
599 sptr = line_start_ptr + decbyterate.length();
600 uint32 rate;
601 if (!PV_atoi(sptr, 'd', (line_end_ptr - sptr), rate))
602 {
603 PVMF_SDP_PARSER_LOGERROR((0, "SDPBaseMediaInfoParser::parseMediaInfo - Bad a=X-decbyterate: line format"));
604 return SDP_BAD_MEDIA_FORMAT;
605 }
606 mediaStr->setDecByteRate(rate);
607 }
608
609 StrPtrLen adapt_supp("a=3GPP-Adaptation-Support:");
610 if (!oscl_strncmp(line_start_ptr, adapt_supp.c_str(),
611 adapt_supp.length()))
612 {
613 const char *sptr = line_start_ptr + adapt_supp.length();
614 sptr = skip_whitespace_and_line_term(sptr, line_end_ptr);
615 uint32 frequency;
616 if (!PV_atoi(sptr, 'd', line_end_ptr - sptr, frequency))
617 {
618 PVMF_SDP_PARSER_LOGERROR((0, "SDPBaseMediaInfoParser::parseMediaInfo - Bad a=3GPP-Adaptation-Support: line format - frequency not correct"));
619 return SDP_BAD_MEDIA_FORMAT;
620 }
621 mediaStr->setReportFrequency(frequency);
622 }
623
624 StrPtrLen asset_info("a=3GPP-Asset-Information:");
625 if (!oscl_strncmp(line_start_ptr, asset_info.c_str(),
626 asset_info.length()))
627 {
628 const char *sptr = line_start_ptr + asset_info.length();
629 AssetInfoType assetInfo;
630 if (!parseAssetInfo(sptr, line_end_ptr, assetInfo))
631 {
632 PVMF_SDP_PARSER_LOGERROR((0, "SDPBaseMediaInfoParser::parseMediaInfo - Bad a=3GPP-Asset-Information: line format"));
633 return SDP_BAD_SESSION_FORMAT;
634 }
635
636 mediaStr->setAssetInfo(assetInfo);
637
638 }
639 StrPtrLen srtp("a=3GPP-SRTP-Config:");
640 if (!oscl_strncmp(line_start_ptr, srtp.c_str(),
641 srtp.length()))
642 {
643 const char *sptr = line_start_ptr + srtp.length();
644 const char *eptr;
645 sptr = skip_whitespace(sptr, line_end_ptr);
646 eptr = skip_to_whitespace(sptr, line_end_ptr);
647 memFrag.ptr = (void *)sptr;
648 memFrag.len = eptr - sptr;
649
650 mediaStr->setSRTPintg_nonce(memFrag);
651
652 eptr = eptr + 1;
653 sptr = eptr;
654 if (sptr >= line_end_ptr)
655 {
656 PVMF_SDP_PARSER_LOGERROR((0, "SDPBaseMediaInfoParser::parseMediaInfo - Bad a=3GPP-SRTP-Config: line format"));
657 return SDP_BAD_MEDIA_FORMAT;
658 }
659 eptr = skip_to_whitespace(eptr, line_end_ptr);
660 if (eptr >= line_end_ptr)
661 {
662 PVMF_SDP_PARSER_LOGERROR((0, "SDPBaseMediaInfoParser::parseMediaInfo - Bad a=3GPP-SRTP-Config: line format"));
663 return SDP_BAD_MEDIA_FORMAT;
664 }
665
666 memFrag.ptr = (void *)sptr;
667 memFrag.len = eptr - sptr;
668 mediaStr->setSRTPkey_salt(memFrag);
669
670 eptr = eptr + 1;
671 sptr = eptr;
672
673 if (!oscl_strncmp(sptr, "auth-tag-len=", oscl_strlen("auth-tag-len=")))
674 {
675 sptr = sptr + oscl_strlen("auth-tag-len=");
676 uint32 length;
677 if (!PV_atoi(sptr, 'd', 2, length))
678 {
679 PVMF_SDP_PARSER_LOGERROR((0, "SDPBaseMediaInfoParser::parseMediaInfo - Bad a=3GPP-SRTP-Config: line format for auth-tag-len= field"));
680 return SDP_BAD_MEDIA_FORMAT;
681 }
682 if ((length != 32) && (length != 80))
683 {
684 PVMF_SDP_PARSER_LOGERROR((0, "SDPBaseMediaInfoParser::parseMediaInfo - Bad a=3GPP-SRTP-Config: line format for auth-tag-len= field"));
685 return SDP_BAD_MEDIA_FORMAT;
686 }
687 else
688 mediaStr->setSRTPauth_tag_len(length);
689
690 }
691 else
692 {
693 memFrag.ptr = (void *)sptr;
694 memFrag.len = line_end_ptr - sptr;
695
696 mediaStr->setSRTPparam_ext(memFrag);
697
698
699 }
700
701
702 }
703 StrPtrLen rtcp_fb("a=rtcp-fb:");
704 if (!oscl_strncmp(line_start_ptr, rtcp_fb.c_str(), rtcp_fb.length()))
705 {
706 const char *sptr = line_start_ptr + rtcp_fb.length();
707 const char *eptr = skip_to_whitespace(sptr, line_end_ptr);
708
709 if (eptr >= line_end_ptr)
710 {
711 PVMF_SDP_PARSER_LOGERROR((0, "SDPBaseMediaInfoParser::parseMediaInfo - Bad a=rtcp-fb: line format"));
712 return SDP_BAD_MEDIA_FORMAT;
713 }
714
715 memFrag.ptr = (void *)sptr;
716 memFrag.len = eptr - sptr;
717 mediaStr->setrtcp_fb_pt(memFrag);
718
719 sptr = skip_whitespace(eptr, line_end_ptr);
720 eptr = skip_to_whitespace(sptr, line_end_ptr);
721
722 memFrag.ptr = (void *)sptr;
723 memFrag.len = eptr - sptr;
724 mediaStr->setrtcp_fb_val(memFrag);
725
726 if (eptr >= line_end_ptr)
727 break;
728
729 if (!oscl_strncmp(sptr, "trr-int", eptr - sptr))
730 {
731 sptr = skip_whitespace(eptr, line_end_ptr);
732 eptr = skip_to_line_term(sptr, line_end_ptr);
733 uint32 trr;
734 if (!PV_atoi(sptr, 'd', eptr - sptr, trr))
735 {
736 PVMF_SDP_PARSER_LOGERROR((0, "SDPBaseMediaInfoParser::parseMediaInfo - Bad a=rtcp-fb: line format for trr-int field"));
737 return SDP_BAD_MEDIA_FORMAT;
738 }
739
740 mediaStr->setrtcp_fb_trr_val(trr);
741 }
742 else
743 {
744 sptr = skip_whitespace(eptr, line_end_ptr);
745 eptr = skip_to_line_term(sptr, line_end_ptr);
746 memFrag.ptr = (void *)sptr;
747 memFrag.len = eptr - sptr;
748 mediaStr->setrtcp_fb_val_param(memFrag);
749
750 }
751
752
753 }
754 if (!oscl_strncmp(line_start_ptr, "a=alt:", oscl_strlen("a=alt:")))
755 {
756 line_start_ptr += oscl_strlen("a=alt:");
757 const char *end1 = line_start_ptr;
758 for (; *end1 != ':'; end1++);
759 uint32 id;
760 if (!PV_atoi(line_start_ptr, 'd' , end1 - line_start_ptr, id))
761 {
762 PVMF_SDP_PARSER_LOGERROR((0, "SDPBaseMediaInfoParser::parseMediaInfo - Bad ID in a=alt: line format"));
763 return SDP_BAD_MEDIA_ALT_ID;
764 }
765
766 //check if id is already present
767 Oscl_Vector<int, SDPParserAlloc> alt_track = mediaStr->getalternateTrackId();
768 bool found = false;
769 for (int ss = 0; ss < (int)alt_track.size(); ss++)
770 {
771 if (alt_track[ss] == (int)id)
772 found = true;
773 }
774 if (!found)
775 mediaStr->setalternateTrackId(id);
776 }
777 if (!oscl_strncmp(line_start_ptr, "a=maxprate:", oscl_strlen("a=maxprate:")))
778 {
779 line_start_ptr += oscl_strlen("a=maxprate:");
780 OsclFloat rate;
781 if (!PV_atof(line_start_ptr, line_end_ptr - line_start_ptr, rate))
782 {
783 PVMF_SDP_PARSER_LOGERROR((0, "SDPBaseMediaInfoParser::parseMediaInfo - Bad a=maxprate: line format for rate field"));
784 return SDP_BAD_MEDIA_FORMAT;
785 }
786 mediaStr->setMaxprate(rate);
787 }
788 if (!oscl_strncmp(line_start_ptr, "a=X-allowrecord", oscl_strlen("a=X-allowrecord")))
789 {
790 mediaStr->setAllowRecord(true);
791 }
792
793 }
794 break;
795 case 'b':
796 {
797 if (!oscl_strncmp(line_start_ptr, "b=AS:", oscl_strlen("b=AS:")))
798 {
799 const char *sptr;
800 sptr = line_start_ptr + oscl_strlen("b=AS:");
801 sptr = skip_whitespace(sptr, line_end_ptr);
802 if (sptr >= line_end_ptr)
803 {
804 PVMF_SDP_PARSER_LOGERROR((0, "SDPBaseMediaInfoParser::parseMediaInfo - Bad b=AS: line format"));
805 return SDP_BAD_MEDIA_FORMAT;
806 }
807
808 uint32 bitRate;
809 if (PV_atoi(sptr, 'd', (line_end_ptr - sptr), bitRate) == true)
810 {
811 mediaStr->setBitrate(1000*bitRate);
812 }
813 else
814 {
815 PVMF_SDP_PARSER_LOGERROR((0, "SDPBaseMediaInfoParser::parseMediaInfo - Bad b=AS: line format - bitrate incorrect"));
816 return SDP_BAD_MEDIA_FORMAT;
817 }
818 }
819 else if (!oscl_strncmp(line_start_ptr, "b=RS:", oscl_strlen("b=RS:")))
820 {
821 const char *sptr;
822 sptr = line_start_ptr + oscl_strlen("b=AS:");
823 sptr = skip_whitespace(sptr, line_end_ptr);
824 if (sptr >= line_end_ptr)
825 {
826 PVMF_SDP_PARSER_LOGERROR((0, "SDPBaseMediaInfoParser::parseMediaInfo - Bad b=RS: line format"));
827 return SDP_BAD_MEDIA_FORMAT;
828 }
829
830 uint32 rtcpBWSender;
831 if (PV_atoi(sptr, 'd', (line_end_ptr - sptr), rtcpBWSender) == true)
832 {
833 mediaStr->setRTCPSenderBitRate(rtcpBWSender);
834 }
835 else
836 {
837 PVMF_SDP_PARSER_LOGERROR((0, "SDPBaseMediaInfoParser::parseMediaInfo - Bad b=RS: line format - Sender Bitrate incorrect"));
838 return SDP_BAD_MEDIA_FORMAT;
839 }
840 }
841 else if (!oscl_strncmp(line_start_ptr, "b=RR:", oscl_strlen("b=RR:")))
842 {
843 const char *sptr;
844 sptr = line_start_ptr + oscl_strlen("b=AS:");
845 sptr = skip_whitespace(sptr, line_end_ptr);
846 if (sptr >= line_end_ptr)
847 {
848 PVMF_SDP_PARSER_LOGERROR((0, "SDPBaseMediaInfoParser::parseMediaInfo - Bad b=RR: line format"));
849 return SDP_BAD_MEDIA_FORMAT;
850 }
851
852 uint32 rtcpBWReceiver;
853 if (PV_atoi(sptr, 'd', (line_end_ptr - sptr), rtcpBWReceiver) == true)
854 {
855 mediaStr->setRTCPReceiverBitRate(rtcpBWReceiver);
856 }
857 else
858 {
859 PVMF_SDP_PARSER_LOGERROR((0, "SDPBaseMediaInfoParser::parseMediaInfo - Bad b=RR: line format - Receiver Bit rate incorrect"));
860 return SDP_BAD_MEDIA_FORMAT;
861 }
862 }
863 else if (!oscl_strncmp(line_start_ptr, "b=TIAS:", oscl_strlen("b=TIAS:")))
864 {
865 const char *sptr;
866 sptr = line_start_ptr + oscl_strlen("b=TIAS:");
867 sptr = skip_whitespace(sptr, line_end_ptr);
868 if (sptr >= line_end_ptr)
869 {
870 PVMF_SDP_PARSER_LOGERROR((0, "SDPBaseMediaInfoParser::parseMediaInfo - Bad b=T1AS: line format"));
871 return SDP_BAD_MEDIA_FORMAT;
872 }
873
874 uint32 bMod;
875 if (PV_atoi(sptr, 'd', (line_end_ptr - sptr), bMod) == true)
876 {
877 mediaStr->setBWtias(1000 * bMod);
878 }
879 else
880 {
881 PVMF_SDP_PARSER_LOGERROR((0, "SDPBaseMediaInfoParser::parseMediaInfo - Bad b=T1AS: line format - bMod incorrect"));
882 return SDP_BAD_MEDIA_FORMAT;
883 }
884 }
885 }
886 break;
887 case 'u':
888 {
889 PVMF_SDP_PARSER_LOGERROR((0, "SDPBaseMediaInfoParser::parseMediaInfo - u field not supported"));
890 return SDP_BAD_MEDIA_FORMAT;
891 }
892 case 'c':
893 {
894 if (*(line_start_ptr + 1) != '=')
895 {
896 PVMF_SDP_PARSER_LOGERROR((0, "SDPBaseMediaInfoParser::parseMediaInfo - Bad c= line format - '=' missing after c"));
897 return SDP_BAD_SESSION_FORMAT;
898 }
899
900 mediaStr->setCFieldStatus(true);
901
902 // parse through each field
903 const char *sptr, *eptr;
904
905 // get the connection network type
906 sptr = skip_whitespace(line_start_ptr + 2, line_end_ptr);
907 if (sptr >= line_end_ptr)
908 {
909 PVMF_SDP_PARSER_LOGERROR((0, "SDPBaseMediaInfoParser::parseMediaInfo - Bad c= line format - connection network type missing"));
910 return SDP_BAD_SESSION_FORMAT;
911 }
912
913 eptr = skip_to_whitespace(sptr, line_end_ptr);
914 if (eptr <= sptr)
915 {
916 PVMF_SDP_PARSER_LOGERROR((0, "SDPBaseMediaInfoParser::parseMediaInfo - Bad c= line format - part after connection network type missing"));
917 return SDP_BAD_SESSION_FORMAT;
918 }
919
920 memFrag.ptr = (void*)sptr;
921 memFrag.len = (eptr - sptr);
922 mediaStr->setCNetworkType(memFrag);
923
924 // get the address type
925 sptr = skip_whitespace(eptr, line_end_ptr);
926 if (sptr >= line_end_ptr)
927 {
928 PVMF_SDP_PARSER_LOGERROR((0, "SDPBaseMediaInfoParser::parseMediaInfo - Bad c= line format - address type missing"));
929 return SDP_BAD_SESSION_FORMAT;
930 }
931
932 eptr = skip_to_whitespace(sptr, line_end_ptr);
933 if (eptr <= sptr)
934 {
935 PVMF_SDP_PARSER_LOGERROR((0, "SDPBaseMediaInfoParser::parseMediaInfo - Bad c= line format - part after address type missing"));
936 return SDP_BAD_SESSION_FORMAT;
937 }
938 memFrag.ptr = (void*)sptr;
939 memFrag.len = (eptr - sptr);
940 mediaStr->setCAddressType(memFrag);
941
942 // get the address
943 sptr = skip_whitespace(eptr, line_end_ptr);
944 if (sptr >= line_end_ptr)
945 {
946 PVMF_SDP_PARSER_LOGERROR((0, "SDPBaseMediaInfoParser::parseMediaInfo - Bad c= line format - address missing"));
947 return SDP_BAD_SESSION_FORMAT;
948 }
949
950 eptr = skip_to_whitespace(sptr, line_end_ptr);
951 if (eptr < sptr)
952 {
953 PVMF_SDP_PARSER_LOGERROR((0, "SDPBaseMediaInfoParser::parseMediaInfo - Bad c= line format - part after address missing"));
954 return SDP_BAD_SESSION_FORMAT;
955 }
956 memFrag.ptr = (void*)sptr;
957 memFrag.len = (eptr - sptr);
958 mediaStr->setCAddress(memFrag);
959 uint32 len = OSCL_MIN((uint32)(eptr - sptr), oscl_strlen("IP4"));
960 if (oscl_strncmp(sptr, "IP4", len) == 0)
961 {
962 uint32 address;
963 const char *addrend = sptr;
964 for (; *addrend != '.'; ++addrend);
965
966 if (!PV_atoi(sptr, 'd', addrend - sptr, address))
967 {
968 PVMF_SDP_PARSER_LOGERROR((0, "SDPBaseMediaInfoParser::parseMediaInfo - Bad c= line format"));
969 return SDP_BAD_SESSION_FORMAT;
970 }
971
972 if (address >= 224 && address <= 239) //multicast address look for TTL
973 {
974 for (; (*sptr != '/') && (sptr < eptr); ++sptr);
975 if (sptr == eptr)
976 {
977 PVMF_SDP_PARSER_LOGERROR((0, "SDPBaseMediaInfoParser::parseMediaInfo - Bad c= line format"));
978 return SDP_BAD_SESSION_FORMAT; // no TTL found in multicast address.
979 }
980 else
981 {
982 uint32 ttl;
983 sptr = sptr + 1;
984 if (!PV_atoi(sptr, 'd', eptr - sptr, ttl))
985 {
986 PVMF_SDP_PARSER_LOGERROR((0, "SDPBaseMediaInfoParser::parseMediaInfo - Bad c= line format"));
987 return SDP_BAD_SESSION_FORMAT;
988 }
989 if (!(ttl <= 255))
990 {
991 PVMF_SDP_PARSER_LOGERROR((0, "SDPBaseMediaInfoParser::parseMediaInfo - Bad c= line format"));
992 return SDP_BAD_SESSION_FORMAT; // ttl out of range.
993 }
994
995 }
996
997 }
998 else // unicast address
999 {
1000 for (; (*sptr != '/') && (sptr < eptr); ++sptr);
1001 if (!oscl_strncmp(sptr, "/", 1))
1002 {
1003 PVMF_SDP_PARSER_LOGERROR((0, "SDPBaseMediaInfoParser::parseMediaInfo - Bad c= line format"));
1004 return SDP_BAD_SESSION_FORMAT; //unicast address can not have TTL.
1005 }
1006 }
1007
1008 if (eptr < line_end_ptr)
1009 {
1010 PVMF_SDP_PARSER_LOGERROR((0, "SDPBaseMediaInfoParser::parseMediaInfo - Bad c= line format"));
1011 return SDP_BAD_SESSION_FORMAT;
1012 }
1013 }
1014 //use "len" here since "IP4" and "IP6" have same lengths
1015 else if (oscl_strncmp(sptr, "IP6", len) == 0)
1016 {
1017 //TBD
1018 }
1019 break;
1020 }
1021
1022 default:
1023 {
1024 //skip a line we don't understand
1025 }
1026 break;
1027 }
1028 }
1029 current_start = line_end_ptr;
1030 }
1031
1032 mediaStr->setmediaTrackId(alt_id);
1033
1034 if (!alt_def_id && alt_id)
1035 {
1036 uint32 defaultId;
1037 getAltDefaultId(buff, buff + index, defaultId);
1038 if (defaultId != 0)
1039 mediaStr->setalternateTrackId(defaultId);
1040 else
1041 return SDP_BAD_MEDIA_ALT_ID;
1042 }
1043
1044 if (!a_control_found)
1045 {
1046 uint32 addr;
1047 connectionInfo ci;
1048 mediaStr->getConnectionInformation(&ci);
1049 PV_atoi(ci.connectionAddress.get_cstr(), 'd', addr);
1050 //224.0.0.0 through 239.255.255.255 represent class D network addresses
1051 //reserved for multicasting, which indicate a DVB connection
1052 if (addr >= 224 && addr <= 239)
1053 {
1054 uint32 id = mediaStr->getMediaInfoID();
1055 mediaStr->setControlTrackID(id);
1056 a_control_set = true;
1057 }
1058 }
1059
1060 /*
1061 * cannot assume that range is always going to be set at media level
1062 */
1063 if ((isSipSdp && a_rtpmap_found) || (!alt_def_id && alt_id))
1064 return SDP_SUCCESS;
1065 else if ((a_rtpmap_found && a_control_found) || (!alt_def_id && alt_id) || (a_control_set))
1066 return SDP_SUCCESS;
1067 else
1068 {
1069 PVMF_SDP_PARSER_LOGERROR((0, "SDPBaseMediaInfoParser::parseMediaInfo - Bad Media - no rtpmap and control present"));
1070 return SDP_BAD_MEDIA_FORMAT;
1071 }
1072 }
1073
1074
getAltDefaultId(const char * start,const char * end,uint32 & defaultId)1075 SDP_ERROR_CODE SDPBaseMediaInfoParser::getAltDefaultId(const char* start, const char *end, uint32 &defaultId)
1076 {
1077 const char *current_start = start;
1078 const char *line_start_ptr, *line_end_ptr;
1079 defaultId = 0;
1080 while (get_next_line(current_start, end,
1081 line_start_ptr, line_end_ptr))
1082 {
1083 switch (*line_start_ptr)
1084 {
1085 case 'a':
1086 {
1087 if (!oscl_strncmp(line_start_ptr, "a=alt-default-id:", oscl_strlen("a=alt-default-id:")))
1088 {
1089 line_start_ptr += oscl_strlen("a=alt-default-id:");
1090
1091 if (!PV_atoi(line_start_ptr, 'd', line_end_ptr - line_start_ptr, defaultId))
1092 return SDP_BAD_MEDIA_ALT_ID;
1093 else
1094 return SDP_SUCCESS;
1095
1096 }
1097 }
1098 break;
1099 default:
1100 break;
1101
1102 }
1103
1104 current_start = line_end_ptr;
1105 }
1106
1107 return SDP_SUCCESS;
1108 }
1109
setDependentMediaId(const char * start,int length,mediaInfo * mediaPtr,int mediaId)1110 SDP_ERROR_CODE SDPBaseMediaInfoParser::setDependentMediaId(const char *start, int length, mediaInfo *mediaPtr, int mediaId)
1111 {
1112 const char *startPtr = start;
1113 const char *endLine = start + length;
1114
1115 while (startPtr < endLine)
1116 {
1117 for (; *startPtr != '='; ++startPtr);
1118 startPtr = startPtr + 1;
1119 if (startPtr > endLine)
1120 return SDP_BAD_MEDIA_ALT_ID;
1121 const char *endPtr = startPtr;
1122 for (; (*endPtr != ';') && (endPtr != endLine); ++endPtr);
1123
1124 if (endPtr > endLine)
1125 return SDP_BAD_MEDIA_ALT_ID;
1126
1127 if (lookForMediaId(startPtr, endPtr, mediaId))
1128 {
1129 while (startPtr < endPtr)
1130 {
1131 const char *end = startPtr;
1132 for (; (*end != ',') && (end < endPtr) ; ++end);
1133 uint32 id;
1134 if (!PV_atoi(startPtr, 'd', end - startPtr, id))
1135 return SDP_BAD_MEDIA_ALT_ID;
1136 if ((int)id != mediaId)
1137 mediaPtr->setdependentTrackId(id);
1138 startPtr = end + 1;
1139 }
1140 }
1141 else
1142 startPtr = endPtr + 1;
1143 }
1144
1145 return SDP_SUCCESS;
1146
1147 }
1148
lookForMediaId(const char * startPtr,const char * endPtr,int mediaId)1149 bool SDPBaseMediaInfoParser::lookForMediaId(const char *startPtr, const char* endPtr, int mediaId)
1150 {
1151 const char *end = startPtr;
1152
1153 while (startPtr < endPtr)
1154 {
1155 for (; (*end != ',') && (end < endPtr); ++end);
1156 uint32 id;
1157 PV_atoi(startPtr, 'd' , end - startPtr, id);
1158 if ((int)id == mediaId)
1159 return true;
1160 end = end + 1;
1161 startPtr = end;
1162 }
1163
1164 return false;
1165 }
1166
1167