diff --git a/coreapi/Makefile.am b/coreapi/Makefile.am index 4835dc74cc30391fc2b9ae104aa97be6f361d243..8f88045f568a2c3993ffa01b6b705e5f03c1d3b8 100644 --- a/coreapi/Makefile.am +++ b/coreapi/Makefile.am @@ -35,7 +35,8 @@ liblinphone_la_SOURCES=\ linphonecall.c \ sipsetup.c sipsetup.h \ siplogin.c \ - lsd.c linphonecore_utils.h + lsd.c linphonecore_utils.h \ + ec-calibrator.c liblinphone_la_LDFLAGS= -version-info $(LIBLINPHONE_SO_VERSION) -no-undefined @@ -49,7 +50,7 @@ if BUILD_WIN32 liblinphone_la_LIBADD+=$(top_builddir)/oRTP/src/libortp.la endif -noinst_PROGRAMS=test_lsd +noinst_PROGRAMS=test_lsd test_ecc test_lsd_SOURCES=test_lsd.c @@ -57,6 +58,14 @@ test_lsd_LDADD=liblinphone.la \ $(MEDIASTREAMER_LIBS) \ $(ORTP_LIBS) +test_ecc_SOURCES=test_ecc.c + +test_ecc_LDADD=liblinphone.la \ + $(MEDIASTREAMER_LIBS) \ + $(ORTP_LIBS) + + + AM_CFLAGS=$(STRICT_OPTIONS) -DIN_LINPHONE \ $(ORTP_CFLAGS) \ $(OSIP_CFLAGS) \ diff --git a/coreapi/ec-calibrator.c b/coreapi/ec-calibrator.c new file mode 100644 index 0000000000000000000000000000000000000000..5d0851add4801b582e1d404cf50c1b5b1e7a640b --- /dev/null +++ b/coreapi/ec-calibrator.c @@ -0,0 +1,171 @@ +/* +linphone +Copyright (C) 2011 Belledonne Communications SARL +Author: Simon MORLAT (simon.morlat@linphone.org) + +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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "private.h" + +#include "mediastreamer2/mstonedetector.h" +#include "mediastreamer2/dtmfgen.h" + + + + + +static void ecc_init_filters(EcCalibrator *ecc){ + ecc->ticker=ms_ticker_new(); + + ecc->sndread=ms_snd_card_create_reader(ecc->play_card); + ecc->det=ms_filter_new(MS_TONE_DETECTOR_ID); + ecc->rec=ms_filter_new(MS_FILE_REC_ID); + + ms_filter_link(ecc->sndread,0,ecc->det,0); + ms_filter_link(ecc->det,0,ecc->rec,0); + + ecc->play=ms_filter_new(MS_FILE_PLAYER_ID); + ecc->gen=ms_filter_new(MS_DTMF_GEN_ID); + ecc->sndwrite=ms_snd_card_create_writer(ecc->capt_card); + + ms_filter_link(ecc->play,0,ecc->gen,0); + ms_filter_link(ecc->gen,0,ecc->sndwrite,0); + + ms_ticker_attach(ecc->ticker,ecc->play); + ms_ticker_attach(ecc->ticker,ecc->sndread); +} + +static void ecc_deinit_filters(EcCalibrator *ecc){ + ms_ticker_detach(ecc->ticker,ecc->play); + ms_ticker_detach(ecc->ticker,ecc->sndread); + + ms_filter_unlink(ecc->play,0,ecc->gen,0); + ms_filter_unlink(ecc->gen,0,ecc->sndwrite,0); + + ms_filter_unlink(ecc->sndread,0,ecc->det,0); + ms_filter_unlink(ecc->det,0,ecc->rec,0); + + ms_filter_destroy(ecc->sndread); + ms_filter_destroy(ecc->det); + ms_filter_destroy(ecc->rec); + ms_filter_destroy(ecc->play); + ms_filter_destroy(ecc->gen); + ms_filter_destroy(ecc->sndwrite); + + ms_ticker_destroy(ecc->ticker); +} + +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 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); +} + +static void ecc_play_tones(EcCalibrator *ecc){ + MSDtmfGenCustomTone tone; + MSToneDetectorDef expected_tone; + + + ms_filter_set_notify_callback(ecc->det,on_tone_received,ecc); + + expected_tone.frequency=2000; + expected_tone.min_duration=40; + expected_tone.min_amplitude=0.02; + + ms_filter_call_method (ecc->det,MS_TONE_DETECTOR_ADD_SCAN,&expected_tone); + + tone.frequency=1000; + tone.duration=1000; + tone.amplitude=1.0; + + /*play an initial tone to startup the audio playback/capture*/ + ms_filter_call_method(ecc->gen,MS_DTMF_GEN_PLAY_CUSTOM,&tone); + sleep(2); + + ms_filter_set_notify_callback(ecc->gen,on_tone_sent,ecc); + tone.frequency=2000; + tone.duration=100; + + ms_filter_call_method(ecc->gen,MS_DTMF_GEN_PLAY_CUSTOM,&tone); + sleep(1); + ms_filter_call_method(ecc->gen,MS_DTMF_GEN_PLAY_CUSTOM,&tone); + sleep(1); + ms_filter_call_method(ecc->gen,MS_DTMF_GEN_PLAY_CUSTOM,&tone); + sleep(1); + + if (ecc->sent_count==3 && 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{ + ms_error("Echo calibration failed, tones received = %i",ecc->recv_count); + ecc->status=LinphoneEcCalibratorFailed; + } + +} + +static void * ecc_thread(void *p){ + EcCalibrator *ecc=(EcCalibrator*)p; + + ecc_init_filters(ecc); + ecc_play_tones(ecc); + ecc_deinit_filters(ecc); + return NULL; +} + +EcCalibrator * ec_calibrator_new(MSSndCard *play_card, MSSndCard *capt_card, LinphoneEcCalibrationCallback cb, void *cb_data ){ + EcCalibrator *ecc=ms_new0(EcCalibrator,1); + + ecc->cb=cb; + ecc->cb_data=cb_data; + ecc->capt_card=capt_card; + ecc->play_card=play_card; + ms_thread_create(&ecc->thread,NULL,ecc_thread,ecc); + return ecc; +} + +LinphoneEcCalibratorStatus ec_calibrator_get_status(EcCalibrator *ecc){ + return ecc->status; +} + +void ec_calibrator_destroy(EcCalibrator *ecc){ + ms_thread_join(ecc->thread,NULL); + ms_free(ecc); +} + +int linphone_core_start_echo_calibration(LinphoneCore *lc, LinphoneEcCalibrationCallback cb, void *cb_data){ + if (lc->ecc!=NULL){ + ms_error("Echo calibration is still on going !"); + return -1; + } + lc->ecc=ec_calibrator_new(lc->sound_conf.play_sndcard,lc->sound_conf.capt_sndcard,cb,cb_data); + return 0; +} diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 7252a5490d4b6a3f0bd384554060e3353f545576..7861632cfa96564261e6f9ad961307a16273edc0 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -1635,6 +1635,19 @@ void linphone_core_iterate(LinphoneCore *lc){ one_second_elapsed=TRUE; } + if (lc->ecc!=NULL){ + LinphoneEcCalibratorStatus ecs=ec_calibrator_get_status(lc->ecc); + if (ecs!=LinphoneEcCalibratorInProgress){ + if (lc->ecc->cb) + lc->ecc->cb(lc,ecs,lc->ecc->delay,lc->ecc->cb_data); + if (ecs==LinphoneEcCalibratorDone){ + lp_config_set_int(lc->config, "sound", "ec_delay",MAX(lc->ecc->delay-10,0)); + } + ec_calibrator_destroy(lc->ecc); + lc->ecc=NULL; + } + } + if (lc->preview_finished){ lc->preview_finished=0; ring_stop(lc->ringstream); diff --git a/coreapi/linphonecore_utils.h b/coreapi/linphonecore_utils.h index 8c29ef1afe5883f7c7d6e434d6cda5e63ed43d88..b2ede96496cbd0186cc660ca4f0be41e8935caec 100644 --- a/coreapi/linphonecore_utils.h +++ b/coreapi/linphonecore_utils.h @@ -49,4 +49,21 @@ void linphone_sound_daemon_release_all_players(LinphoneSoundDaemon *obj); void linphone_core_use_sound_daemon(LinphoneCore *lc, LinphoneSoundDaemon *lsd); void linphone_sound_daemon_destroy(LinphoneSoundDaemon *obj); +/** + * Enum describing the result of the echo canceller calibration process. +**/ +typedef enum { + LinphoneEcCalibratorInProgress, + LinphoneEcCalibratorDone, + LinphoneEcCalibratorFailed +}LinphoneEcCalibratorStatus; + + +typedef void (*LinphoneEcCalibrationCallback)(LinphoneCore *lc, LinphoneEcCalibratorStatus status, int delay_ms, void *data); + +/** + * Start an echo calibration of the sound devices, in order to find adequate settings for the echo canceller automatically. +**/ +int linphone_core_start_echo_calibration(LinphoneCore *lc, LinphoneEcCalibrationCallback cb, void *cb_data); + #endif diff --git a/coreapi/private.h b/coreapi/private.h index 5759bbc19a67778a2e65a94516965f06a8ffec35..a960acbd8130adb94a28cb811fd5734d7a82a2d1 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -26,6 +26,7 @@ #define _PRIVATE_H #include "linphonecore.h" +#include "linphonecore_utils.h" #include "sal.h" #ifdef HAVE_CONFIG_H @@ -424,6 +425,7 @@ struct _LinphoneCore unsigned long video_window_id; unsigned long preview_window_id; time_t netup_time; /*time when network went reachable */ + struct _EcCalibrator *ecc; bool_t use_files; bool_t apply_nat_settings; bool_t initial_subscribes_sent; @@ -451,6 +453,27 @@ bool_t linphone_core_is_payload_type_usable_for_bandwidth(LinphoneCore *lc, Payl #define linphone_core_ready(lc) ((lc)->state!=LinphoneGlobalStartup) void _linphone_core_configure_resolver(); +struct _EcCalibrator{ + ms_thread_t thread; + MSSndCard *play_card,*capt_card; + MSFilter *sndread,*det,*rec; + MSFilter *play, *gen, *sndwrite; + MSTicker *ticker; + LinphoneEcCalibrationCallback cb; + void *cb_data; + int recv_count; + int sent_count; + int64_t acc; + int delay; + LinphoneEcCalibratorStatus status; +}; + +typedef struct _EcCalibrator EcCalibrator; + +LinphoneEcCalibratorStatus ec_calibrator_get_status(EcCalibrator *ecc); + +void ec_calibrator_destroy(EcCalibrator *ecc); + #define HOLD_OFF (0) #define HOLD_ON (1) diff --git a/coreapi/test_ecc.c b/coreapi/test_ecc.c new file mode 100644 index 0000000000000000000000000000000000000000..7553c20189ad021056aaea880d0821176b11d68b --- /dev/null +++ b/coreapi/test_ecc.c @@ -0,0 +1,46 @@ +/* +linphone +Copyright (C) 2011 Belledonne Communications SARL +Author: Simon MORLAT (simon.morlat@linphone.org) + +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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + + +#include "linphonecore.h" +#include "linphonecore_utils.h" + +static void calibration_finished(LinphoneCore *lc, LinphoneEcCalibratorStatus status, int delay, void *data){ + ms_message("echo calibration finished %s.",status==LinphoneEcCalibratorDone ? "successfully" : "with faillure"); + if (status==LinphoneEcCalibratorDone) ms_message("Measured delay is %i",delay); +} + +int main(int argc, char *argv[]){ + int count=0; + LinphoneCoreVTable vtable={0}; + LinphoneCore *lc=linphone_core_new(&vtable,NULL,NULL,NULL); + + linphone_core_enable_logs(NULL); + + linphone_core_start_echo_calibration(lc,calibration_finished,NULL); + + while(count++<1000){ + linphone_core_iterate(lc); + ms_usleep(10000); + } + linphone_core_destroy(lc); + return 0; +} + diff --git a/mediastreamer2 b/mediastreamer2 index c5959fa4520005013cd14d2f773116f24f2eb7b7..434b627405d46c50cb109c001e44891551d0efab 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit c5959fa4520005013cd14d2f773116f24f2eb7b7 +Subproject commit 434b627405d46c50cb109c001e44891551d0efab diff --git a/oRTP b/oRTP index c8b487f32fe225f8b1961754db9140eb282a0d28..37c60a638fd108404ca437e2bbef78f227178450 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit c8b487f32fe225f8b1961754db9140eb282a0d28 +Subproject commit 37c60a638fd108404ca437e2bbef78f227178450