/* This file is part of Peers, a java SIP softphone. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Copyright 2007, 2008, 2009, 2010 Yohann Martineau */ package com.genersoft.iot.vmp.gb28181.sdp; import java.io.BufferedReader; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStreamReader; import java.net.InetAddress; import java.util.ArrayList; import java.util.Hashtable; import java.util.List; public class SdpParser { public SessionDescription parse(byte[] body) throws IOException { if (body == null || body.length == 0) { return null; } ByteArrayInputStream in = new ByteArrayInputStream(body); InputStreamReader inputStreamReader = new InputStreamReader(in); BufferedReader reader = new BufferedReader(inputStreamReader); SessionDescription sessionDescription = new SessionDescription(); //version String line = reader.readLine(); if (line.length() < 3) { return null; } if (line.charAt(0) != RFC4566_28181.TYPE_VERSION || line.charAt(1) != RFC4566_28181.SEPARATOR || line.charAt(2) != RFC4566_28181.VERSION) { return null; } //origin line = reader.readLine(); if (line.length() < 3) { return null; } if (line.charAt(0) != RFC4566_28181.TYPE_ORIGIN || line.charAt(1) != RFC4566_28181.SEPARATOR) { return null; } line = line.substring(2); String[] originArr = line.split(" "); if (originArr == null || originArr.length != 6) { return null; } sessionDescription.setUsername(originArr[0]); sessionDescription.setId(Long.parseLong(originArr[1])); sessionDescription.setVersion(Long.parseLong(originArr[2])); sessionDescription.setIpAddress(InetAddress.getByName(originArr[5])); //name line = reader.readLine(); if (line.length() < 3) { return null; } if (line.charAt(0) != RFC4566_28181.TYPE_SUBJECT || line.charAt(1) != RFC4566_28181.SEPARATOR) { return null; } sessionDescription.setName(line.substring(2)); //session connection and attributes Hashtable sessionAttributes = new Hashtable(); sessionDescription.setAttributes(sessionAttributes); while ((line = reader.readLine()) != null && line.charAt(0) != RFC4566_28181.TYPE_MEDIA) { if (line.length() > 3 && line.charAt(0) == RFC4566_28181.TYPE_CONNECTION && line.charAt(1) == RFC4566_28181.SEPARATOR) { String connection = parseConnection(line.substring(2)); if (connection == null) { continue; } sessionDescription.setIpAddress(InetAddress.getByName(connection)); } else if (line.length() > 3 && line.charAt(0) == RFC4566_28181.TYPE_ATTRIBUTE && line.charAt(1) == RFC4566_28181.SEPARATOR) { String value = line.substring(2); int pos = value.indexOf(RFC4566_28181.ATTR_SEPARATOR); if (pos > -1) { sessionAttributes.put(value.substring(0, pos), value.substring(pos + 1)); } else { sessionAttributes.put(value, ""); } } } if (line == null) { return null; } //we are at the first media line ArrayList mediaLines = new ArrayList(); do { if (line.length() < 2) { return null; } if (line.charAt(1) != RFC4566_28181.SEPARATOR) { return null; } if (line.charAt(0) == RFC4566_28181.TYPE_SSRC) { sessionDescription.setSsrc(line.length() >=2 ?line.substring(2):""); }else if (line.charAt(0) == RFC4566_28181.TYPE_MEDIA_DES) { sessionDescription.setGbMediaDescriptions(line.length() >=2 ?line.substring(2):""); }else { SdpLine mediaLine = new SdpLine(); mediaLine.setType(line.charAt(0)); mediaLine.setValue(line.substring(2)); mediaLines.add(mediaLine); } } while ((line = reader.readLine()) != null ); ArrayList mediaDescriptions = new ArrayList(); sessionDescription.setMediaDescriptions(mediaDescriptions); for (SdpLine sdpLine : mediaLines) { MediaDescription mediaDescription; if (sdpLine.getType() == RFC4566_28181.TYPE_MEDIA) { String[] mediaArr = sdpLine.getValue().split(" "); if (mediaArr == null || mediaArr.length < 4) { return null; } mediaDescription = new MediaDescription(); mediaDescription.setType(mediaArr[0]); //TODO manage port range mediaDescription.setPort(Integer.parseInt(mediaArr[1])); mediaDescription.setAttributes(new Hashtable()); List codecs = new ArrayList(); for (int i = 3; i < mediaArr.length; ++i) { int payloadType = Integer.parseInt(mediaArr[i]); Codec codec = new Codec(); codec.setPayloadType(payloadType); codec.setName("unsupported"); codecs.add(codec); } mediaDescription.setCodecs(codecs); mediaDescriptions.add(mediaDescription); } else { mediaDescription = mediaDescriptions.get(mediaDescriptions.size() - 1); String sdpLineValue = sdpLine.getValue(); if (sdpLine.getType() == RFC4566_28181.TYPE_CONNECTION) { String ipAddress = parseConnection(sdpLineValue); mediaDescription.setIpAddress(InetAddress.getByName(ipAddress)); } else if (sdpLine.getType() == RFC4566_28181.TYPE_ATTRIBUTE) { Hashtable attributes = mediaDescription.getAttributes(); int pos = sdpLineValue.indexOf(RFC4566_28181.ATTR_SEPARATOR); if (pos > -1) { String name = sdpLineValue.substring(0, pos); String value = sdpLineValue.substring(pos + 1); pos = value.indexOf(" "); if (pos > -1) { int payloadType; try { payloadType = Integer.parseInt(value.substring(0, pos)); List codecs = mediaDescription.getCodecs(); for (Codec codec: codecs) { if (codec.getPayloadType() == payloadType) { value = value.substring(pos + 1); pos = value.indexOf("/"); if (pos > -1) { value = value.substring(0, pos); codec.setName(value); } break; } } } catch (NumberFormatException e) { attributes.put(name, value); } } else { attributes.put(name, value); } } else { attributes.put(sdpLineValue, ""); } } } } sessionDescription.setMediaDescriptions(mediaDescriptions); for (MediaDescription description : mediaDescriptions) { if (description.getIpAddress() == null) { InetAddress sessionAddress = sessionDescription.getIpAddress(); if (sessionAddress == null) { return null; } description.setIpAddress(sessionAddress); } } return sessionDescription; } private String parseConnection(String line) { String[] connectionArr = line.split(" "); if (connectionArr == null || connectionArr.length != 3) { return null; } return connectionArr[2]; } }