Skip to content

Instantly share code, notes, and snippets.

@kafecho
Created September 5, 2014 16:47
Show Gist options
  • Save kafecho/a42263cce99765b9a0aa to your computer and use it in GitHub Desktop.
Save kafecho/a42263cce99765b9a0aa to your computer and use it in GitHub Desktop.

Revisions

  1. kafecho created this gist Sep 5, 2014.
    98 changes: 98 additions & 0 deletions SdpParser.scala
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,98 @@
    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)

    }