diff --git a/configure.ac b/configure.ac index 34485363c..5f803f662 100644 --- a/configure.ac +++ b/configure.ac @@ -1,6 +1,6 @@ dnl Process this file with autoconf to produce a configure script. -AC_INIT([linphone],[3.3.99.6],[linphone-developers@nongnu.org]) +AC_INIT([linphone],[3.3.99.7],[linphone-developers@nongnu.org]) AC_CANONICAL_SYSTEM AC_CONFIG_SRCDIR([coreapi/linphonecore.c]) diff --git a/console/Makefile.am b/console/Makefile.am index bef1e90d1..cf6a336ed 100644 --- a/console/Makefile.am +++ b/console/Makefile.am @@ -51,6 +51,3 @@ linphonecsh_LDADD = $(ORTP_LIBS) endif - - - diff --git a/console/commands.c b/console/commands.c index 51314ccb1..d22d4b818 100644 --- a/console/commands.c +++ b/console/commands.c @@ -91,6 +91,7 @@ static int lpc_cmd_rtp_no_xmit_on_audio_mute(LinphoneCore *lc, char *args); #ifdef VIDEO_ENABLED static int lpc_cmd_camera(LinphoneCore *lc, char *args); static int lpc_cmd_video_window(LinphoneCore *lc, char *args); +static int lpc_cmd_preview_window(LinphoneCore *lc, char *args); static int lpc_cmd_snapshot(LinphoneCore *lc, char *args); #endif static int lpc_cmd_states(LinphoneCore *lc, char *args); @@ -125,7 +126,7 @@ static LPC_COMMAND *lpc_find_command(const char *name); void linphonec_out(const char *fmt,...); VideoParams lpc_video_params={-1,-1,-1,-1,0,TRUE}; - +VideoParams lpc_preview_params={-1,-1,-1,-1,0,TRUE}; /*************************************************************************** * @@ -273,7 +274,17 @@ static LPC_COMMAND advanced_commands[] = { "'vwindow show': shows video window\n" "'vwindow hide': hides video window\n" "'vwindow pos ': Moves video window to x,y pixel coordinates\n" - "'vwindow size ': Resizes video window" + "'vwindow size ': Resizes video window\n" + "'vwindow id ': embeds video display into supplied window id." + }, + { "pwindow", lpc_cmd_preview_window, "Control local camera video display (preview window)", + "'pwindow show': shows the local camera video display\n" + "'pwindow hide': hides the local camera video display\n" + "'pwindow pos ': Moves preview window to x,y pixel coordinates\n" + "'pwindow size ': Resizes preview window\n" + "'pwindow id ': embeds preview display into supplied window id.\n" + "'pwindow integrated': integrate preview display within the video window of current call.\n" + "'pwindow standalone': use standalone window for preview display." }, { "snapshot", lpc_cmd_snapshot, "Take a snapshot of currently received video stream", "'snapshot ': take a snapshot and records it in jpeg format into the supplied path\n" @@ -2200,44 +2211,62 @@ static int lpc_cmd_rtp_no_xmit_on_audio_mute(LinphoneCore *lc, char *args) } #ifdef VIDEO_ENABLED -static int lpc_cmd_video_window(LinphoneCore *lc, char *args){ +static int _lpc_cmd_video_window(LinphoneCore *lc, char *args, bool_t is_preview){ char subcommand[64]; int a,b; int err; + VideoParams *params=is_preview ? &lpc_preview_params : &lpc_video_params; if (!args) return 0; err=sscanf(args,"%s %i %i",subcommand,&a,&b); if (err>=1){ if (strcmp(subcommand,"pos")==0){ if (err<3) return 0; - lpc_video_params.x=a; - lpc_video_params.y=b; - lpc_video_params.refresh=TRUE; + params->x=a; + params->y=b; + params->refresh=TRUE; }else if (strcmp(subcommand,"size")==0){ if (err<3) return 0; - lpc_video_params.w=a; - lpc_video_params.h=b; - lpc_video_params.refresh=TRUE; + params->w=a; + params->h=b; + params->refresh=TRUE; }else if (strcmp(subcommand,"show")==0){ - lpc_video_params.show=TRUE; - lpc_video_params.refresh=TRUE; + params->show=TRUE; + params->refresh=TRUE; + if (is_preview) linphone_core_enable_video_preview (lc,TRUE); }else if (strcmp(subcommand,"hide")==0){ - lpc_video_params.show=FALSE; - lpc_video_params.refresh=TRUE; + params->show=FALSE; + params->refresh=TRUE; + if (is_preview) linphone_core_enable_video_preview (lc,FALSE); }else if (strcmp(subcommand,"id")==0){ - static char envbuf[128]; if (err == 1){ - linphonec_out("vwindow id: 0x%x / SDL_WINDOWID='%s'\n",(unsigned int)lpc_video_params.wid, getenv("SDL_WINDOWID")); + linphonec_out("vwindow id: 0x%x\n",is_preview ? linphone_core_get_native_preview_window_id (lc) : + linphone_core_get_native_video_window_id (lc)); return 1; } else if (err != 2) return 0; - lpc_video_params.wid=a; - snprintf(envbuf, sizeof(envbuf)-1, "SDL_WINDOWID=0x%x", (unsigned int)lpc_video_params.wid); - err = putenv(envbuf); - linphonec_out("vwindow id: 0x%x / SDL_WNIDOWID='%s'\n",(unsigned int)lpc_video_params.wid, getenv("SDL_WINDOWID")); + params->wid=a; + if (is_preview) + linphone_core_set_native_preview_window_id (lc,a); + else + linphone_core_set_native_video_window_id(lc,a); + }else if (is_preview==TRUE){ + if (strcmp(subcommand,"integrated")==0){ + linphone_core_use_preview_window (lc,FALSE); + }else if (strcmp(subcommand,"standalone")==0){ + linphone_core_use_preview_window(lc,TRUE); + }else return 0; }else return 0; } return 1; } + +static int lpc_cmd_video_window(LinphoneCore *lc, char *args){ + return _lpc_cmd_video_window(lc, args, FALSE); +} + +static int lpc_cmd_preview_window(LinphoneCore *lc, char *args){ + return _lpc_cmd_video_window(lc, args, TRUE); +} #endif static void lpc_display_global_state(LinphoneCore *lc){ diff --git a/console/linphonec.c b/console/linphonec.c index 6948776ce..ef1760ee4 100644 --- a/console/linphonec.c +++ b/console/linphonec.c @@ -177,7 +177,6 @@ static ortp_pipe_t server_sock; bool_t linphonec_camera_enabled=TRUE; -extern VideoParams lpc_video_params; void linphonec_call_identify(LinphoneCall* call){ static long callid=1; @@ -869,63 +868,68 @@ usage: linphonec [-c file] [-s sipaddr] [-a] [-V] [-d level ] [-l logfile]\n\ #ifdef VIDEO_ENABLED #ifdef HAVE_X11_XLIB_H -static void sdl_x11_apply_video_params(){ - static SDL_SysWMinfo info; - bool_t wminfo_ready=FALSE; - - - SDL_VERSION(&info.version); - if ( SDL_GetWMInfo(&info) ) { - if ( info.subsystem == SDL_SYSWM_X11 ) { - wminfo_ready=TRUE; - } +static void x11_apply_video_params(VideoParams *params, Window window){ + XWindowChanges wc; + unsigned int flags=0; + static Display *display = NULL; + const char *dname=getenv("DISPLAY"); + + if (display==NULL && dname!=NULL){ + display=XOpenDisplay(dname); } - - if ( !wminfo_ready) return; - - { - XWindowChanges wc; - unsigned int flags=0; - Display *display = info.info.x11.display; - Window window = info.info.x11.wmwindow; - - memset(&wc,0,sizeof(wc)); - wc.x=lpc_video_params.x; - wc.y=lpc_video_params.y; - wc.width=lpc_video_params.w; - wc.height=lpc_video_params.h; - if (lpc_video_params.x!=-1 ){ - flags|=CWX|CWY; - } - if (lpc_video_params.w!=-1){ - flags|=CWWidth|CWHeight; - } - info.info.x11.lock_func(); - XConfigureWindow(display,window,flags,&wc); - if (lpc_video_params.show) - XMapWindow(display,window); - else - XUnmapWindow(display,window); - info.info.x11.unlock_func(); + + if (display==NULL){ + ms_error("Could not open display %s",dname); + return; } + memset(&wc,0,sizeof(wc)); + wc.x=params->x; + wc.y=params->y; + wc.width=params->w; + wc.height=params->h; + if (params->x!=-1 ){ + flags|=CWX|CWY; + } + if (params->w!=-1){ + flags|=CWWidth|CWHeight; + } + /*printf("XConfigureWindow x=%i,y=%i,w=%i,h=%i\n", + wc.x, wc.y ,wc.width, wc.height);*/ + XConfigureWindow(display,window,flags,&wc); + if (params->show) + XMapWindow(display,window); + else + XUnmapWindow(display,window); + XSync(display,FALSE); } #endif static void lpc_apply_video_params(){ - static unsigned long prev_wid=0; - + static unsigned long old_wid=0,old_pwid=0; unsigned long wid=linphone_core_get_native_video_window_id (linphonec); + unsigned long pwid=linphone_core_get_native_preview_window_id (linphonec); - if (wid!=0 && (lpc_video_params.refresh || prev_wid!=wid)){ + if (wid!=0 && (lpc_video_params.refresh || old_wid!=wid)){ lpc_video_params.refresh=FALSE; #ifdef HAVE_X11_XLIB_H if (lpc_video_params.wid==0){ // do not manage window if embedded - sdl_x11_apply_video_params(); + x11_apply_video_params(&lpc_video_params,wid); } #endif } - prev_wid=wid; + old_wid=wid; + if (pwid!=0 && (lpc_preview_params.refresh || old_pwid!=pwid)){ + lpc_preview_params.refresh=FALSE; +#ifdef HAVE_X11_XLIB_H + /*printf("wid=%lu pwid=%lu\n",wid,pwid);*/ + if (lpc_preview_params.wid==0){ // do not manage window if embedded + printf("Refreshing\n"); + x11_apply_video_params(&lpc_preview_params,pwid); + } +#endif + } + old_pwid=pwid; } #endif diff --git a/console/linphonec.h b/console/linphonec.h index f38319ac0..9d7487b97 100644 --- a/console/linphonec.h +++ b/console/linphonec.h @@ -104,6 +104,10 @@ typedef struct { bool_t refresh; } VideoParams; + +extern VideoParams lpc_video_params; +extern VideoParams lpc_preview_params; + /*************************************************************************** * * Forward declarations diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index 2b9400e67..add616d85 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -297,6 +297,8 @@ static void call_ack(SalOp *op){ static void call_updating(SalOp *op){ LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op)); LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op); + LinphoneCallState prevstate=LinphoneCallIdle; + if (call->resultdesc) sal_media_description_unref(call->resultdesc); call->resultdesc=sal_call_get_final_media_description(op); @@ -319,7 +321,9 @@ static void call_updating(SalOp *op){ linphone_call_set_state (call,LinphoneCallStreamsRunning,"Connected (streams running)"); } else if(call->state==LinphoneCallStreamsRunning && - sal_media_description_has_dir(call->resultdesc,SalStreamRecvOnly) && !strcmp(call->resultdesc->addr,"0.0.0.0")){ + ( sal_media_description_has_dir(call->resultdesc,SalStreamRecvOnly) + || sal_media_description_has_dir(call->resultdesc,SalStreamInactive) + || strcmp(call->resultdesc->addr,"0.0.0.0")==0)){ if(lc->vtable.display_status) lc->vtable.display_status(lc,_("We are being paused...")); linphone_call_set_state (call,LinphoneCallPausedByRemote,"Call paused by remote"); @@ -327,6 +331,7 @@ static void call_updating(SalOp *op){ ms_error("Inconsitency detected: current call is %p but call %p is being paused !",lc->current_call,call); } }else{ + prevstate=call->state; linphone_call_set_state(call, LinphoneCallUpdatedByRemote,"Call updated by remote"); } /*accept the modification (sends a 200Ok)*/ @@ -334,6 +339,9 @@ static void call_updating(SalOp *op){ linphone_call_stop_media_streams (call); linphone_call_init_media_streams (call); linphone_call_start_media_streams (call); + if (prevstate!=LinphoneCallIdle){ + linphone_call_set_state (call,prevstate,"Connected (streams running)"); + } } if (lc->current_call==NULL) linphone_core_start_pending_refered_calls (lc); } diff --git a/coreapi/chat.c b/coreapi/chat.c index 357267962..3a41b4c9f 100644 --- a/coreapi/chat.c +++ b/coreapi/chat.c @@ -33,7 +33,6 @@ cr->lc=lc; cr->peer=linphone_address_as_string(parsed_url); cr->peer_url=parsed_url; - cr->route=ms_strdup(linphone_core_get_route(lc)); lc->chatrooms=ms_list_append(lc->chatrooms,(void *)cr); return cr; } @@ -46,11 +45,13 @@ lc->chatrooms=ms_list_remove(lc->chatrooms,(void *) cr); linphone_address_destroy(cr->peer_url); ms_free(cr->peer); - ms_free(cr->route); + if (cr->op) + sal_op_release(cr->op); } void linphone_chat_room_send_message(LinphoneChatRoom *cr, const char *msg){ - const char *identity=linphone_core_get_identity(cr->lc); + const char *route=NULL; + const char *identity=linphone_core_find_best_identity(cr->lc,cr->peer_url,&route); SalOp *op; LinphoneCall *call; if((call = linphone_core_get_call_by_remote_address(cr->lc,cr->peer))!=NULL) @@ -61,7 +62,12 @@ void linphone_chat_room_send_message(LinphoneChatRoom *cr, const char *msg){ else { op = sal_op_new(cr->lc->sal); - sal_op_set_route(op,cr->route); + sal_op_set_route(op,route); + if (cr->op!=NULL){ + sal_op_release (cr->op); + cr->op=NULL; + } + cr->op=op; } sal_text_send(op,identity,cr->peer,msg); } diff --git a/coreapi/friend.c b/coreapi/friend.c index a1bf5c1f8..451f8ad64 100644 --- a/coreapi/friend.c +++ b/coreapi/friend.c @@ -128,6 +128,7 @@ void __linphone_friend_do_subscribe(LinphoneFriend *fr){ char *friend=NULL; const char *route=NULL; const char *from=NULL; + const char *fixed_contact=NULL; LinphoneProxyConfig *cfg; friend=linphone_address_as_string(fr->uri); @@ -135,6 +136,12 @@ void __linphone_friend_do_subscribe(LinphoneFriend *fr){ if (cfg!=NULL){ route=linphone_proxy_config_get_route(cfg); from=linphone_proxy_config_get_identity(cfg); + if (cfg->op){ + fixed_contact=sal_op_get_contact(cfg->op); + if (fixed_contact) { + ms_message("Contact for subscribe has been fixed using proxy to %s",fixed_contact); + } + } }else from=linphone_core_get_primary_contact(fr->lc); if (fr->outsub==NULL){ /* people for which we don't have yet an answer should appear as offline */ @@ -149,6 +156,7 @@ void __linphone_friend_do_subscribe(LinphoneFriend *fr){ } fr->outsub=sal_op_new(fr->lc->sal); sal_op_set_route(fr->outsub,route); + sal_op_set_contact(fr->outsub,fixed_contact); sal_subscribe_presence(fr->outsub,from,friend); fr->subscribe_active=TRUE; ms_free(friend); @@ -367,6 +375,7 @@ void linphone_friend_apply(LinphoneFriend *fr, LinphoneCore *lc){ } ms_message("linphone_friend_apply() done."); lc->bl_refresh=TRUE; + fr->commit=FALSE; } void linphone_friend_edit(LinphoneFriend *fr){ @@ -391,7 +400,8 @@ void linphone_core_add_friend(LinphoneCore *lc, LinphoneFriend *lf) return ; } lc->friends=ms_list_append(lc->friends,lf); - linphone_friend_apply(lf,lc); + if ( linphone_core_ready(lc)) linphone_friend_apply(lf,lc); + else lf->commit=TRUE; return ; } @@ -404,6 +414,15 @@ void linphone_core_remove_friend(LinphoneCore *lc, LinphoneFriend* fl){ } } +void linphone_core_send_initial_subscribes(LinphoneCore *lc){ + const MSList *elem; + for(elem=lc->friends;elem!=NULL;elem=elem->next){ + LinphoneFriend *f=(LinphoneFriend*)elem->data; + if (f->commit) + linphone_friend_apply(f,lc); + } +} + void linphone_friend_set_ref_key(LinphoneFriend *lf, const char *key){ if (lf->refkey!=NULL){ ms_free(lf->refkey); @@ -562,7 +581,7 @@ void linphone_core_write_friends_config(LinphoneCore* lc) { MSList *elem; int i; - if (!lc->ready) return; /*dont write config when reading it !*/ + if (! linphone_core_ready(lc)) return; /*dont write config when reading it !*/ for (elem=lc->friends,i=0; elem!=NULL; elem=ms_list_next(elem),i++){ linphone_friend_write_to_config_file(lc->config,(LinphoneFriend*)elem->data,i); } diff --git a/coreapi/help/Makefile.am b/coreapi/help/Makefile.am index c24672180..4ded6c77f 100644 --- a/coreapi/help/Makefile.am +++ b/coreapi/help/Makefile.am @@ -1,7 +1,7 @@ EXTRA_DIST = Doxyfile.in doxygen.dox -SOURCES= doxygen.dox *.c $(top_srcdir)/coreapi/*.c $(top_srcdir)/coreapi/*.h +SOURCES= doxygen.dox $(top_srcdir)/coreapi/help/*.c $(top_srcdir)/coreapi/*.c $(top_srcdir)/coreapi/*.h #html doc diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 62d4fa6c2..8139bbdb2 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -824,7 +824,12 @@ static void _linphone_call_start_media_streams(LinphoneCall *call, bool_t send_e video_stream_set_sent_video_size(call->videostream,linphone_core_get_preferred_video_size(lc)); video_stream_enable_self_view(call->videostream,lc->video_conf.selfview); - + if (lc->video_window_id!=0) + video_stream_set_native_window_id(call->videostream,lc->video_window_id); + if (lc->preview_window_id!=0) + video_stream_set_native_preview_window_id (call->videostream,lc->preview_window_id); + video_stream_use_preview_video_window (call->videostream,lc->use_preview_window); + if (stream->dir==SalStreamSendOnly && lc->video_conf.capture ){ cam=get_nowebcam_device(); dir=VideoStreamSendOnly; diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 5339e4b3b..b9e7fe518 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -38,7 +38,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. /*#define UNSTANDART_GSM_11K 1*/ static const char *liblinphone_version=LIBLINPHONE_VERSION; -static void set_network_reachable(LinphoneCore* lc,bool_t isReachable); +static void set_network_reachable(LinphoneCore* lc,bool_t isReachable, time_t curtime); #include "enum.h" @@ -52,6 +52,7 @@ static void toggle_video_preview(LinphoneCore *lc, bool_t val); extern SalCallbacks linphone_sal_callbacks; + void lc_callback_obj_init(LCCallbackObj *obj,LinphoneCoreCbFunc func,void* ud) { obj->_func=func; @@ -103,7 +104,7 @@ static void call_logs_write_to_config_file(LinphoneCore *lc){ char *tmp; LpConfig *cfg=lc->config; - if (!lc->ready) return; + if (linphone_core_get_global_state (lc)==LinphoneGlobalStartup) return; for(i=0,elem=lc->call_logs;elem!=NULL;elem=elem->next,++i){ LinphoneCallLog *cl=(LinphoneCallLog*)elem->data; @@ -996,10 +997,8 @@ static void linphone_core_init (LinphoneCore * lc, const LinphoneCoreVTable *vta ui_config_read(lc); if (lc->vtable.display_status) lc->vtable.display_status(lc,_("Ready")); - linphone_core_set_state(lc,LinphoneGlobalOn,"Ready"); lc->auto_net_state_mon=lc->sip_conf.auto_net_state_mon; - - lc->ready=TRUE; + linphone_core_set_state(lc,LinphoneGlobalOn,"Ready"); } /** @@ -1529,7 +1528,7 @@ static void monitor_network_state(LinphoneCore *lc, time_t curtime){ if (new_status){ ms_message("New local ip address is %s",result); } - set_network_reachable(lc,new_status); + set_network_reachable(lc,new_status, curtime); last_status=new_status; } } @@ -1724,6 +1723,12 @@ void linphone_core_iterate(LinphoneCore *lc){ linphone_core_do_plugin_tasks(lc); + if (lc->initial_subscribes_sent==FALSE && lc->netup_time!=0 && + (curtime-lc->netup_time)>3){ + linphone_core_send_initial_subscribes(lc); + lc->initial_subscribes_sent=TRUE; + } + if (one_second_elapsed && lp_config_needs_commit(lc->config)){ lp_config_sync(lc->config); } @@ -1861,6 +1866,17 @@ LinphoneProxyConfig * linphone_core_lookup_known_proxy(LinphoneCore *lc, const L return found_cfg; } +const char *linphone_core_find_best_identity(LinphoneCore *lc, const LinphoneAddress *to, const char **route){ + LinphoneProxyConfig *cfg=linphone_core_lookup_known_proxy(lc,to); + if (cfg==NULL) + linphone_core_get_default_proxy (lc,&cfg); + if (cfg!=NULL){ + *route=linphone_proxy_config_get_route(cfg); + return linphone_proxy_config_get_identity (cfg); + } + return linphone_core_get_primary_contact (lc); +} + static char *get_fixed_contact(LinphoneCore *lc, LinphoneCall *call , LinphoneProxyConfig *dest_proxy){ LinphoneAddress *ctt; const char *localip=call->localip; @@ -2669,7 +2685,7 @@ bool_t linphone_core_sound_device_can_playback(LinphoneCore *lc, const char *dev int linphone_core_set_ringer_device(LinphoneCore *lc, const char * devid){ MSSndCard *card=get_card_from_string_id(devid,MS_SND_CARD_CAP_PLAYBACK); lc->sound_conf.ring_sndcard=card; - if (card && lc->ready) + if (card && linphone_core_ready(lc)) lp_config_set_string(lc->config,"sound","ringer_dev_id",ms_snd_card_get_string_id(card)); return 0; } @@ -2683,7 +2699,7 @@ int linphone_core_set_ringer_device(LinphoneCore *lc, const char * devid){ int linphone_core_set_playback_device(LinphoneCore *lc, const char * devid){ MSSndCard *card=get_card_from_string_id(devid,MS_SND_CARD_CAP_PLAYBACK); lc->sound_conf.play_sndcard=card; - if (card && lc->ready) + if (card && linphone_core_ready(lc)) lp_config_set_string(lc->config,"sound","playback_dev_id",ms_snd_card_get_string_id(card)); return 0; } @@ -2697,7 +2713,7 @@ int linphone_core_set_playback_device(LinphoneCore *lc, const char * devid){ int linphone_core_set_capture_device(LinphoneCore *lc, const char * devid){ MSSndCard *card=get_card_from_string_id(devid,MS_SND_CARD_CAP_CAPTURE); lc->sound_conf.capt_sndcard=card; - if (card && lc->ready) + if (card && linphone_core_ready(lc)) lp_config_set_string(lc->config,"sound","capture_dev_id",ms_snd_card_get_string_id(card)); return 0; } @@ -2788,7 +2804,7 @@ void linphone_core_set_ring(LinphoneCore *lc,const char *path){ ms_free(lc->sound_conf.local_ring); } lc->sound_conf.local_ring=ms_strdup(path); - if (lc->ready && lc->sound_conf.local_ring) + if ( linphone_core_ready(lc) && lc->sound_conf.local_ring) lp_config_set_string(lc->config,"sound","local_ring",lc->sound_conf.local_ring); } @@ -2852,7 +2868,7 @@ const char * linphone_core_get_ringback(const LinphoneCore *lc){ **/ void linphone_core_enable_echo_cancellation(LinphoneCore *lc, bool_t val){ lc->sound_conf.ec=val; - if (lc->ready) + if ( linphone_core_ready(lc)) lp_config_set_int(lc->config,"sound","echocancellation",val); } @@ -3042,8 +3058,13 @@ static void toggle_video_preview(LinphoneCore *lc, bool_t val){ #ifdef VIDEO_ENABLED if (val){ if (lc->previewstream==NULL){ - lc->previewstream=video_preview_start(lc->video_conf.device, - lc->video_conf.vsize,lc->video_conf.displaytype); + lc->previewstream=video_preview_new(); + video_preview_set_size(lc->previewstream,lc->video_conf.vsize); + if (lc->video_conf.displaytype) + video_preview_set_display_filter_name(lc->previewstream,lc->video_conf.displaytype); + if (lc->preview_window_id!=0) + video_preview_set_native_window_id(lc->previewstream,lc->preview_window_id); + video_preview_start(lc->previewstream,lc->video_conf.device); } }else{ if (lc->previewstream!=NULL){ @@ -3157,7 +3178,7 @@ int linphone_core_set_video_device(LinphoneCore *lc, const char *id){ if (olddev!=NULL && olddev!=lc->video_conf.device){ toggle_video_preview(lc,FALSE);/*restart the video local preview*/ } - if (lc->ready && lc->video_conf.device){ + if ( linphone_core_ready(lc) && lc->video_conf.device){ vd=ms_web_cam_get_string_id(lc->video_conf.device); if (vd && strstr(vd,"Static picture")!=NULL){ vd=NULL; @@ -3269,7 +3290,49 @@ unsigned long linphone_core_get_native_video_window_id(const LinphoneCore *lc){ if (lc->previewstream) return video_stream_get_native_window_id(lc->previewstream); #endif - return 0; + return lc->video_window_id; +} + +/** + * Set the native video window id where the video is to be displayed. + * If not set the core will create its own window. +**/ +void linphone_core_set_native_video_window_id(LinphoneCore *lc, unsigned long id){ + lc->video_window_id=id; +} + +/** + * Returns the native window handle of the video preview window, casted as an unsigned long. + * + * @ingroup media_parameters +**/ +unsigned long linphone_core_get_native_preview_window_id(const LinphoneCore *lc){ +#ifdef VIDEO_ENABLED + LinphoneCall *call=linphone_core_get_current_call (lc); + if (call && call->videostream) + return video_stream_get_native_preview_window_id(call->videostream); + if (lc->previewstream) + return video_preview_get_native_window_id(lc->previewstream); +#endif + return lc->preview_window_id; +} + +/** + * Set the native window id where the preview video (local camera) is to be displayed. + * This has to be used in conjonction with linphone_core_use_preview_window(). + * If not set the core will create its own window. +**/ +void linphone_core_set_native_preview_window_id(LinphoneCore *lc, unsigned long id){ + lc->preview_window_id=id; +} + +/** + * Tells the core to use a separate window for local camera preview video, instead of + * inserting local view within the remote video window. + * +**/ +void linphone_core_use_preview_window(LinphoneCore *lc, bool_t yesno){ + lc->use_preview_window=yesno; } static MSVideoSizeDef supported_resolutions[]={ @@ -3334,7 +3397,7 @@ void linphone_core_set_preferred_video_size(LinphoneCore *lc, MSVideoSize vsize) toggle_video_preview(lc,FALSE); toggle_video_preview(lc,TRUE); } - if (lc->ready) + if ( linphone_core_ready(lc)) lp_config_set_string(lc->config,"video","size",video_size_get_name(vsize)); } } @@ -3751,7 +3814,7 @@ static void linphone_core_uninit(LinphoneCore *lc) linphone_core_set_state(lc,LinphoneGlobalOff,"Off"); } -static void set_network_reachable(LinphoneCore* lc,bool_t isReachable){ +static void set_network_reachable(LinphoneCore* lc,bool_t isReachable, time_t curtime){ ms_message("Network state is now [%s]",isReachable?"UP":"DOWN"); // second get the list of available proxies const MSList *elem=linphone_core_get_proxy_config_list(lc); @@ -3765,6 +3828,7 @@ static void set_network_reachable(LinphoneCore* lc,bool_t isReachable){ } } } + lc->netup_time=curtime; lc->network_reachable=isReachable; } @@ -3774,7 +3838,7 @@ void linphone_core_set_network_reachable(LinphoneCore* lc,bool_t isReachable) { ms_message("Disabling automatic network state monitoring"); lc->auto_net_state_mon=FALSE; } - set_network_reachable(lc,isReachable); + set_network_reachable(lc,isReachable, ms_time(NULL)); } bool_t linphone_core_is_network_reachabled(LinphoneCore* lc) { diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 29e79a7b4..f8fd75b39 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -800,7 +800,12 @@ float linphone_core_get_static_picture_fps(LinphoneCore *lc); /*function to be used for eventually setting window decorations (icons, title...)*/ unsigned long linphone_core_get_native_video_window_id(const LinphoneCore *lc); +void linphone_core_set_native_video_window_id(LinphoneCore *lc, unsigned long id); +unsigned long linphone_core_get_native_preview_window_id(const LinphoneCore *lc); +void linphone_core_set_native_preview_window_id(LinphoneCore *lc, unsigned long id); + +void linphone_core_use_preview_window(LinphoneCore *lc, bool_t yesno); /*play/record support: use files instead of soundcard*/ void linphone_core_use_files(LinphoneCore *lc, bool_t yesno); diff --git a/coreapi/presence.c b/coreapi/presence.c index 30c9c7e6a..d97f4ed94 100644 --- a/coreapi/presence.c +++ b/coreapi/presence.c @@ -57,11 +57,24 @@ void linphone_subscription_new(LinphoneCore *lc, SalOp *op, const char *from){ LinphoneFriend *lf=NULL; char *tmp; LinphoneAddress *uri; + LinphoneProxyConfig *cfg; + const char *fixed_contact; uri=linphone_address_new(from); linphone_address_clean(uri); tmp=linphone_address_as_string(uri); ms_message("Receiving new subscription from %s.",from); + + cfg=linphone_core_lookup_known_proxy(lc,uri); + if (cfg!=NULL){ + if (cfg->op){ + fixed_contact=sal_op_get_contact(cfg->op); + if (fixed_contact) { + sal_op_set_contact (op,fixed_contact); + ms_message("Contact for next subscribe answer has been fixed using proxy to %s",fixed_contact); + } + } + } /* check if we answer to this subscription */ if (linphone_find_friend(lc->friends,uri,&lf)!=NULL){ lf->insub=op; diff --git a/coreapi/private.h b/coreapi/private.h index b0c95485e..9bee983b6 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -31,6 +31,7 @@ #ifdef HAVE_CONFIG_H #include "config.h" #endif +#include "mediastreamer2/mediastream.h" #ifndef LIBLINPHONE_VERSION #define LIBLINPHONE_VERSION LINPHONE_VERSION @@ -165,6 +166,7 @@ void linphone_core_update_allocated_audio_bandwidth(LinphoneCore *lc); void linphone_core_update_allocated_audio_bandwidth_in_call(LinphoneCore *lc, const PayloadType *pt); void linphone_core_run_stun_tests(LinphoneCore *lc, LinphoneCall *call); +void linphone_core_send_initial_subscribes(LinphoneCore *lc); void linphone_core_write_friends_config(LinphoneCore* lc); void linphone_friend_write_to_config_file(struct _LpConfig *config, LinphoneFriend *lf, int index); LinphoneFriend * linphone_friend_new_from_config_file(struct _LinphoneCore *lc, int index); @@ -172,6 +174,7 @@ LinphoneFriend * linphone_friend_new_from_config_file(struct _LinphoneCore *lc, void linphone_proxy_config_update(LinphoneProxyConfig *cfg); void linphone_proxy_config_get_contact(LinphoneProxyConfig *cfg, const char **ip, int *port); LinphoneProxyConfig * linphone_core_lookup_known_proxy(LinphoneCore *lc, const LinphoneAddress *uri); +const char *linphone_core_find_best_identity(LinphoneCore *lc, const LinphoneAddress *to, const char **route); int linphone_core_get_local_ip_for(int type, const char *dest, char *result); LinphoneProxyConfig *linphone_proxy_config_new_from_config_file(struct _LpConfig *config, int index); @@ -212,6 +215,7 @@ struct _LinphoneProxyConfig int auth_failures; char *dial_prefix; LinphoneRegistrationState state; + SalOp *publish_op; bool_t commit; bool_t reg_sendregister; bool_t registered; @@ -236,8 +240,8 @@ struct _LinphoneAuthInfo struct _LinphoneChatRoom{ struct _LinphoneCore *lc; char *peer; - char *route; LinphoneAddress *peer_url; + SalOp *op; void * user_data; }; @@ -253,6 +257,7 @@ struct _LinphoneFriend{ bool_t subscribe; bool_t subscribe_active; bool_t inc_subscribe_pending; + bool_t commit; }; @@ -389,7 +394,7 @@ struct _LinphoneCore MSList *chatrooms; int max_call_logs; int missed_calls; - struct _VideoStream *previewstream; + VideoPreview *previewstream; struct _MSEventQueue *msevq; RtpTransport *a_rtp,*a_rtcp; MSList *bl_reqs; @@ -408,13 +413,17 @@ struct _LinphoneCore int audio_bw; LinphoneWaitingCallback wait_cb; void *wait_ctx; + unsigned long video_window_id; + unsigned long preview_window_id; + time_t netup_time; /*time when network went reachable */ bool_t use_files; bool_t apply_nat_settings; - bool_t ready; + bool_t initial_subscribes_sent; bool_t bl_refresh; bool_t preview_finished; bool_t auto_net_state_mon; bool_t network_reachable; + bool_t use_preview_window; }; bool_t linphone_core_can_we_add_call(LinphoneCore *lc); @@ -428,6 +437,8 @@ void linphone_core_set_state(LinphoneCore *lc, LinphoneGlobalState gstate, const SalMediaDescription *create_local_media_description(LinphoneCore *lc, LinphoneCall *call, bool_t with_video, bool_t only_one_codec); +#define linphone_core_ready(lc) ((lc)->state!=LinphoneGlobalStartup) + #define HOLD_OFF (0) #define HOLD_ON (1) diff --git a/coreapi/proxy.c b/coreapi/proxy.c index 07a8e6c81..aa901cb8d 100644 --- a/coreapi/proxy.c +++ b/coreapi/proxy.c @@ -72,6 +72,7 @@ void linphone_proxy_config_destroy(LinphoneProxyConfig *obj){ if (obj->type!=NULL) ms_free(obj->type); if (obj->dial_prefix!=NULL) ms_free(obj->dial_prefix); if (obj->op) sal_op_release(obj->op); + if (obj->publish_op) sal_op_release(obj->publish_op); } /** @@ -166,10 +167,16 @@ int linphone_proxy_config_set_route(LinphoneProxyConfig *obj, const char *route) obj->reg_route=NULL; } if (route!=NULL){ + LinphoneAddress *addr; /*try to prepend 'sip:' */ if (strstr(route,"sip:")==NULL){ obj->reg_route=ms_strdup_printf("sip:%s",route); }else obj->reg_route=ms_strdup(route); + addr=linphone_address_new(obj->reg_route); + if (addr==NULL){ + ms_free(obj->reg_route); + obj->reg_route=NULL; + }else linphone_address_destroy(addr); } return 0; } @@ -433,7 +440,9 @@ int linphone_proxy_config_send_publish(LinphoneProxyConfig *proxy, SalOp *op=sal_op_new(proxy->lc->sal); err=sal_publish(op,linphone_proxy_config_get_identity(proxy), linphone_proxy_config_get_identity(proxy),linphone_online_status_to_sal(presence_mode)); - sal_op_release(op); + if (proxy->publish_op!=NULL) + sal_op_release(proxy->publish_op); + proxy->publish_op=op; return err; } @@ -691,8 +700,11 @@ void linphone_proxy_config_update(LinphoneProxyConfig *cfg){ if (cfg->type && cfg->ssctx==NULL){ linphone_proxy_config_activate_sip_setup(cfg); } - if (lc->sip_conf.register_only_when_network_is_up || lc->network_reachable) + if (!lc->sip_conf.register_only_when_network_is_up || lc->network_reachable) linphone_proxy_config_register(cfg); + if (cfg->publish && cfg->publish_op==NULL){ + linphone_proxy_config_send_publish(cfg,lc->presence_mode); + } cfg->commit=FALSE; } } diff --git a/coreapi/sal.h b/coreapi/sal.h index 9f97c5239..0fcd6e5a8 100644 --- a/coreapi/sal.h +++ b/coreapi/sal.h @@ -284,6 +284,8 @@ int sal_call_update(SalOp *h); SalMediaDescription * sal_call_get_final_media_description(SalOp *h); int sal_refer(SalOp *h, const char *refer_to); int sal_refer_accept(SalOp *h); +/* returns the SalOp of a call that should be replaced by h, if any */ +SalOp *sal_call_get_replaces(SalOp *h); int sal_call_send_dtmf(SalOp *h, char dtmf); int sal_call_terminate(SalOp *h); bool_t sal_call_autoanswer_asked(SalOp *op); diff --git a/coreapi/sal_eXosip2.c b/coreapi/sal_eXosip2.c index a7fa26b16..c61ec96ab 100644 --- a/coreapi/sal_eXosip2.c +++ b/coreapi/sal_eXosip2.c @@ -26,7 +26,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. static void text_received(Sal *sal, eXosip_event_t *ev); -static void _osip_list_set_empty(osip_list_t *l, void (*freefunc)(void*)){ +void _osip_list_set_empty(osip_list_t *l, void (*freefunc)(void*)){ void *data; while((data=osip_list_get(l,0))!=NULL){ osip_list_remove(l,0); @@ -102,7 +102,7 @@ static SalOp * sal_find_other(Sal *sal, osip_message_t *response){ return NULL; } -static void sal_add_other(Sal *sal, SalOp *op, osip_message_t *request){ +void sal_add_other(Sal *sal, SalOp *op, osip_message_t *request){ osip_call_id_t *callid=osip_message_get_call_id(request); if (callid==NULL) { ms_error("There is no call id in the request !"); @@ -161,6 +161,7 @@ SalOp * sal_op_new(Sal *sal){ op->sdp_answer=NULL; op->reinvite=FALSE; op->call_id=NULL; + op->replaces=NULL; op->masquerade_via=FALSE; op->auto_answer_asked=FALSE; return op; @@ -201,6 +202,9 @@ void sal_op_release(SalOp *op){ sal_remove_other(op->base.root,op); osip_call_id_free(op->call_id); } + if (op->replaces){ + ms_free(op->replaces); + } __sal_op_free(op); } @@ -655,6 +659,20 @@ int sal_refer(SalOp *h, const char *refer_to){ return err; } +SalOp *sal_call_get_replaces(SalOp *h){ + if (h->replaces!=NULL){ + int cid; + eXosip_lock(); + cid=eXosip_call_find_by_replaces(h->replaces); + eXosip_unlock(); + if (cid>0){ + SalOp *ret=sal_find_call(h->base.root,cid); + return ret; + } + } + return NULL; +} + int sal_call_send_dtmf(SalOp *h, char dtmf){ osip_message_t *msg=NULL; char dtmf_body[128]; @@ -732,6 +750,21 @@ static void set_remote_ua(SalOp* op, osip_message_t *req){ } } +static void set_replaces(SalOp *op, osip_message_t *req){ + osip_header_t *h=NULL; + + if (op->replaces){ + ms_free(op->replaces); + op->replaces=NULL; + } + osip_message_header_get_byname(req,"replaces",0,&h); + if (h){ + if (h->hvalue && h->hvalue[0]!='\0'){ + op->replaces=ms_strdup(h->hvalue); + } + } +} + static SalOp *find_op(Sal *sal, eXosip_event_t *ev){ if (ev->cid>0){ return sal_find_call(sal,ev->cid); @@ -739,6 +772,9 @@ static SalOp *find_op(Sal *sal, eXosip_event_t *ev){ if (ev->rid>0){ return sal_find_register(sal,ev->rid); } + if (ev->sid>0){ + return sal_find_out_subscribe(sal,ev->sid); + } if (ev->response) return sal_find_other(sal,ev->response); return NULL; } @@ -752,6 +788,7 @@ static void inc_new_call(Sal *sal, eXosip_event_t *ev){ set_network_origin(op,ev->request); set_remote_ua(op,ev->request); + set_replaces(op,ev->request); if (sdp){ op->sdp_offering=FALSE; diff --git a/coreapi/sal_eXosip2.h b/coreapi/sal_eXosip2.h index 5f2c681d1..bfb3d10f2 100644 --- a/coreapi/sal_eXosip2.h +++ b/coreapi/sal_eXosip2.h @@ -56,6 +56,7 @@ struct SalOp{ eXosip_event_t *pending_auth; osip_call_id_t *call_id; /*used for out of calls transaction in order to retrieve the operation when receiving a response*/ + char *replaces; bool_t supports_session_timers; bool_t sdp_offering; bool_t reinvite; @@ -65,6 +66,7 @@ struct SalOp{ void sal_remove_out_subscribe(Sal *sal, SalOp *op); void sal_remove_in_subscribe(Sal *sal, SalOp *op); +void sal_add_other(Sal *sal, SalOp *op, osip_message_t *request); void sal_exosip_subscription_recv(Sal *sal, eXosip_event_t *ev); void sal_exosip_subscription_answered(Sal *sal,eXosip_event_t *ev); @@ -72,8 +74,9 @@ void sal_exosip_notify_recv(Sal *sal,eXosip_event_t *ev); void sal_exosip_subscription_closed(Sal *sal,eXosip_event_t *ev); void sal_exosip_in_subscription_closed(Sal *sal, eXosip_event_t *ev); - +SalOp * sal_find_out_subscribe(Sal *sal, int sid); void sal_exosip_fix_route(SalOp *op); +void _osip_list_set_empty(osip_list_t *l, void (*freefunc)(void*)); #endif diff --git a/coreapi/sal_eXosip2_presence.c b/coreapi/sal_eXosip2_presence.c index a38fdf91b..1e7409f19 100644 --- a/coreapi/sal_eXosip2_presence.c +++ b/coreapi/sal_eXosip2_presence.c @@ -21,7 +21,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "sal_eXosip2.h" -static SalOp * sal_find_out_subscribe(Sal *sal, int sid){ +SalOp * sal_find_out_subscribe(Sal *sal, int sid){ const MSList *elem; SalOp *op; for(elem=sal->out_subscribes;elem!=NULL;elem=elem->next){ @@ -83,9 +83,14 @@ int sal_text_send(SalOp *op, const char *from, const char *to, const char *msg){ eXosip_lock(); eXosip_message_build_request(&sip,"MESSAGE",sal_op_get_to(op), sal_op_get_from(op),sal_op_get_route(op)); - osip_message_set_content_type(sip,"text/plain"); - osip_message_set_body(sip,msg,strlen(msg)); - eXosip_message_send_request(sip); + if (sip!=NULL){ + osip_message_set_content_type(sip,"text/plain"); + osip_message_set_body(sip,msg,strlen(msg)); + sal_add_other(op->base.root,op,sip); + eXosip_message_send_request(sip); + }else{ + ms_error("Could not build MESSAGE request !"); + } eXosip_unlock(); } else @@ -93,22 +98,16 @@ int sal_text_send(SalOp *op, const char *from, const char *to, const char *msg){ /* we are currently in communication with the destination */ eXosip_lock(); //First we generate an INFO message to get the current call_id and a good cseq - eXosip_call_build_info(op->did,&sip); + eXosip_call_build_request(op->did,"MESSAGE",&sip); if(sip == NULL) { ms_warning("could not get a build info to send MESSAGE, maybe no previous call established ?"); - osip_message_free(sip); eXosip_unlock(); return -1; } - //change the sip_message to be a MESSAGE ... - osip_free(osip_message_get_method(sip)); - osip_message_set_method(sip,osip_strdup("MESSAGE")); - osip_free(osip_cseq_get_method(osip_message_get_cseq(sip))); - osip_cseq_set_method(osip_message_get_cseq(sip),osip_strdup("MESSAGE")); osip_message_set_content_type(sip,"text/plain"); osip_message_set_body(sip,msg,strlen(msg)); - eXosip_message_send_request(sip); + eXosip_call_send_request(op->did,sip); eXosip_unlock(); } return 0; @@ -125,6 +124,10 @@ int sal_subscribe_presence(SalOp *op, const char *from, const char *to){ eXosip_lock(); eXosip_subscribe_build_initial_request(&msg,sal_op_get_to(op),sal_op_get_from(op), sal_op_get_route(op),"presence",600); + if (op->base.contact){ + _osip_list_set_empty(&msg->contacts,(void (*)(void*))osip_contact_free); + osip_message_set_contact(msg,op->base.contact); + } op->sid=eXosip_subscribe_send_initial_request(msg); eXosip_unlock(); if (op->sid==-1){ @@ -156,6 +159,10 @@ int sal_subscribe_accept(SalOp *op){ osip_message_t *msg; eXosip_lock(); eXosip_insubscription_build_answer(op->tid,202,&msg); + if (op->base.contact){ + _osip_list_set_empty(&msg->contacts,(void (*)(void*))osip_contact_free); + osip_message_set_contact(msg,op->base.contact); + } eXosip_insubscription_send_answer(op->tid,202,msg); eXosip_unlock(); return 0; diff --git a/gtk/main.c b/gtk/main.c index 382052a22..04aea71f0 100644 --- a/gtk/main.c +++ b/gtk/main.c @@ -649,12 +649,14 @@ static gboolean in_call_timer(){ return FALSE; } -static bool_t all_calls_paused(const MSList *calls){ +static bool_t all_other_calls_paused(LinphoneCall *refcall, const MSList *calls){ for(;calls!=NULL;calls=calls->next){ LinphoneCall *call=(LinphoneCall*)calls->data; LinphoneCallState cs=linphone_call_get_state(call); - if (cs!=LinphoneCallPaused && cs!=LinphoneCallIncomingReceived && cs!=LinphoneCallPausing) - return FALSE; + if (refcall!=call){ + if (cs!=LinphoneCallPaused && cs!=LinphoneCallPausing) + return FALSE; + } } return TRUE; } @@ -673,11 +675,17 @@ static void linphone_gtk_update_call_buttons(LinphoneCall *call){ stop_active=FALSE; }else{ stop_active=TRUE; - if (all_calls_paused(calls)){ + if (all_other_calls_paused(NULL,calls)){ start_active=TRUE; add_call=TRUE; - }else if (call!=NULL && linphone_call_get_state(call)==LinphoneCallIncomingReceived){ - start_active=TRUE; + }else if (call!=NULL && linphone_call_get_state(call)==LinphoneCallIncomingReceived && all_other_calls_paused(call,calls)){ + if (ms_list_size(calls)>1){ + start_active=TRUE; + add_call=TRUE; + }else{ + start_active=TRUE; + add_call=FALSE; + } }else{ start_active=FALSE; } @@ -969,7 +977,7 @@ static void linphone_gtk_call_state_changed(LinphoneCore *lc, LinphoneCall *call break; case LinphoneCallIncomingReceived: linphone_gtk_create_in_call_view (call); - linphone_gtk_in_call_view_set_incoming(call,!all_calls_paused (linphone_core_get_calls(lc))); + linphone_gtk_in_call_view_set_incoming(call,!all_other_calls_paused (call,linphone_core_get_calls(lc))); if (auto_answer) { linphone_call_ref(call); g_timeout_add(2000,(GSourceFunc)linphone_gtk_auto_answer ,call); diff --git a/mediastreamer2 b/mediastreamer2 index 20da8f413..93ef451fd 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 20da8f413994f0959ab81b391894defa70eaa1f6 +Subproject commit 93ef451fd6da31fd70fd59e6a6ca59cc26a3b287 diff --git a/po/POTFILES.in b/po/POTFILES.in index 704f41386..c69378f97 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -72,4 +72,4 @@ mediastreamer2/src/chanadapt.c mediastreamer2/src/itc.c mediastreamer2/src/extdisplay.c mediastreamer2/src/msiounit.c - +mediastreamer2/src/x11video.c