multicast impl

This commit is contained in:
Jehan Monnier 2015-01-30 22:34:24 +01:00
parent ef810b108b
commit 06fc0526ec
16 changed files with 740 additions and 34 deletions

View file

@ -210,10 +210,18 @@ static void stream_description_to_sdp ( belle_sdp_session_description_t *session
/*only add a c= line within the stream description if address are differents*/
if (rtp_addr[0]!='\0' && strcmp(rtp_addr,md->addr)!=0){
bool_t inet6;
belle_sdp_connection_t *connection;
if (strchr(rtp_addr,':')!=NULL){
inet6=TRUE;
}else inet6=FALSE;
belle_sdp_media_description_set_connection(media_desc,belle_sdp_connection_create("IN", inet6 ? "IP6" : "IP4", rtp_addr));
connection = belle_sdp_connection_create("IN", inet6 ? "IP6" : "IP4", rtp_addr);
if (ms_is_multicast(rtp_addr)) {
/*remove session cline in case of multicast*/
belle_sdp_session_description_set_connection(session_desc,NULL);
if (inet6 == FALSE)
belle_sdp_connection_set_ttl(connection,stream->ttl);
}
belle_sdp_media_description_set_connection(media_desc,connection);
}
if ( stream->bandwidth>0 )
@ -706,6 +714,7 @@ static SalStreamDescription * sdp_to_stream_description(SalMediaDescription *md,
}
if ( ( cnx=belle_sdp_media_description_get_connection ( media_desc ) ) && belle_sdp_connection_get_address ( cnx ) ) {
strncpy ( stream->rtp_addr,belle_sdp_connection_get_address ( cnx ), sizeof ( stream->rtp_addr ) -1 );
stream->ttl=belle_sdp_connection_get_ttl(cnx);
}
stream->rtp_port=belle_sdp_media_get_media_port ( media );

View file

@ -51,6 +51,7 @@ LinphoneCallParams * linphone_call_params_copy(const LinphoneCallParams *cp){
* The management of the custom headers is not optimal. We copy everything while ref counting would be more efficient.
*/
if (cp->custom_headers) ncp->custom_headers=sal_custom_header_clone(cp->custom_headers);
return ncp;
}
@ -158,6 +159,21 @@ bool_t linphone_call_params_video_enabled(const LinphoneCallParams *cp){
return cp->has_video;
}
LinphoneCallParamsMediaDirection linphone_call_params_get_audio_direction(const LinphoneCallParams *cp) {
return cp->audio_dir;
}
LinphoneCallParamsMediaDirection linphone_call_params_get_video_direction(const LinphoneCallParams *cp) {
return cp->video_dir;
}
void linphone_call_params_set_audio_direction(LinphoneCallParams *cp,LinphoneCallParamsMediaDirection dir) {
cp->audio_dir=dir;
}
void linphone_call_params_set_video_direction(LinphoneCallParams *cp,LinphoneCallParamsMediaDirection dir) {
cp->video_dir=dir;
}
/*******************************************************************************

View file

@ -30,6 +30,20 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
/*******************************************************************************
* Structures and enums *
******************************************************************************/
/**
* Indicates for a given media the stream direction
* */
enum _LinphoneCallParamsMediaDirection {
LinphoneCallParamsMediaDirectionInactive, /** No active media not supported yet*/
LinphoneCallParamsMediaDirectionSendOnly, /** Send only mode*/
LinphoneCallParamsMediaDirectionRecvOnly, /** recv only mode*/
LinphoneCallParamsMediaDirectionSendRecv, /*send receive mode not supported yet*/
};
/**
* Typedef for enum
**/
typedef enum _LinphoneCallParamsMediaDirection LinphoneCallParamsMediaDirection;
/**
* Private structure definition for LinphoneCallParams.
@ -247,6 +261,34 @@ LINPHONE_PUBLIC void linphone_call_params_set_session_name(LinphoneCallParams *c
**/
LINPHONE_PUBLIC bool_t linphone_call_params_video_enabled(const LinphoneCallParams *cp);
/**
* Get the audio stream direction.
* @param[in] cl LinphoneCallParams object
* @return The audio stream direction associated with the call params.
**/
LINPHONE_PUBLIC LinphoneCallParamsMediaDirection linphone_call_params_get_audio_direction(const LinphoneCallParams *cp);
/**
* Get the video stream direction.
* @param[in] cl LinphoneCallParams object
* @return The video stream direction associated with the call params.
**/
LINPHONE_PUBLIC LinphoneCallParamsMediaDirection linphone_call_params_get_video_direction(const LinphoneCallParams *cp);
/**
* Set the audio stream direction. Only relevant for multicast
* @param[in] cl LinphoneCallParams object
* @param[in] The audio stream direction associated with this call params.
**/
/*LINPHONE_PUBLIC void linphone_call_params_set_audio_direction(LinphoneCallParams *cp, LinphoneCallParamsMediaDirection dir);*/
/**
* Set the video stream direction. Only relevant for multicast
* @param[in] cl LinphoneCallParams object
* @param[in] The video stream direction associated with this call params.
**/
/*LINPHONE_PUBLIC void linphone_call_params_set_video_direction(LinphoneCallParams *cp, LinphoneCallParamsMediaDirection dir);*/
/*******************************************************************************
* Reference and user data handling functions *

View file

@ -546,7 +546,24 @@ void linphone_call_make_local_media_description(LinphoneCore *lc, LinphoneCall *
const char *me;
SalMediaDescription *md=sal_media_description_new();
LinphoneAddress *addr;
char* local_ip=call->localip;
const char* local_audio_ip;
const char* local_video_ip;
/*multicast is only set in case of outgoing call*/
if (call->dir == LinphoneCallOutgoing && linphone_core_audio_multicast_enabled(lc)) {
local_audio_ip=linphone_core_get_audio_multicast_addr(lc);
md->streams[0].ttl=linphone_core_get_audio_multicast_ttl(lc);
md->streams[0].multicast_role = SalMulticastRoleSender;
} else
local_audio_ip=call->localip;
if (call->dir == LinphoneCallOutgoing && linphone_core_video_multicast_enabled(lc)) {
local_video_ip=linphone_core_get_video_multicast_addr(lc);
md->streams[1].ttl=linphone_core_get_video_multicast_ttl(lc);
md->streams[1].multicast_role = SalMulticastRoleSender;
}else
local_video_ip=call->localip;
const char *subject=linphone_call_params_get_session_name(call->params);
CodecConstraints codec_hints={0};
@ -562,7 +579,7 @@ void linphone_call_make_local_media_description(LinphoneCore *lc, LinphoneCall *
md->session_ver=(old_md ? (old_md->session_ver+1) : (rand() & 0xfff));
md->nb_streams=(call->biggestdesc ? call->biggestdesc->nb_streams : 1);
strncpy(md->addr,local_ip,sizeof(md->addr));
strncpy(md->addr,call->localip,sizeof(md->addr));
strncpy(md->username,linphone_address_get_username(addr),sizeof(md->username));
if (subject) strncpy(md->name,subject,sizeof(md->name));
@ -571,8 +588,8 @@ void linphone_call_make_local_media_description(LinphoneCore *lc, LinphoneCall *
else md->bandwidth=linphone_core_get_download_bandwidth(lc);
/*set audio capabilities */
strncpy(md->streams[0].rtp_addr,local_ip,sizeof(md->streams[0].rtp_addr));
strncpy(md->streams[0].rtcp_addr,local_ip,sizeof(md->streams[0].rtcp_addr));
strncpy(md->streams[0].rtp_addr,local_audio_ip,sizeof(md->streams[0].rtp_addr));
strncpy(md->streams[0].rtcp_addr,local_audio_ip,sizeof(md->streams[0].rtcp_addr));
strncpy(md->streams[0].name,"Audio",sizeof(md->streams[0].name)-1);
md->streams[0].rtp_port=call->media_ports[0].rtp_port;
md->streams[0].rtcp_port=call->media_ports[0].rtcp_port;
@ -599,8 +616,8 @@ void linphone_call_make_local_media_description(LinphoneCore *lc, LinphoneCall *
nb_active_streams++;
if (call->params->has_video){
strncpy(md->streams[1].rtp_addr,local_ip,sizeof(md->streams[1].rtp_addr));
strncpy(md->streams[1].rtcp_addr,local_ip,sizeof(md->streams[1].rtcp_addr));
strncpy(md->streams[1].rtp_addr,local_video_ip,sizeof(md->streams[1].rtp_addr));
strncpy(md->streams[1].rtcp_addr,local_video_ip,sizeof(md->streams[1].rtcp_addr));
strncpy(md->streams[1].name,"Video",sizeof(md->streams[1].name)-1);
md->streams[1].rtp_port=call->media_ports[1].rtp_port;
md->streams[1].rtcp_port=call->media_ports[1].rtcp_port;
@ -764,6 +781,9 @@ static void linphone_call_init_common(LinphoneCall *call, LinphoneAddress *from,
linphone_call_init_stats(&call->stats[LINPHONE_CALL_STATS_AUDIO], LINPHONE_CALL_STATS_AUDIO);
linphone_call_init_stats(&call->stats[LINPHONE_CALL_STATS_VIDEO], LINPHONE_CALL_STATS_VIDEO);
/*by default local_audio_ip=local_video_ip=local_ip*/
strncpy(call->local_audio_ip,call->localip,sizeof(call->local_audio_ip));
strncpy(call->local_video_ip,call->localip,sizeof(call->local_video_ip));
}
void linphone_call_init_stats(LinphoneCallStats *stats, int type) {
@ -935,6 +955,20 @@ void linphone_call_set_compatible_incoming_call_parameters(LinphoneCall *call, c
if ((sal_media_description_has_srtp(md) == TRUE) && (ms_srtp_supported() == TRUE)) {
call->params->media_encryption = LinphoneMediaEncryptionSRTP;
}
//set both local audio & video
if (ms_is_multicast(md->streams[0].rtp_addr)) {
strncpy(call->local_audio_ip,md->streams[0].rtp_addr,sizeof(call->local_audio_ip));
ms_message("Disabling audio rtcp on call [%p] because of multicast",call);
call->media_ports[0].rtp_port=md->streams[0].rtp_port;
call->media_ports[0].rtcp_port=0;
}
if (ms_is_multicast(md->streams[1].rtp_addr)) {
strncpy(call->local_video_ip,md->streams[1].rtp_addr,sizeof(call->local_video_ip));
call->media_ports[1].rtp_port=md->streams[1].rtp_port;
call->media_ports[1].rtcp_port=0;
ms_message("Disabling video rtcp on call [%p] because of multicast",call);
}
}
LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *from, LinphoneAddress *to, SalOp *op){
@ -1767,11 +1801,12 @@ void linphone_call_init_audio_stream(LinphoneCall *call){
int dscp;
char rtcp_tool[128]={0};
char* cname;
snprintf(rtcp_tool,sizeof(rtcp_tool)-1,"%s-%s",linphone_core_get_user_agent_name(),linphone_core_get_user_agent_version());
if (call->audiostream != NULL) return;
if (call->sessions[0].rtp_session==NULL){
call->audiostream=audiostream=audio_stream_new(call->media_ports[0].rtp_port,call->media_ports[0].rtcp_port,call->af==AF_INET6);
call->audiostream=audiostream=audio_stream_new2(call->local_audio_ip,call->media_ports[0].rtp_port,call->media_ports[0].rtcp_port);
cname = linphone_address_as_string_uri_only(call->me);
audio_stream_set_rtcp_information(call->audiostream, cname, rtcp_tool);
ms_free(cname);
@ -1876,7 +1911,7 @@ void linphone_call_init_video_stream(LinphoneCall *call){
const char *display_filter=linphone_core_get_video_display_filter(lc);
if (call->sessions[1].rtp_session==NULL){
call->videostream=video_stream_new(call->media_ports[1].rtp_port,call->media_ports[1].rtcp_port, call->af==AF_INET6);
call->videostream=video_stream_new2(call->local_video_ip,call->media_ports[1].rtp_port,call->media_ports[1].rtcp_port);
cname = linphone_address_as_string_uri_only(call->me);
video_stream_set_rtcp_information(call->videostream, cname, rtcp_tool);
ms_free(cname);
@ -2259,7 +2294,9 @@ static void linphone_call_start_audio_stream(LinphoneCall *call, bool_t muted, b
}
/*Replace soundcard filters by inactive file players or recorders
when placed in recvonly or sendonly mode*/
if (stream->rtp_port==0 || stream->dir==SalStreamRecvOnly){
if (stream->rtp_port==0
|| stream->dir==SalStreamRecvOnly
|| (stream->multicast_role == SalMulticastRoleReceiver && ms_is_multicast(stream->rtp_addr))){
captcard=NULL;
playfile=NULL;
}else if (stream->dir==SalStreamSendOnly){
@ -2315,13 +2352,16 @@ static void linphone_call_start_audio_stream(LinphoneCall *call, bool_t muted, b
}
}
configure_rtp_session_for_rtcp_xr(lc, call, SalAudio);
if (ms_is_multicast(stream->rtp_addr))
rtp_session_set_multicast_ttl(call->audiostream->ms.sessions.rtp_session,stream->ttl);
audio_stream_start_full(
call->audiostream,
call->audio_profile,
stream->rtp_addr[0]!='\0' ? stream->rtp_addr : call->resultdesc->addr,
stream->rtp_port,
stream->rtcp_addr[0]!='\0' ? stream->rtcp_addr : call->resultdesc->addr,
linphone_core_rtcp_enabled(lc) ? (stream->rtcp_port ? stream->rtcp_port : stream->rtp_port+1) : 0,
(linphone_core_rtcp_enabled(lc) && !ms_is_multicast(stream->rtp_addr)) ? (stream->rtcp_port ? stream->rtcp_port : stream->rtp_port+1) : 0,
used_pt,
linphone_core_get_audio_jittcomp(lc),
playfile,
@ -2402,7 +2442,12 @@ static void linphone_call_start_video_stream(LinphoneCall *call, bool_t all_inpu
video_stream_set_native_preview_window_id (call->videostream,lc->preview_window_id);
video_stream_use_preview_video_window (call->videostream,lc->use_preview_window);
if (vstream->dir==SalStreamSendOnly && lc->video_conf.capture ){
if (ms_is_multicast(vstream->rtp_addr)){
if (vstream->multicast_role == SalMulticastRoleReceiver)
dir=VideoStreamRecvOnly;
else
dir=VideoStreamSendOnly;
} else if (vstream->dir==SalStreamSendOnly && lc->video_conf.capture ){
if (local_st_desc->dir==SalStreamSendOnly){
/* localdesc stream dir to SendOnly is when we want to put on hold, so use nowebcam in this case*/
cam=get_nowebcam_device();
@ -2440,6 +2485,9 @@ static void linphone_call_start_video_stream(LinphoneCall *call, bool_t all_inpu
ms_message("%s lc rotation:%d\n", __FUNCTION__, lc->device_rotation);
video_stream_set_device_rotation(call->videostream, lc->device_rotation);
video_stream_set_freeze_on_error(call->videostream, lp_config_get_int(lc->config, "video", "freeze_on_error", 0));
if (ms_is_multicast(vstream->rtp_addr))
rtp_session_set_multicast_ttl(call->videostream->ms.sessions.rtp_session,vstream->ttl);
if( lc->video_conf.reuse_preview_source && source ){
ms_message("video_stream_start_with_source kept: %p", source);
video_stream_start_with_source(call->videostream,
@ -2452,7 +2500,7 @@ static void linphone_call_start_video_stream(LinphoneCall *call, bool_t all_inpu
video_stream_start(call->videostream,
call->video_profile, rtp_addr, vstream->rtp_port,
rtcp_addr,
linphone_core_rtcp_enabled(lc) ? (vstream->rtcp_port ? vstream->rtcp_port : vstream->rtp_port+1) : 0,
(linphone_core_rtcp_enabled(lc) && !ms_is_multicast(vstream->rtp_addr)) ? (vstream->rtcp_port ? vstream->rtcp_port : vstream->rtp_port+1) : 0,
used_pt, linphone_core_get_video_jittcomp(lc), cam);
}
}

View file

@ -947,6 +947,8 @@ static void rtp_config_read(LinphoneCore *lc)
int nortp_timeout;
bool_t rtp_no_xmit_on_audio_mute;
bool_t adaptive_jitt_comp_enabled;
const char* tmp;
int tmp_int;
if (lp_config_get_range(lc->config, "rtp", "audio_rtp_port", &min_port, &max_port, 7078, 7078) == TRUE) {
if (min_port <= 0) min_port = 1;
@ -981,6 +983,26 @@ static void rtp_config_read(LinphoneCore *lc)
linphone_core_enable_video_adaptive_jittcomp(lc, adaptive_jitt_comp_enabled);
lc->rtp_conf.disable_upnp = lp_config_get_int(lc->config, "rtp", "disable_upnp", FALSE);
linphone_core_set_avpf_mode(lc,lp_config_get_int(lc->config,"rtp","avpf",0));
if ((tmp=lp_config_get_string(lc->config,"rtp","audio_multicast_addr",NULL)))
linphone_core_set_audio_multicast_addr(lc,tmp);
else
lc->rtp_conf.audio_multicast_addr=ms_strdup("224.1.2.3");
if ((tmp_int=lp_config_get_int(lc->config,"rtp","audio_multicast_enabled",-1)) >-1)
linphone_core_enable_audio_multicast(lc,tmp_int);
if ((tmp_int=lp_config_get_int(lc->config,"rtp","audio_multicast_ttl",-1))>0)
linphone_core_set_audio_multicast_ttl(lc,tmp_int);
else
lc->rtp_conf.audio_multicast_ttl=1;/*local network*/
if ((tmp=lp_config_get_string(lc->config,"rtp","video_multicast_addr",NULL)))
linphone_core_set_video_multicast_addr(lc,tmp);
else
lc->rtp_conf.video_multicast_addr=ms_strdup("224.1.2.3");
if ((tmp_int=lp_config_get_int(lc->config,"rtp","video_multicast_ttl",-1))>-1)
linphone_core_set_video_multicast_ttl(lc,tmp_int);
else
lc->rtp_conf.video_multicast_ttl=1;/*local network*/
if ((tmp_int=lp_config_get_int(lc->config,"rtp","video_multicast_enabled",-1)) >0)
linphone_core_enable_video_multicast(lc,tmp_int);
}
static PayloadType * find_payload(const MSList *default_list, const char *mime_type, int clock_rate, int channels, const char *recv_fmtp){
@ -6123,6 +6145,8 @@ void rtp_config_uninit(LinphoneCore *lc)
lp_config_set_int(lc->config,"rtp","nortp_timeout",config->nortp_timeout);
lp_config_set_int(lc->config,"rtp","audio_adaptive_jitt_comp_enabled",config->audio_adaptive_jitt_comp_enabled);
lp_config_set_int(lc->config,"rtp","video_adaptive_jitt_comp_enabled",config->video_adaptive_jitt_comp_enabled);
ms_free(lc->rtp_conf.audio_multicast_addr);
ms_free(lc->rtp_conf.video_multicast_addr);
ms_free(config->srtp_suites);
}
@ -6878,6 +6902,8 @@ void linphone_core_init_default_params(LinphoneCore*lc, LinphoneCallParams *para
params->in_conference=FALSE;
params->privacy=LinphonePrivacyDefault;
params->avpf_enabled=FALSE;
params->audio_dir=LinphoneCallParamsMediaDirectionSendRecv;
params->video_dir=LinphoneCallParamsMediaDirectionSendRecv;
}
void linphone_core_set_device_identifier(LinphoneCore *lc,const char* device_id) {
@ -7216,3 +7242,81 @@ void linphone_core_remove_listener(LinphoneCore *lc, const LinphoneCoreVTable *v
ms_message("Vtable [%p] unregistered on core [%p]",lc,vtable);
lc->vtables=ms_list_remove(lc->vtables,(void*)vtable);
}
int linphone_core_set_audio_multicast_addr(LinphoneCore *lc, const char* ip) {
char* new_value;
if (ip && !ms_is_multicast(ip)) {
ms_error("Cannot set multicast audio addr to core [%p] because [%s] is not multicast",lc,ip);
return -1;
}
new_value = ip?ms_strdup(ip):NULL;
if (lc->rtp_conf.audio_multicast_addr) ms_free(lc->rtp_conf.audio_multicast_addr);
lp_config_set_string(lc->config,"rtp","audio_multicast_addr",lc->rtp_conf.audio_multicast_addr=new_value);
return 0;
}
int linphone_core_set_video_multicast_addr(LinphoneCore *lc, const char* ip) {
char* new_value;
if (ip && !ms_is_multicast(ip)) {
ms_error("Cannot set multicast video addr to core [%p] because [%s] is not multicast",lc,ip);
return -1;
}
new_value = ip?ms_strdup(ip):NULL;
if (lc->rtp_conf.video_multicast_addr) ms_free(lc->rtp_conf.video_multicast_addr);
lp_config_set_string(lc->config,"rtp","video_multicast_addr",lc->rtp_conf.video_multicast_addr=new_value);
return 0;
}
const char* linphone_core_get_audio_multicast_addr(const LinphoneCore *lc) {
return lc->rtp_conf.audio_multicast_addr;
}
const char* linphone_core_get_video_multicast_addr(const LinphoneCore *lc){
return lc->rtp_conf.video_multicast_addr;
}
int linphone_core_set_audio_multicast_ttl(LinphoneCore *lc, int ttl) {
if (ttl>255) {
ms_error("Cannot set multicast audio ttl to core [%p] to [%i] value must be <256",lc,ttl);
return -1;
}
lp_config_set_int(lc->config,"rtp","audio_multicast_ttl",lc->rtp_conf.audio_multicast_ttl=ttl);
return 0;
}
int linphone_core_set_video_multicast_ttl(LinphoneCore *lc, int ttl) {
if (ttl>255) {
ms_error("Cannot set multicast video ttl to core [%p] to [%i] value must be <256",lc,ttl);
return -1;
}
lp_config_set_int(lc->config,"rtp","video_multicast_ttl",lc->rtp_conf.video_multicast_ttl=ttl);
return 0;
}
int linphone_core_get_audio_multicast_ttl(const LinphoneCore *lc) {
return lc->rtp_conf.audio_multicast_ttl;
}
int linphone_core_get_video_multicast_ttl(const LinphoneCore *lc){
return lc->rtp_conf.video_multicast_ttl;
}
void linphone_core_enable_audio_multicast(LinphoneCore *lc, bool_t yesno) {
lp_config_set_int(lc->config,"rtp","audio_multicast_enabled",lc->rtp_conf.audio_multicast_enabled=yesno);
}
bool_t linphone_core_audio_multicast_enabled(const LinphoneCore *lc) {
return lc->rtp_conf.audio_multicast_enabled;
}
void linphone_core_enable_video_multicast(LinphoneCore *lc, bool_t yesno) {
lp_config_set_int(lc->config,"rtp","video_multicast_enabled",lc->rtp_conf.video_multicast_enabled=yesno);
}
bool_t linphone_core_video_multicast_enabled(const LinphoneCore *lc) {
return lc->rtp_conf.video_multicast_enabled;
}

View file

@ -3305,6 +3305,105 @@ LINPHONE_PUBLIC void linphone_core_set_avpf_rr_interval(LinphoneCore *lc, int in
LINPHONE_PUBLIC int linphone_core_get_avpf_rr_interval(const LinphoneCore *lc);
/**
* Use to set multicast address to be used for audio stream.
* @param core the core
* @param ip an ipv4/6 multicast address
* @return 0 in case of success
* @ingroup media_parameters
**/
LINPHONE_PUBLIC int linphone_core_set_audio_multicast_addr(LinphoneCore *core, const char* ip);
/**
* Use to set multicast address to be used for video stream.
* @param core the core
* @param ip an ipv4/6 multicast address
* @return 0 in case of success
* @ingroup media_parameters
**/
LINPHONE_PUBLIC int linphone_core_set_video_multicast_addr(LinphoneCore *lc, const char *ip);
/**
* Use to get multicast address to be used for audio stream.
* @param core the core
* @return an ipv4/6 multicast address or default value
* @ingroup media_parameters
**/
LINPHONE_PUBLIC const char* linphone_core_get_audio_multicast_addr(const LinphoneCore *core);
/**
* Use to get multicast address to be used for video stream.
* @param core the core
* @return an ipv4/6 multicast address, or default value
* @ingroup media_parameters
**/
LINPHONE_PUBLIC const char* linphone_core_get_video_multicast_addr(const LinphoneCore *core);
/**
* Use to set multicast ttl to be used for audio stream.
* @param core the core
* @param ip an ttl or -1 if not used [0..255] default value is 1
* @return 0 in case of success
* @ingroup media_parameters
**/
LINPHONE_PUBLIC int linphone_core_set_audio_multicast_ttl(LinphoneCore *core, int ttl);
/**
* Use to set multicast ttl to be used for video stream.
* @param core the core
* @param ip an ttl or -1 if not used [0..255] default value is 1
* @return 0 in case of success
* @ingroup media_parameters
**/
LINPHONE_PUBLIC int linphone_core_set_video_multicast_ttl(LinphoneCore *lc, int ttl);
/**
* Use to get multicast ttl to be used for audio stream.
* @param core the core
* @return an time to leave value or -1 if not set
* @ingroup media_parameters
**/
LINPHONE_PUBLIC int linphone_core_get_audio_multicast_ttl(const LinphoneCore *core);
/**
* Use to get multicast ttl to be used for video stream.
* @param core the core
* @return an an time to leave value or -1 if not set
* @ingroup media_parameters
**/
LINPHONE_PUBLIC int linphone_core_get_video_multicast_ttl(const LinphoneCore *core);
/**
* Use to enable multicast rtp for audio stream.
* @param core the core
* @param yesno if yes, subsequent calls propose multicast ip set by #linphone_core_set_audio_multicast_addr
* @return an ipv4/6 multicast address or null
* @ingroup media_parameters
**/
LINPHONE_PUBLIC void linphone_core_enable_audio_multicast(LinphoneCore *core, bool_t yesno);
/**
* Use to get multicast state of audio stream.
* @param core the core
* @return true if subsequent calls propose multicast ip set by #linphone_core_set_audio_multicast_addr
* @ingroup media_parameters
**/
LINPHONE_PUBLIC bool_t linphone_core_audio_multicast_enabled(const LinphoneCore *core);
/**
* Use to enable multicast rtp for video stream.
* @param core the core
* @param yesno if yes, subsequent calls propose multicast ip set by #linphone_core_set_video_multicast_addr
* @ingroup media_parameters
**/
LINPHONE_PUBLIC void linphone_core_enable_video_multicast(LinphoneCore *core, bool_t yesno);
/**
* Use to get multicast state of video stream.
* @param core the core
* @return true if subsequent calls propose multicast ip set by #linphone_core_set_audio_multicast_addr
* @ingroup media_parameters
**/
LINPHONE_PUBLIC bool_t linphone_core_video_multicast_enabled(const LinphoneCore *core);
#ifdef __cplusplus
}
#endif

View file

@ -296,9 +296,81 @@ static void initiate_outgoing(const SalStreamDescription *local_offer,
SalStreamDescription *result){
if (remote_answer->rtp_port!=0)
result->payloads=match_payloads(local_offer->payloads,remote_answer->payloads,TRUE,FALSE);
else {
ms_message("Local stream description [%p] rejected by peer",local_offer);
result->rtp_port=0;
return;
}
result->proto=remote_answer->proto;
result->type=local_offer->type;
result->dir=compute_dir_outgoing(local_offer->dir,remote_answer->dir);
if (ms_is_multicast(local_offer->rtp_addr)) {
/*6.2 Multicast Streams
...
If a multicast stream is accepted, the address and port information
in the answer MUST match that of the offer. Similarly, the
directionality information in the answer (sendonly, recvonly, or
sendrecv) MUST equal that of the offer. This is because all
participants in a multicast session need to have equivalent views of
the parameters of the session, an underlying assumption of the
multicast bias of RFC 2327.*/
if (strcmp(local_offer->rtp_addr,remote_answer->rtp_addr) !=0 ) {
ms_message("Remote answered IP [%s] does not match offered [%s] for local stream description [%p]"
,remote_answer->rtp_addr
,local_offer->rtp_addr
,local_offer);
result->rtp_port=0;
return;
}
if (local_offer->rtp_port!=remote_answer->rtp_port) {
ms_message("Remote answered rtp port [%i] does not match offered [%i] for local stream description [%p]"
,remote_answer->rtp_port
,local_offer->rtp_port
,local_offer);
result->rtp_port=0;
return;
}
if (local_offer->dir!=remote_answer->dir) {
ms_message("Remote answered dir [%s] does not match offered [%s] for local stream description [%p]"
,sal_stream_dir_to_string(remote_answer->dir)
,sal_stream_dir_to_string(local_offer->dir)
,local_offer);
result->rtp_port=0;
return;
}
if (local_offer->bandwidth!=remote_answer->bandwidth) {
ms_message("Remote answered bandwidth [%i] does not match offered [%i] for local stream description [%p]"
,remote_answer->bandwidth
,local_offer->bandwidth
,local_offer);
result->rtp_port=0;
return;
}
if (local_offer->ptime > 0 && local_offer->ptime!=remote_answer->ptime) {
ms_message("Remote answered ptime [%i] does not match offered [%i] for local stream description [%p]"
,remote_answer->ptime
,local_offer->ptime
,local_offer);
result->rtp_port=0;
return;
}
if (local_offer->ttl > 0 && local_offer->ttl!=remote_answer->ttl) {
ms_message("Remote answered ttl [%i] does not match offered [%i] for local stream description [%p]"
,remote_answer->ttl
,local_offer->ttl
,local_offer);
result->rtp_port=0;
return;
}
result->ttl=local_offer->ttl;
result->dir=local_offer->dir;
result->multicast_role = SalMulticastRoleSender;
} else {
result->dir=compute_dir_outgoing(local_offer->dir,remote_answer->dir);
}
if (result->payloads && !only_telephone_event(result->payloads)){
strcpy(result->rtp_addr,remote_answer->rtp_addr);
@ -328,16 +400,34 @@ static void initiate_incoming(const SalStreamDescription *local_cap,
result->payloads=match_payloads(local_cap->payloads,remote_offer->payloads, FALSE, one_matching_codec);
result->proto=remote_offer->proto;
result->type=local_cap->type;
result->dir=compute_dir_incoming(local_cap->dir,remote_offer->dir);
if (result->payloads && !only_telephone_event(result->payloads) && (remote_offer->rtp_port!=0 || remote_offer->rtp_port==SalStreamSendOnly)){
if (!result->payloads || only_telephone_event(result->payloads) || remote_offer->rtp_port==0 || remote_offer->rtp_port==SalStreamSendOnly){
result->dir=compute_dir_incoming(local_cap->dir,remote_offer->dir);
result->rtp_port=0;
return;
}
if (ms_is_multicast(remote_offer->rtp_addr)) {
if (sal_stream_description_has_srtp(result) == TRUE) {
ms_message("SAVP not supported for multicast address for remote stream [%p]",remote_offer);
result->rtp_port=0;
return;
}
result->dir=remote_offer->dir;
strcpy(result->rtp_addr,remote_offer->rtp_addr);
strcpy(result->rtcp_addr,remote_offer->rtcp_addr);
result->rtp_port=remote_offer->rtp_port;
/*result->rtcp_port=remote_offer->rtcp_port;*/
result->rtcp_port=0; /* rtcp not supported yet*/
result->bandwidth=remote_offer->bandwidth;
result->ptime=remote_offer->ptime;
result->ttl=remote_offer->ttl;
result->multicast_role = SalMulticastRoleReceiver;
} else {
strcpy(result->rtp_addr,local_cap->rtp_addr);
strcpy(result->rtcp_addr,local_cap->rtcp_addr);
result->rtp_port=local_cap->rtp_port;
result->rtcp_port=local_cap->rtcp_port;
result->bandwidth=local_cap->bandwidth;
result->ptime=local_cap->ptime;
}else{
result->rtp_port=0;
}
if (sal_stream_description_has_srtp(result) == TRUE) {
/* select crypto algo */
@ -358,6 +448,7 @@ static void initiate_incoming(const SalStreamDescription *local_cap,
}
/**
* Returns a media description to run the streams with, based on a local offer
* and the returned response (remote).

View file

@ -1796,6 +1796,8 @@ void linphone_notify_convert_presence_to_xml(SalOp *op, SalPresenceModel *presen
return;
}
xmlTextWriterSetIndent(writer,1);
err = xmlTextWriterStartDocument(writer, "1.0", "UTF-8", NULL);
if (err >= 0) {
err = xmlTextWriterStartElementNS(writer, NULL, (const xmlChar *)"presence", (const xmlChar *)"urn:ietf:params:xml:ns:pidf");

View file

@ -79,6 +79,7 @@ extern "C" {
#endif
#endif
struct _LinphoneCallParams{
belle_sip_object_t base;
void *user_data;
@ -105,6 +106,9 @@ struct _LinphoneCallParams{
bool_t no_user_consent;/*when set to TRUE an UPDATE request will be used instead of reINVITE*/
uint16_t avpf_rr_interval; /*in milliseconds*/
LinphonePrivacyMask privacy;
LinphoneCallParamsMediaDirection audio_dir;
LinphoneCallParamsMediaDirection video_dir;
};
BELLE_SIP_DECLARE_VPTR(LinphoneCallParams);
@ -217,6 +221,8 @@ struct _LinphoneCall{
SalOp *op;
SalOp *ping_op;
char localip[LINPHONE_IPADDR_SIZE]; /* our best guess for local ipaddress for this call */
char local_audio_ip[LINPHONE_IPADDR_SIZE]; /* our best guess for local ipaddress for this call or what proposed in sdp in case of multicast*/
char local_video_ip[LINPHONE_IPADDR_SIZE]; /* our best guess for local ipaddress for this call or what proposed in sdp in case of multicast*/
LinphoneCallState state;
LinphoneCallState prevstate;
LinphoneCallState transfer_state; /*idle if no transfer*/
@ -589,6 +595,12 @@ typedef struct rtp_config
bool_t audio_adaptive_jitt_comp_enabled;
bool_t video_adaptive_jitt_comp_enabled;
bool_t pad;
char* audio_multicast_addr;
bool_t audio_multicast_enabled;
int audio_multicast_ttl;
char* video_multicast_addr;
int video_multicast_ttl;
bool_t video_multicast_enabled;
}rtp_config_t;

View file

@ -196,6 +196,14 @@ typedef enum {
SalDtlsRoleUnset
} SalDtlsRole;
typedef enum {
SalMulticastInative=0,
SalMulticastRoleSender,
SalMulticastRoleReceiver,
SalMulticastSenderReceiver
} SalMulticastRole;
typedef struct SalStreamDescription{
char name[16]; /*unique name of stream, in order to ease offer/answer model algorithm*/
SalMediaProto proto;
@ -226,6 +234,8 @@ typedef struct SalStreamDescription{
bool_t pad[2];
char dtls_fingerprint[256];
SalDtlsRole dtls_role;
int ttl; /*for multicast -1 to disable*/
SalMulticastRole multicast_role;
} SalStreamDescription;
const char *sal_stream_description_get_type_as_string(const SalStreamDescription *desc);

View file

@ -15,6 +15,7 @@ liblinphonetester_la_SOURCES = tester.c \
register_tester.c \
message_tester.c \
call_tester.c \
multicast_call_tester.c \
presence_tester.c \
upnp_tester.c \
eventapi_tester.c \

View file

@ -127,8 +127,8 @@ void linphone_transfer_state_changed(LinphoneCore *lc, LinphoneCall *transfered,
}
}
#ifdef VIDEO_ENABLED
static void linphone_call_cb(LinphoneCall *call,void * user_data) {
void linphone_call_cb(LinphoneCall *call,void * user_data) {
char* to=linphone_address_as_string(linphone_call_get_call_log(call)->to);
char* from=linphone_address_as_string(linphone_call_get_call_log(call)->from);
stats* counters;
@ -139,7 +139,6 @@ static void linphone_call_cb(LinphoneCall *call,void * user_data) {
counters = (stats*)get_stats(lc);
counters->number_of_IframeDecoded++;
}
#endif
void liblinphone_tester_check_rtcp(LinphoneCoreManager* caller, LinphoneCoreManager* callee) {
LinphoneCall *c1,*c2;
@ -314,7 +313,7 @@ void end_call(LinphoneCoreManager *m1, LinphoneCoreManager *m2){
CU_ASSERT_TRUE(wait_for(m1->lc,m2->lc,&m2->stat.number_of_LinphoneCallReleased,1));
}
static void simple_call(void) {
void simple_call_base(bool_t enable_multicast_recv_side) {
int begin;
int leaked_objects;
LinphoneCoreManager* marie;
@ -347,6 +346,8 @@ static void simple_call(void) {
linphone_address_unref(marie_addr);
}
linphone_core_enable_audio_multicast(pauline->lc,enable_multicast_recv_side);
CU_ASSERT_TRUE(call(marie,pauline));
pauline_call=linphone_core_get_current_call(pauline->lc);
CU_ASSERT_PTR_NOT_NULL(pauline_call);
@ -375,7 +376,9 @@ static void simple_call(void) {
belle_sip_object_dump_active_objects();
}
}
static void simple_call() {
simple_call_base(FALSE);
}
static void call_with_timeouted_bye(void) {
int begin;
int leaked_objects;
@ -1131,12 +1134,14 @@ static void call_with_custom_headers(void) {
linphone_core_manager_destroy(pauline);
}
static void call_paused_resumed(void) {
void call_paused_resumed_base(bool_t multicast) {
LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc");
LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc");
LinphoneCall* call_pauline;
const rtp_stats_t * stats;
linphone_core_enable_audio_multicast(pauline->lc,multicast);
CU_ASSERT_TRUE(call(pauline,marie));
call_pauline = linphone_core_get_current_call(pauline->lc);
@ -1170,7 +1175,9 @@ static void call_paused_resumed(void) {
linphone_core_manager_destroy(marie);
linphone_core_manager_destroy(pauline);
}
static void call_paused_resumed(void) {
call_paused_resumed_base(FALSE);
}
#define CHECK_CURRENT_LOSS_RATE() \
rtcp_count_current = pauline->stat.number_of_rtcp_sent; \
/*wait for an RTCP packet to have an accurate cumulative lost value*/ \

View file

@ -64,6 +64,7 @@ extern test_suite_t player_test_suite;
extern test_suite_t dtmf_test_suite;
extern test_suite_t offeranswer_test_suite;
extern test_suite_t video_test_suite;
extern test_suite_t multicast_call_test_suite;
extern int liblinphone_tester_nb_test_suites(void);
@ -314,7 +315,9 @@ void liblinphone_tester_enable_ipv6(bool_t enabled);
void cunit_android_trace_handler(int level, const char *fmt, va_list args) ;
#endif
int liblinphone_tester_fprintf(FILE * stream, const char * format, ...);
void linphone_call_cb(LinphoneCall *call,void * user_data);
void call_paused_resumed_base(bool_t multicast);
void simple_call_base(bool_t enable_multicast_recv_side);
void call_base(LinphoneMediaEncryption mode, bool_t enable_video,bool_t enable_relay,LinphoneFirewallPolicy policy,bool_t enable_tunnel);
#endif /* LIBLINPHONE_TESTER_H_ */

View file

@ -0,0 +1,198 @@
/*
liblinphone_tester - liblinphone test suite
Copyright (C) 2014 Belledonne Communications SARL
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, see <http://www.gnu.org/licenses/>.
*/
#include "liblinphone_tester.h"
#include "linphonecore.h"
#include "belle-sip/belle-sip.h"
static void call_multicast_base(bool_t video) {
LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc");
LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc");
int begin;
int leaked_objects;
LinphoneVideoPolicy marie_policy, pauline_policy;
belle_sip_object_enable_leak_detector(TRUE);
begin=belle_sip_object_get_object_count();
if (video) {
linphone_core_enable_video_capture(marie->lc, TRUE);
linphone_core_enable_video_display(marie->lc, TRUE);
linphone_core_enable_video_capture(pauline->lc, TRUE);
linphone_core_enable_video_display(pauline->lc, FALSE);
marie_policy.automatically_initiate=TRUE;
marie_policy.automatically_accept=TRUE;
pauline_policy.automatically_initiate=TRUE;
pauline_policy.automatically_accept=TRUE;
linphone_core_set_video_policy(marie->lc,&marie_policy);
linphone_core_set_video_policy(pauline->lc,&pauline_policy);
linphone_core_set_video_multicast_addr(pauline->lc,"224.1.2.3");
linphone_core_enable_video_multicast(pauline->lc,TRUE);
}
linphone_core_set_audio_multicast_addr(pauline->lc,"224.1.2.3");
linphone_core_enable_audio_multicast(pauline->lc,TRUE);
CU_ASSERT_TRUE(call(pauline,marie));
wait_for_until(marie->lc, pauline->lc, NULL, 1, 3000);
if (linphone_core_get_current_call(marie->lc)) {
CU_ASSERT_TRUE(linphone_call_get_audio_stats(linphone_core_get_current_call(marie->lc))->download_bandwidth>70);
if (video) {
/*check video path*/
linphone_call_set_next_video_frame_decoded_callback(linphone_core_get_current_call(marie->lc),linphone_call_cb,marie->lc);
linphone_call_send_vfu_request(linphone_core_get_current_call(marie->lc));
CU_ASSERT_TRUE( wait_for(marie->lc,pauline->lc,&marie->stat.number_of_IframeDecoded,1));
}
end_call(marie,pauline);
}
linphone_core_manager_destroy(marie);
linphone_core_manager_destroy(pauline);
leaked_objects=belle_sip_object_get_object_count()-begin;
CU_ASSERT_TRUE(leaked_objects==0);
if (leaked_objects>0){
belle_sip_object_dump_active_objects();
}
}
static void call_multicast(void) {
call_multicast_base(FALSE);
}
static void multicast_audio_with_pause_resume() {
call_paused_resumed_base(TRUE);
}
#ifdef VIDEO_ENABLED
static void call_multicast_video(void) {
call_multicast_base(TRUE);
}
#endif
static void early_media_with_multicast_base(bool_t video) {
LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc");
LinphoneCoreManager* pauline = linphone_core_manager_new("pauline_rc");
MSList* lcs = NULL;
LinphoneCall* marie_call;
int dummy=0;
int leaked_objects;
int begin;
LinphoneVideoPolicy marie_policy, pauline_policy;
belle_sip_object_enable_leak_detector(TRUE);
begin=belle_sip_object_get_object_count();
if (video) {
linphone_core_enable_video_capture(pauline->lc, TRUE);
linphone_core_enable_video_display(pauline->lc, TRUE);
linphone_core_enable_video_capture(marie->lc, TRUE);
linphone_core_enable_video_display(marie->lc, FALSE);
marie_policy.automatically_initiate=TRUE;
marie_policy.automatically_accept=TRUE;
pauline_policy.automatically_initiate=TRUE;
pauline_policy.automatically_accept=TRUE;
linphone_core_set_video_policy(marie->lc,&marie_policy);
linphone_core_set_video_policy(pauline->lc,&pauline_policy);
linphone_core_set_video_multicast_addr(marie->lc,"224.1.2.3");
linphone_core_enable_video_multicast(marie->lc,TRUE);
}
linphone_core_set_audio_multicast_addr(marie->lc,"224.1.2.3");
linphone_core_enable_audio_multicast(marie->lc,TRUE);
lcs = ms_list_append(lcs,marie->lc);
lcs = ms_list_append(lcs,pauline->lc);
/*
Marie calls Pauline, and after the call has rung, transitions to an early_media session
*/
marie_call = linphone_core_invite_address(marie->lc, pauline->identity);
CU_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallIncomingReceived,1,3000));
CU_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallOutgoingRinging,1,1000));
if (linphone_core_inc_invite_pending(pauline->lc)) {
/* send a 183 to initiate the early media */
if (video) {
/*check video path*/
linphone_call_set_next_video_frame_decoded_callback(linphone_core_get_current_call(pauline->lc),linphone_call_cb,pauline->lc);
}
linphone_core_accept_early_media(pauline->lc, linphone_core_get_current_call(pauline->lc));
CU_ASSERT_TRUE( wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallIncomingEarlyMedia,1,2000) );
CU_ASSERT_TRUE( wait_for_list(lcs, &marie->stat.number_of_LinphoneCallOutgoingEarlyMedia,1,2000) );
wait_for_list(lcs, &dummy, 1, 3000);
CU_ASSERT_TRUE(linphone_call_get_audio_stats(linphone_core_get_current_call(pauline->lc))->download_bandwidth>70);
if (video) {
CU_ASSERT_TRUE( wait_for(marie->lc,pauline->lc,&pauline->stat.number_of_IframeDecoded,1));
}
linphone_core_accept_call(pauline->lc, linphone_core_get_current_call(pauline->lc));
CU_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallConnected, 1,1000));
CU_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallStreamsRunning, 1,1000));
end_call(marie,pauline);
}
ms_free(lcs);
linphone_core_manager_destroy(marie);
linphone_core_manager_destroy(pauline);
leaked_objects=belle_sip_object_get_object_count()-begin;
CU_ASSERT_TRUE(leaked_objects==2/*fixme jehan*/);
if ((leaked_objects)>0){
belle_sip_object_dump_active_objects();
}
}
static void early_media_with_multicast_audio() {
early_media_with_multicast_base(FALSE);
}
static void unicast_incoming_with_multicast_audio_on() {
simple_call_base(TRUE);
}
#ifdef VIDEO_ENABLED
static void early_media_with_multicast_video() {
early_media_with_multicast_base(TRUE);
}
#endif
test_t multicast_call_tests[] = {
{ "Multicast audio call",call_multicast},
{ "Multicast call with pause/resume",multicast_audio_with_pause_resume},
{ "Early media multicast audio call",early_media_with_multicast_audio},
{ "Unicast incoming call with multicast activated",unicast_incoming_with_multicast_audio_on},
#ifdef VIDEO_ENABLED
{ "Multicast video call",call_multicast_video},
{ "Early media multicast video call",early_media_with_multicast_video},
#endif
};
test_suite_t multicast_call_test_suite = {
"Multicast Call",
NULL,
NULL,
sizeof(multicast_call_tests) / sizeof(multicast_call_tests[0]),
multicast_call_tests
};

View file

@ -347,7 +347,7 @@ static void presence_information(void) {
linphone_core_manager_destroy(marie);
linphone_core_manager_destroy(pauline);
}
#define USE_PRESENCE_SERVER 0
#define USE_PRESENCE_SERVER 1
#if USE_PRESENCE_SERVER
static void test_subscribe_notify_publish(void) {
@ -382,25 +382,87 @@ static void test_subscribe_notify_publish(void) {
wait_for_until(pauline->lc,marie->lc,&pauline->stat.number_of_NotifyReceived,2,2000);
CU_ASSERT_EQUAL(LinphoneStatusOnline,linphone_friend_get_status(lf));
presence =linphone_presence_model_new_with_activity(LinphonePresenceActivityOffline,NULL);
presence =linphone_presence_model_new_with_activity(LinphonePresenceActivityBusy,NULL);
linphone_core_set_presence_model(marie->lc,presence);
/*wait for new status*/
wait_for_until(pauline->lc,marie->lc,&pauline->stat.number_of_NotifyReceived,3,2000);
CU_ASSERT_EQUAL(LinphonePresenceActivityOffline,linphone_friend_get_status(lf));
CU_ASSERT_EQUAL(LinphoneStatusBusy,linphone_friend_get_status(lf));
/*wait for refresh*/
wait_for_until(pauline->lc,marie->lc,&pauline->stat.number_of_NotifyReceived,4,5000);
CU_ASSERT_EQUAL(LinphonePresenceActivityOffline,linphone_friend_get_status(lf));
CU_ASSERT_EQUAL(LinphoneStatusBusy,linphone_friend_get_status(lf));
//linphone_core_remove_friend(pauline->lc,lf);
/*linphone_core_remove_friend(pauline->lc,lf);*/
/*wait for final notify*/
//wait_for_until(pauline->lc,marie->lc,&pauline->stat.number_of_NotifyReceived,4,5000);
//CU_ASSERT_EQUAL(LinphonePresenceActivityOffline,linphone_friend_get_status(lf));
/*wait_for_until(pauline->lc,marie->lc,&pauline->stat.number_of_NotifyReceived,4,5000);
CU_ASSERT_EQUAL(LinphonePresenceActivityOffline,linphone_friend_get_status(lf));
*/
linphone_core_manager_destroy(marie);
linphone_core_manager_destroy(pauline);
}
static void test_forked_subscribe_notify_publish(void) {
LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc");
LinphoneCoreManager* marie2 = linphone_core_manager_new( "marie_rc");
LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc");
LinphoneProxyConfig* proxy;
LinphonePresenceModel* presence;
MSList* lcs=ms_list_append(NULL,pauline->lc);
lcs=ms_list_append(lcs,marie->lc);
lcs=ms_list_append(lcs,marie->lc);
lcs=ms_list_append(lcs,marie2->lc);
LpConfig *pauline_lp = linphone_core_get_config(pauline->lc);
char* lf_identity=linphone_address_as_string_uri_only(marie->identity);
LinphoneFriend *lf = linphone_core_create_friend_with_address(pauline->lc,lf_identity);
lp_config_set_int(pauline_lp,"sip","subscribe_expires",5);
linphone_core_add_friend(pauline->lc,lf);
/*wait for subscribe acknowledgment*/
wait_for_list(lcs,&pauline->stat.number_of_NotifyReceived,1,2000);
CU_ASSERT_EQUAL(LinphoneStatusOffline,linphone_friend_get_status(lf));
/*enable publish*/
linphone_core_get_default_proxy(marie->lc,&proxy);
linphone_proxy_config_edit(proxy);
linphone_proxy_config_enable_publish(proxy,TRUE);
linphone_proxy_config_set_publish_expires(proxy,3);
linphone_proxy_config_done(proxy);
linphone_core_get_default_proxy(marie2->lc,&proxy);
linphone_proxy_config_edit(proxy);
linphone_proxy_config_enable_publish(proxy,TRUE);
linphone_proxy_config_set_publish_expires(proxy,3);
linphone_proxy_config_done(proxy);
/*wait for marie status*/
wait_for_list(lcs,&pauline->stat.number_of_NotifyReceived,3,2000);
CU_ASSERT_EQUAL(LinphoneStatusOnline,linphone_friend_get_status(lf));
presence =linphone_presence_model_new_with_activity(LinphonePresenceActivityBusy,NULL);
linphone_core_set_presence_model(marie->lc,presence);
/*wait for new status*/
wait_for_list(lcs,&pauline->stat.number_of_NotifyReceived,4,2000);
CU_ASSERT_EQUAL(LinphoneStatusBusy,linphone_friend_get_status(lf));
presence =linphone_presence_model_new_with_activity( LinphonePresenceActivityMeeting,NULL);
linphone_core_set_presence_model(marie2->lc,presence);
/*wait for new status*/
wait_for_list(lcs,&pauline->stat.number_of_NotifyReceived,5,2000);
CU_ASSERT_EQUAL(LinphoneStatusBusy,linphone_friend_get_status(lf)); /*because liblinphone compositor is very simple for now (I.E only take first occurence)*/
linphone_core_manager_destroy(marie);
linphone_core_manager_destroy(marie2);
linphone_core_manager_destroy(pauline);
}
#endif
@ -414,6 +476,7 @@ test_t presence_tests[] = {
{ "App managed presence failure", subscribe_failure_handle_by_app },
#if USE_PRESENCE_SERVER
{ "Subscribe with late publish", test_subscribe_notify_publish },
{ "Forked subscribe with late publish", test_forked_subscribe_notify_publish },
#endif
};

View file

@ -453,6 +453,7 @@ void liblinphone_tester_init(void) {
#if defined(VIDEO_ENABLED) && defined(HAVE_GTK)
add_test_suite(&video_test_suite);
#endif
add_test_suite(&multicast_call_test_suite);
}
void liblinphone_tester_uninit(void) {