@ -23,6 +23,9 @@
using std : : string ;
using std : : map ;
# include <cctype>
# include <algorithm>
// Not on Solaris!
# if !defined (__SVR4) && !defined (__sun)
# include "strings.h"
@ -42,8 +45,8 @@ static char* parse_until(char* s, char* end, char c);
static bool contains ( char * s , char * next_line , char c ) ;
static bool is_wsp ( char s ) ;
static int media_type ( std : : string media ) ;
static in t transport_type ( std : : string transport ) ;
static MediaType media_type ( std : : string media ) ;
static TransPro t transport_type ( std : : string transport ) ;
static bool attr_check ( std : : string attr ) ;
enum parse_st { SDP_DESCR , SDP_MEDIA } ;
@ -81,6 +84,7 @@ inline string media_t_2_str(int mt)
case MT_APPLICATION : return " application " ;
case MT_TEXT : return " text " ;
case MT_MESSAGE : return " message " ;
case MT_IMAGE : return " image " ;
default : return " <unknown media type> " ;
}
}
@ -91,6 +95,7 @@ inline string transport_p_2_str(int tp)
case TP_RTPAVP : return " RTP/AVP " ;
case TP_UDP : return " udp " ;
case TP_RTPSAVP : return " RTP/SAVP " ;
case TP_UDPTL : return " udptl " ;
default : return " <unknown media type> " ;
}
}
@ -175,12 +180,24 @@ SdpPayload* AmSdp::telephoneEventPayload() const {
void AmSdp : : print ( string & body ) const
{
string out_buf =
" v= " + int2str ( version ) + " \r \n "
" o= " + origin . user + " " + int2str ( origin . sessId ) + " " + int2str ( origin . sessV ) + " IN IP4 " + conn . address + " \r \n "
" s= " + sessionName + " \r \n "
" c=IN IP4 " + conn . address + " \r \n "
" t=0 0 \r \n " ;
string out_buf = " v= " + int2str ( version ) + " \r \n "
" o= " + origin . user + " " + int2str ( origin . sessId ) + " " +
int2str ( origin . sessV ) + " IN IP4 " ;
if ( ! origin . conn . address . empty ( ) )
out_buf + = origin . conn . address + " \r \n " ;
else if ( ! conn . address . empty ( ) )
out_buf + = conn . address + " \r \n " ;
else if ( media . size ( ) & & ! media [ 0 ] . conn . address . empty ( ) )
out_buf + = media [ 0 ] . conn . address + " \r \n " ;
else
out_buf + = " 0.0.0.0 \r \n " ;
out_buf + =
" s= " + sessionName + " \r \n " ;
if ( ! conn . address . empty ( ) )
out_buf + = " c=IN IP4 " + conn . address + " \r \n " ;
out_buf + = " t=0 0 \r \n " ;
// add attributes (session level)
for ( std : : vector < SdpAttribute > : : const_iterator a_it =
@ -193,37 +210,43 @@ void AmSdp::print(string& body) const
out_buf + = " m= " + media_t_2_str ( media_it - > type ) + " " + int2str ( media_it - > port ) + " " + transport_p_2_str ( media_it - > transport ) ;
string options ;
for ( std : : vector < SdpPayload > : : const_iterator pl_it = media_it - > payloads . begin ( ) ;
pl_it ! = media_it - > payloads . end ( ) ; pl_it + + ) {
if ( media_it - > transport = = TP_RTPAVP | | media_it - > transport = = TP_RTPSAVP ) {
string options ;
for ( std : : vector < SdpPayload > : : const_iterator pl_it = media_it - > payloads . begin ( ) ;
pl_it ! = media_it - > payloads . end ( ) ; pl_it + + ) {
out_buf + = " " + int2str ( pl_it - > payload_type ) ;
if ( ! media_it - > conn . address . empty ( ) )
options + = " c=IN IP4 " + media_it - > conn . address + " \r \n " ;
if ( pl_it - > encoding_name . empty ( ) ) // don't add rtpmap if no encoding name given
continue ;
continue ;
// "a=rtpmap:" line
options + = " a=rtpmap: " + int2str ( pl_it - > payload_type ) + " "
+ pl_it - > encoding_name + " / " + int2str ( pl_it - > clock_rate ) ;
+ pl_it - > encoding_name + " / " + int2str ( pl_it - > clock_rate ) ;
if ( pl_it - > encoding_param > 0 ) {
options + = " / " + int2str ( pl_it - > encoding_param ) ;
options + = " / " + int2str ( pl_it - > encoding_param ) ;
}
options + = " \r \n " ;
// "a=fmtp:" line
if ( pl_it - > sdp_format_parameters . size ( ) ) {
options + = " a=fmtp: " + int2str ( pl_it - > payload_type ) + " "
+ pl_it - > sdp_format_parameters + " \r \n " ;
options + = " a=fmtp: " + int2str ( pl_it - > payload_type ) + " "
+ pl_it - > sdp_format_parameters + " \r \n " ;
}
}
}
out_buf + = " \r \n " + options ;
out_buf + = " \r \n " + options ;
if ( remote_active /* dir == SdpMedia::DirActive */ )
out_buf + = " a=direction:passive \r \n " ;
} else {
// for other transports (UDP/UDPTL) just print out fmt
out_buf + = " " + media_it - > fmt + " \r \n " ;
}
// add attributes (media level)
for ( std : : vector < SdpAttribute > : : const_iterator a_it =
@ -231,6 +254,12 @@ void AmSdp::print(string& body) const
out_buf + = a_it - > print ( ) ;
}
switch ( media_it - > dir ) {
case SdpMedia : : DirActive : out_buf + = " a=direction:active \r \n " ; break ;
case SdpMedia : : DirPassive : out_buf + = " a=direction:passive \r \n " ; break ;
case SdpMedia : : DirBoth : out_buf + = " a=direction:both \r \n " ; break ;
case SdpMedia : : DirUndefined : break ;
}
}
body = out_buf ;
@ -727,7 +756,6 @@ static void parse_sdp_media(AmSdp* sdp_msg, char* s)
SdpPayload payload ;
unsigned int payload_type ;
DBG ( " parse_sdp_line_ex: parse_sdp_media: parsing media description... \n " ) ;
m . dir = SdpMedia : : DirBoth ;
while ( parsing ) {
switch ( state ) {
@ -738,7 +766,7 @@ static void parse_sdp_media(AmSdp* sdp_msg, char* s)
if ( next > media_line )
media = string ( media_line , int ( next - media_line ) - 1 ) ;
m . type = media_type ( media ) ;
if ( m . type < 0 ) {
if ( m . type == MT_NONE ) {
ERROR ( " parse_sdp_media: Unknown media type \n " ) ;
}
media_line = next ;
@ -787,7 +815,7 @@ static void parse_sdp_media(AmSdp* sdp_msg, char* s)
// break;
// }
m . transport = transport_type ( proto ) ;
if ( m . transport < 0 ) {
if ( m . transport == TP_NONE ) {
DBG ( " Unknown transport protocol: %s \n " , proto . c_str ( ) ) ;
}
media_line = next ;
@ -796,41 +824,49 @@ static void parse_sdp_media(AmSdp* sdp_msg, char* s)
}
case FMT :
{
if ( contains ( media_line , line_end , ' ' ) ) {
next = parse_until ( media_line , ' ' ) ;
string value ;
if ( next > media_line )
value = string ( media_line , int ( next - media_line ) - 1 ) ;
if ( ! value . empty ( ) ) {
payload . type = m . type ;
str2i ( value , payload_type ) ;
payload . payload_type = payload_type ;
m . payloads . push_back ( payload ) ;
}
media_line = next ;
state = FMT ;
} else {
string last_value ;
if ( line_end > media_line ) {
if ( * line_end = = ' \0 ' ) {
// last line in message
last_value = string ( media_line , int ( line_end - media_line ) ) ;
} else {
last_value = string ( media_line , int ( line_end - media_line ) - 1 ) ;
if ( m . transport = = TP_RTPAVP | | m . transport = = TP_RTPSAVP ) {
if ( contains ( media_line , line_end , ' ' ) ) {
next = parse_until ( media_line , ' ' ) ;
string value ;
if ( next > media_line )
value = string ( media_line , int ( next - media_line ) - 1 ) ;
if ( ! value . empty ( ) ) {
payload . type = m . type ;
str2i ( value , payload_type ) ;
payload . payload_type = payload_type ;
m . payloads . push_back ( payload ) ;
}
media_line = next ;
} else {
string last_value ;
if ( line_end > media_line ) {
if ( * line_end = = ' \0 ' ) {
// last line in message
last_value = string ( media_line , int ( line_end - media_line ) ) ;
} else {
last_value = string ( media_line , int ( line_end - media_line ) - 1 ) ;
}
}
if ( ! last_value . empty ( ) ) {
payload . type = m . type ;
str2i ( last_value , payload_type ) ;
payload . payload_type = payload_type ;
m . payloads . push_back ( payload ) ;
}
parsing = 0 ;
}
if ( ! last_value . empty ( ) ) {
payload . type = m . type ;
str2i ( last_value , payload_type ) ;
payload . payload_type = payload_type ;
m . payloads . push_back ( payload ) ;
}
} else {
line_end - - ;
while ( line_end > media_line & &
( * line_end = = ' \r ' | | * line_end = = ' \n ' ) )
line_end - - ;
if ( line_end > media_line )
m . fmt = string ( media_line , line_end - media_line + 1 ) ;
DBG ( " set media fmt to '%s' \n " , m . fmt . c_str ( ) ) ;
parsing = 0 ;
}
break ;
}
} break ;
}
}
sdp_msg - > media . push_back ( m ) ;
@ -1053,32 +1089,28 @@ static void parse_sdp_attr(AmSdp* sdp_msg, char* s)
} else {
attr_check ( attr ) ;
next = parse_until ( attr_line , ' \r ' ) ;
if ( next < line_end ) {
string value ( attr_line , int ( next - attr_line ) - 1 ) ;
DBG ( " found media attr '%s' value '%s' \n " ,
( char * ) attr . c_str ( ) , ( char * ) value . c_str ( ) ) ;
media . attributes . push_back ( SdpAttribute ( attr , value ) ) ;
} else {
if ( next > = line_end ) {
DBG ( " found media attr '%s', but value is not followed by cr \n " ,
( char * ) attr . c_str ( ) ) ;
}
string value ( attr_line , int ( next - attr_line ) - 1 ) ;
DBG ( " found media attr '%s' value '%s' \n " ,
( char * ) attr . c_str ( ) , ( char * ) value . c_str ( ) ) ;
media . attributes . push_back ( SdpAttribute ( attr , value ) ) ;
}
} else {
next = parse_until ( attr_line , ' \r ' ) ;
if ( next < line_end ) {
string attr ( attr_line , int ( next - attr_line ) - 1 ) ;
attr_check ( attr ) ;
DBG ( " found media attr '%s' \n " , ( char * ) attr . c_str ( ) ) ;
media . attributes . push_back ( SdpAttribute ( attr ) ) ;
} else {
if ( next > = line_end ) {
DBG ( " found media attr line '%s', which is not followed by cr \n " ,
attr_line ) ;
}
string attr ( attr_line , int ( next - attr_line ) - 1 ) ;
attr_check ( attr ) ;
DBG ( " found media attr '%s' \n " , ( char * ) attr . c_str ( ) ) ;
media . attributes . push_back ( SdpAttribute ( attr ) ) ;
}
return ;
}
static void parse_sdp_origin ( AmSdp * sdp_msg , char * s )
@ -1172,10 +1204,10 @@ static void parse_sdp_origin(AmSdp* sdp_msg, char* s)
next = parse_until ( origin_line , ' ' ) ;
//check if line contains more values than allowed
if ( next > line_end ) {
string unicast_addr ( origin_line , int ( line_end - origin_line ) - 1 ) ;
origin. conn . address = string ( origin_line , int ( line_end - origin_line ) - 2 ) ;
} else {
DBG ( " parse_sdp_origin: 'o=' contains more values than allowed; these values will be ignored \n " ) ;
string unicast_addr ( origin_line , int ( next - origin_line ) - 1 ) ;
origin. conn . address = string ( origin_line , int ( next - origin_line ) - 1 ) ;
}
parsing = 0 ;
break ;
@ -1263,32 +1295,39 @@ inline char* get_next_line(char* s)
/*
* Check if known media type is used
*/
static int media_type ( std : : string media )
static MediaType media_type ( std : : string media )
{
if ( media = = " audio " )
return 1 ;
return MT_AUDIO ;
else if ( media = = " video " )
return 2 ;
return MT_VIDEO ;
else if ( media = = " application " )
return 3 ;
return MT_APPLICATION ;
else if ( media = = " text " )
return 4 ;
return MT_TEXT ;
else if ( media = = " message " )
return 5 ;
return MT_MESSAGE ;
else if ( media = = " image " )
return MT_IMAGE ;
else
return - 1 ;
return MT_NONE ;
}
static int transport_type ( std : : string transport )
static TransProt transport_type ( string transport )
{
if ( transport = = " RTP/AVP " )
return 1 ;
else if ( transport = = " UDP " )
return 2 ;
else if ( transport = = " RTP/SAVP " )
return 3 ;
string transport_uc = transport ;
std : : transform ( transport_uc . begin ( ) , transport_uc . end ( ) , transport_uc . begin ( ) , toupper ) ;
if ( transport_uc = = " RTP/AVP " )
return TP_RTPAVP ;
else if ( transport_uc = = " UDP " )
return TP_UDP ;
else if ( transport_uc = = " RTP/SAVP " )
return TP_RTPSAVP ;
else if ( transport_uc = = " UDPTL " )
return TP_UDPTL ;
else
return - 1 ;
return TP_NONE ;
}
/*
@ -1336,7 +1375,7 @@ static bool attr_check(std::string attr)
return true ;
else
{
DBG ( " sdp_parse_attr: Unknown attribute name used: %s, plz see RFC4566\n " ,
DBG ( " sdp_parse_attr: Unknown attribute name used: %s, plz see RFC4566\n " ,
( char * ) attr . c_str ( ) ) ;
return false ;
}