From b8eff5b034d157bbbc9d7d641e8c37bd6470111a Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Tue, 19 Feb 2013 17:43:16 +0100 Subject: [PATCH] improve echo calibration add mising declineCall() method to java api. --- coreapi/ec-calibrator.c | 101 +++++++++++++----- coreapi/linphonecore.c | 6 +- coreapi/linphonecore_jni.cc | 19 ++++ coreapi/private.h | 3 +- .../org/linphone/core/LinphoneCore.java | 10 ++ java/common/org/linphone/core/Reason.java | 56 ++++++++++ .../org/linphone/core/LinphoneCoreImpl.java | 52 +++++---- mediastreamer2 | 2 +- 8 files changed, 194 insertions(+), 55 deletions(-) create mode 100644 java/common/org/linphone/core/Reason.java diff --git a/coreapi/ec-calibrator.c b/coreapi/ec-calibrator.c index 7fb001d3..8efbabb1 100644 --- a/coreapi/ec-calibrator.c +++ b/coreapi/ec-calibrator.c @@ -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_sleep(1); + ms_usleep(300000); + + tone.frequency=2300; + tone.duration=100; ms_filter_call_method(ecc->gen,MS_DTMF_GEN_PLAY_CUSTOM,&tone); - ms_sleep(1); + ms_usleep(300000); + + tone.frequency=2500; + tone.duration=100; 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."); } } diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 5ba0fbf7..d9d199c3 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -2054,9 +2054,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); } diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index 64897b21..9c8697f6 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -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 diff --git a/coreapi/private.h b/coreapi/private.h index 90054052..c0b467ce 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -643,12 +643,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; diff --git a/java/common/org/linphone/core/LinphoneCore.java b/java/common/org/linphone/core/LinphoneCore.java index 11a7c275..3a6cf2a7 100644 --- a/java/common/org/linphone/core/LinphoneCore.java +++ b/java/common/org/linphone/core/LinphoneCore.java @@ -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 diff --git a/java/common/org/linphone/core/Reason.java b/java/common/org/linphone/core/Reason.java new file mode 100644 index 00000000..b07686aa --- /dev/null +++ b/java/common/org/linphone/core/Reason.java @@ -0,0 +1,56 @@ +package org.linphone.core; + +import java.util.Vector; + +public class Reason { + static private Vector values = new Vector(); + /** + * 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