]> sjero.net Git - linphone/blob - coreapi/ec-calibrator.c
Fix swapped soundcards and use voidsink.
[linphone] / coreapi / ec-calibrator.c
1 /*
2 linphone
3 Copyright (C) 2011 Belledonne Communications SARL
4 Author: Simon MORLAT (simon.morlat@linphone.org)
5
6 This program is free software; you can redistribute it and/or
7 modify it under the terms of the GNU General Public License
8 as published by the Free Software Foundation; either version 2
9 of the License, or (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19 */
20
21 #include "private.h"
22
23 #include "mediastreamer2/mstonedetector.h"
24 #include "mediastreamer2/dtmfgen.h"
25
26 #include "lpconfig.h"
27
28
29
30 static void ecc_init_filters(EcCalibrator *ecc){
31         unsigned int rate;
32         int channels = 1;
33         int ecc_channels = 1;
34         MSTickerParams params={0};
35         params.name="Echo calibrator";
36         params.prio=MS_TICKER_PRIO_HIGH;
37         ecc->ticker=ms_ticker_new_with_params(&params);
38
39         ecc->sndread=ms_snd_card_create_reader(ecc->capt_card);
40         ms_filter_call_method(ecc->sndread,MS_FILTER_SET_SAMPLE_RATE,&ecc->rate);
41         ms_filter_call_method(ecc->sndread,MS_FILTER_GET_SAMPLE_RATE,&rate);
42         ms_filter_call_method(ecc->sndread,MS_FILTER_SET_NCHANNELS,&ecc_channels);
43         ms_filter_call_method(ecc->sndread,MS_FILTER_GET_NCHANNELS,&channels);
44         ecc->read_resampler=ms_filter_new(MS_RESAMPLE_ID);
45         ms_filter_call_method(ecc->read_resampler,MS_FILTER_SET_SAMPLE_RATE,&rate);
46         ms_filter_call_method(ecc->read_resampler,MS_FILTER_SET_OUTPUT_SAMPLE_RATE,&ecc->rate);
47         ms_filter_call_method(ecc->read_resampler,MS_FILTER_SET_NCHANNELS,&ecc_channels);
48         ms_filter_call_method(ecc->read_resampler,MS_FILTER_SET_OUTPUT_NCHANNELS,&channels);
49         
50         
51         ecc->det=ms_filter_new(MS_TONE_DETECTOR_ID);
52         ms_filter_call_method(ecc->det,MS_FILTER_SET_SAMPLE_RATE,&ecc->rate);
53         ecc->rec=ms_filter_new(MS_VOID_SINK_ID);
54
55         ms_filter_link(ecc->sndread,0,ecc->read_resampler,0);
56         ms_filter_link(ecc->read_resampler,0,ecc->det,0);
57         ms_filter_link(ecc->det,0,ecc->rec,0);
58
59         ecc->play=ms_filter_new(MS_VOID_SOURCE_ID);
60         ecc->gen=ms_filter_new(MS_DTMF_GEN_ID);
61         ms_filter_call_method(ecc->gen,MS_FILTER_SET_SAMPLE_RATE,&ecc->rate);
62         ecc->write_resampler=ms_filter_new(MS_RESAMPLE_ID);
63         ecc->sndwrite=ms_snd_card_create_writer(ecc->play_card);
64         
65         ms_filter_call_method(ecc->sndwrite,MS_FILTER_SET_SAMPLE_RATE,&ecc->rate);
66         ms_filter_call_method(ecc->sndwrite,MS_FILTER_GET_SAMPLE_RATE,&rate);
67         ms_filter_call_method(ecc->sndwrite,MS_FILTER_SET_NCHANNELS,&ecc_channels);
68         ms_filter_call_method(ecc->sndwrite,MS_FILTER_GET_NCHANNELS,&channels);
69         ms_filter_call_method(ecc->write_resampler,MS_FILTER_SET_SAMPLE_RATE,&ecc->rate);
70         ms_filter_call_method(ecc->write_resampler,MS_FILTER_SET_OUTPUT_SAMPLE_RATE,&rate);
71         ms_filter_call_method(ecc->write_resampler,MS_FILTER_SET_NCHANNELS,&ecc_channels);
72         ms_filter_call_method(ecc->write_resampler,MS_FILTER_SET_OUTPUT_NCHANNELS,&channels);
73
74         ms_filter_link(ecc->play,0,ecc->gen,0);
75         ms_filter_link(ecc->gen,0,ecc->write_resampler,0);
76         ms_filter_link(ecc->write_resampler,0,ecc->sndwrite,0);
77
78         ms_ticker_attach(ecc->ticker,ecc->sndread);
79         ms_ticker_attach(ecc->ticker,ecc->play);
80
81         if (ecc->audio_init_cb != NULL) {
82                 (*ecc->audio_init_cb)(ecc->cb_data);
83         }
84 }
85
86 static void ecc_deinit_filters(EcCalibrator *ecc){
87         if (ecc->audio_uninit_cb != NULL) {
88                 (*ecc->audio_uninit_cb)(ecc->cb_data);
89         }
90
91         ms_ticker_detach(ecc->ticker,ecc->sndread);
92         ms_ticker_detach(ecc->ticker,ecc->play);
93
94         ms_filter_unlink(ecc->play,0,ecc->gen,0);
95         ms_filter_unlink(ecc->gen,0,ecc->write_resampler,0);
96         ms_filter_unlink(ecc->write_resampler,0,ecc->sndwrite,0);
97
98         ms_filter_unlink(ecc->sndread,0,ecc->read_resampler,0);
99         ms_filter_unlink(ecc->read_resampler,0,ecc->det,0);
100         ms_filter_unlink(ecc->det,0,ecc->rec,0);
101
102         ms_filter_destroy(ecc->sndread);
103         ms_filter_destroy(ecc->det);
104         ms_filter_destroy(ecc->rec);
105         ms_filter_destroy(ecc->play);
106         ms_filter_destroy(ecc->gen);
107         ms_filter_destroy(ecc->read_resampler);
108         ms_filter_destroy(ecc->write_resampler);
109         ms_filter_destroy(ecc->sndwrite);
110
111         ms_ticker_destroy(ecc->ticker);
112 }
113
114 static void on_tone_sent(void *data, MSFilter *f, unsigned int event_id, void *arg){
115         MSDtmfGenEvent *ev=(MSDtmfGenEvent*)arg;
116         EcCalibrator *ecc=(EcCalibrator*)data;
117         ecc->acc-=ev->tone_start_time;
118         ms_message("Sent tone at %u",(unsigned int)ev->tone_start_time);
119 }
120
121 static bool_t is_valid_tone(EcCalibrator *ecc, MSToneDetectorEvent *ev){
122         bool_t *toneflag=NULL;
123         if (strcmp(ev->tone_name,"freq1")==0){
124                 toneflag=&ecc->freq1;
125         }else if (strcmp(ev->tone_name,"freq2")==0){
126                 toneflag=&ecc->freq2;
127         }else if (strcmp(ev->tone_name,"freq3")==0){
128                 toneflag=&ecc->freq3;
129         }else{
130                 ms_error("Calibrator bug.");
131                 return FALSE;
132         }
133         if (*toneflag){
134                 ms_message("Duplicated tone event, ignored.");
135                 return FALSE;
136         }
137         *toneflag=TRUE;
138         return TRUE;
139 }
140
141 static void on_tone_received(void *data, MSFilter *f, unsigned int event_id, void *arg){
142         MSToneDetectorEvent *ev=(MSToneDetectorEvent*)arg;
143         EcCalibrator *ecc=(EcCalibrator*)data;
144         if (is_valid_tone(ecc,ev)){
145                 ecc->acc+=ev->tone_start_time;
146                 ms_message("Received tone at %u",(unsigned int)ev->tone_start_time);
147         }
148 }
149
150 static void ecc_play_tones(EcCalibrator *ecc){
151         MSDtmfGenCustomTone tone;
152         MSToneDetectorDef expected_tone;
153         
154         memset(&tone,0,sizeof(tone));
155         memset(&expected_tone,0,sizeof(expected_tone));
156
157         ms_filter_set_notify_callback(ecc->det,on_tone_received,ecc);
158
159         /* configure the tones to be scanned */
160         
161         strncpy(expected_tone.tone_name,"freq1",sizeof(expected_tone.tone_name));
162         expected_tone.frequency=2000;
163         expected_tone.min_duration=40;
164         expected_tone.min_amplitude=0.1;
165
166         ms_filter_call_method (ecc->det,MS_TONE_DETECTOR_ADD_SCAN,&expected_tone);
167         
168         strncpy(expected_tone.tone_name,"freq2",sizeof(expected_tone.tone_name));
169         expected_tone.frequency=2300;
170         expected_tone.min_duration=40;
171         expected_tone.min_amplitude=0.1;
172
173         ms_filter_call_method (ecc->det,MS_TONE_DETECTOR_ADD_SCAN,&expected_tone);
174         
175         strncpy(expected_tone.tone_name,"freq3",sizeof(expected_tone.tone_name));
176         expected_tone.frequency=2500;
177         expected_tone.min_duration=40;
178         expected_tone.min_amplitude=0.1;
179
180         ms_filter_call_method (ecc->det,MS_TONE_DETECTOR_ADD_SCAN,&expected_tone);
181         
182         /*play an initial tone to startup the audio playback/capture*/
183         
184         tone.frequencies[0]=140;
185         tone.duration=1000;
186         tone.amplitude=0.5;
187
188         ms_filter_call_method(ecc->gen,MS_DTMF_GEN_PLAY_CUSTOM,&tone);
189         ms_sleep(2);
190
191         ms_filter_set_notify_callback(ecc->gen,on_tone_sent,ecc);
192         
193         /* play the three tones*/
194         
195         tone.frequencies[0]=2000;
196         tone.duration=100;
197         ms_filter_call_method(ecc->gen,MS_DTMF_GEN_PLAY_CUSTOM,&tone);
198         ms_usleep(300000);
199         
200         tone.frequencies[0]=2300;
201         tone.duration=100;
202         ms_filter_call_method(ecc->gen,MS_DTMF_GEN_PLAY_CUSTOM,&tone);
203         ms_usleep(300000);
204         
205         tone.frequencies[0]=2500;
206         tone.duration=100;
207         ms_filter_call_method(ecc->gen,MS_DTMF_GEN_PLAY_CUSTOM,&tone);
208         ms_sleep(1);
209         
210         if (ecc->freq1 && ecc->freq2 && ecc->freq3) {
211                 int delay=ecc->acc/3;
212                 if (delay<0){
213                         ms_error("Quite surprising calibration result, delay=%i",delay);
214                         ecc->status=LinphoneEcCalibratorFailed;
215                 }else{
216                         ms_message("Echo calibration estimated delay to be %i ms",delay);
217                         ecc->delay=delay;
218                         ecc->status=LinphoneEcCalibratorDone;
219                 }
220         } else if ((ecc->freq1 || ecc->freq2 || ecc->freq3)==FALSE) {
221                         ms_message("Echo calibration succeeded, no echo has been detected");
222                         ecc->status = LinphoneEcCalibratorDoneNoEcho;
223         } else {
224                         ecc->status = LinphoneEcCalibratorFailed;
225         }
226
227         if (ecc->status == LinphoneEcCalibratorFailed) {
228                 ms_error("Echo calibration failed.");
229         }
230 }
231
232 static void  * ecc_thread(void *p){
233         EcCalibrator *ecc=(EcCalibrator*)p;
234         
235         ecc_init_filters(ecc);
236         ecc_play_tones(ecc);
237         ecc_deinit_filters(ecc);
238         ms_thread_exit(NULL);
239         return NULL;
240 }
241
242 EcCalibrator * ec_calibrator_new(MSSndCard *play_card, MSSndCard *capt_card, unsigned int rate, LinphoneEcCalibrationCallback cb,
243                                  LinphoneEcCalibrationAudioInit audio_init_cb, LinphoneEcCalibrationAudioUninit audio_uninit_cb, void *cb_data){
244         EcCalibrator *ecc=ms_new0(EcCalibrator,1);
245
246         ecc->rate=rate;
247         ecc->cb=cb;
248         ecc->cb_data=cb_data;
249         ecc->audio_init_cb=audio_init_cb;
250         ecc->audio_uninit_cb=audio_uninit_cb;
251         ecc->capt_card=capt_card;
252         ecc->play_card=play_card;
253         ms_thread_create(&ecc->thread,NULL,ecc_thread,ecc);
254         return ecc;
255 }
256
257 LinphoneEcCalibratorStatus ec_calibrator_get_status(EcCalibrator *ecc){
258         return ecc->status;
259 }
260
261 void ec_calibrator_destroy(EcCalibrator *ecc){
262         ms_thread_join(ecc->thread,NULL);
263         ms_free(ecc);
264 }
265
266 int linphone_core_start_echo_calibration(LinphoneCore *lc, LinphoneEcCalibrationCallback cb,
267                                          LinphoneEcCalibrationAudioInit audio_init_cb, LinphoneEcCalibrationAudioUninit audio_uninit_cb, void *cb_data){
268         if (lc->ecc!=NULL){
269                 ms_error("Echo calibration is still on going !");
270                 return -1;
271         }
272         unsigned int rate = lp_config_get_int(lc->config,"sound","echo_cancellation_rate",8000);
273         lc->ecc=ec_calibrator_new(lc->sound_conf.play_sndcard,lc->sound_conf.capt_sndcard,rate,cb,audio_init_cb,audio_uninit_cb,cb_data);
274         return 0;
275 }
276