diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index 6cee4473d51a3267f5ca9a50670ed1fefac6a6b8..f4f0a0425e463355a8c58fdef691d90828ce2b8e 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -532,6 +532,20 @@ static void call_failure(SalOp *op, SalError error, SalReason sr, const char *de lc->vtable.display_status(lc,msg600); break; case SalReasonMedia: + //media_encryption_mandatory + if (call->params.media_encryption == LinphoneMediaEncryptionSRTP && + !linphone_core_is_media_encryption_mandatory(lc)) { + int i; + ms_message("Outgoing call failed with SRTP (SAVP) enabled - retrying with AVP"); + /* clear SRTP local params */ + call->params.media_encryption = LinphoneMediaEncryptionNone; + for(i=0; i<call->localdesc->nstreams; i++) { + call->localdesc->streams[i].proto = SalProtoRtpAvp; + memset(call->localdesc->streams[i].crypto, 0, sizeof(call->localdesc->streams[i].crypto)); + } + linphone_core_start_invite(lc, call, NULL); + return; + } msg=_("No common codecs"); if (lc->vtable.display_status) lc->vtable.display_status(lc,msg); diff --git a/coreapi/conference.c b/coreapi/conference.c index 065a6d99d0fb28607dd9ec8b8025d2db793c4c86..5992024ae23da5eb4f190a9b37518ab0036ddc1f 100644 --- a/coreapi/conference.c +++ b/coreapi/conference.c @@ -140,6 +140,7 @@ int linphone_core_add_to_conference(LinphoneCore *lc, LinphoneCall *call){ conference_check_init(&lc->conf_ctx); call->params.in_conference=TRUE; call->params.has_video=FALSE; + call->params.media_encryption=LinphoneMediaEncryptionNone; params=call->params; if (call->state==LinphoneCallPaused) linphone_core_resume_call(lc,call); diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index dee7a21cc79a7393221dafb1fc99880f5a31bf51..918fb18951a5ee4044decdda4d63521b5721178d 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -26,6 +26,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "lpconfig.h" #include "private.h" #include <ortp/event.h> +#include <ortp/b64.h> #include "mediastreamer2/mediastream.h" @@ -41,6 +42,27 @@ static MSWebCam *get_nowebcam_device(){ } #endif +static bool_t generate_b64_crypto_key(int key_length, char* key_out) { + int b64_size; + uint8_t* tmp = (uint8_t*) malloc(key_length); + if (ortp_crypto_get_random(tmp, key_length)!=0) { + ms_error("Failed to generate random key"); + free(tmp); + return FALSE; + } + + b64_size = b64_encode((const char*)tmp, key_length, NULL, 0); + if (b64_size == 0) { + ms_error("Failed to b64 encode key"); + free(tmp); + return FALSE; + } + key_out[b64_size] = '\0'; + b64_encode((const char*)tmp, key_length, key_out, 40); + free(tmp); + return TRUE; +} + LinphoneCore *linphone_call_get_core(const LinphoneCall *call){ return call->core; } @@ -165,6 +187,7 @@ static MSList *make_codec_list(LinphoneCore *lc, const MSList *codecs, int bandw static SalMediaDescription *_create_local_media_description(LinphoneCore *lc, LinphoneCall *call, unsigned int session_id, unsigned int session_ver){ MSList *l; PayloadType *pt; + int i; const char *me=linphone_core_get_identity(lc); LinphoneAddress *addr=linphone_address_new(me); const char *username=linphone_address_get_username (addr); @@ -180,7 +203,8 @@ static SalMediaDescription *_create_local_media_description(LinphoneCore *lc, Li /*set audio capabilities */ strncpy(md->streams[0].addr,call->localip,sizeof(md->streams[0].addr)); md->streams[0].port=call->audio_port; - md->streams[0].proto=SalProtoRtpAvp; + md->streams[0].proto=(call->params.media_encryption == LinphoneMediaEncryptionSRTP) ? + SalProtoRtpSavp : SalProtoRtpAvp; md->streams[0].type=SalAudio; md->streams[0].ptime=lc->net_conf.down_ptime; l=make_codec_list(lc,lc->codecs_conf.audio_codecs,call->params.audio_bw); @@ -192,11 +216,26 @@ static SalMediaDescription *_create_local_media_description(LinphoneCore *lc, Li if (call->params.has_video){ md->nstreams++; md->streams[1].port=call->video_port; - md->streams[1].proto=SalProtoRtpAvp; + md->streams[1].proto=md->streams[0].proto; md->streams[1].type=SalVideo; l=make_codec_list(lc,lc->codecs_conf.video_codecs,0); md->streams[1].payloads=l; } + + for(i=0; i<md->nstreams; i++) { + if (md->streams[i].proto == SalProtoRtpSavp) { + md->streams[i].crypto[0].tag = 1; + md->streams[i].crypto[0].algo = AES_128_SHA1_80; + if (!generate_b64_crypto_key(30, md->streams[i].crypto[0].master_key)) + md->streams[i].crypto[0].algo = 0; + md->streams[i].crypto[1].tag = 2; + md->streams[i].crypto[1].algo = AES_128_SHA1_32; + if (!generate_b64_crypto_key(30, md->streams[i].crypto[1].master_key)) + md->streams[i].crypto[1].algo = 0; + md->streams[i].crypto[2].algo = 0; + } + } + linphone_address_destroy(addr); return md; } @@ -314,7 +353,7 @@ LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *fro linphone_address_clean(from); linphone_core_get_local_ip(lc,linphone_address_get_domain(from),call->localip); linphone_call_init_common(call, from, to); - call->params.has_video=linphone_core_video_enabled(lc); + linphone_core_init_default_params(lc, &call->params); call->localdesc=create_local_media_description (lc,call); call->camera_active=call->params.has_video; if (linphone_core_get_firewall_policy(call->core)==LinphonePolicyUseStun) @@ -408,7 +447,7 @@ void linphone_call_set_state(LinphoneCall *call, LinphoneCallState cstate, const if (call->state==LinphoneCallEnd || call->state==LinphoneCallError){ if (cstate!=LinphoneCallReleased){ ms_warning("Spurious call state change from %s to %s, ignored.",linphone_call_state_to_string(call->state), - linphone_call_state_to_string(cstate)); + linphone_call_state_to_string(cstate)); return; } } @@ -421,13 +460,13 @@ void linphone_call_set_state(LinphoneCall *call, LinphoneCallState cstate, const } if (cstate==LinphoneCallEnd || cstate==LinphoneCallError){ if (call->reason==LinphoneReasonDeclined){ - call->log->status=LinphoneCallDeclined; - } - linphone_call_set_terminated (call); + call->log->status=LinphoneCallDeclined; + } + linphone_call_set_terminated (call); + } + if (cstate == LinphoneCallConnected) { + call->log->status=LinphoneCallSuccess; } - if (cstate == LinphoneCallConnected) { - call->log->status=LinphoneCallSuccess; - } if (lc->vtable.call_state_changed) lc->vtable.call_state_changed(lc,call,cstate,message); @@ -679,6 +718,15 @@ bool_t linphone_call_params_video_enabled(const LinphoneCallParams *cp){ return cp->has_video; } +enum LinphoneMediaEncryption linphone_call_params_get_media_encryption(LinphoneCallParams *cp) { + return cp->media_encryption; +} + +void linphone_call_params_set_media_encryption(LinphoneCallParams *cp, enum LinphoneMediaEncryption e) { + cp->media_encryption = e; +} + + /** * Enable sending of real early media (during outgoing calls). **/ @@ -989,7 +1037,12 @@ static void linphone_call_start_audio_stream(LinphoneCall *call, const char *cna LinphoneCore *lc=call->core; int jitt_comp=lc->rtp_conf.audio_jitt_comp; int used_pt=-1; + /* look for savp stream first */ const SalStreamDescription *stream=sal_media_description_find_stream(call->resultdesc, + SalProtoRtpSavp,SalAudio); + /* no savp audio stream, use avp */ + if (!stream) + stream=sal_media_description_find_stream(call->resultdesc, SalProtoRtpAvp,SalAudio); if (stream && stream->dir!=SalStreamInactive && stream->port!=0){ @@ -1070,6 +1123,17 @@ static void linphone_call_start_audio_stream(LinphoneCall *call, const char *cna /*transform the graph to connect it to the conference filter */ linphone_call_add_to_conf(call); } + + if (stream->proto == SalProtoRtpSavp) { + const SalStreamDescription *local_st_desc=sal_media_description_find_stream(call->localdesc, + SalProtoRtpSavp,SalAudio); + + audio_stream_enable_strp( + call->audiostream, + stream->crypto[0].algo, + local_st_desc->crypto[0].master_key, + stream->crypto[0].master_key); + } }else ms_warning("No audio stream accepted ?"); } } @@ -1078,8 +1142,14 @@ static void linphone_call_start_video_stream(LinphoneCall *call, const char *cna #ifdef VIDEO_ENABLED LinphoneCore *lc=call->core; int used_pt=-1; + /* look for savp stream first */ const SalStreamDescription *vstream=sal_media_description_find_stream(call->resultdesc, - SalProtoRtpAvp,SalVideo); + SalProtoRtpSavp,SalVideo); + /* no savp audio stream, use avp */ + if (!vstream) + vstream=sal_media_description_find_stream(call->resultdesc, + SalProtoRtpAvp,SalVideo); + /* shutdown preview */ if (lc->previewstream!=NULL) { video_preview_stop(lc->previewstream); @@ -1136,6 +1206,18 @@ static void linphone_call_start_video_stream(LinphoneCall *call, const char *cna used_pt, lc->rtp_conf.audio_jitt_comp, cam); video_stream_set_rtcp_information(call->videostream, cname,LINPHONE_RTCP_SDES_TOOL); } + + if (vstream->proto == SalProtoRtpSavp) { + const SalStreamDescription *local_st_desc=sal_media_description_find_stream(call->localdesc, + SalProtoRtpSavp,SalVideo); + + video_stream_enable_strp( + call->videostream, + vstream->crypto[0].algo, + local_st_desc->crypto[0].master_key, + vstream->crypto[0].master_key + ); + } }else ms_warning("No video stream accepted."); }else{ ms_warning("No valid video stream defined."); diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 66334ea0f4e3022a7ac8062f6d6bb324dbcf2151..c4b5dbb6e91ea720f2a5234a7d3716b7495ff6be 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -23,6 +23,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "private.h" #include <ortp/telephonyevents.h> +#include <ortp/zrtp.h> #include "mediastreamer2/mediastream.h" #include "mediastreamer2/mseventqueue.h" #include "mediastreamer2/msvolume.h" @@ -35,6 +36,10 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #endif #endif +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + /*#define UNSTANDART_GSM_11K 1*/ #define ROOT_CA_FILE PACKAGE_DATA_DIR "/linphone/rootca.pem" @@ -523,7 +528,7 @@ static void sip_config_read(LinphoneCore *lc) #else sal_root_ca(lc->sal, lp_config_get_string(lc->config,"sip","root_ca", ROOT_CA_FILE)); #endif - + tmp=lp_config_get_int(lc->config,"sip","guess_hostname",1); linphone_core_set_guess_hostname(lc,tmp); @@ -4260,7 +4265,7 @@ LinphoneGlobalState linphone_core_get_global_state(const LinphoneCore *lc){ LinphoneCallParams *linphone_core_create_default_call_parameters(LinphoneCore *lc){ LinphoneCallParams *p=ms_new0(LinphoneCallParams,1); - p->has_video=linphone_core_video_enabled(lc); + linphone_core_init_default_params(lc, p); return p; } @@ -4363,7 +4368,6 @@ void linphone_core_set_zrtp_secrets_file(LinphoneCore *lc, const char* file){ lc->zrtp_secrets_cache=file ? ms_strdup(file) : NULL; } -// if (stringUri.equals(call.getRemoteAddress().asStringUriOnly())) { const LinphoneCall* linphone_core_find_call_from_uri(LinphoneCore *lc, const char *uri) { if (uri == NULL) return NULL; MSList *calls=lc->calls; @@ -4410,3 +4414,59 @@ bool_t linphone_core_sound_resources_locked(LinphoneCore *lc){ } return FALSE; } + +void linphone_core_set_srtp_enabled(LinphoneCore *lc, bool_t enabled) { + lp_config_set_int(lc->config,"sip","srtp",(int)enabled); +} + +/** + * Returns whether a media encryption scheme is supported by the LinphoneCore engine +**/ +bool_t linphone_core_media_encryption_supported(const LinphoneCore *lc, LinphoneMediaEncryption menc){ + switch(menc){ + case LinphoneMediaEncryptionSRTP: + return ortp_srtp_supported(); + case LinphoneMediaEncryptionZRTP: + return ortp_zrtp_available(); + case LinphoneMediaEncryptionNone: + return TRUE; + } + return FALSE; +} + +void linphone_core_set_media_encryption(LinphoneCore *lc, enum LinphoneMediaEncryption menc) { + if (menc == LinphoneMediaEncryptionSRTP) + lp_config_set_string(lc->config,"sip","media_encryption","srtp"); + else if (menc == LinphoneMediaEncryptionZRTP) + lp_config_set_string(lc->config,"sip","media_encryption","zrtp"); + else + lp_config_set_string(lc->config,"sip","media_encryption","none"); +} + +LinphoneMediaEncryption linphone_core_get_media_encryption(LinphoneCore *lc) { + const char* menc = lp_config_get_string(lc->config, "sip", "media_encryption", NULL); + + if (menc == NULL) + return LinphoneMediaEncryptionNone; + else if (strcmp(menc, "srtp")==0) + return LinphoneMediaEncryptionSRTP; + else if (strcmp(menc, "zrtp")==0) + return LinphoneMediaEncryptionZRTP; + else + return LinphoneMediaEncryptionNone; +} + +bool_t linphone_core_is_media_encryption_mandatory(LinphoneCore *lc) { + return (bool_t)lp_config_get_int(lc->config, "sip", "media_encryption_mandatory", 0); +} + +void linphone_core_set_media_encryption_mandatory(LinphoneCore *lc, bool_t m) { + lp_config_set_int(lc->config, "sip", "media_encryption_mandatory", (int)m); +} + +void linphone_core_init_default_params(LinphoneCore*lc, LinphoneCallParams *params) { + params->has_video=linphone_core_video_enabled(lc); + params->media_encryption=linphone_core_get_media_encryption(lc); + params->in_conference=FALSE; +} + diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 0f49a4593e561decd055992ab718fc1d9a404971..f4bb368c61240e1c40ed9ee7b10e1e69fa41ffe8 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -156,7 +156,13 @@ typedef struct _LinphoneCallLog{ struct _LinphoneCore *lc; } LinphoneCallLog; +enum LinphoneMediaEncryption { + LinphoneMediaEncryptionNone, + LinphoneMediaEncryptionSRTP, + LinphoneMediaEncryptionZRTP +}; +typedef enum LinphoneMediaEncryption LinphoneMediaEncryption; /*public: */ void linphone_call_log_set_user_pointer(LinphoneCallLog *cl, void *up); @@ -179,6 +185,8 @@ typedef struct _LinphoneCallParams LinphoneCallParams; LinphoneCallParams * linphone_call_params_copy(const LinphoneCallParams *cp); void linphone_call_params_enable_video(LinphoneCallParams *cp, bool_t enabled); bool_t linphone_call_params_video_enabled(const LinphoneCallParams *cp); +enum LinphoneMediaEncryption linphone_call_params_get_media_encryption(LinphoneCallParams *cp); +void linphone_call_params_set_media_encryption(LinphoneCallParams *cp, enum LinphoneMediaEncryption e); void linphone_call_params_enable_early_media_sending(LinphoneCallParams *cp, bool_t enabled); bool_t linphone_call_params_early_media_sending_enabled(const LinphoneCallParams *cp); bool_t linphone_call_params_local_conference_mode(const LinphoneCallParams *cp); @@ -259,6 +267,10 @@ float linphone_call_get_play_volume(LinphoneCall *call); float linphone_call_get_record_volume(LinphoneCall *call); float linphone_call_get_current_quality(LinphoneCall *call); float linphone_call_get_average_quality(LinphoneCall *call); +bool_t linphone_call_are_all_streams_encrypted(LinphoneCall *call); +const char* linphone_call_get_authentication_token(LinphoneCall *call); +bool_t linphone_call_get_authentication_token_verified(LinphoneCall *call); +void linphone_call_send_vfu_request(LinphoneCall *call); void *linphone_call_get_user_pointer(LinphoneCall *call); void linphone_call_set_user_pointer(LinphoneCall *call, void *user_pointer); /** @@ -1007,15 +1019,9 @@ LinphoneGlobalState linphone_core_get_global_state(const LinphoneCore *lc); */ void linphone_core_refresh_registers(LinphoneCore* lc); - -void linphone_call_send_vfu_request(LinphoneCall *call); - /* Path to the file storing secrets cache */ void linphone_core_set_zrtp_secrets_file(LinphoneCore *lc, const char* file); -bool_t linphone_call_are_all_streams_encrypted(LinphoneCall *call); -const char* linphone_call_get_authentication_token(LinphoneCall *call); -bool_t linphone_call_get_authentication_token_verified(LinphoneCall *call); const LinphoneCall* linphone_core_find_call_from_uri(LinphoneCore *lc, const char *uri); @@ -1033,6 +1039,26 @@ int linphone_core_get_conference_size(LinphoneCore *lc); int linphone_core_get_max_calls(LinphoneCore *lc); bool_t linphone_core_sound_resources_locked(LinphoneCore *lc); +bool_t linphone_core_media_encryption_supported(const LinphoneCore *lc, LinphoneMediaEncryption menc); + +/** + * Choose media encryption policy to be used for RTP packets + */ +void linphone_core_set_media_encryption(LinphoneCore *lc, enum LinphoneMediaEncryption menc); +enum LinphoneMediaEncryption linphone_core_get_media_encryption(LinphoneCore *lc); + +bool_t linphone_core_is_media_encryption_mandatory(LinphoneCore *lc); +/** + * Defines Linphone behaviour when encryption parameters negociation fails on outoing call. + * If set to TRUE call will fail; if set to FALSE will resend an INVITE with encryption disabled + */ +void linphone_core_set_media_encryption_mandatory(LinphoneCore *lc, bool_t m); + +/** + * Init call params using LinphoneCore's current configuration + */ +void linphone_core_init_default_params(LinphoneCore*lc, LinphoneCallParams *params); + #ifdef __cplusplus } #endif diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index 6da09ef6b9ae9f549d0deba7c2174b2a1c52d599..4dab0d0a84ca2cf505cafc0b252b62306136ce23 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -775,7 +775,82 @@ extern "C" jint Java_org_linphone_core_LinphoneCoreImpl_startEchoCalibration(JNI } +static enum LinphoneMediaEncryption media_encryption_string_to_enum(const char* menc) { + if (menc==NULL) + return LinphoneMediaEncryptionNone; + else if (strcasecmp(menc, "none")==0) + return LinphoneMediaEncryptionNone; + else if (strcasecmp(menc, "srtp")==0) + return LinphoneMediaEncryptionSRTP; + else if (strcasecmp(menc, "zrtp")==0) + return LinphoneMediaEncryptionZRTP; + else + return LinphoneMediaEncryptionNone; +} + +static jstring media_encryption_enum_to_jstring(JNIEnv* env, enum LinphoneMediaEncryption enc) { + switch (enc) { + case LinphoneMediaEncryptionSRTP: + return env->NewStringUTF("srtp"); + case LinphoneMediaEncryptionZRTP: + return env->NewStringUTF("zrtp"); + case LinphoneMediaEncryptionNone: + return env->NewStringUTF("none"); + default: + return NULL; + } +} +extern "C" jstring Java_org_linphone_core_LinphoneCoreImpl_getMediaEncryption(JNIEnv* env + ,jobject thiz + ,jlong lc + ) { + return media_encryption_enum_to_jstring(env, + linphone_core_get_media_encryption((LinphoneCore*)lc)); +} +extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setMediaEncryption(JNIEnv* env + ,jobject thiz + ,jlong lc + ,jstring jmenc) { + const char* menc = jmenc?env->GetStringUTFChars(jmenc, NULL):NULL; + + linphone_core_set_media_encryption((LinphoneCore*)lc, + media_encryption_string_to_enum(menc)); + + if (menc) env->ReleaseStringUTFChars(jmenc, menc); +} + +extern "C" jstring Java_org_linphone_core_LinphoneCallParamsImpl_getMediaEncryption(JNIEnv* env + ,jobject thiz + ,jlong lc + ) { + return media_encryption_enum_to_jstring(env, + linphone_call_params_get_media_encryption((LinphoneCallParams*)lc)); +} +extern "C" void Java_org_linphone_core_LinphoneCallParamsImpl_setMediaEncryption(JNIEnv* env + ,jobject thiz + ,jlong lc + ,jstring jmenc) { + const char* menc = jmenc?env->GetStringUTFChars(jmenc, NULL):NULL; + linphone_call_params_set_media_encryption((LinphoneCallParams*)lc, + media_encryption_string_to_enum(menc)); + if (menc) env->ReleaseStringUTFChars(jmenc, menc); +} + +extern "C" jboolean Java_org_linphone_core_LinphoneCoreImpl_getMediaEncryptionMandatory(JNIEnv* env + ,jobject thiz + ,jlong lc + ) { + return linphone_core_is_media_encryption_mandatory((LinphoneCore*)lc); +} + +extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setMediaEncryptionMandatory(JNIEnv* env + ,jobject thiz + ,jlong lc + , jboolean yesno + ) { + linphone_core_set_media_encryption_mandatory((LinphoneCore*)lc, yesno); +} //ProxyConfig diff --git a/coreapi/offeranswer.c b/coreapi/offeranswer.c index 3e054508b1aa5a863287569b5ed9730957f49619..ab213a2391b591c3013603e26657145a6538d256 100644 --- a/coreapi/offeranswer.c +++ b/coreapi/offeranswer.c @@ -128,6 +128,31 @@ static MSList *match_payloads(const MSList *local, const MSList *remote, bool_t return res; } +static bool_t match_crypto_algo(const SalSrtpCryptoAlgo* local, const SalSrtpCryptoAlgo* remote, + SalSrtpCryptoAlgo* result, bool_t use_local_key) { + int i,j; + for(i=0; i<SAL_CRYPTO_ALGO_MAX; i++) { + if (remote[i].algo == 0) + break; + + for(j=0; j<SAL_CRYPTO_ALGO_MAX; j++) { + if (remote[i].algo == local[j].algo) { + result->algo = remote[i].algo; + if (use_local_key) { + strncpy(result->master_key, local[j].master_key, 41); + result->tag = local[j].tag; + } else { + strncpy(result->master_key, remote[j].master_key, 41); + result->tag = remote[j].tag; + } + result->master_key[40] = '\0'; + return TRUE; + } + } + } + return FALSE; +} + static SalStreamDir compute_dir_outgoing(SalStreamDir local, SalStreamDir answered){ @@ -174,7 +199,7 @@ static void initiate_outgoing(const SalStreamDescription *local_offer, SalStreamDescription *result){ if (remote_answer->port!=0) result->payloads=match_payloads(local_offer->payloads,remote_answer->payloads,TRUE,FALSE); - result->proto=local_offer->proto; + result->proto=remote_answer->proto; result->type=local_offer->type; result->dir=compute_dir_outgoing(local_offer->dir,remote_answer->dir); @@ -186,6 +211,12 @@ static void initiate_outgoing(const SalStreamDescription *local_offer, }else{ result->port=0; } + if (result->proto == SalProtoRtpSavp) { + /* verify crypto algo */ + memset(result->crypto, 0, sizeof(result->crypto)); + if (!match_crypto_algo(local_offer->crypto, remote_answer->crypto, &result->crypto[0], FALSE)) + result->port = 0; + } } @@ -193,7 +224,7 @@ static void initiate_incoming(const SalStreamDescription *local_cap, const SalStreamDescription *remote_offer, SalStreamDescription *result, bool_t one_matching_codec){ result->payloads=match_payloads(local_cap->payloads,remote_offer->payloads, FALSE, one_matching_codec); - result->proto=local_cap->proto; + result->proto=remote_offer->proto; result->type=local_cap->type; result->dir=compute_dir_incoming(local_cap->dir,remote_offer->dir); if (result->payloads && !only_telephone_event(result->payloads)){ @@ -205,6 +236,13 @@ static void initiate_incoming(const SalStreamDescription *local_cap, }else{ result->port=0; } + if (result->proto == SalProtoRtpSavp) { + /* select crypto algo */ + memset(result->crypto, 0, sizeof(result->crypto)); + if (!match_crypto_algo(local_cap->crypto, remote_offer->crypto, &result->crypto[0], TRUE)) + result->port = 0; + + } } /** @@ -215,6 +253,7 @@ int offer_answer_initiate_outgoing(const SalMediaDescription *local_offer, const SalMediaDescription *remote_answer, SalMediaDescription *result){ int i,j; + const SalStreamDescription *ls,*rs; for(i=0,j=0;i<local_offer->nstreams;++i){ ms_message("Processing for stream %i",i); @@ -246,10 +285,18 @@ int offer_answer_initiate_incoming(const SalMediaDescription *local_capabilities for(i=0;i<remote_offer->nstreams;++i){ rs=&remote_offer->streams[i]; ms_message("Processing for stream %i",i); + ls=sal_media_description_find_stream((SalMediaDescription*)local_capabilities,rs->proto,rs->type); + ms_message("remote proto: %s => %p", (rs->proto == SalProtoRtpAvp)?"AVP":"SAVP", ls); + /* if matching failed, and remote proposes Avp only, ask for local Savp streams */ + if (!ls && rs->proto == SalProtoRtpAvp) { + ls=sal_media_description_find_stream((SalMediaDescription*)local_capabilities,SalProtoRtpSavp,rs->type); + ms_message("retry with AVP => %p", ls); + } if (ls){ initiate_incoming(ls,rs,&result->streams[i],one_matching_codec); - } else { + } + else { /* create an inactive stream for the answer, as there where no matching stream a local capability */ result->streams[i].dir=SalStreamInactive; result->streams[i].port=0; diff --git a/coreapi/private.h b/coreapi/private.h index 49c7c4016703525e135b778cb41df1e99fe58464..216d26f15d1147ed70e9f35fa375f362474c6d76 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -57,7 +57,6 @@ #endif #endif - struct _LinphoneCallParams{ LinphoneCall *referer; /*in case this call creation is consecutive to an incoming transfer, this points to the original call */ int audio_bw; /* bandwidth limit for audio stream */ @@ -65,6 +64,7 @@ struct _LinphoneCallParams{ bool_t real_early_media; /*send real media even during early media (for outgoing calls)*/ bool_t in_conference; /*in conference mode */ bool_t pad; + enum LinphoneMediaEncryption media_encryption; }; struct _LinphoneCall diff --git a/coreapi/sal.h b/coreapi/sal.h index b2a0ecd595f126b1225c0d4eddd3cd1e4376546f..86a0fb86b6042688a8b6ea4788f0484527335346 100644 --- a/coreapi/sal.h +++ b/coreapi/sal.h @@ -112,6 +112,15 @@ typedef struct SalEndpointCandidate{ #define SAL_ENDPOINT_CANDIDATE_MAX 2 +typedef struct SalSrtpCryptoAlgo { + unsigned int tag; + enum ortp_srtp_crypto_suite_t algo; + /* 41= 40 max(key_length for all algo) + '\0' */ + char master_key[41]; +} SalSrtpCryptoAlgo; + +#define SAL_CRYPTO_ALGO_MAX 4 + typedef struct SalStreamDescription{ SalMediaProto proto; SalStreamType type; @@ -123,6 +132,7 @@ typedef struct SalStreamDescription{ int ptime; SalEndpointCandidate candidates[SAL_ENDPOINT_CANDIDATE_MAX]; SalStreamDir dir; + SalSrtpCryptoAlgo crypto[SAL_CRYPTO_ALGO_MAX]; } SalStreamDescription; #define SAL_MEDIA_DESCRIPTION_MAX_STREAMS 4 diff --git a/coreapi/sal_eXosip2.c b/coreapi/sal_eXosip2.c index 772997b6b67b876bcb938ac3fe07b2494454b28d..5314bb28160b83b06ce7e4bbda891b710034fe30 100644 --- a/coreapi/sal_eXosip2.c +++ b/coreapi/sal_eXosip2.c @@ -514,12 +514,18 @@ static void sdp_process(SalOp *h){ It should contains media parameters constraint from the remote offer, not our response*/ strcpy(h->result->addr,h->base.remote_media->addr); h->result->bandwidth=h->base.remote_media->bandwidth; + + //remplacer la cle for(i=0;i<h->result->nstreams;++i){ if (h->result->streams[i].port>0){ strcpy(h->result->streams[i].addr,h->base.remote_media->streams[i].addr); h->result->streams[i].ptime=h->base.remote_media->streams[i].ptime; h->result->streams[i].bandwidth=h->base.remote_media->streams[i].bandwidth; h->result->streams[i].port=h->base.remote_media->streams[i].port; + + if (h->result->streams[i].proto == SalProtoRtpSavp) { + h->result->streams[i].crypto[0] = h->base.remote_media->streams[i].crypto[0]; + } } } } @@ -546,6 +552,9 @@ int sal_call(SalOp *h, const char *from, const char *to){ sal_op_set_from(h,from); sal_op_set_to(h,to); sal_exosip_fix_route(h); + + h->terminated = FALSE; + route = sal_op_get_route(h); err=eXosip_call_build_initial_invite(&invite,to,from,route,"Phone call"); if (err!=0){ diff --git a/coreapi/sal_eXosip2_sdp.c b/coreapi/sal_eXosip2_sdp.c index 5160777a782ee4f88f07a32eb0046082578f502a..f67fb9cfd714e1f520534b39ac41fd6a2ea49e4d 100644 --- a/coreapi/sal_eXosip2_sdp.c +++ b/coreapi/sal_eXosip2_sdp.c @@ -234,9 +234,47 @@ static void add_line(sdp_message_t *msg, int lineno, const SalStreamDescription osip_strdup ("IN"), inet6 ? osip_strdup ("IP6") : osip_strdup ("IP4"), osip_strdup (addr), NULL, NULL); } - sdp_message_m_media_add (msg, osip_strdup (mt), - int_2char (port), NULL, - osip_strdup ("RTP/AVP")); + + if (desc->proto == SalProtoRtpSavp) { + int i; + + sdp_message_m_media_add (msg, osip_strdup (mt), + int_2char (port), NULL, + osip_strdup ("RTP/SAVP")); + + /* add crypto lines */ + for(i=0; i<SAL_CRYPTO_ALGO_MAX; i++) { + char buffer[1024]; + switch (desc->crypto[i].algo) { + case AES_128_SHA1_80: + snprintf(buffer, 1024, "%d %s inline:%s", + desc->crypto[i].tag, "AES_CM_128_HMAC_SHA1_80", desc->crypto[i].master_key); + sdp_message_a_attribute_add(msg, lineno, osip_strdup("crypto"), + osip_strdup(buffer)); + break; + case AES_128_SHA1_32: + snprintf(buffer, 1024, "%d %s inline:%s", + desc->crypto[i].tag, "AES_CM_128_HMAC_SHA1_32", desc->crypto[i].master_key); + sdp_message_a_attribute_add(msg, lineno, osip_strdup("crypto"), + osip_strdup(buffer)); + break; + case AES_128_NO_AUTH: + ms_warning("Unsupported crypto suite: AES_128_NO_AUTH"); + break; + case NO_CIPHER_SHA1_80: + ms_warning("Unsupported crypto suite: NO_CIPHER_SHA1_80"); + break; + default: + i = SAL_CRYPTO_ALGO_MAX; + } + } + + } else { + sdp_message_m_media_add (msg, osip_strdup (mt), + int_2char (port), NULL, + osip_strdup ("RTP/AVP")); + + } if (desc->bandwidth>0) sdp_message_b_bandwidth_add (msg, lineno, osip_strdup ("AS"), int_2char(desc->bandwidth)); if (desc->ptime>0) sdp_message_a_attribute_add(msg,lineno,osip_strdup("ptime"), @@ -356,7 +394,7 @@ int sdp_to_media_description(sdp_message_t *msg, SalMediaDescription *desc){ for(j=0;(sbw=sdp_message_bandwidth_get(msg,i,j))!=NULL;++j){ if (strcasecmp(sbw->b_bwtype,"AS")==0) stream->bandwidth=atoi(sbw->b_bandwidth); } - stream->dir=_sdp_message_get_mline_dir(msg,i); + stream->dir=_sdp_message_get_mline_dir(msg,i); /* for each payload type */ for (j=0;((number=sdp_message_m_payload_get (msg, i,j)) != NULL); j++){ const char *rtpmap,*fmtp; @@ -374,6 +412,49 @@ int sdp_to_media_description(sdp_message_t *msg, SalMediaDescription *desc){ pt->send_fmtp ? pt->send_fmtp : ""); } } + + /* read crypto lines if any */ + if (stream->proto == SalProtoRtpSavp) { + int k, valid_count = 0; + sdp_attribute_t *attr; + + memset(&stream->crypto, 0, sizeof(stream->crypto)); + for (k=0;valid_count < SAL_CRYPTO_ALGO_MAX && (attr=sdp_message_attribute_get(msg,i,k))!=NULL;k++){ + char tmp[256], tmp2[256]; + if (keywordcmp("crypto",attr->a_att_field)==0 && attr->a_att_value!=NULL){ + int nb = sscanf(attr->a_att_value, "%d %256s inline:%256s", + &stream->crypto[valid_count].tag, + tmp, + tmp2); + ms_message("Found valid crypto line (tag:%d algo:'%s' key:'%s'", + stream->crypto[valid_count].tag, + tmp, + tmp2); + if (nb == 3) { + if (strcmp(tmp, "AES_CM_128_HMAC_SHA1_80") == 0) + stream->crypto[valid_count].algo = AES_128_SHA1_80; + else if (strcmp(tmp, "AES_CM_128_HMAC_SHA1_32") == 0) + stream->crypto[valid_count].algo = AES_128_SHA1_32; + else { + ms_warning("Failed to parse crypto-algo: '%s'", tmp); + stream->crypto[valid_count].algo = 0; + } + if (stream->crypto[valid_count].algo) { + strncpy(stream->crypto[valid_count].master_key, tmp2, 41); + stream->crypto[valid_count].master_key[40] = '\0'; + ms_message("Found valid crypto line (tag:%d algo:'%s' key:'%s'", + stream->crypto[valid_count].tag, + tmp, + stream->crypto[valid_count].master_key); + valid_count++; + } + } else { + ms_warning("sdp has a strange a= line (%s) nb=%i",attr->a_att_value,nb); + } + } + } + ms_message("Found: %d valid crypto lines", valid_count); + } } desc->nstreams=i; return 0; diff --git a/gtk/parameters.ui b/gtk/parameters.ui index 3bec2e63ed2fb1be6e368bac06afe80c868f0282..d853a4bb019c8de96f5b4da71747b6ab4ae41305 100644 --- a/gtk/parameters.ui +++ b/gtk/parameters.ui @@ -296,116 +296,129 @@ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> <property name="left_padding">12</property> <child> - <object class="GtkVBox" id="vbox6"> + <object class="GtkTable" id="table1"> <property name="visible">True</property> <property name="can_focus">False</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <property name="n_rows">4</property> + <property name="n_columns">2</property> <child> - <placeholder/> + <object class="GtkComboBox" id="proto_combo"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="model">model8</property> + <child> + <object class="GtkCellRendererText" id="renderer1"/> + <attributes> + <attribute name="text">0</attribute> + </attributes> + </child> + </object> + </child> + <child> + <object class="GtkSpinButton" id="proto_port"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="invisible_char">•</property> + <property name="invisible_char_set">True</property> + <property name="primary_icon_activatable">False</property> + <property name="secondary_icon_activatable">False</property> + <property name="adjustment">adjustment7</property> + </object> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + </packing> + </child> + <child> + <object class="GtkSpinButton" id="video_rtp_port"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <property name="invisible_char">•</property> + <property name="invisible_char_set">True</property> + <property name="primary_icon_activatable">False</property> + <property name="secondary_icon_activatable">False</property> + <property name="adjustment">adjustment2</property> + <signal name="value-changed" handler="linphone_gtk_video_port_changed" swapped="no"/> + </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="GtkTable" id="table1"> + <object class="GtkSpinButton" id="audio_rtp_port"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <property name="invisible_char">•</property> + <property name="invisible_char_set">True</property> + <property name="primary_icon_activatable">False</property> + <property name="secondary_icon_activatable">False</property> + <property name="adjustment">adjustment3</property> + <signal name="value-changed" handler="linphone_gtk_audio_port_changed" swapped="no"/> + </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="label7"> <property name="visible">True</property> <property name="can_focus">False</property> <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> - <property name="n_rows">3</property> - <property name="n_columns">2</property> - <child> - <object class="GtkComboBox" id="proto_combo"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="model">model8</property> - <child> - <object class="GtkCellRendererText" id="renderer1"/> - <attributes> - <attribute name="text">0</attribute> - </attributes> - </child> - </object> - </child> - <child> - <object class="GtkSpinButton" id="proto_port"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="invisible_char">•</property> - <property name="invisible_char_set">True</property> - <property name="primary_icon_activatable">False</property> - <property name="secondary_icon_activatable">False</property> - <property name="adjustment">adjustment7</property> - </object> - <packing> - <property name="left_attach">1</property> - <property name="right_attach">2</property> - </packing> - </child> - <child> - <object class="GtkSpinButton" id="video_rtp_port"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> - <property name="invisible_char">•</property> - <property name="invisible_char_set">True</property> - <property name="primary_icon_activatable">False</property> - <property name="secondary_icon_activatable">False</property> - <property name="adjustment">adjustment2</property> - <signal name="value-changed" handler="linphone_gtk_video_port_changed" swapped="no"/> - </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="GtkSpinButton" id="audio_rtp_port"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> - <property name="invisible_char">•</property> - <property name="invisible_char_set">True</property> - <property name="primary_icon_activatable">False</property> - <property name="secondary_icon_activatable">False</property> - <property name="adjustment">adjustment3</property> - <signal name="value-changed" handler="linphone_gtk_audio_port_changed" swapped="no"/> - </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="label7"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> - <property name="label" translatable="yes">Video RTP/UDP:</property> - <property name="justify">right</property> - </object> - <packing> - <property name="top_attach">1</property> - <property name="bottom_attach">2</property> - </packing> - </child> - <child> - <object class="GtkLabel" id="label6"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> - <property name="label" translatable="yes">Audio RTP/UDP:</property> - <property name="justify">right</property> - </object> - <packing> - <property name="top_attach">2</property> - <property name="bottom_attach">3</property> - </packing> - </child> + <property name="label" translatable="yes">Video RTP/UDP:</property> + <property name="justify">right</property> </object> <packing> - <property name="expand">True</property> - <property name="fill">True</property> - <property name="position">1</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="label6"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <property name="label" translatable="yes">Audio RTP/UDP:</property> + <property name="justify">right</property> + </object> + <packing> + <property name="top_attach">2</property> + <property name="bottom_attach">3</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="media_encryption_label"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="yes">Media encryption type</property> + </object> + <packing> + <property name="top_attach">3</property> + <property name="bottom_attach">4</property> + </packing> + </child> + <child> + <object class="GtkComboBoxText" id="media_encryption_combo"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="active">0</property> + <items> + <item translatable="yes">None</item> + </items> + </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> </object> @@ -1202,6 +1215,9 @@ <property name="visible">True</property> <property name="can_focus">True</property> <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <child internal-child="selection"> + <object class="GtkTreeSelection" id="treeview-selection1"/> + </child> </object> </child> </object> @@ -1620,6 +1636,9 @@ virtual network !</property> <property name="can_focus">True</property> <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> <property name="has_tooltip">True</property> + <child internal-child="selection"> + <object class="GtkTreeSelection" id="treeview-selection2"/> + </child> </object> </child> </object> diff --git a/gtk/propertybox.c b/gtk/propertybox.c index c7c3d7cd7abd771d136e229897791c66e5ae8292..aece58048600ea0cc3e0cd5cc3ef525df797dae5 100644 --- a/gtk/propertybox.c +++ b/gtk/propertybox.c @@ -803,6 +803,56 @@ void linphone_gtk_ui_level_toggled(GtkWidget *w) { linphone_gtk_ui_level_adapt(top); } +static void linphone_gtk_media_encryption_changed(GtkWidget *combo){ + const char *selected=gtk_combo_box_get_active_text(GTK_COMBO_BOX(combo)); + LinphoneCore *lc=linphone_gtk_get_core(); + if (selected!=NULL){ + if (strcasecmp(selected,"SRTP")==0) + linphone_core_set_media_encryption(lc,LinphoneMediaEncryptionSRTP); + else if (strcasecmp(selected,"ZRTP")==0) + linphone_core_set_media_encryption(lc,LinphoneMediaEncryptionZRTP); + else linphone_core_set_media_encryption(lc,LinphoneMediaEncryptionNone); + }else g_warning("gtk_combo_box_get_active_text() returned NULL"); +} + +static void linphone_gtk_show_media_encryption(GtkWidget *pb){ + LinphoneCore *lc=linphone_gtk_get_core(); + GtkWidget *combo=linphone_gtk_get_widget(pb,"media_encryption_combo"); + bool_t no_enc=TRUE; + int srtp_id=-1,zrtp_id=-1; + + if (linphone_core_media_encryption_supported(lc,LinphoneMediaEncryptionSRTP)){ + gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo),_("SRTP")); + srtp_id=1; + no_enc=FALSE; + } + if (linphone_core_media_encryption_supported(lc,LinphoneMediaEncryptionZRTP)){ + gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo),_("ZRTP")); + no_enc=FALSE; + if (srtp_id!=-1) zrtp_id=2; + else zrtp_id=1; + } + if (no_enc){ + /*hide this setting*/ + gtk_widget_hide(combo); + gtk_widget_hide(linphone_gtk_get_widget(pb,"media_encryption_label")); + }else{ + LinphoneMediaEncryption menc=linphone_core_get_media_encryption(lc); + switch(menc){ + case LinphoneMediaEncryptionNone: + gtk_combo_box_set_active(GTK_COMBO_BOX(combo),0); + break; + case LinphoneMediaEncryptionSRTP: + if (srtp_id!=-1) gtk_combo_box_set_active(GTK_COMBO_BOX(combo),srtp_id); + break; + case LinphoneMediaEncryptionZRTP: + if (zrtp_id!=-1) gtk_combo_box_set_active(GTK_COMBO_BOX(combo),zrtp_id); + break; + } + g_signal_connect(G_OBJECT(combo),"changed",(GCallback)linphone_gtk_media_encryption_changed,NULL); + } +} + void linphone_gtk_show_parameters(void){ GtkWidget *pb=linphone_gtk_create_window("parameters"); LinphoneCore *lc=linphone_gtk_get_core(); @@ -841,6 +891,8 @@ void linphone_gtk_show_parameters(void){ gtk_spin_button_set_value(GTK_SPIN_BUTTON(linphone_gtk_get_widget(pb,"video_rtp_port")), linphone_core_get_video_port(lc)); + linphone_gtk_show_media_encryption(pb); + tmp=linphone_core_get_nat_address(lc); if (tmp) gtk_entry_set_text(GTK_ENTRY(linphone_gtk_get_widget(pb,"nat_address")),tmp); tmp=linphone_core_get_stun_server(lc); diff --git a/java/common/org/linphone/core/LinphoneCallParams.java b/java/common/org/linphone/core/LinphoneCallParams.java index 78a63d3fa9fd495fad08b3862af2507d3b275edf..c3bdc43ec8439e18da622cb2ba5068b154a7e038 100644 --- a/java/common/org/linphone/core/LinphoneCallParams.java +++ b/java/common/org/linphone/core/LinphoneCallParams.java @@ -35,4 +35,15 @@ public interface LinphoneCallParams { */ void setAudioBandwidth(int value); + /** + * return selected media encryption + * @return 'none', 'srtp' or 'zrtp' + */ + String getMediaEncryption(); + /** + * set media encryption (rtp) to use + * @params menc: 'none', 'srtp' or 'zrtp' + */ + void setMediaEnctyption(String menc); + } diff --git a/java/common/org/linphone/core/LinphoneCore.java b/java/common/org/linphone/core/LinphoneCore.java index fcd041dc8a6c5745fef27c0abd5d7ce0aee72f0b..0bea6f60c4d1ffefcf2d611b90b29a466c31600c 100644 --- a/java/common/org/linphone/core/LinphoneCore.java +++ b/java/common/org/linphone/core/LinphoneCore.java @@ -634,4 +634,22 @@ public interface LinphoneCore { * @return */ boolean soundResourcesLocked(); + /** + * set media encryption (rtp) to use + * @params menc: 'none', 'srtp' or 'zrtp' + */ + void setMediaEncryption(String menc); + /** + * return selected media encryption + * @return 'none', 'srtp' or 'zrtp' + */ + String getMediaEncryption(); +/** + * Set media encryption required for outgoing calls + */ + void setMediaEncryptionMandatory(boolean yesno); + /** + * @return if media encryption is required for ougtoing calls + */ + boolean isMediaEncryptionMandatory(); } diff --git a/oRTP b/oRTP index 7606207905bd3dc661e68576097adce471916697..fd6d3f04884a51d20fdd02e0d73b41bb9bd28495 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit 7606207905bd3dc661e68576097adce471916697 +Subproject commit fd6d3f04884a51d20fdd02e0d73b41bb9bd28495