Example #1
0
Boolean MediaSession::initializeWithSDP(char const* sdpDescription) {
  if (sdpDescription == NULL) return False;

  // Begin by processing all SDP lines until we see the first "m="
  char const* sdpLine = sdpDescription;
  char const* nextSDPLine;
  while (1) {
    if (!parseSDPLine(sdpLine, nextSDPLine)) return False;
    //##### We should really check for: 
    // - "a=control:" attributes (to set the URL for aggregate control)
    // - the correct SDP version (v=0)
    if (sdpLine[0] == 'm') break;
    sdpLine = nextSDPLine;
    if (sdpLine == NULL) break; // there are no m= lines at all 

    // Check for various special SDP lines that we understand:
    if (parseSDPLine_c(sdpLine)) continue;
    if (parseSDPAttribute_range(sdpLine)) continue;
    if (parseSDPAttribute_type(sdpLine)) continue;
    if (parseSDPAttribute_source_filter(sdpLine)) continue;
#ifdef SUPPORT_REAL_RTSP
    if (RealParseSDPAttributes(this, sdpLine)) continue;
#endif
  }
    
  while (sdpLine != NULL) {
    // We have a "m=" line, representing a new sub-session:
    MediaSubsession* subsession = new MediaSubsession(*this);
    if (subsession == NULL) {
      envir().setResultMsg("Unable to create new MediaSubsession");
      return False;
    }

    // Parse the line as "m=<medium_name> <client_portNum> RTP/AVP <fmt>"
    // or "m=<medium_name> <client_portNum>/<num_ports> RTP/AVP <fmt>"
    // (Should we be checking for >1 payload format number here?)#####
    char* mediumName = strDupSize(sdpLine); // ensures we have enough space
    char* protocolName = NULL;
    unsigned payloadFormat;
    if ((sscanf(sdpLine, "m=%s %hu RTP/AVP %u",
		mediumName, &subsession->fClientPortNum, &payloadFormat) == 3 ||
	 sscanf(sdpLine, "m=%s %hu/%*u RTP/AVP %u",
		mediumName, &subsession->fClientPortNum, &payloadFormat) == 3)
	&& payloadFormat <= 127) {
      protocolName = "RTP";
    } else if ((sscanf(sdpLine, "m=%s %hu UDP %u",
		       mediumName, &subsession->fClientPortNum, &payloadFormat) == 3 ||
		sscanf(sdpLine, "m=%s %hu udp %u",
		       mediumName, &subsession->fClientPortNum, &payloadFormat) == 3 ||
		sscanf(sdpLine, "m=%s %hu RAW/RAW/UDP %u",
		       mediumName, &subsession->fClientPortNum, &payloadFormat) == 3)
	       && payloadFormat <= 127) {
      // This is a RAW UDP source
      protocolName = "UDP";
    } else {
      // This "m=" line is bad; output an error message saying so:
      char* sdpLineStr;
      if (nextSDPLine == NULL) {
	sdpLineStr = (char*)sdpLine;
      } else {
	sdpLineStr = strDup(sdpLine);
	sdpLineStr[nextSDPLine-sdpLine] = '\0';
      }
      envir() << "Bad SDP \"m=\" line: " <<  sdpLineStr << "\n";
      if (sdpLineStr != (char*)sdpLine) delete[] sdpLineStr;

      delete[] mediumName;
      delete subsession;

      // Skip the following SDP lines, up until the next "m=":
      while (1) {
	sdpLine = nextSDPLine;
	if (sdpLine == NULL) break; // we've reached the end
	if (!parseSDPLine(sdpLine, nextSDPLine)) return False;

	if (sdpLine[0] == 'm') break; // we've reached the next subsession
      }
      continue;
    }

    // Insert this subsession at the end of the list:
    if (fSubsessionsTail == NULL) {
      fSubsessionsHead = fSubsessionsTail = subsession;
    } else {
      fSubsessionsTail->setNext(subsession);
      fSubsessionsTail = subsession;
    }

    subsession->serverPortNum = subsession->fClientPortNum; // by default

    char const* mStart = sdpLine;
    subsession->fSavedSDPLines = strDup(mStart);

    subsession->fMediumName = strDup(mediumName);
    delete[] mediumName;
    subsession->fProtocolName = strDup(protocolName);
    subsession->fRTPPayloadFormat = payloadFormat;

    // Process the following SDP lines, up until the next "m=":
    while (1) {
      sdpLine = nextSDPLine;
      if (sdpLine == NULL) break; // we've reached the end
      if (!parseSDPLine(sdpLine, nextSDPLine)) return False;

      if (sdpLine[0] == 'm') break; // we've reached the next subsession

      // Check for various special SDP lines that we understand:
      if (subsession->parseSDPLine_c(sdpLine)) continue;
      if (subsession->parseSDPAttribute_rtpmap(sdpLine)) continue;
      if (subsession->parseSDPAttribute_control(sdpLine)) continue;
      if (subsession->parseSDPAttribute_range(sdpLine)) continue;
      if (subsession->parseSDPAttribute_fmtp(sdpLine)) continue;
      if (subsession->parseSDPAttribute_source_filter(sdpLine)) continue;
      if (subsession->parseSDPAttribute_x_mct_slap(sdpLine)) continue;
      if (subsession->parseSDPAttribute_x_dimensions(sdpLine)) continue;
      if (subsession->parseSDPAttribute_x_framerate(sdpLine)) continue;
#ifdef SUPPORT_REAL_RTSP
      if (RealParseSDPAttributes(subsession, sdpLine)) continue;
#endif

      // (Later, check for malformed lines, and other valid SDP lines#####)
    }
    if (sdpLine != NULL) subsession->fSavedSDPLines[sdpLine-mStart] = '\0';

    // If we don't yet know the codec name, try looking it up from the
    // list of static payload types:
    if (subsession->fCodecName == NULL) {
      subsession->fCodecName
	= lookupPayloadFormat(subsession->fRTPPayloadFormat,
			      subsession->fRTPTimestampFrequency,
			      subsession->fNumChannels);
      if (subsession->fCodecName == NULL) {
	char typeStr[20];
	sprintf(typeStr, "%d", subsession->fRTPPayloadFormat);
	envir().setResultMsg("Unknown codec name for RTP payload type ",
			     typeStr);
	return False;
      }
    }

    // If we don't yet know this subsession's RTP timestamp frequency
    // (because it uses a dynamic payload type and the corresponding
    // SDP "rtpmap" attribute erroneously didn't specify it),
    // then guess it now:
    if (subsession->fRTPTimestampFrequency == 0) {
      subsession->fRTPTimestampFrequency
	= guessRTPTimestampFrequency(subsession->fMediumName,
				     subsession->fCodecName);
    }
  }

  return True;
}