Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
What's new
10
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Open sidebar
BC
public
liblinphone
Commits
39ff61f8
Commit
39ff61f8
authored
Jan 11, 2010
by
Simon Morlat
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
SAL (signaling abstraction layer) in progress.
parent
1d96392a
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
619 additions
and
0 deletions
+619
-0
linphone/coreapi/Makefile.am
linphone/coreapi/Makefile.am
+3
-0
linphone/coreapi/offeranswer.c
linphone/coreapi/offeranswer.c
+142
-0
linphone/coreapi/offeranswer.h
linphone/coreapi/offeranswer.h
+47
-0
linphone/coreapi/sal.h
linphone/coreapi/sal.h
+104
-0
linphone/coreapi/sal_eXosip2.c
linphone/coreapi/sal_eXosip2.c
+153
-0
linphone/coreapi/sal_eXosip2_sdp.c
linphone/coreapi/sal_eXosip2_sdp.c
+170
-0
No files found.
linphone/coreapi/Makefile.am
View file @
39ff61f8
...
...
@@ -16,6 +16,9 @@ lib_LTLIBRARIES=liblinphone.la
liblinphone_la_SOURCES
=
\
linphonecore.c linphonecore.h private.h
\
exevents.c exevents.h
\
offeranswer.c offeranswer.h
\
sal_eXosip2.c sal.h
\
sal_eXosip2_sdp.c
\
misc.c
\
address.c
\
enum.c enum.h
\
...
...
linphone/coreapi/offeranswer.c
0 → 100644
View file @
39ff61f8
/*
linphone
Copyright (C) 2010 Simon MORLAT (simon.morlat@free.fr)
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 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 "sal.h"
#include "offeranswer.h"
static
PayloadType
*
find_payload_type_best_match
(
const
MSList
*
l
,
const
PayloadType
*
refpt
){
PayloadType
*
pt
;
char
value
[
10
];
const
MSList
*
elem
;
PayloadType
*
candidate
=
NULL
;
for
(
elem
=
l
;
elem
!=
NULL
;
elem
=
elem
->
next
){
pt
=
(
PayloadType
*
)
elem
->
data
;
if
(
strcasecmp
(
pt
->
mime_type
,
refpt
->
mime_type
)
==
0
&&
pt
->
clock_rate
==
refpt
->
clock_rate
){
candidate
=
pt
;
/*good candidate, check fmtp for H264 */
if
(
strcasecmp
(
pt
->
mime_type
,
"H264"
)
==
0
){
if
(
pt
->
recv_fmtp
!=
NULL
&&
refpt
->
recv_fmtp
!=
NULL
){
int
mode1
=
0
,
mode2
=
0
;
if
(
fmtp_get_value
(
pt
->
recv_fmtp
,
"packetization-mode"
,
value
,
sizeof
(
value
))){
mode1
=
atoi
(
value
);
}
if
(
fmtp_get_value
(
refpt
->
recv_fmtp
,
"packetization-mode"
,
value
,
sizeof
(
value
))){
mode2
=
atoi
(
value
);
}
if
(
mode1
==
mode2
)
break
;
/*exact match */
}
}
else
break
;
}
}
return
candidate
;
}
static
MSList
*
match_payloads
(
const
MSList
*
local
,
const
MSList
*
remote
){
const
MSList
*
e2
;
MSList
*
res
=
NULL
;
PayloadType
*
matched
;
for
(
e2
=
remote
;
e2
!=
NULL
;
e2
=
e2
->
next
){
PayloadType
*
p2
=
(
PayloadType
*
)
e2
->
data
;
matched
=
find_payload_type_best_match
(
local
,
p2
);
if
(
matched
){
matched
=
payload_type_clone
(
matched
);
if
(
p2
->
recv_fmtp
)
payload_type_set_send_fmtp
(
matched
,
p2
->
recv_fmtp
);
res
=
ms_list_append
(
res
,
matched
);
payload_type_set_number
(
matched
,
payload_type_get_number
(
p2
));
}
else
{
ms_message
(
"No match for %s/%i"
,
p2
->
mime_type
,
p2
->
clock_rate
);
}
}
return
res
;
}
static
bool_t
only_telephone_event
(
const
MSList
*
l
){
for
(;
l
!=
NULL
;
l
=
l
->
next
){
PayloadType
*
p
=
(
PayloadType
*
)
l
->
data
;
if
(
strcasecmp
(
p
->
mime_type
,
"telephone-event"
)
!=
0
){
return
FALSE
;
}
}
return
TRUE
;
}
static
void
initiate_outgoing
(
const
SalStreamDescription
*
local_offer
,
const
SalStreamDescription
*
remote_answer
,
SalStreamDescription
*
result
){
result
->
payloads
=
match_payloads
(
local_offer
->
payloads
,
remote_answer
->
payloads
);
if
(
result
->
payloads
&&
!
only_telephone_event
(
result
->
payloads
)){
result
->
port
=
remote_answer
->
port
;
result
->
bandwidth
=
remote_answer
->
bandwidth
;
result
->
ptime
=
remote_answer
->
ptime
;
}
else
{
result
->
port
=
0
;
}
}
static
void
initiate_incoming
(
const
SalStreamDescription
*
local_cap
,
const
SalStreamDescription
*
remote_offer
,
SalStreamDescription
*
result
){
result
->
payloads
=
match_payloads
(
local_cap
->
payloads
,
remote_offer
->
payloads
);
if
(
result
->
payloads
&&
!
only_telephone_event
(
result
->
payloads
)){
result
->
port
=
remote_offer
->
port
;
result
->
bandwidth
=
remote_offer
->
bandwidth
;
result
->
ptime
=
remote_offer
->
ptime
;
}
else
{
result
->
port
=
0
;
}
}
/**
* Returns a media description to run the streams with, based on a local offer
* and the returned response (remote).
**/
int
offer_answer_initiate_outgoing
(
const
SalMediaDescription
*
local_offer
,
const
SalMediaDescription
*
remote_answer
,
SalMediaDescription
*
result
){
int
i
;
for
(
i
=
0
;
i
<
local_offer
->
nstreams
;
++
i
){
initiate_outgoing
(
&
local_offer
->
streams
[
i
],
&
remote_answer
->
streams
[
i
],
&
result
->
streams
[
i
]);
}
result
->
nstreams
=
local_offer
->
nstreams
;
strcpy
(
result
->
addr
,
remote_answer
->
addr
);
return
0
;
}
/**
* Returns a media description to run the streams with, based on the local capabilities and
* and the received offer.
* The returned media description is an answer and should be sent to the offerer.
**/
int
offer_answer_initiate_incoming
(
const
SalMediaDescription
*
local_capabilities
,
const
SalMediaDescription
*
remote_offer
,
SalMediaDescription
*
result
){
int
i
;
for
(
i
=
0
;
i
<
local_capabilities
->
nstreams
;
++
i
){
initiate_incoming
(
&
local_capabilities
->
streams
[
i
],
&
remote_offer
->
streams
[
i
],
&
result
->
streams
[
i
]);
}
result
->
nstreams
=
local_capabilities
->
nstreams
;
strcpy
(
result
->
addr
,
remote_offer
->
addr
);
return
0
;
}
linphone/coreapi/offeranswer.h
0 → 100644
View file @
39ff61f8
/*
linphone
Copyright (C) 2010 Simon MORLAT (simon.morlat@free.fr)
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 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.
*/
#ifndef offeranswer_h
#define offeranswer_h
/**
This header files defines the SDP offer answer API.
It can be used by implementations of SAL directly.
**/
/**
* Returns a media description to run the streams with, based on a local offer
* and the returned response (remote).
**/
int
offer_answer_initiate_outgoing
(
const
SalMediaDescription
*
local_offer
,
const
SalMediaDescription
*
remote_answer
,
SalMediaDescription
*
result
);
/**
* Returns a media description to run the streams with, based on the local capabilities and
* and the received offer.
* The returned media description is an answer and should be sent to the offerer.
**/
int
offer_answer_initiate_incoming
(
const
SalMediaDescription
*
local_capabilities
,
const
SalMediaDescription
*
remote_offer
,
SalMediaDescription
*
result
);
#endif
linphone/coreapi/sal.h
0 → 100644
View file @
39ff61f8
/*
linphone
Copyright (C) 2010 Simon MORLAT (simon.morlat@free.fr)
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 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.
*/
/**
This header files defines the Signaling Abstraction Layer.
The purpose of this layer is too allow experiment different call signaling
protocols and implementations under linphone, for example SIP, JINGLE...
**/
#ifndef sal_h
#define sal_h
#include "mediastreamer2/mscommon.h"
struct
Sal
;
typedef
struct
Sal
Sal
;
struct
SalOp
;
typedef
struct
SalOp
SalOp
;
Sal
*
sal_init
();
void
sal_uninit
(
Sal
*
sal
);
typedef
enum
{
SAL_TRANSPORT_DATAGRAM
,
SAL_TRANSPORT_STREAM
}
SalTransport
;
typedef
enum
{
SAL_AUDIO
,
SAL_VIDEO
,
SAL_OTHER
}
SalStreamType
;
typedef
struct
SalStreamDescription
{
SalStreamType
type
;
int
port
;
MSList
*
payloads
;
//<list of PayloadType
int
bandwidth
;
int
ptime
;
}
SalStreamDescription
;
typedef
struct
SalMediaDescription
{
char
addr
[
64
];
char
username
[
64
];
int
nstreams
;
SalStreamDescription
streams
[
2
];
}
SalMediaDescription
;
void
sal_media_description_free
(
SalMediaDescription
*
md
);
typedef
enum
SalError
{
SalErrorNetwork
,
SalErrorMedia
,
SalErrorAuth
,
SalErrorForbidden
}
SalError
;
typedef
void
(
*
SalOnCallReceived
)(
SalOp
*
op
);
typedef
void
(
*
SalOnCallRinging
)(
SalOp
*
op
);
typedef
void
(
*
SalOnCallAccepted
)(
SalOp
*
op
);
typedef
void
(
*
SalOnCallTerminated
)(
SalOp
*
op
);
typedef
void
(
*
SalOnCallFailure
)(
SalOp
*
op
,
SalError
error
,
const
char
*
details
);
int
sal_listen_port
(
Sal
*
ctx
,
const
char
*
addr
,
int
port
,
SalTransport
tr
,
int
is_secure
);
void
sal_set_user_agent
(
Sal
*
ctx
,
const
char
*
user_agent
);
void
sal_use_session_timers
(
Sal
*
ctx
,
int
expires
);
SalOp
*
sal_call_create
(
Sal
*
sal
,
const
char
*
from
,
const
char
*
to
,
const
char
*
route
,
const
char
*
contact
);
int
sal_call_set_local_media_description
(
SalOp
*
h
,
const
SalMediaDescription
*
desc
);
int
sal_call
(
SalOp
*
h
);
int
sal_call_accept
(
SalOp
*
h
);
int
sal_call_get_final_media_description
(
SalOp
*
h
,
SalMediaDescription
*
result
);
int
sal_call_terminate
(
SalOp
*
h
);
int
sal_iterate
(
Sal
*
sal
);
SalOp
*
sal_register_create
(
Sal
*
ctx
,
const
char
*
from
,
const
char
*
contact
,
int
expires
);
int
sal_register
(
SalOp
*
h
);
void
sal_op_release
(
SalOp
*
h
);
#define payload_type_set_number(pt,n) (pt)->user_data=(void*)((long)n);
#define payload_type_get_number(pt) ((int)(long)(pt)->user_data)
#endif
linphone/coreapi/sal_eXosip2.c
0 → 100644
View file @
39ff61f8
/*
linphone
Copyright (C) 2010 Simon MORLAT (simon.morlat@free.fr)
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 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 "sal.h"
#include <eXosip2/eXosip.h>
extern
char
*
media_description_to_sdp
(
const
SalMediaDescription
*
sal
);
struct
Sal
{
int
running
;
int
session_expires
;
};
struct
SalOp
{
int
cid
;
int
did
;
int
tid
;
osip_message_t
*
request
;
};
static
SalOp
*
sal_op_new
(){
SalOp
*
op
=
ms_new
(
SalOp
,
1
);
op
->
cid
=
op
->
did
=
op
->
tid
=-
1
;
op
->
request
=
NULL
;
return
op
;
}
void
sal_op_release
(
SalOp
*
op
){
ms_free
(
op
);
}
Sal
*
sal_init
(){
eXosip_init
();
return
ms_new0
(
Sal
,
1
);
}
void
sal_uninit
(
Sal
*
sal
){
eXosip_quit
();
ms_free
(
sal
);
}
int
sal_listen_port
(
Sal
*
ctx
,
const
char
*
addr
,
int
port
,
SalTransport
tr
,
int
is_secure
){
int
err
;
bool_t
ipv6
;
int
proto
=
IPPROTO_UDP
;
if
(
ctx
->
running
)
eXosip_quit
();
eXosip_init
();
err
=
0
;
eXosip_set_option
(
13
,
&
err
);
/*13=EXOSIP_OPT_SRV_WITH_NAPTR, as it is an enum value, we can't use it unless we are sure of the
version of eXosip, which is not the case*/
/*see if it looks like an IPv6 address*/
ipv6
=
strchr
(
addr
,
':'
)
!=
NULL
;
eXosip_enable_ipv6
(
ipv6
);
if
(
tr
!=
SAL_TRANSPORT_DATAGRAM
||
is_secure
){
ms_fatal
(
"SIP over TCP or TLS or DTLS is not supported yet."
);
return
-
1
;
}
err
=
eXosip_listen_addr
(
proto
,
addr
,
port
,
ipv6
?
PF_INET6
:
PF_INET
,
0
);
return
err
;
}
void
sal_set_user_agent
(
Sal
*
ctx
,
const
char
*
user_agent
){
eXosip_set_user_agent
(
user_agent
);
}
void
sal_use_session_timers
(
Sal
*
ctx
,
int
expires
){
ctx
->
session_expires
=
expires
;
}
SalOp
*
sal_call_create
(
Sal
*
sal
,
const
char
*
from
,
const
char
*
to
,
const
char
*
route
,
const
char
*
contact
){
int
err
;
SalOp
*
op
;
osip_message_t
*
invite
=
NULL
;
err
=
eXosip_call_build_initial_invite
(
&
invite
,
to
,
from
,
route
,
"Phone call"
);
if
(
err
!=
0
){
ms_error
(
"Could not create call."
);
return
NULL
;
}
if
(
contact
)
osip_message_set_contact
(
invite
,
contact
);
if
(
sal
->
session_expires
!=
0
){
osip_message_set_header
(
invite
,
"Session-expires"
,
"200"
);
osip_message_set_supported
(
invite
,
"timer"
);
}
op
=
sal_op_new
();
op
->
request
=
invite
;
return
op
;
}
static
void
set_sdp
(
osip_message_t
*
sip
,
const
SalMediaDescription
*
desc
){
int
sdplen
;
char
clen
[
10
];
char
*
sdp
=
media_description_to_sdp
(
desc
);
if
(
sdp
==
NULL
)
{
ms_error
(
"Fail to print sdp message !"
);
return
;
}
sdplen
=
strlen
(
sdp
);
snprintf
(
clen
,
sizeof
(
clen
),
"%i"
,
sdplen
);
osip_message_set_body
(
sip
,
sdp
,
sdplen
);
osip_message_set_content_type
(
sip
,
"application/sdp"
);
osip_message_set_content_length
(
sip
,
clen
);
osip_free
(
sdp
);
}
int
sal_call_set_local_media_description
(
SalOp
*
h
,
const
SalMediaDescription
*
desc
){
set_sdp
(
h
->
request
,
desc
);
return
0
;
}
int
sal_call
(
SalOp
*
h
){
int
err
;
eXosip_lock
();
err
=
eXosip_call_send_initial_invite
(
h
->
request
);
eXosip_unlock
();
h
->
cid
=
err
;
if
(
err
<
0
){
ms_error
(
"Fail to send invite !"
);
return
-
1
;
}
return
0
;
}
int
sal_call_accept
(
SalOp
*
h
);
int
sal_call_get_final_media_description
(
SalOp
*
h
,
SalMediaDescription
*
result
);
int
sal_call_terminate
(
SalOp
*
h
);
int
sal_iterate
(
Sal
*
sal
);
SalOp
*
sal_register_create
(
Sal
*
ctx
,
const
char
*
from
,
const
char
*
contact
,
int
expires
);
int
sal_register
(
SalOp
*
h
);
linphone/coreapi/sal_eXosip2_sdp.c
0 → 100644
View file @
39ff61f8
/*
linphone
Copyright (C) 2010 Simon MORLAT (simon.morlat@free.fr)
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 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 "ortp/b64.h"
#include "sal.h"
#include <eXosip2/eXosip.h>
#define keywordcmp(key,b) strncmp(key,b,sizeof(key))
#ifdef FOR_LATER
static
char
*
make_relay_session_id
(
const
char
*
username
,
const
char
*
relay
){
/*ideally this should be a hash of the parameters with a random part*/
char
tmp
[
128
];
int
s1
=
(
int
)
random
();
int
s2
=
(
int
)
random
();
long
long
int
res
=
((
long
long
int
)
s1
)
<<
32
|
(
long
long
int
)
s2
;
void
*
src
=&
res
;
b64_encode
(
src
,
sizeof
(
long
long
int
),
tmp
,
sizeof
(
tmp
));
return
osip_strdup
(
tmp
);
}
static
void
add_relay_info
(
sdp_message_t
*
sdp
,
int
mline
,
const
char
*
relay
,
const
char
*
relay_session_id
){
if
(
relay
)
sdp_message_a_attribute_add
(
sdp
,
mline
,
osip_strdup
(
"relay-addr"
),
osip_strdup
(
relay
));
if
(
relay_session_id
)
sdp_message_a_attribute_add
(
sdp
,
mline
,
osip_strdup
(
"relay-session-id"
),
osip_strdup
(
relay_session_id
));
}
#endif
char
*
int_2char
(
int
a
){
char
*
p
=
osip_malloc
(
16
);
snprintf
(
p
,
16
,
"%i"
,
a
);
return
p
;
}
/* return the value of attr "field" for payload pt at line pos (field=rtpmap,fmtp...)*/
char
*
sdp_message_a_attr_value_get_with_pt
(
sdp_message_t
*
sdp
,
int
pos
,
int
pt
,
const
char
*
field
)
{
int
i
,
tmppt
=
0
,
scanned
=
0
;
char
*
tmp
;
sdp_attribute_t
*
attr
;
for
(
i
=
0
;(
attr
=
sdp_message_attribute_get
(
sdp
,
pos
,
i
))
!=
NULL
;
i
++
){
if
(
keywordcmp
(
field
,
attr
->
a_att_field
)
==
0
&&
attr
->
a_att_value
!=
NULL
){
int
nb
=
sscanf
(
attr
->
a_att_value
,
"%i %n"
,
&
tmppt
,
&
scanned
);
/* the return value may depend on how %n is interpreted by the libc: see manpage*/
if
(
nb
==
1
||
nb
==
2
){
if
(
pt
==
tmppt
){
tmp
=
attr
->
a_att_value
+
scanned
;
if
(
strlen
(
tmp
)
>
0
)
return
tmp
;
}
}
else
ms_warning
(
"sdp has a strange a= line (%s) nb=%i"
,
attr
->
a_att_value
,
nb
);
}
}
return
NULL
;
}
/* return the value of attr "field" */
char
*
sdp_message_a_attr_value_get
(
sdp_message_t
*
sdp
,
int
pos
,
const
char
*
field
)
{
int
i
;
sdp_attribute_t
*
attr
;
for
(
i
=
0
;(
attr
=
sdp_message_attribute_get
(
sdp
,
pos
,
i
))
!=
NULL
;
i
++
){
if
(
keywordcmp
(
field
,
attr
->
a_att_field
)
==
0
&&
attr
->
a_att_value
!=
NULL
){
return
attr
->
a_att_value
;
}
}
return
NULL
;
}
static
int
_sdp_message_get_a_ptime
(
sdp_message_t
*
sdp
,
int
mline
){
int
i
,
ret
;
sdp_attribute_t
*
attr
;
for
(
i
=
0
;(
attr
=
sdp_message_attribute_get
(
sdp
,
mline
,
i
))
!=
NULL
;
i
++
){
if
(
keywordcmp
(
"ptime"
,
attr
->
a_att_field
)
==
0
){
int
nb
=
sscanf
(
attr
->
a_att_value
,
"%i"
,
&
ret
);
/* the return value may depend on how %n is interpreted by the libc: see manpage*/
if
(
nb
==
1
){
return
ret
;
}
else
ms_warning
(
"sdp has a strange a=ptime line (%s) "
,
attr
->
a_att_value
);
}
}
return
0
;
}
static
sdp_message_t
*
create_generic_sdp
(
const
SalMediaDescription
*
desc
)
{
sdp_message_t
*
local
;
int
inet6
;
sdp_message_init
(
&
local
);
if
(
strchr
(
desc
->
addr
,
':'
)
!=
NULL
){
inet6
=
1
;
}
else
inet6
=
0
;
sdp_message_v_version_set
(
local
,
osip_strdup
(
"0"
));
sdp_message_o_origin_set
(
local
,
osip_strdup
(
desc
->
username
),
osip_strdup
(
"123456"
),
osip_strdup
(
"654321"
),
osip_strdup
(
"IN"
),
inet6
?
osip_strdup
(
"IP6"
)
:
osip_strdup
(
"IP4"
),
osip_strdup
(
desc
->
addr
));
sdp_message_s_name_set
(
local
,
osip_strdup
(
"A conversation"
));
sdp_message_c_connection_add
(
local
,
-
1
,
osip_strdup
(
"IN"
),
inet6
?
osip_strdup
(
"IP6"
)
:
osip_strdup
(
"IP4"
),
osip_strdup
(
desc
->
addr
),
NULL
,
NULL
);
sdp_message_t_time_descr_add
(
local
,
osip_strdup
(
"0"
),
osip_strdup
(
"0"
));
return
local
;
}
void
add_payload
(
sdp_message_t
*
msg
,
int
line
,
const
PayloadType
*
pt
)
{
char
attr
[
256
];
sdp_message_m_payload_add
(
msg
,
line
,
int_2char
(
payload_type_get_number
(
pt
)));
snprintf
(
attr
,
sizeof
(
attr
),
"%i %s"
,
payload_type_get_number
(
pt
),
pt
->
mime_type
);
sdp_message_a_attribute_add
(
msg
,
line
,
osip_strdup
(
"rtpmap"
),
osip_strdup
(
attr
));
if
(
pt
->
recv_fmtp
!=
NULL
)
{
snprintf
(
attr
,
sizeof
(
attr
),
"%i %s"
,
payload_type_get_number
(
pt
),
pt
->
recv_fmtp
);
sdp_message_a_attribute_add
(
msg
,
line
,
osip_strdup
(
"fmtp"
),
osip_strdup
(
attr
));
}
}
static
void
add_line
(
sdp_message_t
*
msg
,
int
lineno
,
const
SalStreamDescription
*
desc
){
const
char
*
mt
=
desc
->
type
==
SAL_AUDIO
?
"audio"
:
"video"
;
const
MSList
*
elem
;
sdp_message_m_media_add
(
msg
,
osip_strdup
(
mt
),
int_2char
(
desc
->
port
),
NULL
,
osip_strdup
(
"RTP/AVP"
));