diff --git a/README.macos b/README.macos index 3ec0d0429..aecd2922f 100644 --- a/README.macos +++ b/README.macos @@ -16,6 +16,7 @@ You need: $ port install libeXosip2 #WARNING: currently outdated in macport $ port install ffmpeg-devel $ port install libvpx + $ port install readline - Install srtp (optional) for call encryption $ port install srtp diff --git a/build/android/Android-no-neon.mk b/build/android/Android-no-neon.mk index 3d72ffc55..d0c87b4f8 100644 --- a/build/android/Android-no-neon.mk +++ b/build/android/Android-no-neon.mk @@ -26,11 +26,13 @@ include $(CLEAR_VARS) include $(linphone-root-dir)/submodules/linphone/build/android/common.mk +ifeq ($(LINPHONE_VIDEO),1) LOCAL_SHARED_LIBRARIES += \ libavcodecnoneon \ libswscale \ libavcore \ libavutil +endif LOCAL_MODULE := liblinphonenoneon ifeq ($(TARGET_ARCH_ABI),armeabi) diff --git a/build/android/Android.mk b/build/android/Android.mk index 549367611..b46664b61 100755 --- a/build/android/Android.mk +++ b/build/android/Android.mk @@ -26,11 +26,13 @@ include $(CLEAR_VARS) include $(linphone-root-dir)/submodules/linphone/build/android/common.mk +ifeq ($(LINPHONE_VIDEO),1) LOCAL_SHARED_LIBRARIES += \ libavcodec \ libswscale \ libavcore \ libavutil +endif LOCAL_MODULE := liblinphone diff --git a/build/android/common.mk b/build/android/common.mk index 4fa833b59..4db1f6809 100644 --- a/build/android/common.mk +++ b/build/android/common.mk @@ -59,6 +59,7 @@ LOCAL_CFLAGS += \ -DORTP_INET6 \ -DINET6 \ -DOSIP_MT \ + -DHAVE_EXOSIP_RESET_TRANSPORTS \ -DENABLE_TRACE \ -DLINPHONE_VERSION=\"$(LINPHONE_VERSION)\" \ -DLINPHONE_PLUGINS_DIR=\"\\tmp\" \ diff --git a/configure.ac b/configure.ac index b4259e1d9..71f0abd60 100644 --- a/configure.ac +++ b/configure.ac @@ -502,7 +502,7 @@ AS_CASE($enable_external_mediastreamer, AC_CONFIG_SUBDIRS( mediastreamer2 ) MEDIASTREAMER_DIR=${top_srcdir}/mediastreamer2 MEDIASTREAMER_CFLAGS="-I\$(top_srcdir)/mediastreamer2/include" - MEDIASTREAMER_LIBS="\$(top_builddir)/mediastreamer2/src/libmediastreamer.la" + MEDIASTREAMER_LIBS="\$(top_builddir)/mediastreamer2/src/libmediastreamer_base.la \$(top_builddir)/mediastreamer2/src/libmediastreamer_voip.la" dnl need to temporary change quotes to allow square brackets changequote(<<, >>) MS2_VERSION=`grep -e '^.C_INIT(' $MEDIASTREAMER_DIR/configure.ac | sed -e 's:\([^(]\+\)(\[mediastreamer\],\[\(.*\)\]):\2:g'` diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index 161aaab24..14ca748e1 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -732,9 +732,12 @@ static void refer_received(Sal *sal, SalOp *op, const char *referto){ static void text_received(Sal *sal, const char *from, const char *msg){ LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal); - linphone_core_text_received(lc,from,msg); + linphone_core_message_received(lc,from,msg,NULL); +} +void message_external_body_received(Sal *sal, const char *from, const char *url) { + LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal); + linphone_core_message_received(lc,from,NULL,url); } - static void notify(SalOp *op, const char *from, const char *msg){ LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op)); LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer (op); @@ -801,6 +804,28 @@ static void notify_refer(SalOp *op, SalReferStatus status){ } } +static LinphoneChatMessageState chatStatusSal2Linphone(SalTextDeliveryStatus status){ + switch(status){ + case SalTextDeliveryInProgress: + return LinphoneChatMessageStateInProgress; + case SalTextDeliveryDone: + return LinphoneChatMessageStateDelivered; + case SalTextDeliveryFailed: + return LinphoneChatMessageStateNotDelivered; + } + return LinphoneChatMessageStateIdle; +} + +static void text_delivery_update(SalOp *op, SalTextDeliveryStatus status){ + LinphoneChatMessage *chat_msg=(LinphoneChatMessage* )sal_op_get_user_pointer(op); + if (chat_msg && chat_msg->cb) { + chat_msg->cb(chat_msg + ,chatStatusSal2Linphone(status) + ,chat_msg->cb_ud); + } + linphone_chat_message_destroy(chat_msg); +} + SalCallbacks linphone_sal_callbacks={ call_received, call_ringing, @@ -818,12 +843,14 @@ SalCallbacks linphone_sal_callbacks={ dtmf_received, refer_received, text_received, + message_external_body_received, + text_delivery_update, notify, notify_presence, notify_refer, subscribe_received, subscribe_closed, - ping_reply + ping_reply, }; diff --git a/coreapi/chat.c b/coreapi/chat.c index 3d336dbcd..941cce423 100644 --- a/coreapi/chat.c +++ b/coreapi/chat.c @@ -55,6 +55,7 @@ static void _linphone_chat_room_send_message(LinphoneChatRoom *cr, LinphoneChatM const char *identity=linphone_core_find_best_identity(cr->lc,cr->peer_url,&route); SalOp *op=NULL; LinphoneCall *call; + char* content_type; if((call = linphone_core_get_call_by_remote_address(cr->lc,cr->peer))!=NULL){ if (call->state==LinphoneCallConnected || call->state==LinphoneCallStreamsRunning || @@ -77,7 +78,15 @@ static void _linphone_chat_room_send_message(LinphoneChatRoom *cr, LinphoneChatM cr->op=op; sal_op_set_user_pointer(op, msg); /*if out of call, directly store msg*/ } - sal_text_send(op,identity,cr->peer,msg->message); + if (msg->external_body_url) { + content_type=ms_strdup_printf("message/external-body; access-type=URL; URL=\"%s\"",msg->external_body_url); + sal_message_send(op,identity,cr->peer,content_type,NULL); + ms_free(content_type); + } else { + sal_text_send(op, identity, cr->peer, msg->message); + } + + } void linphone_chat_room_send_message(LinphoneChatRoom *cr, const char *msg) { @@ -89,16 +98,20 @@ bool_t linphone_chat_room_matches(LinphoneChatRoom *cr, const LinphoneAddress *f return FALSE; } -void linphone_chat_room_text_received(LinphoneChatRoom *cr, LinphoneCore *lc, const LinphoneAddress *from, const char *msg){ - if (lc->vtable.text_received!=NULL) lc->vtable.text_received(lc, cr, from, msg); +void linphone_chat_room_message_received(LinphoneChatRoom *cr, LinphoneCore *lc, LinphoneChatMessage *msg){ + if (msg->message) + //legacy API + if (lc->vtable.text_received!=NULL) lc->vtable.text_received(lc, cr, msg->from, msg->message); + if (lc->vtable.message_received!=NULL) lc->vtable.message_received(lc, cr,msg); + } -void linphone_core_text_received(LinphoneCore *lc, const char *from, const char *msg){ +void linphone_core_message_received(LinphoneCore *lc, const char *from, const char *raw_msg,const char* external_url){ MSList *elem; LinphoneChatRoom *cr=NULL; LinphoneAddress *addr; char *cleanfrom; - + LinphoneChatMessage* msg; addr=linphone_address_new(from); linphone_address_clean(addr); for(elem=lc->chatrooms;elem!=NULL;elem=ms_list_next(elem)){ @@ -113,12 +126,23 @@ void linphone_core_text_received(LinphoneCore *lc, const char *from, const char /* create a new chat room */ cr=linphone_core_create_chat_room(lc,cleanfrom); } - + msg = linphone_chat_room_create_message(cr, raw_msg); + linphone_chat_message_set_from(msg, cr->peer_url); + if (external_url) { + linphone_chat_message_set_external_body_url(msg, external_url); + } linphone_address_destroy(addr); - linphone_chat_room_text_received(cr,lc,cr->peer_url,msg); + linphone_chat_room_message_received(cr,lc,msg); ms_free(cleanfrom); } +LinphoneCore* linphone_chat_room_get_lc(LinphoneChatRoom *cr){ + return cr->lc; +} + +LinphoneChatRoom* linphone_chat_message_get_chat_room(LinphoneChatMessage *msg){ + return msg->chat_room; +} void linphone_chat_room_set_user_data(LinphoneChatRoom *cr, void * ud){ cr->user_data=ud; @@ -133,13 +157,17 @@ const LinphoneAddress* linphone_chat_room_get_peer_address(LinphoneChatRoom *cr) LinphoneChatMessage* linphone_chat_room_create_message(const LinphoneChatRoom *cr,const char* message) { LinphoneChatMessage* msg = ms_new0(LinphoneChatMessage,1); msg->chat_room=(LinphoneChatRoom*)cr; - msg->message=ms_strdup(message); + msg->message=message?ms_strdup(message):NULL; return msg; } + void linphone_chat_message_destroy(LinphoneChatMessage* msg) { - if (msg->message) ms_free((void*)msg->message); - ms_free((void*)msg); + if (msg->message) ms_free(msg->message); + if (msg->external_body_url) ms_free(msg->external_body_url); + if (msg->from) linphone_address_destroy(msg->from); + ms_free(msg); } + void linphone_chat_room_send_message2(LinphoneChatRoom *cr, LinphoneChatMessage* msg,LinphoneChatMessageStateChangeCb status_cb,void* ud) { msg->cb=status_cb; msg->cb_ud=ud; @@ -156,6 +184,15 @@ const char* linphone_chat_message_state_to_string(const LinphoneChatMessageState } } + +char* linphone_chat_message_get_message(LinphoneChatMessage* msg) { + return msg->message; +} + +const LinphoneAddress* linphone_chat_message_get_peer_address(LinphoneChatMessage *msg) { + return linphone_chat_room_get_peer_address(msg->chat_room); +} + /** * user pointer set function */ @@ -167,4 +204,45 @@ void linphone_chat_message_set_user_data(LinphoneChatMessage* message,void* ud) */ void* linphone_chat_message_get_user_data(const LinphoneChatMessage* message) { return message->message_userdata; +} + +const char* linphone_chat_message_get_external_body_url(const LinphoneChatMessage* message) { + return message->external_body_url; +} + +void linphone_chat_message_set_external_body_url(LinphoneChatMessage* message,const char* url) { + if (message->external_body_url) { + ms_free(message->external_body_url); + } + message->external_body_url=url?ms_strdup(url):NULL; +} +void linphone_chat_message_set_from(LinphoneChatMessage* message, const LinphoneAddress* from) { + if(message->from) linphone_address_destroy(message->from); + message->from=linphone_address_clone(from); + +} +LinphoneAddress* linphone_chat_message_get_from(const LinphoneChatMessage* message) { + return message->from; +} +const char * linphone_chat_message_get_text(const LinphoneChatMessage* message) { + return message->message; +} +LinphoneChatMessage* linphone_chat_message_clone(const LinphoneChatMessage* msg) { + /*struct _LinphoneChatMessage { + char* message; + LinphoneChatRoom* chat_room; + LinphoneChatMessageStateChangeCb cb; + void* cb_ud; + void* message_userdata; + char* external_body_url; + LinphoneAddress* from; + };*/ + LinphoneChatMessage* new_message = linphone_chat_room_create_message(msg->chat_room,msg->message); + if (msg->external_body_url) new_message->external_body_url=ms_strdup(msg->external_body_url); + new_message->cb=msg->cb; + new_message->cb_ud=msg->cb_ud; + new_message->message_userdata=msg->message_userdata; + new_message->cb=msg->cb; + if (msg->from) new_message->from=linphone_address_clone(msg->from); + return new_message; } \ No newline at end of file diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 929814b52..9243be084 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -207,7 +207,10 @@ static SalMediaDescription *_create_local_media_description(LinphoneCore *lc, Li md->nstreams=1; strncpy(md->addr,call->localip,sizeof(md->addr)); strncpy(md->username,username,sizeof(md->username)); - md->bandwidth=linphone_core_get_download_bandwidth(lc); + + if (call->params.down_bw) + md->bandwidth=call->params.down_bw; + else md->bandwidth=linphone_core_get_download_bandwidth(lc); /*set audio capabilities */ strncpy(md->streams[0].rtp_addr,call->localip,sizeof(md->streams[0].rtp_addr)); @@ -217,7 +220,10 @@ static SalMediaDescription *_create_local_media_description(LinphoneCore *lc, Li md->streams[0].proto=(call->params.media_encryption == LinphoneMediaEncryptionSRTP) ? SalProtoRtpSavp : SalProtoRtpAvp; md->streams[0].type=SalAudio; - md->streams[0].ptime=lc->net_conf.down_ptime; + if (call->params.down_ptime) + md->streams[0].ptime=call->params.down_ptime; + else + md->streams[0].ptime=linphone_core_get_download_ptime(lc); l=make_codec_list(lc,lc->codecs_conf.audio_codecs,call->params.audio_bw,&md->streams[0].max_rate); pt=payload_type_clone(rtp_profile_get_payload_from_mime(&av_profile,"telephone-event")); l=ms_list_append(l,pt); @@ -318,6 +324,22 @@ void linphone_call_init_stats(LinphoneCallStats *stats, int type) { stats->type = type; stats->received_rtcp = NULL; stats->sent_rtcp = NULL; + stats->ice_state = LinphoneIceStateNotActivated; +} + +static void update_media_description_from_stun(SalMediaDescription *md, const StunCandidate *ac, const StunCandidate *vc){ + if (ac->port!=0){ + strcpy(md->streams[0].rtp_addr,ac->addr); + md->streams[0].rtp_port=ac->port; + if ((ac->addr[0]!='\0' && vc->addr[0]!='\0' && strcmp(ac->addr,vc->addr)==0) || md->nstreams==1){ + strcpy(md->addr,ac->addr); + } + } + if (vc->port!=0){ + strcpy(md->streams[1].rtp_addr,vc->addr); + md->streams[1].rtp_port=vc->port; + } + } static void discover_mtu(LinphoneCore *lc, const char *remote){ @@ -333,9 +355,13 @@ static void discover_mtu(LinphoneCore *lc, const char *remote){ } } +#define STUN_CANDIDATE_INIT {{0},0} + LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, LinphoneAddress *from, LinphoneAddress *to, const LinphoneCallParams *params) { LinphoneCall *call=ms_new0(LinphoneCall,1); + StunCandidate ac=STUN_CANDIDATE_INIT,vc=STUN_CANDIDATE_INIT; + int ping_time=-1; call->dir=LinphoneCallOutgoing; call->op=sal_op_new(lc->sal); sal_op_set_user_pointer(call->op,call); @@ -347,11 +373,16 @@ LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, LinphoneAddr call->ice_session = ice_session_new(); ice_session_set_role(call->ice_session, IR_Controlling); } - call->localdesc=create_local_media_description (lc,call); - call->camera_active=params->has_video; if (linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseStun) { - linphone_core_run_stun_tests(call->core,call); + ping_time=linphone_core_run_stun_tests(call->core,call,&ac, &vc); } + if (ping_time>=0) { + linphone_core_adapt_to_network(lc,ping_time,&call->params); + } + call->localdesc=create_local_media_description(lc,call); + update_media_description_from_stun(call->localdesc,&ac,&vc); + call->camera_active=params->has_video; + discover_mtu(lc,linphone_address_get_domain (to)); if (params->referer){ sal_call_set_referer(call->op,params->referer->op); @@ -363,6 +394,8 @@ LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, LinphoneAddr LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *from, LinphoneAddress *to, SalOp *op){ LinphoneCall *call=ms_new0(LinphoneCall,1); char *from_str; + int ping_time=-1; + StunCandidate ac=STUN_CANDIDATE_INIT,vc=STUN_CANDIDATE_INIT; call->dir=LinphoneCallIncoming; sal_op_set_user_pointer(op,call); @@ -385,8 +418,6 @@ LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *fro linphone_call_init_common(call, from, to); linphone_core_init_default_params(lc, &call->params); call->params.has_video &= !!lc->video_policy.automatically_accept; - call->localdesc=create_local_media_description (lc,call); - call->camera_active=call->params.has_video; switch (linphone_core_get_firewall_policy(call->core)) { case LinphonePolicyUseIce: call->ice_session = ice_session_new(); @@ -403,11 +434,18 @@ LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *fro } break; case LinphonePolicyUseStun: - linphone_core_run_stun_tests(call->core,call); + ping_time=linphone_core_run_stun_tests(call->core,call,&ac, &vc); /* No break to also destroy ice session in this case. */ default: break; } + if (ping_time>=0) { + linphone_core_adapt_to_network(lc,ping_time,&call->params); + }; + call->localdesc=create_local_media_description(lc,call); + update_media_description_from_stun(call->localdesc,&ac,&vc); + call->camera_active=call->params.has_video; + discover_mtu(lc,linphone_address_get_domain(from)); return call; } @@ -521,7 +559,7 @@ void linphone_call_set_state(LinphoneCall *call, LinphoneCallState cstate, const switch(call->reason){ case LinphoneReasonDeclined: call->log->status=LinphoneCallDeclined; - break; + break; case LinphoneReasonNotAnswered: call->log->status=LinphoneCallMissed; break; @@ -936,11 +974,10 @@ void linphone_call_set_next_video_frame_decoded_callback(LinphoneCall *call, Lin void linphone_call_init_audio_stream(LinphoneCall *call){ LinphoneCore *lc=call->core; - SalMediaDescription *md=call->localdesc; AudioStream *audiostream; - int dscp=lp_config_get_int(lc->config,"rtp","audio_dscp",-1); + int dscp=linphone_core_get_audio_dscp(lc); - call->audiostream=audiostream=audio_stream_new(md->streams[0].rtp_port,md->streams[0].rtcp_port,linphone_core_ipv6_enabled(lc)); + call->audiostream=audiostream=audio_stream_new(call->audio_port,call->audio_port+1,linphone_core_ipv6_enabled(lc)); if (dscp!=-1) audio_stream_set_dscp(audiostream,dscp); if (linphone_core_echo_limiter_enabled(lc)){ @@ -989,13 +1026,12 @@ void linphone_call_init_audio_stream(LinphoneCall *call){ void linphone_call_init_video_stream(LinphoneCall *call){ #ifdef VIDEO_ENABLED LinphoneCore *lc=call->core; - SalMediaDescription *md=call->localdesc; - if ((lc->video_conf.display || lc->video_conf.capture) && md->streams[1].rtp_port>0){ + if ((lc->video_conf.display || lc->video_conf.capture) && call->params.has_video){ int video_recv_buf_size=lp_config_get_int(lc->config,"video","recv_buf_size",0); - int dscp=lp_config_get_int(lc->config,"rtp","video_dscp",-1); + int dscp=linphone_core_get_video_dscp(lc); - call->videostream=video_stream_new(md->streams[1].rtp_port,md->streams[1].rtcp_port,linphone_core_ipv6_enabled(lc)); + call->videostream=video_stream_new(call->video_port,call->video_port+1,linphone_core_ipv6_enabled(lc)); if (dscp!=-1) video_stream_set_dscp(call->videostream,dscp); video_stream_enable_display_filter_auto_rotate(call->videostream, lp_config_get_int(lc->config,"video","display_filter_auto_rotate",0)); @@ -1137,6 +1173,7 @@ static RtpProfile *make_profile(LinphoneCall *call, const SalMediaDescription *m int remote_bw=0; LinphoneCore *lc=call->core; int up_ptime=0; + const LinphoneCallParams *params=&call->params; *used_pt=-1; for(elem=desc->payloads;elem!=NULL;elem=elem->next){ @@ -1146,7 +1183,9 @@ static RtpProfile *make_profile(LinphoneCall *call, const SalMediaDescription *m if ((pt->flags & PAYLOAD_TYPE_FLAG_CAN_SEND) && first) { if (desc->type==SalAudio){ linphone_core_update_allocated_audio_bandwidth_in_call(call,pt); - up_ptime=linphone_core_get_upload_ptime(lc); + if (params->up_ptime) + up_ptime=params->up_ptime; + else up_ptime=linphone_core_get_upload_ptime(lc); } *used_pt=payload_type_get_number(pt); first=FALSE; @@ -1161,7 +1200,12 @@ static RtpProfile *make_profile(LinphoneCall *call, const SalMediaDescription *m } if (desc->type==SalAudio){ - bw=get_min_bandwidth(call->audio_bw,remote_bw); + int audio_bw=call->audio_bw; + if (params->up_bw){ + if (params->up_bw< audio_bw) + audio_bw=params->up_bw; + } + bw=get_min_bandwidth(audio_bw,remote_bw); }else bw=get_min_bandwidth(get_video_bandwidth(linphone_core_get_upload_bandwidth (lc),call->audio_bw),remote_bw); if (bw>0) pt->normal_bitrate=bw*1000; else if (desc->type==SalAudio){ @@ -1498,6 +1542,8 @@ void linphone_call_delete_ice_session(LinphoneCall *call){ call->ice_session = NULL; if (call->audiostream != NULL) call->audiostream->ice_check_list = NULL; if (call->videostream != NULL) call->videostream->ice_check_list = NULL; + call->stats[LINPHONE_CALL_STATS_AUDIO].ice_state = LinphoneIceStateNotActivated; + call->stats[LINPHONE_CALL_STATS_VIDEO].ice_state = LinphoneIceStateNotActivated; } } @@ -1723,6 +1769,7 @@ static void handle_ice_events(LinphoneCall *call, OrtpEvent *ev){ if (ice_session_role(call->ice_session) == IR_Controlling) { ice_session_select_candidates(call->ice_session); linphone_core_update_call(call->core, call, &call->current_params); + linphone_core_update_ice_state_in_call_stats(call); } break; case IS_Failed: @@ -1731,6 +1778,7 @@ static void handle_ice_events(LinphoneCall *call, OrtpEvent *ev){ /* At least one ICE session has succeeded, so perform a call update. */ ice_session_select_candidates(call->ice_session); linphone_core_update_call(call->core, call, &call->current_params); + linphone_core_update_ice_state_in_call_stats(call); } } break; @@ -1738,11 +1786,17 @@ static void handle_ice_events(LinphoneCall *call, OrtpEvent *ev){ break; } } else if (evt == ORTP_EVENT_ICE_GATHERING_FINISHED) { + int ping_time = -1; if (evd->info.ice_processing_successful==TRUE) { ice_session_compute_candidates_foundations(call->ice_session); ice_session_eliminate_redundant_candidates(call->ice_session); ice_session_choose_default_candidates(call->ice_session); + ping_time = ice_session_gathering_duration(call->ice_session); + if (ping_time >=0) { + ping_time /= ice_session_nb_check_lists(call->ice_session); + } } else { + ms_warning("No STUN answer from [%s], disabling ICE",linphone_core_get_stun_server(call->core)); linphone_call_delete_ice_session(call); } switch (call->state) { @@ -1753,10 +1807,16 @@ static void handle_ice_events(LinphoneCall *call, OrtpEvent *ev){ linphone_core_start_accept_call_update(call->core, call); break; case LinphoneCallOutgoingInit: + if (ping_time >= 0) { + linphone_core_adapt_to_network(call->core, ping_time, &call->params); + } linphone_call_stop_media_streams(call); linphone_core_proceed_with_invite_if_ready(call->core, call, NULL); break; default: + if (ping_time >= 0) { + linphone_core_adapt_to_network(call->core, ping_time, &call->params); + } linphone_call_stop_media_streams(call); linphone_core_notify_incoming_call(call->core, call); break; diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 47f8a61ae..152ccf80c 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -615,6 +615,7 @@ static void sip_config_read(LinphoneCore *lc) sal_set_keepalive_period(lc->sal,lc->sip_conf.keepalive_period); sal_use_one_matching_codec_policy(lc->sal,lp_config_get_int(lc->config,"sip","only_one_codec",0)); sal_use_double_registrations(lc->sal,lp_config_get_int(lc->config,"sip","use_double_registrations",1)); + sal_set_dscp(lc->sal,linphone_core_get_sip_dscp(lc)); } static void rtp_config_read(LinphoneCore *lc) @@ -967,14 +968,14 @@ int linphone_core_get_upload_bandwidth(const LinphoneCore *lc){ * Set audio packetization time linphone expects to receive from peer */ void linphone_core_set_download_ptime(LinphoneCore *lc, int ptime) { - lc->net_conf.down_ptime=ptime; + lp_config_set_int(lc->config,"rtp","download_ptime",ptime); } /** * Get audio packetization time linphone expects to receive from peer */ int linphone_core_get_download_ptime(LinphoneCore *lc) { - return lc->net_conf.down_ptime; + return lp_config_get_int(lc->config,"rtp","download_ptime",0); } /** @@ -1903,7 +1904,8 @@ void linphone_core_iterate(LinphoneCore *lc){ if (call->state==LinphoneCallOutgoingInit && (curtime-call->start_time>=2)){ /*start the call even if the OPTIONS reply did not arrive*/ if (call->ice_session != NULL) { - /* ICE candidates gathering has not finished yet, proceed with the call without ICE anyway. */ + ms_warning("ICE candidates gathering from [%s] has not finished yet, proceed with the call without ICE anyway." + ,linphone_core_get_stun_server(lc)); linphone_call_delete_ice_session(call); linphone_call_stop_media_streams(call); } @@ -3650,6 +3652,8 @@ void linphone_core_set_stun_server(LinphoneCore *lc, const char *server){ if (server) lc->net_conf.stun_server=ms_strdup(server); else lc->net_conf.stun_server=NULL; + if (linphone_core_ready(lc)) + lp_config_set_string(lc->config,"net","stun_server",lc->net_conf.stun_server); } const char * linphone_core_get_stun_server(const LinphoneCore *lc){ @@ -3714,6 +3718,8 @@ const char *linphone_core_get_nat_address_resolved(LinphoneCore *lc) void linphone_core_set_firewall_policy(LinphoneCore *lc, LinphoneFirewallPolicy pol){ lc->net_conf.firewall_policy=pol; if (lc->sip_conf.contact) update_primary_contact(lc); + if (linphone_core_ready(lc)) + lp_config_set_int(lc->config,"net","firewall_policy",pol); } LinphoneFirewallPolicy linphone_core_get_firewall_policy(const LinphoneCore *lc){ @@ -3866,6 +3872,8 @@ const LinphoneVideoPolicy *linphone_core_get_video_policy(LinphoneCore *lc){ **/ void linphone_core_enable_video_preview(LinphoneCore *lc, bool_t val){ lc->video_conf.show_local=val; + if (linphone_core_ready(lc)) + lp_config_set_int(lc->config,"video","show_local",val); } /** @@ -3891,6 +3899,9 @@ void linphone_core_enable_self_view(LinphoneCore *lc, bool_t val){ if (call && call->videostream){ video_stream_enable_self_view(call->videostream,val); } + if (linphone_core_ready(lc)){ + lp_config_set_int(lc->config,"video","self_view",val); + } #endif } @@ -4447,7 +4458,6 @@ void net_config_uninit(LinphoneCore *lc) net_config_t *config=&lc->net_conf; if (config->stun_server!=NULL){ - lp_config_set_string(lc->config,"net","stun_server",config->stun_server); ms_free(lc->net_conf.stun_server); } if (config->nat_address!=NULL){ @@ -4457,7 +4467,6 @@ void net_config_uninit(LinphoneCore *lc) if (lc->net_conf.nat_address_ip !=NULL){ ms_free(lc->net_conf.nat_address_ip); } - lp_config_set_int(lc->config,"net","firewall_policy",config->firewall_policy); lp_config_set_int(lc->config,"net","mtu",config->mtu); } @@ -4525,7 +4534,7 @@ void rtp_config_uninit(LinphoneCore *lc) lp_config_set_int(lc->config,"rtp","video_jitt_comp_enabled",config->video_adaptive_jitt_comp_enabled); } -void sound_config_uninit(LinphoneCore *lc) +static void sound_config_uninit(LinphoneCore *lc) { sound_config_t *config=&lc->sound_conf; ms_free(config->cards); @@ -4537,13 +4546,11 @@ void sound_config_uninit(LinphoneCore *lc) ms_snd_card_manager_destroy(); } -void video_config_uninit(LinphoneCore *lc) +static void video_config_uninit(LinphoneCore *lc) { lp_config_set_string(lc->config,"video","size",video_size_get_name(linphone_core_get_preferred_video_size(lc))); lp_config_set_int(lc->config,"video","display",lc->video_conf.display); lp_config_set_int(lc->config,"video","capture",lc->video_conf.capture); - lp_config_set_int(lc->config,"video","show_local",linphone_core_video_preview_enabled(lc)); - lp_config_set_int(lc->config,"video","self_view",linphone_core_self_view_enabled(lc)); if (lc->video_conf.cams) ms_free(lc->video_conf.cams); } @@ -5104,3 +5111,81 @@ void linphone_call_zoom_video(LinphoneCall* call, float zoom_factor, float* cx, }else ms_warning("Could not apply zoom: video output wasn't activated."); } +void linphone_core_set_device_identifier(LinphoneCore *lc,const char* device_id) { + if (lc->device_id) ms_free(lc->device_id); + lc->device_id=ms_strdup(device_id); +} +const char* linphone_core_get_device_identifier(const LinphoneCore *lc) { + return lc->device_id; +} + +/** + * Set the DSCP field for SIP signaling channel. + * + * @ingroup network_parameters + * * The DSCP defines the quality of service in IP packets. + * +**/ +void linphone_core_set_sip_dscp(LinphoneCore *lc, int dscp){ + sal_set_dscp(lc->sal,dscp); + if (linphone_core_ready(lc)) + lp_config_set_int_hex(lc->config,"sip","dscp",dscp); +} + +/** + * Get the DSCP field for SIP signaling channel. + * + * @ingroup network_parameters + * * The DSCP defines the quality of service in IP packets. + * +**/ +int linphone_core_get_sip_dscp(const LinphoneCore *lc){ + return lp_config_get_int(lc->config,"sip","dscp",0x1a); +} + +/** + * Set the DSCP field for outgoing audio streams. + * + * @ingroup network_parameters + * The DSCP defines the quality of service in IP packets. + * +**/ +void linphone_core_set_audio_dscp(LinphoneCore *lc, int dscp){ + if (linphone_core_ready(lc)) + lp_config_set_int_hex(lc->config,"rtp","audio_dscp",dscp); +} + +/** + * Get the DSCP field for outgoing audio streams. + * + * @ingroup network_parameters + * The DSCP defines the quality of service in IP packets. + * +**/ +int linphone_core_get_audio_dscp(const LinphoneCore *lc){ + return lp_config_get_int(lc->config,"rtp","audio_dscp",0x2e); +} + +/** + * Set the DSCP field for outgoing video streams. + * + * @ingroup network_parameters + * The DSCP defines the quality of service in IP packets. + * +**/ +void linphone_core_set_video_dscp(LinphoneCore *lc, int dscp){ + if (linphone_core_ready(lc)) + lp_config_set_int_hex(lc->config,"rtp","video_dscp",dscp); + +} + +/** + * Get the DSCP field for outgoing video streams. + * + * @ingroup network_parameters + * The DSCP defines the quality of service in IP packets. + * +**/ +int linphone_core_get_video_dscp(const LinphoneCore *lc){ + return lp_config_get_int(lc->config,"rtp","video_dscp",0x2e); +} diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 2972bc090..acf81f1df 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -261,6 +261,24 @@ typedef struct _LinphoneCall LinphoneCall; #define LINPHONE_CALL_STATS_AUDIO 0 #define LINPHONE_CALL_STATS_VIDEO 1 +/** + * Enum describing ICE states. + * @ingroup initializing +**/ +enum _LinphoneIceState{ + LinphoneIceStateNotActivated, /**< ICE has not been activated for this call */ + LinphoneIceStateInProgress, /**< ICE process is in progress */ + LinphoneIceStateHostConnection, /**< ICE has established a direct connection to the remote host */ + LinphoneIceStateReflexiveConnection, /**< ICE has established a connection to the remote host through one or several NATs */ + LinphoneIceStateRelayConnection /**< ICE has established a connection through a relay */ +}; + +/** + * Enum describing Ice states. + * @ingroup initializing +**/ +typedef enum _LinphoneIceState LinphoneIceState; + /** * The LinphoneCallStats objects carries various statistic informations regarding quality of audio or video streams. * @@ -285,6 +303,7 @@ struct _LinphoneCallStats { mblk_t* received_rtcp; /** A text message has been received */ + MessageReceived message_received; /** a message is received, can be text or external body*/ DtmfReceived dtmf_received; /**< A dtmf has been received received */ ReferReceived refer_received; /**< An out of call refer was received */ CallEncryptionChangedCb call_encryption_changed; /**NewGlobalRef(env->FindClass("org/linphone/core/LinphoneCall$State")); callStateFromIntId = env->GetStaticMethodID(callStateClass,"fromInt","(I)Lorg/linphone/core/LinphoneCall$State;"); + chatMessageStateClass = (jclass)env->NewGlobalRef(env->FindClass("org/linphone/core/LinphoneChatMessage$State")); + chatMessageStateFromIntId = env->GetStaticMethodID(chatMessageStateClass,"fromInt","(I)Lorg/linphone/core/LinphoneChatMessage$State;"); + /*callEncryption(LinphoneCore lc, LinphoneCall call, boolean encrypted,String auth_token);*/ callEncryptionChangedId=env->GetMethodID(listenerClass,"callEncryptionChanged","(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneCall;ZLjava/lang/String;)V"); @@ -148,6 +152,7 @@ public: /*void textReceived(LinphoneCore lc, LinphoneChatRoom cr,LinphoneAddress from,String message);*/ textReceivedId = env->GetMethodID(listenerClass,"textReceived","(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneChatRoom;Lorg/linphone/core/LinphoneAddress;Ljava/lang/String;)V"); + messageReceivedId = env->GetMethodID(listenerClass,"messageReceived","(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneChatRoom;Lorg/linphone/core/LinphoneAddress;Lorg/linphone/core/LinphoneChatMessage;)V"); proxyClass = (jclass)env->NewGlobalRef(env->FindClass("org/linphone/core/LinphoneProxyConfigImpl")); proxyCtrId = env->GetMethodID(proxyClass,"", "(J)V"); @@ -155,6 +160,9 @@ public: callClass = (jclass)env->NewGlobalRef(env->FindClass("org/linphone/core/LinphoneCallImpl")); callCtrId = env->GetMethodID(callClass,"", "(J)V"); + chatMessageClass = (jclass)env->NewGlobalRef(env->FindClass("org/linphone/core/LinphoneChatMessageImpl")); + chatMessageCtrId = env->GetMethodID(chatMessageClass,"", "(J)V"); + chatRoomClass = (jclass)env->NewGlobalRef(env->FindClass("org/linphone/core/LinphoneChatRoomImpl")); chatRoomCtrId = env->GetMethodID(chatRoomClass,"", "(J)V"); @@ -176,8 +184,10 @@ public: env->DeleteGlobalRef(globalStateClass); env->DeleteGlobalRef(registrationStateClass); env->DeleteGlobalRef(callStateClass); + env->DeleteGlobalRef(chatMessageStateClass); env->DeleteGlobalRef(proxyClass); env->DeleteGlobalRef(callClass); + env->DeleteGlobalRef(chatMessageClass); env->DeleteGlobalRef(chatRoomClass); env->DeleteGlobalRef(friendClass); @@ -191,6 +201,7 @@ public: jmethodID newSubscriptionRequestId; jmethodID notifyPresenceReceivedId; jmethodID textReceivedId; + jmethodID messageReceivedId; jclass globalStateClass; jmethodID globalStateId; @@ -204,6 +215,9 @@ public: jmethodID callStateId; jmethodID callStateFromIntId; + jclass chatMessageStateClass; + jmethodID chatMessageStateFromIntId; + jmethodID callEncryptionChangedId; jclass ecCalibratorStatusClass; @@ -216,6 +230,9 @@ public: jclass callClass; jmethodID callCtrId; + jclass chatMessageClass; + jmethodID chatMessageCtrId; + jclass chatRoomClass; jmethodID chatRoomCtrId; @@ -373,6 +390,21 @@ public: ,env->NewObject(lcData->addressClass,lcData->addressCtrId,(jlong)from) ,message ? env->NewStringUTF(message) : NULL); } + static void message_received(LinphoneCore *lc, LinphoneChatRoom *room, LinphoneChatMessage *msg) { + JNIEnv *env = 0; + jint result = jvm->AttachCurrentThread(&env,NULL); + if (result != 0) { + ms_error("cannot attach VM\n"); + return; + } + LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_get_user_data(lc); + env->CallVoidMethod(lcData->listener + ,lcData->messageReceivedId + ,lcData->core + ,env->NewObject(lcData->chatRoomClass,lcData->chatRoomCtrId,(jlong)room) + ,env->NewObject(lcData->addressClass,lcData->addressCtrId,(jlong)msg->from) + ,env->NewObject(lcData->chatMessageClass,lcData->chatMessageCtrId,(jlong)msg)); + } static void ecCalibrationStatus(LinphoneCore *lc, LinphoneEcCalibratorStatus status, int delay_ms, void *data) { JNIEnv *env = 0; jint result = jvm->AttachCurrentThread(&env,NULL); @@ -955,6 +987,11 @@ extern "C" jstring Java_org_linphone_core_LinphoneProxyConfigImpl_getProxy(JNIEn return NULL; } } +extern "C" void Java_org_linphone_core_LinphoneProxyConfigImpl_setContactParameters(JNIEnv* env,jobject thiz,jlong proxyCfg,jstring jparams) { + const char* params = env->GetStringUTFChars(jparams, NULL); + linphone_proxy_config_set_contact_parameters((LinphoneProxyConfig*)proxyCfg, params); + env->ReleaseStringUTFChars(jparams, params); +} extern "C" int Java_org_linphone_core_LinphoneProxyConfigImpl_setRoute(JNIEnv* env,jobject thiz,jlong proxyCfg,jstring jroute) { if (jroute != NULL) { const char* route = env->GetStringUTFChars(jroute, NULL); @@ -1353,16 +1390,88 @@ extern "C" long Java_org_linphone_core_LinphoneChatRoomImpl_getPeerAddress(JNIEn ,jlong ptr) { return (long) linphone_chat_room_get_peer_address((LinphoneChatRoom*)ptr); } +extern "C" jlong Java_org_linphone_core_LinphoneChatRoomImpl_createLinphoneChatMessage(JNIEnv* env + ,jobject thiz + ,jlong ptr + ,jstring jmessage) { + const char* message = env->GetStringUTFChars(jmessage, NULL); + LinphoneChatMessage *chatMessage = linphone_chat_room_create_message((LinphoneChatRoom *)ptr, message); + env->ReleaseStringUTFChars(jmessage, message); + + return (jlong) chatMessage; +} +extern "C" void Java_org_linphone_core_LinphoneChatMessageImpl_setUserData(JNIEnv* env + ,jobject thiz + ,jlong ptr) { + jobject ud = env->NewGlobalRef(thiz); + linphone_chat_message_set_user_data((LinphoneChatMessage*)ptr,(void*) ud); +} +extern "C" jstring Java_org_linphone_core_LinphoneChatMessageImpl_getMessage(JNIEnv* env + ,jobject thiz + ,jlong ptr) { + jstring jvalue =env->NewStringUTF(linphone_chat_message_get_message((LinphoneChatMessage*)ptr)); + return jvalue; +} +extern "C" jstring Java_org_linphone_core_LinphoneChatMessageImpl_getExternalBodyUrl(JNIEnv* env + ,jobject thiz + ,jlong ptr) { + jstring jvalue =env->NewStringUTF(linphone_chat_message_get_external_body_url((LinphoneChatMessage*)ptr)); + return jvalue; +} +extern "C" void Java_org_linphone_core_LinphoneChatMessageImpl_setExternalBodyUrl(JNIEnv* env + ,jobject thiz + ,jlong ptr + ,jstring jurl) { + const char* url = env->GetStringUTFChars(jurl, NULL); + linphone_chat_message_set_external_body_url((LinphoneChatMessage *)ptr, url); + env->ReleaseStringUTFChars(jurl, url); +} +extern "C" long Java_org_linphone_core_LinphoneChatMessageImpl_getPeerAddress(JNIEnv* env + ,jobject thiz + ,jlong ptr) { + return (long) linphone_chat_message_get_peer_address((LinphoneChatMessage*)ptr); +} extern "C" void Java_org_linphone_core_LinphoneChatRoomImpl_sendMessage(JNIEnv* env ,jobject thiz ,jlong ptr ,jstring jmessage) { const char* message = env->GetStringUTFChars(jmessage, NULL); - linphone_chat_room_send_message((LinphoneChatRoom*)ptr,message); + linphone_chat_room_send_message((LinphoneChatRoom*)ptr, message); env->ReleaseStringUTFChars(jmessage, message); - } +static void chat_room_impl_callback(LinphoneChatMessage* msg, LinphoneChatMessageState state, void* ud) { + JNIEnv *env = 0; + jint result = jvm->AttachCurrentThread(&env,NULL); + if (result != 0) { + ms_error("cannot attach VM\n"); + return; + } + + jobject listener = (jobject) ud; + jclass clazz = (jclass) env->GetObjectClass(listener); + jmethodID method = env->GetMethodID(clazz, "onLinphoneChatMessageStateChanged","(Lorg/linphone/core/LinphoneChatMessage;Lorg/linphone/core/LinphoneChatMessage$State;)V"); + + LinphoneCore *lc = linphone_chat_room_get_lc(linphone_chat_message_get_chat_room(msg)); + LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_get_user_data(lc); + env->CallVoidMethod( + listener, + method, + (jobject)linphone_chat_message_get_user_data(msg), + env->CallStaticObjectMethod(lcData->chatMessageStateClass,lcData->chatMessageStateFromIntId,(jint)state)); + + if (state == LinphoneChatMessageStateDelivered || state == LinphoneChatMessageStateNotDelivered) { + env->DeleteGlobalRef(listener); + } +} +extern "C" void Java_org_linphone_core_LinphoneChatRoomImpl_sendMessage2(JNIEnv* env + ,jobject thiz + ,jlong ptr + ,jlong jmessage + ,jobject jlistener) { + jobject listener = env->NewGlobalRef(jlistener); + linphone_chat_room_send_message2((LinphoneChatRoom*)ptr, (LinphoneChatMessage*)jmessage, chat_room_impl_callback, (void*)listener); +} extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setVideoWindowId(JNIEnv* env ,jobject thiz ,jlong lc diff --git a/coreapi/linphonecore_utils.h b/coreapi/linphonecore_utils.h index bd41ec2b9..964385683 100644 --- a/coreapi/linphonecore_utils.h +++ b/coreapi/linphonecore_utils.h @@ -86,7 +86,15 @@ typedef bool_t (*LinphoneCoreIterateHook)(void *data); void linphone_core_add_iterate_hook(LinphoneCore *lc, LinphoneCoreIterateHook hook, void *hook_data); void linphone_core_remove_iterate_hook(LinphoneCore *lc, LinphoneCoreIterateHook hook, void *hook_data); - +/** + * @ingroup misc + *Function to get call country code from ISO 3166-1 alpha-2 code, ex: FR returns 33 + *@param iso country code alpha2 + *@return call country code or -1 if not found + */ +int linphone_dial_plan_lookup_ccc_from_iso(const char* iso); + + #ifdef __cplusplus } #endif diff --git a/coreapi/lpconfig.c b/coreapi/lpconfig.c index 4cd7202cc..0efdc335e 100644 --- a/coreapi/lpconfig.c +++ b/coreapi/lpconfig.c @@ -273,7 +273,13 @@ const char *lp_config_get_string(LpConfig *lpconfig, const char *section, const int lp_config_get_int(LpConfig *lpconfig,const char *section, const char *key, int default_value){ const char *str=lp_config_get_string(lpconfig,section,key,NULL); - if (str!=NULL) return atoi(str); + if (str!=NULL) { + int ret=0; + if (strstr(str,"0x")==str){ + sscanf(str,"%x",&ret); + }else ret=atoi(str); + return ret; + } else return default_value; } @@ -324,6 +330,12 @@ void lp_config_set_int(LpConfig *lpconfig,const char *section, const char *key, lp_config_set_string(lpconfig,section,key,tmp); } +void lp_config_set_int_hex(LpConfig *lpconfig,const char *section, const char *key, int value){ + char tmp[30]; + snprintf(tmp,sizeof(tmp),"0x%x",value); + lp_config_set_string(lpconfig,section,key,tmp); +} + void lp_config_set_int64(LpConfig *lpconfig,const char *section, const char *key, int64_t value){ char tmp[30]; snprintf(tmp,sizeof(tmp),"%lli",(long long)value); diff --git a/coreapi/lpconfig.h b/coreapi/lpconfig.h index c1821d2aa..a27f7e39a 100644 --- a/coreapi/lpconfig.h +++ b/coreapi/lpconfig.h @@ -96,6 +96,14 @@ void lp_config_set_string(LpConfig *lpconfig,const char *section, const char *ke * @ingroup misc **/ void lp_config_set_int(LpConfig *lpconfig,const char *section, const char *key, int value); + +/** + * Sets an integer config item, but store it as hexadecimal + * + * @ingroup misc +**/ +void lp_config_set_int_hex(LpConfig *lpconfig,const char *section, const char *key, int value); + /** * Sets a 64 bits integer config item * diff --git a/coreapi/misc.c b/coreapi/misc.c index a22bbc1d9..d05a275ba 100644 --- a/coreapi/misc.c +++ b/coreapi/misc.c @@ -466,12 +466,13 @@ static int recvStunResponse(ortp_socket_t sock, char *ipaddr, int *port, int *id return len; } -void linphone_core_run_stun_tests(LinphoneCore *lc, LinphoneCall *call){ +/* this functions runs a simple stun test and return the number of milliseconds to complete the tests, or -1 if the test were failed.*/ +int linphone_core_run_stun_tests(LinphoneCore *lc, LinphoneCall *call, StunCandidate *ac, StunCandidate *vc){ const char *server=linphone_core_get_stun_server(lc); - + if (lc->sip_conf.ipv6_enabled){ ms_warning("stun support is not implemented for ipv6"); - return; + return -1; } if (server!=NULL){ struct sockaddr_storage ss; @@ -482,30 +483,28 @@ void linphone_core_run_stun_tests(LinphoneCore *lc, LinphoneCall *call){ bool_t got_audio,got_video; bool_t cone_audio=FALSE,cone_video=FALSE; struct timeval init,cur; - SalEndpointCandidate *ac,*vc; - - ac=&call->localdesc->streams[0].candidates[0]; - vc=&call->localdesc->streams[1].candidates[0]; + double elapsed; + int ret=0; if (parse_hostname_to_addr(server,&ss,&ss_len)<0){ ms_error("Fail to parser stun server address: %s",server); - return; + return -1; } if (lc->vtable.display_status!=NULL) lc->vtable.display_status(lc,_("Stun lookup in progress...")); /*create the two audio and video RTP sockets, and send STUN message to our stun server */ sock1=create_socket(call->audio_port); - if (sock1==-1) return; + if (sock1==-1) return -1; if (video_enabled){ sock2=create_socket(call->video_port); - if (sock2==-1) return ; + if (sock2==-1) return -1; } got_audio=FALSE; got_video=FALSE; gettimeofday(&init,NULL); do{ - double elapsed; + int id; if (loops%20==0){ ms_message("Sending stun requests..."); @@ -544,10 +543,12 @@ void linphone_core_run_stun_tests(LinphoneCore *lc, LinphoneCall *call){ elapsed=((cur.tv_sec-init.tv_sec)*1000.0) + ((cur.tv_usec-init.tv_usec)/1000.0); if (elapsed>2000) { ms_message("Stun responses timeout, going ahead."); + ret=-1; break; } loops++; }while(!(got_audio && (got_video||sock2==-1) ) ); + if (ret==0) ret=(int)elapsed; if (!got_audio){ ms_error("No stun server response for audio port."); }else{ @@ -564,15 +565,32 @@ void linphone_core_run_stun_tests(LinphoneCore *lc, LinphoneCall *call){ } } } - if ((ac->addr[0]!='\0' && vc->addr[0]!='\0' && strcmp(ac->addr,vc->addr)==0) - || sock2==-1){ - strcpy(call->localdesc->addr,ac->addr); - } close_socket(sock1); if (sock2!=-1) close_socket(sock2); + return ret; + } + return -1; +} + +void linphone_core_adapt_to_network(LinphoneCore *lc, int ping_time_ms, LinphoneCallParams *params){ + if (lp_config_get_int(lc->config,"net","activate_edge_workarounds",0)==1){ + ms_message("Stun server ping time is %i ms",ping_time_ms); + int threshold=lp_config_get_int(lc->config,"net","edge_ping_time",500); + + if (ping_time_ms>threshold){ + int edge_ptime=lp_config_get_int(lc->config,"net","edge_ptime",100); + int edge_bw=lp_config_get_int(lc->config,"net","edge_bw",20); + /* we are in a 2G network*/ + params->up_bw=params->down_bw=edge_bw; + params->up_ptime=params->down_ptime=edge_ptime; + params->has_video=FALSE; + + }/*else use default settings */ } } + + int linphone_core_gather_ice_candidates(LinphoneCore *lc, LinphoneCall *call) { char local_addr[64]; @@ -606,16 +624,57 @@ int linphone_core_gather_ice_candidates(LinphoneCore *lc, LinphoneCall *call) } ice_add_local_candidate(audio_check_list, "host", local_addr, call->audio_port, 1, NULL); ice_add_local_candidate(audio_check_list, "host", local_addr, call->audio_port + 1, 2, NULL); + call->stats[LINPHONE_CALL_STATS_AUDIO].ice_state = LinphoneIceStateInProgress; if (call->params.has_video && (video_check_list != NULL)) { ice_add_local_candidate(video_check_list, "host", local_addr, call->video_port, 1, NULL); ice_add_local_candidate(video_check_list, "host", local_addr, call->video_port + 1, 2, NULL); + call->stats[LINPHONE_CALL_STATS_VIDEO].ice_state = LinphoneIceStateInProgress; } + ms_message("ICE: gathering candidate from [%s]",server); /* Gather local srflx candidates. */ ice_session_gather_candidates(call->ice_session, ss, ss_len); return 0; } +void linphone_core_update_ice_state_in_call_stats(LinphoneCall *call) +{ + IceCheckList *audio_check_list; + IceCheckList *video_check_list; + + if (call->ice_session == NULL) return; + audio_check_list = ice_session_check_list(call->ice_session, 0); + video_check_list = ice_session_check_list(call->ice_session, 1); + if (audio_check_list == NULL) return; + + switch (ice_check_list_selected_valid_candidate_type(audio_check_list)) { + case ICT_HostCandidate: + call->stats[LINPHONE_CALL_STATS_AUDIO].ice_state = LinphoneIceStateHostConnection; + break; + case ICT_ServerReflexiveCandidate: + case ICT_PeerReflexiveCandidate: + call->stats[LINPHONE_CALL_STATS_AUDIO].ice_state = LinphoneIceStateReflexiveConnection; + break; + case ICT_RelayedCandidate: + call->stats[LINPHONE_CALL_STATS_AUDIO].ice_state = LinphoneIceStateRelayConnection; + break; + } + if (call->params.has_video && (video_check_list != NULL)) { + switch (ice_check_list_selected_valid_candidate_type(video_check_list)) { + case ICT_HostCandidate: + call->stats[LINPHONE_CALL_STATS_VIDEO].ice_state = LinphoneIceStateHostConnection; + break; + case ICT_ServerReflexiveCandidate: + case ICT_PeerReflexiveCandidate: + call->stats[LINPHONE_CALL_STATS_VIDEO].ice_state = LinphoneIceStateReflexiveConnection; + break; + case ICT_RelayedCandidate: + call->stats[LINPHONE_CALL_STATS_VIDEO].ice_state = LinphoneIceStateRelayConnection; + break; + } + } +} + void linphone_core_update_local_media_description_from_ice(SalMediaDescription *desc, IceSession *session) { const char *rtp_addr, *rtcp_addr; diff --git a/coreapi/offeranswer.c b/coreapi/offeranswer.c index f2cb836c2..541a1eee3 100644 --- a/coreapi/offeranswer.c +++ b/coreapi/offeranswer.c @@ -240,7 +240,6 @@ static void initiate_incoming(const SalStreamDescription *local_cap, if (result->payloads && !only_telephone_event(result->payloads) && (remote_offer->rtp_port!=0 || remote_offer->rtp_port==SalStreamSendOnly)){ strcpy(result->rtp_addr,local_cap->rtp_addr); strcpy(result->rtcp_addr,local_cap->rtcp_addr); - memcpy(result->candidates,local_cap->candidates,sizeof(result->candidates)); result->rtp_port=local_cap->rtp_port; result->rtcp_port=local_cap->rtcp_port; result->bandwidth=local_cap->bandwidth; diff --git a/coreapi/private.h b/coreapi/private.h index 6c9ba8d29..f0b3b2c30 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -69,8 +69,12 @@ struct _LinphoneCallParams{ LinphoneCall *referer; /*in case this call creation is consecutive to an incoming transfer, this points to the original call */ int audio_bw; /* bandwidth limit for audio stream */ LinphoneMediaEncryption media_encryption; - PayloadType *audio_codec; - PayloadType *video_codec; + PayloadType *audio_codec; /*audio codec currently in use */ + PayloadType *video_codec; /*video codec currently in use */ + int down_bw; + int up_bw; + int down_ptime; + int up_ptime; bool_t has_video; bool_t real_early_media; /*send real media even during early media (for outgoing calls)*/ bool_t in_conference; /*in conference mode */ @@ -87,11 +91,13 @@ typedef struct _CallCallbackObj static const int linphone_call_magic=0x3343; struct _LinphoneChatMessage { - const char* message; + char* message; LinphoneChatRoom* chat_room; LinphoneChatMessageStateChangeCb cb; void* cb_ud; void* message_userdata; + char* external_body_url; + LinphoneAddress* from; }; struct _LinphoneCall @@ -179,10 +185,7 @@ int parse_hostname_to_addr(const char *server, struct sockaddr_storage *ss, sock int set_lock_file(); int get_lock_file(); int remove_lock_file(); -int do_registration(LinphoneCore *lc, bool_t doit); -void check_for_registration(LinphoneCore *lc); void check_sound_device(LinphoneCore *lc); -void linphone_core_verify_codecs(LinphoneCore *lc); void linphone_core_get_local_ip(LinphoneCore *lc, const char *to, char *result); bool_t host_has_ipv6_network(); bool_t lp_spawn_command_line_sync(const char *command, char **result,int *command_ret); @@ -229,8 +232,16 @@ MSList *linphone_find_friend(MSList *fl, const LinphoneAddress *fri, LinphoneFri void linphone_core_update_allocated_audio_bandwidth(LinphoneCore *lc); void linphone_core_update_allocated_audio_bandwidth_in_call(LinphoneCall *call, const PayloadType *pt); -void linphone_core_run_stun_tests(LinphoneCore *lc, LinphoneCall *call); + +typedef struct StunCandidate{ + char addr[64]; + int port; +}StunCandidate; + +int linphone_core_run_stun_tests(LinphoneCore *lc, LinphoneCall *call, StunCandidate *ac, StunCandidate *vc); +void linphone_core_adapt_to_network(LinphoneCore *lc, int ping_time_ms, LinphoneCallParams *params); int linphone_core_gather_ice_candidates(LinphoneCore *lc, LinphoneCall *call); +void linphone_core_update_ice_state_in_call_stats(LinphoneCall *call); void linphone_core_update_local_media_description_from_ice(SalMediaDescription *desc, IceSession *session); void linphone_core_update_ice_from_remote_media_description(LinphoneCall *call, const SalMediaDescription *md); void linphone_core_deactivate_ice_for_deactivated_media_streams(LinphoneCall *call, const SalMediaDescription *md); @@ -251,7 +262,7 @@ void linphone_proxy_config_write_to_config_file(struct _LpConfig* config,Linphon int linphone_proxy_config_normalize_number(LinphoneProxyConfig *cfg, const char *username, char *result, size_t result_len); -void linphone_core_text_received(LinphoneCore *lc, const char *from, const char *msg); +void linphone_core_message_received(LinphoneCore *lc, const char *from, const char *raw_msg,const char* external_url); void linphone_core_play_tone(LinphoneCore *lc); @@ -386,6 +397,7 @@ typedef struct rtp_config /* stop rtp xmit when audio muted */ bool_t audio_adaptive_jitt_comp_enabled; bool_t video_adaptive_jitt_comp_enabled; + bool_t pad; }rtp_config_t; @@ -400,7 +412,6 @@ typedef struct net_config int upload_bw; int firewall_policy; int mtu; - int down_ptime; bool_t nat_sdp_only; }net_config_t; @@ -413,10 +424,10 @@ typedef struct sound_config struct _MSSndCard * lsd_card; /* dummy playback card for Linphone Sound Daemon extension */ const char **cards; int latency; /* latency in samples of the current used sound device */ + float soft_play_lev; /*playback gain in db.*/ char rec_lev; char play_lev; char ring_lev; - char soft_play_lev; char source; char *local_ring; char *remote_ring; @@ -539,6 +550,7 @@ struct _LinphoneCore int device_rotation; int max_calls; LinphoneTunnel *tunnel; + char* device_id; }; LinphoneTunnel *linphone_core_tunnel_new(LinphoneCore *lc); diff --git a/coreapi/proxy.c b/coreapi/proxy.c index bb01f14ee..ba9c0d752 100644 --- a/coreapi/proxy.c +++ b/coreapi/proxy.c @@ -375,21 +375,33 @@ bool_t linphone_proxy_config_get_dial_escape_plus(const LinphoneProxyConfig *cfg */ typedef struct dial_plan{ const char *country; + const char* iso_country_code; /* ISO 3166-1 alpha-2 code, ex: FR for France*/ char ccc[8]; /*country calling code*/ int nnl; /*maximum national number length*/ const char * icp; /*international call prefix, ex: 00 in europe*/ + }dial_plan_t; /* TODO: fill with information for all countries over the world*/ static dial_plan_t const dial_plans[]={ - {"France" , "33" , 9 , "00" }, - {"United States", "1" , 10 , "011" }, - {"Turkey" , "90" , 10 , "00" }, - {"Switzerland" , "41" , 9 , "00" }, - {NULL , "" , 0 , NULL } + {"France" ,"FR" , "33" , 9 , "00" }, + {"United States" ,"US" , "1" , 10 , "011" }, + {"Turkey" ,"TR" , "90" , 10 , "00" }, + {"Switzerland" ,"XK" , "41" , 9 , "00" }, + {NULL ,NULL,"" , 0 , NULL } }; -static dial_plan_t most_common_dialplan={ "generic" , "", 10, "00"}; +static dial_plan_t most_common_dialplan={ "generic" ,"", "", 10, "00"}; + +int linphone_dial_plan_lookup_ccc_from_iso(const char* iso) { + dial_plan_t* dial_plan; + for (dial_plan=(dial_plan_t*)dial_plans; dial_plan->country!=NULL; dial_plan++) { + if (strcmp(iso, dial_plan->iso_country_code)==0) { + return atoi(dial_plan->ccc); + } + } + return -1; +} static void lookup_dial_plan(const char *ccc, dial_plan_t *plan){ int i; @@ -728,6 +740,9 @@ void linphone_proxy_config_write_to_config_file(LpConfig *config, LinphoneProxyC if (obj->reg_identity!=NULL){ lp_config_set_string(config,key,"reg_identity",obj->reg_identity); } + if (obj->contact_params!=NULL){ + lp_config_set_string(config,key,"contact_params",obj->contact_params); + } lp_config_set_int(config,key,"reg_expires",obj->expires); lp_config_set_int(config,key,"reg_sendregister",obj->reg_sendregister); lp_config_set_int(config,key,"publish",obj->publish); @@ -762,6 +777,8 @@ LinphoneProxyConfig *linphone_proxy_config_new_from_config_file(LpConfig *config tmp=lp_config_get_string(config,key,"reg_route",NULL); if (tmp!=NULL) linphone_proxy_config_set_route(cfg,tmp); + linphone_proxy_config_set_contact_parameters(cfg,lp_config_get_string(config,key,"contact_parameters",NULL)); + linphone_proxy_config_expires(cfg,lp_config_get_int(config,key,"reg_expires",DEFAULT_INT(config,reg_expires,600))); linphone_proxy_config_enableregister(cfg,lp_config_get_int(config,key,"reg_sendregister",0)); diff --git a/coreapi/sal.h b/coreapi/sal.h index 616b0aba9..751cc6533 100644 --- a/coreapi/sal.h +++ b/coreapi/sal.h @@ -105,11 +105,6 @@ typedef enum{ SalStreamInactive }SalStreamDir; -typedef struct SalEndpointCandidate{ - char addr[64]; - int port; -}SalEndpointCandidate; - #define SAL_ENDPOINT_CANDIDATE_MAX 2 #define SAL_MEDIA_DESCRIPTION_MAX_ICE_ADDR_LEN 64 @@ -159,7 +154,6 @@ typedef struct SalStreamDescription{ MSList *payloads; //other_transactions;elem!=NULL;elem=elem->next){ @@ -284,6 +283,7 @@ Sal * sal_init(){ sal->rootCa = 0; sal->verify_server_certs=TRUE; sal->expire_old_contact=FALSE; + sal->dscp=-1; return sal; } @@ -342,6 +342,8 @@ void sal_set_callbacks(Sal *ctx, const SalCallbacks *cbs){ ctx->callbacks.text_received=(SalOnTextReceived)unimplemented_stub; if (ctx->callbacks.ping_reply==NULL) ctx->callbacks.ping_reply=(SalOnPingReply)unimplemented_stub; + if (ctx->callbacks.message_external_body==NULL) + ctx->callbacks.message_external_body=(SalOnMessageExternalBodyReceived)unimplemented_stub; } int sal_unlisten_ports(Sal *ctx){ @@ -379,6 +381,12 @@ static void set_tls_options(Sal *ctx){ #endif } +void sal_set_dscp(Sal *ctx, int dscp){ + ctx->dscp=dscp; + if (dscp!=-1) + eXosip_set_option(EXOSIP_OPT_SET_DSCP,&ctx->dscp); +} + int sal_listen_port(Sal *ctx, const char *addr, int port, SalTransport tr, int is_secure){ int err; bool_t ipv6; @@ -405,6 +413,7 @@ int sal_listen_port(Sal *ctx, const char *addr, int port, SalTransport tr, int i eXosip_set_option(EXOSIP_OPT_USE_RPORT,&use_rports); int dont_use_101 = !ctx->use_101; // Copy char to int to avoid bad alignment eXosip_set_option(EXOSIP_OPT_DONT_SEND_101,&dont_use_101); + sal_set_dscp(ctx,ctx->dscp); ipv6=strchr(addr,':')!=NULL; eXosip_enable_ipv6(ipv6); @@ -931,9 +940,9 @@ void sal_op_authenticate(SalOp *h, const SalAuthInfo *info){ } void sal_op_cancel_authentication(SalOp *h) { if (h->rid >0) { - sal_op_get_sal(h)->callbacks.register_failure(h,SalErrorFailure, SalReasonForbidden,_("Authentication failure")); + sal_op_get_sal(h)->callbacks.register_failure(h,SalErrorFailure, SalReasonForbidden,"Authentication failure"); } else if (h->cid >0) { - sal_op_get_sal(h)->callbacks.call_failure(h,SalErrorFailure, SalReasonForbidden,_("Authentication failure"),0); + sal_op_get_sal(h)->callbacks.call_failure(h,SalErrorFailure, SalReasonForbidden,"Authentication failure",0); } else { ms_warning("Auth failure not handled"); } @@ -999,6 +1008,7 @@ static SalOp *find_op(Sal *sal, eXosip_event_t *ev){ return sal_find_in_subscribe(sal,ev->nid); } if (ev->response) return sal_find_other(sal,ev->response); + else if (ev->request) return sal_find_other(sal,ev->request); return NULL; } @@ -1701,15 +1711,44 @@ static bool_t comes_from_local_if(osip_message_t *msg){ static void text_received(Sal *sal, eXosip_event_t *ev){ osip_body_t *body=NULL; char *from=NULL,*msg; + osip_content_type_t* content_type; + osip_uri_param_t* external_body_url; + char unquoted_external_body_url [256]; + int external_body_size=0; + content_type= osip_message_get_content_type(ev->request); + if (!content_type) { + ms_error("Could not get message because no content type"); + return; + } + osip_from_to_str(ev->request->from,&from); + if (content_type->type + && strcmp(content_type->type, "text")==0 + && content_type->subtype + && strcmp(content_type->subtype, "plain")==0 ) { osip_message_get_body(ev->request,0,&body); if (body==NULL){ ms_error("Could not get text message from SIP body"); return; } msg=body->body; - osip_from_to_str(ev->request->from,&from); sal->callbacks.text_received(sal,from,msg); + } if (content_type->type + && strcmp(content_type->type, "message")==0 + && content_type->subtype + && strcmp(content_type->subtype, "external-body")==0 ) { + + osip_content_type_param_get_byname(content_type, "URL", &external_body_url); + /*remove both first and last character*/ + strncpy(unquoted_external_body_url + ,&external_body_url->gvalue[1] + ,external_body_size=MIN(strlen(external_body_url->gvalue)-1,sizeof(unquoted_external_body_url))); + unquoted_external_body_url[external_body_size-1]='\0'; + sal->callbacks.message_external_body(sal,from,unquoted_external_body_url); + + } else { + ms_warning("Unsupported content type [%s/%s]",content_type->type,content_type->subtype); + } osip_free(from); } @@ -1953,26 +1992,27 @@ static bool_t registration_failure(Sal *sal, eXosip_event_t *ev){ static void other_request_reply(Sal *sal,eXosip_event_t *ev){ SalOp *op=find_op(sal,ev); - LinphoneChatMessage* chat_msg; - ms_message("Processing reponse status [%i] for method [%s]",ev->response->status_code,osip_message_get_method(ev->request)); if (op==NULL){ ms_warning("other_request_reply(): Receiving response to unknown request."); return; } if (ev->response){ + ms_message("Processing reponse status [%i] for method [%s]",ev->response->status_code,osip_message_get_method(ev->request)); update_contact_from_response(op,ev->response); if (ev->request && strcmp(osip_message_get_method(ev->request),"OPTIONS")==0) sal->callbacks.ping_reply(op); - else if (ev->request && strcmp(osip_message_get_method(ev->request),"MESSAGE")==0) { - /*out of call message acknolegment*/ - chat_msg=(LinphoneChatMessage* )op->base.user_pointer; - if (chat_msg->cb) { - chat_msg->cb(chat_msg - ,(ev->response->status_code==200?LinphoneChatMessageStateDelivered:LinphoneChatMessageStateNotDelivered) - ,chat_msg->cb_ud); + } + if (ev->request && strcmp(osip_message_get_method(ev->request),"MESSAGE")==0) { + /*out of call message acknolegment*/ + SalTextDeliveryStatus status=SalTextDeliveryFailed; + if (ev->response){ + if (ev->response->status_code<200){ + status=SalTextDeliveryInProgress; + }else if (ev->response->status_code<300 && ev->response->status_code>=200){ + status=SalTextDeliveryDone; } - linphone_chat_message_destroy(chat_msg); } + sal->callbacks.text_delivery_update(op,status); } } @@ -2081,8 +2121,8 @@ static bool_t process_event(Sal *sal, eXosip_event_t *ev){ if (ev->response && (ev->response->status_code == 407 || ev->response->status_code == 401)){ return process_authentication(sal,ev); } - case EXOSIP_SUBSCRIPTION_SERVERFAILURE: - case EXOSIP_SUBSCRIPTION_GLOBALFAILURE: + case EXOSIP_SUBSCRIPTION_SERVERFAILURE: + case EXOSIP_SUBSCRIPTION_GLOBALFAILURE: sal_exosip_subscription_closed(sal,ev); break; case EXOSIP_REGISTRATION_FAILURE: @@ -2221,12 +2261,28 @@ int sal_register(SalOp *h, const char *proxy, const char *from, int expires){ int sal_register_refresh(SalOp *op, int expires){ osip_message_t *msg=NULL; const char *contact=sal_op_get_contact(op); - + if (op->rid==-1){ ms_error("Unexistant registration context, not possible to refresh."); return -1; } +#ifdef HAVE_EXOSIP_TRYLOCK + { + int tries=0; + /*iOS hack: in the keep alive handler, we have no more than 10 seconds to refresh registers, otherwise the application is suspended forever. + * In order to prevent this case that can occur when the exosip thread is busy with DNS while network isn't in a good shape, we try to take + * the exosip lock in a non blocking way, and give up if it takes too long*/ + while (eXosip_trylock()!=0){ + ms_usleep(100000); + if (tries>30) {/*after 3 seconds, give up*/ + ms_warning("Could not obtain exosip lock in a reasonable time, giving up."); + return -1; + } + } + } +#else eXosip_lock(); +#endif eXosip_register_build_register(op->rid,expires,&msg); if (msg!=NULL){ if (contact) register_set_contact(msg,contact); diff --git a/coreapi/sal_eXosip2.h b/coreapi/sal_eXosip2.h index ccc95d56a..71463854c 100644 --- a/coreapi/sal_eXosip2.h +++ b/coreapi/sal_eXosip2.h @@ -41,6 +41,7 @@ struct Sal{ int keepalive_period; void *up; /*user pointer*/ char* rootCa; /* File _or_ folder containing root CA */ + int dscp; bool_t one_matching_codec; bool_t double_reg; bool_t use_rports; diff --git a/coreapi/sal_eXosip2_presence.c b/coreapi/sal_eXosip2_presence.c index f79866a0a..3559081db 100644 --- a/coreapi/sal_eXosip2_presence.c +++ b/coreapi/sal_eXosip2_presence.c @@ -81,7 +81,7 @@ void sal_remove_in_subscribe(Sal *sal, SalOp *op){ sal->in_subscribes=ms_list_remove(sal->in_subscribes,op); } -int sal_text_send(SalOp *op, const char *from, const char *to, const char *msg){ +int sal_message_send(SalOp *op, const char *from, const char *to, const char* content_type, const char *msg){ osip_message_t *sip=NULL; if(op->cid == -1) @@ -97,8 +97,8 @@ int sal_text_send(SalOp *op, const char *from, const char *to, const char *msg){ eXosip_message_build_request(&sip,"MESSAGE",sal_op_get_to(op), sal_op_get_from(op),sal_op_get_route(op)); if (sip!=NULL){ - osip_message_set_content_type(sip,"text/plain"); - osip_message_set_body(sip,msg,strlen(msg)); + osip_message_set_content_type(sip,content_type); + if (msg) osip_message_set_body(sip,msg,strlen(msg)); sal_add_other(op->base.root,op,sip); eXosip_message_send_request(sip); }else{ @@ -118,14 +118,16 @@ int sal_text_send(SalOp *op, const char *from, const char *to, const char *msg){ eXosip_unlock(); return -1; } - osip_message_set_content_type(sip,"text/plain"); - osip_message_set_body(sip,msg,strlen(msg)); + osip_message_set_content_type(sip,content_type); + if (msg) osip_message_set_body(sip,msg,strlen(msg)); eXosip_call_send_request(op->did,sip); eXosip_unlock(); } return 0; } - +int sal_text_send(SalOp *op, const char *from, const char *to, const char *msg) { + return sal_message_send(op,from,to,"text/plain",msg); +} /*presence Subscribe/notify*/ int sal_subscribe_presence(SalOp *op, const char *from, const char *to){ osip_message_t *msg=NULL; diff --git a/coreapi/sal_eXosip2_sdp.c b/coreapi/sal_eXosip2_sdp.c index 6b1dd8855..050a53a76 100644 --- a/coreapi/sal_eXosip2_sdp.c +++ b/coreapi/sal_eXosip2_sdp.c @@ -18,6 +18,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +#include "ortp/port.h" #include "ortp/b64.h" #include "ortp/ortp_srtp.h" #include "sal.h" @@ -279,10 +280,6 @@ static void add_line(sdp_message_t *msg, int lineno, const SalStreamDescription rtcp_addr=desc->rtcp_addr; rtp_port=desc->rtp_port; rtcp_port=desc->rtcp_port; - if (desc->candidates[0].addr[0]!='\0'){ - rtp_addr=desc->candidates[0].addr; - rtp_port=desc->candidates[0].port; - } if (desc->proto == SalProtoRtpSavp) { int i; diff --git a/gtk/Makefile.am b/gtk/Makefile.am index a4dceba61..ede08b900 100644 --- a/gtk/Makefile.am +++ b/gtk/Makefile.am @@ -9,7 +9,8 @@ UI_FILES= about.ui \ log.ui \ buddylookup.ui \ tunnel_config.ui \ - waiting.ui + waiting.ui \ + dscp_settings.ui PIXMAPS= \ stock_people.png diff --git a/gtk/chat.c b/gtk/chat.c index 0dafbdb9c..aa1e7dff6 100644 --- a/gtk/chat.c +++ b/gtk/chat.c @@ -19,6 +19,11 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "linphone.h" + +#ifdef HAVE_GTK_OSX +#include +#endif + GtkWidget * linphone_gtk_init_chatroom(LinphoneChatRoom *cr, const char *with){ GtkWidget *w; GtkTextBuffer *b; @@ -37,6 +42,7 @@ GtkWidget * linphone_gtk_init_chatroom(LinphoneChatRoom *cr, const char *with){ } void linphone_gtk_create_chatroom(const char *with){ + LinphoneChatRoom *cr=linphone_core_create_chat_room(linphone_gtk_get_core(),with); if (!cr) return; linphone_gtk_init_chatroom(cr,with); @@ -84,6 +90,10 @@ const char* linphone_gtk_get_used_identity(){ else return linphone_core_get_primary_contact(lc); } +static void on_chat_state_changed(LinphoneChatMessage *msg, LinphoneChatMessageState state, void *user_pointer){ + g_message("chat message state is %s",linphone_chat_message_state_to_string(state)); +} + void linphone_gtk_send_text(GtkWidget *button){ GtkWidget *w=gtk_widget_get_toplevel(button); GtkWidget *entry=linphone_gtk_get_widget(w,"text_entry"); @@ -91,19 +101,37 @@ void linphone_gtk_send_text(GtkWidget *button){ const gchar *entered; entered=gtk_entry_get_text(GTK_ENTRY(entry)); if (strlen(entered)>0) { + LinphoneChatMessage *msg; linphone_gtk_push_text(GTK_TEXT_VIEW(linphone_gtk_get_widget(w,"textlog")), linphone_gtk_get_used_identity(), entered,TRUE); - linphone_chat_room_send_message(cr,entered); + msg=linphone_chat_room_create_message(cr,entered); + linphone_chat_room_send_message2(cr,msg,on_chat_state_changed,NULL); gtk_entry_set_text(GTK_ENTRY(entry),""); } } void linphone_gtk_text_received(LinphoneCore *lc, LinphoneChatRoom *room, const LinphoneAddress *from, const char *message){ - GtkWidget *w=(GtkWidget*)linphone_chat_room_get_user_data(room); - if (w==NULL){ + GtkWidget *w=(GtkWidget*)linphone_chat_room_get_user_data(room); + if (w==NULL){ w=linphone_gtk_init_chatroom(room,linphone_address_as_string_uri_only(from)); + g_object_set_data(G_OBJECT(w),"is_notified",GINT_TO_POINTER(FALSE)); } + + #ifdef HAVE_GTK_OSX + /* Notified when a new message is sent */ + linphone_gtk_status_icon_set_blinking(TRUE); + #else + if (!gtk_window_is_active((GtkWindow*)w)){ + if(!GPOINTER_TO_INT(g_object_get_data(G_OBJECT(w),"is_notified"))){ + linphone_gtk_notify(NULL,message); + g_object_set_data(G_OBJECT(w),"is_notified",GINT_TO_POINTER(TRUE)); + } + } else { + g_object_set_data(G_OBJECT(w),"is_notified",GINT_TO_POINTER(FALSE)); + } + #endif + linphone_gtk_push_text(GTK_TEXT_VIEW(linphone_gtk_get_widget(w,"textlog")), linphone_address_as_string_uri_only(from), message,FALSE); diff --git a/gtk/dscp_settings.ui b/gtk/dscp_settings.ui new file mode 100644 index 000000000..4664768c6 --- /dev/null +++ b/gtk/dscp_settings.ui @@ -0,0 +1,178 @@ + + + + + + False + 5 + Dscp settings + True + dialog + + + + True + False + 2 + + + True + False + end + + + gtk-close + True + True + True + False + True + + + False + False + 0 + + + + + gtk-ok + True + True + True + False + True + + + False + False + 1 + + + + + False + True + end + 0 + + + + + True + False + 0 + none + + + True + False + 3 + 2 + True + + + True + True + • + True + False + False + True + True + + + 1 + 2 + + + + + True + True + • + True + False + False + True + True + + + 1 + 2 + 1 + 2 + + + + + True + True + • + True + False + False + True + True + + + 1 + 2 + 2 + 3 + + + + + True + False + SIP + + + + + True + False + Audio RTP stream + + + 1 + 2 + + + + + True + False + Video RTP stream + + + 2 + 3 + + + + + + + True + False + <b>Set DSCP values (in hexadecimal)</b> + True + + + + + False + False + 1 + + + + + + button2 + button1 + + + diff --git a/gtk/linphone.h b/gtk/linphone.h index d4cafe28f..97a4400c7 100644 --- a/gtk/linphone.h +++ b/gtk/linphone.h @@ -97,6 +97,9 @@ void * linphone_gtk_wait(LinphoneCore *lc, void *ctx, LinphoneWaitingState ws, c void linphone_gtk_show_directory_search(void); +void linphone_gtk_status_icon_set_blinking(gboolean val); +void linphone_gtk_notify(LinphoneCall *call, const char *msg); + /*functions controlling the different views*/ gboolean linphone_gtk_use_in_call_view(); LinphoneCall *linphone_gtk_get_currently_displayed_call(gboolean *is_conf); diff --git a/gtk/main.c b/gtk/main.c index 2955b3ecc..193803256 100644 --- a/gtk/main.c +++ b/gtk/main.c @@ -65,10 +65,11 @@ static void linphone_gtk_call_state_changed(LinphoneCore *lc, LinphoneCall *call static void linphone_gtk_call_encryption_changed(LinphoneCore *lc, LinphoneCall *call, bool_t enabled, const char *token); static void linphone_gtk_transfer_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState cstate); static gboolean linphone_gtk_auto_answer(LinphoneCall *call); -static void linphone_gtk_status_icon_set_blinking(gboolean val); +void linphone_gtk_status_icon_set_blinking(gboolean val); void _linphone_gtk_enable_video(gboolean val); + static gboolean verbose=0; static gboolean auto_answer = 0; static gchar * addr_to_call = NULL; @@ -1028,18 +1029,20 @@ static void make_notification(const char *title, const char *body){ #endif -static void linphone_gtk_notify(LinphoneCall *call, const char *msg){ +void linphone_gtk_notify(LinphoneCall *call, const char *msg){ #ifdef HAVE_NOTIFY if (!notify_is_initted()) if (!notify_init ("Linphone")) ms_error("Libnotify failed to init."); #endif if (!call) { + #ifdef HAVE_NOTIFY if (!notify_notification_show(notify_notification_new("Linphone",msg,NULL #ifdef HAVE_NOTIFY1 ,NULL #endif ),NULL)) + ms_error("Failed to send notification."); #else linphone_gtk_show_main_window(); @@ -1347,7 +1350,7 @@ static gboolean do_icon_blink(GtkStatusIcon *gi){ #endif -static void linphone_gtk_status_icon_set_blinking(gboolean val){ +void linphone_gtk_status_icon_set_blinking(gboolean val){ #ifdef HAVE_GTK_OSX static gint attention_id; GtkOSXApplication *theMacApp=(GtkOSXApplication*)g_object_new(GTK_TYPE_OSX_APPLICATION, NULL); diff --git a/gtk/parameters.ui b/gtk/parameters.ui index 9fc8538c0..7e76c385f 100644 --- a/gtk/parameters.ui +++ b/gtk/parameters.ui @@ -207,10 +207,10 @@ Set Maximum Transmission Unit: - False True True False + False True @@ -247,10 +247,10 @@ Send DTMFs as SIP info - False True True False + False True @@ -263,11 +263,11 @@ Use IPv6 instead of IPv4 - False True True False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + False True @@ -315,7 +315,7 @@ True False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 5 + 6 2 @@ -377,23 +377,24 @@ Tunnel - 4 - 5 + 5 + 6 - edit - False + gtk-edit True True + False + True 1 2 - 4 - 5 + 5 + 6 @@ -462,6 +463,34 @@ 3 + + + True + False + DSCP fields + + + 4 + 5 + + + + + gtk-edit + True + True + True + False + True + + + + 1 + 2 + 4 + 5 + + @@ -496,10 +525,10 @@ Direct connection to the Internet - False True True False + False True True @@ -517,10 +546,10 @@ Behind NAT / Firewall (specify gateway IP below) - False True True False + False True True no_nat @@ -585,10 +614,10 @@ Behind NAT / Firewall (use STUN to resolve) - False True True False + False True no_nat @@ -602,10 +631,10 @@ Behind NAT / Firewall (use ICE) - False True True False + False True no_nat @@ -743,9 +772,6 @@ GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK 6 2 - - - True @@ -767,11 +793,11 @@ gtk-media-play - False True True True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + False True @@ -944,10 +970,10 @@ Enable echo cancellation - False True True False + False True @@ -958,6 +984,9 @@ 6 + + + @@ -1293,10 +1322,10 @@ GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - False True True True + False @@ -1340,11 +1369,11 @@ - False True True True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + False @@ -1388,11 +1417,11 @@ - False True True True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + False @@ -1436,11 +1465,11 @@ - False True True True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + False @@ -1484,9 +1513,9 @@ - False True True + False @@ -1573,11 +1602,11 @@ virtual network ! GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - False True True True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + False @@ -1759,11 +1788,11 @@ virtual network ! gtk-go-up - False True True True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + False True @@ -1776,11 +1805,11 @@ virtual network ! gtk-go-down - False True True True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + False True @@ -1792,11 +1821,11 @@ virtual network ! - False True True True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + False @@ -1840,11 +1869,11 @@ virtual network ! - False True True True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + False @@ -2007,10 +2036,10 @@ virtual network ! Enable adaptive rate control - False True True False + False 0 True @@ -2162,10 +2191,10 @@ virtual network ! Show advanced settings - False True True False + False True @@ -2242,11 +2271,11 @@ virtual network ! end - False True True True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + False diff --git a/gtk/propertybox.c b/gtk/propertybox.c index 6870e2786..31c76f93b 100644 --- a/gtk/propertybox.c +++ b/gtk/propertybox.c @@ -1131,3 +1131,55 @@ void linphone_gtk_tunnel_ok(GtkButton *button){ void linphone_gtk_tunnel_cancel(GtkButton *button){ } + +static void show_dscp(GtkWidget *entry, int val){ + char tmp[20]; + snprintf(tmp,sizeof(tmp),"0x%x",val); + gtk_entry_set_text(GTK_ENTRY(entry),tmp); + +} + +static int read_dscp(GtkWidget *entry){ + const char *val=gtk_entry_get_text(GTK_ENTRY(entry)); + const char *begin; + int ret=0; + if (val==NULL || val[0]=='\0') return 0; + /*skip potential 0x*/ + begin=strstr(val,"0x"); + if (begin) begin+=2; + else begin=val; + if (sscanf(begin,"%x",&ret)==1) + return ret; + return -1; +} + +void linphone_gtk_dscp_edit(){ + LinphoneCore *lc=linphone_gtk_get_core(); + GtkWidget *widget=linphone_gtk_create_window("dscp_settings"); + show_dscp(linphone_gtk_get_widget(widget,"sip_dscp"), + linphone_core_get_sip_dscp(lc)); + show_dscp(linphone_gtk_get_widget(widget,"audio_dscp"), + linphone_core_get_audio_dscp(lc)); + show_dscp(linphone_gtk_get_widget(widget,"video_dscp"), + linphone_core_get_video_dscp(lc)); + gtk_widget_show(widget); +} + +void linphone_gtk_dscp_edit_response(GtkWidget *dialog, guint response_id){ + LinphoneCore *lc=linphone_gtk_get_core(); + switch(response_id){ + case GTK_RESPONSE_OK: + linphone_core_set_sip_dscp(lc, + read_dscp(linphone_gtk_get_widget(dialog,"sip_dscp"))); + linphone_core_set_audio_dscp(lc, + read_dscp(linphone_gtk_get_widget(dialog,"audio_dscp"))); + linphone_core_set_video_dscp(lc, + read_dscp(linphone_gtk_get_widget(dialog,"video_dscp"))); + + break; + default: + break; + } + gtk_widget_destroy(dialog); +} + diff --git a/java/common/org/linphone/core/LinphoneCall.java b/java/common/org/linphone/core/LinphoneCall.java index c42ebb740..6fe6704de 100644 --- a/java/common/org/linphone/core/LinphoneCall.java +++ b/java/common/org/linphone/core/LinphoneCall.java @@ -21,7 +21,7 @@ package org.linphone.core; import java.util.Vector; /** - * Object representing a Call. calls are created using {@link LinphoneCore#invite(LinphoneAddress)} or passed to the application by listener {@link LinphoneCoreListener#callState(LinphoneCore, LinphoneCall, State, String)} + * Object representing a call. Calls are created using {@link LinphoneCore#invite(LinphoneAddress)} or passed to the application by listener {@link LinphoneCoreListener#callState} * */ diff --git a/java/common/org/linphone/core/LinphoneChatMessage.java b/java/common/org/linphone/core/LinphoneChatMessage.java new file mode 100644 index 000000000..3b135fc65 --- /dev/null +++ b/java/common/org/linphone/core/LinphoneChatMessage.java @@ -0,0 +1,90 @@ +package org.linphone.core; + +import java.util.Vector; + + +public interface LinphoneChatMessage { + interface StateListener{ + void onLinphoneChatMessageStateChanged(LinphoneChatMessage msg, State state); + } + static class State { + @SuppressWarnings("rawtypes") + static private Vector values = new Vector(); + private final int mValue; + public final int value() {return mValue;} + + private final String mStringValue; + /** + * Idle + */ + public final static State Idle = new State(0,"Idle"); + /** + * Incoming call received. + */ + public final static State InProgress = new State(1,"InProgress"); + /** + * Outgoing call initialiazed. + */ + public final static State Delivered = new State(2,"Delivered"); + /** + * Outgoing call in progress. + */ + public final static State NotDelivered = new State(3,"NotDelivered"); + + @SuppressWarnings("unchecked") + private State(int value,String stringValue) { + mValue = value; + values.addElement(this); + mStringValue=stringValue; + } + + public static State fromInt(int value) { + + for (int i=0; i -
  • Managing proxies +
  • Managing proxies
  • + +

    Related Documentation

    @@ -155,7 +159,12 @@ Any subsequente modifications to {@link org.linphone.core.LinphoneFriend} must b my_friend.enableSubscribes(true); /*disable subscription for this friend*/ my_friend.done(); /*commit changes triggering an UNSUBSCRIBE message*/ - + Do not display status messages +-J Pass directly to the runtime system + +Provided by Standard doclet: +-d Destination directory for output files +-use Publishing presence status
    Local presence status can be changed using function {@link org.linphone.core.LinphoneCore#setPresenceInfo }.New status is propagated to all friends {@link org.linphone.core.LinphoneCore#addFriend(LinphoneFriend lf) previously added } to LinphoneCore. @@ -189,6 +198,80 @@ from a peer sip uri. System.out.println("Message ["+message+"] received from ["+from+"] "); } + + +

    +Sound and echo cancellation settings +

    +Sound levels +
    +It is possible to tune the microphone input gain and speaker/receiver output gain by setting parameters into the linphonerc factory config file loaded when instanciating the {@link org.linphone.core.LinphoneCore LinphoneCore}. These gains are liblinphone's internal software gains and are unrelated to volume levels managed by the operating system. For example:
    +
    +[sound]
    +#set the speaker or receiver playback gain in dbm0 (0 db = no change). 
    +playback_gain_db=-3
    +#set the microphone gain in linear scale:
    +mic_gain=0.1
    +
    +
    + +
    + +Echo cancellation +
    +On Android devices, echo is a problem, especially with low-end devices. The root cause is the unpredictable latency of Android's sound system. The liblinphone software {@link org.linphone.core.LinphoneCore#enableEchoCancellation echo canceller} that is operating well on desktop platforms (Mac, Linux, Windows) is unable to operate under Android platform. The situation is very heterogenous:
    +
      +
    • On new (after 2011) high end devices, manufacturers often include a hardware echo cancellation. If available, liblinphone will make use of it and no software correction is required. + Source file linphone-android/submodules/linphone/mediastreamer2/java/src/org/linphone/mediastream/video/capture/hwconf/Hacks.java contains a method hasBuiltInEchoCanceller() that returns true if an hardware echo canceller is available, based on device model identifier. The current list is incomplete. +
    • +
    • On former models with decent CPU power (armv7), sound system behaves in a nearly predictive way so that it is possible to use {@link org.linphone.core.LinphoneCore#enableEchoLimiter echo limiter}. Echo limiter is a simple echo attenuation technique which consists in strongly attenuating the microphone input when speaker is playing voice, in order to cut the echo. The main drawback of echo limiter is that the conversation is perceived as half duplex by users, because they won't hear background noise from the remote side while they are speaking. +
    • +
    • On low class android devices or very old models (armv5 processor), no solution works. +
    • +
    + +
    +In order to benefit from the best echo cancellation solution, we recommend applications to run the following algorithm, when it is run for the first time:
    +First of {@link org.linphone.core.LinphoneCore#enableEchoCancellation echo canceller} should not be used, in any case. +
      +
    • Use the Hacks.hasBuiltInEchoCanceller() method to first check if the device has hardware echo canceller. If yes, then echo limiter must be turned off.
    • +
    • If no the hasBuiltInEchoCanceller() returned false, then it is possible to use the echo calibration procedure. If the calibration procedure fails, it means that + probably the phone performs hardware echo cancellation, so in this case echo limiter must be turned off.
    • +
    • If the echo calibration succeeded, then echo is present, so it is recommended to enable echo limiter. +
    + +
    +Echo calibration procedure +
    +The echo calibration procedure is a five second test which consists in playing small beeps to the speaker while the microphone input is recorded. +If the device is subject to echo (or doesn't have hardware echo cancellation), then beeps recorded by the microphone will be detected and a measurement of echo delay can be computed. +Echo calibration procedure can be started by calling {@link org.linphone.core.LinphoneCore#startEchoCalibration LinphoneCore.startEchoCalibration}. + +

    +Echo limiter settings
    +Echo limiter requires settings to be defined in linphonerc factory config file for correction operation. +Typical settings are: +
    +
    +[sound]
    +el_type=mic
    +#speaker energy threshold (linear scale) above which echo limiter decreases mic gain.
    +el_thres=0.03
    +#attenuation applied to mic gain (linear scale)
    +el_force=100000
    +#minimum time in milliseconds during which attenuation is applied
    +el_sustain=600
    +#double talk detection: threshold of ratio mic-energy/speaker-energy above which mic input is sent anyway.
    +el_transmit_thres=1.7
    +#noise gate floorgain (gain applied when no voice is detected).
    +ng_floorgain=0.01
    +
    +
    + +Up to date settings must be found from linphone-android/res/raw/linphonerc file. + +
    + \ No newline at end of file diff --git a/media_api/.gitignore b/media_api/.gitignore deleted file mode 100644 index e99558847..000000000 --- a/media_api/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -.deps -Makefile -Makefile.in diff --git a/media_api/DESIGN.txt b/media_api/DESIGN.txt deleted file mode 100644 index f7c9cfc1f..000000000 --- a/media_api/DESIGN.txt +++ /dev/null @@ -1,135 +0,0 @@ -MEDIA API DESIGN DRAFT -********************** - - -The objective of the media_api is to construct and run the necessary -processing on audio and video data flows for a given call (two party call) or -conference. -The media_api must support calls where callmember can be remote as well -local hosted, in other words the media_api can be used inside linphone as -well as in sip conferencing server. The api must support multiples way of -getting media data: from disk, from rtp, from soundcard... -The media_api is object oriented in C, and is based on the mediastreamer library -to deal with audio or video signals, and on glib for types and usefull routines. - -The api must provide object and methods that describes the call, and then functions -that executes the processing (using the mediastreamer) that is necessary for the -call described. - -Proposed API: - -************************************************************************ -object: MediaFlow -This object reprensent a media that is shared between all members of the call, -for example voice. -methods: -MediaFlow *media_flow_new(char *id_string,gint type,gint duplex); -type can be FLOW_AUDIO, FLOW_VIDEO. -if duplex is 1, it means that the media flow is used by every member in both -receiving and sending mode. -id_string is just a string to identify the flow. - -void media_flow_destroy(MediaFlow *flow); -destructor - -************************************************************************** -object: CallMember -This object reprensent a member of a call. -methods: -CallMember *call_member_new(); - -gint call_member_setup_flow(CallMember *member, MediaFlow *flow, - char *rx_endpoint, char *tx_endpoint); - This is the most important function of the API. It describes the way each - call member receives and send a given media flow. - The MediaFlow "flow" is added to the list of flows used by the member "member". - rx_endpoint is a string that described how data is received by the call member. - It should be an url, for example "rtp://213.21.54.127:7080". In this case it - means that data will be received on port 7080 at ip address 213.21.54.127. - tx_endpoint is a string that described how data is sent by the call member. - The role of url is very important. They can be: - "rtp://213.21.54.127:7080" - "file://tmp/media.out" -a file on disk - "oss://0" -souncard 0 using oss api - "alsa://0" -soundcard 0 using alsa api. - In order to work, the call member must be part of a BasicCall, as well as - the flow must be part of the BasicCall too (using basic_call_add_flow()) - This function may (on the backend) create a MediaEndpoint object that stores - the rx_endpoint and tx_endpoint parameter. This object is added to: - -the list of MediaEndpoint maintained by the member (list per member) - -the list of MediaEndpoint maintained by the flow (list per flow) - - -************************************************************************** -object: BasicCall -This object handles simple calls (two party calls). It defines inside itself -two CallMember objects. -method: -BasicCall *basic_call_new(); - -CallMember *basic_call_get_member(BasicCall *call, gint member_number); - Returns a member of a BasicCall according to a number. - -void basic_call_add_flow(BasicCall *call, MediaFlow *flow); - Adds a flow to the call's list of flow. - -gint basic_call_start_flow(BasicCall *call, MediaFlow *flow); - This function construct the mediastreamer processing chain necessary to make - the call running, if not done, and runs it using ms_start() - -gint basic_call_stop_flow(BasicCall *call, MediaFlow *flow); - -gint basic_call_start_all_flows(BasicCall *call); - -void basic_call_destroy(BasicCall *call); - Destroy all data used by the call: call members, call flows. - -************************************************************************** -object: ConferenceCall -This object handles conference call (which are quite much complicated than basic -calls). But this object should have the same method as the BasicCall object. - -******************************************************************* - EXAMPLE -******************************************************************* - -Two party call between call member A on machine "linphone.org" and call member B on machine "home.com". -The media_api is running on "home.com". - - A (on linphone.org) B (on home.com) - ------->(send to rtp://home.com:7080 MSRTPReceiver------>Decode----->(send to oss:/0) - -------<(recv on rtp://linphone.org:7020 MSRTPSender<--------Encode<-----(read on oss://0) - -This is how to setup this call using the media_api: -BasicCall *call; -CallMember *memberA,*memberB; -MediaFlow *flow; - -/* create a basic call*/ -call=basic_call_new(); -/* get a pointer to the pre-define members of the call */ -memberA=basic_call_get_member(call,0); -memberB=basic_call_get_member(call,1); - -/* create a media flow */ -flow=media_flow_new("voice",FLOW_AUDIO,1); -/* tell that the flow is used by the call */ -basic_call_add_flow(call,flow); -/* tell how each member uses the flow (how is the interface ?)*/ -call_member_setup_flow(memberA,flow,"rtp://linphone.org:7020","rtp://home.com:7080"); -/* note: it is not efficient to do name resolution at this stage: that's why in reality numeric ip address -should be given instead of host name */ -call_member_setup_flow(memberB,flow,"oss://0","oss://0"); - -/* start the flow */ -basic_call_start_flow(call,flow); - -In case where the media api is running on another host called "toto" (in a media translator application for example), - the only thing that would change is the url given to memberB: tx="rtp://home.com:8820" for example and - rx="rtp://toto:9522". - -In the sipomatic application (the test application I use to test linphone (it answers to call and plays -a short annoucement)), I would write rx="file://path_to_annoucement.raw" and tx="file://dev/null" instead of -"oss://0". diff --git a/media_api/Makefile.am b/media_api/Makefile.am deleted file mode 100644 index 38dcf063f..000000000 --- a/media_api/Makefile.am +++ /dev/null @@ -1,31 +0,0 @@ -## Process this file with automake to produce Makefile.in -if BUILD_MEDIA_API - -#the media_api library is the only one we have to build here -lib_LTLIBRARIES=libmedia_api.la - -#definition of the sources of libmedia_api -libmedia_api_la_SOURCES= basiccall.c callmember.c mediaflow.c - -# libmedia_api needs libmediastreamer -libmedia_api_la_LIBADD=$(top_srcdir)/mediastreamer/libmediastreamer.la - -#the media_api test program -bin_PROGRAMS=apitest - -apitest_SOURCES= apitest.c -# the test program links to libmedia_api -apitest_LDADD=libmedia_api.la - -endif - -DEFS=@DEFS@ @SOUNDDEFS@ -DDEBUG -DG_LOG_DOMAIN=\"MediaApi\" - -INCLUDES=-I$(top_srcdir)/mediastreamer \ - -I$(top_srcdir)/speex \ - -I$(top_srcdir)/gsmlib \ - $(ORTP_CFLAGS) \ - -I$(top_srcdir)/lpc10-1.5 \ - -I$(top_srcdir)/ffmpeg - - diff --git a/media_api/apitest.c b/media_api/apitest.c deleted file mode 100644 index cd4ac9e33..000000000 --- a/media_api/apitest.c +++ /dev/null @@ -1,36 +0,0 @@ -#include "basiccall.h" -#include -static int flag = 1; -void stop(int sign){ - flag = 0; -} - - -int main(){ - BasicCall *call; - char *id; - CallMember *memberA, *memberB; - MediaFlow *flow, *flow1; - - signal(SIGINT, stop); - call = basic_call_new(); - memberA = basic_call_get_member(call,MemberA); - memberB = basic_call_get_member(call,MemberB); - - id = "test_voice"; - printf("\n"); - flow = media_flow_new(id, MEDIA_FLOW_VOICE); - - basic_call_add_flow(call, flow); - - call_member_setup_flow(memberA, flow, "file://temp", "oss://0"); - call_member_setup_flow(memberB, flow, "oss://0", "oss://0"); - - media_flow_setup_fd(flow, memberA, memberB, MEDIA_FLOW_HALF_DUPLEX); - basic_call_start_flow(call, flow); - - while(flag){ - sleep(1); - } - -} diff --git a/media_api/apitest.h b/media_api/apitest.h deleted file mode 100644 index e69de29bb..000000000 diff --git a/media_api/basiccall.c b/media_api/basiccall.c deleted file mode 100644 index 8a0044754..000000000 --- a/media_api/basiccall.c +++ /dev/null @@ -1,170 +0,0 @@ -/* - The objective of the media_api is to construct and run the necessary processing - on audio and video data flows for a given call (two party call) or conference. - Copyright (C) 2001 Sharath Udupa skuds@gmx.net - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library 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 - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -#include "basiccall.h" -#include "../mediastreamer/mscodec.h" - -#define ONESYNC 10 -#define MULTISYNC 20 - -BasicCall *basic_call_new(){ - BasicCall *bc = (BasicCall*) g_malloc(sizeof(BasicCall)); - api_trace("basic_call_new: creating a basic call"); - bc->memberA = call_member_new("memberA"); - bc->memberB = call_member_new("memberB"); - return bc; -} - -CallMember *basic_call_get_member(BasicCall *call, int member_nu){ - api_trace("basic_call_get_member: called for %d",member_nu); - if(member_nu == MemberA){ - return call->memberA; - } - else if(member_nu == MemberB){ - return call->memberB; - } -} - -void basic_call_add_flow(BasicCall *call, MediaFlow *flow){ - api_trace("basic_call_add_flow: called for %s",flow->id); - call->flows = g_list_append( call->flows, flow); - return 1; -} - -int find_mediaflow(gconstpointer llist, gconstpointer flow){ - //MediaFlow *mf = (MediaFlow *) ((BasicCallFlow*)llist)->mediaFlow; - if(((MediaFlow*)flow)->id == ((MediaFlow*)llist)->id){ - return 0; - } - return 1; -} - -int basic_call_start_flow(BasicCall *call, MediaFlow *flow){ - int i=0; - int syncFlag=0; - int nFlowDirections; - MSSync *sync; - Members *source, *destination; - FlowDirections *fd; - GList *elem, *selem; - GList *snd_read = NULL, *snd_write = NULL, *filter = NULL; - - //Commented by Sharat - //This is initialized in media_api.c - //when should these functions be really called? - //ms_init(); - //ortp_init(); - - api_trace("basic_call_start_flow: called for flow %s", flow->id); - - elem = g_list_find_custom( call->flows, flow, &find_mediaflow); - if(elem == NULL){ - api_error("basic_call_start_flow: Called for unregistered mediaflow %s", flow->id); - } - - nFlowDirections = g_list_length(flow->flowDirections); - if(flow->type == MEDIA_FLOW_VOICE){ - syncFlag = ONESYNC; - sync = ms_timer_new(); - } - else{ - syncFlag = MULTISYNC; - } - - for(i=0;i< nFlowDirections; i++){ - - if(syncFlag == MULTISYNC){ - sync = ms_timer_new(); - } - fd = (FlowDirections*)g_list_nth_data(flow->flowDirections,i); - source = fd->source; - destination = fd->destination; - - media_flow_start_fd(fd, sync); - if(fd->type == MEDIA_FLOW_DUPLEX){ - switch(source->tx_endpoint->protocol){ - case MEDIA_ALSA: - case MEDIA_OSS: - snd_read = g_list_append(snd_read, fd->recv); - } - switch(destination->rx_endpoint->protocol){ - case MEDIA_ALSA: - case MEDIA_OSS: - snd_write = g_list_append(snd_write, fd->play); - } - - switch(destination->tx_endpoint->protocol){ - case MEDIA_ALSA: - case MEDIA_OSS: - snd_read = g_list_append(snd_read, fd->read); - } - - switch(source->rx_endpoint->protocol){ - case MEDIA_ALSA: - case MEDIA_OSS: - snd_write = g_list_append(snd_write, fd->send); - } - - } - else if(fd->type == MEDIA_FLOW_HALF_DUPLEX){ - - switch(source->tx_endpoint->protocol){ - case MEDIA_ALSA: - case MEDIA_OSS: - snd_read = g_list_append(snd_read, fd->recv); - } - switch(destination->rx_endpoint->protocol){ - case MEDIA_ALSA: - case MEDIA_OSS: - snd_write = g_list_append(snd_write, fd->play); - } - } - if(syncFlag == MULTISYNC){ - flow->sync = g_list_append(flow->sync, sync); - } - } - if(syncFlag == ONESYNC){ - ms_start(sync); - flow->sync = g_list_append(flow->sync, sync); - } - if(syncFlag == MULTISYNC){ - selem = flow->sync; - while(selem != NULL){ - ms_start(selem->data); - selem = g_list_next(selem); - } - } - filter = snd_read; - while(filter != NULL){ - ms_sound_read_start(MS_SOUND_READ((MSFilter*)filter->data)); - filter = g_list_next(filter); - } - - filter = snd_write; - while(filter != NULL){ - ms_sound_write_start(MS_SOUND_WRITE((MSFilter*)filter->data)); - filter = g_list_next(filter); - } - return 1; -} - -int basic_call_stop_flow(BasicCall *call, MediaFlow *flow){ - -} diff --git a/media_api/basiccall.h b/media_api/basiccall.h deleted file mode 100644 index 2351faccc..000000000 --- a/media_api/basiccall.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - The objective of the media_api is to construct and run the necessary processing - on audio and video data flows for a given call (two party call) or conference. - Copyright (C) 2001 Sharath Udupa skuds@gmx.net - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library 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 - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -#include "common.h" -#include "mediaflow.h" -#include "callmember.h" - -//other includes required to be done here -#define MemberA 1 -#define MemberB 2 - - -struct _BasicCall{ - CallMember *memberA, *memberB; - GList *flows; //linked list of MediaFlows -}; - -typedef struct _BasicCall BasicCall; - - -BasicCall *basic_call_new(); - -CallMember *basic_call_get_member(BasicCall *call, int member_nu); - -void basic_call_add_flow(BasicCall *call, MediaFlow *flow); - -int basic_call_start_flow(BasicCall *call, MediaFlow *flow); - -int basic_call_stop_flow(BasicCall *call, MediaFlow *flow); - -int basic_call_start_all_flows(BasicCall *call); - -int basic_call_destroy(BasicCall *call); - diff --git a/media_api/callmember.c b/media_api/callmember.c deleted file mode 100644 index 643ba7b7c..000000000 --- a/media_api/callmember.c +++ /dev/null @@ -1,153 +0,0 @@ -/* - The objective of the media_api is to construct and run the necessary processing - on audio and video data flows for a given call (two party call) or conference. - Copyright (C) 2001 Sharath Udupa skuds@gmx.net - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library 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 - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ -#include -#include "common.h" -#include "callmember.h" -#include "mediaflow.h" - - -CallMember *call_member_new(char *name){ - CallMember *member = (CallMember*) g_malloc(sizeof(CallMember)); - api_trace("call_member_new: creating %s", name); - member->name = name; - member->flows = NULL; - member->profile = NULL; - return member; -} - -int call_member_set_rtp_profile(CallMember *member, RtpProfile *profile){ - member->profile = profile; - return 1; -} - -int call_member_setup_flow(CallMember *member, MediaFlow *flow, char* rx, char *tx){ - Members *mem = (Members*) g_malloc(sizeof(Members)); - Flows *flows = (Flows*) g_malloc(sizeof(Flows)); - api_trace("call_member_setup_flow: setting up flow for: CallMember->%s , MediaFlow->%s", member->name, flow->id); - mem->member = member; - mem->rx_endpoint = parse_end_point(rx); - mem->tx_endpoint = parse_end_point(tx); - flow->members = g_list_append(flow->members, mem); - - flows->flow = flow; - flows->rx_endpoint = parse_end_point(rx); - flows->tx_endpoint = parse_end_point(tx); - member->flows = g_list_append(member->flows, flows); - return 1; -} - -EndPoint *parse_end_point(char *endpoint){ - EndPoint *result = (EndPoint*) g_malloc(sizeof(EndPoint)); - int i=0,len1,len2,len, tlen; - char *str2, temp[30], *host_str; - //api_trace("parse_end_point: parsing %s\n", endpoint); - result->pt = -1; - while(1){ - str2 = (char*) strpbrk(endpoint, ":"); - if(str2 == NULL){ - str2 = (char*) strpbrk(endpoint, ";"); - if(str2 == NULL){ - len = strlen(endpoint); - } - else{ - len1 = strlen(endpoint); - len2 = strlen(str2); - len = len1-len2; - } - } - else{ - len1 = strlen(endpoint); - len2 = strlen(str2); - len = len1-len2; - } - strncpy(temp,endpoint,len); - temp[len] = '\0'; - tlen = strlen(temp); - if((tlen >= 2)&&(temp[0] == '/')&&(temp[1] == '/')){ - host_str = remove_slash(temp); - } - switch(i){ - case 0: if(strcmp(temp,"rtp")==0){ - result->protocol=MEDIA_RTP; - } - else if(strcmp(temp,"oss")==0){ - result->protocol=MEDIA_OSS; - } - else if(strcmp(temp,"alsa")==0){ - result->protocol=MEDIA_ALSA; - } - else if(strcmp(temp,"file")==0){ - result->protocol=MEDIA_FILE; - } - break; - case 1: if(result->protocol==MEDIA_FILE){ - result->file=host_str; - } - else{ - result->host = host_str; - } - break; - case 2: result->port = to_digits(temp); - break; - case 3: result->pt = pt_digits(temp); - break; - default://result->options[result->nOptions++] = temp; - break; - } - if(str2 != NULL) endpoint = str2+1; - else break; - i++; - } - return result; -} - -int to_digits(char *str){ - int nu=0,a,len,i; - len = strlen(str); - for(i=0;i3)&&(str[0]=='p')&&(str[1]=='t')&&(str[2]=='=')){ - return to_digits(str+3); - } - else{ - api_warn("Wrong parameters passed in the endpoints"); - return 0; - //ERROR handling - } -} -char *remove_slash(char var[]){ - char *temp = (char*) g_malloc(10*sizeof(char)); - int len,i; - len=strlen(var); - for(i=2;i - -#define api_trace g_message -#define api_error g_error -#define api_warn g_warning - -#define MEDIA_FLOW_DUPLEX 1 -#define MEDIA_FLOW_HALF_DUPLEX 2 - -//Mediaflow type -#define MEDIA_FLOW_VIDEO 1 -#define MEDIA_FLOW_VOICE 2 - -//Mediaflow protocols -#define MEDIA_RTP 1 -#define MEDIA_OSS 2 -#define MEDIA_ALSA 3 -#define MEDIA_FILE 4 - -//Mediaflow codec function -#define MEDIA_API_DECODER 1 -#define MEDIA_API_ENCODER 2 - -#endif - - diff --git a/media_api/media_api.c b/media_api/media_api.c deleted file mode 100644 index 8746e9b0c..000000000 --- a/media_api/media_api.c +++ /dev/null @@ -1,69 +0,0 @@ -/* - The objective of the media_api is to construct and run the necessary processing - on audio and video data flows for a given call (two party call) or conference. - Copyright (C) 2001 Sharath Udupa skuds@gmx.net - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library 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 - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -#include "media_api.h" - -/* non-standard payload types for oRTP */ -PayloadType lpc1015={ - PAYLOAD_AUDIO_PACKETIZED, - 8000, - 0, - NULL, - 0, - 2400, - "1015/8000/1" -}; - -PayloadType speex_nb={ - PAYLOAD_AUDIO_PACKETIZED, - 8000, - 0, - NULL, - 0, - 15000, - "speex/8000/1" -}; - -PayloadType speex_nb_lbr={ - PAYLOAD_AUDIO_PACKETIZED, - 8000, - 0, - NULL, - 0, - 8000, - "speex-lbr/8000/1" -}; - -void media_api_init() -{ - ortp_init(); - ortp_set_debug_file("oRTP",NULL); - rtp_profile_set_payload(&av_profile,115,&lpc1015); - rtp_profile_set_payload(&av_profile,110,&speex_nb); - rtp_profile_set_payload(&av_profile,111,&speex_nb_lbr); - rtp_profile_set_payload(&av_profile,101,&telephone_event); - ms_init(); - ms_speex_codec_init(); -#ifdef HAVE_AVCODEC - ms_AVCodec_init(); -#endif -} - - diff --git a/media_api/media_api.h b/media_api/media_api.h deleted file mode 100644 index b7341fc4a..000000000 --- a/media_api/media_api.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - The objective of the media_api is to construct and run the necessary processing - on audio and video data flows for a given call (two party call) or conference. - Copyright (C) 2001 Sharath Udupa skuds@gmx.net - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version - - This library 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 - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -#ifndef MEDIA_API_H -#define MEDIA_API_H - -/* some mediastreamer include files....*/ - -#include "ms.h" - -/* audio codecs ; all these header are not really required as we should use ms_codec_new..() to -create codec filters*/ -/*Commented by Sharath Udupa -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef BUILD_FFMPEG -#include -#include */ -#endif - -/* some usefull filters of the mediastreamer */ -#include "mscopy.h" -#include "msfdispatcher.h" -#include "msqdispatcher.h" - -/* some synchronisation sources */ -#include -#include - -/* some streams sources and sinks */ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#endif - - - diff --git a/media_api/mediaflow.c b/media_api/mediaflow.c deleted file mode 100644 index e0e6be403..000000000 --- a/media_api/mediaflow.c +++ /dev/null @@ -1,179 +0,0 @@ -/* - The objective of the media_api is to construct and run the necessary processing - on audio and video data flows for a given call (two party call) or conference. - Copyright (C) 2001 Sharath Udupa skuds@gmx.net - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library 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 - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ -#include "common.h" -#include "mediaflow.h" -#include "callmember.h" - - -MediaFlow *media_flow_new(char *id_string, int type){ - MediaFlow *flow = (MediaFlow *) g_malloc(sizeof(MediaFlow)); //malloc required? - api_trace("media_flow_new: creating %s",id_string); - flow->id = id_string; - flow->type = type; - flow->flowDirections = NULL; - flow->members = NULL; - return flow; -} - -int media_flow_destroy(MediaFlow *flow){ - g_free(flow); - return 1; -} - -int media_flow_setup_fd(MediaFlow *flow, CallMember* csource, CallMember *cdestination, int direction){ - GList *source, *destination; - char *dir; - FlowDirections *fd = (FlowDirections *) g_malloc(sizeof(FlowDirections)); - if(direction == MEDIA_FLOW_DUPLEX) dir = "DUPLEX"; - else if(direction == MEDIA_FLOW_HALF_DUPLEX) dir = "HALF_DUPLEX"; - api_trace("media_flow_setup_fd: setting up %s flow for %s , %s",dir, csource->name, cdestination->name); - source = g_list_find_custom(flow->members, csource, &find); - destination =g_list_find_custom(flow->members, cdestination, &find); - if(source == NULL){ - api_error("media_flow_setup_fd: Invalid source %s specified", csource->name); - } - if(destination == NULL){ - api_error("media_flow_setup_fd: Invalid destination %s specified", cdestination->name); - //ERROR handling to be done here - } - fd->source = (Members*)source->data; - fd->destination = (Members*)destination->data; - fd->type = direction; - flow->flowDirections = g_list_append(flow->flowDirections, fd); - return 1; -} - -int find(gconstpointer mem, gconstpointer cmember){ - if(!strcmp(((Members*)mem)->member->name, ((CallMember*)cmember)->name)){ - return 0; - } - return 1; -} - -int media_flow_start_fd(FlowDirections *fd, MSSync *sync){ - Members *source, *destination; - source = fd->source; - destination = fd->destination; - if(fd->type == MEDIA_FLOW_DUPLEX){ - fd->recv = set_MSFilter(source->tx_endpoint,1,fd); - fd->dec = set_CODECFilter(source->member->profile, source->tx_endpoint->pt,MEDIA_API_DECODER); - fd->play = set_MSFilter(destination->rx_endpoint,0,fd); - - ms_filter_add_link(fd->recv,fd->dec); - ms_filter_add_link(fd->dec,fd->play); - ms_sync_attach(sync, fd->recv); - - fd->read = set_MSFilter(destination->tx_endpoint,1,fd); - fd->enc = set_CODECFilter(destination->member->profile, destination->tx_endpoint->pt,MEDIA_API_ENCODER); - fd->send = set_MSFilter(source->rx_endpoint,0,fd); - - ms_filter_add_link(fd->read, fd->enc); - ms_filter_add_link(fd->enc, fd->send); - ms_sync_attach(sync, fd->read); - - } - else if(fd->type == MEDIA_FLOW_HALF_DUPLEX){ - - fd->recv = set_MSFilter(source->tx_endpoint,1,fd); - fd->dec = set_CODECFilter(sourcec->member->profile, source->tx_endpoint->pt,MEDIA_API_DECODER); - fd->play = set_MSFilter(destination->rx_endpoint,0,fd); - - ms_filter_add_link(fd->recv,fd->dec); - ms_filter_add_link(fd->dec,fd->play); - ms_sync_attach(sync, fd->recv); - } - return 1; -} - - -MSFilter *set_MSFilter(EndPoint *endpoint, int type, FlowDirections *fdir){ - MSFilter *filter; - RtpSession *rtps; - switch(endpoint->protocol){ - case MEDIA_RTP: - rtps = rtp_session_new(RTP_SESSION_RECVONLY); - rtp_session_set_local_addr(rtps,"0.0.0.0",8000,8001); - rtp_session_set_scheduling_mode(rtps,0); - rtp_session_set_blocking_mode(rtps,0); - - if(type == 1){ - filter = ms_rtp_recv_new(); - ms_rtp_recv_set_session(MS_RTP_RECV(filter), rtps); - fdir->rtpSessions = g_list_append(fdir->rtpSessions, rtps); - return filter; - } - else{ - //ms_rtp_send_new - } - case MEDIA_OSS: - if(type == 1){ - filter = ms_oss_read_new(); - ms_sound_read_set_device(MS_SOUND_READ(filter),0); - return filter; - } - else{ - filter = ms_oss_write_new(); - ms_sound_write_set_device(MS_SOUND_WRITE(filter),0); - return filter; - } - case MEDIA_FILE: - if(type == 1){ - filter = ms_read_new(endpoint->file); - return filter; - } - if(type == 0){ - filter = ms_write_new(endpoint->file); - return filter; - } - - } -} - -MSFilter *set_CODECFilter(RtpProfile *profile, int pt, int mode){ - PayloadType *payload; - - switch(mode){ - case MEDIA_API_DECODER: - payload = rtp_profile_get_payload(profile, pt); - if(payload == NULL){ - api_error("media_api: undefined payload in URL\n"); - return NULL; - } - return ms_decoder_new_with_string_id(payload->mime_type); - - //Commented this to include the new RtpProfile - /*if(pt != -1) return ms_decoder_new_with_pt(pt); - *else return ms_copy_new(); - */ - case MEDIA_API_ENCODER: - - payload = rtp_profile_get_payload(profile, pt); - if(payload == NULL){ - api_error("media_api: undefined payload in URL\n"); - return NULL; - } - return ms_encoder_new_with_string_id(payload->mime_type); - /*if(pt != -1) return ms_encoder_new_with_pt(pt); - *else return ms_copy_new(); - */ - } -} - - diff --git a/media_api/mediaflow.h b/media_api/mediaflow.h deleted file mode 100644 index 598df4d98..000000000 --- a/media_api/mediaflow.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - The objective of the media_api is to construct and run the necessary processing - on audio and video data flows for a given call (two party call) or conference. - Copyright (C) 2001 Sharath Udupa skuds@gmx.net - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library 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 - Lesser General Public License for more details. - - You should have received a c:opy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -struct _MediaFlow{ - char *id; - int type; - GList *members; - GList *flowDirections; - GList *sync; //holds all the filters in this MediaFlow -}; - -typedef struct _MediaFlow MediaFlow; - -struct _Members{ - struct _CallMember *member; - struct _EndPoint *rx_endpoint; - struct _EndPoint *tx_endpoint; -}; - -typedef struct _Members Members; - -struct _FlowDirections{ - Members *source, *destination; - MSFilter *recv, - *dec, - *play; - MSFilter *read, //Filters used - *enc, //if type==DUPLEX - *send; - GList *rtpSessions; - int type; -}; - -typedef struct _FlowDirections FlowDirections; - - -MediaFlow *media_flow_new(char *id_string, int type); - -int media_flow_setup_fd(MediaFlow*, struct _CallMember *, struct _CallMember *, int); - -int media_flow_start_fd(FlowDirections *fd, MSSync *sync); - -int media_flow_destroy(MediaFlow *flow); - -/* Internal functions */ -int find(gconstpointer, gconstpointer); - -MSFilter *set_MSFilter(struct _EndPoint *, int, FlowDirections *); - -MSFilter *set_CODECFilter(RtpProfile* , int, int); - diff --git a/mediastreamer2 b/mediastreamer2 index 0e62557bf..88b9146cc 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 0e62557bfedcb090b10c81697a41d6f1b3a85e1e +Subproject commit 88b9146ccbd33c9d8d3317be92078f6211498907 diff --git a/oRTP b/oRTP index 716ac0178..b7c5f78d8 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit 716ac0178612a7416c828fd74261e4dda44930de +Subproject commit b7c5f78d83f8a310ba3700e93174c7eb1234d2d3 diff --git a/po/POTFILES.in b/po/POTFILES.in index 01deec29e..ac50ac8aa 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -1,5 +1,4 @@ # List of source files containing translatable strings. -gtk/tunnel_config.ui gtk/calllogs.c gtk/conference.c gtk/logging.c @@ -25,6 +24,8 @@ gtk/loginframe.c [type: gettext/glade]gtk/parameters.ui [type: gettext/glade]gtk/buddylookup.ui [type: gettext/glade]gtk/waiting.ui +[type: gettext/glade]gtk/dscp_settings.ui +[type: gettext/glade]gtk/tunnel_config.ui coreapi/linphonecore.c coreapi/misc.c coreapi/presence.c