Merge branch 'master' of git.linphone.org:linphone

Conflicts:
	mediastreamer2
This commit is contained in:
Simon Morlat 2013-02-22 21:37:11 +01:00
commit 468a1b69d4
24 changed files with 1260 additions and 1151 deletions

View file

@ -782,6 +782,7 @@ printf "* %-30s %s\n" "Account assistant" $build_wizard
printf "* %-30s %s\n" "Console interface" $console_ui
printf "* %-30s %s\n" "Tools" $build_tools
printf "* %-30s %s\n" "zRTP encryption (GPLv3)" $zrtp
printf "* %-30s %s\n" "uPnP support" $build_upnp
if test "$enable_tunnel" = "true" ; then
printf "* Tunnel support\t\ttrue\n"

View file

@ -55,22 +55,38 @@ static void remove_local_endpoint(LinphoneConference *ctx){
}
}
static int linphone_conference_get_size(LinphoneConference *conf){
if (conf->conf == NULL) {
return 0;
}
return ms_audio_conference_get_size(conf->conf) - (conf->record_endpoint ? 1 : 0);
}
static int remote_participants_count(LinphoneConference *ctx) {
if (!ctx->conf || ms_audio_conference_get_size(ctx->conf)==0) return 0;
if (!ctx->local_participant) return ms_audio_conference_get_size(ctx->conf);
return ms_audio_conference_get_size(ctx->conf) -1;
int count=linphone_conference_get_size(ctx);
if (count==0) return 0;
if (!ctx->local_participant) return count;
return count -1;
}
void linphone_core_conference_check_uninit(LinphoneCore *lc){
LinphoneConference *ctx=&lc->conf_ctx;
if (ctx->conf){
ms_message("conference_check_uninit(): nmembers=%i",ms_audio_conference_get_size(ctx->conf));
if (remote_participants_count(ctx)==1){
int remote_count=remote_participants_count(ctx);
ms_message("conference_check_uninit(): size=%i",linphone_conference_get_size(ctx));
if (remote_count==1){
convert_conference_to_call(lc);
}
if (ms_audio_conference_get_size(ctx->conf)==1 && ctx->local_participant!=NULL){
remove_local_endpoint(ctx);
if (remote_count==0){
if (ctx->local_participant!=NULL)
remove_local_endpoint(ctx);
if (ctx->record_endpoint){
ms_audio_conference_remove_member(ctx->conf,ctx->record_endpoint);
ms_audio_endpoint_destroy(ctx->record_endpoint);
ctx->record_endpoint=NULL;
}
}
if (ms_audio_conference_get_size(ctx->conf)==0){
ms_audio_conference_destroy(ctx->conf);
ctx->conf=NULL;
@ -381,10 +397,37 @@ int linphone_core_terminate_conference(LinphoneCore *lc) {
* @returns the number of participants to the conference
**/
int linphone_core_get_conference_size(LinphoneCore *lc) {
if (lc->conf_ctx.conf == NULL) {
return 0;
LinphoneConference *conf=&lc->conf_ctx;
return linphone_conference_get_size(conf);
}
int linphone_core_start_conference_recording(LinphoneCore *lc, const char *path){
LinphoneConference *conf=&lc->conf_ctx;
if (conf->conf == NULL) {
ms_warning("linphone_core_start_conference_recording(): no conference now.");
return -1;
}
return ms_audio_conference_get_size(lc->conf_ctx.conf);
if (conf->record_endpoint==NULL){
conf->record_endpoint=ms_audio_endpoint_new_recorder();
ms_audio_conference_add_member(conf->conf,conf->record_endpoint);
}
ms_audio_recorder_endpoint_start(conf->record_endpoint,path);
return 0;
}
int linphone_core_stop_conference_recording(LinphoneCore *lc){
LinphoneConference *conf=&lc->conf_ctx;
if (conf->conf == NULL) {
ms_warning("linphone_core_stop_conference_recording(): no conference now.");
return -1;
}
if (conf->record_endpoint==NULL){
ms_warning("linphone_core_stop_conference_recording(): no record active.");
return -1;
}
ms_audio_recorder_endpoint_stop(conf->record_endpoint);
return 0;
}
/**

View file

@ -97,17 +97,37 @@ static void ecc_deinit_filters(EcCalibrator *ecc){
static void on_tone_sent(void *data, MSFilter *f, unsigned int event_id, void *arg){
MSDtmfGenEvent *ev=(MSDtmfGenEvent*)arg;
EcCalibrator *ecc=(EcCalibrator*)data;
ecc->sent_count++;
ecc->acc-=ev->tone_start_time;
ms_message("Sent tone at %u",(unsigned int)ev->tone_start_time);
}
static bool_t is_valid_tone(EcCalibrator *ecc, MSToneDetectorEvent *ev){
bool_t *toneflag=NULL;
if (strcmp(ev->tone_name,"freq1")==0){
toneflag=&ecc->freq1;
}else if (strcmp(ev->tone_name,"freq2")==0){
toneflag=&ecc->freq2;
}else if (strcmp(ev->tone_name,"freq3")==0){
toneflag=&ecc->freq3;
}else{
ms_error("Calibrator bug.");
return FALSE;
}
if (*toneflag){
ms_message("Duplicated tone event, ignored.");
return FALSE;
}
*toneflag=TRUE;
return TRUE;
}
static void on_tone_received(void *data, MSFilter *f, unsigned int event_id, void *arg){
MSToneDetectorEvent *ev=(MSToneDetectorEvent*)arg;
EcCalibrator *ecc=(EcCalibrator*)data;
ecc->recv_count++;
ecc->acc+=ev->tone_start_time;
ms_message("Received tone at %u",(unsigned int)ev->tone_start_time);
if (is_valid_tone(ecc,ev)){
ecc->acc+=ev->tone_start_time;
ms_message("Received tone at %u",(unsigned int)ev->tone_start_time);
}
}
static void ecc_play_tones(EcCalibrator *ecc){
@ -116,53 +136,76 @@ static void ecc_play_tones(EcCalibrator *ecc){
ms_filter_set_notify_callback(ecc->det,on_tone_received,ecc);
/* configure the tones to be scanned */
strncpy(expected_tone.tone_name,"freq1",sizeof(expected_tone.tone_name));
expected_tone.frequency=2000;
expected_tone.min_duration=40;
expected_tone.min_amplitude=0.02;
expected_tone.min_amplitude=0.1;
ms_filter_call_method (ecc->det,MS_TONE_DETECTOR_ADD_SCAN,&expected_tone);
tone.frequency=1300;
tone.duration=1000;
tone.amplitude=1.0;
strncpy(expected_tone.tone_name,"freq2",sizeof(expected_tone.tone_name));
expected_tone.frequency=2300;
expected_tone.min_duration=40;
expected_tone.min_amplitude=0.1;
ms_filter_call_method (ecc->det,MS_TONE_DETECTOR_ADD_SCAN,&expected_tone);
strncpy(expected_tone.tone_name,"freq3",sizeof(expected_tone.tone_name));
expected_tone.frequency=2500;
expected_tone.min_duration=40;
expected_tone.min_amplitude=0.1;
ms_filter_call_method (ecc->det,MS_TONE_DETECTOR_ADD_SCAN,&expected_tone);
/*play an initial tone to startup the audio playback/capture*/
tone.frequency=140;
tone.duration=1000;
tone.amplitude=0.5;
ms_filter_call_method(ecc->gen,MS_DTMF_GEN_PLAY_CUSTOM,&tone);
ms_sleep(2);
ms_filter_set_notify_callback(ecc->gen,on_tone_sent,ecc);
/* play the three tones*/
tone.frequency=2000;
tone.duration=100;
ms_filter_call_method(ecc->gen,MS_DTMF_GEN_PLAY_CUSTOM,&tone);
ms_usleep(300000);
tone.frequency=2300;
tone.duration=100;
ms_filter_call_method(ecc->gen,MS_DTMF_GEN_PLAY_CUSTOM,&tone);
ms_usleep(300000);
tone.frequency=2500;
tone.duration=100;
ms_filter_call_method(ecc->gen,MS_DTMF_GEN_PLAY_CUSTOM,&tone);
ms_sleep(1);
ms_filter_call_method(ecc->gen,MS_DTMF_GEN_PLAY_CUSTOM,&tone);
ms_sleep(1);
ms_filter_call_method(ecc->gen,MS_DTMF_GEN_PLAY_CUSTOM,&tone);
ms_sleep(1);
if (ecc->sent_count==3) {
if (ecc->recv_count==3){
int delay=ecc->acc/3;
if (delay<0){
ms_error("Quite surprising calibration result, delay=%i",delay);
ecc->status=LinphoneEcCalibratorFailed;
}else{
ms_message("Echo calibration estimated delay to be %i ms",delay);
ecc->delay=delay;
ecc->status=LinphoneEcCalibratorDone;
}
} else if (ecc->recv_count == 0) {
if (ecc->freq1 && ecc->freq2 && ecc->freq3) {
int delay=ecc->acc/3;
if (delay<0){
ms_error("Quite surprising calibration result, delay=%i",delay);
ecc->status=LinphoneEcCalibratorFailed;
}else{
ms_message("Echo calibration estimated delay to be %i ms",delay);
ecc->delay=delay;
ecc->status=LinphoneEcCalibratorDone;
}
} else if ((ecc->freq1 || ecc->freq2 || ecc->freq3)==FALSE) {
ms_message("Echo calibration succeeded, no echo has been detected");
ecc->status = LinphoneEcCalibratorDoneNoEcho;
} else {
} else {
ecc->status = LinphoneEcCalibratorFailed;
}
}else{
ecc->status=LinphoneEcCalibratorFailed;
}
if (ecc->status == LinphoneEcCalibratorFailed) {
ms_error("Echo calibration failed, tones received = %i",ecc->recv_count);
ms_error("Echo calibration failed.");
}
}

View file

@ -508,14 +508,21 @@ LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *fro
call->core=lc;
if (lc->sip_conf.ping_with_options){
/*the following sends an option request back to the caller so that
we get a chance to discover our nat'd address before answering.*/
call->ping_op=sal_op_new(lc->sal);
from_str=linphone_address_as_string_uri_only(from);
sal_op_set_route(call->ping_op,sal_op_get_network_origin(op));
sal_op_set_user_pointer(call->ping_op,call);
sal_ping(call->ping_op,linphone_core_find_best_identity(lc,from,NULL),from_str);
ms_free(from_str);
#ifdef BUILD_UPNP
if (lc->upnp != NULL && linphone_core_get_firewall_policy(lc)==LinphonePolicyUseUpnp &&
linphone_upnp_context_get_state(lc->upnp) == LinphoneUpnpStateOk) {
#else //BUILD_UPNP
{
#endif //BUILD_UPNP
/*the following sends an option request back to the caller so that
we get a chance to discover our nat'd address before answering.*/
call->ping_op=sal_op_new(lc->sal);
from_str=linphone_address_as_string_uri_only(from);
sal_op_set_route(call->ping_op,sal_op_get_network_origin(op));
sal_op_set_user_pointer(call->ping_op,call);
sal_ping(call->ping_op,linphone_core_find_best_identity(lc,from,NULL),from_str);
ms_free(from_str);
}
}
linphone_address_clean(from);
@ -1100,7 +1107,7 @@ void linphone_call_params_add_custom_header(LinphoneCallParams *params, const ch
params->custom_headers=sal_custom_header_append(params->custom_headers,header_name,header_value);
}
const char *linphone_call_params_get_custom_header(LinphoneCallParams *params, const char *header_name){
const char *linphone_call_params_get_custom_header(const LinphoneCallParams *params, const char *header_name){
return sal_custom_header_find(params->custom_headers,header_name);
}

View file

@ -92,12 +92,7 @@ int lc_callback_obj_invoke(LCCallbackObj *obj, LinphoneCore *lc){
/*prevent a gcc bug with %c*/
static size_t my_strftime(char *s, size_t max, const char *fmt, const struct tm *tm){
#if !defined(_WIN32_WCE)
return strftime(s, max, fmt, tm);
#else
return 0;
/*FIXME*/
#endif /*_WIN32_WCE*/
}
static void set_call_log_date(LinphoneCallLog *cl, time_t start_time){
@ -120,7 +115,7 @@ LinphoneCallLog * linphone_call_log_new(LinphoneCall *call, LinphoneAddress *fro
set_call_log_date(cl,cl->start_date_time);
cl->from=from;
cl->to=to;
cl->status=LinphoneCallAborted; /*default status*/
cl->status=LinphoneCallAborted; /*default status*/
return cl;
}
@ -666,6 +661,9 @@ static void sip_config_read(LinphoneCore *lc)
tmp=lp_config_get_int(lc->config,"sip","in_call_timeout",0);
linphone_core_set_in_call_timeout(lc,tmp);
tmp=lp_config_get_int(lc->config,"sip","delayed_timeout",4);
linphone_core_set_delayed_timeout(lc,tmp);
/* get proxies config */
for(i=0;; i++){
@ -1304,9 +1302,6 @@ static void linphone_core_init (LinphoneCore * lc, const LinphoneCoreVTable *vta
lc->tunnel=linphone_core_tunnel_new(lc);
if (lc->tunnel) linphone_tunnel_configure(lc->tunnel);
#endif
#ifdef BUILD_UPNP
lc->upnp = linphone_upnp_context_new(lc);
#endif //BUILD_UPNP
if (lc->vtable.display_status)
lc->vtable.display_status(lc,_("Ready"));
lc->auto_net_state_mon=lc->sip_conf.auto_net_state_mon;
@ -2054,9 +2049,11 @@ void linphone_core_iterate(LinphoneCore *lc){
lc->ecc->cb(lc,ecs,lc->ecc->delay,lc->ecc->cb_data);
if (ecs==LinphoneEcCalibratorDone){
int len=lp_config_get_int(lc->config,"sound","ec_tail_len",0);
lp_config_set_int(lc->config, "sound", "ec_delay",MAX(lc->ecc->delay-(len/2),0));
int margin=len/2;
lp_config_set_int(lc->config, "sound", "ec_delay",MAX(lc->ecc->delay-margin,0));
} else if (ecs == LinphoneEcCalibratorFailed) {
lp_config_set_int(lc->config, "sound", "ec_delay", LP_CONFIG_DEFAULT_INT(lc->config, "ec_delay", 250));
lp_config_set_int(lc->config, "sound", "ec_delay", -1);/*use default value from soundcard*/
} else if (ecs == LinphoneEcCalibratorDoneNoEcho) {
linphone_core_enable_echo_cancellation(lc, FALSE);
}
@ -2095,7 +2092,7 @@ void linphone_core_iterate(LinphoneCore *lc){
linphone_core_start_invite() */
calls=calls->next;
linphone_call_background_tasks(call,one_second_elapsed);
if (call->state==LinphoneCallOutgoingInit && (elapsed>=4)){
if (call->state==LinphoneCallOutgoingInit && (elapsed>=lc->sip_conf.delayed_timeout)){
/*start the call even if the OPTIONS reply did not arrive*/
if (call->ice_session != NULL) {
ms_warning("ICE candidates gathering from [%s] has not finished yet, proceed with the call without ICE anyway."
@ -2605,15 +2602,23 @@ LinphoneCall * linphone_core_invite_address_with_params(LinphoneCore *lc, const
}
if (call->dest_proxy==NULL && lc->sip_conf.ping_with_options==TRUE){
/*defer the start of the call after the OPTIONS ping*/
call->ping_replied=FALSE;
call->ping_op=sal_op_new(lc->sal);
sal_ping(call->ping_op,from,real_url);
sal_op_set_user_pointer(call->ping_op,call);
call->start_time=time(NULL);
}else{
if (defer==FALSE) linphone_core_start_invite(lc,call);
#ifdef BUILD_UPNP
if (lc->upnp != NULL && linphone_core_get_firewall_policy(lc)==LinphonePolicyUseUpnp &&
linphone_upnp_context_get_state(lc->upnp) == LinphoneUpnpStateOk) {
#else //BUILD_UPNP
{
#endif //BUILD_UPNP
/*defer the start of the call after the OPTIONS ping*/
call->ping_replied=FALSE;
call->ping_op=sal_op_new(lc->sal);
sal_ping(call->ping_op,from,real_url);
sal_op_set_user_pointer(call->ping_op,call);
call->start_time=time(NULL);
defer = TRUE;
}
}
if (defer==FALSE) linphone_core_start_invite(lc,call);
if (real_url!=NULL) ms_free(real_url);
return call;
@ -3496,6 +3501,26 @@ int linphone_core_get_in_call_timeout(LinphoneCore *lc){
return lc->sip_conf.in_call_timeout;
}
/**
* Returns the delayed timeout
*
* @ingroup call_control
* See linphone_core_set_delayed_timeout() for details.
**/
int linphone_core_get_delayed_timeout(LinphoneCore *lc){
return lc->sip_conf.delayed_timeout;
}
/**
* Set the in delayed timeout in seconds.
*
* @ingroup call_control
* After this timeout period, a delayed call (internal call initialisation or resolution) is resumed.
**/
void linphone_core_set_delayed_timeout(LinphoneCore *lc, int seconds){
lc->sip_conf.delayed_timeout=seconds;
}
void linphone_core_set_presence_info(LinphoneCore *lc,int minutes_away,
const char *contact,
LinphoneOnlineStatus presence_mode)
@ -4213,6 +4238,19 @@ void linphone_core_set_firewall_policy(LinphoneCore *lc, LinphoneFirewallPolicy
}
#endif //BUILD_UPNP
lc->net_conf.firewall_policy=pol;
#ifdef BUILD_UPNP
if(pol == LinphonePolicyUseUpnp) {
if(lc->upnp == NULL) {
lc->upnp = linphone_upnp_context_new(lc);
}
} else {
if(lc->upnp != NULL) {
linphone_upnp_context_destroy(lc->upnp);
lc->upnp = NULL;
}
}
linphone_core_enable_keep_alive(lc, (lc->sip_conf.keepalive_period > 0));
#endif //BUILD_UPNP
if (lc->sip_conf.contact) update_primary_contact(lc);
if (linphone_core_ready(lc))
lp_config_set_int(lc->config,"net","firewall_policy",pol);
@ -5006,6 +5044,7 @@ void sip_config_uninit(LinphoneCore *lc)
lp_config_set_string(lc->config,"sip","contact",config->contact);
lp_config_set_int(lc->config,"sip","inc_timeout",config->inc_timeout);
lp_config_set_int(lc->config,"sip","in_call_timeout",config->in_call_timeout);
lp_config_set_int(lc->config,"sip","delayed_timeout",config->delayed_timeout);
lp_config_set_int(lc->config,"sip","use_info",config->use_info);
lp_config_set_int(lc->config,"sip","use_rfc2833",config->use_rfc2833);
lp_config_set_int(lc->config,"sip","use_ipv6",config->ipv6_enabled);
@ -5168,10 +5207,11 @@ static void linphone_core_uninit(LinphoneCore *lc)
usleep(50000);
#endif
}
#ifdef BUILD_UPNP
linphone_upnp_context_destroy(lc->upnp);
lc->upnp = NULL;
if(lc->upnp != NULL) {
linphone_upnp_context_destroy(lc->upnp);
lc->upnp = NULL;
}
#endif //BUILD_UPNP
if (lc->friends)
@ -5204,6 +5244,17 @@ static void linphone_core_uninit(LinphoneCore *lc)
ms_list_for_each(lc->last_recv_msg_ids,ms_free);
lc->last_recv_msg_ids=ms_list_free(lc->last_recv_msg_ids);
// Free struct variable
if(lc->zrtp_secrets_cache != NULL) {
ms_free(lc->zrtp_secrets_cache);
}
if(lc->play_file!=NULL){
ms_free(lc->play_file);
}
if(lc->rec_file!=NULL){
ms_free(lc->rec_file);
}
linphone_core_free_payload_types(lc);
ortp_exit();
@ -5438,6 +5489,11 @@ const char *linphone_error_to_string(LinphoneReason err){
* Enables signaling keep alive
*/
void linphone_core_enable_keep_alive(LinphoneCore* lc,bool_t enable) {
#ifdef BUILD_UPNP
if (linphone_core_get_firewall_policy(lc)==LinphonePolicyUseUpnp) {
enable = FALSE;
}
#endif //BUILD_UPNP
if (enable > 0) {
sal_use_tcp_tls_keepalive(lc->sal,lc->sip_conf.tcp_tls_keepalive);
sal_set_keepalive_period(lc->sal,lc->sip_conf.keepalive_period);
@ -5506,7 +5562,7 @@ void linphone_core_remove_iterate_hook(LinphoneCore *lc, LinphoneCoreIterateHook
for(elem=lc->hooks;elem!=NULL;elem=elem->next){
Hook *h=(Hook*)elem->data;
if (h->fun==hook && h->data==hook_data){
ms_list_remove_link(lc->hooks,elem);
lc->hooks = ms_list_remove_link(lc->hooks,elem);
ms_free(h);
return;
}

View file

@ -37,14 +37,12 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
extern "C" {
#endif
struct _MSSndCard;
struct _LinphoneCore;
/**
* Linphone core main object created by function linphone_core_new() .
* @ingroup initializing
*/
typedef struct _LinphoneCore LinphoneCore;
struct SalOp;
struct _LpConfig;
@ -201,7 +199,7 @@ void linphone_call_params_enable_low_bandwidth(LinphoneCallParams *cp, bool_t en
void linphone_call_params_set_record_file(LinphoneCallParams *cp, const char *path);
const char *linphone_call_params_get_record_file(const LinphoneCallParams *cp);
void linphone_call_params_add_custom_header(LinphoneCallParams *params, const char *header_name, const char *header_value);
const char *linphone_call_params_get_custom_header(LinphoneCallParams *params, const char *header_name);
const char *linphone_call_params_get_custom_header(const LinphoneCallParams *params, const char *header_name);
/**
* Enum describing failure reasons.
* @ingroup initializing
@ -1101,6 +1099,10 @@ void linphone_core_set_in_call_timeout(LinphoneCore *lc, int seconds);
int linphone_core_get_in_call_timeout(LinphoneCore *lc);
void linphone_core_set_delayed_timeout(LinphoneCore *lc, int seconds);
int linphone_core_get_delayed_timeout(LinphoneCore *lc);
void linphone_core_set_stun_server(LinphoneCore *lc, const char *server);
const char * linphone_core_get_stun_server(const LinphoneCore *lc);
@ -1366,6 +1368,8 @@ float linphone_core_get_conference_local_input_volume(LinphoneCore *lc);
int linphone_core_terminate_conference(LinphoneCore *lc);
int linphone_core_get_conference_size(LinphoneCore *lc);
int linphone_core_start_conference_recording(LinphoneCore *lc, const char *path);
int linphone_core_stop_conference_recording(LinphoneCore *lc);
int linphone_core_get_max_calls(LinphoneCore *lc);
void linphone_core_set_max_calls(LinphoneCore *lc, int max);

View file

@ -650,6 +650,13 @@ extern "C" void Java_org_linphone_core_LinphoneCoreImpl_terminateCall( JNIEnv*
linphone_core_terminate_call((LinphoneCore*)lc,(LinphoneCall*)call);
}
extern "C" void Java_org_linphone_core_LinphoneCoreImpl_declineCall( JNIEnv* env
,jobject thiz
,jlong lc
,jlong call, jint reason) {
linphone_core_decline_call((LinphoneCore*)lc,(LinphoneCall*)call,(LinphoneReason)reason);
}
extern "C" jlong Java_org_linphone_core_LinphoneCoreImpl_getRemoteAddress( JNIEnv* env
,jobject thiz
,jlong lc) {
@ -993,6 +1000,18 @@ extern "C" jint Java_org_linphone_core_LinphoneCoreImpl_startEchoCalibration(JNI
}
extern "C" jboolean Java_org_linphone_core_LinphoneCoreImpl_needsEchoCalibration(JNIEnv *env, jobject thiz, jlong lc){
MSSndCard *sndcard;
MSSndCardManager *m=ms_snd_card_manager_get();
const char *card=linphone_core_get_capture_device((LinphoneCore*)lc);
sndcard=ms_snd_card_manager_get_card(m,card);
if (sndcard == NULL){
ms_error("Could not get soundcard.");
return TRUE;
}
return (ms_snd_card_get_capabilities(sndcard) & MS_SND_CARD_CAP_BUILTIN_ECHO_CANCELLER) || (ms_snd_card_get_minimal_latency(sndcard)>0);
}
extern "C" jint Java_org_linphone_core_LinphoneCoreImpl_getMediaEncryption(JNIEnv* env
,jobject thiz
,jlong lc
@ -2041,9 +2060,11 @@ extern "C" void Java_org_linphone_core_LinphoneCoreImpl_leaveConference(JNIEnv *
extern "C" void Java_org_linphone_core_LinphoneCoreImpl_addAllToConference(JNIEnv *env,jobject thiz,jlong pCore) {
linphone_core_add_all_to_conference((LinphoneCore *) pCore);
}
extern "C" void Java_org_linphone_core_LinphoneCoreImpl_addToConference(JNIEnv *env,jobject thiz,jlong pCore, jlong pCall) {
linphone_core_add_to_conference((LinphoneCore *) pCore, (LinphoneCall *) pCall);
}
extern "C" void Java_org_linphone_core_LinphoneCoreImpl_removeFromConference(JNIEnv *env,jobject thiz,jlong pCore, jlong pCall) {
linphone_core_remove_from_conference((LinphoneCore *) pCore, (LinphoneCall *) pCall);
}
@ -2054,6 +2075,22 @@ extern "C" void Java_org_linphone_core_LinphoneCoreImpl_terminateConference(JNIE
extern "C" jint Java_org_linphone_core_LinphoneCoreImpl_getConferenceSize(JNIEnv *env,jobject thiz,jlong pCore) {
return (jint)linphone_core_get_conference_size((LinphoneCore *) pCore);
}
extern "C" jint Java_org_linphone_core_LinphoneCoreImpl_startConferenceRecording(JNIEnv *env,jobject thiz,jlong pCore, jstring jpath){
int err=-1;
if (jpath){
const char *path=env->GetStringUTFChars(jpath, NULL);
err=linphone_core_start_conference_recording((LinphoneCore*)pCore,path);
env->ReleaseStringUTFChars(jpath,path);
}
return err;
}
extern "C" jint Java_org_linphone_core_LinphoneCoreImpl_stopConferenceRecording(JNIEnv *env,jobject thiz,jlong pCore){
int err=linphone_core_stop_conference_recording((LinphoneCore*)pCore);
return err;
}
extern "C" void Java_org_linphone_core_LinphoneCoreImpl_terminateAllCalls(JNIEnv *env,jobject thiz,jlong pCore) {
linphone_core_terminate_all_calls((LinphoneCore *) pCore);
}

View file

@ -420,6 +420,7 @@ typedef struct sip_config
MSList *deleted_proxies;
int inc_timeout; /*timeout after an un-answered incoming call is rejected*/
int in_call_timeout; /*timeout after a call is hangup */
int delayed_timeout; /*timeout after a delayed call is resumed */
unsigned int keepalive_period; /* interval in ms between keep alive messages sent to the proxy server*/
LCSipTransports transports;
bool_t use_info;
@ -529,6 +530,7 @@ struct _LinphoneConference{
MSAudioConference *conf;
AudioStream *local_participant;
MSAudioEndpoint *local_endpoint;
MSAudioEndpoint *record_endpoint;
RtpProfile *local_dummy_profile;
bool_t local_muted;
};
@ -642,12 +644,11 @@ struct _EcCalibrator{
MSTicker *ticker;
LinphoneEcCalibrationCallback cb;
void *cb_data;
int recv_count;
int sent_count;
int64_t acc;
int delay;
unsigned int rate;
LinphoneEcCalibratorStatus status;
bool_t freq1,freq2,freq3;
};
typedef struct _EcCalibrator EcCalibrator;

View file

@ -263,15 +263,30 @@ static char *guess_contact_for_register(LinphoneProxyConfig *obj){
if (proxy==NULL) return NULL;
host=linphone_address_get_domain (proxy);
if (host!=NULL){
char localip[LINPHONE_IPADDR_SIZE];
int localport = -1;
char localip_tmp[LINPHONE_IPADDR_SIZE] = {'\0'};
const char *localip = NULL;
char *tmp;
LCSipTransports tr;
LinphoneAddress *contact;
linphone_core_get_local_ip(obj->lc,host,localip);
contact=linphone_address_new(obj->reg_identity);
linphone_address_set_domain (contact,localip);
linphone_address_set_port_int(contact,linphone_core_get_sip_port(obj->lc));
#ifdef BUILD_UPNP
if (obj->lc->upnp != NULL && linphone_core_get_firewall_policy(obj->lc)==LinphonePolicyUseUpnp &&
linphone_upnp_context_get_state(obj->lc->upnp) == LinphoneUpnpStateOk) {
localip = linphone_upnp_context_get_external_ipaddress(obj->lc->upnp);
localport = linphone_upnp_context_get_external_port(obj->lc->upnp);
}
#endif //BUILD_UPNP
if(localip == NULL) {
localip = localip_tmp;
linphone_core_get_local_ip(obj->lc,host,localip_tmp);
}
if(localport == -1) {
localport = linphone_core_get_sip_port(obj->lc);
}
linphone_address_set_port_int(contact,localport);
linphone_address_set_domain(contact,localip);
linphone_address_set_display_name(contact,NULL);
linphone_core_get_sip_transports(obj->lc,&tr);
@ -1082,9 +1097,19 @@ 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) &&
(!lc->sip_conf.register_only_when_upnp_is_ok || linphone_core_get_upnp_state(lc) == LinphoneUpnpStateOk))
linphone_proxy_config_register(cfg);
switch(linphone_core_get_firewall_policy(lc)) {
case LinphonePolicyUseUpnp:
#ifdef BUILD_UPNP
if(!lc->sip_conf.register_only_when_upnp_is_ok ||
(lc->upnp != NULL && !linphone_upnp_context_is_ready_for_register(lc->upnp))) {
break;
}
#endif //BUILD_UPNP
default:
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);
}

View file

@ -21,9 +21,12 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "private.h"
#include "lpconfig.h"
#define UPNP_ADD_MAX_RETRY 4
#define UPNP_ADD_MAX_RETRY 4
#define UPNP_REMOVE_MAX_RETRY 4
#define UPNP_SECTION_NAME "uPnP"
#define UPNP_SECTION_NAME "uPnP"
#define UPNP_CORE_READY_CHECK 1
#define UPNP_CORE_RETRY_DELAY 4
#define UPNP_CALL_RETRY_DELAY 1
/*
* uPnP Definitions
@ -41,6 +44,7 @@ typedef struct _UpnpPortBinding {
int ref;
bool_t to_remove;
bool_t to_add;
time_t last_update;
} UpnpPortBinding;
typedef struct _UpnpStream {
@ -69,7 +73,9 @@ struct _UpnpContext {
ms_mutex_t mutex;
ms_cond_t empty_cond;
time_t last_ready_check;
LinphoneUpnpState last_ready_state;
};
@ -77,19 +83,25 @@ bool_t linphone_core_upnp_hook(void *data);
void linphone_core_upnp_refresh(UpnpContext *ctx);
UpnpPortBinding *linphone_upnp_port_binding_new();
UpnpPortBinding *linphone_upnp_port_binding_new_with_parameters(upnp_igd_ip_protocol protocol, int local_port, int external_port);
UpnpPortBinding *linphone_upnp_port_binding_new_or_collect(MSList *list, upnp_igd_ip_protocol protocol, int local_port, int external_port);
UpnpPortBinding *linphone_upnp_port_binding_copy(const UpnpPortBinding *port);
bool_t linphone_upnp_port_binding_equal(const UpnpPortBinding *port1, const UpnpPortBinding *port2);
UpnpPortBinding *linphone_upnp_port_binding_equivalent_in_list(MSList *list, const UpnpPortBinding *port);
UpnpPortBinding *linphone_upnp_port_binding_retain(UpnpPortBinding *port);
void linphone_upnp_update_port_binding(UpnpContext *lupnp, UpnpPortBinding **port_mapping, upnp_igd_ip_protocol protocol, int port, int retry_delay);
void linphone_upnp_port_binding_log(int level, const char *msg, const UpnpPortBinding *port);
void linphone_upnp_port_binding_release(UpnpPortBinding *port);
void linphone_upnp_update_config(UpnpContext *lupnp);
// Configuration
MSList *linphone_upnp_config_list_port_bindings(struct _LpConfig *lpc);
void linphone_upnp_config_add_port_binding(UpnpContext *lupnp, const UpnpPortBinding *port);
void linphone_upnp_config_remove_port_binding(UpnpContext *lupnp, const UpnpPortBinding *port);
int linphone_upnp_context_send_remove_port_binding(UpnpContext *lupnp, UpnpPortBinding *port);
int linphone_upnp_context_send_add_port_binding(UpnpContext *lupnp, UpnpPortBinding *port);
// uPnP
int linphone_upnp_context_send_remove_port_binding(UpnpContext *lupnp, UpnpPortBinding *port, bool_t retry);
int linphone_upnp_context_send_add_port_binding(UpnpContext *lupnp, UpnpPortBinding *port, bool_t retry);
/**
@ -172,7 +184,7 @@ void linphone_upnp_igd_callback(void *cookie, upnp_igd_event event, void *arg) {
mapping = (upnp_igd_port_mapping *) arg;
port_mapping = (UpnpPortBinding*) mapping->cookie;
port_mapping->external_port = -1; //Force random external port
if(linphone_upnp_context_send_add_port_binding(lupnp, port_mapping) != 0) {
if(linphone_upnp_context_send_add_port_binding(lupnp, port_mapping, TRUE) != 0) {
linphone_upnp_port_binding_log(ORTP_ERROR, "Can't add port binding", port_mapping);
}
@ -190,7 +202,7 @@ void linphone_upnp_igd_callback(void *cookie, upnp_igd_event event, void *arg) {
case UPNP_IGD_PORT_MAPPING_REMOVE_FAILURE:
mapping = (upnp_igd_port_mapping *) arg;
port_mapping = (UpnpPortBinding*) mapping->cookie;
if(linphone_upnp_context_send_remove_port_binding(lupnp, port_mapping) != 0) {
if(linphone_upnp_context_send_remove_port_binding(lupnp, port_mapping, TRUE) != 0) {
linphone_upnp_port_binding_log(ORTP_ERROR, "Can't remove port binding", port_mapping);
linphone_upnp_config_remove_port_binding(lupnp, port_mapping);
}
@ -208,7 +220,7 @@ void linphone_upnp_igd_callback(void *cookie, upnp_igd_event event, void *arg) {
if(port_mapping->to_remove) {
if(port_mapping->state == LinphoneUpnpStateOk) {
port_mapping->to_remove = FALSE;
linphone_upnp_context_send_remove_port_binding(lupnp, port_mapping);
linphone_upnp_context_send_remove_port_binding(lupnp, port_mapping, FALSE);
} else if(port_mapping->state == LinphoneUpnpStateKo) {
port_mapping->to_remove = FALSE;
}
@ -216,7 +228,7 @@ void linphone_upnp_igd_callback(void *cookie, upnp_igd_event event, void *arg) {
if(port_mapping->to_add) {
if(port_mapping->state == LinphoneUpnpStateIdle || port_mapping->state == LinphoneUpnpStateKo) {
port_mapping->to_add = FALSE;
linphone_upnp_context_send_add_port_binding(lupnp, port_mapping);
linphone_upnp_context_send_add_port_binding(lupnp, port_mapping, FALSE);
}
}
@ -239,13 +251,14 @@ void linphone_upnp_igd_callback(void *cookie, upnp_igd_event event, void *arg) {
*/
UpnpContext* linphone_upnp_context_new(LinphoneCore *lc) {
LCSipTransports transport;
UpnpContext *lupnp = (UpnpContext *)ms_new0(UpnpContext,1);
const char *ip_address;
ms_mutex_init(&lupnp->mutex, NULL);
ms_cond_init(&lupnp->empty_cond, NULL);
lupnp->last_ready_check = 0;
lupnp->last_ready_state = LinphoneUpnpStateIdle;
lupnp->lc = lc;
lupnp->pending_bindings = NULL;
lupnp->adding_configs = NULL;
@ -253,31 +266,10 @@ UpnpContext* linphone_upnp_context_new(LinphoneCore *lc) {
lupnp->state = LinphoneUpnpStateIdle;
ms_message("uPnP IGD: New %p for core %p", lupnp, lc);
linphone_core_get_sip_transports(lc, &transport);
if(transport.udp_port != 0) {
lupnp->sip_udp = linphone_upnp_port_binding_new();
lupnp->sip_udp->protocol = UPNP_IGD_IP_PROTOCOL_UDP;
lupnp->sip_udp->local_port = transport.udp_port;
lupnp->sip_udp->external_port = transport.udp_port;
} else {
lupnp->sip_udp = NULL;
}
if(transport.tcp_port != 0) {
lupnp->sip_tcp = linphone_upnp_port_binding_new();
lupnp->sip_tcp->protocol = UPNP_IGD_IP_PROTOCOL_TCP;
lupnp->sip_tcp->local_port = transport.tcp_port;
lupnp->sip_tcp->external_port = transport.tcp_port;
} else {
lupnp->sip_tcp = NULL;
}
if(transport.tls_port != 0) {
lupnp->sip_tls = linphone_upnp_port_binding_new();
lupnp->sip_tls->protocol = UPNP_IGD_IP_PROTOCOL_TCP;
lupnp->sip_tls->local_port = transport.tls_port;
lupnp->sip_tls->external_port = transport.tls_port;
} else {
lupnp->sip_tls = NULL;
}
// Init ports
lupnp->sip_udp = NULL;
lupnp->sip_tcp = NULL;
lupnp->sip_tls = NULL;
linphone_core_add_iterate_hook(lc, linphone_core_upnp_hook, lupnp);
@ -289,17 +281,6 @@ UpnpContext* linphone_upnp_context_new(LinphoneCore *lc) {
return NULL;
}
ip_address = upnp_igd_get_local_ipaddress(lupnp->upnp_igd_ctxt);
if(lupnp->sip_udp != NULL) {
strncpy(lupnp->sip_udp->local_addr, ip_address, sizeof(lupnp->sip_udp->local_addr));
}
if(lupnp->sip_tcp != NULL) {
strncpy(lupnp->sip_tcp->local_addr, ip_address, sizeof(lupnp->sip_tcp->local_addr));
}
if(lupnp->sip_tls != NULL) {
strncpy(lupnp->sip_tls->local_addr, ip_address, sizeof(lupnp->sip_tls->local_addr));
}
lupnp->state = LinphoneUpnpStatePending;
upnp_igd_start(lupnp->upnp_igd_ctxt);
@ -307,22 +288,19 @@ UpnpContext* linphone_upnp_context_new(LinphoneCore *lc) {
}
void linphone_upnp_context_destroy(UpnpContext *lupnp) {
/*
* Not need, all hooks are removed before
* linphone_core_remove_iterate_hook(lc, linphone_core_upnp_hook, lc);
*/
linphone_core_remove_iterate_hook(lupnp->lc, linphone_core_upnp_hook, lupnp);
ms_mutex_lock(&lupnp->mutex);
/* Send port binding removes */
if(lupnp->sip_udp != NULL) {
linphone_upnp_context_send_remove_port_binding(lupnp, lupnp->sip_udp);
linphone_upnp_context_send_remove_port_binding(lupnp, lupnp->sip_udp, TRUE);
}
if(lupnp->sip_tcp != NULL) {
linphone_upnp_context_send_remove_port_binding(lupnp, lupnp->sip_tcp);
linphone_upnp_context_send_remove_port_binding(lupnp, lupnp->sip_tcp, TRUE);
}
if(lupnp->sip_tls != NULL) {
linphone_upnp_context_send_remove_port_binding(lupnp, lupnp->sip_tls);
linphone_upnp_context_send_remove_port_binding(lupnp, lupnp->sip_tls, TRUE);
}
/* Wait all pending bindings are done */
@ -330,14 +308,14 @@ void linphone_upnp_context_destroy(UpnpContext *lupnp) {
ms_message("uPnP IGD: Wait all pending port bindings ...");
ms_cond_wait(&lupnp->empty_cond, &lupnp->mutex);
}
ms_mutex_unlock(&lupnp->mutex);
if(lupnp->upnp_igd_ctxt != NULL) {
upnp_igd_destroy(lupnp->upnp_igd_ctxt);
lupnp->upnp_igd_ctxt = NULL;
}
/* Run one time the hook for configuration update */
linphone_core_upnp_hook(lupnp);
/* Run one more time configuration update */
linphone_upnp_update_config(lupnp);
/* Release port bindings */
if(lupnp->sip_udp != NULL) {
@ -360,6 +338,8 @@ void linphone_upnp_context_destroy(UpnpContext *lupnp) {
lupnp->removing_configs = ms_list_free(lupnp->removing_configs);
ms_list_for_each(lupnp->pending_bindings,(void (*)(void*))linphone_upnp_port_binding_release);
lupnp->pending_bindings = ms_list_free(lupnp->pending_bindings);
ms_mutex_unlock(&lupnp->mutex);
ms_mutex_destroy(&lupnp->mutex);
ms_cond_destroy(&lupnp->empty_cond);
@ -368,15 +348,88 @@ void linphone_upnp_context_destroy(UpnpContext *lupnp) {
ms_free(lupnp);
}
LinphoneUpnpState linphone_upnp_context_get_state(UpnpContext *ctx) {
return ctx->state;
LinphoneUpnpState linphone_upnp_context_get_state(UpnpContext *lupnp) {
LinphoneUpnpState state;
ms_mutex_lock(&lupnp->mutex);
state = lupnp->state;
ms_mutex_unlock(&lupnp->mutex);
return state;
}
const char* linphone_upnp_context_get_external_ipaddress(UpnpContext *ctx) {
return upnp_igd_get_external_ipaddress(ctx->upnp_igd_ctxt);
bool_t _linphone_upnp_context_is_ready_for_register(UpnpContext *lupnp) {
bool_t ready = TRUE;
// 1 Check global uPnP state
ready = (lupnp->state == LinphoneUpnpStateOk);
// 2 Check external ip address
if(ready) {
if (upnp_igd_get_external_ipaddress(lupnp->upnp_igd_ctxt) == NULL) {
ready = FALSE;
}
}
// 3 Check sip ports bindings
if(ready) {
if(lupnp->sip_udp != NULL) {
if(lupnp->sip_udp->state != LinphoneUpnpStateOk) {
ready = FALSE;
}
} else if(lupnp->sip_tcp != NULL) {
if(lupnp->sip_tcp->state != LinphoneUpnpStateOk) {
ready = FALSE;
}
} else if(lupnp->sip_tls != NULL) {
if(lupnp->sip_tls->state != LinphoneUpnpStateOk) {
ready = FALSE;
}
} else {
ready = FALSE;
}
}
return ready;
}
int linphone_upnp_context_send_add_port_binding(UpnpContext *lupnp, UpnpPortBinding *port) {
bool_t linphone_upnp_context_is_ready_for_register(UpnpContext *lupnp) {
bool_t ready;
ms_mutex_lock(&lupnp->mutex);
ready = _linphone_upnp_context_is_ready_for_register(lupnp);
ms_mutex_unlock(&lupnp->mutex);
return ready;
}
int linphone_upnp_context_get_external_port(UpnpContext *lupnp) {
int port = -1;
ms_mutex_lock(&lupnp->mutex);
if(lupnp->sip_udp != NULL) {
if(lupnp->sip_udp->state == LinphoneUpnpStateOk) {
port = lupnp->sip_udp->external_port;
}
} else if(lupnp->sip_tcp != NULL) {
if(lupnp->sip_tcp->state == LinphoneUpnpStateOk) {
port = lupnp->sip_tcp->external_port;
}
} else if(lupnp->sip_tls != NULL) {
if(lupnp->sip_tls->state == LinphoneUpnpStateOk) {
port = lupnp->sip_tls->external_port;
}
}
ms_mutex_unlock(&lupnp->mutex);
return port;
}
const char* linphone_upnp_context_get_external_ipaddress(UpnpContext *lupnp) {
const char* addr = NULL;
ms_mutex_lock(&lupnp->mutex);
addr = upnp_igd_get_external_ipaddress(lupnp->upnp_igd_ctxt);
ms_mutex_unlock(&lupnp->mutex);
return addr;
}
int linphone_upnp_context_send_add_port_binding(UpnpContext *lupnp, UpnpPortBinding *port, bool_t retry) {
upnp_igd_port_mapping mapping;
char description[128];
int ret;
@ -404,6 +457,11 @@ int linphone_upnp_context_send_add_port_binding(UpnpContext *lupnp, UpnpPortBind
return 0;
}
}
// No retry if specified
if(port->retry != 0 && !retry) {
return -1;
}
if(port->retry >= UPNP_ADD_MAX_RETRY) {
ret = -1;
@ -435,7 +493,7 @@ int linphone_upnp_context_send_add_port_binding(UpnpContext *lupnp, UpnpPortBind
return ret;
}
int linphone_upnp_context_send_remove_port_binding(UpnpContext *lupnp, UpnpPortBinding *port) {
int linphone_upnp_context_send_remove_port_binding(UpnpContext *lupnp, UpnpPortBinding *port, bool_t retry) {
upnp_igd_port_mapping mapping;
int ret;
@ -461,6 +519,11 @@ int linphone_upnp_context_send_remove_port_binding(UpnpContext *lupnp, UpnpPortB
return 0;
}
}
// No retry if specified
if(port->retry != 0 && !retry) {
return 1;
}
if(port->retry >= UPNP_REMOVE_MAX_RETRY) {
ret = -1;
@ -489,68 +552,34 @@ int linphone_core_update_upnp_audio_video(LinphoneCall *call, bool_t audio, bool
LinphoneCore *lc = call->core;
UpnpContext *lupnp = lc->upnp;
int ret = -1;
const char *local_addr, *external_addr;
if(lupnp == NULL) {
return ret;
}
ms_mutex_lock(&lupnp->mutex);
// Don't handle when the call
if(lupnp->state == LinphoneUpnpStateOk && call->upnp_session != NULL) {
ret = 0;
local_addr = upnp_igd_get_local_ipaddress(lupnp->upnp_igd_ctxt);
external_addr = upnp_igd_get_external_ipaddress(lupnp->upnp_igd_ctxt);
/*
* Audio part
*/
strncpy(call->upnp_session->audio->rtp->local_addr, local_addr, LINPHONE_IPADDR_SIZE);
strncpy(call->upnp_session->audio->rtp->external_addr, external_addr, LINPHONE_IPADDR_SIZE);
call->upnp_session->audio->rtp->local_port = call->audio_port;
if(call->upnp_session->audio->rtp->external_port == -1) {
call->upnp_session->audio->rtp->external_port = call->audio_port;
}
strncpy(call->upnp_session->audio->rtcp->local_addr, local_addr, LINPHONE_IPADDR_SIZE);
strncpy(call->upnp_session->audio->rtcp->external_addr, external_addr, LINPHONE_IPADDR_SIZE);
call->upnp_session->audio->rtcp->local_port = call->audio_port+1;
if(call->upnp_session->audio->rtcp->external_port == -1) {
call->upnp_session->audio->rtcp->external_port = call->audio_port+1;
}
if(audio) {
// Add audio port binding
linphone_upnp_context_send_add_port_binding(lupnp, call->upnp_session->audio->rtp);
linphone_upnp_context_send_add_port_binding(lupnp, call->upnp_session->audio->rtcp);
} else {
// Remove audio port binding
linphone_upnp_context_send_remove_port_binding(lupnp, call->upnp_session->audio->rtp);
linphone_upnp_context_send_remove_port_binding(lupnp, call->upnp_session->audio->rtcp);
}
linphone_upnp_update_port_binding(lupnp, &call->upnp_session->audio->rtp,
UPNP_IGD_IP_PROTOCOL_UDP, (audio)? call->audio_port:0, UPNP_CALL_RETRY_DELAY);
linphone_upnp_update_port_binding(lupnp, &call->upnp_session->audio->rtcp,
UPNP_IGD_IP_PROTOCOL_UDP, (audio)? call->audio_port+1:0, UPNP_CALL_RETRY_DELAY);
/*
* Video part
*/
strncpy(call->upnp_session->video->rtp->local_addr, local_addr, LINPHONE_IPADDR_SIZE);
strncpy(call->upnp_session->video->rtp->external_addr, external_addr, LINPHONE_IPADDR_SIZE);
call->upnp_session->video->rtp->local_port = call->video_port;
if(call->upnp_session->video->rtp->external_port == -1) {
call->upnp_session->video->rtp->external_port = call->video_port;
}
strncpy(call->upnp_session->video->rtcp->local_addr, local_addr, LINPHONE_IPADDR_SIZE);
strncpy(call->upnp_session->video->rtcp->external_addr, external_addr, LINPHONE_IPADDR_SIZE);
call->upnp_session->video->rtcp->local_port = call->video_port+1;
if(call->upnp_session->video->rtcp->external_port == -1) {
call->upnp_session->video->rtcp->external_port = call->video_port+1;
}
if(video) {
// Add video port binding
linphone_upnp_context_send_add_port_binding(lupnp, call->upnp_session->video->rtp);
linphone_upnp_context_send_add_port_binding(lupnp, call->upnp_session->video->rtcp);
} else {
// Remove video port binding
linphone_upnp_context_send_remove_port_binding(lupnp, call->upnp_session->video->rtp);
linphone_upnp_context_send_remove_port_binding(lupnp, call->upnp_session->video->rtcp);
}
linphone_upnp_update_port_binding(lupnp, &call->upnp_session->video->rtp,
UPNP_IGD_IP_PROTOCOL_UDP, (video)? call->video_port:0, UPNP_CALL_RETRY_DELAY);
linphone_upnp_update_port_binding(lupnp, &call->upnp_session->video->rtcp,
UPNP_IGD_IP_PROTOCOL_UDP, (video)? call->video_port+1:0, UPNP_CALL_RETRY_DELAY);
}
ms_mutex_unlock(&lupnp->mutex);
@ -564,6 +593,7 @@ int linphone_core_update_upnp_audio_video(LinphoneCall *call, bool_t audio, bool
}
int linphone_core_update_upnp_from_remote_media_description(LinphoneCall *call, const SalMediaDescription *md) {
bool_t audio = FALSE;
bool_t video = FALSE;
@ -591,6 +621,23 @@ void linphone_core_update_upnp_state_in_call_stats(LinphoneCall *call) {
call->stats[LINPHONE_CALL_STATS_VIDEO].upnp_state = call->upnp_session->video->state;
}
void linphone_upnp_update_stream_state(UpnpStream *stream) {
if((stream->rtp == NULL || stream->rtp->state == LinphoneUpnpStateOk || stream->rtp->state == LinphoneUpnpStateIdle) &&
(stream->rtcp == NULL || stream->rtcp->state == LinphoneUpnpStateOk || stream->rtcp->state == LinphoneUpnpStateIdle)) {
stream->state = LinphoneUpnpStateOk;
} else if((stream->rtp != NULL &&
(stream->rtp->state == LinphoneUpnpStateAdding || stream->rtp->state == LinphoneUpnpStateRemoving)) ||
(stream->rtcp != NULL &&
(stream->rtcp->state == LinphoneUpnpStateAdding || stream->rtcp->state == LinphoneUpnpStateRemoving))) {
stream->state = LinphoneUpnpStatePending;
} else if((stream->rtp != NULL && stream->rtp->state == LinphoneUpnpStateKo) ||
(stream->rtcp != NULL && stream->rtcp->state == LinphoneUpnpStateKo)) {
stream->state = LinphoneUpnpStateKo;
} else {
ms_error("Invalid stream %p state", stream);
}
}
int linphone_upnp_call_process(LinphoneCall *call) {
LinphoneCore *lc = call->core;
UpnpContext *lupnp = lc->upnp;
@ -610,39 +657,18 @@ int linphone_upnp_call_process(LinphoneCall *call) {
/*
* Update Audio state
*/
if((call->upnp_session->audio->rtp->state == LinphoneUpnpStateOk || call->upnp_session->audio->rtp->state == LinphoneUpnpStateIdle) &&
(call->upnp_session->audio->rtcp->state == LinphoneUpnpStateOk || call->upnp_session->audio->rtcp->state == LinphoneUpnpStateIdle)) {
call->upnp_session->audio->state = LinphoneUpnpStateOk;
} else if(call->upnp_session->audio->rtp->state == LinphoneUpnpStateAdding ||
call->upnp_session->audio->rtp->state == LinphoneUpnpStateRemoving ||
call->upnp_session->audio->rtcp->state == LinphoneUpnpStateAdding ||
call->upnp_session->audio->rtcp->state == LinphoneUpnpStateRemoving) {
call->upnp_session->audio->state = LinphoneUpnpStatePending;
} else if(call->upnp_session->audio->rtcp->state == LinphoneUpnpStateKo ||
call->upnp_session->audio->rtp->state == LinphoneUpnpStateKo) {
call->upnp_session->audio->state = LinphoneUpnpStateKo;
} else {
call->upnp_session->audio->state = LinphoneUpnpStateIdle;
}
linphone_upnp_update_stream_state(call->upnp_session->audio);
/*
* Update Video state
*/
if((call->upnp_session->video->rtp->state == LinphoneUpnpStateOk || call->upnp_session->video->rtp->state == LinphoneUpnpStateIdle) &&
(call->upnp_session->video->rtcp->state == LinphoneUpnpStateOk || call->upnp_session->video->rtcp->state == LinphoneUpnpStateIdle)) {
call->upnp_session->video->state = LinphoneUpnpStateOk;
} else if(call->upnp_session->video->rtp->state == LinphoneUpnpStateAdding ||
call->upnp_session->video->rtp->state == LinphoneUpnpStateRemoving ||
call->upnp_session->video->rtcp->state == LinphoneUpnpStateAdding ||
call->upnp_session->video->rtcp->state == LinphoneUpnpStateRemoving) {
call->upnp_session->video->state = LinphoneUpnpStatePending;
} else if(call->upnp_session->video->rtcp->state == LinphoneUpnpStateKo ||
call->upnp_session->video->rtp->state == LinphoneUpnpStateKo) {
call->upnp_session->video->state = LinphoneUpnpStateKo;
} else {
call->upnp_session->video->state = LinphoneUpnpStateIdle;
}
linphone_upnp_update_stream_state(call->upnp_session->video);
/*
* Update stat
*/
linphone_core_update_upnp_state_in_call_stats(call);
/*
* Update session state
*/
@ -660,41 +686,34 @@ int linphone_upnp_call_process(LinphoneCall *call) {
call->upnp_session->state = LinphoneUpnpStateIdle;
}
newState = call->upnp_session->state;
/* When change is done proceed update */
if(oldState != LinphoneUpnpStateOk && oldState != LinphoneUpnpStateKo &&
(call->upnp_session->state == LinphoneUpnpStateOk || call->upnp_session->state == LinphoneUpnpStateKo)) {
if(call->upnp_session->state == LinphoneUpnpStateOk)
ms_message("uPnP IGD: uPnP for Call %p is ok", call);
else
ms_message("uPnP IGD: uPnP for Call %p is ko", call);
switch (call->state) {
case LinphoneCallUpdating:
linphone_core_start_update_call(lc, call);
break;
case LinphoneCallUpdatedByRemote:
linphone_core_start_accept_call_update(lc, call);
break;
case LinphoneCallOutgoingInit:
linphone_core_proceed_with_invite_if_ready(lc, call, NULL);
break;
case LinphoneCallIdle:
linphone_core_notify_incoming_call(lc, call);
break;
default:
break;
}
}
}
ms_mutex_unlock(&lupnp->mutex);
/* When change is done proceed update */
if(oldState != LinphoneUpnpStateOk && oldState != LinphoneUpnpStateKo &&
(newState == LinphoneUpnpStateOk || newState == LinphoneUpnpStateKo)) {
if(call->upnp_session->state == LinphoneUpnpStateOk)
ms_message("uPnP IGD: uPnP for Call %p is ok", call);
else
ms_message("uPnP IGD: uPnP for Call %p is ko", call);
/*
* Update uPnP call stats
*/
if(oldState != newState) {
linphone_core_update_upnp_state_in_call_stats(call);
switch (call->state) {
case LinphoneCallUpdating:
linphone_core_start_update_call(lc, call);
break;
case LinphoneCallUpdatedByRemote:
linphone_core_start_accept_call_update(lc, call);
break;
case LinphoneCallOutgoingInit:
linphone_core_proceed_with_invite_if_ready(lc, call, NULL);
break;
case LinphoneCallIdle:
linphone_core_notify_incoming_call(lc, call);
break;
default:
break;
}
}
return ret;
@ -709,7 +728,6 @@ void linphone_core_upnp_refresh(UpnpContext *lupnp) {
ms_message("uPnP IGD: Refresh mappings");
/* Remove context port bindings */
if(lupnp->sip_udp != NULL) {
global_list = ms_list_append(global_list, lupnp->sip_udp);
}
@ -720,26 +738,32 @@ void linphone_core_upnp_refresh(UpnpContext *lupnp) {
global_list = ms_list_append(global_list, lupnp->sip_tls);
}
/* Remove call port bindings */
list = lupnp->lc->calls;
while(list != NULL) {
call = (LinphoneCall *)list->data;
if(call->upnp_session != NULL) {
global_list = ms_list_append(global_list, call->upnp_session->audio->rtp);
global_list = ms_list_append(global_list, call->upnp_session->audio->rtcp);
global_list = ms_list_append(global_list, call->upnp_session->video->rtp);
global_list = ms_list_append(global_list, call->upnp_session->video->rtcp);
if(call->upnp_session->audio->rtp != NULL) {
global_list = ms_list_append(global_list, call->upnp_session->audio->rtp);
}
if(call->upnp_session->audio->rtcp != NULL) {
global_list = ms_list_append(global_list, call->upnp_session->audio->rtcp);
}
if(call->upnp_session->video->rtp != NULL) {
global_list = ms_list_append(global_list, call->upnp_session->video->rtp);
}
if(call->upnp_session->video->rtcp != NULL) {
global_list = ms_list_append(global_list, call->upnp_session->video->rtcp);
}
}
list = list->next;
}
// Remove port binding configurations
list = linphone_upnp_config_list_port_bindings(lupnp->lc->config);
for(item = list;item != NULL; item = item->next) {
port_mapping = (UpnpPortBinding *)item->data;
port_mapping2 = linphone_upnp_port_binding_equivalent_in_list(global_list, port_mapping);
if(port_mapping2 == NULL) {
linphone_upnp_context_send_remove_port_binding(lupnp, port_mapping);
linphone_upnp_context_send_remove_port_binding(lupnp, port_mapping, TRUE);
} else if(port_mapping2->state == LinphoneUpnpStateIdle){
/* Force to remove */
port_mapping2->state = LinphoneUpnpStateOk;
@ -753,20 +777,60 @@ void linphone_core_upnp_refresh(UpnpContext *lupnp) {
list = global_list;
while(list != NULL) {
port_mapping = (UpnpPortBinding *)list->data;
linphone_upnp_context_send_remove_port_binding(lupnp, port_mapping);
linphone_upnp_context_send_add_port_binding(lupnp, port_mapping);
linphone_upnp_context_send_remove_port_binding(lupnp, port_mapping, TRUE);
linphone_upnp_context_send_add_port_binding(lupnp, port_mapping, TRUE);
list = list->next;
}
global_list = ms_list_free(global_list);
}
bool_t linphone_core_upnp_hook(void *data) {
char key[64];
MSList *item;
UpnpPortBinding *port_mapping;
UpnpContext *lupnp = (UpnpContext *)data;
ms_mutex_lock(&lupnp->mutex);
void linphone_upnp_update_port_binding(UpnpContext *lupnp, UpnpPortBinding **port_mapping, upnp_igd_ip_protocol protocol, int port, int retry_delay) {
const char *local_addr, *external_addr;
time_t now = time(NULL);
if(port != 0) {
if(*port_mapping != NULL) {
if(port != (*port_mapping)->local_port) {
linphone_upnp_context_send_remove_port_binding(lupnp, *port_mapping, FALSE);
*port_mapping = NULL;
}
}
if(*port_mapping == NULL) {
*port_mapping = linphone_upnp_port_binding_new_or_collect(lupnp->pending_bindings, protocol, port, port);
}
// Get addresses
local_addr = upnp_igd_get_local_ipaddress(lupnp->upnp_igd_ctxt);
external_addr = upnp_igd_get_external_ipaddress(lupnp->upnp_igd_ctxt);
// Force binding update on local address change
if(local_addr != NULL) {
if(strncmp((*port_mapping)->local_addr, local_addr, sizeof((*port_mapping)->local_addr))) {
linphone_upnp_context_send_remove_port_binding(lupnp, *port_mapping, FALSE);
strncpy((*port_mapping)->local_addr, local_addr, sizeof((*port_mapping)->local_addr));
}
}
if(external_addr != NULL) {
strncpy((*port_mapping)->external_addr, external_addr, sizeof((*port_mapping)->external_addr));
}
// Add (if not already done) the binding
if(now - (*port_mapping)->last_update >= retry_delay) {
(*port_mapping)->last_update = now;
linphone_upnp_context_send_add_port_binding(lupnp, *port_mapping, FALSE);
}
} else {
if(*port_mapping != NULL) {
linphone_upnp_context_send_remove_port_binding(lupnp, *port_mapping, FALSE);
*port_mapping = NULL;
}
}
}
void linphone_upnp_update_config(UpnpContext* lupnp) {
char key[64];
const MSList *item;
UpnpPortBinding *port_mapping;
/* Add configs */
for(item = lupnp->adding_configs;item!=NULL;item=item->next) {
port_mapping = (UpnpPortBinding *)item->data;
@ -792,6 +856,48 @@ bool_t linphone_core_upnp_hook(void *data) {
}
ms_list_for_each(lupnp->removing_configs,(void (*)(void*))linphone_upnp_port_binding_release);
lupnp->removing_configs = ms_list_free(lupnp->removing_configs);
}
bool_t linphone_core_upnp_hook(void *data) {
LCSipTransports transport;
LinphoneUpnpState ready_state;
const MSList *item;
time_t now = time(NULL);
UpnpContext *lupnp = (UpnpContext *)data;
ms_mutex_lock(&lupnp->mutex);
/* Update ports */
if(lupnp->state == LinphoneUpnpStateOk) {
linphone_core_get_sip_transports(lupnp->lc, &transport);
linphone_upnp_update_port_binding(lupnp, &lupnp->sip_udp, UPNP_IGD_IP_PROTOCOL_UDP, transport.udp_port, UPNP_CORE_RETRY_DELAY);
linphone_upnp_update_port_binding(lupnp, &lupnp->sip_tcp, UPNP_IGD_IP_PROTOCOL_TCP, transport.tcp_port, UPNP_CORE_RETRY_DELAY);
linphone_upnp_update_port_binding(lupnp, &lupnp->sip_tls, UPNP_IGD_IP_PROTOCOL_TCP, transport.tls_port, UPNP_CORE_RETRY_DELAY);
}
/* Refresh registers if we are ready */
if(now - lupnp->last_ready_check >= UPNP_CORE_READY_CHECK) {
lupnp->last_ready_check = now;
ready_state = (_linphone_upnp_context_is_ready_for_register(lupnp))? LinphoneUpnpStateOk: LinphoneUpnpStateKo;
if(ready_state != lupnp->last_ready_state) {
for(item=linphone_core_get_proxy_config_list(lupnp->lc);item!=NULL;item=item->next) {
LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)item->data;
if (linphone_proxy_config_register_enabled(cfg)) {
if (ready_state != LinphoneUpnpStateOk) {
// Only reset ithe registration if we require that upnp should be ok
if(lupnp->lc->sip_conf.register_only_when_upnp_is_ok) {
linphone_proxy_config_set_state(cfg, LinphoneRegistrationNone, "Registration impossible (uPnP not ready)");
}
} else {
cfg->commit=TRUE;
}
}
}
lupnp->last_ready_state = ready_state;
}
}
linphone_upnp_update_config(lupnp);
ms_mutex_unlock(&lupnp->mutex);
return TRUE;
@ -811,11 +917,11 @@ int linphone_core_update_local_media_description_from_upnp(SalMediaDescription *
upnpStream = session->video;
}
if(upnpStream != NULL) {
if(upnpStream->rtp->state == LinphoneUpnpStateOk) {
if(upnpStream->rtp != NULL && upnpStream->rtp->state == LinphoneUpnpStateOk) {
strncpy(stream->rtp_addr, upnpStream->rtp->external_addr, LINPHONE_IPADDR_SIZE);
stream->rtp_port = upnpStream->rtp->external_port;
}
if(upnpStream->rtcp->state == LinphoneUpnpStateOk) {
if(upnpStream->rtcp != NULL && upnpStream->rtcp->state == LinphoneUpnpStateOk) {
strncpy(stream->rtcp_addr, upnpStream->rtcp->external_addr, LINPHONE_IPADDR_SIZE);
stream->rtcp_port = upnpStream->rtcp->external_port;
}
@ -834,6 +940,7 @@ UpnpPortBinding *linphone_upnp_port_binding_new() {
port = ms_new0(UpnpPortBinding,1);
ms_mutex_init(&port->mutex, NULL);
port->state = LinphoneUpnpStateIdle;
port->protocol = UPNP_IGD_IP_PROTOCOL_UDP;
port->local_addr[0] = '\0';
port->local_port = -1;
port->external_addr[0] = '\0';
@ -841,9 +948,30 @@ UpnpPortBinding *linphone_upnp_port_binding_new() {
port->to_remove = FALSE;
port->to_add = FALSE;
port->ref = 1;
port->last_update = 0;
return port;
}
UpnpPortBinding *linphone_upnp_port_binding_new_with_parameters(upnp_igd_ip_protocol protocol, int local_port, int external_port) {
UpnpPortBinding *port_binding = linphone_upnp_port_binding_new();
port_binding->protocol = protocol;
port_binding->local_port = local_port;
port_binding->external_port = external_port;
return port_binding;
}
UpnpPortBinding *linphone_upnp_port_binding_new_or_collect(MSList *list, upnp_igd_ip_protocol protocol, int local_port, int external_port) {
UpnpPortBinding *tmp_binding;
UpnpPortBinding *end_binding;
end_binding = linphone_upnp_port_binding_new_with_parameters(protocol, local_port, external_port);
tmp_binding = linphone_upnp_port_binding_equivalent_in_list(list, end_binding);
if(tmp_binding != NULL) {
linphone_upnp_port_binding_release(end_binding);
end_binding = tmp_binding;
}
return end_binding;
}
UpnpPortBinding *linphone_upnp_port_binding_copy(const UpnpPortBinding *port) {
UpnpPortBinding *new_port = NULL;
new_port = ms_new0(UpnpPortBinding,1);
@ -915,18 +1043,20 @@ void linphone_upnp_port_binding_release(UpnpPortBinding *port) {
UpnpStream* linphone_upnp_stream_new() {
UpnpStream *stream = ms_new0(UpnpStream,1);
stream->state = LinphoneUpnpStateIdle;
stream->rtp = linphone_upnp_port_binding_new();
stream->rtp->protocol = UPNP_IGD_IP_PROTOCOL_UDP;
stream->rtcp = linphone_upnp_port_binding_new();
stream->rtcp->protocol = UPNP_IGD_IP_PROTOCOL_UDP;
stream->rtp = NULL;
stream->rtcp = NULL;
return stream;
}
void linphone_upnp_stream_destroy(UpnpStream* stream) {
linphone_upnp_port_binding_release(stream->rtp);
stream->rtp = NULL;
linphone_upnp_port_binding_release(stream->rtcp);
stream->rtcp = NULL;
if(stream->rtp != NULL) {
linphone_upnp_port_binding_release(stream->rtp);
stream->rtp = NULL;
}
if(stream->rtcp != NULL) {
linphone_upnp_port_binding_release(stream->rtcp);
stream->rtcp = NULL;
}
ms_free(stream);
}
@ -949,10 +1079,18 @@ void linphone_upnp_session_destroy(UpnpSession *session) {
if(lc->upnp != NULL) {
/* Remove bindings */
linphone_upnp_context_send_remove_port_binding(lc->upnp, session->audio->rtp);
linphone_upnp_context_send_remove_port_binding(lc->upnp, session->audio->rtcp);
linphone_upnp_context_send_remove_port_binding(lc->upnp, session->video->rtp);
linphone_upnp_context_send_remove_port_binding(lc->upnp, session->video->rtcp);
if(session->audio->rtp != NULL) {
linphone_upnp_context_send_remove_port_binding(lc->upnp, session->audio->rtp, TRUE);
}
if(session->audio->rtcp != NULL) {
linphone_upnp_context_send_remove_port_binding(lc->upnp, session->audio->rtcp, TRUE);
}
if(session->video->rtp != NULL) {
linphone_upnp_context_send_remove_port_binding(lc->upnp, session->video->rtp, TRUE);
}
if(session->video->rtcp != NULL) {
linphone_upnp_context_send_remove_port_binding(lc->upnp, session->video->rtcp, TRUE);
}
}
linphone_upnp_stream_destroy(session->audio);
@ -964,6 +1102,7 @@ LinphoneUpnpState linphone_upnp_session_get_state(UpnpSession *session) {
return session->state;
}
/*
* uPnP Config
*/

View file

@ -40,6 +40,8 @@ UpnpContext *linphone_upnp_context_new(LinphoneCore *lc);
void linphone_upnp_context_destroy(UpnpContext *ctx);
LinphoneUpnpState linphone_upnp_context_get_state(UpnpContext *ctx);
const char *linphone_upnp_context_get_external_ipaddress(UpnpContext *ctx);
int linphone_upnp_context_get_external_port(UpnpContext *ctx);
bool_t linphone_upnp_context_is_ready_for_register(UpnpContext *ctx);
void linphone_core_update_upnp_state_in_call_stats(LinphoneCall *call);
#endif //LINPHONE_UPNP_H

View file

@ -1,179 +1,22 @@
<?xml version="1.0"?>
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<requires lib="gtk+" version="2.24"/>
<!-- interface-naming-policy project-wide -->
<object class="GtkDialog" id="call_statistics">
<property name="can_focus">False</property>
<property name="border_width">5</property>
<property name="title" translatable="yes">Call statistics</property>
<property name="type_hint">dialog</property>
<signal name="response" handler="linphone_gtk_call_statistics_closed"/>
<signal name="response" handler="linphone_gtk_call_statistics_closed" swapped="no"/>
<child internal-child="vbox">
<object class="GtkVBox" id="dialog-vbox1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="spacing">2</property>
<child>
<object class="GtkFrame" id="frame1">
<property name="visible">True</property>
<property name="label_xalign">0</property>
<property name="shadow_type">none</property>
<child>
<object class="GtkAlignment" id="alignment1">
<property name="visible">True</property>
<property name="left_padding">12</property>
<child>
<object class="GtkTable" id="table1">
<property name="visible">True</property>
<property name="n_rows">6</property>
<property name="n_columns">2</property>
<property name="homogeneous">True</property>
<child>
<object class="GtkLabel" id="audio_codec_label">
<property name="visible">True</property>
<property name="label" translatable="yes">Audio codec</property>
</object>
<packing>
<property name="x_options"></property>
</packing>
</child>
<child>
<object class="GtkLabel" id="video_codec_label">
<property name="visible">True</property>
<property name="label" translatable="yes">Video codec</property>
</object>
<packing>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
<property name="x_options"></property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label3">
<property name="visible">True</property>
<property name="label" translatable="yes">Audio IP bandwidth usage</property>
</object>
<packing>
<property name="top_attach">2</property>
<property name="bottom_attach">3</property>
<property name="x_options"></property>
</packing>
</child>
<child>
<object class="GtkLabel" id="audio_codec">
<property name="visible">True</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="video_codec">
<property name="visible">True</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="audio_bandwidth_usage">
<property name="visible">True</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">2</property>
<property name="bottom_attach">3</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label4">
<property name="visible">True</property>
<property name="label" translatable="yes">Audio Media connectivity</property>
</object>
<packing>
<property name="top_attach">4</property>
<property name="bottom_attach">5</property>
<property name="x_options"></property>
</packing>
</child>
<child>
<object class="GtkLabel" id="audio_media_connectivity">
<property name="visible">True</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">4</property>
<property name="bottom_attach">5</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label1">
<property name="visible">True</property>
<property name="label" translatable="yes">Video IP bandwidth usage</property>
</object>
<packing>
<property name="top_attach">3</property>
<property name="bottom_attach">4</property>
<property name="x_options"></property>
</packing>
</child>
<child>
<object class="GtkLabel" id="video_bandwidth_usage">
<property name="visible">True</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">3</property>
<property name="bottom_attach">4</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label2">
<property name="visible">True</property>
<property name="label" translatable="yes">Video Media connectivity</property>
</object>
<packing>
<property name="top_attach">5</property>
<property name="bottom_attach">6</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="video_media_connectivity">
<property name="visible">True</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">5</property>
<property name="bottom_attach">6</property>
</packing>
</child>
</object>
</child>
</object>
</child>
<child type="label">
<object class="GtkLabel" id="call_statistics_label">
<property name="visible">True</property>
<property name="label" translatable="yes">&lt;b&gt;Call statistics and information&lt;/b&gt;</property>
<property name="use_markup">True</property>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
<child internal-child="action_area">
<object class="GtkHButtonBox" id="dialog-action_area1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="layout_style">end</property>
<child>
<placeholder/>
@ -184,6 +27,7 @@
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_action_appearance">False</property>
<property name="use_stock">True</property>
</object>
<packing>
@ -195,10 +39,210 @@
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="pack_type">end</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkFrame" id="frame1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label_xalign">0</property>
<property name="shadow_type">none</property>
<child>
<object class="GtkAlignment" id="alignment1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="left_padding">12</property>
<child>
<object class="GtkTable" id="table1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="n_rows">7</property>
<property name="n_columns">2</property>
<property name="homogeneous">True</property>
<child>
<object class="GtkLabel" id="audio_codec_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Audio codec</property>
</object>
<packing>
<property name="x_options"></property>
</packing>
</child>
<child>
<object class="GtkLabel" id="video_codec_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Video codec</property>
</object>
<packing>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
<property name="x_options"></property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label3">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Audio IP bandwidth usage</property>
</object>
<packing>
<property name="top_attach">2</property>
<property name="bottom_attach">3</property>
<property name="x_options"></property>
</packing>
</child>
<child>
<object class="GtkLabel" id="audio_codec">
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="video_codec">
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="audio_bandwidth_usage">
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">2</property>
<property name="bottom_attach">3</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label4">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Audio Media connectivity</property>
</object>
<packing>
<property name="top_attach">4</property>
<property name="bottom_attach">5</property>
<property name="x_options"></property>
</packing>
</child>
<child>
<object class="GtkLabel" id="audio_media_connectivity">
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">4</property>
<property name="bottom_attach">5</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Video IP bandwidth usage</property>
</object>
<packing>
<property name="top_attach">3</property>
<property name="bottom_attach">4</property>
<property name="x_options"></property>
</packing>
</child>
<child>
<object class="GtkLabel" id="video_bandwidth_usage">
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">3</property>
<property name="bottom_attach">4</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label2">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Video Media connectivity</property>
</object>
<packing>
<property name="top_attach">5</property>
<property name="bottom_attach">6</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="video_media_connectivity">
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">5</property>
<property name="bottom_attach">6</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label5">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Round trip time</property>
</object>
<packing>
<property name="top_attach">6</property>
<property name="bottom_attach">7</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="round_trip_time">
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">6</property>
<property name="bottom_attach">7</property>
</packing>
</child>
</object>
</child>
</object>
</child>
<child type="label">
<object class="GtkLabel" id="call_statistics_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">&lt;b&gt;Call statistics and information&lt;/b&gt;</property>
<property name="use_markup">True</property>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
</object>
</child>
<action-widgets>

View file

@ -27,6 +27,11 @@
#define PADDING_PIXELS 4
/*
* conferencee_box = a vbox where participants are added or removed
* conf_frame = the conference tab
*/
static GtkWidget *create_conference_label(void){
GtkWidget *box=gtk_hbox_new(FALSE,0);
gtk_box_pack_start(GTK_BOX(box),gtk_image_new_from_stock(GTK_STOCK_ADD,GTK_ICON_SIZE_MENU),FALSE,FALSE,0);
@ -46,34 +51,21 @@ static void init_local_participant(GtkWidget *participant){
linphone_gtk_init_audio_meter(sound_meter, (get_volume_t) linphone_core_get_conference_local_input_volume, linphone_gtk_get_core());
}
static GtkWidget *get_conference_tab(GtkWidget *mw){
GtkWidget *box=(GtkWidget*)g_object_get_data(G_OBJECT(mw),"conference_tab");
GtkWidget *conf_frame=(GtkWidget*)g_object_get_data(G_OBJECT(mw),"conf_frame");
if(conf_frame!=NULL){
if (box==NULL){
GtkWidget *conf_box=linphone_gtk_get_widget(conf_frame,"conf_box");
box=gtk_vbox_new(FALSE,0);
GtkWidget *participant=linphone_gtk_create_widget("main","callee_frame");
gtk_box_set_homogeneous(GTK_BOX(box),TRUE);
init_local_participant(participant);
gtk_box_pack_start(GTK_BOX(box),participant,FALSE,FALSE,PADDING_PIXELS);
gtk_widget_show(box);
g_object_set_data(G_OBJECT(mw),"conference_tab",box);
gtk_box_pack_start(GTK_BOX(conf_box),box,FALSE,FALSE,PADDING_PIXELS);
}
}
static GtkWidget *get_conferencee_box(GtkWidget *mw){
GtkWidget *box=(GtkWidget*)g_object_get_data(G_OBJECT(mw),"conferencee_box");
return box;
}
static GtkWidget *find_conferencee_from_call(LinphoneCall *call){
GtkWidget *mw=linphone_gtk_get_main_window();
get_conference_tab(mw);
GtkWidget *conf_frame=(GtkWidget *)g_object_get_data(G_OBJECT(mw),"conf_frame");
GtkWidget *conf_box=linphone_gtk_get_widget(conf_frame,"conf_box");
GtkWidget *conferencee_box=get_conferencee_box(mw);
GList *elem;
GtkWidget *ret=NULL;
if (conferencee_box==NULL) return NULL;
if (call!=NULL){
GList *l=gtk_container_get_children(GTK_CONTAINER(conf_box));
GList *l=gtk_container_get_children(GTK_CONTAINER(conferencee_box));
for(elem=l;elem!=NULL;elem=elem->next){
GtkWidget *frame=(GtkWidget*)elem->data;
if (call==g_object_get_data(G_OBJECT(frame),"call")){
@ -87,28 +79,53 @@ static GtkWidget *find_conferencee_from_call(LinphoneCall *call){
return ret;
}
static GtkWidget * create_conference_panel(void){
GtkWidget *mw=linphone_gtk_get_main_window();
GtkWidget *conf_frame=linphone_gtk_create_widget("main","conf_frame");
GtkWidget *conf_box=linphone_gtk_get_widget(conf_frame,"conf_box");
GtkWidget *button_conf=linphone_gtk_get_widget(conf_frame,"terminate_conf");
GtkWidget *image=create_pixmap("stopcall-small.png");
GtkWidget *box;
GtkWidget *viewswitch=linphone_gtk_get_widget(mw,"viewswitch");
gtk_button_set_image(GTK_BUTTON(button_conf),image);
g_signal_connect_swapped(G_OBJECT(button_conf),"clicked",(GCallback)linphone_gtk_terminate_call,NULL);
g_object_set_data(G_OBJECT(mw),"conf_frame",(gpointer)conf_frame);
box=gtk_vbox_new(FALSE,0);
GtkWidget *participant=linphone_gtk_create_widget("main","callee_frame");
gtk_widget_show(participant);
gtk_box_set_homogeneous(GTK_BOX(box),TRUE);
init_local_participant(participant);
gtk_box_pack_start(GTK_BOX(box),participant,FALSE,FALSE,PADDING_PIXELS);
gtk_widget_show(box);
g_object_set_data(G_OBJECT(mw),"conferencee_box",box);
gtk_box_pack_start(GTK_BOX(conf_box),box,FALSE,FALSE,PADDING_PIXELS);
gtk_notebook_append_page(GTK_NOTEBOOK(viewswitch),conf_frame,
create_conference_label());
return conf_frame;
}
void linphone_gtk_set_in_conference(LinphoneCall *call){
GtkWidget *mw=linphone_gtk_get_main_window();
GtkWidget *viewswitch=linphone_gtk_get_widget(mw,"viewswitch");
GtkWidget *conf_frame=(GtkWidget *)g_object_get_data(G_OBJECT(mw),"conf_frame");
g_object_set_data(G_OBJECT(mw),"is_conf",GINT_TO_POINTER(TRUE));
GtkWidget *viewswitch=linphone_gtk_get_widget(mw,"viewswitch");
if(conf_frame==NULL){
conf_frame=linphone_gtk_create_widget("main","conf_frame");
GtkWidget *button_conf=linphone_gtk_get_widget(conf_frame,"terminate_conf");
GtkWidget *image=create_pixmap("stopcall-small.png");
gtk_button_set_image(GTK_BUTTON(button_conf),image);
g_signal_connect_swapped(G_OBJECT(button_conf),"clicked",(GCallback)linphone_gtk_terminate_call,NULL);
g_object_set_data(G_OBJECT(mw),"conf_frame",(gpointer)conf_frame);
gtk_notebook_append_page(GTK_NOTEBOOK(viewswitch),conf_frame,
create_conference_label());
conf_frame=create_conference_panel();
}
GtkWidget *participant=find_conferencee_from_call(call);
GtkWidget *conf_box=linphone_gtk_get_widget(conf_frame,"conf_box");
GtkWidget *participant=find_conferencee_from_call(call);
if (participant==NULL){
const LinphoneAddress *addr=linphone_call_get_remote_address(call);
participant=linphone_gtk_create_widget("main","callee_frame");
/*create and add it */
GtkWidget *conferencee_box=get_conferencee_box(mw);
GtkWidget *sound_meter;
const LinphoneAddress *addr=linphone_call_get_remote_address(call);
gchar *markup;
participant=linphone_gtk_create_widget("main","callee_frame");
gtk_widget_show(participant);
if (linphone_address_get_display_name(addr)!=NULL){
markup=g_strdup_printf("<b>%s</b>",linphone_address_get_display_name(addr));
}else{
@ -119,11 +136,11 @@ void linphone_gtk_set_in_conference(LinphoneCall *call){
gtk_label_set_markup(GTK_LABEL(linphone_gtk_get_widget(participant,"callee_name_label")),markup);
g_free(markup);
sound_meter=linphone_gtk_get_widget(participant,"sound_indicator");
linphone_gtk_init_audio_meter(sound_meter, (get_volume_t) linphone_call_get_play_volume, call);
gtk_box_pack_start(GTK_BOX(conf_box),participant,FALSE,FALSE,PADDING_PIXELS);
linphone_gtk_init_audio_meter(sound_meter, (get_volume_t) linphone_call_get_play_volume, call);
gtk_box_pack_start(GTK_BOX(conferencee_box),participant,FALSE,FALSE,PADDING_PIXELS);
g_object_set_data_full(G_OBJECT(participant),"call",linphone_call_ref(call),(GDestroyNotify)linphone_call_unref);
gtk_notebook_set_current_page(GTK_NOTEBOOK(viewswitch),
gtk_notebook_page_num(GTK_NOTEBOOK(viewswitch),conf_frame));
gtk_notebook_page_num(GTK_NOTEBOOK(viewswitch),conf_frame));
}
}
@ -135,24 +152,26 @@ void linphone_gtk_terminate_conference_participant(LinphoneCall *call){
}
void linphone_gtk_unset_from_conference(LinphoneCall *call){
GtkWidget *mw=linphone_gtk_get_main_window();
GtkWidget *conf_frame=(GtkWidget *)g_object_get_data(G_OBJECT(mw),"conf_frame");
GtkWidget *conf_box=linphone_gtk_get_widget(conf_frame,"conf_box");
GtkWidget *frame;
if (conf_box==NULL) return; /*conference tab already destroyed*/
frame=find_conferencee_from_call(call);
GList *children;
GtkWidget *frame=find_conferencee_from_call(call);
if (frame){
GtkWidget *mw=linphone_gtk_get_main_window();
GtkWidget *conf_frame=(GtkWidget *)g_object_get_data(G_OBJECT(mw),"conf_frame");
GtkWidget *conferencee_box=g_object_get_data(G_OBJECT(mw),"conferencee_box");
GList *children;
g_message("Removing a participant from conference");
gtk_widget_destroy(frame);
children=gtk_container_get_children(GTK_CONTAINER(conferencee_box));
if (g_list_length(children)==1){ /* only local participant */
/*the conference is terminated */
g_message("The conference is terminated");
g_object_set_data(G_OBJECT(mw),"conferencee_box",NULL);
gtk_widget_destroy(conf_frame);
g_object_set_data(G_OBJECT(mw),"conf_frame",NULL);
}
g_list_free(children);
}
children=gtk_container_get_children(GTK_CONTAINER(conf_box));
if (g_list_length(children)==2){
/*the conference is terminated */
gtk_widget_destroy(conf_box);
g_object_set_data(G_OBJECT(mw),"conference_tab",NULL);
}
gtk_widget_destroy(conf_frame);
g_list_free(children);
g_object_set_data(G_OBJECT(mw),"is_conf",GINT_TO_POINTER(FALSE));
g_object_set_data(G_OBJECT(mw),"conf_frame",NULL);
}

View file

@ -50,7 +50,8 @@ LinphoneCall *linphone_gtk_get_currently_displayed_call(gboolean *is_conf){
if (page!=NULL){
LinphoneCall *call=(LinphoneCall*)g_object_get_data(G_OBJECT(page),"call");
if (call==NULL){
if (GPOINTER_TO_INT(g_object_get_data(G_OBJECT(main_window),"is_conf"))){
GtkWidget *conf_frame=(GtkWidget *)g_object_get_data(G_OBJECT(main_window),"conf_frame");
if (conf_frame==page){
if (is_conf)
*is_conf=TRUE;
return NULL;
@ -75,25 +76,28 @@ static GtkWidget *make_tab_header(int number){
}
void update_tab_header(LinphoneCall *call,gboolean pause){
GtkWidget *w=(GtkWidget*)linphone_call_get_user_pointer(call);
GtkWidget *main_window=linphone_gtk_get_main_window();
GtkNotebook *notebook=GTK_NOTEBOOK(linphone_gtk_get_widget(main_window,"viewswitch"));
gint call_index=GPOINTER_TO_INT(g_object_get_data(G_OBJECT(w),"call_index"));
GtkWidget *new_label=gtk_hbox_new (FALSE,0);
GtkWidget *i=NULL;
if(pause){
i=gtk_image_new_from_stock(GTK_STOCK_MEDIA_PAUSE,GTK_ICON_SIZE_SMALL_TOOLBAR);
} else {
i=create_pixmap ("startcall-small.png");
}
GtkWidget *w=(GtkWidget*)linphone_call_get_user_pointer(call);
GtkWidget *main_window=linphone_gtk_get_main_window();
GtkNotebook *notebook=GTK_NOTEBOOK(linphone_gtk_get_widget(main_window,"viewswitch"));
gint call_index=GPOINTER_TO_INT(g_object_get_data(G_OBJECT(w),"call_index"));
GtkWidget *new_label=gtk_hbox_new (FALSE,0);
GtkWidget *i=NULL;
GtkWidget *l;
gchar *text=g_strdup_printf(_("Call #%i"),call_index);
gchar *text;
if(pause){
i=gtk_image_new_from_stock(GTK_STOCK_MEDIA_PAUSE,GTK_ICON_SIZE_SMALL_TOOLBAR);
} else {
i=create_pixmap ("startcall-small.png");
}
text=g_strdup_printf(_("Call #%i"),call_index);
l=gtk_label_new (text);
gtk_box_pack_start (GTK_BOX(new_label),i,FALSE,FALSE,0);
gtk_box_pack_end(GTK_BOX(new_label),l,TRUE,TRUE,0);
gtk_notebook_set_tab_label(notebook,w,new_label);
gtk_widget_show_all(new_label);
gtk_notebook_set_tab_label(notebook,w,new_label);
gtk_widget_show_all(new_label);
}
static void linphone_gtk_in_call_set_animation_image(GtkWidget *callview, const char *image_name, gboolean is_stock){
@ -157,8 +161,7 @@ void transfer_button_clicked(GtkWidget *button, gpointer call_ref){
g_signal_connect_swapped(G_OBJECT(menu_item),"activate",(GCallback)linphone_gtk_transfer_call,other_call);
}
}
gtk_menu_popup(GTK_MENU(menu),NULL,NULL,NULL,NULL,0,
gtk_get_current_event_time());
gtk_menu_popup(GTK_MENU(menu),NULL,NULL,NULL,NULL,0,gtk_get_current_event_time());
gtk_widget_show(menu);
}
@ -178,7 +181,6 @@ static void conference_button_clicked(GtkWidget *button, gpointer call_ref){
gtk_widget_set_sensitive(button,FALSE);
g_object_set_data(G_OBJECT(linphone_gtk_get_main_window()),"conf_frame",NULL);
linphone_core_add_all_to_conference(linphone_gtk_get_core());
//linphone_core_add_to_conference(linphone_gtk_get_core(),(LinphoneCall*)call_ref);
}
@ -202,7 +204,6 @@ static void show_used_codecs(GtkWidget *callstats, LinphoneCall *call){
GtkWidget *acodec_ui=linphone_gtk_get_widget(callstats,"audio_codec");
GtkWidget *vcodec_ui=linphone_gtk_get_widget(callstats,"video_codec");
if (acodec){
char tmp[64]={0};
snprintf(tmp,sizeof(tmp)-1,"%s/%i/%i",acodec->mime_type,acodec->clock_rate,acodec->channels);
gtk_label_set_label(GTK_LABEL(acodec_ui),tmp);
@ -252,28 +253,40 @@ static const char *upnp_state_to_string(LinphoneUpnpState ice_state){
static void _refresh_call_stats(GtkWidget *callstats, LinphoneCall *call){
const LinphoneCallStats *as=linphone_call_get_audio_stats(call);
const LinphoneCallStats *vs=linphone_call_get_video_stats(call);
const char *audio_media_connectivity = _("Direct");
const char *video_media_connectivity = _("Direct");
const char *audio_media_connectivity = _("Direct or through server");
const char *video_media_connectivity = _("Direct or through server");
gboolean has_video=linphone_call_params_video_enabled(linphone_call_get_current_params(call));
gchar *tmp=g_strdup_printf(_("download: %f\nupload: %f (kbit/s)"),
as->download_bandwidth,as->upload_bandwidth);
gtk_label_set_markup(GTK_LABEL(linphone_gtk_get_widget(callstats,"audio_bandwidth_usage")),tmp);
g_free(tmp);
tmp=g_strdup_printf(_("download: %f\nupload: %f (kbit/s)"),
vs->download_bandwidth,vs->upload_bandwidth);
if (has_video)
tmp=g_strdup_printf(_("download: %f\nupload: %f (kbit/s)"),vs->download_bandwidth,vs->upload_bandwidth);
else tmp=NULL;
gtk_label_set_markup(GTK_LABEL(linphone_gtk_get_widget(callstats,"video_bandwidth_usage")),tmp);
g_free(tmp);
if (tmp) g_free(tmp);
if(as->upnp_state != LinphoneUpnpStateNotAvailable && as->upnp_state != LinphoneUpnpStateIdle) {
audio_media_connectivity = upnp_state_to_string(as->upnp_state);
} else if(as->ice_state != LinphoneIceStateNotActivated) {
audio_media_connectivity = ice_state_to_string(as->ice_state);
}
gtk_label_set_text(GTK_LABEL(linphone_gtk_get_widget(callstats,"audio_media_connectivity")),audio_media_connectivity);
if(vs->upnp_state != LinphoneUpnpStateNotAvailable && vs->upnp_state != LinphoneUpnpStateIdle) {
video_media_connectivity = upnp_state_to_string(vs->upnp_state);
} else if(vs->ice_state != LinphoneIceStateNotActivated) {
video_media_connectivity = ice_state_to_string(vs->ice_state);
}
if (has_video){
if(vs->upnp_state != LinphoneUpnpStateNotAvailable && vs->upnp_state != LinphoneUpnpStateIdle) {
video_media_connectivity = upnp_state_to_string(vs->upnp_state);
} else if(vs->ice_state != LinphoneIceStateNotActivated) {
video_media_connectivity = ice_state_to_string(vs->ice_state);
}
}else video_media_connectivity=NULL;
gtk_label_set_text(GTK_LABEL(linphone_gtk_get_widget(callstats,"video_media_connectivity")),video_media_connectivity);
if (as->round_trip_delay>0){
tmp=g_strdup_printf(_("%.3f seconds"),as->round_trip_delay);
gtk_label_set_text(GTK_LABEL(linphone_gtk_get_widget(callstats,"round_trip_time")),tmp);
g_free(tmp);
}
}
static gboolean refresh_call_stats(GtkWidget *callstats){
@ -689,6 +702,9 @@ void linphone_gtk_in_call_view_set_in_call(LinphoneCall *call){
if (in_conf){
linphone_gtk_set_in_conference(call);
gtk_widget_set_sensitive(linphone_gtk_get_widget(callview,"incall_mute"),FALSE);
}else{
linphone_gtk_unset_from_conference(call); /*in case it was previously*/
gtk_widget_set_sensitive(linphone_gtk_get_widget(callview,"incall_mute"),TRUE);
}
gtk_widget_show_all(linphone_gtk_get_widget(callview,"buttons_panel"));
if (!in_conf) gtk_widget_show_all(linphone_gtk_get_widget(callview,"record_hbox"));
@ -857,18 +873,46 @@ void linphone_gtk_call_statistics_closed(GtkWidget *call_stats){
void linphone_gtk_record_call_toggled(GtkWidget *button){
gboolean active=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button));
LinphoneCall *call=linphone_gtk_get_currently_displayed_call(NULL);
GtkWidget *callview=(GtkWidget*)linphone_call_get_user_pointer (call);
const LinphoneCallParams *params=linphone_call_get_current_params(call);
const char *filepath=linphone_call_params_get_record_file(params);
gchar *message=g_strdup_printf(_("<small><i>Recording into %s %s</i></small>"),filepath,active ? "" : _("(Paused)"));
gboolean is_conf=FALSE;
const char *filepath;
gchar *message;
LinphoneCore *lc=linphone_gtk_get_core();
LinphoneCall *call=linphone_gtk_get_currently_displayed_call(&is_conf);
GtkWidget *callview;
GtkWidget *label;
if (call){
callview=(GtkWidget*)linphone_call_get_user_pointer (call);
const LinphoneCallParams *params=linphone_call_get_current_params(call);
filepath=linphone_call_params_get_record_file(params);
label=linphone_gtk_get_widget(callview,"record_status");
}else if (is_conf){
GtkWidget *mw=linphone_gtk_get_main_window();
callview=(GtkWidget *)g_object_get_data(G_OBJECT(linphone_gtk_get_main_window()),"conf_frame");
label=linphone_gtk_get_widget(callview,"conf_record_status");
filepath=(const char*)g_object_get_data(G_OBJECT(mw),"conf_record_path");
if (filepath==NULL){
filepath=linphone_gtk_get_record_path(NULL,TRUE);
g_object_set_data_full(G_OBJECT(mw),"conf_record_path",(char*)filepath,g_free);
}
}else{
g_warning("linphone_gtk_record_call_toggled(): bug.");
return;
}
message=g_strdup_printf(_("<small><i>Recording into\n%s %s</i></small>"),filepath,active ? "" : _("(Paused)"));
if (active){
linphone_call_start_recording(call);
if (call)
linphone_call_start_recording(call);
else
linphone_core_start_conference_recording(lc,filepath);
}else {
linphone_call_stop_recording(call);
if (call)
linphone_call_stop_recording(call);
else
linphone_core_stop_conference_recording(lc);
}
gtk_label_set_markup(GTK_LABEL(linphone_gtk_get_widget(callview,"record_status")),message);
gtk_label_set_markup(GTK_LABEL(label),message);
g_free(message);
}

View file

@ -149,3 +149,5 @@ void linphone_gtk_uninit_instance(void);
void linphone_gtk_monitor_usb(void);
void linphone_gtk_unmonitor_usb(void);
gchar *linphone_gtk_get_record_path(const LinphoneAddress *address, gboolean is_conference);

View file

@ -750,14 +750,35 @@ static void linphone_gtk_update_call_buttons(LinphoneCall *call){
}
}
gchar *linphone_gtk_get_call_record_path(LinphoneAddress *address){
gchar *linphone_gtk_get_record_path(const LinphoneAddress *address, gboolean is_conference){
const char *dir=g_get_user_special_dir(G_USER_DIRECTORY_MUSIC);
const char *id=linphone_address_get_username(address);
const char *id="unknown";
char filename[256]={0};
if (id==NULL) id=linphone_address_get_domain(address);
snprintf(filename,sizeof(filename)-1,"%s-%lu-%s-record.wav",
linphone_gtk_get_ui_config("title","Linphone"),
(unsigned long)time(NULL),id);
char date[64]={0};
time_t curtime=time(NULL);
struct tm loctime;
#ifdef WIN32
loctime=*localtime(&curtime);
#else
localtime_r(&curtime,&loctime);
#endif
snprintf(date,sizeof(date)-1,"%i%02i%02i-%02i%02i",loctime.tm_year+1900,loctime.tm_mon+1,loctime.tm_mday, loctime.tm_hour, loctime.tm_min);
if (address){
id=linphone_address_get_username(address);
if (id==NULL) id=linphone_address_get_domain(address);
}
if (is_conference){
snprintf(filename,sizeof(filename)-1,"%s-conference-%s.wav",
linphone_gtk_get_ui_config("title","Linphone"),
date);
}else{
snprintf(filename,sizeof(filename)-1,"%s-call-%s-%s.wav",
linphone_gtk_get_ui_config("title","Linphone"),
date,
id);
}
return g_build_filename(dir,filename,NULL);
}
@ -768,7 +789,7 @@ static gboolean linphone_gtk_start_call_do(GtkWidget *uri_bar){
if (addr!=NULL){
LinphoneCallParams *params=linphone_core_create_default_call_parameters(lc);
gchar *record_file=linphone_gtk_get_call_record_path(addr);
gchar *record_file=linphone_gtk_get_record_path(addr,FALSE);
linphone_call_params_set_record_file(params,record_file);
linphone_core_invite_address_with_params(lc,addr,params);
completion_add_text(GTK_ENTRY(uri_bar),entered);
@ -781,24 +802,34 @@ static gboolean linphone_gtk_start_call_do(GtkWidget *uri_bar){
return FALSE;
}
static void accept_incoming_call(LinphoneCall *call){
LinphoneCore *lc=linphone_gtk_get_core();
LinphoneCallParams *params=linphone_core_create_default_call_parameters(lc);
gchar *record_file=linphone_gtk_get_record_path(linphone_call_get_remote_address(call),FALSE);
linphone_call_params_set_record_file(params,record_file);
linphone_core_accept_call_with_params(lc,call,params);
linphone_call_params_destroy(params);
}
static gboolean linphone_gtk_auto_answer(LinphoneCall *call){
if (linphone_call_get_state(call)==LinphoneCallIncomingReceived){
linphone_core_accept_call (linphone_gtk_get_core(),call);
LinphoneCallState state=linphone_call_get_state(call);
if (state==LinphoneCallIncomingReceived || state==LinphoneCallIncomingEarlyMedia){
accept_incoming_call(call);
linphone_call_unref(call);
}
return FALSE;
}
void linphone_gtk_start_call(GtkWidget *w){
LinphoneCore *lc=linphone_gtk_get_core();
LinphoneCall *call;
LinphoneCall *call=linphone_gtk_get_currently_displayed_call(NULL);
/*change into in-call mode, then do the work later as it might block a bit */
GtkWidget *mw=gtk_widget_get_toplevel(w);
GtkWidget *uri_bar=linphone_gtk_get_widget(mw,"uribar");
LinphoneCallState state= call ? linphone_call_get_state(call) : LinphoneCallIdle;
call=linphone_gtk_get_currently_displayed_call(NULL);
if (call!=NULL && linphone_call_get_state(call)==LinphoneCallIncomingReceived){
linphone_core_accept_call(lc,call);
if (state == LinphoneCallIncomingReceived || state == LinphoneCallIncomingEarlyMedia){
accept_incoming_call(call);
}else{
/*immediately disable the button and delay a bit the execution the linphone_core_invite()
so that we don't freeze the button. linphone_core_invite() might block for some hundreds of milliseconds*/
@ -831,7 +862,7 @@ void linphone_gtk_decline_clicked(GtkWidget *button){
void linphone_gtk_answer_clicked(GtkWidget *button){
LinphoneCall *call=linphone_gtk_get_currently_displayed_call(NULL);
if (call){
linphone_core_accept_call(linphone_gtk_get_core(),call);
accept_incoming_call(call);
linphone_gtk_show_main_window(); /* useful when the button is clicked on a notification */
}
}

View file

@ -215,9 +215,6 @@
<object class="GtkVBox" id="conf_box">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<placeholder/>
</child>
<child>
<object class="GtkHButtonBox" id="button_conf">
<property name="visible">True</property>
@ -242,9 +239,53 @@
<property name="expand">True</property>
<property name="fill">True</property>
<property name="pack_type">end</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkHBox" id="conf_record_hbox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkToggleButton" id="conf_record_button">
<property name="label">gtk-media-record</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_action_appearance">False</property>
<property name="use_stock">True</property>
<signal name="toggled" handler="linphone_gtk_record_call_toggled" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="conf_record_status">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="wrap">True</property>
<property name="wrap_mode">char</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="pack_type">end</property>
<property name="position">1</property>
</packing>
</child>
<child>
<placeholder/>
</child>
</object>
</child>
</object>

View file

@ -972,7 +972,8 @@ static void linphone_gtk_show_media_encryption(GtkWidget *pb){
}
g_signal_connect(G_OBJECT(combo),"changed",(GCallback)linphone_gtk_media_encryption_changed,NULL);
}
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(pb,"media_encryption_mandatory")),linphone_core_is_media_encryption_mandatory(lc));
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(pb,"media_encryption_mandatory")),
linphone_core_is_media_encryption_mandatory(lc));
g_object_unref(G_OBJECT(model));
}
@ -1015,10 +1016,8 @@ void linphone_gtk_show_parameters(void){
if (pb==NULL) {
pb=linphone_gtk_create_window("parameters");
g_object_set_data(G_OBJECT(mw),"parameters",pb);
ms_error("linphone_gtk_show_paramters: create");
}else {
gtk_widget_show(pb);
ms_error("linphone_gtk_show_parameters: show");
return;
}
codec_list=linphone_gtk_get_widget(pb,"codec_list");
@ -1028,21 +1027,21 @@ void linphone_gtk_show_parameters(void){
linphone_core_ipv6_enabled(lc));
linphone_core_get_sip_transports(lc,&tr);
if (tr.tcp_port > 0) {
gtk_combo_box_set_active(GTK_COMBO_BOX(linphone_gtk_get_widget(pb,"proto_combo")), 1);
gtk_spin_button_set_value(GTK_SPIN_BUTTON(linphone_gtk_get_widget(pb,"proto_port")),
if (tr.tcp_port > 0) {
gtk_combo_box_set_active(GTK_COMBO_BOX(linphone_gtk_get_widget(pb,"proto_combo")), 1);
gtk_spin_button_set_value(GTK_SPIN_BUTTON(linphone_gtk_get_widget(pb,"proto_port")),
tr.tcp_port);
}
else if (tr.tls_port > 0) {
gtk_combo_box_set_active(GTK_COMBO_BOX(linphone_gtk_get_widget(pb,"proto_combo")), 2);
gtk_spin_button_set_value(GTK_SPIN_BUTTON(linphone_gtk_get_widget(pb,"proto_port")),
}
else if (tr.tls_port > 0) {
gtk_combo_box_set_active(GTK_COMBO_BOX(linphone_gtk_get_widget(pb,"proto_combo")), 2);
gtk_spin_button_set_value(GTK_SPIN_BUTTON(linphone_gtk_get_widget(pb,"proto_port")),
tr.tls_port);
}
else {
gtk_combo_box_set_active(GTK_COMBO_BOX(linphone_gtk_get_widget(pb,"proto_combo")), 0);
gtk_spin_button_set_value(GTK_SPIN_BUTTON(linphone_gtk_get_widget(pb,"proto_port")),
}
else {
gtk_combo_box_set_active(GTK_COMBO_BOX(linphone_gtk_get_widget(pb,"proto_combo")), 0);
gtk_spin_button_set_value(GTK_SPIN_BUTTON(linphone_gtk_get_widget(pb,"proto_port")),
tr.udp_port);
}
}
linphone_core_get_audio_port_range(lc, &min_port, &max_port);
gtk_spin_button_set_value(GTK_SPIN_BUTTON(linphone_gtk_get_widget(pb, "audio_min_rtp_port")), min_port);
@ -1083,6 +1082,10 @@ void linphone_gtk_show_parameters(void){
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(pb,"use_upnp")),TRUE);
break;
}
if(!linphone_core_upnp_available(lc)) {
gtk_widget_hide(linphone_gtk_get_widget(pb,"use_upnp"));
}
mtu=linphone_core_get_mtu(lc);
if (mtu<=0){
gtk_widget_set_sensitive(linphone_gtk_get_widget(pb,"mtu"),FALSE);

0
gtk/update.c Executable file → Normal file
View file

View file

@ -396,6 +396,10 @@ public interface LinphoneCore {
* @param aCall to be terminated
*/
public void terminateCall(LinphoneCall aCall);
/**
* Declines an incoming call, providing a reason for declining it.
*/
public void declineCall(LinphoneCall aCall, Reason reason);
/**
* Returns The LinphoneCall the current call if one is in call
*
@ -744,6 +748,12 @@ public interface LinphoneCore {
**/
void startEchoCalibration(Object data) throws LinphoneCoreException;
/**
* Returns true if echo calibration is recommended.
* If the device has a builtin echo canceller or calibration value is already known, it will return false.
*/
boolean needsEchoCalibration();
void enableIpv6(boolean enable);
/**
* @deprecated
@ -751,25 +761,63 @@ public interface LinphoneCore {
*/
void adjustSoftwareVolume(int i);
/**
* Pause a call.
**/
boolean pauseCall(LinphoneCall call);
/**
* Resume a call.
**/
boolean resumeCall(LinphoneCall call);
boolean pauseAllCalls();
void setZrtpSecretsCache(String file);
void enableEchoLimiter(boolean val);
/**
* Indicates whether the local user is part of the conference.
**/
boolean isInConference();
/**
* Connect the local user to the conference.
**/
boolean enterConference();
/**
* Disconnect the local user from the conference.
**/
void leaveConference();
/**
* Add an established call to the conference. The LinphoneCore is able to manage one client based conference.
**/
void addToConference(LinphoneCall call);
void addAllToConference();
/**
* Remove an established call from the conference.
**/
void removeFromConference(LinphoneCall call);
void addAllToConference();
/**
* Terminate the conference, all users are disconnected.
**/
void terminateConference();
int getConferenceSize();
/**
* Request recording of the conference into a supplied file path.
* The format is wav.
**/
void startConferenceRecording(String path);
/**
* Stop recording of the conference.
**/
void stopConferenceRecording();
void terminateAllCalls();
/**
* Returns all calls.
**/
LinphoneCall[] getCalls();
int getCallsNb();

View file

@ -0,0 +1,56 @@
package org.linphone.core;
import java.util.Vector;
public class Reason {
static private Vector<Reason> values = new Vector<Reason>();
/**
* None (no failure)
*/
static public Reason None = new Reason(0,"None");
/**
* No response
*/
static public Reason NoResponse = new Reason(1,"NoResponse");
/**
* Bad credentials
*/
static public Reason BadCredentials = new Reason(2,"BadCredentials");
/**
* Call declined
*/
static public Reason Declined = new Reason(3,"Declined");
/**
* Not found
*/
static public Reason NotFound = new Reason(4,"NotFound");
/**
* Call not answered (in time).
*/
static public Reason NotAnswered = new Reason(5,"NotAnswered");
/**
* Call not answered (in time).
*/
static public Reason Busy = new Reason(6,"Busy");
protected final int mValue;
private final String mStringValue;
private Reason(int value,String stringValue) {
mValue = value;
values.addElement(this);
mStringValue=stringValue;
}
public static Reason fromInt(int value) {
for (int i=0; i<values.size();i++) {
Reason state = (Reason) values.elementAt(i);
if (state.mValue == value) return state;
}
throw new RuntimeException("Reason not found ["+value+"]");
}
public String toString() {
return mStringValue;
}
}

View file

@ -757,30 +757,30 @@ class LinphoneCoreImpl implements LinphoneCore {
setVideoPolicy(nativePtr, autoInitiate, autoAccept);
}
private native void setStaticPicture(long nativePtr, String path);
public void setStaticPicture(String path) {
public synchronized void setStaticPicture(String path) {
setStaticPicture(nativePtr, path);
}
private native void setUserAgent(long nativePtr, String name, String version);
@Override
public void setUserAgent(String name, String version) {
public synchronized void setUserAgent(String name, String version) {
setUserAgent(nativePtr,name,version);
}
private native void setCpuCountNative(int count);
public void setCpuCount(int count)
public synchronized void setCpuCount(int count)
{
setCpuCountNative(count);
}
public int getMissedCallsCount() {
public synchronized int getMissedCallsCount() {
return getMissedCallsCount(nativePtr);
}
public void removeCallLog(LinphoneCallLog log) {
public synchronized void removeCallLog(LinphoneCallLog log) {
removeCallLog(nativePtr, ((LinphoneCallLogImpl) log).getNativePtr());
}
public void resetMissedCallsCount() {
public synchronized void resetMissedCallsCount() {
resetMissedCallsCount(nativePtr);
}
@ -793,7 +793,7 @@ class LinphoneCoreImpl implements LinphoneCore {
}
private native void refreshRegisters(long nativePtr);
public void refreshRegisters() {
public synchronized void refreshRegisters() {
refreshRegisters(nativePtr);
}
@ -803,19 +803,19 @@ class LinphoneCoreImpl implements LinphoneCore {
}
@Override
public PayloadType findPayloadType(String mime, int clockRate) {
public synchronized PayloadType findPayloadType(String mime, int clockRate) {
return findPayloadType(mime, clockRate, 1);
}
private native void removeFriend(long ptr, long lf);
@Override
public void removeFriend(LinphoneFriend lf) {
public synchronized void removeFriend(LinphoneFriend lf) {
removeFriend(nativePtr, lf.getNativePtr());
}
private native long getFriendByAddress(long ptr, String sipUri);
@Override
public LinphoneFriend findFriendByAddress(String sipUri) {
public synchronized LinphoneFriend findFriendByAddress(String sipUri) {
long ptr = getFriendByAddress(nativePtr, sipUri);
if (ptr == 0) {
return null;
@ -823,55 +823,65 @@ class LinphoneCoreImpl implements LinphoneCore {
return new LinphoneFriendImpl(ptr);
}
public void setAudioPort(int port) {
public synchronized void setAudioPort(int port) {
setAudioPort(nativePtr, port);
}
public void setVideoPort(int port) {
public synchronized void setVideoPort(int port) {
setVideoPort(nativePtr, port);
}
public void setAudioPortRange(int minPort, int maxPort) {
public synchronized void setAudioPortRange(int minPort, int maxPort) {
setAudioPortRange(nativePtr, minPort, maxPort);
}
public void setVideoPortRange(int minPort, int maxPort) {
public synchronized void setVideoPortRange(int minPort, int maxPort) {
setVideoPortRange(nativePtr, minPort, maxPort);
}
public void setIncomingTimeout(int timeout) {
public synchronized void setIncomingTimeout(int timeout) {
setIncomingTimeout(nativePtr, timeout);
}
public void setInCallTimeout(int timeout)
public synchronized void setInCallTimeout(int timeout)
{
setInCallTimeout(nativePtr, timeout);
}
private native void setMicrophoneGain(long ptr, float gain);
public void setMicrophoneGain(float gain) {
public synchronized void setMicrophoneGain(float gain) {
setMicrophoneGain(nativePtr, gain);
}
public void setPrimaryContact(String displayName, String username) {
public synchronized void setPrimaryContact(String displayName, String username) {
setPrimaryContact(nativePtr, displayName, username);
}
private native void setUseSipInfoForDtmfs(long ptr, boolean use);
public void setUseSipInfoForDtmfs(boolean use) {
public synchronized void setUseSipInfoForDtmfs(boolean use) {
setUseSipInfoForDtmfs(nativePtr, use);
}
private native void setUseRfc2833ForDtmfs(long ptr, boolean use);
public void setUseRfc2833ForDtmfs(boolean use) {
public synchronized void setUseRfc2833ForDtmfs(boolean use) {
setUseRfc2833ForDtmfs(nativePtr, use);
}
private native long getConfig(long ptr);
public LpConfig getConfig() {
public synchronized LpConfig getConfig() {
long configPtr=getConfig(nativePtr);
return new LpConfigImpl(configPtr);
}
private native boolean needsEchoCalibration(long ptr);
@Override
public synchronized boolean needsEchoCalibration() {
return needsEchoCalibration(nativePtr);
}
private native void declineCall(long coreptr, long callptr, int reason);
@Override
public synchronized void declineCall(LinphoneCall aCall, Reason reason) {
declineCall(nativePtr,((LinphoneCallImpl)aCall).nativePtr,reason.mValue);
}
private native boolean upnpAvailable(long ptr);
public boolean upnpAvailable() {
@ -887,4 +897,15 @@ class LinphoneCoreImpl implements LinphoneCore {
public String getUpnpExternalIpaddress() {
return getUpnpExternalIpaddress(nativePtr);
}
private native int startConferenceRecording(long nativePtr, String path);
@Override
public void startConferenceRecording(String path) {
startConferenceRecording(nativePtr,path);
}
private native int stopConferenceRecording(long nativePtr);
@Override
public void stopConferenceRecording() {
stopConferenceRecording(nativePtr);
}
}

View file

@ -1,558 +0,0 @@
<?xml version = '1.0'?>
<kdevelop>
<general>
<author>Simon Morlat</author>
<email>simon.morlat@linphone.org</email>
<version>[3.1.2]</version>
<projectmanagement>KDevCustomProject</projectmanagement>
<primarylanguage>C</primarylanguage>
<ignoreparts/>
<projectname>linphone</projectname>
<projectdirectory>.</projectdirectory>
<absoluteprojectpath>false</absoluteprojectpath>
<description/>
<defaultencoding/>
</general>
<kdevcustomproject>
<run>
<directoryradio>executable</directoryradio>
<mainprogram>gtk-glade/linphone</mainprogram>
<programargs/>
<globaldebugarguments/>
<globalcwd/>
<useglobalprogram>false</useglobalprogram>
<terminal>false</terminal>
<autocompile>false</autocompile>
<autoinstall>false</autoinstall>
<autokdesu>false</autokdesu>
<envvars/>
</run>
<filetypes>
<filetype>*.java</filetype>
<filetype>*.h</filetype>
<filetype>*.H</filetype>
<filetype>*.hh</filetype>
<filetype>*.hxx</filetype>
<filetype>*.hpp</filetype>
<filetype>*.c</filetype>
<filetype>*.C</filetype>
<filetype>*.cc</filetype>
<filetype>*.cpp</filetype>
<filetype>*.c++</filetype>
<filetype>*.cxx</filetype>
</filetypes>
<blacklist>
<path>config.h</path>
<path>exosip</path>
<path>exosip/eXosip2.h</path>
<path>exosip/eXosip.c</path>
<path>exosip/eXosip_cfg.h</path>
<path>exosip/eXosip.h</path>
<path>exosip/eXutils.c</path>
<path>exosip/jauth.c</path>
<path>exosip/jcallback.c</path>
<path>exosip/jcall.c</path>
<path>exosip/jdialog.c</path>
<path>exosip/jevents.c</path>
<path>exosip/jfreinds.c</path>
<path>exosip/jidentity.c</path>
<path>exosip/jnotify.c</path>
<path>exosip/jpipe.c</path>
<path>exosip/jpipe.h</path>
<path>exosip/jpublish.c</path>
<path>exosip/jreg.c</path>
<path>exosip/jrequest.c</path>
<path>exosip/jresponse.c</path>
<path>exosip/jsubscribe.c</path>
<path>exosip/jsubscribers.c</path>
<path>exosip/misc.c</path>
<path>exosip/sdp_offans.c</path>
<path>exosip/udp.c</path>
<path>gnome</path>
<path>gnome/addressbook.c</path>
<path>gnome/addressbook.h</path>
<path>gnome/applet.c</path>
<path>gnome/callbacks.c</path>
<path>gnome/callbacks.h</path>
<path>gnome/friends.c</path>
<path>gnome/friends.h</path>
<path>gnome/gui_utils.c</path>
<path>gnome/gui_utils.h</path>
<path>gnome/interface.c</path>
<path>gnome/interface.h</path>
<path>gnome/linphone.c</path>
<path>gnome/linphone.h</path>
<path>gnome/main.c</path>
<path>gnome/presence.c</path>
<path>gnome/presence.h</path>
<path>gnome/propertybox.c</path>
<path>gnome/propertybox.h</path>
<path>gnome/support.c</path>
<path>gnome/support.h</path>
<path>gsmlib</path>
<path>gsmlib/code.c</path>
<path>gsmlib/config.h</path>
<path>gsmlib/debug.c</path>
<path>gsmlib/decode.c</path>
<path>gsmlib/gsmadd.c</path>
<path>gsmlib/gsm_create.c</path>
<path>gsmlib/gsm_decode.c</path>
<path>gsmlib/gsm_destroy.c</path>
<path>gsmlib/gsm_encode.c</path>
<path>gsmlib/gsm_explode.c</path>
<path>gsmlib/gsm.h</path>
<path>gsmlib/gsm_implode.c</path>
<path>gsmlib/gsm_option.c</path>
<path>gsmlib/gsm_print.c</path>
<path>gsmlib/gsm_wrapper.c</path>
<path>gsmlib/gsm_wrapper.h</path>
<path>gsmlib/long_term.c</path>
<path>gsmlib/lpc.c</path>
<path>gsmlib/preprocess.c</path>
<path>gsmlib/private.h</path>
<path>gsmlib/proto.h</path>
<path>gsmlib/rpe.c</path>
<path>gsmlib/short_term.c</path>
<path>gsmlib/table.c</path>
<path>gsmlib/toast.h</path>
<path>gsmlib/unproto.h</path>
<path>gtk</path>
<path>gtk/addressbook.c</path>
<path>gtk/addressbook.h</path>
<path>gtk/applet.c</path>
<path>gtk/callbacks.c</path>
<path>gtk/callbacks.h</path>
<path>gtk/friends.c</path>
<path>gtk/friends.h</path>
<path>gtk/gui_utils.c</path>
<path>gtk/gui_utils.h</path>
<path>gtk/interface.c</path>
<path>gtk/interface.h</path>
<path>gtk/linphone.c</path>
<path>gtk/linphone.h</path>
<path>gtk/main.c</path>
<path>gtk/presence.c</path>
<path>gtk/presence.h</path>
<path>gtk/propertybox.c</path>
<path>gtk/propertybox.h</path>
<path>gtk/support.c</path>
<path>gtk/support.h</path>
<path>intl</path>
<path>intl/bindtextdom.c</path>
<path>intl/cat-compat.c</path>
<path>intl/dcgettext.c</path>
<path>intl/dgettext.c</path>
<path>intl/explodename.c</path>
<path>intl/finddomain.c</path>
<path>intl/gettext.c</path>
<path>intl/gettext.h</path>
<path>intl/gettextP.h</path>
<path>intl/hash-string.h</path>
<path>intl/intl-compat.c</path>
<path>intl/l10nflist.c</path>
<path>intl/libgettext.h</path>
<path>intl/loadinfo.h</path>
<path>intl/loadmsgcat.c</path>
<path>intl/localealias.c</path>
<path>intl/textdomain.c</path>
<path>lpc10-1.5</path>
<path>lpc10-1.5/analys.c</path>
<path>lpc10-1.5/bitio.c</path>
<path>lpc10-1.5/bsynz.c</path>
<path>lpc10-1.5/chanwr.c</path>
<path>lpc10-1.5/dcbias.c</path>
<path>lpc10-1.5/decode.c</path>
<path>lpc10-1.5/deemp.c</path>
<path>lpc10-1.5/difmag.c</path>
<path>lpc10-1.5/dyptrk.c</path>
<path>lpc10-1.5/encode.c</path>
<path>lpc10-1.5/energy.c</path>
<path>lpc10-1.5/f2c.h</path>
<path>lpc10-1.5/f2clib.c</path>
<path>lpc10-1.5/ham84.c</path>
<path>lpc10-1.5/hp100.c</path>
<path>lpc10-1.5/invert.c</path>
<path>lpc10-1.5/irc2pc.c</path>
<path>lpc10-1.5/ivfilt.c</path>
<path>lpc10-1.5/lpc10.h</path>
<path>lpc10-1.5/lpc10_wrapper.c</path>
<path>lpc10-1.5/lpc10_wrapper.h</path>
<path>lpc10-1.5/lpcdec.c</path>
<path>lpc10-1.5/lpcenc.c</path>
<path>lpc10-1.5/lpcini.c</path>
<path>lpc10-1.5/lpfilt.c</path>
<path>lpc10-1.5/median.c</path>
<path>lpc10-1.5/mload.c</path>
<path>lpc10-1.5/onset.c</path>
<path>lpc10-1.5/pitsyn.c</path>
<path>lpc10-1.5/placea.c</path>
<path>lpc10-1.5/placev.c</path>
<path>lpc10-1.5/preemp.c</path>
<path>lpc10-1.5/prepro.c</path>
<path>lpc10-1.5/random.c</path>
<path>lpc10-1.5/rcchk.c</path>
<path>lpc10-1.5/synths.c</path>
<path>lpc10-1.5/tbdm.c</path>
<path>lpc10-1.5/voicin.c</path>
<path>lpc10-1.5/vparms.c</path>
<path>media_api</path>
<path>media_api/apitest.c</path>
<path>media_api/apitest.h</path>
<path>media_api/basiccall.c</path>
<path>media_api/basiccall.h</path>
<path>media_api/callmember.c</path>
<path>media_api/callmember.h</path>
<path>media_api/common.h</path>
<path>media_api/media_api.c</path>
<path>media_api/media_api.h</path>
<path>media_api/mediaflow.c</path>
<path>media_api/mediaflow.h</path>
<path>mediastreamer</path>
<path>mediastreamer/affine.c</path>
<path>mediastreamer/affine.h</path>
<path>mediastreamer/alsacard.c</path>
<path>mediastreamer/alsacard.h</path>
<path>mediastreamer/audiostream.c</path>
<path>mediastreamer/g711common.h</path>
<path>mediastreamer/hpuxsndcard.c</path>
<path>mediastreamer/jackcard.c</path>
<path>mediastreamer/jackcard.h</path>
<path>mediastreamer/mediastream.c</path>
<path>mediastreamer/mediastream.h</path>
<path>mediastreamer/msAlawdec.c</path>
<path>mediastreamer/msAlawdec.h</path>
<path>mediastreamer/msAlawenc.c</path>
<path>mediastreamer/msAlawenc.h</path>
<path>mediastreamer/msavdecoder.c</path>
<path>mediastreamer/msavdecoder.h</path>
<path>mediastreamer/msavencoder.c</path>
<path>mediastreamer/msavencoder.h</path>
<path>mediastreamer/msbuffer.c</path>
<path>mediastreamer/msbuffer.h</path>
<path>mediastreamer/ms.c</path>
<path>mediastreamer/mscodec.c</path>
<path>mediastreamer/mscodec.h</path>
<path>mediastreamer/mscopy.c</path>
<path>mediastreamer/mscopy.h</path>
<path>mediastreamer/msfdispatcher.c</path>
<path>mediastreamer/msfdispatcher.h</path>
<path>mediastreamer/msfifo.c</path>
<path>mediastreamer/msfifo.h</path>
<path>mediastreamer/msfilter.c</path>
<path>mediastreamer/msfilter.h</path>
<path>mediastreamer/msGSMdecoder.c</path>
<path>mediastreamer/msGSMdecoder.h</path>
<path>mediastreamer/msGSMencoder.c</path>
<path>mediastreamer/msGSMencoder.h</path>
<path>mediastreamer/ms.h</path>
<path>mediastreamer/msLPC10decoder.c</path>
<path>mediastreamer/msLPC10decoder.h</path>
<path>mediastreamer/msLPC10encoder.c</path>
<path>mediastreamer/msLPC10encoder.h</path>
<path>mediastreamer/msMUlawdec.c</path>
<path>mediastreamer/msMUlawdec.h</path>
<path>mediastreamer/msMUlawenc.c</path>
<path>mediastreamer/msMUlawenc.h</path>
<path>mediastreamer/msnosync.c</path>
<path>mediastreamer/msnosync.h</path>
<path>mediastreamer/msossread.c</path>
<path>mediastreamer/msossread.h</path>
<path>mediastreamer/msosswrite.c</path>
<path>mediastreamer/msosswrite.h</path>
<path>mediastreamer/msqdispatcher.c</path>
<path>mediastreamer/msqdispatcher.h</path>
<path>mediastreamer/msqueue.c</path>
<path>mediastreamer/msqueue.h</path>
<path>mediastreamer/msread.c</path>
<path>mediastreamer/msread.h</path>
<path>mediastreamer/msringplayer.c</path>
<path>mediastreamer/msringplayer.h</path>
<path>mediastreamer/msrtprecv.c</path>
<path>mediastreamer/msrtprecv.h</path>
<path>mediastreamer/msrtpsend.c</path>
<path>mediastreamer/msrtpsend.h</path>
<path>mediastreamer/mssdlout.c</path>
<path>mediastreamer/mssdlout.h</path>
<path>mediastreamer/mssmpeg.c</path>
<path>mediastreamer/mssmpeg.h</path>
<path>mediastreamer/mssoundread.c</path>
<path>mediastreamer/mssoundread.h</path>
<path>mediastreamer/mssoundwrite.c</path>
<path>mediastreamer/mssoundwrite.h</path>
<path>mediastreamer/msspeexdec.c</path>
<path>mediastreamer/msspeexdec.h</path>
<path>mediastreamer/msspeexenc.c</path>
<path>mediastreamer/msspeexenc.h</path>
<path>mediastreamer/mssync.c</path>
<path>mediastreamer/mssync.h</path>
<path>mediastreamer/mstcpclient.c</path>
<path>mediastreamer/mstcpclient.h</path>
<path>mediastreamer/mstcpserv.c</path>
<path>mediastreamer/mstcpserv.h</path>
<path>mediastreamer/mstimer.c</path>
<path>mediastreamer/mstimer.h</path>
<path>mediastreamer/mstruespeechdecoder.c</path>
<path>mediastreamer/mstruespeechdecoder.h</path>
<path>mediastreamer/mstruespeechencoder.c</path>
<path>mediastreamer/mstruespeechencoder.h</path>
<path>mediastreamer/msutils.h</path>
<path>mediastreamer/msv4l.c</path>
<path>mediastreamer/msv4l.h</path>
<path>mediastreamer/msvideooutput.c</path>
<path>mediastreamer/msvideooutput.h</path>
<path>mediastreamer/msvideosource.c</path>
<path>mediastreamer/msvideosource.h</path>
<path>mediastreamer/mswrite.c</path>
<path>mediastreamer/mswrite.h</path>
<path>mediastreamer/msxine.c</path>
<path>mediastreamer/msxine.h</path>
<path>mediastreamer/osscard.c</path>
<path>mediastreamer/osscard.h</path>
<path>mediastreamer/rfc2429.h</path>
<path>mediastreamer/ring_test.c</path>
<path>mediastreamer/sndcard.c</path>
<path>mediastreamer/sndcard.h</path>
<path>mediastreamer/test_alaw.c</path>
<path>mediastreamer/test.c</path>
<path>mediastreamer/test_gsm.c</path>
<path>mediastreamer/test_lpc10.c</path>
<path>mediastreamer/test_mulaw.c</path>
<path>mediastreamer/test_rtprecv.c</path>
<path>mediastreamer/test_smpeg.c</path>
<path>mediastreamer/test_speex.c</path>
<path>mediastreamer/test_truespeech.c</path>
<path>mediastreamer/test_v4l.c</path>
<path>mediastreamer/test_videostream.c</path>
<path>mediastreamer/test_xine.c</path>
<path>mediastreamer/videoclient.c</path>
<path>mediastreamer/videoserver.c</path>
<path>mediastreamer/videostream.c</path>
<path>mediastreamer/waveheader.h</path>
<path>po</path>
<path>po/cat-id-tbl.c</path>
<path>win32acm</path>
<path>win32acm/afl.c</path>
<path>win32acm/com.h</path>
<path>win32acm/config.h</path>
<path>win32acm/cpudetect.c</path>
<path>win32acm/cpudetect.h</path>
<path>win32acm/cputable.h</path>
<path>win32acm/driver.c</path>
<path>win32acm/driver.h</path>
<path>win32acm/elfdll.c</path>
<path>win32acm/ext.c</path>
<path>win32acm/ext.h</path>
<path>win32acm/ldt_keeper.c</path>
<path>win32acm/ldt_keeper.h</path>
<path>win32acm/loader.h</path>
<path>win32acm/module.c</path>
<path>win32acm/mp_msg.c</path>
<path>win32acm/mp_msg.h</path>
<path>win32acm/pe_image.c</path>
<path>win32acm/pe_resource.c</path>
<path>win32acm/registry.c</path>
<path>win32acm/registry.h</path>
<path>win32acm/resource.c</path>
<path>win32acm/test_truespeech.c</path>
<path>win32acm/win32.c</path>
<path>win32acm/win32codec.c</path>
<path>win32acm/win32codec.h</path>
<path>win32acm/win32.h</path>
<path>win32acm/wine</path>
<path>win32acm/wine/basetsd.h</path>
<path>win32acm/wine/debugtools.h</path>
<path>win32acm/wine/driver.h</path>
<path>win32acm/wine/elfdll.h</path>
<path>win32acm/wine/heap.h</path>
<path>win32acm/wine/ldt.h</path>
<path>win32acm/wine/mmreg.h</path>
<path>win32acm/wine/module.h</path>
<path>win32acm/wine/msacmdrv.h</path>
<path>win32acm/wine/msacm.h</path>
<path>win32acm/wine/ntdef.h</path>
<path>win32acm/wine/pe_image.h</path>
<path>win32acm/wine/poppack.h</path>
<path>win32acm/wine/pshpack1.h</path>
<path>win32acm/wine/pshpack2.h</path>
<path>win32acm/wine/pshpack4.h</path>
<path>win32acm/wine/pshpack8.h</path>
<path>win32acm/wine/vfw.h</path>
<path>win32acm/wine/winbase.h</path>
<path>win32acm/wine/windef.h</path>
<path>win32acm/wine/windows.h</path>
<path>win32acm/wine/winerror.h</path>
<path>win32acm/wine/winestring.h</path>
<path>win32acm/wine/winnt.h</path>
<path>win32acm/wine/winreg.h</path>
<path>win32acm/wine/winuser.h</path>
<path>win32acm/wineacm.h</path>
<path>win32acm/wrapper.h</path>
<path>builddate.h</path>
</blacklist>
<build>
<buildtool>make</buildtool>
<builddir/>
</build>
<other>
<prio>0</prio>
<otherbin/>
<defaulttarget/>
<otheroptions/>
<selectedenvironment>default</selectedenvironment>
<environments>
<default/>
</environments>
</other>
<make>
<abortonerror>true</abortonerror>
<numberofjobs>0</numberofjobs>
<prio>0</prio>
<dontact>false</dontact>
<makebin/>
<defaulttarget/>
<makeoptions/>
<selectedenvironment>default</selectedenvironment>
<environments>
<default/>
</environments>
</make>
</kdevcustomproject>
<kdevdebugger>
<general>
<dbgshell/>
<gdbpath/>
<configGdbScript/>
<runShellScript/>
<runGdbScript/>
<breakonloadinglibs>true</breakonloadinglibs>
<separatetty>false</separatetty>
<floatingtoolbar>false</floatingtoolbar>
<raiseGDBOnStart>false</raiseGDBOnStart>
</general>
<display>
<staticmembers>false</staticmembers>
<demanglenames>true</demanglenames>
<outputradix>10</outputradix>
</display>
</kdevdebugger>
<kdevdoctreeview>
<ignoretocs>
<toc>ada</toc>
<toc>ada_bugs_gcc</toc>
<toc>bash</toc>
<toc>bash_bugs</toc>
<toc>clanlib</toc>
<toc>fortran_bugs_gcc</toc>
<toc>gnome1</toc>
<toc>gnustep</toc>
<toc>gtk</toc>
<toc>gtk_bugs</toc>
<toc>haskell</toc>
<toc>haskell_bugs_ghc</toc>
<toc>java_bugs_gcc</toc>
<toc>java_bugs_sun</toc>
<toc>kde2book</toc>
<toc>libstdc++</toc>
<toc>opengl</toc>
<toc>pascal_bugs_fp</toc>
<toc>php</toc>
<toc>php_bugs</toc>
<toc>perl</toc>
<toc>perl_bugs</toc>
<toc>python</toc>
<toc>python_bugs</toc>
<toc>qt-kdev3</toc>
<toc>ruby</toc>
<toc>ruby_bugs</toc>
<toc>sdl</toc>
<toc>stl</toc>
<toc>sw</toc>
<toc>w3c-dom-level2-html</toc>
<toc>w3c-svg</toc>
<toc>w3c-uaag10</toc>
<toc>wxwidgets_bugs</toc>
</ignoretocs>
<ignoreqt_xml>
<toc>Guide to the Qt Translation Tools</toc>
<toc>Qt Assistant Manual</toc>
<toc>Qt Designer Manual</toc>
<toc>Qt Reference Documentation</toc>
<toc>qmake User Guide</toc>
</ignoreqt_xml>
<ignoredoxygen>
<toc>KDE Libraries (Doxygen)</toc>
</ignoredoxygen>
</kdevdoctreeview>
<kdevfilecreate>
<filetypes/>
<useglobaltypes>
<type ext="c" />
<type ext="h" />
</useglobaltypes>
</kdevfilecreate>
<kdevcppsupport>
<qt>
<used>false</used>
<version>3</version>
<includestyle>3</includestyle>
<root></root>
<designerintegration>EmbeddedKDevDesigner</designerintegration>
<qmake></qmake>
<designer></designer>
<designerpluginpaths/>
</qt>
<references/>
<codecompletion>
<automaticCodeCompletion>false</automaticCodeCompletion>
<automaticArgumentsHint>true</automaticArgumentsHint>
<automaticHeaderCompletion>true</automaticHeaderCompletion>
<codeCompletionDelay>250</codeCompletionDelay>
<argumentsHintDelay>400</argumentsHintDelay>
<headerCompletionDelay>250</headerCompletionDelay>
<showOnlyAccessibleItems>false</showOnlyAccessibleItems>
<completionBoxItemOrder>0</completionBoxItemOrder>
<howEvaluationContextMenu>true</howEvaluationContextMenu>
<showCommentWithArgumentHint>true</showCommentWithArgumentHint>
<statusBarTypeEvaluation>false</statusBarTypeEvaluation>
<namespaceAliases>std=_GLIBCXX_STD;__gnu_cxx=std</namespaceAliases>
<processPrimaryTypes>true</processPrimaryTypes>
<processFunctionArguments>false</processFunctionArguments>
<preProcessAllHeaders>false</preProcessAllHeaders>
<parseMissingHeadersExperimental>false</parseMissingHeadersExperimental>
<resolveIncludePathsUsingMakeExperimental>false</resolveIncludePathsUsingMakeExperimental>
<alwaysParseInBackground>true</alwaysParseInBackground>
<usePermanentCaching>true</usePermanentCaching>
<alwaysIncludeNamespaces>false</alwaysIncludeNamespaces>
<includePaths>.;</includePaths>
</codecompletion>
<creategettersetter>
<prefixGet/>
<prefixSet>set</prefixSet>
<prefixVariable>m_,_</prefixVariable>
<parameterName>theValue</parameterName>
<inlineGet>true</inlineGet>
<inlineSet>true</inlineSet>
</creategettersetter>
<splitheadersource>
<enabled>false</enabled>
<synchronize>true</synchronize>
<orientation>Vertical</orientation>
</splitheadersource>
</kdevcppsupport>
<kdevfileview>
<groups>
<hidenonprojectfiles>false</hidenonprojectfiles>
<hidenonlocation>false</hidenonlocation>
</groups>
<tree>
<hidepatterns>*.o,*.lo,CVS</hidepatterns>
<hidenonprojectfiles>false</hidenonprojectfiles>
</tree>
</kdevfileview>
<cppsupportpart>
<filetemplates>
<interfacesuffix>.h</interfacesuffix>
<implementationsuffix>.cpp</implementationsuffix>
</filetemplates>
</cppsupportpart>
</kdevelop>

@ -1 +1 @@
Subproject commit 44992c096673ace578ba5248db7019ba1e0d78d5
Subproject commit 4ed2e518cf79c62fe8df7f23ce99e0fbfe2e799d