Skip to content
GitLab
Menu
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
Menu
Open sidebar
savoirfairelinux
jami-daemon
Commits
312cd3db
Commit
312cd3db
authored
Apr 20, 2011
by
Alexandre Savard
Browse files
[#5571] Codec negotiation refactored and unittested
parent
3c77247f
Changes
5
Expand all
Hide whitespace changes
Inline
Side-by-side
sflphone-common/src/sip/sdp.cpp
View file @
312cd3db
This diff is collapsed.
Click to expand it.
sflphone-common/src/sip/sdp.h
View file @
312cd3db
/*
* Copyright (C) 2004, 2005, 2006, 2009, 2008, 2009, 2010, 2011 Savoir-Faire Linux Inc.
*
* Author: Emmanuel Milou <emmanuel.milou@savoirfairelinux.com>
* Author: Alexandre Savard <alexandre.savard@savoirfairelinux.com>
*
* 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
...
...
@@ -64,6 +64,7 @@ class SdpException : public std::exception
};
typedef
std
::
vector
<
std
::
string
>
CryptoOffer
;
typedef
std
::
vector
<
sdpMedia
*>
SdpMediaList
;
class
Sdp
{
...
...
@@ -85,31 +86,79 @@ class Sdp
*
* @return std::vector<sdpMedia*> the vector containing the different media
*/
std
::
vector
<
sdpMedia
*>
getLocalMediaCap
(
void
)
{
return
_
local
_m
edia
_c
ap
;
std
::
vector
<
sdpMedia
*>
getLocalMediaCap
(
void
)
{
return
local
AudioM
edia
C
ap
;
}
/*
* Read accessor. Get the sdp session information
*
* @return pjmedia_sdp_session The structure that describes a SDP session
*/
pjmedia_sdp_session
*
getLocalSdpSession
(
void
)
{
return
localSession
;
}
/**
* Accessor for the internal memory pool
*/
inline
pj_pool_t
*
getMemoryPool
(
void
)
{
return
_pool
;
return
memPool
;
}
/**
* Read accessor. Get the local passive sdp session information before negotiation
*
* @return The structure that describes a SDP session
*/
pjmedia_sdp_session
*
getLocalSdpSession
(
void
)
{
return
localSession
;
}
/**
* Read accessor. Get the remote passive sdp session information before negotiation
*
* @return The structure that describe the SDP session
*/
pjmedia_sdp_session
*
getRemoteSdpSession
(
void
)
{
return
remoteSession
;
}
/**
* Set the negociated sdp offer from the sip payload.
*
* @param sdp the negociated offer
*/
void
setActiveLocalSdpSession
(
const
pjmedia_sdp_session
*
sdp
);
/**
* read accessor. Return the negociated local session
*
* @return pjmedia_sdp_session The negociated offer
*/
pjmedia_sdp_session
*
getActiveLocalSdpSession
(
void
)
{
return
activeLocalSession
;
}
/**
* Retrieve the negociated sdp offer from the sip payload.
*
* @param sdp the negociated offer
*/
void
setActiveRemoteSdpSession
(
const
pjmedia_sdp_session
*
sdp
);
/**
* read accessor. Return the negociated offer
*
* @return pjmedia_sdp_session The negociated offer
*/
pjmedia_sdp_session
*
getActiveRemoteSdpSession
(
void
)
{
return
activeRemoteSession
;
}
/**
* Return the codec of the first media after negociation
*/
AudioCodec
*
getSessionMedia
(
void
);
/*
* On building an invite outside a dialog, build the local offer and create the
* SDP negociator instance with it.
*/
int
create
Initial
Offer
(
CodecOrder
selectedCodecs
);
int
createOffer
(
CodecOrder
selectedCodecs
);
/*
* On receiving an invite outside a dialog, build the local offer and create the
...
...
@@ -117,7 +166,7 @@ class Sdp
*
* @param remote The remote offer
*/
int
rec
eivingInitial
Offer
(
pjmedia_sdp_session
*
remote
,
CodecOrder
selectedCodecs
);
int
rec
ieve
Offer
(
const
pjmedia_sdp_session
*
remote
,
CodecOrder
selectedCodecs
);
/*
* On receiving a message, check if it contains SDP and negotiate. Should be used for
...
...
@@ -127,20 +176,25 @@ class Sdp
* @param inv The the invitation
* @param rdata The remote data
*/
int
receivingAnswerAfterInitialOffer
(
const
pjmedia_sdp_session
*
remote
);
int
receivingAnswerAfterInitialOffer
(
pjmedia_sdp_session
*
remote
);
int
generateAnswerFromInitialOffer
(
void
);
/**
* Generate answer after receiving Initial Offer
*/
int
generateAnswerAfterInitialOffer
(
void
);
/*
* Start the sdp negociation.
*
* @return pj_status_t 0 on success
* 1 otherwise
*/
/*
*
* Start the sdp negociation.
*
* @return pj_status_t 0 on success
* 1 otherwise
*/
pj_status_t
startNegociation
(
void
);
// pj_status_t check_sdp_answer (pjsip_inv_session *inv, pjsip_rx_data *rdata);
/**
* Update internal state after negotiation
*/
void
updateInternalState
(
void
);
/**
* Remove all media in the session media vector.
...
...
@@ -150,35 +204,13 @@ class Sdp
/**
* Remove all media in local media capability vector
*/
void
clean
_l
ocal
_m
edia
_c
apabilities
(
void
);
void
clean
L
ocal
M
edia
C
apabilities
(
void
);
/*
/*
*
* Return a string description of the media added to the session,
* ie the local media capabilities
*/
std
::
string
media_to_string
(
void
);
/*
* Return the codec of the first media after negociation
*/
AudioCodec
*
get_session_media
(
void
);
/*
* read accessor. Return the negociated offer
*
* @return pjmedia_sdp_session The negociated offer
*/
pjmedia_sdp_session
*
get_negociated_offer
(
void
)
{
return
_negociated_offer
;
}
/*
* Retrieve the negociated sdp offer from the sip payload.
*
* @param sdp the negociated offer
*/
void
set_negotiated_sdp
(
const
pjmedia_sdp_session
*
sdp
);
std
::
string
mediaToString
(
void
);
/*
* Attribute the specified port to every medias provided
...
...
@@ -187,7 +219,7 @@ class Sdp
*
* @param port The media port
*/
void
attribute_port_to_all_m
edia
(
int
port
);
void
setPortToAllM
edia
(
int
port
);
/*
...
...
@@ -208,14 +240,14 @@ class Sdp
* @param Set the published audio port
*/
void
setLocalPublishedAudioPort
(
int
port
)
{
local
Published
AudioPort
=
port
;
localAudioPort
=
port
;
}
/**
* @return The published audio port
*/
int
getLocalPublishedAudioPort
(
void
)
{
return
local
Published
AudioPort
;
return
localAudioPort
;
}
/**
...
...
@@ -250,31 +282,20 @@ class Sdp
return
remoteAudioPort
;
}
void
set_media_transport_info_from_remote_sdp
(
const
pjmedia_sdp_session
*
remote_sdp
);
std
::
vector
<
sdpMedia
*>
get_session_media_list
(
void
)
{
return
_session_media
;
std
::
vector
<
sdpMedia
*>
getSessionMediaList
(
void
)
{
return
sessionAudioMedia
;
}
void
get
_r
emote
_sdp_c
rypto
_f
rom
_o
ffer
(
const
pjmedia_sdp_session
*
remote_sdp
,
CryptoOffer
&
crypto_offer
);
void
get
R
emote
SdpC
rypto
F
rom
O
ffer
(
const
pjmedia_sdp_session
*
remote_sdp
,
CryptoOffer
&
crypto_offer
);
/*
* Build the sdp media section
* Add rtpmap field if necessary
*
* @param media The media to add to SDP
* @param med The structure to receive the media section
*/
void
set_media_descriptor_line
(
sdpMedia
*
media
,
pjmedia_sdp_media
**
p_med
);
/* Set the zrtp hash that was previously calculated from the hello message in the zrtp layer.
* This hash value is unique at the media level. Therefore, if video support is added, one would
* have to set the correct zrtp-hash value in the corresponding media section.
* @param hash The hello hash of a rtp session. (Only audio at the moment)
*/
inline
void
set_zrtp_hash
(
const
std
::
string
&
hash
)
{
_
zrtp
_h
ello
_h
ash
=
hash
;
zrtp
H
ello
H
ash
=
hash
;
_debug
(
"Zrtp hash set with %s
\n
"
,
hash
.
c_str
());
}
...
...
@@ -282,21 +303,21 @@ class Sdp
* @param mk The Master Key of a srtp session.
*/
inline
void
set_srtp_crypto
(
const
std
::
vector
<
std
::
string
>
lc
)
{
_
srtp
_c
rypto
=
lc
;
srtp
C
rypto
=
lc
;
}
void
toString
(
void
);
/** negociator */
pjmedia_sdp_neg
*
_negociator
;
private:
/**
* The pool to allocate memory, ownership to SipCall
* SDP should not release the pool itself
*/
pj_pool_t
*
_pool
;
pj_pool_t
*
memPool
;
/** negociator */
pjmedia_sdp_neg
*
negociator
;
/**
* Local SDP
...
...
@@ -308,39 +329,73 @@ class Sdp
*/
pjmedia_sdp_session
*
remoteSession
;
/* The negociated SDP offer */
// Explanation: each endpoint's offer is negociated, and a new sdp offer results from this
// negociation, with the compatible media from each part
pjmedia_sdp_session
*
_negociated_offer
;
/**
* The negociated SDP remote session
* Explanation: each endpoint's offer is negociated, and a new sdp offer results from this
* negociation, with the compatible media from each part
*/
pjmedia_sdp_session
*
activeLocalSession
;
/** Codec Map */
std
::
vector
<
sdpMedia
*>
_local_media_cap
;
/**
* The negociated SDP remote session
* Explanation: each endpoint's offer is negociated, and a new sdp offer results from this
* negociation, with the compatible media from each part
*/
pjmedia_sdp_session
*
activeRemoteSession
;
/* The media that will be used by the session (after the SDP negociation) */
std
::
vector
<
sdpMedia
*>
_session_media
;
/**
* Codec Map used for offer
*/
SdpMediaList
localAudioMediaCap
;
/** IP address */
std
::
string
localIpAddr
;
/**
* The media that will be used by the session (after the SDP negociation)
*/
SdpMediaList
sessionAudioMedia
;
/** Local audio port */
int
localPublishedAudioPort
;
/**
* IP address
*/
std
::
string
localIpAddr
;
/** Remote's IP address */
/**
* Remote's IP address
*/
std
::
string
remoteIpAddr
;
/** Remote audio port */
unsigned
int
remoteAudioPort
;
/**
* Local audio port
*/
int
localAudioPort
;
/**
* Remote audio port
*/
unsigned
int
remoteAudioPort
;
std
::
string
_zrtp_hello_hash
;
/**
* Zrtp hello hash
*/
std
::
string
zrtpHelloHash
;
/** "a=crypto" sdes local attributes obtained from AudioSrtpSession */
std
::
vector
<
std
::
string
>
_srtp_crypto
;
/**
* "a=crypto" sdes local attributes obtained from AudioSrtpSession
*/
std
::
vector
<
std
::
string
>
srtpCrypto
;
Sdp
(
const
Sdp
&
);
//No Copy Constructor
Sdp
&
operator
=
(
const
Sdp
&
);
//No Assignment Operator
/*
* Build the sdp media section
* Add rtpmap field if necessary
*
* @param media The media to add to SDP
* @param med The structure to receive the media section
*/
void
setMediaDescriptorLine
(
sdpMedia
*
media
,
pjmedia_sdp_media
**
p_med
);
/**
* Build the local media capabilities for this session
* @param List of codec in preference order
...
...
@@ -352,96 +407,89 @@ class Sdp
*/
int
createLocalSession
(
CodecOrder
selectedCodecs
);
/*
* Mandatory field: Protocol version ("v=")
* Add the protocol version in the SDP session description
*/
void
addProtocol
(
void
);
/*
* Mandatory field: Origin ("o=")
* Gives the originator of the session.
* Serves as a globally unique identifier for this version of this session description.
*/
void
sdp_
add
_o
rigin
(
void
);
void
add
O
rigin
(
void
);
/*
* Mandatory field:
Protocol version
("
v
=")
* Add
the protocol version in the SDP session description
* Mandatory field:
Session name
("
s
=")
* Add
a textual session name.
*/
void
sdp_add_protocol
(
void
);
void
addSessionName
(
void
);
/*
* Optional field: Connection data ("c=")
* Contains connection data.
*/
void
sdp_
add
_c
onnection
_i
nfo
(
void
);
void
add
C
onnection
I
nfo
(
void
);
/*
* Mandatory field:
Session name
("
s
=")
*
Add a textual
session
name
.
* Mandatory field:
Timing
("
t
=")
*
Specify the start and the stop time for a
session.
*/
void
sdp_add_session_name
(
void
);
void
addTiming
(
void
);
/*
* Optional field: Session information ("s=")
* Provides textual information about the session.
*/
void
sdp_
add
_s
ession
_i
nfo
(
void
)
{}
void
add
S
ession
I
nfo
(
void
)
{}
/*
* Optional field: Uri ("u=")
* Add a pointer to additional information about the session.
*/
void
sdp_
add
_u
ri
(
void
)
{}
void
add
U
ri
(
void
)
{}
/*
* Optional fields: Email address and phone number ("e=" and "p=")
* Add contact information for the person responsible for the conference.
*/
void
sdp_
add
_e
mail
(
void
)
{}
void
add
E
mail
(
void
)
{}
/*
* Optional field: Bandwidth ("b=")
* Denotes the proposed bandwidth to be used by the session or the media .
*/
void
sdp_
add
_b
andwidth
(
void
)
{}
void
add
B
andwidth
(
void
)
{}
/*
* Mandatory field: Timing ("t=")
* Specify the start and the stop time for a session.
*/
void
sdp_add_timing
(
void
);
/*
* Optional field: Time zones ("z=")
*/
void
sdp_
add
_t
ime
_z
one
(
void
)
{}
void
add
T
ime
Z
one
(
void
)
{}
/*
* Optional field: Encryption keys ("k=")
*/
void
sdp_
add
_e
ncryption
_k
ey
(
void
)
{}
void
add
E
ncryption
K
ey
(
void
)
{}
/*
* Optional field: Attributes ("a=")
*/
void
sdp_
add
_a
ttributes
();
void
add
A
ttributes
();
/*
* Mandatory field: Media descriptions ("m=")
*/
void
sdp_add_media_description
();
std
::
string
convert_int_to_string
(
int
value
);
void
set_remote_ip_from_sdp
(
const
pjmedia_sdp_session
*
r_sdp
);
void
set_remote_audio_port_from_sdp
(
pjmedia_sdp_media
*
r_media
);
void
get_remote_sdp_media_from_offer
(
const
pjmedia_sdp_session
*
r_sdp
,
pjmedia_sdp_media
**
r_media
);
void
addMediaDescription
();
/*
* Adds a sdes attribute to the given media section.
*
* @param media The media to add the srtp attribute to
*/
void
sdp_
add
_s
des
_a
ttribute
(
std
::
vector
<
std
::
string
>&
crypto
)
throw
(
SdpException
);
void
add
S
des
A
ttribute
(
std
::
vector
<
std
::
string
>&
crypto
)
throw
(
SdpException
);
/*
* Adds a zrtp-hash attribute to
...
...
@@ -452,7 +500,19 @@ class Sdp
* @param media The media to add the zrtp-hash attribute to
* @param hash The hash to which the attribute should be set to
*/
void
sdp_add_zrtp_attribute
(
pjmedia_sdp_media
*
media
,
std
::
string
hash
)
throw
(
SdpException
);
void
addZrtpAttribute
(
pjmedia_sdp_media
*
media
,
std
::
string
hash
)
throw
(
SdpException
);
std
::
string
convertIntToString
(
int
value
);
void
setRemoteIpFromSdp
(
const
pjmedia_sdp_session
*
r_sdp
);
void
setRemoteAudioPortFromSdp
(
pjmedia_sdp_media
*
r_media
);
void
setMediaTransportInfoFromRemoteSdp
(
const
pjmedia_sdp_session
*
remote_sdp
);
void
getRemoteSdpMediaFromOffer
(
const
pjmedia_sdp_session
*
remote_sdp
,
pjmedia_sdp_media
**
r_media
);
};
...
...
sflphone-common/src/sip/sipvoiplink.cpp
View file @
312cd3db
...
...
@@ -185,24 +185,28 @@ void setVoicemailInfo (AccountID account, pjsip_msg_body *body);
pj_bool_t
stun_sock_on_status_cb
(
pj_stun_sock
*
stun_sock
,
pj_stun_sock_op
op
,
pj_status_t
status
);
pj_bool_t
stun_sock_on_rx_data_cb
(
pj_stun_sock
*
stun_sock
,
void
*
pkt
,
unsigned
pkt_len
,
const
pj_sockaddr_t
*
src_addr
,
unsigned
addr_len
);
/*
* Session callback
* Called
when the invite session state has chang
ed.
* Called
after SDP offer/answer session has complet
ed.
*
* @param inv A pointer on a pjsip_inv_session structure
* @param
e A pointer on a pjsip_even
t structure
* @param
status A pj_status_
t structure
*/
void
invite_session_state_changed_cb
(
pjsip_inv_session
*
inv
,
pjsip_event
*
e
);
void
sdp_media_update_cb
(
pjsip_inv_session
*
inv
,
pj_status_t
status
UNUSED
);
void
sdp_request_offer_cb
(
pjsip_inv_session
*
inv
,
const
pjmedia_sdp_session
*
offer
);
void
sdp_create_offer_cb
(
pjsip_inv_session
*
inv
,
pjmedia_sdp_session
**
p_offer
);
/*
* Session callback
* Called
after SDP offer/answer session has complet
ed.
* Called
when the invite session state has chang
ed.
*
* @param inv A pointer on a pjsip_inv_session structure
* @param
status A pj_status_
t structure
* @param
e A pointer on a pjsip_even
t structure
*/
void
sdp_media_update
_cb
(
pjsip_inv_session
*
inv
,
pj
_status_t
status
UNUSED
);
void
invite_session_state_changed
_cb
(
pjsip_inv_session
*
inv
,
pj
sip_event
*
e
);
/*
* Called when the invite usage module has created a new dialog and invite
...
...
@@ -224,9 +228,6 @@ void outgoing_request_forked_cb (pjsip_inv_session *inv, pjsip_event *e);
*/
void
transaction_state_changed_cb
(
pjsip_inv_session
*
inv
,
pjsip_transaction
*
tsx
,
pjsip_event
*
e
);
void
invite_request_offer_cb
(
pjsip_inv_session
*
inv
,
const
pjmedia_sdp_session
*
offer
);
void
invite_create_offer_cb
(
pjsip_inv_session
*
inv
,
pjmedia_sdp_session
**
p_offer
);
/*
* Registration callback
...
...
@@ -706,7 +707,7 @@ Call *SIPVoIPLink::newOutgoingCall (const CallID& id, const std::string& toUrl)
// Building the local SDP offer
call
->
getLocalSDP
()
->
setLocalIP
(
addrSdp
);
status
=
call
->
getLocalSDP
()
->
create
Initial
Offer
(
account
->
getActiveCodecs
());
//
status = call->getLocalSDP()->createOffer (account->getActiveCodecs ());
if
(
status
!=
PJ_SUCCESS
)
{
delete
call
;
...
...
@@ -1042,7 +1043,7 @@ SIPVoIPLink::offhold (const CallID& id)
}
// Retreive previously selected codec
sfl
::
Codec
*
sessionMedia
=
call
->
getLocalSDP
()
->
get
_s
ession
_m
edia
();
sfl
::
Codec
*
sessionMedia
=
call
->
getLocalSDP
()
->
get
S
ession
M
edia
();
if
(
!
sessionMedia
)
return
false
;
...
...
@@ -1334,7 +1335,7 @@ SIPVoIPLink::getCurrentCodecName()
call
=
getSIPCall
(
Manager
::
instance
().
getCurrentCallId
());
if
(
call
)
ac
=
call
->
getLocalSDP
()
->
get
_s
ession
_m
edia
();
ac
=
call
->
getLocalSDP
()
->
get
S
ession
M
edia
();
if
(
ac
)
name
=
ac
->
getMimeSubtype
();
...
...
@@ -1759,7 +1760,7 @@ bool SIPVoIPLink::SIPNewIpToIpCall (const CallID& id, const std::string& to)
// Building the local SDP offer
call
->
getLocalSDP
()
->
setLocalIP
(
addrSdp
);
call
->
getLocalSDP
()
->
create
Initial
Offer
(
account
->
getActiveCodecs
());
//
call->getLocalSDP()->createOffer (account->getActiveCodecs ());
// Init TLS transport if enabled
if
(
account
->
isTlsEnabled
())
{
...
...
@@ -1979,8 +1980,8 @@ bool SIPVoIPLink::pjsipInit()
inv_cb
.
on_new_session
=
&
outgoing_request_forked_cb
;
inv_cb
.
on_media_update
=
&
sdp_media_update_cb
;
inv_cb
.
on_tsx_state_changed
=
&
transaction_state_changed_cb
;
inv_cb
.
on_rx_offer
=
&
invite
_request_offer_cb
;
inv_cb
.
on_create_offer
=
&
invite
_create_offer_cb
;
inv_cb
.
on_rx_offer
=
&
sdp
_request_offer_cb
;
inv_cb
.
on_create_offer
=
&
sdp
_create_offer_cb
;
// Initialize session invite module
status
=
pjsip_inv_usage_init
(
_endpt
,
&
inv_cb
);
...
...
@@ -3255,24 +3256,104 @@ void invite_session_state_changed_cb (pjsip_inv_session *inv, pjsip_event *e)
}
void
sdp_request_offer_cb
(
pjsip_inv_session
*
inv
,
const
pjmedia_sdp_session
*
offer
)
{
_info
(
"UserAgent: Received SDP offer"
);
#ifdef CAN_REINVITE
_debug
(
"UserAgent: %s (%d): on_rx_offer REINVITE"
,
__FILE__
,
__LINE__
);
SIPCall
*
call
;
pj_status_t
status
;
AccountID
accId
;
SIPVoIPLink
*
link
;
call
=
(
SIPCall
*
)
inv
->
mod_data
[
getModId
()
];
if
(
!
call
)
{
return
;
}
accId
=
Manager
::
instance
().
getAccountFromCall
(
call
->
getCallId
());
link
=
dynamic_cast
<
SIPVoIPLink
*>
(
Manager
::
instance
().
getAccountLink
(
accId
));
SIPAccount
*
account
=
dynamic_cast
<
SIPAccount
*>
(
Manager
::
instance
().
getAccount
(
accId
));