diff --git a/coreapi/call_params.c b/coreapi/call_params.c
index 8acc33b19..828fba70c 100644
--- a/coreapi/call_params.c
+++ b/coreapi/call_params.c
@@ -235,6 +235,21 @@ void linphone_call_params_unref(LinphoneCallParams *cp) {
belle_sip_object_unref(cp);
}
+void linphone_call_params_enable_audio_multicast(LinphoneCallParams *params, bool_t yesno) {
+ params->audio_multicast_enabled=yesno;
+}
+
+bool_t linphone_call_params_audio_multicast_enabled(const LinphoneCallParams *params) {
+ return params->audio_multicast_enabled;
+}
+
+void linphone_call_params_enable_video_multicast(LinphoneCallParams *params, bool_t yesno) {
+ params->video_multicast_enabled=yesno;
+}
+bool_t linphone_call_params_video_multicast_enabled(const LinphoneCallParams *params) {
+ return params->video_multicast_enabled;
+}
+
/*******************************************************************************
* Constructor and destructor functions *
******************************************************************************/
diff --git a/coreapi/call_params.h b/coreapi/call_params.h
index beecc9791..8f9182af1 100644
--- a/coreapi/call_params.h
+++ b/coreapi/call_params.h
@@ -322,6 +322,42 @@ LINPHONE_PUBLIC LinphoneCallParams * linphone_call_params_ref(LinphoneCallParams
LINPHONE_PUBLIC void linphone_call_params_unref(LinphoneCallParams *cp);
+/**
+ * Use to enable multicast rtp for audio stream.
+ * * If enabled, outgoing calls put a multicast address from #linphone_core_get_video_multicast_addr into audio cline. In case of outgoing call audio stream is sent to this multicast address.
+ *
For incoming calls behavior is unchanged.
+ * @param core #LinphoneCallParams
+ * @param yesno if yes, subsequent calls will propose multicast ip set by #linphone_core_set_audio_multicast_addr
+ * @ingroup media_parameters
+**/
+LINPHONE_PUBLIC void linphone_call_params_enable_audio_multicast(LinphoneCallParams *param, bool_t yesno);
+
+/**
+ * Use to get multicast state of audio stream.
+ * @param core #LinphoneCallParams
+ * @return true if subsequent calls will propose multicast ip set by #linphone_core_set_audio_multicast_addr
+ * @ingroup media_parameters
+**/
+LINPHONE_PUBLIC bool_t linphone_call_params_audio_multicast_enabled(const LinphoneCallParams *param);
+
+/**
+ * Use to enable multicast rtp for video stream.
+ * If enabled, outgoing calls put a multicast address from #linphone_core_get_video_multicast_addr into video cline. In case of outgoing call video stream is sent to this multicast address.
+ *
For incoming calls behavior is unchanged.
+ * @param core #LinphoneCallParams
+ * @param yesno if yes, subsequent outgoing calls will propose multicast ip set by #linphone_core_set_video_multicast_addr
+ * @ingroup media_parameters
+**/
+LINPHONE_PUBLIC void linphone_call_params_enable_video_multicast(LinphoneCallParams *param, bool_t yesno);
+/**
+ * Use to get multicast state of video stream.
+ * @param core #LinphoneCallParams
+ * @return true if subsequent calls will propose multicast ip set by #linphone_core_set_video_multicast_addr
+ * @ingroup media_parameters
+**/
+LINPHONE_PUBLIC bool_t linphone_call_params_video_multicast_enabled(const LinphoneCallParams *param);
+
+
/*******************************************************************************
* DEPRECATED *
******************************************************************************/
diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c
index 0143be751..b945be221 100644
--- a/coreapi/callbacks.c
+++ b/coreapi/callbacks.c
@@ -144,10 +144,13 @@ void linphone_core_update_streams(LinphoneCore *lc, LinphoneCall *call, SalMedia
call->resultdesc=new_md;
if ((call->audiostream && call->audiostream->ms.state==MSStreamStarted) || (call->videostream && call->videostream->ms.state==MSStreamStarted)){
clear_early_media_destinations(call);
+ int md_changed=0;
/* we already started media: check if we really need to restart it*/
if (oldmd){
- int md_changed = media_parameters_changed(call, oldmd, new_md);
- if ((md_changed & (SAL_MEDIA_DESCRIPTION_CODEC_CHANGED|SAL_MEDIA_DESCRIPTION_STREAMS_CHANGED))){
+ md_changed = media_parameters_changed(call, oldmd, new_md);
+ if ((md_changed & ( SAL_MEDIA_DESCRIPTION_CODEC_CHANGED
+ |SAL_MEDIA_DESCRIPTION_STREAMS_CHANGED
+ |SAL_MEDIA_DESCRIPTION_NETWORK_XXXCAST_CHANGED))){
ms_message("Media descriptions are different, need to restart the streams.");
} else if ( call->playing_ringbacktone) {
ms_message("Playing ringback tone, will restart the streams.");
@@ -181,6 +184,11 @@ void linphone_core_update_streams(LinphoneCore *lc, LinphoneCall *call, SalMedia
}
}
linphone_call_stop_media_streams (call);
+ if (md_changed & SAL_MEDIA_DESCRIPTION_NETWORK_XXXCAST_CHANGED){
+ ms_message("Media ip type has changed, destroying sessions context on call [%p]",call);
+ ms_media_stream_sessions_uninit(&call->sessions[0]);
+ ms_media_stream_sessions_uninit(&call->sessions[1]);
+ }
linphone_call_init_media_streams (call);
}
diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c
index 94655e19c..4969da7ba 100644
--- a/coreapi/linphonecall.c
+++ b/coreapi/linphonecall.c
@@ -591,12 +591,12 @@ void linphone_call_make_local_media_description_with_params(LinphoneCore *lc, Li
CodecConstraints codec_hints={0};
/*multicast is only set in case of outgoing call*/
- if (call->dir == LinphoneCallOutgoing && linphone_core_audio_multicast_enabled(lc)) {
+ if (call->dir == LinphoneCallOutgoing && linphone_call_params_audio_multicast_enabled(params)) {
md->streams[0].ttl=linphone_core_get_audio_multicast_ttl(lc);
md->streams[0].multicast_role = SalMulticastSender;
}
- if (call->dir == LinphoneCallOutgoing && linphone_core_video_multicast_enabled(lc)) {
+ if (call->dir == LinphoneCallOutgoing && linphone_call_params_video_multicast_enabled(params)) {
md->streams[1].ttl=linphone_core_get_video_multicast_ttl(lc);
md->streams[1].multicast_role = SalMulticastSender;
}
@@ -814,17 +814,6 @@ static void linphone_call_init_common(LinphoneCall *call, LinphoneAddress *from,
linphone_core_get_video_port_range(call->core, &min_port, &max_port);
port_config_set(call,1,min_port,max_port);
- if (call->dir==LinphoneCallOutgoing){
- if ( linphone_core_audio_multicast_enabled(call->core)){
- strncpy(call->media_ports[0].multicast_ip,
- linphone_core_get_audio_multicast_addr(call->core), sizeof(call->media_ports[0].multicast_ip));
- }
- if ( linphone_core_video_multicast_enabled(call->core)){
- strncpy(call->media_ports[1].multicast_ip,
- linphone_core_get_video_multicast_addr(call->core), sizeof(call->media_ports[1].multicast_ip));
- }
- }
-
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);
#ifdef VIDEO_ENABLED
@@ -944,7 +933,19 @@ BELLE_SIP_INSTANCIATE_VPTR(LinphoneCall, belle_sip_object_t,
NULL, // marshal
FALSE
);
+void linphone_call_fill_media_multicast_addr(LinphoneCall *call) {
+ if (linphone_call_params_audio_multicast_enabled(call->params)){
+ strncpy(call->media_ports[0].multicast_ip,
+ linphone_core_get_audio_multicast_addr(call->core), sizeof(call->media_ports[0].multicast_ip));
+ } else
+ call->media_ports[0].multicast_ip[0]='\0';
+ if (linphone_call_params_video_multicast_enabled(call->params)){
+ strncpy(call->media_ports[1].multicast_ip,
+ linphone_core_get_video_multicast_addr(call->core), sizeof(call->media_ports[1].multicast_ip));
+ } else
+ call->media_ports[1].multicast_ip[0]='\0';
+}
LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, LinphoneAddress *from, LinphoneAddress *to, const LinphoneCallParams *params, LinphoneProxyConfig *cfg){
LinphoneCall *call = belle_sip_object_new(LinphoneCall);
@@ -955,6 +956,8 @@ LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, LinphoneAddr
linphone_call_init_common(call,from,to);
call->params = linphone_call_params_copy(params);
+ linphone_call_fill_media_multicast_addr(call);
+
if (linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseIce) {
call->ice_session = ice_session_new();
/*for backward compatibility purposes, shall be enabled by default in futur*/
@@ -1010,26 +1013,18 @@ void linphone_call_set_compatible_incoming_call_parameters(LinphoneCall *call, c
call->params->media_encryption = LinphoneMediaEncryptionNone;
}
- /* set both local audio & video multicast ip address if any*/
- for (i=0;i<2;++i){
- if (md->streams[i].rtp_addr[i]!='\0' && ms_is_multicast(md->streams[i].rtp_addr)) {
- strncpy(call->media_ports[i].multicast_ip,md->streams[i].rtp_addr,sizeof(call->media_ports[i].multicast_ip));
- ms_message("Disabling rtcp on call [%p], stream [%i] because of multicast",call,i);
- call->media_ports[i].mcast_rtp_port=md->streams[i].rtp_port;
- call->media_ports[i].mcast_rtcp_port=0;
- }
- }
}
LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *from, LinphoneAddress *to, SalOp *op){
LinphoneCall *call = belle_sip_object_new(LinphoneCall);
- const SalMediaDescription *md;
+ SalMediaDescription *md;
LinphoneFirewallPolicy fpol;
call->dir=LinphoneCallIncoming;
sal_op_set_user_pointer(op,call);
call->op=op;
call->core=lc;
+ int i;
linphone_call_incoming_select_ip_version(call);
sal_op_cnx_ip_to_0000_if_sendonly_enable(op,lp_config_get_default_int(lc->config,"sip","cnx_ip_to_0000_if_sendonly_enabled",0));
@@ -1075,7 +1070,14 @@ LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *fro
// It is licit to receive an INVITE without SDP
// In this case WE chose the media parameters according to policy.
linphone_call_set_compatible_incoming_call_parameters(call, md);
+ /* set multicast role & address if any*/
+ for (i=0;inb_streams;i++){
+ if (!sal_call_is_offerer(op) && ms_is_multicast(md->streams[i].rtp_addr))
+ md->streams[i].multicast_role = SalMulticastReceiver;
+ strncpy(call->media_ports[i].multicast_ip,md->streams[i].rtp_addr,sizeof(call->media_ports[i].multicast_ip));
+ }
}
+
fpol=linphone_core_get_firewall_policy(call->core);
/*create the ice session now if ICE is required*/
if (fpol==LinphonePolicyUseIce){
@@ -1478,10 +1480,23 @@ const LinphoneCallParams * linphone_call_get_current_params(LinphoneCall *call){
call->current_params->avpf_rr_interval = 0;
}
if (md){
+ const char *rtp_addr;
+
SalStreamDescription *sd=sal_media_description_find_best_stream(md,SalAudio);
call->current_params->audio_dir=sd ? media_direction_from_sal_stream_dir(sd->dir) : LinphoneMediaDirectionInactive;
+ if (call->current_params->audio_dir != LinphoneMediaDirectionInactive) {
+ rtp_addr = sd->rtp_addr[0]!='\0' ? sd->rtp_addr : call->resultdesc->addr;
+ call->current_params->audio_multicast_enabled = ms_is_multicast(rtp_addr);
+ } else
+ call->current_params->audio_multicast_enabled = FALSE;
+
sd=sal_media_description_find_best_stream(md,SalVideo);
call->current_params->video_dir=sd ? media_direction_from_sal_stream_dir(sd->dir) : LinphoneMediaDirectionInactive;
+ if (call->current_params->video_dir != LinphoneMediaDirectionInactive) {
+ rtp_addr = sd->rtp_addr[0]!='\0' ? sd->rtp_addr : call->resultdesc->addr;
+ call->current_params->video_multicast_enabled = ms_is_multicast(rtp_addr);
+ } else
+ call->current_params->video_multicast_enabled = FALSE;
}
return call->current_params;
@@ -1900,9 +1915,38 @@ int linphone_call_prepare_ice(LinphoneCall *call, bool_t incoming_offer){
/*eventually join to a multicast group if told to do so*/
static void linphone_call_join_multicast_group(LinphoneCall *call, int stream_index, MediaStream *ms){
- if (call->media_ports[stream_index].multicast_ip[stream_index]!='\0' && call->media_ports[stream_index].mcast_rtp_port!=0){
+ if (call->media_ports[stream_index].multicast_ip[stream_index]!='\0'){
media_stream_join_multicast_group(ms, call->media_ports[stream_index].multicast_ip);
- }
+ } else
+ ms_error("Cannot join multicast group if multicast ip is not set for call [%p]",call);
+}
+
+static SalMulticastRole linphone_call_get_multicast_role(const LinphoneCall *call,SalStreamType type) {
+ SalMulticastRole multicast_role=SalMulticastInactive;
+ SalMediaDescription *remotedesc, *localdesc;
+ SalStreamDescription *stream_desc = NULL;
+ if (!call->op) goto end;
+ remotedesc = sal_call_get_remote_media_description(call->op);
+ localdesc = call->localdesc;
+ if (!localdesc && !remotedesc && call->dir == LinphoneCallOutgoing) {
+ /*well using call dir*/
+ if ((type == SalAudio && linphone_call_params_audio_multicast_enabled(call->params))
+ || (type == SalVideo && linphone_call_params_video_multicast_enabled(call->params)))
+ multicast_role=SalMulticastSender;
+ } else if (localdesc && (!remotedesc || sal_call_is_offerer(call->op))) {
+ stream_desc = sal_media_description_find_best_stream(localdesc, type);
+ } else if (!sal_call_is_offerer(call->op) && remotedesc)
+ stream_desc = sal_media_description_find_best_stream(remotedesc, type);
+
+ if (stream_desc)
+ multicast_role=stream_desc->multicast_role;
+ else
+ ms_message("Cannot determine multicast role for stream type [%s] on call [%p]",sal_stream_type_to_string(type),call);
+
+
+ end:
+ return multicast_role;
+
}
void linphone_call_init_audio_stream(LinphoneCall *call){
@@ -1913,14 +1957,23 @@ void linphone_call_init_audio_stream(LinphoneCall *call){
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){
+ SalMulticastRole multicast_role = linphone_call_get_multicast_role(call,SalAudio);
+ SalMediaDescription *remotedesc=NULL;
+ SalStreamDescription *stream_desc = NULL;
+ if (call->op) remotedesc = sal_call_get_remote_media_description(call->op);
+ if (remotedesc)
+ stream_desc = sal_media_description_find_best_stream(remotedesc, SalAudio);
+
call->audiostream=audiostream=audio_stream_new2(linphone_call_get_bind_ip_for_stream(call,0),
- call->media_ports[0].mcast_rtp_port ? call->media_ports[0].mcast_rtp_port : call->media_ports[0].rtp_port,
- call->media_ports[0].mcast_rtcp_port ? call->media_ports[0].mcast_rtcp_port : call->media_ports[0].rtcp_port);
- linphone_call_join_multicast_group(call, 0, &audiostream->ms);
+ multicast_role == SalMulticastReceiver ? stream_desc->rtp_port : call->media_ports[0].rtp_port,
+ multicast_role == SalMulticastReceiver ? 0 /*disabled for now*/ : call->media_ports[0].rtcp_port);
+ if (multicast_role == SalMulticastReceiver)
+ linphone_call_join_multicast_group(call, 0, &audiostream->ms);
rtp_session_enable_network_simulation(call->audiostream->ms.sessions.rtp_session, &lc->net_conf.netsim_params);
cname = linphone_address_as_string_uri_only(call->me);
audio_stream_set_rtcp_information(call->audiostream, cname, rtcp_tool);
@@ -2014,11 +2067,14 @@ void linphone_call_init_audio_stream(LinphoneCall *call){
_linphone_call_prepare_ice_for_stream(call,0,FALSE);
}
+
void linphone_call_init_video_stream(LinphoneCall *call){
#ifdef VIDEO_ENABLED
LinphoneCore *lc=call->core;
char* cname;
char rtcp_tool[128];
+
+
snprintf(rtcp_tool,sizeof(rtcp_tool)-1,"%s-%s",linphone_core_get_user_agent_name(),linphone_core_get_user_agent_version());
if (call->videostream == NULL){
@@ -2027,10 +2083,18 @@ 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){
+ SalMulticastRole multicast_role = linphone_call_get_multicast_role(call,SalVideo);
+ SalMediaDescription *remotedesc=NULL;
+ SalStreamDescription *stream_desc = NULL;
+ if (call->op) remotedesc = sal_call_get_remote_media_description(call->op);
+ if (remotedesc)
+ stream_desc = sal_media_description_find_best_stream(remotedesc, SalVideo);
+
call->videostream=video_stream_new2(linphone_call_get_bind_ip_for_stream(call,1),
- call->media_ports[1].mcast_rtp_port>0 ? call->media_ports[1].mcast_rtp_port : call->media_ports[1].rtp_port,
- call->media_ports[1].mcast_rtcp_port>0 ? call->media_ports[1].mcast_rtcp_port : call->media_ports[1].rtcp_port);
- linphone_call_join_multicast_group(call, 1, &call->videostream->ms);
+ multicast_role == SalMulticastReceiver ? stream_desc->rtp_port : call->media_ports[1].rtp_port,
+ multicast_role == SalMulticastReceiver ? 0 /*disabled for now*/ : call->media_ports[1].rtcp_port);
+ if (multicast_role == SalMulticastReceiver)
+ linphone_call_join_multicast_group(call, 1, &call->videostream->ms);
rtp_session_enable_network_simulation(call->videostream->ms.sessions.rtp_session, &lc->net_conf.netsim_params);
cname = linphone_address_as_string_uri_only(call->me);
video_stream_set_rtcp_information(call->videostream, cname, rtcp_tool);
diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c
index 2d3efb6f0..c58b3a281 100644
--- a/coreapi/linphonecore.c
+++ b/coreapi/linphonecore.c
@@ -3436,6 +3436,8 @@ int linphone_core_start_update_call(LinphoneCore *lc, LinphoneCall *call){
int err;
bool_t no_user_consent=call->params->no_user_consent;
+ linphone_call_fill_media_multicast_addr(call);
+
if (!no_user_consent) linphone_call_make_local_media_description(lc,call);
#ifdef BUILD_UPNP
if(call->upnp_session != NULL) {
@@ -3651,6 +3653,11 @@ int _linphone_core_accept_call_update(LinphoneCore *lc, LinphoneCall *call, cons
}
if (params==NULL){
linphone_call_params_enable_video(call->params, lc->video_policy.automatically_accept || call->current_params->has_video);
+ if (!sal_call_is_offerer(call->op)) {
+ /*reset call param for multicast because this param is only relevant when offering*/
+ linphone_call_params_enable_audio_multicast(call->params,FALSE);
+ linphone_call_params_enable_video_multicast(call->params,FALSE);
+ }
}else
linphone_call_set_new_params(call,params);
@@ -3662,6 +3669,9 @@ int _linphone_core_accept_call_update(LinphoneCore *lc, LinphoneCall *call, cons
ms_warning("Video isn't supported in conference");
call->params->has_video = FALSE;
}
+ /*update multicast params according to call params*/
+ linphone_call_fill_media_multicast_addr(call);
+
linphone_call_init_media_streams(call); /*so that video stream is initialized if necessary*/
if (call->ice_session != NULL) {
if (linphone_call_prepare_ice(call,TRUE)==1)
@@ -7053,6 +7063,8 @@ void linphone_core_init_default_params(LinphoneCore*lc, LinphoneCallParams *para
params->audio_dir=LinphoneMediaDirectionSendRecv;
params->video_dir=LinphoneMediaDirectionSendRecv;
params->real_early_media=lp_config_get_int(lc->config,"misc","real_early_media",FALSE);
+ params->audio_multicast_enabled=linphone_core_audio_multicast_enabled(lc);
+ params->video_multicast_enabled=linphone_core_video_multicast_enabled(lc);
}
void linphone_core_set_device_identifier(LinphoneCore *lc,const char* device_id) {
diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc
index a61091a68..968d897be 100644
--- a/coreapi/linphonecore_jni.cc
+++ b/coreapi/linphonecore_jni.cc
@@ -3631,6 +3631,19 @@ extern "C" jboolean Java_org_linphone_core_LinphoneCallParamsImpl_getVideoEnable
return (jboolean)linphone_call_params_video_enabled((LinphoneCallParams*)lcp);
}
+extern "C" void Java_org_linphone_core_LinphoneCallParamsImpl_enableVideoMulticast(JNIEnv *env, jobject thiz, jlong lcp, jboolean b){
+ linphone_call_params_enable_video_multicast((LinphoneCallParams*)lcp, b);
+}
+extern "C" jboolean Java_org_linphone_core_LinphoneCallParamsImpl_videoMulticastEnabled(JNIEnv *env, jobject thiz, jlong lcp){
+ return (jboolean)linphone_call_params_video_multicast_enabled((LinphoneCallParams*)lcp);
+}
+extern "C" void Java_org_linphone_core_LinphoneCallParamsImpl_enableAudioMulticast(JNIEnv *env, jobject thiz, jlong lcp, jboolean b){
+ linphone_call_params_enable_audio_multicast((LinphoneCallParams*)lcp, b);
+}
+extern "C" jboolean Java_org_linphone_core_LinphoneCallParamsImpl_audioMulticastEnabled(JNIEnv *env, jobject thiz, jlong lcp){
+ return (jboolean)linphone_call_params_audio_multicast_enabled((LinphoneCallParams*)lcp);
+}
+
extern "C" jboolean Java_org_linphone_core_LinphoneCallParamsImpl_localConferenceMode(JNIEnv *env, jobject thiz, jlong lcp){
return (jboolean)linphone_call_params_get_local_conference_mode((LinphoneCallParams*)lcp);
}
diff --git a/coreapi/private.h b/coreapi/private.h
index 9ef265d26..8faa8ad35 100644
--- a/coreapi/private.h
+++ b/coreapi/private.h
@@ -112,7 +112,8 @@ struct _LinphoneCallParams{
LinphoneMediaDirection video_dir;
bool_t video_declined; /*use to keep traces of declined video to avoid to re-offer video in case of automatic RE-INVITE*/
bool_t internal_call_update; /*use mark that call update was requested internally (might be by ice)*/
-
+ bool_t video_multicast_enabled;
+ bool_t audio_multicast_enabled;
};
BELLE_SIP_DECLARE_VPTR(LinphoneCallParams);
@@ -205,8 +206,6 @@ typedef struct StunCandidate{
typedef struct _PortConfig{
char multicast_ip[LINPHONE_IPADDR_SIZE];
- int mcast_rtp_port;
- int mcast_rtcp_port;
int rtp_port;
int rtcp_port;
}PortConfig;
@@ -859,6 +858,7 @@ void linphone_core_set_state(LinphoneCore *lc, LinphoneGlobalState gstate, const
void linphone_call_make_local_media_description(LinphoneCore *lc, LinphoneCall *call);
void linphone_call_make_local_media_description_with_params(LinphoneCore *lc, LinphoneCall *call, LinphoneCallParams *params);
void linphone_call_increment_local_media_description(LinphoneCall *call);
+void linphone_call_fill_media_multicast_addr(LinphoneCall *call);
void linphone_core_update_streams(LinphoneCore *lc, LinphoneCall *call, SalMediaDescription *new_md);
bool_t linphone_core_is_payload_type_usable_for_bandwidth(LinphoneCore *lc, const PayloadType *pt, int bandwidth_limit);
diff --git a/coreapi/sal.c b/coreapi/sal.c
index a5a0755d1..2d6ed1dde 100644
--- a/coreapi/sal.c
+++ b/coreapi/sal.c
@@ -307,6 +307,8 @@ int sal_stream_description_equals(const SalStreamDescription *sd1, const SalStre
if (sd1->type != sd2->type) result |= SAL_MEDIA_DESCRIPTION_CODEC_CHANGED;
if (strcmp(sd1->rtp_addr, sd2->rtp_addr) != 0) result |= SAL_MEDIA_DESCRIPTION_NETWORK_CHANGED;
+ if (sd1->rtp_addr[0]!='\0' && sd2->rtp_addr[0]!='\0' && ms_is_multicast(sd1->rtp_addr) != ms_is_multicast(sd2->rtp_addr))
+ result |= SAL_MEDIA_DESCRIPTION_NETWORK_XXXCAST_CHANGED;
if (sd1->rtp_port != sd2->rtp_port) {
if ((sd1->rtp_port == 0) || (sd2->rtp_port == 0)) result |= SAL_MEDIA_DESCRIPTION_CODEC_CHANGED;
else result |= SAL_MEDIA_DESCRIPTION_NETWORK_CHANGED;
@@ -330,6 +332,8 @@ int sal_media_description_equals(const SalMediaDescription *md1, const SalMediaD
int i;
if (strcmp(md1->addr, md2->addr) != 0) result |= SAL_MEDIA_DESCRIPTION_NETWORK_CHANGED;
+ if (md1->addr[0]!='\0' && md2->addr[0]!='\0' && ms_is_multicast(md1->addr) != ms_is_multicast(md2->addr))
+ result |= SAL_MEDIA_DESCRIPTION_NETWORK_XXXCAST_CHANGED;
if (md1->nb_streams != md2->nb_streams) result |= SAL_MEDIA_DESCRIPTION_STREAMS_CHANGED;
if (md1->bandwidth != md2->bandwidth) result |= SAL_MEDIA_DESCRIPTION_CODEC_CHANGED;
for(i = 0; i < md1->nb_streams; ++i){
diff --git a/include/sal/sal.h b/include/sal/sal.h
index 26d8e5bb9..ac0aed989 100644
--- a/include/sal/sal.h
+++ b/include/sal/sal.h
@@ -68,15 +68,20 @@ typedef enum {
SalTransportDTLS, /*DTLS*/
}SalTransport;
-#define SAL_MEDIA_DESCRIPTION_UNCHANGED 0x00
-#define SAL_MEDIA_DESCRIPTION_NETWORK_CHANGED (1)
-#define SAL_MEDIA_DESCRIPTION_CODEC_CHANGED (1<<1)
-#define SAL_MEDIA_DESCRIPTION_CRYPTO_KEYS_CHANGED (1<<2)
-#define SAL_MEDIA_DESCRIPTION_CRYPTO_POLICY_CHANGED (1<<3)
-#define SAL_MEDIA_DESCRIPTION_STREAMS_CHANGED (1<<4)
+#define SAL_MEDIA_DESCRIPTION_UNCHANGED 0x00
+#define SAL_MEDIA_DESCRIPTION_NETWORK_CHANGED (1)
+#define SAL_MEDIA_DESCRIPTION_CODEC_CHANGED (1<<1)
+#define SAL_MEDIA_DESCRIPTION_CRYPTO_KEYS_CHANGED (1<<2)
+#define SAL_MEDIA_DESCRIPTION_CRYPTO_POLICY_CHANGED (1<<3)
+#define SAL_MEDIA_DESCRIPTION_STREAMS_CHANGED (1<<4)
+#define SAL_MEDIA_DESCRIPTION_NETWORK_XXXCAST_CHANGED (1<<5) /* use to notify when switching from multicast to unicast*/
-#define SAL_MEDIA_DESCRIPTION_CHANGED (SAL_MEDIA_DESCRIPTION_NETWORK_CHANGED | SAL_MEDIA_DESCRIPTION_CODEC_CHANGED |\
- SAL_MEDIA_DESCRIPTION_CRYPTO_KEYS_CHANGED |SAL_MEDIA_DESCRIPTION_CRYPTO_POLICY_CHANGED | SAL_MEDIA_DESCRIPTION_STREAMS_CHANGED)
+#define SAL_MEDIA_DESCRIPTION_CHANGED (SAL_MEDIA_DESCRIPTION_NETWORK_CHANGED \
+ |SAL_MEDIA_DESCRIPTION_CODEC_CHANGED \
+ |SAL_MEDIA_DESCRIPTION_CRYPTO_KEYS_CHANGED \
+ |SAL_MEDIA_DESCRIPTION_CRYPTO_POLICY_CHANGED \
+ |SAL_MEDIA_DESCRIPTION_STREAMS_CHANGED \
+ |SAL_MEDIA_DESCRIPTION_NETWORK_XXXCAST_CHANGED)
const char* sal_transport_to_string(SalTransport transport);
SalTransport sal_transport_parse(const char*);
diff --git a/java/common/org/linphone/core/LinphoneCallParams.java b/java/common/org/linphone/core/LinphoneCallParams.java
index 7086a56fb..fa827faa2 100644
--- a/java/common/org/linphone/core/LinphoneCallParams.java
+++ b/java/common/org/linphone/core/LinphoneCallParams.java
@@ -131,4 +131,31 @@ public interface LinphoneCallParams {
* @return The received video size.
*/
VideoSize getReceivedVideoSize();
+ /**
+ * Use to enable multicast rtp for audio stream.
+ * * If enabled, outgoing calls put a multicast address from #linphone_core_get_video_multicast_addr into audio cline. In case of outgoing call audio stream is sent to this multicast address.
+ *
For incoming calls behavior is unchanged.
+ * @param yesno if yes, subsequent calls will propose multicast ip set by LinphoneCore.setAudioMulticastAddr
+ **/
+ void enableAudioMulticast(boolean yesno);
+
+ /**
+ * Use to get multicast state of audio stream.
+ * @return true if subsequent calls will propose multicast ip set by LinphoneCore.setAudioMulticastAddr
+ **/
+ boolean audioMulticastEnabled();
+
+ /**
+ * Use to enable multicast rtp for video stream.
+ * If enabled, outgoing calls put a multicast address from #linphone_core_get_video_multicast_addr into video cline. In case of outgoing call video stream is sent to this multicast address.
+ *
For incoming calls behavior is unchanged.
+ * @param yesno if yes, subsequent outgoing calls will propose multicast ip set by LinphoneCore.setVideoMulticastAddr
+ **/
+ void enableVideoMulticast(boolean yesno);
+ /**
+ * Use to get multicast state of video stream.
+ * @return true if subsequent calls will propose multicast ip set by LinphoneCore.setVideoMulticastAddr
+ **/
+ boolean videoMulticastEnabled();
+
}
diff --git a/java/impl/org/linphone/core/LinphoneCallParamsImpl.java b/java/impl/org/linphone/core/LinphoneCallParamsImpl.java
index a3c6425b8..c4b356fa7 100644
--- a/java/impl/org/linphone/core/LinphoneCallParamsImpl.java
+++ b/java/impl/org/linphone/core/LinphoneCallParamsImpl.java
@@ -150,4 +150,25 @@ public class LinphoneCallParamsImpl implements LinphoneCallParams {
vSize.height = nativeSize[1];
return vSize;
}
+ private native void enableAudioMulticast(long ptr,boolean yesno);
+ @Override
+ public void enableAudioMulticast(boolean yesno) {
+ enableAudioMulticast(nativePtr,yesno);
+ }
+ private native boolean audioMulticastEnabled(long ptr);
+ @Override
+ public boolean audioMulticastEnabled() {
+ return audioMulticastEnabled(nativePtr);
+ }
+ private native void enableVideoMulticast(long ptr,boolean yesno);
+
+ @Override
+ public void enableVideoMulticast(boolean yesno) {
+ enableVideoMulticast(nativePtr,yesno);
+ }
+ private native boolean videoMulticastEnabled(long ptr);
+ @Override
+ public boolean videoMulticastEnabled() {
+ return videoMulticastEnabled(nativePtr);
+ }
}
diff --git a/tester/call_tester.c b/tester/call_tester.c
index 58b396704..f5abb2c31 100644
--- a/tester/call_tester.c
+++ b/tester/call_tester.c
@@ -3086,7 +3086,7 @@ static void multiple_early_media(void) {
linphone_core_manager_destroy(pauline);
}
-static void check_media_direction(LinphoneCoreManager* mgr, LinphoneCall *call, MSList* lcs,LinphoneMediaDirection audio_dir, LinphoneMediaDirection video_dir) {
+void check_media_direction(LinphoneCoreManager* mgr, LinphoneCall *call, MSList* lcs,LinphoneMediaDirection audio_dir, LinphoneMediaDirection video_dir) {
CU_ASSERT_PTR_NOT_NULL(call);
if (call) {
int current_recv_iframe = mgr->stat.number_of_IframeDecoded;
diff --git a/tester/liblinphone_tester.h b/tester/liblinphone_tester.h
index 2b7f9a26c..28fcfad3b 100644
--- a/tester/liblinphone_tester.h
+++ b/tester/liblinphone_tester.h
@@ -308,6 +308,7 @@ void call_base(LinphoneMediaEncryption mode, bool_t enable_video,bool_t enable_r
bool_t call_with_caller_params(LinphoneCoreManager* caller_mgr,LinphoneCoreManager* callee_mgr, const LinphoneCallParams *params);
bool_t pause_call_1(LinphoneCoreManager* mgr_1,LinphoneCall* call_1,LinphoneCoreManager* mgr_2,LinphoneCall* call_2);
bool_t compare_files(const char *path1, const char *path2);
+void check_media_direction(LinphoneCoreManager* mgr, LinphoneCall *call, MSList* lcs,LinphoneMediaDirection audio_dir, LinphoneMediaDirection video_dir);
static const int audio_cmp_min_overlap=90;
diff --git a/tester/multicast_call_tester.c b/tester/multicast_call_tester.c
index fb4b58d6c..22c7fcd8b 100644
--- a/tester/multicast_call_tester.c
+++ b/tester/multicast_call_tester.c
@@ -96,6 +96,7 @@ static void early_media_with_multicast_base(bool_t video) {
int begin;
LinphoneVideoPolicy marie_policy, pauline_policy;
LpConfig *marie_lp;
+ LinphoneCallParams *params;
belle_sip_object_enable_leak_detector(TRUE);
begin=belle_sip_object_get_object_count();
@@ -172,6 +173,12 @@ static void early_media_with_multicast_base(bool_t video) {
CU_ASSERT_TRUE(linphone_call_get_audio_stats(linphone_core_get_current_call(pauline2->lc))->download_bandwidth>70);
CU_ASSERT_TRUE(linphone_call_get_audio_stats(linphone_core_get_current_call(pauline2->lc))->download_bandwidth<90);
+ CU_ASSERT_TRUE(linphone_call_params_audio_multicast_enabled(linphone_call_get_current_params(linphone_core_get_current_call(pauline->lc))));
+ CU_ASSERT_TRUE(linphone_call_params_audio_multicast_enabled(linphone_call_get_current_params(linphone_core_get_current_call(marie->lc))));
+ if (video) {
+ CU_ASSERT_TRUE(linphone_call_params_video_multicast_enabled(linphone_call_get_current_params(linphone_core_get_current_call(pauline->lc))));
+ CU_ASSERT_TRUE(linphone_call_params_video_multicast_enabled(linphone_call_get_current_params(linphone_core_get_current_call(marie->lc))));
+ }
if (video) {
CU_ASSERT_TRUE( wait_for_list(lcs,&pauline->stat.number_of_IframeDecoded,1,2000));
@@ -182,13 +189,48 @@ static void early_media_with_multicast_base(bool_t video) {
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));
+ CU_ASSERT_TRUE(wait_for_list(lcs, &pauline2->stat.number_of_LinphoneCallEnd, 1,1000));
+
+ CU_ASSERT_TRUE(linphone_call_params_audio_multicast_enabled(linphone_call_get_current_params(linphone_core_get_current_call(pauline->lc))));
+ CU_ASSERT_TRUE(linphone_call_params_audio_multicast_enabled(linphone_call_get_current_params(linphone_core_get_current_call(marie->lc))));
+ if (video) {
+ CU_ASSERT_TRUE(linphone_call_params_video_multicast_enabled(linphone_call_get_current_params(linphone_core_get_current_call(pauline->lc))));
+ CU_ASSERT_TRUE(linphone_call_params_video_multicast_enabled(linphone_call_get_current_params(linphone_core_get_current_call(marie->lc))));
+ }
+ params=linphone_call_params_copy(linphone_call_get_current_params(linphone_core_get_current_call(pauline->lc)));
+
+ linphone_call_params_enable_audio_multicast(params,FALSE);
+ linphone_call_params_enable_video_multicast(params,FALSE);
+ 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, TRUE);
linphone_core_update_call( pauline->lc
, linphone_core_get_current_call(pauline->lc)
- , linphone_call_get_current_params(linphone_core_get_current_call(pauline->lc)));
+ , params);
+ linphone_call_params_destroy(params);
- CU_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallStreamsRunning, 2,1000));
+ CU_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallStreamsRunning, 2,1000));
+ CU_ASSERT_FALSE(linphone_call_params_audio_multicast_enabled(linphone_call_get_current_params(linphone_core_get_current_call(pauline->lc))));
+ CU_ASSERT_FALSE(linphone_call_params_audio_multicast_enabled(linphone_call_get_current_params(linphone_core_get_current_call(marie->lc))));
+
+ check_media_direction( pauline
+ , linphone_core_get_current_call(pauline->lc)
+ , lcs
+ ,LinphoneMediaDirectionSendRecv
+ , video?LinphoneMediaDirectionSendRecv:LinphoneMediaDirectionInactive);
+ check_media_direction( marie
+ , linphone_core_get_current_call(marie->lc)
+ , lcs
+ ,LinphoneMediaDirectionSendRecv
+ , video?LinphoneMediaDirectionSendRecv:LinphoneMediaDirectionInactive);
+
+ if (video) {
+ CU_ASSERT_FALSE(linphone_call_params_video_multicast_enabled(linphone_call_get_current_params(linphone_core_get_current_call(marie->lc))));
+ CU_ASSERT_FALSE(linphone_call_params_video_multicast_enabled(linphone_call_get_current_params(linphone_core_get_current_call(pauline->lc))));
+ }
end_call(marie,pauline);
}
ms_free(lcs);