Skip to content

Instantly share code, notes, and snippets.

@kafecho
Created September 5, 2014 16:47
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kafecho/a42263cce99765b9a0aa to your computer and use it in GitHub Desktop.
Save kafecho/a42263cce99765b9a0aa to your computer and use it in GitHub Desktop.
Initial work on Scala parser combinators for reading sdp (session description protocol) files.
package org.kafecho.learning.parser
import scala.util.parsing.combinator.RegexParsers
import java.net.URI
sealed trait SdpValue
sealed trait Username
case class UserLogin(login: String) extends Username
case object UserIdsNotSupported extends Username
sealed trait Media
case object Audio extends Media
case object Video extends Media
case object Text extends Media
case object Application extends Media
sealed trait Attribute
case class BinaryAttribute(value: String) extends Attribute
case class KeyValueAttribute(key: String, value: String) extends Attribute
case class ProtocolVersion(version: Long) extends SdpValue
case class Origin(username: Username, sessionId: Long, sessionVersion: Long, netType: String, addrType: String, unicastAddress: Option[String]) extends SdpValue
case class SessionName(name: String) extends SdpValue
case class Information(information: String) extends SdpValue
case class Protocol(protocol: String)
case class MediaField(media: Media, port: Long, protocol: Protocol, payloadType: Long)
/** Prototype parser for the Session Description Protocol.
* See http://tools.ietf.org/html/rfc4566.html#page-39
* Also see http://www.regular-expressions.info/posixbrackets.html for some help on regexes.
*/
class SdpParser extends RegexParsers {
def nonWsString: Parser[String] = """\p{Graph}+""".r
def number: Parser[Long] = """\p{Digit}+""".r ^^ { _.toLong }
def text: Parser[String] = """\p{Print}+""".r
def username: Parser[Username] = ("-" | nonWsString) ^^ {
case "-" => UserIdsNotSupported
case s: String => UserLogin(s)
}
def netType: Parser[String] = "IN"
def addrType: Parser[String] = "IP4|IP6".r
def media: Parser[Media] = ("video" | "audio" | "text" | "application") ^^ {
case "video" => Video
case "audio" => Audio
case "text" => Text
case "application" => Application
}
val token = """( \x21 | [\x23-\x27]|[\x2A-\x2B]|[\x2D-\x2E]|[\x30-\x39]|[\x41-\x5A]|[\x5E-\x7E])+""".r
def protocolVersionField: Parser[ProtocolVersion] = "v=" ~ number ^^ { case _ ~ n => ProtocolVersion(n) }
def originField: Parser[Origin] = ("o=" ~ username ~ number ~ number ~ netType ~ addrType ~ opt(nonWsString)) ^^ {
case _ ~ username ~ sessionId ~ sessionVersion ~ netType ~ addrType ~ unicastAddress =>
Origin(username, sessionId, sessionVersion, netType, addrType, unicastAddress)
}
def sessionNameField: Parser[SessionName] = ("s=" ~ text) ^^ { case _ ~ text => SessionName(text) }
def informationField: Parser[Information] = ("i=" ~ text) ^^ { case _ ~ text => Information(text) }
def uriField : Parser[URI] = ("u=" ~ text) ^^ { case _ ~ s => new URI(s)}
def protocol : Parser[Protocol] = ("""RTP/AVP""" | "udp") ^^ { s => Protocol(s) }
def mediaField : Parser[MediaField] = ("m=" ~ media ~ number ~ protocol ~ number) ^^ { case _ ~ media ~ port ~ protocol ~ payloadType =>
MediaField(media, port, protocol, payloadType)
}
def keyValueAttribute : Parser[Attribute]= ( token ~ ":" ~ nonWsString ) ^^ { case key ~ ":" ~ value => KeyValueAttribute(key, value)}
def binaryAttribute: Parser[Attribute]= nonWsString ^^ { s => BinaryAttribute(s)}
def attributeField : Parser[List[Attribute]] = "a=" ~ rep(keyValueAttribute | binaryAttribute) ^^ { case _ ~ l => l }
def mediaDescriptions: Parser[Any] = rep(mediaField ~ rep (attributeField))
}
object SdpParser extends App{
val src = """
m=audio 49170 RTP/AVP 0
m=audio 49170 RTP/AVP 0
a=rtpmap:99 h263-1998/90000"""
val parser = new SdpParser
val parseResult = parser.parseAll(parser.mediaDescriptions, src)
println (parseResult)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment