~ubuntu-branches/ubuntu/quantal/linphone/quantal

« back to all changes in this revision

Viewing changes to console/sipomatic.c

  • Committer: Bazaar Package Importer
  • Author(s): Samuel Mimram
  • Date: 2004-06-30 13:58:16 UTC
  • Revision ID: james.westby@ubuntu.com-20040630135816-wwx75gdlodkqbabb
Tags: upstream-0.12.2
ImportĀ upstreamĀ versionĀ 0.12.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/***************************************************************************
 
2
                          linphone  - sipomatic.c
 
3
This is a test program for linphone. It acts as a sip server and answers to linphone's
 
4
call.
 
5
                             -------------------
 
6
    begin                : ven mar  30
 
7
    copyright            : (C) 2001 by Simon MORLAT
 
8
    email                : simon.morlat@linphone.org
 
9
 ***************************************************************************/
 
10
 
 
11
/***************************************************************************
 
12
 *                                                                         *
 
13
 *   This program is free software; you can redistribute it and/or modify  *
 
14
 *   it under the terms of the GNU General Public License as published by  *
 
15
 *   the Free Software Foundation; either version 2 of the License, or     *
 
16
 *   (at your option) any later version.                                   *
 
17
 *                                                                         *
 
18
 ***************************************************************************/
 
19
 
 
20
#include <signal.h>
 
21
#include "sipomatic.h"
 
22
 
 
23
 
 
24
int run_cond=1;
 
25
 
 
26
Sipomatic sipomatic;
 
27
 
 
28
static char *num2str(int a)
 
29
{
 
30
        char *p=smalloc(10);
 
31
        snprintf(p,10,"%i",a);
 
32
        return p;
 
33
}
 
34
 
 
35
 
 
36
void stop_handler(int signum)
 
37
{
 
38
        run_cond=0;
 
39
}
 
40
 
 
41
int invite_accepted_cb(OsipDialog *call,transaction_t *trn, sip_t *msg,void *p2)
 
42
{
 
43
        /* we should never be here since sipomatic is unable to to make invites*/
 
44
        return(0);
 
45
}
 
46
 
 
47
int bye_cb(OsipDialog *dialog,transaction_t *trn, sip_t *msg,void *p2)
 
48
{
 
49
        /* get the call */
 
50
        Call *call=(Call*)dialog->data;
 
51
        sipomatic_lock(&sipomatic);
 
52
        if ( sipomatic_check_call(&sipomatic,call))
 
53
                call->state=CALL_STATE_FINISHED;
 
54
        sipomatic_unlock(&sipomatic);
 
55
        return(0);
 
56
}
 
57
 
 
58
int invite_cb(OsipDialog *dialog,transaction_t *trn, sip_t *sipmsg,void *p2)
 
59
{
 
60
        /* we have just received an invite, so wait two seconds, then accept it*/
 
61
        char *p;
 
62
        Call *call;
 
63
        
 
64
        from_2char(sipmsg->from,&p);
 
65
        g_message("Contacted by %s.\n",p);
 
66
        sfree(p);
 
67
        call=call_new(dialog);
 
68
        call->current_trn=trn;
 
69
        call->root=&sipomatic;
 
70
        sipomatic_lock(&sipomatic);
 
71
        sipomatic.calls=g_list_append(sipomatic.calls,call);
 
72
        sipomatic_unlock(&sipomatic);
 
73
        return(0);
 
74
}
 
75
 
 
76
gint endoffile_cb(MSFilter *f,gint ev,gpointer arg,gpointer data)
 
77
{
 
78
        Call*call=(Call*)data;
 
79
        call->eof=1;
 
80
}
 
81
 
 
82
void call_accept(Call *call)
 
83
{
 
84
        SdpContext *ctx;
 
85
        int status;
 
86
        OsipDialog *dialog=call->dialog;
 
87
        CallParams *callparams;
 
88
        PayloadType *payload;
 
89
        gchar *hellofile;
 
90
        
 
91
        ctx=SDP_CONTEXT(osip_dialog_get_body_context(dialog,"application/sdp",0));
 
92
        callparams=(CallParams*)BODY_CONTEXT(ctx)->data;
 
93
        status=sdp_context_get_negociation_status(ctx);
 
94
        if (status!=200){
 
95
                g_message("Error during sdp negociation, cannot accept call.\n");
 
96
                osip_dialog_respond(dialog,call->current_trn,SDP_CONTEXT(ctx)->negoc_status);
 
97
                call->state=CALL_STATE_FINISHED;
 
98
                return;
 
99
        }
 
100
        payload=rtp_profile_get_payload(callparams->profile,callparams->pt);
 
101
        if (strcmp(payload->mime_type,"telephone-event")==0){
 
102
                /* telephone-event is not enough to accept a call */
 
103
                g_message("Cannot accept call with only telephone-event.\n");
 
104
                osip_dialog_respond(dialog,call->current_trn,415);
 
105
                call->state=CALL_STATE_FINISHED;
 
106
                return;
 
107
        }
 
108
        if (payload->clock_rate==16000){
 
109
                hellofile=call->root->file_path16000hz;
 
110
        }else hellofile=call->root->file_path8000hz;
 
111
        osip_dialog_accept_invite(dialog,call->current_trn);
 
112
        call->audio_stream=audio_stream_start_with_files(callparams->profile,callparams->localport,
 
113
                                callparams->remaddr,callparams->remoteport,callparams->pt,20,hellofile,"/dev/null",NULL);
 
114
        g_timer_reset(call->timer);
 
115
        call->state=CALL_STATE_RUNNING;
 
116
        call->params=callparams;
 
117
        ms_filter_set_notify_func(call->audio_stream->soundread,endoffile_cb,(gpointer)call);
 
118
}
 
119
 
 
120
 
 
121
int faillure_cb(OsipDialog *call,transaction_t *trn, sip_t *msg,void *p2)
 
122
{
 
123
        return(0);
 
124
}
 
125
 
 
126
 
 
127
int payload_is_supported(SdpPayload *payload,RtpProfile *local_profile,RtpProfile *dialog_profile)
 
128
{
 
129
        int localpt;
 
130
        if (payload->a_rtpmap!=NULL){
 
131
                localpt=rtp_profile_get_payload_number_from_rtpmap(local_profile,payload->a_rtpmap);
 
132
        }else{
 
133
                localpt=payload->pt;
 
134
                g_warning("payload has no rtpmap.");
 
135
        }
 
136
        
 
137
        if (localpt>=0){
 
138
 
 
139
                /* this payload is supported in our local rtp profile, so add it to the dialog rtp
 
140
                profile */
 
141
                PayloadType *rtppayload;
 
142
                rtppayload=rtp_profile_get_payload(local_profile,localpt);
 
143
                if (rtppayload==NULL) return 0;
 
144
                rtppayload=payload_type_clone(rtppayload);
 
145
                rtp_profile_set_payload(dialog_profile,payload->pt,rtppayload);
 
146
                /* add to the rtp payload type some other parameters (bandwidth) */
 
147
                if (payload->b_as_bandwidth!=0) rtppayload->normal_bitrate=payload->b_as_bandwidth*1000;
 
148
                return 1;
 
149
        }
 
150
        return 0;
 
151
}
 
152
int accept_audio_offer(SdpHandler *sdph,SdpContext *ctx,SdpPayload *payload)
 
153
{
 
154
        static int audioport=8000;
 
155
        OsipDialog *dialog=BODY_CONTEXT(ctx)->dialog;
 
156
        CallParams *callparams;
 
157
        int supported;
 
158
        if (BODY_CONTEXT(ctx)->data!=NULL){
 
159
                callparams=(CallParams *) BODY_CONTEXT(ctx)->data;
 
160
        }else{
 
161
                callparams=call_params_new();
 
162
                BODY_CONTEXT(ctx)->data=(void*)callparams;
 
163
        }
 
164
        
 
165
        /* see if this codec is supported in our local rtp profile*/
 
166
        supported=payload_is_supported(payload,&av_profile,callparams->profile);
 
167
        if (!supported) {
 
168
                g_message("Refusing codec %i (%s)",payload->pt,payload->a_rtpmap);
 
169
                return -1;
 
170
        }
 
171
        if (callparams->ncodecs==0){
 
172
                /* this is the first codec we may accept*/
 
173
                callparams->localport=payload->localport=audioport;
 
174
                callparams->remoteport=payload->remoteport;
 
175
                callparams->line=payload->line;
 
176
                callparams->pt=payload->pt; /* remember the first payload accepted */
 
177
                callparams->remaddr=payload->c_addr;
 
178
                callparams->ncodecs++;
 
179
                audioport+=4;
 
180
        }else{
 
181
                /* refuse all other audio lines*/
 
182
                if(callparams->line!=payload->line) return -1;
 
183
        }
 
184
        return 0;
 
185
}
 
186
 
 
187
void sipomatic_init(Sipomatic *obj, gchar *url)
 
188
{
 
189
        MSCodecInfo *info;
 
190
        GList *elem;
 
191
        BodyHandler *sdph;
 
192
        if (url==NULL){
 
193
                url=getenv("SIPOMATIC_URL");
 
194
                if (url==NULL) url="sip:robot@0.0.0.0:5064";
 
195
        }
 
196
        g_message("Starting using url %s",url);
 
197
        obj->audio_codecs=ms_codec_get_all_audio();
 
198
        obj->lock=g_mutex_new();
 
199
        obj->calls=NULL;
 
200
        obj->acceptance_time=5;
 
201
        obj->max_call_time=300;
 
202
        obj->file_path8000hz=g_strdup_printf("%s/%s",PACKAGE_SOUND_DIR,ANNOUCE_FILE8000HZ);
 
203
        obj->file_path16000hz=g_strdup_printf("%s/%s",PACKAGE_SOUND_DIR,ANNOUCE_FILE16000HZ);
 
204
        
 
205
        /* create a user agent */
 
206
        obj->ua=osip_ua_new();
 
207
        osip_ua_set_contact(obj->ua,url);
 
208
        osip_ua_signal_connect(obj->ua,"INVITE_ACCEPTED",invite_accepted_cb);
 
209
        osip_ua_signal_connect(obj->ua,"BYE",bye_cb);
 
210
        osip_ua_signal_connect(obj->ua,"FAILLURE",faillure_cb);
 
211
        osip_ua_signal_connect(obj->ua,"INVITE",invite_cb);
 
212
        /* add sdp capabilities to the user agent */
 
213
        sdph=sdp_handler_new();
 
214
        sdp_handler_set_write_offer_fcn(SDP_HANDLER(sdph),NULL,NULL);
 
215
        sdp_handler_set_accept_offer_fcn(SDP_HANDLER(sdph),accept_audio_offer,NULL);
 
216
        sdp_handler_set_read_answer_fcn(SDP_HANDLER(sdph),NULL,NULL);
 
217
        
 
218
        osip_ua_add_body_handler(obj->ua,sdph);
 
219
        
 
220
}
 
221
 
 
222
void sipomatic_uninit(Sipomatic *obj)
 
223
{
 
224
        g_mutex_free(obj->lock);
 
225
        osip_ua_destroy(obj->ua);
 
226
}
 
227
 
 
228
void sipomatic_iterate(Sipomatic *obj)
 
229
{
 
230
        GList *elem;
 
231
        Call *call;
 
232
        gdouble time;
 
233
        sipomatic_lock(obj);
 
234
        elem=obj->calls;
 
235
        while(elem!=NULL){
 
236
                call=(Call*)elem->data;
 
237
                time=g_timer_elapsed(call->timer,NULL);
 
238
                switch(call->state){
 
239
                        case CALL_STATE_INIT:
 
240
                                if (time>obj->acceptance_time){
 
241
                                        call_accept(call);
 
242
                                }
 
243
                        break;
 
244
                        case CALL_STATE_RUNNING:
 
245
                                if (time>obj->max_call_time || call->eof){
 
246
                                        call_release(call);
 
247
                                        elem=obj->calls=g_list_remove(obj->calls,call);
 
248
                                        call_destroy(call);
 
249
                                }
 
250
                        break;
 
251
                        case CALL_STATE_FINISHED:
 
252
                                elem=obj->calls=g_list_remove(obj->calls,call);
 
253
                                call_destroy(call);
 
254
                        break;
 
255
                }
 
256
                elem=g_list_next(elem);
 
257
        }
 
258
        sipomatic_unlock(obj);
 
259
}
 
260
 
 
261
CallParams * call_params_new(){
 
262
        CallParams *obj;
 
263
        obj=g_new0(CallParams,1);
 
264
        obj->profile=rtp_profile_new("remote");
 
265
        return obj;
 
266
}
 
267
void call_params_destroy(CallParams *obj)
 
268
{
 
269
        rtp_profile_destroy(obj->profile);
 
270
        g_free(obj);
 
271
}
 
272
 
 
273
gboolean sipomatic_check_call(Sipomatic *obj,Call *call)
 
274
{
 
275
        GList *it;
 
276
        for (it=obj->calls;it!=NULL;it=g_list_next(it)){
 
277
                if ( ((Call*)it->data)==call) return 1;
 
278
        }
 
279
        return 0;
 
280
}
 
281
 
 
282
Call * call_new(OsipDialog *dialog)
 
283
{
 
284
        Call *obj=g_new0(Call,1);
 
285
        obj->timer=g_timer_new();
 
286
        obj->dialog=dialog;
 
287
        dialog->data=(void*)obj;
 
288
        g_timer_start(obj->timer);
 
289
        obj->audio_stream=NULL;
 
290
        obj->state=CALL_STATE_INIT;
 
291
        obj->eof=0;
 
292
        return obj;
 
293
}
 
294
 
 
295
void call_release(Call *call)
 
296
{
 
297
        osip_dialog_bye(call->dialog);
 
298
        call->state=CALL_STATE_FINISHED;
 
299
}
 
300
 
 
301
void call_destroy(Call *obj)
 
302
{
 
303
        if (obj->audio_stream!=NULL) audio_stream_stop(obj->audio_stream);
 
304
        g_timer_destroy(obj->timer);
 
305
        if (obj->params!=NULL) call_params_destroy(obj->params);
 
306
        g_free(obj);
 
307
}
 
308
 
 
309
void sipomatic_set_annouce_file(Sipomatic *obj, char *file)
 
310
{
 
311
        if (obj->file_path8000hz!=NULL){
 
312
                g_free(obj->file_path8000hz);
 
313
        }
 
314
        obj->file_path8000hz=g_strdup(file);
 
315
}
 
316
 
 
317
extern OsipManager *def_manager;
 
318
 
 
319
void display_help()
 
320
{
 
321
        printf("sipomatic [-u sip-url] [-f annouce-file ] [-s port]\n"
 
322
                        "sipomatic -h or --help: display this help.\n"
 
323
                        "sipomatic -v or --version: display version information.\n"
 
324
                        "       -u sip-url : specify the sip url sipomatic listens and answers.\n"
 
325
                        "       -f annouce-file : set the annouce file (16 bit raw format,8000Hz)\n"
 
326
                        "       -s port : set the port sipomatic uses to send its SIP answers.\n");
 
327
        exit(0);
 
328
}
 
329
 
 
330
char *getarg(int argc, char*argv[], int i)
 
331
{
 
332
        if (i<argc){
 
333
                return argv[i];
 
334
        }
 
335
        else display_help();
 
336
}
 
337
 
 
338
int main(int argc, char *argv[])
 
339
{
 
340
        int sendport=5070;
 
341
        char *file=NULL;
 
342
        gchar *url=NULL;
 
343
        int i;
 
344
        
 
345
        for(i=1;i<argc;i++){
 
346
                if ( (strcmp(argv[i],"-h")==0) || (strcmp(argv[i],"--help")==0) ){
 
347
                        display_help();
 
348
                        continue;
 
349
                }
 
350
                if ( (strcmp(argv[i],"-v")==0) || (strcmp(argv[i],"--version")==0) ){
 
351
                        printf("version: " LINPHONE_VERSION "\n");
 
352
                        exit(0);
 
353
                }
 
354
                if (strcmp(argv[i],"-u")==0){
 
355
                        i++;
 
356
                        url=getarg(argc,argv,i);
 
357
                        continue;
 
358
                }
 
359
                if (strcmp(argv[i],"-s")==0){
 
360
                        char *port;
 
361
                        i++;
 
362
                        port=getarg(argc,argv,i);
 
363
                        sendport=atoi(port);
 
364
                        continue;
 
365
                }
 
366
                if (strcmp(argv[i],"-f")==0){
 
367
                        i++;
 
368
                        file=getarg(argc,argv,i);
 
369
                        continue;
 
370
                }
 
371
        }
 
372
        
 
373
        signal(SIGINT,stop_handler);
 
374
        ms_init();
 
375
        ms_speex_codec_init();
 
376
        ortp_init();
 
377
        ortp_set_debug_file("oRTP",NULL);
 
378
        rtp_profile_set_payload(&av_profile,115,&lpc1015);
 
379
        rtp_profile_set_payload(&av_profile,110,&speex_nb);
 
380
        rtp_profile_set_payload(&av_profile,111,&speex_wb);
 
381
        rtp_profile_set_payload(&av_profile,101,&telephone_event);
 
382
        rtp_profile_set_payload(&av_profile,116,&truespeech);
 
383
        TRACE_INITIALIZE(TRACE_LEVEL6,stdout);
 
384
        osipua_init();
 
385
        osip_manager_set_send_port(def_manager,sendport);
 
386
        sipomatic_init(&sipomatic,url);
 
387
        if (file!=NULL) sipomatic_set_annouce_file(&sipomatic,file);
 
388
        
 
389
        while (run_cond){
 
390
                sipomatic_iterate(&sipomatic);
 
391
                usleep(20000);
 
392
        }
 
393
        
 
394
        return(0);
 
395
}