1 /***************************************************************************
3 This is a test program for linphone. It acts as a sip server and answers to linphone's
7 copyright : (C) 2001 by Simon MORLAT
8 email : simon.morlat@linphone.org
9 ***************************************************************************/
11 /***************************************************************************
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. *
18 ***************************************************************************/
21 #include "sipomatic.h"
22 #include <eXosip2/eXosip.h>
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);
32 sdp_handler_t sipomatic_sdp_handler={
33 sipomatic_accept_audio_offer, /*from remote sdp */
34 sipomatic_accept_video_offer,
41 void stop_handler(int signum)
46 void sipomatic_process_event(Sipomatic *obj,eXosip_event_t *ev)
50 case EXOSIP_CALL_INVITE:
53 case EXOSIP_CALL_CLOSED:
54 case EXOSIP_CALL_CANCELLED:
55 call=sipomatic_find_call(obj,ev->did);
57 ms_warning("Could not find call with did %i !",ev->did);
65 eXosip_event_free(ev);
69 void endoffile_cb(void *ud, MSFilter *f, unsigned int ev,void * arg){
74 void call_accept(Call *call)
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);
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;
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);
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()));
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);
118 PayloadType * sipomatic_payload_is_supported(sdp_payload_t *payload,RtpProfile *local_profile,RtpProfile *dialog_profile)
121 if (payload->a_rtpmap!=NULL){
122 localpt=rtp_profile_get_payload_number_from_rtpmap(local_profile,payload->a_rtpmap);
125 ms_warning("payload has no rtpmap.");
129 /* this payload is supported in our local rtp profile, so add it to the dialog rtp
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);
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);
157 int sipomatic_accept_audio_offer(sdp_context_t *ctx,sdp_payload_t *payload)
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;
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);
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;
181 /* refuse all other audio lines*/
182 if(params->line!=payload->line) return -1;
187 int sipomatic_accept_video_offer(sdp_context_t *ctx,sdp_payload_t *payload)
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;
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);
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;
211 /* refuse all other video lines*/
212 if(params->line!=payload->line) return -1;
220 void sipomatic_init(Sipomatic *obj, char *url, bool_t ipv6)
222 osip_uri_t *uri=NULL;
228 url=getenv("SIPOMATIC_URL");
230 if (ipv6) url="sip:robot@[::1]:5064";
231 else url="sip:robot@127.0.0.1:5064";
236 if (osip_uri_parse(uri,url)==0){
237 if (uri->port!=NULL) port=atoi(uri->port);
239 ms_warning("Invalid identity uri:%s",url);
242 ms_message("Starting using url %s",url);
243 ms_mutex_init(&obj->lock,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);
262 eXosip_set_user_agent("sipomatic-" LINPHONE_VERSION "/eXosip");
263 eXosip_listen_addr(IPPROTO_UDP,NULL,port,ipv6 ? AF_INET6 : AF_INET,0);
266 void sipomatic_uninit(Sipomatic *obj)
268 ms_mutex_destroy(&obj->lock);
272 void sipomatic_iterate(Sipomatic *obj)
275 MSList *to_be_destroyed=NULL;
280 while((ev=eXosip_event_wait(0,0))!=NULL){
281 sipomatic_process_event(obj,ev);
285 call=(Call*)elem->data;
286 elapsed=time(NULL)-call->time;
288 case CALL_STATE_INIT:
289 if (elapsed>obj->acceptance_time){
293 case CALL_STATE_RUNNING:
294 if (elapsed>obj->max_call_time || call->eof){
296 to_be_destroyed=ms_list_append(to_be_destroyed,call);
300 elem=ms_list_next(elem);
302 for(;to_be_destroyed!=NULL; to_be_destroyed=ms_list_next(to_be_destroyed)){
303 call_destroy((Call*)to_be_destroyed->data);
308 Call* sipomatic_find_call(Sipomatic *obj,int did)
312 for (it=obj->calls;it!=NULL;it=ms_list_next(it)){
313 call=(Call*)it->data;
314 if ( call->did==did) return call;
320 Call * call_new(Sipomatic *root, eXosip_event_t *ev)
328 sdp=eXosip_get_sdp_info(ev->request);
329 sdpc=sdp_handler_create_context(&sipomatic_sdp_handler,NULL,"sipomatic",NULL);
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);
336 eXosip_call_send_answer(ev->tid,180,NULL);
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);
349 obj->time=time(NULL);
350 obj->audio_stream=NULL;
351 obj->state=CALL_STATE_INIT;
354 root->calls=ms_list_append(root->calls,obj);
358 void call_release(Call *call)
360 eXosip_call_terminate(0,call->did);
361 if (call->audio_stream!=NULL) audio_stream_stop(call->audio_stream);
363 if (call->video_stream!=NULL) video_stream_send_only_stop(call->video_stream);
365 call->state=CALL_STATE_FINISHED;
368 void call_destroy(Call *obj)
370 obj->root->calls=ms_list_remove(obj->root->calls,obj);
371 rtp_profile_destroy(obj->profile);
372 sdp_context_free(obj->sdpc);
376 void sipomatic_set_annouce_file(Sipomatic *obj, char *file)
378 if (obj->file_path8000hz!=NULL){
379 ms_free(obj->file_path8000hz);
381 obj->file_path8000hz=ms_strdup(file);
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");
396 char *getarg(int argc, char*argv[], int i)
405 int main(int argc, char *argv[])
414 if ( (strcmp(argv[i],"-h")==0) || (strcmp(argv[i],"--help")==0) ){
418 if ( (strcmp(argv[i],"-v")==0) || (strcmp(argv[i],"--version")==0) ){
419 printf("version: " LINPHONE_VERSION "\n");
422 if (strcmp(argv[i],"-u")==0){
424 url=getarg(argc,argv,i);
427 if (strcmp(argv[i],"-s")==0){
430 port=getarg(argc,argv,i);
434 if (strcmp(argv[i],"-f")==0){
436 file=getarg(argc,argv,i);
439 if (strcmp(argv[i],"-6")==0){
445 signal(SIGINT,stop_handler);
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);
457 sipomatic_init(&sipomatic,url,ipv6);
458 if (file!=NULL) sipomatic_set_annouce_file(&sipomatic,file);
461 sipomatic_iterate(&sipomatic);