All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.restcomm.media.sdp.SessionDescriptionParser Maven / Gradle / Ivy

/*
 * TeleStax, Open Source Cloud Communications
 * Copyright 2011-2014, Telestax Inc and individual contributors
 * by the @authors tag.
 *
 * This program is free software: you can redistribute it and/or modify
 * under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation; either version 3 of
 * the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see 
 *
 */

package org.restcomm.media.sdp;

import org.restcomm.media.sdp.attributes.ConnectionModeAttribute;
import org.restcomm.media.sdp.attributes.FormatParameterAttribute;
import org.restcomm.media.sdp.attributes.MaxPacketTimeAttribute;
import org.restcomm.media.sdp.attributes.PacketTimeAttribute;
import org.restcomm.media.sdp.attributes.RtpMapAttribute;
import org.restcomm.media.sdp.attributes.SsrcAttribute;
import org.restcomm.media.sdp.dtls.attributes.FingerprintAttribute;
import org.restcomm.media.sdp.dtls.attributes.SetupAttribute;
import org.restcomm.media.sdp.fields.AttributeField;
import org.restcomm.media.sdp.fields.ConnectionField;
import org.restcomm.media.sdp.fields.MediaDescriptionField;
import org.restcomm.media.sdp.fields.OriginField;
import org.restcomm.media.sdp.fields.SessionNameField;
import org.restcomm.media.sdp.fields.TimingField;
import org.restcomm.media.sdp.fields.VersionField;
import org.restcomm.media.sdp.format.AVProfile;
import org.restcomm.media.sdp.format.RTPFormat;
import org.restcomm.media.sdp.ice.attributes.CandidateAttribute;
import org.restcomm.media.sdp.ice.attributes.IceLiteAttribute;
import org.restcomm.media.sdp.ice.attributes.IcePwdAttribute;
import org.restcomm.media.sdp.ice.attributes.IceUfragAttribute;
import org.restcomm.media.sdp.rtcp.attributes.RtcpAttribute;
import org.restcomm.media.sdp.rtcp.attributes.RtcpMuxAttribute;

/**
 * Parses an SDP text description into a {@link SessionDescription} object.
 * 
 * @author Henrique Rosa ([email protected])
 *
 */
public class SessionDescriptionParser {

	private static final String NEWLINE = "\n";
	private static final String PARSE_ERROR = "Cannot parse SDP: ";
	private static final String PARSE_ERROR_EMPTY = PARSE_ERROR + "empty";

	private static final SdpParserPipeline PARSERS = new SdpParserPipeline();

	public static SessionDescription parse(String text) throws SdpException {

		if (text == null || text.isEmpty()) {
			throw new SdpException(PARSE_ERROR_EMPTY);
		}

		SdpParsingInfo info = new SdpParsingInfo();

		// Process each line of SDP
		String[] lines = text.split(NEWLINE);
		for (String line : lines) {
			try {
				// Get type of field to check whether its an sdp attribute or
				// not
				char fieldType = line.charAt(0);
				switch (fieldType) {
				case AttributeField.FIELD_TYPE:
					// The field is an attribute
					// Get the type of attribute so we can invoke the right
					// parser
					int separator = line
							.indexOf(AttributeField.ATTRIBUTE_SEPARATOR);
					String attributeType = (separator == -1) ? line
							.substring(2).trim() : line.substring(2, separator);

					// Get the right parser for the attribute and parse the text
					SdpParser attributeParser = PARSERS
							.getAttributeParser(attributeType);
					if (attributeParser != null) {
						convertAndApplyAttribute(attributeParser.parse(line),
								info);
					}
					break;
				default:
					// Get the right parser for the field and parse the text
					SdpParser fieldParser = PARSERS
							.getFieldParser(fieldType);
					if (fieldParser != null) {
						convertAndApplyField(fieldParser.parse(line), info);
					}
					break;
				}
			} catch (Exception e) {
				throw new SdpException("Could not parse SDP: " + line, e);
			}
		}
		return info.sdp;
	}

	private static void convertAndApplyField(SdpField field, SdpParsingInfo info) {
		switch (field.getFieldType()) {
		case VersionField.FIELD_TYPE:
			info.sdp.setVersion((VersionField) field);
			break;

		case OriginField.FIELD_TYPE:
			info.sdp.setOrigin((OriginField) field);
			break;

		case SessionNameField.FIELD_TYPE:
			info.sdp.setSessionName((SessionNameField) field);
			break;

		case TimingField.FIELD_TYPE:
			info.sdp.setTiming((TimingField) field);
			break;

		case ConnectionField.FIELD_TYPE:
			if (info.media == null) {
				info.sdp.setConnection((ConnectionField) field);
			} else {
				info.media.setConnection((ConnectionField) field);
			}
			break;

		case MediaDescriptionField.FIELD_TYPE:
			info.media = (MediaDescriptionField) field;
			info.sdp.addMediaDescription(info.media);
			info.media.setSession(info.sdp);
			break;

		default:
			// Ignore unsupported type
			break;
		}
	}

	private static void convertAndApplyAttribute(AttributeField attribute,
			SdpParsingInfo info) {
		switch (attribute.getKey()) {
		case RtpMapAttribute.ATTRIBUTE_TYPE:
			info.format = (RtpMapAttribute) attribute;
			info.media.addFormat(info.format);
			break;

		case FormatParameterAttribute.ATTRIBUTE_TYPE:
		    FormatParameterAttribute fmtp = (FormatParameterAttribute) attribute;
		    
		    if(info.format == null) {
		        // Format unspecified on SDP. Load it manually
		        RTPFormat format = AVProfile.getFormat(fmtp.getFormat());
		        if(format == null) {
		            // Unsupported codec. Drop it.
		            break;
		        } else {
		            info.format = new RtpMapAttribute(format.getID(), format.getFormat().getName().toString(), format.getClockRate(), RtpMapAttribute.DEFAULT_CODEC_PARAMS);
		        }
		    }
		    info.format.setParameters((FormatParameterAttribute) attribute);
			break;

		case PacketTimeAttribute.ATTRIBUTE_TYPE:
			info.media.setPtime((PacketTimeAttribute) attribute);
			break;

		case MaxPacketTimeAttribute.ATTRIBUTE_TYPE:
			info.media.setMaxptime((MaxPacketTimeAttribute) attribute);
			break;

		case ConnectionModeAttribute.SENDONLY:
		case ConnectionModeAttribute.RECVONLY:
		case ConnectionModeAttribute.SENDRECV:
		case ConnectionModeAttribute.INACTIVE:
			if (info.media == null) {
				info.sdp.setConnectionMode((ConnectionModeAttribute) attribute);
			} else {
				info.media
						.setConnectionMode((ConnectionModeAttribute) attribute);
			}
			break;

		case RtcpAttribute.ATTRIBUTE_TYPE:
			info.media.setRtcp((RtcpAttribute) attribute);
			break;

		case RtcpMuxAttribute.ATTRIBUTE_TYPE:
			info.media.setRtcpMux((RtcpMuxAttribute) attribute);
			break;

		case IceLiteAttribute.ATTRIBUTE_TYPE:
			info.sdp.setIceLite((IceLiteAttribute) attribute);
			break;

		case IceUfragAttribute.ATTRIBUTE_TYPE:
			if (info.media == null) {
				info.sdp.setIceUfrag((IceUfragAttribute) attribute);
			} else {
				info.media.setIceUfrag((IceUfragAttribute) attribute);
			}
			break;

		case IcePwdAttribute.ATTRIBUTE_TYPE:
			if (info.media == null) {
				info.sdp.setIcePwd((IcePwdAttribute) attribute);
			} else {
				info.media.setIcePwd((IcePwdAttribute) attribute);
			}
			break;

		case CandidateAttribute.ATTRIBUTE_TYPE:
			info.media.addCandidate((CandidateAttribute) attribute);
			break;

		case SetupAttribute.ATTRIBUTE_TYPE:
			if (info.media == null) {
				info.sdp.setSetup((SetupAttribute) attribute);
			} else {
				info.media.setSetup((SetupAttribute) attribute);
			}
			break;

		case FingerprintAttribute.ATTRIBUTE_TYPE:
			if (info.media == null) {
				info.sdp.setFingerprint((FingerprintAttribute) attribute);
			} else {
				info.media.setFingerprint((FingerprintAttribute) attribute);
			}
			break;

		case SsrcAttribute.ATTRIBUTE_TYPE:
			SsrcAttribute ssrc = (SsrcAttribute) attribute;
			SsrcAttribute ssrcAttribute = info.media.getSsrc();
			if (ssrcAttribute == null) {
				info.media.setSsrc(ssrc);
			} else {
				ssrcAttribute.addAttribute(ssrc.getLastAttribute(),
						ssrc.getLastValue());
			}
			break;

		default:
			break;
		}
	}

	private static class SdpParsingInfo {

		final SessionDescription sdp;
		MediaDescriptionField media;
		RtpMapAttribute format;

		public SdpParsingInfo() {
			this.sdp = new SessionDescription();
		}

	}

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy