diff --git a/coreapi/CMakeLists.txt b/coreapi/CMakeLists.txt index 3308c9072..d86e01bbd 100644 --- a/coreapi/CMakeLists.txt +++ b/coreapi/CMakeLists.txt @@ -86,6 +86,7 @@ set(LINPHONE_SOURCE_FILES_C dial_plan.c dict.c ec-calibrator.c + echo-tester.c enum.c enum.h event.c diff --git a/coreapi/Makefile.am b/coreapi/Makefile.am index b62a2aa6a..a35031e3c 100644 --- a/coreapi/Makefile.am +++ b/coreapi/Makefile.am @@ -68,6 +68,7 @@ liblinphone_la_SOURCES=\ dial_plan.c \ dict.c \ ec-calibrator.c \ + echo-tester.c \ enum.c enum.h \ event.c \ friend.c \ diff --git a/coreapi/echo-tester.c b/coreapi/echo-tester.c new file mode 100644 index 000000000..5740c7302 --- /dev/null +++ b/coreapi/echo-tester.c @@ -0,0 +1,104 @@ +/* +linphone +Copyright (C) 2016 Belledonne Communications SARL +Author: Erwan CROZE (erwan.croze@belledonne-communications.com) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#include "private.h" + +#include "mediastreamer2/msfilter.h" +#include "mediastreamer2/mssndcard.h" +#include "mediastreamer2/msticker.h" +#include + +EchoTester* ec_tester_new(MSFactory *factory, MSSndCard *capture_card, MSSndCard *playback_card, unsigned int rate) { + EchoTester *ect = ms_new0(EchoTester,1); + ect->factory = factory; + ect->capture_card = capture_card; + ect->playback_card = playback_card; + ect->rate = rate; + + return ect; +} + +static void ect_init_filters(EchoTester *ect) { + unsigned int rate; + int channels = 1; + int ect_channels = 1; + MSTickerParams params={0}; + params.name="Echo tester"; + params.prio=MS_TICKER_PRIO_HIGH; + ect->ticker=ms_ticker_new_with_params(¶ms); + + ect->in = ms_snd_card_create_reader(ect->capture_card); + ect->out = ms_snd_card_create_writer(ect->playback_card); + + ms_filter_call_method(ect->in,MS_FILTER_SET_SAMPLE_RATE,&ect->rate); + ms_filter_call_method(ect->in,MS_FILTER_GET_SAMPLE_RATE,&rate); + ms_filter_call_method(ect->in,MS_FILTER_SET_NCHANNELS,&ect_channels); + ms_filter_call_method(ect->in,MS_FILTER_GET_NCHANNELS,&channels); + + ms_filter_call_method(ect->out,MS_FILTER_SET_SAMPLE_RATE,&ect->rate); + ms_filter_call_method(ect->out,MS_FILTER_SET_OUTPUT_SAMPLE_RATE,&rate); + ms_filter_call_method(ect->out,MS_FILTER_SET_NCHANNELS,&ect_channels); + ms_filter_call_method(ect->out,MS_FILTER_SET_OUTPUT_NCHANNELS,&channels); + + ms_filter_link(ect->in,0,ect->out,0); + + ms_ticker_attach(ect->ticker,ect->in); + ms_ticker_attach(ect->ticker,ect->out); +} + +static void ect_uninit_filters(EchoTester *ect) { + ms_ticker_detach(ect->ticker,ect->in); + ms_ticker_detach(ect->ticker,ect->out); + + ms_filter_unlink(ect->in,0,ect->out,0); + + ms_filter_destroy(ect->in); + ms_filter_destroy(ect->out); + + ms_ticker_destroy(ect->ticker); +} + +void ec_tester_destroy(EchoTester *ect) { + ms_free(ect); +} + +int linphone_core_start_echo_tester(LinphoneCore *lc, unsigned int rate) { + if (lc->ect != NULL) { + ms_error("Echo tester is still on going !"); + return -1; + } + lc->ect = ec_tester_new(lc->factory, lc->sound_conf.capt_sndcard + ,lc->sound_conf.play_sndcard, rate); + ect_init_filters(lc->ect); + + return 1; +} + +int linphone_core_stop_echo_tester(LinphoneCore *lc) { + if (lc->ect == NULL) { + ms_error("Echo tester is not running !"); + return -1; + } + ect_uninit_filters(lc->ect); + + ec_tester_destroy(lc->ect); + lc->ect = NULL; + return 1; +} \ No newline at end of file diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index d538ffbe6..0e9373352 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -2481,6 +2481,19 @@ extern "C" jboolean Java_org_linphone_core_LinphoneCoreImpl_needsEchoCalibration return TRUE; } +extern "C" int Java_org_linphone_core_LinphoneCoreImpl_startEchoTester(JNIEnv* env + ,jobject thiz + ,jlong lc + ,jint rate) { + return linphone_core_start_echo_tester((LinphoneCore*)lc, rate); +} + +extern "C" int Java_org_linphone_core_LinphoneCoreImpl_stopEchoTester(JNIEnv* env + ,jobject thiz + ,jlong lc) { + return linphone_core_stop_echo_tester((LinphoneCore*)lc); +} + extern "C" jboolean Java_org_linphone_core_LinphoneCoreImpl_hasCrappyOpenGL(JNIEnv *env, jobject thiz, jlong lcptr) { LinphoneCore *lc = (LinphoneCore*) lcptr; MSFactory * factory = linphone_core_get_ms_factory(lc); diff --git a/coreapi/linphonecore_utils.h b/coreapi/linphonecore_utils.h index 08453d346..1eb87893f 100644 --- a/coreapi/linphonecore_utils.h +++ b/coreapi/linphonecore_utils.h @@ -73,6 +73,15 @@ typedef void (*LinphoneEcCalibrationAudioUninit)(void *data); **/ LINPHONE_PUBLIC int linphone_core_start_echo_calibration(LinphoneCore *lc, LinphoneEcCalibrationCallback cb, LinphoneEcCalibrationAudioInit audio_init_cb, LinphoneEcCalibrationAudioUninit audio_uninit_cb, void *cb_data); +/** + * Start the simulation of call to test the latency with an external device + *@param bitrate +**/ +LINPHONE_PUBLIC int linphone_core_start_echo_tester(LinphoneCore *lc, unsigned int rate); +/** + * Stop the simulation of call +**/ +LINPHONE_PUBLIC int linphone_core_stop_echo_tester(LinphoneCore *lc); /** * @ingroup IOS * Special function to warm up dtmf feeback stream. #linphone_core_stop_dtmf_stream must() be called before entering FG mode diff --git a/coreapi/private.h b/coreapi/private.h index 000effe18..95234c49f 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -974,6 +974,7 @@ struct _LinphoneCore void *preview_window_id; time_t netup_time; /*time when network went reachable */ struct _EcCalibrator *ecc; + struct _EchoTester *ect; LinphoneTaskList hooks; /*tasks periodically executed in linphone_core_iterate()*/ LinphoneConference *conf_ctx; char* zrtp_secrets_cache; @@ -1110,6 +1111,17 @@ LinphoneEcCalibratorStatus ec_calibrator_get_status(EcCalibrator *ecc); void ec_calibrator_destroy(EcCalibrator *ecc); +struct _EchoTester { + MSFactory *factory; + MSFilter *in,*out; + MSSndCard *capture_card; + MSSndCard *playback_card; + MSTicker *ticker; + unsigned int rate; +}; + +typedef struct _EchoTester EchoTester; + void linphone_call_background_tasks(LinphoneCall *call, bool_t one_second_elapsed); void linphone_call_set_broken(LinphoneCall *call); void linphone_call_repair_if_broken(LinphoneCall *call); diff --git a/java/common/org/linphone/core/LinphoneCore.java b/java/common/org/linphone/core/LinphoneCore.java index 80715b16f..f7b950cf6 100644 --- a/java/common/org/linphone/core/LinphoneCore.java +++ b/java/common/org/linphone/core/LinphoneCore.java @@ -1399,7 +1399,20 @@ public interface LinphoneCore { * If the device has a builtin echo canceller, it will return false. */ boolean hasBuiltInEchoCanceler(); - + + /** + * Start the speaker and the micro to test the echo + * @param bitrate + * @return the status + */ + int startEchoTester(int rate); + + /** + * Stop the speaker and the micro + * @return the status + */ + int stopEchoTester(); + /** * Returns true if the OpenGL on this device is crappy and we need to use the old Android display */ diff --git a/java/impl/org/linphone/core/LinphoneCoreImpl.java b/java/impl/org/linphone/core/LinphoneCoreImpl.java index a9f542615..a99b26260 100644 --- a/java/impl/org/linphone/core/LinphoneCoreImpl.java +++ b/java/impl/org/linphone/core/LinphoneCoreImpl.java @@ -139,6 +139,8 @@ class LinphoneCoreImpl implements LinphoneCore { private native void enableKeepAlive(long nativePtr,boolean enable); private native boolean isKeepAliveEnabled(long nativePtr); private native int startEchoCalibration(long nativePtr,Object data); + private native int startEchoTester(long nativePtr, int rate); + private native int stopEchoTester(long nativePtr); private native int getSignalingTransportPort(long nativePtr, int code); private native void setSignalingTransportPorts(long nativePtr, int udp, int tcp, int tls); private native void enableIpv6(long nativePtr,boolean enable); @@ -677,6 +679,14 @@ class LinphoneCoreImpl implements LinphoneCore { startEchoCalibration(nativePtr, listener); } + public synchronized int startEchoTester(int rate) { + return startEchoTester(nativePtr, rate); + } + + public synchronized int stopEchoTester() { + return stopEchoTester(nativePtr); + } + public synchronized Transports getSignalingTransportPorts() { Transports transports = new Transports(); transports.udp = getSignalingTransportPort(nativePtr, 0);