扩展resiproacte的SdpContent以支持ICE

来源:互联网 发布:网络层协议有哪些作用 编辑:程序博客网 时间:2024/04/27 23:47

下面对resiproacte的SdpContents.h /SdpContents.cpp两个文件进行修改以支持ICE.修改部分以'larrin'字样标注。

SdpContents.h
==============================================

#if !defined(RESIP_SDPCONTENTS_HXX)
#define RESIP_SDPCONTENTS_HXX
 
//Begin by larrin
//
// Extend SdpContent as ICE description.
// a=ice-pwd:$RPASS
// m=audio $STUN-PUB-4.PORT RTP/AVP 0
// a=rtpmap:0 PCMU/8000
// a=rtcp:$STUN-PUB-5.PORT
// a=candidate $R1 1 UDP 1.0 $R-PUB-1.IP $R-PUB-1.PORT
// a=candidate $R1 2 UDP 1.0 $R-PUB-2.IP $R-PUB-2.PORT
// a=candidate $R2 1 UDP 0.3 $STUN-PUB-4.IP $STUN-PUB-4.PORT
// a=candidate $R2 2 UDP 0.3 $STUN-PUB-5.IP $STUN-PUB-5.PORT
//
 
#include <vector>
#include <list>
#include <iosfwd>
 
#include "resip/stack/Contents.hxx"
#include "resip/stack/Uri.hxx"
#include "rutil/Data.hxx"
#include "rutil/HashMap.hxx"
#include "rutil/HeapInstanceCounter.hxx"
 
namespace resip
{
 
class SdpContents;
 
class AttributeHelper
{
   public:
      RESIP_HeapCount(AttributeHelper);
      AttributeHelper();
      AttributeHelper(const AttributeHelper& rhs);
      AttributeHelper& operator=(const AttributeHelper& rhs);
 
      bool exists(const Data& key) const;
      const std::list<Data>& getValues(const Data& key) const;
      std::ostream& encode(std::ostream& s) const;
      void parse(ParseBuffer& pb);
      void addAttribute(const Data& key, const Data& value = Data::Empty);
      void clearAttribute(const Data& key);
 
      std::list<Data> & get_candidates()
      {
          return mCandidates;
      }
 
   private:
      HashMap< Data, std::list<Data> > mAttributes;
 
      //Add by larrin for candidate
      std::list<Data> mCandidates;
      //End by larrin
};
 
class SdpContents : public Contents
{
   public:
      RESIP_HeapCount(SdpContents);
      typedef enum {IP4=1, IP6} AddrType;
      static const SdpContents Empty;
 
      class Session;
 
      class Session
      {
         public:
            class Medium;
 
            class Codec
            {
               public:
                  Codec() : mName(), mRate(0), mPayloadType(-1) {}
                  Codec(const Data& name, unsigned long rate, const Data& parameters = Data::Empty);
                  Codec(const Data& name, int payloadType, int rate=8000);
                  Codec(const Codec& rhs);
                  Codec& operator=(const Codec& codec);
 
                  void parse(ParseBuffer& pb,
                             const SdpContents::Session::Medium& medium,
                             int payLoadType);
 
                  const Data& getName() const;
                  int getRate() const;
 
                  int payloadType() const {return mPayloadType;}
                  int& payloadType() {return mPayloadType;}
 
                  const Data& parameters() const {return mParameters;}
                  Data& parameters() {return mParameters;}
 
                  static const Codec ULaw_8000;
                  static const Codec ALaw_8000;
                  static const Codec G729_8000;
                  static const Codec G723_8000;
                  static const Codec GSM_8000;
                  static const Codec TelephoneEvent;
                  static const Codec FrfDialedDigit;
 
                  typedef HashMap<int, Codec> CodecMap;
                  // "static" payload types as defined in RFC 3551.
                  // Maps payload type (number) to Codec definition.
                  static CodecMap& getStaticCodecs();
 
                  friend bool operator==(const Codec&, const Codec&);
 
               private:
                  Data mName;
                  unsigned long mRate;
                  int mPayloadType;
                  Data mParameters;
 
                  static std::auto_ptr<CodecMap> sStaticCodecs;
                  static bool sStaticCodecsCreated;
                  friend std::ostream& operator<<(std::ostream&, const Codec&);
            };
 
            class Origin
            {
               public:
                  Origin(const Data& user,
                         const UInt64& sessionId,
                         const UInt64& version,
                         AddrType addr,
                         const Data& address);
                  Origin(const Origin& rhs);
                  Origin& operator=(const Origin& rhs);
 
                  void parse(ParseBuffer& pb);
                  std::ostream& encode(std::ostream&) const;
 
                  const UInt64& getSessionId() const {return mSessionId;}
                  UInt64& getSessionId() { return mSessionId; }
 
                  const UInt64& getVersion() const {return mVersion;}
                  UInt64& getVersion() { return mVersion; }
                  const Data& user() const {return mUser;}
                  Data& user() {return mUser;}
                  AddrType getAddressType() const {return mAddrType;}
                  const Data& getAddress() const {return mAddress;}
                  void setAddress(const Data& host, AddrType type = IP4);
 
               private:
                  Origin();
 
                  Data mUser;
                  UInt64 mSessionId;
                  UInt64 mVersion;
                  AddrType mAddrType;
                  Data mAddress;
 
                  friend class Session;
            };
 
            class Email
            {
               public:
                  Email(const Data& address,
                        const Data& freeText);
 
                  Email(const Email& rhs);
                  Email& operator=(const Email& rhs);
 
                  void parse(ParseBuffer& pb);
                  std::ostream& encode(std::ostream&) const;
 
                  const Data& getAddress() const {return mAddress;}
                  const Data& getFreeText() const {return mFreeText;}
 
               private:
                  Email() {}
 
                  Data mAddress;
                  Data mFreeText;
 
                  friend class Session;
            };
 
            class Phone
            {
               public:
                  Phone(const Data& number,
                        const Data& freeText);
                  Phone(const Phone& rhs);
                  Phone& operator=(const Phone& rhs);
 
                  void parse(ParseBuffer& pb);
                  std::ostream& encode(std::ostream&) const;
 
                  const Data& getNumber() const {return mNumber;}
                  const Data& getFreeText() const {return mFreeText;}
 
               private:
                  Phone() {}
 
                  Data mNumber;
                  Data mFreeText;
 
                  friend class Session;
            };
 
            class Connection
            {
               public:
                  Connection(AddrType addType,
                             const Data& address,
                             unsigned long ttl = 0);
                  Connection(const Connection& rhs);
                  Connection& operator=(const Connection& rhs);
 
                  void parse(ParseBuffer& pb);
                  std::ostream& encode(std::ostream&) const;
 
                  AddrType getAddressType() const {return mAddrType;}
                  const Data& getAddress() const {return mAddress;}
                  void setAddress(const Data& host, AddrType type = IP4);
                  unsigned long ttl() const {return mTTL;}
                  unsigned long& ttl() {return mTTL;}
 
               private:
                  Connection();
 
                  AddrType mAddrType;
                  Data mAddress;
                  unsigned long mTTL;
 
                  friend class Session;
                  friend class Medium;
            };
 
            class Bandwidth
            {
               public:
                  Bandwidth(const Data& modifier,
                            unsigned long kbPerSecond);
                  Bandwidth(const Bandwidth& rhs);
                  Bandwidth& operator=(const Bandwidth& rhs);
 
                  void parse(ParseBuffer& pb);
                  std::ostream& encode(std::ostream&) const;
 
                  const Data& modifier() const {return mModifier;}
                  Data modifier() {return mModifier;}
                  unsigned long kbPerSecond() const {return mKbPerSecond;}
                  unsigned long& kbPerSecond() {return mKbPerSecond;}
 
               private:
                  Bandwidth() {}
                  Data mModifier;
                  unsigned long mKbPerSecond;
 
                  friend class Session;
                  friend class Medium;
            };
 
            class Time
            {
               public:
                  Time(unsigned long start,
                       unsigned long stop);
                  Time(const Time& rhs);
                  Time& operator=(const Time& rhs);
 
                  void parse(ParseBuffer& pb);
                  std::ostream& encode(std::ostream&) const;
 
                  class Repeat
                  {
                     public:
                        Repeat(unsigned long interval,
                               unsigned long duration,
                               std::list<int> offsets);
                        void parse(ParseBuffer& pb);
                        std::ostream& encode(std::ostream&) const;
 
                        unsigned long getInterval() const {return mInterval;}
                        unsigned long getDuration() const {return mDuration;}
                        const std::list<int> getOffsets() const {return mOffsets;}
 
                     private:
                        Repeat() {}
                        unsigned long mInterval;
                        unsigned long mDuration;
                        std::list<int> mOffsets;
 
                        friend class Time;
                  };
 
                  void addRepeat(const Repeat& repeat);
 
                  unsigned long getStart() const {return mStart;}
                  unsigned long getStop() const {return mStop;}
                  const std::list<Repeat>& getRepeats() const {return mRepeats;}
 
               private:
                 Time() {}
                  unsigned long mStart;
                  unsigned long mStop;
                  std::list<Repeat> mRepeats;
 
                  friend class Session;
            };
 
            class Timezones
            {
               public:
                  class Adjustment
                  {
                     public:
                        Adjustment(unsigned long time,
                                   int offset);
                        Adjustment(const Adjustment& rhs);
                        Adjustment& operator=(const Adjustment& rhs);
 
                        unsigned long time;
                        int offset;
                  };
 
                  Timezones();
                  Timezones(const Timezones& rhs);
                  Timezones& operator=(const Timezones& rhs);
 
                  void parse(ParseBuffer& pb);
                  std::ostream& encode(std::ostream&) const;
 
                  void addAdjustment(const Adjustment& adjusment);
                  const std::list<Adjustment>& getAdjustments() const {return mAdjustments; }
               private:
                  std::list<Adjustment> mAdjustments;
            };
 
 
            class Encryption
            {
               public:
                  typedef enum {NoEncryption = 0, Prompt, Clear, Base64, UriKey} KeyType;
                  Encryption(const KeyType& method,
                             const Data& key);
                  Encryption(const Encryption& rhs);
                  Encryption& operator=(const Encryption& rhs);
 
 
                  void parse(ParseBuffer& pb);
                  std::ostream& encode(std::ostream&) const;
 
                  const KeyType& getMethod() const {return mMethod;}
                  const KeyType& method() const {return mMethod;}
                  KeyType& method() {return mMethod;}
                  const Data& getKey() const {return mKey;}
                  const Data& key() const {return mKey;}
                  Data& key() {return mKey;}
 
                  Encryption();
               private:
                  KeyType mMethod;
                  Data mKey;
            };
 
              // a=candidate $R1 1 UDP 1.0 $R-PUB-1.IP $R-PUB-1.PORT
              //Begin Add by larrin to support ICE candidate
              //about candidate priority:
             
              struct Component
              {       
                   Data id;
                   Data ip;
                   int port;
 
                   Component()
                   {
                   }
 
                   Component(const Data &id_,const Data &ip_,int port_):id(id_),ip(ip_),port(port_)
                   {
                   }
 
                   Component(const Component &val)
                   {
                       *this = val ;
                   }
 
                   Component & operator=(const Component &val)
                   {
                       this->id = val.id ;
                       this->ip = val.ip ;
                       this->port = val.port ;
 
                       return *this ;
                   }
              };
 
              class Candidate
              {
              public:
 
                   Candidate()
                   {
                   }
 
                   Candidate(const Candidate &rhs)
                   {
                       *this = rhs;
                   }
 
                   ~Candidate()
                   {
                   }
 
                   Candidate & operator=(const Candidate &rhs)
                   {
                       mName = rhs.mName;
                       priority = rhs.priority;
                       transportType = rhs.transportType;
 
                       mComponents.clear();
                       std::list<Component>::const_iterator it;
                       for(it = rhs.mComponents.begin() ; it != rhs.mComponents.end() ; it++)
                       {
                            mComponents.push_back(*it);
                       }
 
                       return *this;
                   }
 
                   const Data &getName() const
                   {
                       return mName ;
                   }
 
                   void setName(const Data name)
                   {
                       mName = name ;
                   }
 
                   int getPriority() const
                   {
                       return priority ;
                   }
 
                   void setPriority(int pri)
                   {
                       priority = pri ;
                   }
 
                   const Data & getTransportType() const
                   {
                       return transportType;
                   }
 
                   void setTransportType(const Data & type)
                   {
                       transportType = type ;
                   }
 
                   const std::list<Component> & getComponents() const
                   {
                       return mComponents;
                   }
 
                   void addComponent(const Component &component)
                   {
                       mComponents.push_back(component);
                   }
 
                   std::ostream& encode(std::ostream&) const;
 
              private:
 
                   Data mName;
                   int priority;
                   Data transportType;
                   std::list<Component> mComponents;
              };
              //End add by larrin
 
            class Medium
            {
               public:
                  Medium();
                  Medium(const Medium& rhs);
                  Medium(const Data& name,
                         unsigned long port,
                         unsigned long multicast,
                         const Data& protocol);
                  Medium& operator=(const Medium& rhs);
 
                  void parse(ParseBuffer& pb);
                  std::ostream& encode(std::ostream&) const;
 
                  void addFormat(const Data& format);
                  void setConnection(const Connection& connection);
                  void addConnection(const Connection& connection);
                  void setBandwidth(const Bandwidth& bandwidth);
                  void addBandwidth(const Bandwidth& bandwidth);
                  void addAttribute(const Data& key, const Data& value = Data::Empty);
 
                  const Data& name() const {return mName;}
                  Data& name() {return mName;}
 
                  int port() const {return mPort;}
                  unsigned long& port() {return mPort;}
                 void setPort(int port);
                  int multicast() const {return mMulticast;}
                  unsigned long& multicast() {return mMulticast;}
                  const Data& protocol() const {return mProtocol;}
                  Data& protocol() {return mProtocol;}
 
                  // preferred codec/format interface
                  const std::list<Codec>& codecs() const;
                  std::list<Codec>& codecs();
                  void clearCodecs();
                  void addCodec(const Codec& codec);
 
                  const std::list<Data>& getFormats() const {return mFormats;}
                  const Data& information() const {return mInformation;}
                  Data& information() {return mInformation;}
                  const std::list<Bandwidth>& bandwidths() const {return mBandwidths;}
                  std::list<Bandwidth>& bandwidths() {return mBandwidths;}
 
                  // from session if empty
                  const std::list<Connection> getConnections() const;
                  // does not include session connections
                  const std::list<Connection>& getMediumConnections() const {return mConnections;}
                  const Encryption& getEncryption() const {return mEncryption;}
                  const Encryption& encryption() const {return mEncryption;}
                  Encryption& encryption() {return mEncryption;}
                  bool exists(const Data& key) const;
                  const std::list<Data>& getValues(const Data& key) const;
                  void clearAttribute(const Data& key);
 
                  const Codec& findFirstMatchingCodecs(const std::list<Codec>& codecs, Codec* pMatchingCodec = 0) const;
                  const Codec& findFirstMatchingCodecs(const Medium& medium, Codec* pMatchingCodec = 0) const
                  {
                     if (&medium == this)
                        return codecs().front();
                     else
                        return findFirstMatchingCodecs(medium.codecs(), pMatchingCodec);
                  }
 
                  int findTelephoneEventPayloadType() const;
 
                    //Begin Add by larrin
                    bool add_candidate_component(const char *candidate_name,
                        const char *component,
                        const char *transport_type,
                        int priority,
                        const char *ip,
                        int port);
 
                    const HashMap<Data,Candidate> & getCandidates() const
                    {
                        return mCandidates ;
                    }
 
                    //End by larrin
 
               private:
 
                    //Begin Add by larrin
                    bool parse_candidate_component(const Data &str);
                    
 
                    typedef HashMap<Data,Candidate> CANDIDATE_MAP;
                    CANDIDATE_MAP mCandidates;
 
                    //End by larrin
 
                  void setSession(Session* session);
                  Session* mSession;
 
                  Data mName;
                  unsigned long mPort;
                  unsigned long mMulticast;
                  Data mProtocol;
                  mutable std::list<Data> mFormats;
                  mutable std::list<Codec> mCodecs;
                  Data mTransport;
                  Data mInformation;
                  std::list<Connection> mConnections;
                  std::list<Bandwidth> mBandwidths;
                  Encryption mEncryption;
                  mutable AttributeHelper mAttributeHelper;
 
                  mutable bool mRtpMapDone;
                  typedef HashMap<int, Codec> RtpMap;
                  mutable RtpMap mRtpMap;
 
                  friend class Session;
            };
 
            Session(int version,
                    const Origin& origin,
                    const Data& name);
 
            Session() : mVersion(0) {}
            Session(const Session& rhs);
            Session& operator=(const Session& rhs);
 
            void parse(ParseBuffer& pb);
            std::ostream& encode(std::ostream&) const;
 
            int version() const {return mVersion;}
            int& version() {return mVersion;}
            const Origin& origin() const {return mOrigin;}
            Origin& origin() {return mOrigin;}
            const Data& name() const {return mName;}
            Data& name() {return mName;}
            const Data& information() const {return mInformation;}
            Data& information() {return mInformation;}
            const Uri& uri() const {return mUri;}
            Uri& uri() {return mUri;}
            const std::list<Email>& getEmails() const {return mEmails;}
            const std::list<Phone>& getPhones() const {return mPhones;}
            const Connection& connection() const {return mConnection;}
            Connection& connection() {return mConnection;} // !dlb! optional?
            bool isConnection() const { return mConnection.mAddress != Data::Empty; }
            const std::list<Bandwidth>& bandwidths() const {return mBandwidths;}
            std::list<Bandwidth>& bandwidths() {return mBandwidths;}
            const std::list<Time>& getTimes() const {return mTimes;}
            const Timezones& getTimezones() const {return mTimezones;}
            const Encryption& getEncryption() const {return mEncryption;}
            const Encryption& encryption() const {return mEncryption;}
            Encryption& encryption() {return mEncryption;}
            const std::list<Medium>& media() const {return mMedia;}
            std::list<Medium>& media() {return mMedia;}
 
            void addEmail(const Email& email);
            void addPhone(const Phone& phone);
            void addBandwidth(const Bandwidth& bandwidth);
            void addTime(const Time& t);
            void addMedium(const Medium& medium);
            void clearMedium() { mMedia.clear(); }
            void clearAttribute(const Data& key);
            void addAttribute(const Data& key, const Data& value = Data::Empty);
            bool exists(const Data& key) const;
            const std::list<Data>& getValues(const Data& key) const;
 
         private:
            int mVersion;
            Origin mOrigin;
            Data mName;
            std::list<Medium> mMedia;
 
            // applies to all Media where unspecified
            Data mInformation;
            Uri mUri;
            std::list<Email> mEmails;
            std::list<Phone> mPhones;
            Connection mConnection;
            std::list<Bandwidth> mBandwidths;
            std::list<Time> mTimes;
            Timezones mTimezones;
            Encryption mEncryption;
            AttributeHelper mAttributeHelper;
 
            friend class SdpContents;
      };
 
      SdpContents();
      SdpContents(HeaderFieldValue* hfv, const Mime& contentTypes);
      ~SdpContents();
 
      SdpContents(const SdpContents& rhs);
      SdpContents& operator=(const SdpContents& rhs);
 
      virtual Contents* clone() const;
 
      virtual Data getBodyData() const;
 
      Session& session() {checkParsed(); return mSession;}
      const Session& session() const {checkParsed(); return mSession;}
 
      //Begin Add by larrin
      
      //We need this function to create SDP object
      Session & get_session(){return mSession;}
      //End by larrin
 
 
      virtual std::ostream& encodeParsed(std::ostream& str) const;
      virtual void parse(ParseBuffer& pb);
      static const Mime& getStaticType() ;
 
      static bool init();
 
   private:
      SdpContents(const Data& data, const Mime& contentTypes);
      Session mSession;
};
 
static bool invokeSdpContentsInit = SdpContents::init();
 
typedef SdpContents::Session::Codec Codec;
 
bool operator==(const SdpContents::Session::Codec& lhs,
                const SdpContents::Session::Codec& rhs);
 
std::ostream& operator<<(std::ostream& str, const SdpContents::Session::Codec& codec);
 
}
 
#endif
 
/* ====================================================================
 * The Vovida Software License, Version 1.0
 *
 * Copyright (c) 2000 Vovida Networks, Inc. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this std::vector of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this std::vector of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The names "VOCAL", "Vovida Open Communication Application Library",
 *    and "Vovida Open Communication Application Library (VOCAL)" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact vocal@vovida.org.
 *
 * 4. Products derived from this software may not be called "VOCAL", nor
 *    may "VOCAL" appear in their name, without prior written
 *    permission of Vovida Networks, Inc.
 *
 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
 * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA
 * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
 * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
 * DAMAGE.
 *
 * ====================================================================
 *
 * This software consists of voluntary contributions made by Vovida
 * Networks, Inc. and many individuals on behalf of Vovida Networks,
 * Inc. For more information on Vovida Networks, Inc., please see
 * <http://www.vovida.org/>.
 *
 */
 

SdpContents.cpp
===============================================

#if defined(HAVE_CONFIG_H)
#include "resip/stack/config.hxx"
#endif
 
#include "resip/stack/SdpContents.hxx"
#include "rutil/ParseBuffer.hxx"
#include "rutil/DataStream.hxx"
#include "resip/stack/Symbols.hxx"
#include "rutil/Logger.hxx"
#include "rutil/WinLeakCheck.hxx"
 
#define RESIPROCATE_SUBSYSTEM resip::Subsystem::SDP
 
using namespace resip;
using namespace std;
 
const SdpContents SdpContents::Empty;
 
bool
SdpContents::init()
{
   static ContentsFactory<SdpContents> factory;
   (void)factory;
   return true;
}
 
const char* NetworkType[] = {"???", "IP4", "IP6"};
 
static const Data rtpmap("rtpmap");
static const Data fmtp("fmtp");
 
// RF C2327 6. page 9
// "parsers should be tolerant and accept records terminated with a single
// newline character"
void skipEol(ParseBuffer& pb)
{
   while(!pb.eof() && (*pb.position() == Symbols::SPACE[0] ||
                       *pb.position() == Symbols::TAB[0]))
   {
      pb.skipChar();
   }
  
   if (*pb.position() == Symbols::LF[0])
   {
      pb.skipChar();
   }
   else
   {
      // allow extra 0x0d bytes.
      while(*pb.position() == Symbols::CR[0])
      {
         pb.skipChar();
      }
      pb.skipChar(Symbols::LF[0]);
   }
  
}
 
AttributeHelper::AttributeHelper(const AttributeHelper& rhs)
   : mAttributes(rhs.mAttributes)
{
}
 
AttributeHelper::AttributeHelper()
{
}
 
AttributeHelper&
AttributeHelper::operator=(const AttributeHelper& rhs)
{
   if (this != &rhs)
   {
      mAttributes = rhs.mAttributes;
   }
   return *this;
}
 
bool
AttributeHelper::exists(const Data& key) const
{
   return mAttributes.find(key) != mAttributes.end();
}
 
const list<Data>&
AttributeHelper::getValues(const Data& key) const
{
   if (!exists(key))
   {
      static const list<Data> emptyList;
      return emptyList;
   }
   return mAttributes.find(key)->second;
}
 
ostream&
AttributeHelper::encode(ostream& s) const
{
   for (HashMap< Data, list<Data> >::const_iterator i = mAttributes.begin();
        i != mAttributes.end(); ++i)
   {
      for (list<Data>::const_iterator j = i->second.begin();
           j != i->second.end(); ++j)
      {
         s << "a="
           << i->first;
         if (!j->empty())
         {
            s << Symbols::COLON[0] << *j;
         }
         s << Symbols::CRLF;
      }
   }
   return s;
}
 
void
AttributeHelper::parse(ParseBuffer& pb)
{
   while (!pb.eof() && *pb.position() == 'a')
   {
      Data key;
      Data value;
 
      pb.skipChar('a');
      const char* anchor = pb.skipChar(Symbols::EQUALS[0]);
      pb.skipToOneOf(Symbols::COLON, Symbols::CRLF);
      pb.data(key, anchor);
      if (!pb.eof() && *pb.position() == Symbols::COLON[0])
      {
         anchor = pb.skipChar(Symbols::COLON[0]);
         pb.skipToOneOf(Symbols::CRLF);
         pb.data(value, anchor);
      }
 
      if(!pb.eof()) skipEol(pb);
 
      //mAttributes[key].push_back(value);
 
      //Begin by larrin
 
      //mAttributes[key].push_back(value);
      if(value.size() > 0)
      {
         mAttributes[key].push_back(value);
      }
      else
      {
              ParseBuffer pb1(key);
              const char* anchor = pb1.skipWhitespace();
              pb1.skipToChar(Symbols::SPACE[0]);
              Data key1;
              Data value1;
              pb1.data(key1, anchor);
 
              anchor = pb1.skipChar(Symbols::SPACE[0]);
              pb1.skipToChars(Symbols::CRLF);
              pb1.data(value1, anchor);
             
              if(stricmp(key1.c_str(),"candidate") != 0)
                   mAttributes[key1].push_back(value1);
              else
                   mCandidates.push_back(value1);
      }
      //End by larrin
   }
}
 
void
AttributeHelper::addAttribute(const Data& key, const Data& value)
{
   mAttributes[key].push_back(value);
}
 
void
AttributeHelper::clearAttribute(const Data& key)
{
   mAttributes.erase(key);
}
 
SdpContents::SdpContents() : Contents(getStaticType())
{
}
 
SdpContents::SdpContents(HeaderFieldValue* hfv, const Mime& contentTypes)
   : Contents(hfv, contentTypes)
{
}
 
SdpContents::SdpContents(const SdpContents& rhs)
   : Contents(rhs),
     mSession(rhs.mSession)
{
}
 
SdpContents::~SdpContents()
{
}
 
 
SdpContents&
SdpContents::operator=(const SdpContents& rhs)
{
   if (this != &rhs)
   {
      Contents::operator=(rhs);
      mSession = rhs.mSession;
   }
   return *this;
}
 
Contents*
SdpContents::clone() const
{
   return new SdpContents(*this);
}
 
Data
SdpContents::getBodyData() const
{
   checkParsed();
 
   Data d;
   {
      DataStream s(d);
      mSession.encode(s);
   }  
   return d;
}
 
void
SdpContents::parse(ParseBuffer& pb)
{
   mSession.parse(pb);
}
 
ostream&
SdpContents::encodeParsed(ostream& s) const
{
   mSession.encode(s);
   return s;
}
 
const Mime&
SdpContents::getStaticType()
{
   static Mime type("application", "sdp");
   return type;
}
 
static Data nullOrigin("0.0.0.0");
 
SdpContents::Session::Origin::Origin()
   : mUser(Data::Empty),
     mSessionId(0),
     mVersion(0),
     mAddrType(IP4),
     mAddress(nullOrigin)
{}
 
SdpContents::Session::Origin::Origin(const Origin& rhs)
   : mUser(rhs.mUser),
     mSessionId(rhs.mSessionId),
     mVersion(rhs.mVersion),
     mAddrType(rhs.mAddrType),
     mAddress(rhs.mAddress)
{
}
 
SdpContents::Session::Origin&
SdpContents::Session::Origin::operator=(const Origin& rhs)
{
   if (this != &rhs)
   {
      mUser = rhs.mUser;
      mSessionId = rhs.mSessionId;
      mVersion = rhs.mVersion;
      mAddrType = rhs.mAddrType;
      mAddress = rhs.mAddress;
   }
   return *this;
}
 
 
SdpContents::Session::Origin::Origin(const Data& user,
                                     const UInt64& sessionId,
                                     const UInt64& version,
                                     AddrType addr,
                                     const Data& address)
   : mUser(user),
     mSessionId(sessionId),
     mVersion(version),
     mAddrType(addr),
     mAddress(address)
{}
 
ostream&
SdpContents::Session::Origin::encode(ostream& s) const
{
   s << "o="
     << mUser << Symbols::SPACE[0]
     << mSessionId << Symbols::SPACE[0]
     << mVersion << Symbols::SPACE[0]
     << "IN "
     << NetworkType[mAddrType] << Symbols::SPACE[0]
     << mAddress << Symbols::CRLF;
   return s;
}
 
void
SdpContents::Session::Origin::setAddress(const Data& host, AddrType addr)
{
    mAddress = host;
    mAddrType = addr;
}
 
void
SdpContents::Session::Origin::parse(ParseBuffer& pb)
{
   pb.skipChar('o');
   const char* anchor = pb.skipChar(Symbols::EQUALS[0]);
 
   pb.skipToChar(Symbols::SPACE[0]);
   pb.data(mUser, anchor);
 
   anchor = pb.skipChar(Symbols::SPACE[0]);
   mSessionId = pb.unsignedLongLong();
 
   anchor = pb.skipChar(Symbols::SPACE[0]);
   mVersion = pb.unsignedLongLong();
 
   pb.skipChar(Symbols::SPACE[0]);
   pb.skipChar('I');
   pb.skipChar('N');
 
   anchor = pb.skipChar(Symbols::SPACE[0]);
   pb.skipToChar(Symbols::SPACE[0]);
   Data addrType;
   pb.data(addrType, anchor);
   if (addrType == NetworkType[IP4])
   {
      mAddrType = IP4;
   }
   else if (addrType == NetworkType[IP6])
   {
      mAddrType = IP6;
   }
   else
   {
      mAddrType = static_cast<AddrType>(0);
   }
 
   anchor = pb.skipChar(Symbols::SPACE[0]);
   pb.skipToOneOf(Symbols::CRLF);
   pb.data(mAddress, anchor);
 
   skipEol(pb);
}
 
SdpContents::Session::Email::Email(const Data& address,
                                   const Data& freeText)
   : mAddress(address),
     mFreeText(freeText)
{}
 
SdpContents::Session::Email::Email(const Email& rhs)
   : mAddress(rhs.mAddress),
     mFreeText(rhs.mFreeText)
{}
 
SdpContents::Session::Email&
SdpContents::Session::Email::operator=(const Email& rhs)
{
   if (this != &rhs)
   {
      mAddress = rhs.mAddress;
      mFreeText = rhs.mFreeText;
   }
   return *this;
}
 
ostream&
SdpContents::Session::Email::encode(ostream& s) const
{
   s << "e=" << mAddress;
   if (!mFreeText.empty())
   {
      s << Symbols::SPACE[0];
      s << Symbols::LPAREN[0] << mFreeText << Symbols::RPAREN[0];
   }
   s << Symbols::CRLF;
 
   return s;
}
 
// helper to parse email and phone numbers with display name
void parseEorP(ParseBuffer& pb, Data& eOrp, Data& freeText)
{
   // =mjh@isi.edu (Mark Handley)
   // =mjh@isi.edu
   // =Mark Handley <mjh@isi.edu>
   // =<mjh@isi.edu>
 
   const char* anchor = pb.skipChar(Symbols::EQUALS[0]);
 
   pb.skipToOneOf("<(/n/r"); // find a left angle bracket "<", a left paren "(", or a CR
   switch (*pb.position())
   {
      case '/n':                     // Symbols::CR[0]
      case '/r':                     // Symbols::LF[0]
         // mjh@isi.edu
         //            ^
         pb.data(eOrp, anchor);
         break;
 
      case '<':                      // Symbols::LA_QUOTE[0]
         // Mark Handley <mjh@isi.edu>
         //              ^
         // <mjh@isi.edu>
         // ^
          
         pb.data(freeText, anchor);
         anchor = pb.skipChar();
         pb.skipToEndQuote(Symbols::RA_QUOTE[0]);
         pb.data(eOrp, anchor);
         pb.skipChar(Symbols::RA_QUOTE[0]);
         break;
          
      case '(':                      // Symbols::LPAREN[0]
         // mjh@isi.edu (Mark Handley)
         //             ^
          
         pb.data(eOrp, anchor);
         anchor = pb.skipChar();
         pb.skipToEndQuote(Symbols::RPAREN[0]);
         pb.data(freeText, anchor);
         pb.skipChar(Symbols::RPAREN[0]);
         break;
      default:
         assert(0);
   }
}
 
void
SdpContents::Session::Email::parse(ParseBuffer& pb)
{
   pb.skipChar('e');
   parseEorP(pb, mAddress, mFreeText);
   skipEol(pb);
}
 
SdpContents::Session::Phone::Phone(const Data& number,
                                   const Data& freeText)
   : mNumber(number),
     mFreeText(freeText)
{}
 
SdpContents::Session::Phone::Phone(const Phone& rhs)
   : mNumber(rhs.mNumber),
     mFreeText(rhs.mFreeText)
{}
 
SdpContents::Session::Phone&
SdpContents::Session::Phone::operator=(const Phone& rhs)
{
   if (this != &rhs)
   {
      mNumber = rhs.mNumber;
      mFreeText = rhs.mFreeText;
   }
   return *this;
}
 
ostream&
SdpContents::Session::Phone::encode(ostream& s) const
{
 s << "p=" << mNumber;
   if (!mFreeText.empty())
   {
      s << Symbols::SPACE[0];
      s << Symbols::LPAREN[0] << mFreeText << Symbols::RPAREN[0];
   }
   s << Symbols::CRLF;
 
   return s;
}
 
void
SdpContents::Session::Phone::parse(ParseBuffer& pb)
{
   pb.skipChar('p');
   parseEorP(pb, mNumber, mFreeText);
   skipEol(pb);
}
 
SdpContents::Session::Connection::Connection(AddrType addType,
                                             const Data& address,
                                             unsigned long ttl)
   : mAddrType(addType),
     mAddress(address),
     mTTL(ttl)
{}
 
SdpContents::Session::Connection::Connection()
   : mAddrType(IP4),
     mAddress(Data::Empty),
     mTTL(0)
{}
 
SdpContents::Session::Connection::Connection(const Connection& rhs)
   : mAddrType(rhs.mAddrType),
     mAddress(rhs.mAddress),
     mTTL(rhs.mTTL)
{
}
 
SdpContents::Session::Connection&
SdpContents::Session::Connection::operator=(const Connection& rhs)
{
   if (this != &rhs)
   {
      mAddrType = rhs.mAddrType;
      mAddress = rhs.mAddress;
      mTTL = rhs.mTTL;
   }
   return *this;
}
 
ostream&
SdpContents::Session::Connection::encode(ostream& s) const
{
   s << "c=IN "
     << NetworkType[mAddrType] << Symbols::SPACE[0] << mAddress;
 
   if (mTTL)
   {
      s << Symbols::SLASH[0] << mTTL;
   }
   s << Symbols::CRLF;
   return s;
}
 
void
SdpContents::Session::Connection::setAddress(const Data& host, AddrType addr)
{
    mAddress = host;
    mAddrType = addr;
}
 
void
SdpContents::Session::Connection::parse(ParseBuffer& pb)
{
   pb.skipChar('c');
   pb.skipChar(Symbols::EQUALS[0]);
   pb.skipChar('I');
   pb.skipChar('N');
 
   const char* anchor = pb.skipChar(Symbols::SPACE[0]);
   pb.skipToChar(Symbols::SPACE[0]);
   Data addrType;
   pb.data(addrType, anchor);
   if (addrType == NetworkType[IP4])
   {
      mAddrType = IP4;
   }
   else if (addrType == NetworkType[IP6])
   {
      mAddrType = IP6;
   }
   else
   {
      mAddrType = static_cast<AddrType>(0);
   }
 
   anchor = pb.skipChar();
   pb.skipToOneOf(Symbols::SLASH, Symbols::CRLF);
   pb.data(mAddress, anchor);
 
   mTTL = 0;
   if (!pb.eof() && *pb.position() == Symbols::SLASH[0])
   {
      pb.skipChar();
      mTTL = pb.integer();
   }
 
   // multicast dealt with above this parser
   if (!pb.eof() && *pb.position() != Symbols::SLASH[0])
   {
      skipEol(pb);
   }
}
 
SdpContents::Session::Bandwidth::Bandwidth(const Data& modifier,
                                           unsigned long kbPerSecond)
   : mModifier(modifier),
     mKbPerSecond(kbPerSecond)
{}
 
SdpContents::Session::Bandwidth::Bandwidth(const Bandwidth& rhs)
   : mModifier(rhs.mModifier),
     mKbPerSecond(rhs.mKbPerSecond)
{}
 
SdpContents::Session::Bandwidth&
SdpContents::Session::Bandwidth::operator=(const Bandwidth& rhs)
{
   if (this != &rhs)
   {
      mModifier = rhs.mModifier;
      mKbPerSecond = rhs.mKbPerSecond;
   }
   return *this;
}
 
ostream&
SdpContents::Session::Bandwidth::encode(ostream& s) const
{
   s << "b="
     << mModifier
     << Symbols::COLON[0] << mKbPerSecond
     << Symbols::CRLF;
   return s;
}
 
void
SdpContents::Session::Bandwidth::parse(ParseBuffer& pb)
{
   pb.skipChar('b');
   const char* anchor = pb.skipChar(Symbols::EQUALS[0]);
 
   pb.skipToOneOf(Symbols::COLON, Symbols::CRLF);
   if (*pb.position() == Symbols::COLON[0])
   {
      pb.data(mModifier, anchor);
 
      anchor = pb.skipChar(Symbols::COLON[0]);
      mKbPerSecond = pb.integer();
 
      skipEol(pb);
   }
   else
   {
      pb.fail(__FILE__, __LINE__);
   }
}
 
SdpContents::Session::Time::Time(unsigned long start,
                                 unsigned long stop)
   : mStart(start),
     mStop(stop)
{}
 
SdpContents::Session::Time::Time(const Time& rhs)
   : mStart(rhs.mStart),
     mStop(rhs.mStop)
{}
 
SdpContents::Session::Time&
SdpContents::Session::Time::operator=(const Time& rhs)
{
   if (this != &rhs)
   {
      mStart = rhs.mStart;
      mStop = rhs.mStop;
      mRepeats = rhs.mRepeats;
   }
   return *this;
}
 
ostream&
SdpContents::Session::Time::encode(ostream& s) const
{
   s << "t=" << mStart << Symbols::SPACE[0]
     << mStop
     << Symbols::CRLF;
 
   for (list<Repeat>::const_iterator i = mRepeats.begin();
        i != mRepeats.end(); ++i)
   {
      i->encode(s);
   }
   return s;
}
 
void
SdpContents::Session::Time::parse(ParseBuffer& pb)
{
   pb.skipChar('t');
   pb.skipChar(Symbols::EQUALS[0]);
 
   mStart = pb.integer();
   pb.skipChar(Symbols::SPACE[0]);
   mStop = pb.integer();
 
   skipEol(pb);
 
   while (!pb.eof() && *pb.position() == 'r')
   {
      addRepeat(Repeat());
      mRepeats.back().parse(pb);
   }
}
 
void
SdpContents::Session::Time::addRepeat(const Repeat& repeat)
{
   mRepeats.push_back(repeat);
}
 
SdpContents::Session::Time::Repeat::Repeat(unsigned long interval,
                                           unsigned long duration,
                                           list<int> offsets)
   : mInterval(interval),
     mDuration(duration),
     mOffsets(offsets)
{}
 
ostream&
SdpContents::Session::Time::Repeat::encode(ostream& s) const
{
   s << "r="
     << mInterval << Symbols::SPACE[0]
     << mDuration << 's';
   for (list<int>::const_iterator i = mOffsets.begin();
        i != mOffsets.end(); ++i)
   {
      s << Symbols::SPACE[0] << *i << 's';
   }
 
   s << Symbols::CRLF;
   return s;
}
 
int
parseTypedTime(ParseBuffer& pb)
{
   int v = pb.integer();
   if (!pb.eof())
   {
      switch (*pb.position())
      {
      case 's' :
         pb.skipChar();
         break;
      case 'm' :
         v *= 60;
         pb.skipChar();
         break;
      case 'h' :
         v *= 3600;
         pb.skipChar();
       break;
      case 'd' :
         v *= 3600*24;
         pb.skipChar();
      }
   }
   return v;
}
 
void
SdpContents::Session::Time::Repeat::parse(ParseBuffer& pb)
{
   pb.skipChar('r');
   pb.skipChar(Symbols::EQUALS[0]);
 
   mInterval = parseTypedTime(pb);
   pb.skipChar(Symbols::SPACE[0]);
 
   mDuration = parseTypedTime(pb);
 
   while (!pb.eof() && *pb.position() != Symbols::CR[0])
   {
      pb.skipChar(Symbols::SPACE[0]);
 
      mOffsets.push_back(parseTypedTime(pb));
   }
 
   skipEol(pb);
}
 
SdpContents::Session::Timezones::Adjustment::Adjustment(unsigned long _time,
                                                        int _offset)
   : time(_time),
     offset(_offset)
{}
 
SdpContents::Session::Timezones::Adjustment::Adjustment(const Adjustment& rhs)
   : time(rhs.time),
     offset(rhs.offset)
{}
 
SdpContents::Session::Timezones::Adjustment&
SdpContents::Session::Timezones::Adjustment::operator=(const Adjustment& rhs)
{
   if (this != &rhs)
   {
      time = rhs.time;
      offset = rhs.offset;
   }
   return *this;
}
 
SdpContents::Session::Timezones::Timezones()
   : mAdjustments()
{}
 
SdpContents::Session::Timezones::Timezones(const Timezones& rhs)
   : mAdjustments(rhs.mAdjustments)
{}
 
SdpContents::Session::Timezones&
SdpContents::Session::Timezones::operator=(const Timezones& rhs)
{
   if (this != &rhs)
   {
      mAdjustments = rhs.mAdjustments;
   }
   return *this;
}
 
ostream&
SdpContents::Session::Timezones::encode(ostream& s) const
{
   if (!mAdjustments.empty())
   {
      s << "z=";
      bool first = true;
      for (list<Adjustment>::const_iterator i = mAdjustments.begin();
           i != mAdjustments.end(); ++i)
      {
         if (!first)
         {
            s << Symbols::SPACE[0];
         }
         first = false;
         s << i->time << Symbols::SPACE[0]
           << i->offset << 's';
      }
 
      s << Symbols::CRLF;
   }
   return s;
}
 
void
SdpContents::Session::Timezones::parse(ParseBuffer& pb)
{
   pb.skipChar('z');
   pb.skipChar(Symbols::EQUALS[0]);
 
   while (!pb.eof() && *pb.position() != Symbols::CR[0])
   {
      Adjustment adj(0, 0);
      adj.time = pb.integer();
      pb.skipChar(Symbols::SPACE[0]);
      adj.offset = parseTypedTime(pb);
      addAdjustment(adj);
 
      if (!pb.eof() && *pb.position() == Symbols::SPACE[0])
      {
         pb.skipChar();
      }
   }
 
   skipEol(pb);
}
 
void
SdpContents::Session::Timezones::addAdjustment(const Adjustment& adjust)
{
   mAdjustments.push_back(adjust);
}
 
SdpContents::Session::Encryption::Encryption()
   : mMethod(NoEncryption),
     mKey(Data::Empty)
{}
 
SdpContents::Session::Encryption::Encryption(const KeyType& method,
                                             const Data& key)
   : mMethod(method),
     mKey(key)
{}
 
SdpContents::Session::Encryption::Encryption(const Encryption& rhs)
   : mMethod(rhs.mMethod),
     mKey(rhs.mKey)
{}
 
SdpContents::Session::Encryption&
SdpContents::Session::Encryption::operator=(const Encryption& rhs)
{
   if (this != &rhs)
   {
      mMethod = rhs.mMethod;
      mKey = rhs.mKey;
   }
   return *this;
}
 
const char* KeyTypes[] = {"????", "prompt", "clear", "base64", "uri"};
 
ostream&
SdpContents::Session::Encryption::encode(ostream& s) const
{
   s << "k="
     << KeyTypes[mMethod];
   if (mMethod != Prompt)
   {
      s << Symbols::COLON[0] << mKey;
   }
   s << Symbols::CRLF;
 
   return s;
}
 
void
SdpContents::Session::Encryption::parse(ParseBuffer& pb)
{
   pb.skipChar('k');
   const char* anchor = pb.skipChar(Symbols::EQUALS[0]);
 
   pb.skipToChar(Symbols::COLON[0]);
   if (!pb.eof())
   {
      Data p;
      pb.data(p, anchor);
      if (p == KeyTypes[Clear])
      {
         mMethod = Clear;
      }
      else if (p == KeyTypes[Base64])
      {
         mMethod = Base64;
      }
      else if (p == KeyTypes[UriKey])
      {
         mMethod = UriKey;
      }
 
      anchor = pb.skipChar(Symbols::COLON[0]);
      pb.skipToOneOf(Symbols::CRLF);
      pb.data(mKey, anchor);
   }
   else
   {
      pb.reset(anchor);
      pb.skipToOneOf(Symbols::CRLF);
 
      Data p;
      pb.data(p, anchor);
      if (p == KeyTypes[Prompt])
      {
         mMethod = Prompt;
      }
   }
 
   skipEol(pb);
}
 
SdpContents::Session::Session(int version,
                              const Origin& origin,
                              const Data& name)
   : mVersion(version),
     mOrigin(origin),
     mName(name)
{}
 
SdpContents::Session::Session(const Session& rhs)
{
   *this = rhs;
}
 
SdpContents::Session&
SdpContents::Session::operator=(const Session& rhs)
{
   if (this != &rhs)
   {
      mVersion = rhs.mVersion;
      mOrigin = rhs.mOrigin;
      mName = rhs.mName;
      mMedia = rhs.mMedia;
      mInformation = rhs.mInformation;
      mUri = rhs.mUri;
      mEmails = rhs.mEmails;
      mPhones = rhs.mPhones;
      mConnection = rhs.mConnection;
      mBandwidths = rhs.mBandwidths;
      mTimes = rhs.mTimes;
      mTimezones = rhs.mTimezones;
      mEncryption = rhs.mEncryption;
      mAttributeHelper = rhs.mAttributeHelper;
 
      for (std::list<Medium>::iterator i=mMedia.begin(); i != mMedia.end(); ++i)
      {
         i->setSession(this);
      }
   }
   return *this;
}
 
void
SdpContents::Session::parse(ParseBuffer& pb)
{
   pb.skipChar('v');
   pb.skipChar(Symbols::EQUALS[0]);
   mVersion = pb.integer();
   skipEol(pb);
 
   mOrigin.parse(pb);
 
   pb.skipChar('s');
   const char* anchor = pb.skipChar(Symbols::EQUALS[0]);
   pb.skipToOneOf(Symbols::CRLF);
   pb.data(mName, anchor);
   skipEol(pb);
 
   if (!pb.eof() && *pb.position() == 'i')
   {
      pb.skipChar('i');
      const char* anchor = pb.skipChar(Symbols::EQUALS[0]);
      pb.skipToOneOf(Symbols::CRLF);
      pb.data(mInformation, anchor);
      skipEol(pb);
   }
 
   if (!pb.eof() && *pb.position() == 'u')
   {
      pb.skipChar('u');
      pb.skipChar(Symbols::EQUALS[0]);
      mUri.parse(pb);
      skipEol(pb);
   }
 
   while (!pb.eof() && *pb.position() == 'e')
   {
      addEmail(Email());
      mEmails.back().parse(pb);
   }
 
   while (!pb.eof() && *pb.position() == 'p')
   {
      addPhone(Phone());
      mPhones.back().parse(pb);
   }
 
   if (!pb.eof() && *pb.position() == 'c')
   {
      mConnection.parse(pb);
   }
 
   while (!pb.eof() && *pb.position() == 'b')
   {
      addBandwidth(Bandwidth());
      mBandwidths.back().parse(pb);
   }
 
   while (!pb.eof() && *pb.position() == 't')
   {
      addTime(Time());
      mTimes.back().parse(pb);
   }
 
   if (!pb.eof() && *pb.position() == 'z')
   {
      mTimezones.parse(pb);
   }
 
   if (!pb.eof() && *pb.position() == 'k')
   {
      mEncryption.parse(pb);
   }
 
   mAttributeHelper.parse(pb);
 
   while (!pb.eof() && *pb.position() == 'm')
   {
      addMedium(Medium());
      mMedia.back().parse(pb);
   }
}
 
ostream&
SdpContents::Session::encode(ostream& s) const
{
   s << "v=" << mVersion << Symbols::CRLF;
   mOrigin.encode(s);
   s << "s=" << mName << Symbols::CRLF;
 
   if (!mInformation.empty())
   {
      s << "i=" << mInformation << Symbols::CRLF;
   }
 
   if (!mUri.host().empty())
   {
      mUri.encode(s);
      s << Symbols::CRLF;
   }
 
   for (list<Email>::const_iterator i = mEmails.begin();
        i != mEmails.end(); ++i)
   {
      i->encode(s);
   }
 
   for (list<Phone>::const_iterator i = mPhones.begin();
        i != mPhones.end(); ++i)
   {
      i->encode(s);
   }
 
   if (!mConnection.getAddress().empty())
   {
      mConnection.encode(s);
   }
 
   for (list<Bandwidth>::const_iterator i = mBandwidths.begin();
        i != mBandwidths.end(); ++i)
   {
      i->encode(s);
   }
 
   if (mTimes.empty())
   {
      s << "t=0 0" << Symbols::CRLF;
   }
   else
   {
      for (list<Time>::const_iterator i = mTimes.begin();
           i != mTimes.end(); ++i)
      {
         i->encode(s);
      }
   }
 
   mTimezones.encode(s);
 
   if (mEncryption.getMethod() != Encryption::NoEncryption)
   {
      mEncryption.encode(s);
   }
 
   mAttributeHelper.encode(s);
 
   for (list<Medium>::const_iterator i = mMedia.begin();
        i != mMedia.end(); ++i)
   {
      i->encode(s);
   }
 
   return s;
}
 
void
SdpContents::Session::addEmail(const Email& email)
{
   mEmails.push_back(email);
}
 
void
SdpContents::Session::addTime(const Time& t)
{
   mTimes.push_back(t);
}
 
void
SdpContents::Session::addPhone(const Phone& phone)
{
   mPhones.push_back(phone);
}
 
void
SdpContents::Session::addBandwidth(const Bandwidth& bandwidth)
{
   mBandwidths.push_back(bandwidth);
}
 
void
SdpContents::Session::addMedium(const Medium& medium)
{
   mMedia.push_back(medium);
   mMedia.back().setSession(this);
}
 
void
SdpContents::Session::addAttribute(const Data& key, const Data& value)
{
   mAttributeHelper.addAttribute(key, value);
 
   if (key == rtpmap)
   {
      for (list<Medium>::iterator i = mMedia.begin();
           i != mMedia.end(); ++i)
      {
         i->mRtpMapDone = false;
      }
   }
}
 
void
SdpContents::Session::clearAttribute(const Data& key)
{
   mAttributeHelper.clearAttribute(key);
 
   if (key == rtpmap)
   {
      for (list<Medium>::iterator i = mMedia.begin();
           i != mMedia.end(); ++i)
      {
         i->mRtpMapDone = false;
      }
   }
}
 
bool
SdpContents::Session::exists(const Data& key) const
{
   return mAttributeHelper.exists(key);
}
 
const list<Data>&
SdpContents::Session::getValues(const Data& key) const
{
   return mAttributeHelper.getValues(key);
}
 
SdpContents::Session::Medium::Medium(const Data& name,
                                     unsigned long port,
                                     unsigned long multicast,
                                     const Data& protocol)
   : mSession(0),
     mName(name),
     mPort(port),
     mMulticast(multicast),
     mProtocol(protocol),
     mRtpMapDone(false)
{}
 
SdpContents::Session::Medium::Medium()
   : mSession(0),
     mPort(0),
     mMulticast(1),
     mRtpMapDone(false)
{}
 
SdpContents::Session::Medium::Medium(const Medium& rhs)
   : mSession(0),
     mName(rhs.mName),
     mPort(rhs.mPort),
     mMulticast(rhs.mMulticast),
     mProtocol(rhs.mProtocol),
     mFormats(rhs.mFormats),
     mCodecs(rhs.mCodecs),
     mTransport(rhs.mTransport),
     mInformation(rhs.mInformation),
     mConnections(rhs.mConnections),
     mBandwidths(rhs.mBandwidths),
     mEncryption(rhs.mEncryption),
     mAttributeHelper(rhs.mAttributeHelper),
     mRtpMapDone(rhs.mRtpMapDone),
     mRtpMap(rhs.mRtpMap)
{
     mCandidates.clear();
     CANDIDATE_MAP::const_iterator it ;
     for(it = rhs.mCandidates.begin(); it != rhs.mCandidates.end() ; it++)
     {
         mCandidates[(*it).first] = (*it).second ;
     }
}
 
 
SdpContents::Session::Medium&
SdpContents::Session::Medium::operator=(const Medium& rhs)
{
   if (this != &rhs)
   {
      mSession = 0;
      mName = rhs.mName;
      mPort = rhs.mPort;
      mMulticast = rhs.mMulticast;
      mProtocol = rhs.mProtocol;
      mFormats = rhs.mFormats;
      mCodecs = rhs.mCodecs;
      mTransport = rhs.mTransport;
      mInformation = rhs.mInformation;
      mConnections = rhs.mConnections;
      mBandwidths = rhs.mBandwidths;
      mEncryption = rhs.mEncryption;
      mAttributeHelper = rhs.mAttributeHelper;
      mRtpMapDone = rhs.mRtpMapDone;
      mRtpMap = rhs.mRtpMap;
 
      mCandidates.clear();
      CANDIDATE_MAP::const_iterator it ;
      for(it = rhs.mCandidates.begin(); it != rhs.mCandidates.end() ; it++)
      {
              mCandidates[(*it).first] = (*it).second ;
      }
   }
   return *this;
}
 
void
SdpContents::Session::Medium::setPort(int port)
{
   mPort = port;
}
 
void
SdpContents::Session::Medium::setSession(Session* session)
{
   mSession = session;
}
 
void
SdpContents::Session::Medium::parse(ParseBuffer& pb)
{
   pb.skipChar('m');
   const char* anchor = pb.skipChar(Symbols::EQUALS[0]);
 
   pb.skipToChar(Symbols::SPACE[0]);
   pb.data(mName, anchor);
   pb.skipChar(Symbols::SPACE[0]);
 
   mPort = pb.integer();
 
   if (*pb.position() == Symbols::SLASH[0])
   {
      pb.skipChar();
      mMulticast = pb.integer();
   }
 
   anchor = pb.skipChar(Symbols::SPACE[0]);
   pb.skipToOneOf(Symbols::SPACE, Symbols::CRLF);
   pb.data(mProtocol, anchor);
 
   while (*pb.position() != Symbols::CR[0] &&
          *pb.position() != Symbols::LF[0])
   {
      anchor = pb.skipChar(Symbols::SPACE[0]);
      pb.skipToOneOf(Symbols::SPACE, Symbols::CRLF);
      Data format;
      pb.data(format, anchor);
      addFormat(format);
   }
 
   skipEol(pb);
 
   if (!pb.eof() && *pb.position() == 'i')
   {
      pb.skipChar('i');
      anchor = pb.skipChar(Symbols::EQUALS[0]);
      pb.skipToOneOf(Symbols::CRLF);
      pb.data(mInformation, anchor);
 
      skipEol(pb);
   }
 
   while (!pb.eof() && *pb.position() == 'c')
   {
      addConnection(Connection());
      mConnections.back().parse(pb);
      if (!pb.eof() && *pb.position() == Symbols::SLASH[0])
      {
         pb.skipChar();
         int num = pb.integer();
 
         Connection& con = mConnections.back();
         const Data& addr = con.getAddress();
         int i = addr.size() - 1;
         for (; i; i--)
         {
            if (addr[i] == '.')
            {
               break;
            }
         }
 
         if (addr[i] == '.')
         {
            Data before(addr.data(), i);
            ParseBuffer subpb(addr.data()+i+1, addr.size()-i-1);
            int after = subpb.integer();
 
            for (int i = 0; i < num-1; i++)
            {
               addConnection(con);
               mConnections.back().mAddress = before + Data(after+i);
            }
         }
 
         skipEol(pb);
      }
   }
 
   while (!pb.eof() && *pb.position() == 'b')
   {
      addBandwidth(Bandwidth());
      mBandwidths.back().parse(pb);
   }
 
   if (!pb.eof() && *pb.position() == 'k')
   {
      mEncryption.parse(pb);
   }
 
   mAttributeHelper.parse(pb);
 
   //Add by larrin for candidates
     list<Data> &candidates = mAttributeHelper.get_candidates();
 
     list<Data>::iterator it ;
     for(it = candidates.begin(); it != candidates.end() ; it++)
     {
         parse_candidate_component(*it);
     }
 
   //End by larrin
}
 
ostream&
SdpContents::Session::Medium::encode(ostream& s) const
{
   s << "m="
     << mName << Symbols::SPACE[0]
     << mPort;
   if (mMulticast > 1)
   {
      s << Symbols::SLASH[0] << mMulticast;
   }
   s << Symbols::SPACE[0]
     << mProtocol;
 
   for (list<Data>::const_iterator i = mFormats.begin();
        i != mFormats.end(); ++i)
   {
      s << Symbols::SPACE[0] << *i;
   }
 
   if (!mCodecs.empty())
   {
      for (list<Codec>::const_iterator i = mCodecs.begin();
           i != mCodecs.end(); ++i)
      {
         s << Symbols::SPACE[0] << i->payloadType();
      }
   }
 
   s << Symbols::CRLF;
 
   if (!mInformation.empty())
   {
      s << "i=" << mInformation << Symbols::CRLF;
   }
 
   for (list<Connection>::const_iterator i = mConnections.begin();
        i != mConnections.end(); ++i)
   {
      i->encode(s);
   }
 
   for (list<Bandwidth>::const_iterator i = mBandwidths.begin();
        i != mBandwidths.end(); ++i)
   {
      i->encode(s);
   }
 
   if (mEncryption.getMethod() != Encryption::NoEncryption)
   {
      mEncryption.encode(s);
   }
 
   if (!mCodecs.empty())
   {
      // add codecs to information and attributes
      for (list<Codec>::const_iterator i = mCodecs.begin();
           i != mCodecs.end(); ++i)
      {
          // If codec is static (defined in RFC 3551) we probably shouldn't
          // add attributes for it. But some UAs do include them.
          //Codec::CodecMap& staticCodecs = Codec::getStaticCodecs();
          //if (staticCodecs.find(i->payloadType()) != staticCodecs.end())
          //{
          //    continue;
          //}
 
         s << "a=rtpmap:"
           << i->payloadType() << Symbols::SPACE[0] << *i
           << Symbols::CRLF;
         if (!i->parameters().empty())
         {
            s << "a=fmtp:"
              << i->payloadType() << Symbols::SPACE[0] << i->parameters()
              << Symbols::CRLF;
         }
      }
   }
 
   mAttributeHelper.encode(s);
 
   //Begin Add by larrin
 
   CANDIDATE_MAP::const_iterator it ;
   for(it = mCandidates.begin() ; it != mCandidates.end() ; it++)
   {
         (*it).second.encode(s);
   }
 
   //End by larrin
 
   return s;
}
 
void
SdpContents::Session::Medium::addFormat(const Data& format)
{
   mFormats.push_back(format);
}
 
void
SdpContents::Session::Medium::setConnection(const Connection& connection)
{
   mConnections.clear();
   addConnection(connection);
}
 
void
SdpContents::Session::Medium::addConnection(const Connection& connection)
{
   mConnections.push_back(connection);
}
 
void
SdpContents::Session::Medium::setBandwidth(const Bandwidth& bandwidth)
{
   mBandwidths.clear();
   addBandwidth(bandwidth);
}
 
void
SdpContents::Session::Medium::addBandwidth(const Bandwidth& bandwidth)
{
   mBandwidths.push_back(bandwidth);
}
 
void
SdpContents::Session::Medium::addAttribute(const Data& key, const Data& value)
{
     //Begin Add by larrin
     if(key == "candidate")
     {
         parse_candidate_component(value);
     }
     //End by larrin
     else
     {
         mAttributeHelper.addAttribute(key, value);
         if (key == rtpmap)
         {
              mRtpMapDone = false;
         }
     }
    
}
 
//Begin Add by larrin
bool SdpContents::Session::Medium::parse_candidate_componentconst Data &str)
{
     Data name;
     Data component;
     Data transport_type;
     int priority;
     Data ip;
     int port;
 
     ParseBuffer pb(str);
 
     try
     {
         const char* anchor = pb.skipWhitespace();
         pb.skipToChar(Symbols::SPACE[0]);
         pb.data(name, anchor);
 
         //format:a=candidate $R2 2 UDP 0.3 $STUN-PUB-5.IP $STUN-PUB-5.PORT
         anchor = pb.skipChar(Symbols::SPACE[0]);
         pb.skipToChar(Symbols::SPACE[0]);
         pb.data(component,anchor);
 
         anchor = pb.skipChar(Symbols::SPACE[0]);
         pb.skipToChar(Symbols::SPACE[0]);
          pb.data(transport_type,anchor);
 
         anchor = pb.skipChar(Symbols::SPACE[0]);
         priority = pb.integer();
 
         anchor = pb.skipChar();
         pb.skipToChar(Symbols::SPACE[0]);
         pb.data(ip,anchor);
 
         pb.skipChar();
         port = pb.integer();
     }
     catch(ParseBuffer::Exception &e)
     {
         return false ;
     }
    
     return add_candidate_component( name.c_str(),
                                          component.c_str(),
                                          transport_type.c_str(),
                                          priority,
                                          ip.c_str(),
                                          port);
    
     return true;
}
 
bool SdpContents::Session::Medium::add_candidate_component(const char *candidate_name,
                                  const char *component,
                                  const char *transport_type,
                                  int priority,
                                  const char *ip,
                                  int port)
{
     CANDIDATE_MAP::iterator it = mCandidates.find(candidate_name);
     if(it == mCandidates.end())
     {
         pair<CANDIDATE_MAP::iterator,bool> res = mCandidates.insert(CANDIDATE_MAP::value_type(candidate_name,Candidate()));
         if(res.second == false)
              return false ;
 
         it = res.first;
         Candidate &candidate = (*it).second ;
         candidate.setName(candidate_name);
         candidate.setPriority(priority);
         candidate.setTransportType(transport_type);
     }
 
     Candidate &candidate = (*it).second ;
 
     candidate.addComponent(Component(component,ip,port));
 
     return true ;
}
 
//format:a=candidate $R2 2 UDP 0.3 $STUN-PUB-5.IP $STUN-PUB-5.PORT
std::ostream& SdpContents::Session::Candidate::encode(std::ostream& s) const
{
     list<Component>::const_iterator it ;
     for(it = mComponents.begin() ; it != mComponents.end() ; it++)
     {
         const Component &component = *it;
         s << "a=candidate " << mName << " " << component.id << " " << transportType << " " << priority << " " << component.ip << " " << component.port << Symbols::CRLF;
     }
 
     return s;
}
 
//End by larrin
 
const list<SdpContents::Session::Connection>
SdpContents::Session::Medium::getConnections() const
{
   list<Connection> connections = const_cast<Medium*>(this)->getMediumConnections();
   if (mSession)
   {
      connections.push_back(mSession->connection());
   }
 
   return connections;
}
 
bool
SdpContents::Session::Medium::exists(const Data& key) const
{
   if (mAttributeHelper.exists(key))
   {
      return true;
   }
   return mSession && mSession->exists(key);
}
 
const list<Data>&
SdpContents::Session::Medium::getValues(const Data& key) const
{
   if (exists(key))
   {
      return mAttributeHelper.getValues(key);
   }
   if (!mSession)
   {
      assert(false);
      static list<Data> error;
      return error;
   }
   return mSession->getValues(key);
}
 
void
SdpContents::Session::Medium::clearAttribute(const Data& key)
{
   mAttributeHelper.clearAttribute(key);
   if (key == rtpmap)
   {
      mRtpMapDone = false;
   }
}
 
void
SdpContents::Session::Medium::clearCodecs()
{
   mFormats.clear();
   clearAttribute(rtpmap);
   clearAttribute(fmtp);
   mCodecs.clear();
}
 
void
SdpContents::Session::Medium::addCodec(const Codec& codec)
{
   codecs();
   mCodecs.push_back(codec);
}
 
 
const list<Codec>&
SdpContents::Session::Medium::codecs() const
{
   return const_cast<Medium*>(this)->codecs();
}
 
list<Codec>&
SdpContents::Session::Medium::codecs()
{
#if defined(WIN32) && defined(_MSC_VER) && (_MSC_VER < 1310) // CJ TODO fix
     assert(0);
#else
   if (!mRtpMapDone)
   {
      // prevent recursion
      mRtpMapDone = true;
 
      if (exists(rtpmap))
      {
         for (list<Data>::const_iterator i = getValues(rtpmap).begin();
              i != getValues(rtpmap).end(); ++i)
         {
            //DebugLog(<< "SdpContents::Session::Medium::getCodec(" << *i << ")");
            ParseBuffer pb(i->data(), i->size());
            int format = pb.integer();
            // pass to codec constructor for parsing
            // pass this for other codec attributes
            try
            {
               mRtpMap[format].parse(pb, *this, format);
            }
            catch (ParseBuffer::Exception&)
            {
               mRtpMap.erase(format);
            }
         }
      }
 
      for (list<Data>::const_iterator i = mFormats.begin();
           i != mFormats.end(); ++i)
      {
         int mapKey = i->convertInt();
         RtpMap::const_iterator ri = mRtpMap.find(mapKey);
         if (ri != mRtpMap.end())
         {
            //DebugLog(<< "SdpContents::Session::Medium::getCodec[](" << ri->second << ")");
            mCodecs.push_back(ri->second);
         }
         else
         {
             // !kk! Is it a static format?
             Codec::CodecMap& staticCodecs = Codec::getStaticCodecs();
             Codec::CodecMap::const_iterator ri = staticCodecs.find(mapKey);
             if (ri != staticCodecs.end())
             {
                //DebugLog(<< "Found static codec for format: " << mapKey);
                mCodecs.push_back(ri->second);
             }
         }
      }
 
      // don't store twice
      mFormats.clear();
      mAttributeHelper.clearAttribute(rtpmap);
      mAttributeHelper.clearAttribute(fmtp); // parsed out in codec.parse
   }
#endif
 
   return mCodecs;
}
 
const Codec&
SdpContents::Session::Medium::findFirstMatchingCodecs(const std::list<Codec>& codecs, Codec* pMatchingCodec) const
{
   static Codec emptyCodec;
   std::list<resip::SdpContents::Session::Codec>::const_iterator sIter;
   std::list<resip::SdpContents::Session::Codec>::const_iterator sEnd = mCodecs.end();
   std::list<resip::SdpContents::Session::Codec>::const_iterator eIter;
   std::list<resip::SdpContents::Session::Codec>::const_iterator eEnd = codecs.end();
   bool found = false;
   for (eIter = codecs.begin(); eIter != eEnd ; ++eIter)
   {
      for (sIter = mCodecs.begin(); sIter != sEnd; ++sIter)
      {
         if (*sIter == *eIter)
         {
            found = true;
              if (pMatchingCodec) *pMatchingCodec = *eIter;
            return *sIter;
         }
      }
   }
   return emptyCodec;
}
 
int
SdpContents::Session::Medium::findTelephoneEventPayloadType() const
{
   const std::list<Codec>& codecList = codecs();
   for (std::list<Codec>::const_iterator i = codecList.begin(); i != codecList.end(); i++)
   {
      if (i->getName() == SdpContents::Session::Codec::TelephoneEvent.getName())
      {
         return i->payloadType();
      }
   }
   return -1;
}
 
Codec::Codec(const Data& name,
             unsigned long rate,
             const Data& parameters)
   : mName(name),
     mRate(rate),
     mPayloadType(-1),
     mParameters(parameters)
{
}
 
Codec::Codec(const Codec& rhs)
   : mName(rhs.mName),
     mRate(rhs.mRate),
     mPayloadType(rhs.mPayloadType),
     mParameters(rhs.mParameters)
{
}
 
Codec::Codec(const Data& name, int payloadType, int rate)
   : mName(name),
     mRate(rate),
     mPayloadType(payloadType),
     mParameters()
{
}
 
Codec&
Codec::operator=(const Codec& rhs)
{
   if (this != &rhs)
   {
      mName = rhs.mName;
      mRate = rhs.mRate;
      mPayloadType = rhs.mPayloadType;
      mParameters = rhs.mParameters;
   }
   return *this;
}
 
void
Codec::parse(ParseBuffer& pb,
             const SdpContents::Session::Medium& medium,
             int payloadType)
{
   const char* anchor = pb.skipWhitespace();
   pb.skipToChar(Symbols::SLASH[0]);
   pb.data(mName, anchor);
   pb.skipChar(Symbols::SLASH[0]);
   mRate = pb.integer();
   mPayloadType = payloadType;
 
   // get parameters if they exist
   if (medium.exists(fmtp))
   {
      for (list<Data>::const_iterator i = medium.getValues(fmtp).begin();
           i != medium.getValues(fmtp).end(); ++i)
      {
         ParseBuffer pb(i->data(), i->size());
         int payload = pb.integer();
         if (payload == payloadType)
         {
            const char* anchor = pb.skipWhitespace();
            pb.skipToEnd();
            pb.data(mParameters, anchor);
            break;
         }
      }
   }
}
 
const Data&
Codec::getName() const
{
   return mName;
};
 
int
Codec::getRate() const
{
   return mRate;
};
 
Codec::CodecMap& Codec::getStaticCodecs()
{
 
    if (! sStaticCodecsCreated)
    {
        //
        // Build map of static codecs as defined in RFC 3551
        //
       sStaticCodecs = std::auto_ptr<CodecMap>(new CodecMap);
 
        // Audio codecs
        sStaticCodecs->insert(make_pair(0,Codec("PCMU",0,8000)));
        sStaticCodecs->insert(make_pair(3,Codec("GSM",3,8000)));
        sStaticCodecs->insert(make_pair(4,Codec("G723",4,8000)));
        sStaticCodecs->insert(make_pair(5,Codec("DVI4",5,8000)));
        sStaticCodecs->insert(make_pair(6,Codec("DVI4",6,16000)));
        sStaticCodecs->insert(make_pair(7,Codec("LPC",7,8000)));
        sStaticCodecs->insert(make_pair(8,Codec("PCMA",8,8000)));
        sStaticCodecs->insert(make_pair(9,Codec("G722",9,8000)));
        sStaticCodecs->insert(make_pair(10,Codec("L16-2",10,44100)));
        sStaticCodecs->insert(make_pair(11,Codec("L16-1",11,44100)));
        sStaticCodecs->insert(make_pair(12,Codec("QCELP",12,8000)));
        sStaticCodecs->insert(make_pair(13,Codec("CN",13,8000)));
        sStaticCodecs->insert(make_pair(14,Codec("MPA",14,90000)));
        sStaticCodecs->insert(make_pair(15,Codec("G728",15,8000)));
        sStaticCodecs->insert(make_pair(16,Codec("DVI4",16,11025)));
        sStaticCodecs->insert(make_pair(17,Codec("DVI4",17,22050)));
        sStaticCodecs->insert(make_pair(18,Codec("G729",18,8000)));
 
        // Video or audio/video codecs
        sStaticCodecs->insert(make_pair(25,Codec("CelB",25,90000)));
        sStaticCodecs->insert(make_pair(26,Codec("JPEG",26,90000)));
        sStaticCodecs->insert(make_pair(28,Codec("nv",28,90000)));
        sStaticCodecs->insert(make_pair(31,Codec("H261",31,90000)));
        sStaticCodecs->insert(make_pair(32,Codec("MPV",32,90000)));
        sStaticCodecs->insert(make_pair(33,Codec("MP2T",33,90000)));
        sStaticCodecs->insert(make_pair(34,Codec("H263",34,90000)));
 
        sStaticCodecsCreated = true;
    }
    return *(sStaticCodecs.get());
}
 
bool
resip::operator==(const Codec& lhs, const Codec& rhs)
{
   return (isEqualNoCase(lhs.mName, rhs.mName) && lhs.mRate == rhs.mRate);
}
 
ostream&
resip::operator<<(ostream& str, const Codec& codec)
{
   str << codec.mName;
   str << Symbols::SLASH[0];
   str << codec.mRate;
   return str;
}
 
const Codec Codec::ULaw_8000("PCMU", 0, 8000);
const Codec Codec::ALaw_8000("PCMA", 8, 8000);
const Codec Codec::G729_8000("G729", 18, 8000);
const Codec Codec::G723_8000("G723", 4, 8000);
const Codec Codec::GSM_8000("GSM", 3, 8000);
 
const Codec Codec::TelephoneEvent("telephone-event", 101, 8000);
const Codec Codec::FrfDialedDigit("frf-dialed-event",102, 8000);
 
bool Codec::sStaticCodecsCreated = false;
std::auto_ptr<Codec::CodecMap> Codec::sStaticCodecs;
 
/* ====================================================================
 * The Vovida Software License, Version 1.0
 *
 * Copyright (c) 2000 Vovida Networks, Inc. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this vector of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this vector of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The names "VOCAL", "Vovida Open Communication Application Library",
 *    and "Vovida Open Communication Application Library (VOCAL)" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact vocal@vovida.org.
 *
 * 4. Products derived from this software may not be called "VOCAL", nor
 *    may "VOCAL" appear in their name, without prior written
 *    permission of Vovida Networks, Inc.
 *
 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
 * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA
 * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
 * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
 * DAMAGE.
 *
 * ====================================================================
 *
 * This software consists of voluntary contributions made by Vovida
 * Networks, Inc. and many individuals on behalf of Vovida Networks,
 * Inc. For more information on Vovida Networks, Inc., please see
 * <http://www.vovida.org/>.
 *
 */