/**************************************************************************** 
** File: rtp.c
**
** Author: Mike Borella
**
** Comments: Dump RTP header information. 
**
** $Id: rtp.c,v 1.7 2001/10/11 20:43:50 mborella Exp $
**
** 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 2 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 Library General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
**
*****************************************************************************/

#include "rtp.h"

/*
 * Static part of RTP header
 *  0                   1                   2                   3
 *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 * |V=2|P|X|  CC   |M|     PT      |       sequence number         |
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 * |                           timestamp                           |
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 * |           synchronization source (SSRC) identifier            |
 * +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
 * |            contributing source (CSRC) identifiers             |
 * |                             ....                              |
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 */

typedef struct rtp_header
{
#if defined(WORDS_BIGENDIAN)
  u_int8_t version:2,
	   padding:1,
	   extension:1,
	   csrc_count:4;
#else
  u_int8_t csrc_count:4,
            extension:1,
            padding:1,
            version:2;
#endif
#if defined(WORDS_BIGENDIAN)
  u_int8_t marker:1,
           payload_type:7;
#else
  u_int8_t payload_type:7,
	   marker:1;
#endif
  u_int16_t seqno;
  u_int32_t timestamp;
  u_int32_t ssrc;
  
} rtp_header_t;

/* 
 * RTP payload type definitions 
 */

#define RTP_PAYLOADTYPE_PCMU         0
#define RTP_PAYLOADTYPE_1016         1
#define RTP_PAYLOADTYPE_G72632       2
#define RTP_PAYLOADTYPE_GSM          3
#define RTP_PAYLOADTYPE_G723         4
#define RTP_PAYLOADTYPE_DVI48000     5
#define RTP_PAYLOADTYPE_DVI416000    6
#define RTP_PAYLOADTYPE_LPC          7
#define RTP_PAYLOADTYPE_PCMA         8
#define RTP_PAYLOADTYPE_G722         9
#define RTP_PAYLOADTYPE_L161CH       10
#define RTP_PAYLOADTYPE_L162CH       11
#define RTP_PAYLOADTYPE_QCELP        12
#define RTP_PAYLOADTYPE_RESERVED1    13
#define RTP_PAYLOADTYPE_MPA          14
#define RTP_PAYLOADTYPE_G728         15
#define RTP_PAYLOADTYPE_DVI411025    16
#define RTP_PAYLOADTYPE_DVI422050    17
#define RTP_PAYLOADTYPE_G729         18
#define RTP_PAYLOADTYPE_RESERVED2    19
#define RTP_PAYLOADTYPE_CELB         25
#define RTP_PAYLOADTYPE_JPEG         26
#define RTP_PAYLOADTYPE_NV           28
#define RTP_PAYLOADTYPE_H261         31
#define RTP_PAYLOADTYPE_MPV          32
#define RTP_PAYLOADTYPE_MP2T         33
#define RTP_PAYLOADTYPE_H263         34

/*
 * RTP payload type map
 */

strmap_t rtp_payloadtype_map[] =
{
  { RTP_PAYLOADTYPE_PCMU,       "PCMU" },
  { RTP_PAYLOADTYPE_1016,       "1016" },
  { RTP_PAYLOADTYPE_G72632,     "G726-32" },
  { RTP_PAYLOADTYPE_G723,       "G723" },
  { RTP_PAYLOADTYPE_DVI48000,   "DVI4 8000Hz" },
  { RTP_PAYLOADTYPE_DVI416000,  "DVI4 16000Hz" },
  { RTP_PAYLOADTYPE_LPC,        "LPC" },
  { RTP_PAYLOADTYPE_PCMA,       "PCMA" },
  { RTP_PAYLOADTYPE_G722,       "G722" },
  { RTP_PAYLOADTYPE_L161CH,     "L16 one channel" },
  { RTP_PAYLOADTYPE_L162CH,     "L16 two channels" },
  { RTP_PAYLOADTYPE_QCELP,      "QCELP" },
  { RTP_PAYLOADTYPE_RESERVED1,  "reserved" },
  { RTP_PAYLOADTYPE_MPA,        "MPA" },
  { RTP_PAYLOADTYPE_G728,       "G728" },
  { RTP_PAYLOADTYPE_DVI411025,  "DVI4 11025Hz" },
  { RTP_PAYLOADTYPE_DVI422050,  "DVI4 22050Hz" },
  { RTP_PAYLOADTYPE_G729,       "G729" },
  { RTP_PAYLOADTYPE_RESERVED2,  "reserved" },
  { RTP_PAYLOADTYPE_CELB,       "CELB" },
  { RTP_PAYLOADTYPE_JPEG,       "JPEG" },
  { RTP_PAYLOADTYPE_NV,         "NV" },
  { RTP_PAYLOADTYPE_H261,       "H261" },
  { RTP_PAYLOADTYPE_MPV,        "MPV" },
  { RTP_PAYLOADTYPE_MP2T,       "MP2T" },
  { RTP_PAYLOADTYPE_H263,       "H263" },
  { 0, ""}
};

extern struct arg_t * my_args;

/*----------------------------------------------------------------------------
**
** dump_rtp()
**
** Parse RTP packet and dump fields
**
**----------------------------------------------------------------------------
*/

void dump_rtp(packet_t * pkt)
{
  rtp_header_t rtp;
  u_int8_t     payload_type;
  u_int8_t     marker;
  u_int8_t     csrc_count;
  u_int8_t     extension;
  u_int8_t     padding;
  u_int8_t     version;
  u_int8_t     i;

  /* Set the layer */
  set_layer(LAYER_APPLICATION);

  /* Get the fixed RTP header */
  if (get_packet_bytes((u_int8_t *) &rtp, pkt, sizeof(rtp)) == 0)
    return;
  
  /* Conversions */
  payload_type = rtp.payload_type;
  marker = rtp.marker;
  csrc_count = rtp.csrc_count;
  extension = rtp.extension;
  padding = rtp.padding;
  version = rtp.version;
  rtp.seqno = ntohs(rtp.seqno);
  rtp.timestamp = ntohl(rtp.timestamp);
  rtp.ssrc = ntohl(rtp.ssrc);

  /* Display */
  if (my_args->m)
    {
      display_minimal_string("| RTPv");
      display_minimal((u_int8_t *) &version, 1, DISP_DEC);
      display_minimal_string(" (");
      display_minimal_string(map2str(rtp_payloadtype_map, payload_type));
      display_minimal_string(",");
      display_minimal((u_int8_t *) &rtp.seqno, 2, DISP_DEC);
      display_minimal_string(") ");
    }
  else
    {
      display_header_banner("RTP Header");
      display("Version", (u_int8_t *) &version, 1, DISP_DEC);
      display("Padding", (u_int8_t *) &padding, 1, DISP_DEC);
      display("Extension", (u_int8_t *) &extension, 1, DISP_DEC);
      display("CSRC count", (u_int8_t *) &csrc_count, 1, DISP_DEC);
      display("Marker", (u_int8_t *) &marker, 1, DISP_DEC);
      display_strmap("Payload type", payload_type, rtp_payloadtype_map);
      display("Sequence number", (u_int8_t *) &rtp.seqno, 2, DISP_DEC);
      display("Timestamp", (u_int8_t *) &rtp.timestamp, 4, DISP_DEC);
      display("SSRC", (u_int8_t *) &rtp.ssrc, 4, DISP_DEC);

      /* Dump contributing sources */
      for (i=0; i < csrc_count; i++)
	{
	  u_int32_t csrc;
	  if (get_packet_bytes((u_int8_t *) &csrc, pkt, sizeof(u_int32_t)) 
	      == 0)
	    return;
	  display("CSRC", (u_int8_t *) &csrc, 4, DISP_DEC);
	}
    }
  
  /* Dump the hex buffer */
  hexbuffer_flush();
}
