]> sjero.net Git - linphone/blob - console/sipomatic.c
Aac-eld add missing header according to RFC3640 3.3.6
[linphone] / console / sipomatic.c
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 #include <eXosip2/eXosip.h>
23
24 int run_cond=1;
25
26 Sipomatic sipomatic;
27
28 int sipomatic_accept_audio_offer(sdp_context_t *ctx,sdp_payload_t *payload);
29 int sipomatic_accept_video_offer(sdp_context_t *ctx,sdp_payload_t *payload);
30
31
32 sdp_handler_t sipomatic_sdp_handler={
33         sipomatic_accept_audio_offer,   /*from remote sdp */
34         sipomatic_accept_video_offer,
35         NULL,
36         NULL,
37         NULL,
38         NULL,
39 };
40
41 void stop_handler(int signum)
42 {
43         run_cond=0;
44 }
45
46 void sipomatic_process_event(Sipomatic *obj,eXosip_event_t *ev)
47 {
48         Call *call;
49         switch(ev->type){
50                 case EXOSIP_CALL_INVITE:
51                         call_new(obj,ev);
52                         break;
53                 case EXOSIP_CALL_CLOSED:
54                 case EXOSIP_CALL_CANCELLED:
55                         call=sipomatic_find_call(obj,ev->did);
56                         if (call==NULL){
57                                 ms_warning("Could not find call with did %i !",ev->did);
58                         }
59                         call_release(call);
60                         call_destroy(call);
61                         break;
62                 default:
63                         break;
64         }
65         eXosip_event_free(ev);
66 }
67
68
69 void endoffile_cb(void *ud, MSFilter *f, unsigned int ev,void * arg){
70         Call*call=(Call*)ud;
71         call->eof=1;
72 }
73
74 void call_accept(Call *call)
75 {
76         sdp_context_t *ctx;
77         PayloadType *payload;
78         char *hellofile;
79         static int call_count=0;        
80         char record_file[250];
81         osip_message_t *msg=NULL;
82         sprintf(record_file,"/tmp/sipomatic%i.wav",call_count);
83
84         ctx=call->sdpc;
85         payload=rtp_profile_get_payload(call->profile,call->audio.pt);
86         if (strcmp(payload->mime_type,"telephone-event")==0){
87                 /* telephone-event is not enough to accept a call */
88                 ms_message("Cannot accept call with only telephone-event.\n");
89                 eXosip_call_send_answer(call->did,415,NULL);
90                 call->state=CALL_STATE_FINISHED;
91                 return;
92         }
93         if (payload->clock_rate==16000){
94                 hellofile=call->root->file_path16000hz;
95         }else hellofile=call->root->file_path8000hz;
96         eXosip_call_build_answer(call->tid,200,&msg);
97         osip_message_set_content_type(msg,"application/sdp");
98         osip_message_set_body(msg,call->sdpc->answerstr,strlen(call->sdpc->answerstr));
99         eXosip_call_send_answer(call->tid,200,msg);
100         call->audio_stream=audio_stream_new(call->audio.localport,call->audio.localport+1,call->root->ipv6);
101         audio_stream_start_with_files(call->audio_stream, call->profile,
102                                 call->audio.remaddr,call->audio.remoteport,call->audio.remoteport+1,
103                                  call->audio.pt,20,hellofile,record_file);
104         call_count++;
105 #ifdef VIDEO_ENABLED
106         if (call->video.remoteport!=0){
107                 video_stream_send_only_start(call->video_stream,call->profile,
108                         call->video.remaddr,call->video.remoteport,call->video.remoteport+1,call->video.pt, 60, 
109                         ms_web_cam_manager_get_default_cam(ms_web_cam_manager_get()));
110         }
111 #endif
112         call->time=time(NULL);
113         call->state=CALL_STATE_RUNNING;
114         ms_filter_set_notify_callback(call->audio_stream->soundread,endoffile_cb,(void*)call);
115 }
116
117
118 PayloadType * sipomatic_payload_is_supported(sdp_payload_t *payload,RtpProfile *local_profile,RtpProfile *dialog_profile)
119 {
120         int localpt;
121         if (payload->a_rtpmap!=NULL){
122                 localpt=rtp_profile_get_payload_number_from_rtpmap(local_profile,payload->a_rtpmap);
123         }else{
124                 localpt=payload->pt;
125                 ms_warning("payload has no rtpmap.");
126         }
127         
128         if (localpt>=0){
129                 /* this payload is supported in our local rtp profile, so add it to the dialog rtp
130                 profile */
131                 PayloadType *rtppayload;
132                 rtppayload=rtp_profile_get_payload(local_profile,localpt);
133                 if (rtppayload==NULL) return NULL;
134                 /*check if we have the appropriate coder/decoder for this payload */
135                 if (strcmp(rtppayload->mime_type,"telephone-event")!=0) {
136                         if (!ms_filter_codec_supported(rtppayload->mime_type)) {
137                                 ms_message("Codec %s is not supported.", rtppayload->mime_type);
138                                 return NULL;
139                         }
140                 }
141                 rtppayload=payload_type_clone(rtppayload);
142                 rtp_profile_set_payload(dialog_profile,payload->pt,rtppayload);
143                 /* add to the rtp payload type some other parameters (bandwidth) */
144                 if (payload->b_as_bandwidth!=0) rtppayload->normal_bitrate=payload->b_as_bandwidth*1000;
145                 if (payload->a_fmtp!=NULL)
146                         payload_type_set_send_fmtp(rtppayload,payload->a_fmtp);
147                 if (strcasecmp(rtppayload->mime_type,"iLBC")==0){
148                         /*default to 30 ms mode */
149                         payload->a_fmtp="ptime=30";
150                         payload_type_set_recv_fmtp(rtppayload,payload->a_fmtp);
151                 }
152                 return rtppayload;
153         }
154         return NULL;
155 }
156
157 int sipomatic_accept_audio_offer(sdp_context_t *ctx,sdp_payload_t *payload)
158 {
159         static int audioport=8000;
160         Call *call=(Call*)sdp_context_get_user_pointer(ctx);
161         PayloadType *supported;
162         struct stream_params *params=&call->audio;
163         
164         /* see if this codec is supported in our local rtp profile*/
165         supported=sipomatic_payload_is_supported(payload,&av_profile,call->profile);
166         if (supported==NULL) {
167                 ms_message("Refusing codec %i (%s)",payload->pt,payload->a_rtpmap);
168                 return -1;
169         }
170         if (strcmp(supported->mime_type,"telephone-event")==0) return 0;
171         if (params->ncodecs==0 ){
172                 /* this is the first codec we may accept*/
173                 params->localport=payload->localport=audioport;
174                 params->remoteport=payload->remoteport;
175                 params->line=payload->line;
176                 params->pt=payload->pt; /* remember the first payload accepted */
177                 params->remaddr=payload->c_addr;
178                 params->ncodecs++;
179                 audioport+=4;
180         }else{
181                 /* refuse all other audio lines*/
182                 if(params->line!=payload->line) return -1;
183         }
184         return 0;
185 }
186
187 int sipomatic_accept_video_offer(sdp_context_t *ctx,sdp_payload_t *payload)
188 {
189 #ifdef VIDEO_ENABLED
190         static int videoport=80000;
191         Call *call=(Call*)sdp_context_get_user_pointer(ctx);
192         PayloadType *supported;
193         struct stream_params *params=&call->video;
194         
195         /* see if this codec is supported in our local rtp profile*/
196         supported=sipomatic_payload_is_supported(payload,&av_profile,call->profile);
197         if (supported==NULL) {
198                 ms_message("Refusing video codec %i (%s)",payload->pt,payload->a_rtpmap);
199                 return -1;
200         }
201         if (params->ncodecs==0 ){
202                 /* this is the first codec we may accept*/
203                 params->localport=payload->localport=videoport;
204                 params->remoteport=payload->remoteport;
205                 params->line=payload->line;
206                 params->pt=payload->pt; /* remember the first payload accepted */
207                 params->remaddr=payload->c_addr;
208                 params->ncodecs++;
209                 videoport+=4;
210         }else{
211                 /* refuse all other video lines*/
212                 if(params->line!=payload->line) return -1;
213         }
214         return 0;
215 #else
216         return -1;
217 #endif
218 }
219
220 void sipomatic_init(Sipomatic *obj, char *url, bool_t ipv6)
221 {
222         osip_uri_t *uri=NULL;
223         int port=5064;
224         
225         obj->ipv6=ipv6;
226         
227         if (url==NULL){
228                 url=getenv("SIPOMATIC_URL");
229                 if (url==NULL){
230                         if (ipv6) url="sip:robot@[::1]:5064";
231                         else url="sip:robot@127.0.0.1:5064";
232                 }
233         }
234         if (url!=NULL) {
235                 osip_uri_init(&uri);
236                 if (osip_uri_parse(uri,url)==0){
237                         if (uri->port!=NULL) port=atoi(uri->port);
238                 }else{
239                         ms_warning("Invalid identity uri:%s",url);
240                 }       
241         }
242         ms_message("Starting using url %s",url);
243         ms_mutex_init(&obj->lock,NULL);
244         obj->calls=NULL;
245         obj->acceptance_time=5;
246         obj->max_call_time=300;
247         obj->file_path8000hz=ms_strdup_printf("%s/%s",PACKAGE_SOUND_DIR,ANNOUCE_FILE8000HZ);
248         obj->file_path16000hz=ms_strdup_printf("%s/%s",PACKAGE_SOUND_DIR,ANNOUCE_FILE16000HZ);
249         osip_trace_initialize(OSIP_INFO1,stdout);
250         osip_trace_initialize(OSIP_INFO2,stdout);
251         osip_trace_initialize(OSIP_WARNING,stdout);
252         osip_trace_initialize(OSIP_ERROR,stdout);
253         osip_trace_initialize(OSIP_BUG,stdout);
254         osip_trace_initialize(OSIP_FATAL,stdout);
255         osip_trace_enable_level(OSIP_INFO1);
256         osip_trace_enable_level(OSIP_INFO2);
257         osip_trace_enable_level(OSIP_WARNING);
258         osip_trace_enable_level(OSIP_ERROR);
259         osip_trace_enable_level(OSIP_BUG);
260         osip_trace_enable_level(OSIP_FATAL);
261         eXosip_init();
262         eXosip_set_user_agent("sipomatic-" LINPHONE_VERSION "/eXosip");
263         eXosip_listen_addr(IPPROTO_UDP,NULL,port,ipv6 ? AF_INET6 : AF_INET,0);
264 }
265
266 void sipomatic_uninit(Sipomatic *obj)
267 {
268         ms_mutex_destroy(&obj->lock);
269         eXosip_quit();
270 }
271
272 void sipomatic_iterate(Sipomatic *obj)
273 {
274         MSList *elem;
275         MSList *to_be_destroyed=NULL;
276         Call *call;
277         double elapsed;
278         eXosip_event_t *ev;
279
280         while((ev=eXosip_event_wait(0,0))!=NULL){
281                 sipomatic_process_event(obj,ev);
282         }
283         elem=obj->calls;
284         while(elem!=NULL){
285                 call=(Call*)elem->data;
286                 elapsed=time(NULL)-call->time;
287                 switch(call->state){
288                         case CALL_STATE_INIT:
289                                 if (elapsed>obj->acceptance_time){
290                                         call_accept(call);
291                                 }
292                         break;
293                         case CALL_STATE_RUNNING:
294                                 if (elapsed>obj->max_call_time || call->eof){
295                                         call_release(call);
296                                         to_be_destroyed=ms_list_append(to_be_destroyed,call);
297                                 }
298                         break;
299                 }
300                 elem=ms_list_next(elem);
301         }
302         for(;to_be_destroyed!=NULL; to_be_destroyed=ms_list_next(to_be_destroyed)){
303                 call_destroy((Call*)to_be_destroyed->data);
304         }
305 }
306
307
308 Call* sipomatic_find_call(Sipomatic *obj,int did)
309 {
310         MSList *it;
311         Call *call=NULL;
312         for (it=obj->calls;it!=NULL;it=ms_list_next(it)){
313                 call=(Call*)it->data;
314                 if ( call->did==did) return call;
315         }
316         return call;
317 }
318
319
320 Call * call_new(Sipomatic *root, eXosip_event_t *ev)
321 {
322         Call *obj;
323         char *sdpans;
324         int status;
325         sdp_message_t *sdp;
326         sdp_context_t *sdpc;
327         
328         sdp=eXosip_get_sdp_info(ev->request);
329         sdpc=sdp_handler_create_context(&sipomatic_sdp_handler,NULL,"sipomatic",NULL);
330         obj=ms_new0(Call,1);
331         obj->profile=rtp_profile_new("remote");
332         eXosip_call_send_answer(ev->tid,100,NULL);
333         sdp_context_set_user_pointer(sdpc,obj);
334         sdpans=sdp_context_get_answer(sdpc,sdp);
335         if (sdpans!=NULL){
336                 eXosip_call_send_answer(ev->tid,180,NULL);
337                 
338         }else{
339                 status=sdp_context_get_status(sdpc);
340                 eXosip_call_send_answer(ev->tid,status,NULL);
341                 sdp_context_free(sdpc);
342                 rtp_profile_destroy(obj->profile);
343                 ms_free(obj);
344                 return NULL;
345         }
346         obj->sdpc=sdpc;
347         obj->did=ev->did;
348         obj->tid=ev->tid;
349         obj->time=time(NULL);
350         obj->audio_stream=NULL;
351         obj->state=CALL_STATE_INIT;
352         obj->eof=0;
353         obj->root=root;
354         root->calls=ms_list_append(root->calls,obj);
355         return obj;
356 }
357
358 void call_release(Call *call)
359 {
360         eXosip_call_terminate(0,call->did);
361         if (call->audio_stream!=NULL) audio_stream_stop(call->audio_stream);
362 #ifdef VIDEO_ENABLED
363         if (call->video_stream!=NULL) video_stream_send_only_stop(call->video_stream);
364 #endif
365         call->state=CALL_STATE_FINISHED;
366 }
367
368 void call_destroy(Call *obj)
369 {
370         obj->root->calls=ms_list_remove(obj->root->calls,obj);
371         rtp_profile_destroy(obj->profile);
372         sdp_context_free(obj->sdpc);
373         ms_free(obj);
374 }
375
376 void sipomatic_set_annouce_file(Sipomatic *obj, char *file)
377 {
378         if (obj->file_path8000hz!=NULL){
379                 ms_free(obj->file_path8000hz);
380         }
381         obj->file_path8000hz=ms_strdup(file);
382 }
383
384
385 void display_help()
386 {
387         printf("sipomatic [-u sip-url] [-f annouce-file ] [-s port]\n"
388                         "sipomatic -h or --help: display this help.\n"
389                         "sipomatic -v or --version: display version information.\n"
390                         "       -u sip-url : specify the sip url sipomatic listens and answers.\n"
391                         "       -f annouce-file : set the annouce file (16 bit raw format,8000Hz)\n"
392                         " -6 enable ipv6 network usage\n");
393         exit(0);
394 }
395
396 char *getarg(int argc, char*argv[], int i)
397 {
398         if (i<argc){
399                 return argv[i];
400         }
401         else display_help();
402         return NULL;
403 }
404
405 int main(int argc, char *argv[])
406 {
407         int sendport=5070;
408         char *file=NULL;
409         char *url=NULL;
410         bool_t ipv6=FALSE;
411         int i;
412         
413         for(i=1;i<argc;i++){
414                 if ( (strcmp(argv[i],"-h")==0) || (strcmp(argv[i],"--help")==0) ){
415                         display_help();
416                         continue;
417                 }
418                 if ( (strcmp(argv[i],"-v")==0) || (strcmp(argv[i],"--version")==0) ){
419                         printf("version: " LINPHONE_VERSION "\n");
420                         exit(0);
421                 }
422                 if (strcmp(argv[i],"-u")==0){
423                         i++;
424                         url=getarg(argc,argv,i);
425                         continue;
426                 }
427                 if (strcmp(argv[i],"-s")==0){
428                         char *port;
429                         i++;
430                         port=getarg(argc,argv,i);
431                         sendport=atoi(port);
432                         continue;
433                 }
434                 if (strcmp(argv[i],"-f")==0){
435                         i++;
436                         file=getarg(argc,argv,i);
437                         continue;
438                 }
439                 if (strcmp(argv[i],"-6")==0){
440                         ipv6=TRUE;
441                         continue;
442                 }
443         }
444         
445         signal(SIGINT,stop_handler);
446         ortp_init();
447         ms_init();
448         ortp_set_log_level_mask(ORTP_MESSAGE|ORTP_WARNING|ORTP_ERROR|ORTP_FATAL);
449         rtp_profile_set_payload(&av_profile,115,&payload_type_lpc1015);
450         rtp_profile_set_payload(&av_profile,110,&payload_type_speex_nb);
451         rtp_profile_set_payload(&av_profile,111,&payload_type_speex_wb);
452         rtp_profile_set_payload(&av_profile,112,&payload_type_ilbc);
453         rtp_profile_set_payload(&av_profile,101,&payload_type_telephone_event);
454         rtp_profile_set_payload(&av_profile,116,&payload_type_truespeech);
455         rtp_profile_set_payload(&av_profile,98,&payload_type_h263_1998);
456         
457         sipomatic_init(&sipomatic,url,ipv6);
458         if (file!=NULL) sipomatic_set_annouce_file(&sipomatic,file);
459         
460         while (run_cond){
461                 sipomatic_iterate(&sipomatic);
462 #ifndef WIN32
463                 usleep(20000);
464 #else
465                 Sleep(20);
466 #endif
467         }
468         
469         return(0);
470 }