source: verona/phapi/phapi.c @ 410:7fe3493323e4

Last change on this file since 410:7fe3493323e4 was 410:7fe3493323e4, checked in by laurent@…, 16 months ago

fix payload without rtpmap

File size: 158.5 KB
Line 
1/*
2 * phapi   phone api
3 *
4 * Copyright (C) 2004        Vadim Lebedev <vadim@mbdsys.com>
5 *
6 * This is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as
8 * published by the Free Software F undation; either version 2,
9 * or (at your option) any later version.
10 *
11 * This is distributed in the hope that it will be useful, but
12 * 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
17 * License along with dpkg; if not, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21/**
22 * @file phapi.c
23 * @brief softphone  API
24 *
25 * phapi is a library providing simplified api to create VOIP sessions
26 * using eXosip library oSIP stack and oRTP stack
27 * <P>
28 */
29
30#include "phglobal.h"
31#ifdef OS_WIN32
32#include <winsock2.h>
33#include <windows.h>
34#endif
35#include <stdio.h>
36#include <string.h>
37#include <stdlib.h>
38#include <sys/stat.h>
39#include <sys/types.h>
40#include <errno.h>
41#include <limits.h>
42#include <ctype.h>
43#include <assert.h>
44#include <time.h>
45
46#if !defined(OS_WIN32) && !defined(_WIN32_WCE)
47//#include "config.h"
48#include <sys/wait.h>
49#include <unistd.h>
50#include <dirent.h>
51#if !defined(OS_MACOSX) && !defined(OS_ANDROID)
52#include <sys/soundcard.h>
53#endif
54#include <sys/ioctl.h>
55#include <fcntl.h>
56#else  /* WIN32 */
57#define snprintf _snprintf
58#ifndef _WIN32_WCE
59#define strncasecmp strnicmp
60#endif /* !_WIN32_WCE */
61# if !defined(strcasecmp)
62#  define strcasecmp stricmp
63# endif
64#define usleep(usecs) Sleep((usecs)/1000)
65#define random rand
66#define osip_free_func osip_free
67#endif
68
69#ifdef HAVE_NETINET_IN_H
70#include <netinet/in.h>
71#endif
72#include <osipparser2/osip_list.h>
73#include <osipparser2/osip_port.h>
74#include <osip2/osip_dialog.h>
75#include <osip2/osip_mt.h>
76#include <osip2/osip.h>
77#include <eXosip2/eXosip.h>
78#include <ortp/stun.h>
79#include <ortp/ortp.h>
80#include <ortp/payloadtype.h>
81
82#include "phapi-config.h"
83
84#include "phdebug.h"
85#include "phapi.h"
86#include "phcall.h"
87#include "phrpc.h"
88
89#include "phms.h"
90#include "phms_audiostream.h"
91#include "sdphandler.h"
92
93#ifdef USE_HTTP_TUNNEL
94#include "httptunnel.h"
95#endif
96
97#if  1
98
99#ifdef PHAPI_VIDEO_SUPPORT
100#include <libavcodec/avcodec.h>
101#include "phms_videostream.h"
102#endif
103
104#ifdef USE_UPNP
105#include <miniupnpc/upnpcommands.h>
106#include <miniupnpc/miniupnpc.h>
107
108static struct UPNPUrls ph_upnp_urls;
109static struct IGDdatas ph_upnp_data;
110static struct UPNPDev * ph_upnp_devlist;
111#endif
112
113static struct osip_thread *phapithread = NULL;
114
115phcall_t *ph_locate_call(eXosip_event_t *je, int creatit);
116phcall_t *ph_allocate_call(int cid);
117phcall_t *ph_locate_call_for_refer(eXosip_event_t *je);
118
119void ph_wegot_dtmf(void  *ctx, int dtmfEvent);
120static int ph_event_get();
121
122
123static char *ph_get_call_(phcall_t *ca);
124static void set_customized_header(osip_message_t *req, const char *h, const char *v);
125static char *ph_get_call_contact(phcall_t *ca);
126
127//#define MEDIA_SUSPEND
128
129/*#ifndef PH_STREAM_AUDIO
130#define PH_STREAM_AUDIO (1 << 0)
131#define PH_STREAM_VIDEO_RX (1 << 1)
132#define PH_STREAM_VIDEO_TX (1 << 2)
133#endif*/
134
135#define PH_STREAM_CNG (1 << 30)
136
137
138static int ph_call_retrieve_payloads(phcall_t *ca, int flags);
139static int ph_call_media_start(phcall_t *ca, eXosip_event_t *je, int flags, int resumeflag);
140static char *ph_ipv4tostr(char *buf, size_t s, const StunAddress4 addr);
141static void ph_release_stream_ports(phcall_t *ca);
142
143void ph_release_call(phcall_t *ca);
144static  int timeout = 10;
145
146static int ph_resend_offset = 30;
147
148#define PORT_STRING_LEN 16
149static char ph_nat_router_addr[32];
150static char ph_nat_port_str[PORT_STRING_LEN];
151
152#ifdef PHAPI_VIDEO_SUPPORT
153static char ph_nat_video_port_str[16];
154#endif
155
156static char ph_nat_sip_port_str[16];
157
158static char vcontact[256];
159
160typedef enum phNatType
161{
162        OPEN,
163        UPNP,
164        STUN,
165        TUNNEL
166}phNatType;
167
168static phNatType ph_nat_type = OPEN;
169static NatType ph_stun_nat_type = StunTypeOpen;
170
171static size_t ph_generate_rfc5626_probe(int rid, const void *addr, int addrlen, char* buf, size_t bsize);
172static char * _get_local_sip_port();
173static void  _get_local_video_sdp_port(char buf[]);
174static void  _get_local_audio_sdp_port(char buf[]);
175
176static char*  _get_public_sip_port();
177
178static void ph_connection_lost(const char *host, int port);
179static int ph_is_connection_lost;
180
181void ph_message_progress(eXosip_event_t *je);
182static void ph_keep_refreshing();
183static void  ph_call_requestfailure(eXosip_event_t *je);
184
185static void ph_frame_display_cbk(void *ctx, void *event);
186static void ph_qos_info_cbk(void *ctx, void *info);
187
188static int ph_call_media_stop(phcall_t * ca);
189static int ph_call_media_suspend(phcall_t *ca, int localhold);
190
191enum ph_direction
192{
193        sendrecv,
194        sendonly,
195        recvonly,
196        inactive
197};
198
199enum ph_direction ph_get_media_direction( sdp_message_t * sdp, const char * media_type);
200enum ph_direction ph_get_local_media_direction( phcall_t *ca, const char * media_type);
201int ph_set_media_direction( sdp_message_t * sdp, const char *media_type, enum ph_direction direction);
202const char * ph_get_str_direction( enum ph_direction direction);
203
204#define nonempty(x)  ((x) && (x)[0])
205
206
207#define USE_VLINES 1
208#ifndef PH_MAX_VLINES
209#define PH_MAX_VLINES 16
210#endif
211
212
213struct vline
214{
215        char  *displayname;
216        char  *nrusername;   /* username for non-REGISTER requests */
217        char  *rusername;    /* username for REGISTER requests */
218        char  *server;
219        int    port;
220        char  *proxy;
221        char  *contact;
222        time_t   regTimeout;
223        time_t   lastRegTime;
224        int   rid;
225#define VL_USED 1
226#define VL_DELETING 2
227        int   used;
228        int   busy;
229        char  *followme;
230        int    mobility;
231        struct
232        {
233                time_t  timeout;
234                time_t  last;
235                char    *etag;
236                char    *uri;
237                char    *evt;
238                char    *ctt;
239                char    *body;
240        } pub;
241};
242
243
244struct vline ph_vlines[PH_MAX_VLINES];
245
246static int
247ph_build_cname(char *buf, int n, struct vline *vl);
248
249
250static int 
251ph_req_set_body(osip_message_t *msg, const char *body, const char *mime);
252static char *
253ph_req_get_body(osip_message_t *msg);
254
255
256static 
257void ph_msession_free(struct ph_msession_s *s);
258static 
259void ph_msession_use(struct ph_msession_s *s);
260
261static struct vline *vline_alloc();
262static void vline_free(struct vline *vl);
263#define PHM_IGNORE_PORT 1
264#define PHM_IGNORE_HOST 2
265static struct vline *ph_find_matching_vline(const char *userid, int ignore);
266static struct vline *ph_find_matching_vline2(const char *username, const char* host, int ignore);
267static struct vline *ph_find_matching_vline3(const char *username, const char* host, int port, int ignore); 
268static struct vline *ph_find_vline_by_rid(int rid);
269
270static char *ph_get_proxy(const char *from);
271static int   ph_get_vline_id(const char *userid, const char *altid);
272static enum phNatType ph_get_nat_type() 
273{
274        return ph_nat_type;
275}
276
277int getPublicPort(char *local_voice_port, char *local_video_port, char *public_voice_port, char *public_video_port);
278
279
280
281#define ph_vlid2vline(vlid) (ph_vlines + (vlid) - 1)
282#define ph_vline2vlid(vl) ((vl) - ph_vlines + 1)
283
284#define clear(x) memset(&x, 0, sizeof(x))
285
286static struct vline *
287ph_valid_vlid(int vlid)
288{
289        struct vline *vl = 0;
290
291        if (vlid > 0 && vlid <= PH_MAX_VLINES)
292        {
293                vl = ph_vlid2vline(vlid);
294                if (!vl->used || vl->used == VL_DELETING)
295                        vl = 0;
296        }
297        return vl;
298}
299
300PHAPI_EXPORT phCallbacks_t *phcb;
301
302PHAPI_EXPORT int phIsInitialized;
303
304PHAPI_EXPORT int phDebugLevel = 0;
305PHAPI_EXPORT char *phLogFileName = 0;
306
307static char ph_follow_me_addr[256];
308
309unsigned short phCallBackPort = PH_CALLBACK_PORT; 
310PHAPI_EXPORT  unsigned short phServerPort = PH_SERVER_PORT;
311
312static int ph_busyFlag;
313
314
315static FILE *ph_log_file;
316
317void *
318ph_api_thread(void *arg);
319
320// mutex for ph_start_call
321ph_mutex_t  *ph_media_start_mutex;
322
323// mutex for ph_release_call
324ph_mutex_t  *ph_media_stop_mutex;
325
326ph_mutex_t *ph_custom_mutex;
327
328osip_list_t ph_custom_headers;
329int  ph_custom_idx;
330
331#define ph_custom_lock() osip_mutex_lock(ph_custom_mutex)
332#define ph_custom_unlock() osip_mutex_unlock(ph_custom_mutex)
333static void ph_apply_header_monitor(osip_message_t* msg,  struct ph_hdr_list *hlist);
334
335
336ph_mutex_t *ph_hdrmon_mutex;
337int ph_hdrmon_idx;
338osip_list_t ph_hdrmon_list;
339
340#define ph_hdrmon_lock() osip_mutex_lock(ph_hdrmon_mutex)
341#define ph_hdrmon_unlock() osip_mutex_unlock(ph_hdrmon_mutex)
342
343
344
345struct ph_custom_hdr
346{
347        char     *matchrequests;
348        char  *hdrname;
349        char  *hdrvalue;
350        int   idx;
351        int   enabled;
352
353};
354
355
356
357static char *presencenames[] =
358{
359                "presence",
360                "presence.winfo",
361                "presence.list",
362                "conflist",
363                "sipprofile",
364                "addressbook.query"
365};
366
367#define name(x) #x
368
369static char *evtnames[] =
370{
371                name(EXOSIP_REGISTRATION_NEW),           /**< announce new registration.       */
372                name(EXOSIP_REGISTRATION_SUCCESS),       /**< user is successfully registred.  */
373                name(EXOSIP_REGISTRATION_FAILURE),       /**< user is not registred.           */
374                name(EXOSIP_REGISTRATION_REFRESHED),     /**< registration has been refreshed. */
375                name(EXOSIP_REGISTRATION_TERMINATED),    /**< UA is not registred any more.    */
376
377                /* INVITE related events within calls */
378                name(EXOSIP_CALL_INVITE),            /**< announce a new call                   */
379                name(EXOSIP_CALL_REINVITE),          /**< announce a new INVITE within call     */
380
381                name(EXOSIP_CALL_NOANSWER),          /**< announce no answer within the timeout */
382                name(EXOSIP_CALL_PROCEEDING),        /**< announce processing by a remote app   */
383                name(EXOSIP_CALL_RINGING),           /**< announce ringback                     */
384                name(EXOSIP_CALL_ANSWERED),          /**< announce start of call                */
385                name(EXOSIP_CALL_REDIRECTED),        /**< announce a redirection                */
386                name(EXOSIP_CALL_REQUESTFAILURE),    /**< announce a request failure            */
387                name(EXOSIP_CALL_SERVERFAILURE),     /**< announce a server failure             */
388                name(EXOSIP_CALL_GLOBALFAILURE),     /**< announce a global failure             */
389                name(EXOSIP_CALL_ACK),               /**< ACK received for 200ok to INVITE      */
390
391                name(EXOSIP_CALL_CANCELLED),         /**< announce that call has been cancelled */
392                name(EXOSIP_CALL_TIMEOUT),           /**< announce that call has failed         */
393
394                /* request related events within calls (except INVITE) */
395                name(EXOSIP_CALL_MESSAGE_NEW),              /**< announce new incoming request. */
396                name(EXOSIP_CALL_MESSAGE_PROCEEDING),       /**< announce a 1xx for request. */
397                name(EXOSIP_CALL_MESSAGE_ANSWERED),         /**< announce a 200ok  */
398                name(EXOSIP_CALL_MESSAGE_REDIRECTED),       /**< announce a failure. */
399                name(EXOSIP_CALL_MESSAGE_REQUESTFAILURE),   /**< announce a failure. */
400                name(EXOSIP_CALL_MESSAGE_SERVERFAILURE),    /**< announce a failure. */
401                name(EXOSIP_CALL_MESSAGE_GLOBALFAILURE),    /**< announce a failure. */
402
403                name(EXOSIP_CALL_CLOSED),            /**< a BYE was received for this call      */
404
405                /* for both UAS & UAC events */
406                name(EXOSIP_CALL_RELEASED),             /**< call context is cleared.            */
407
408                /* response received for request outside calls */
409                name(EXOSIP_MESSAGE_NEW),              /**< announce new incoming request. */
410                name(EXOSIP_MESSAGE_PROCEEDING),       /**< announce a 1xx for request. */
411                name(EXOSIP_MESSAGE_ANSWERED),         /**< announce a 200ok  */
412                name(EXOSIP_MESSAGE_REDIRECTED),       /**< announce a failure. */
413                name(EXOSIP_MESSAGE_REQUESTFAILURE),   /**< announce a failure. */
414                name(EXOSIP_MESSAGE_SERVERFAILURE),    /**< announce a failure. */
415                name(EXOSIP_MESSAGE_GLOBALFAILURE),    /**< announce a failure. */
416
417                /* Presence and Instant Messaging */
418                name(EXOSIP_SUBSCRIPTION_UPDATE),         /**< announce incoming SUBSCRIBE.      */
419                name(EXOSIP_SUBSCRIPTION_CLOSED),         /**< announce end of subscription.     */
420
421                name(EXOSIP_SUBSCRIPTION_NOANSWER),          /**< announce no answer              */
422                name(EXOSIP_SUBSCRIPTION_PROCEEDING),        /**< announce a 1xx                  */
423                name(EXOSIP_SUBSCRIPTION_ANSWERED),          /**< announce a 200ok                */
424                name(EXOSIP_SUBSCRIPTION_REDIRECTED),        /**< announce a redirection          */
425                name(EXOSIP_SUBSCRIPTION_REQUESTFAILURE),    /**< announce a request failure      */
426                name(EXOSIP_SUBSCRIPTION_SERVERFAILURE),     /**< announce a server failure       */
427                name(EXOSIP_SUBSCRIPTION_GLOBALFAILURE),     /**< announce a global failure       */
428                name(EXOSIP_SUBSCRIPTION_NOTIFY),            /**< announce new NOTIFY request     */
429
430                name(EXOSIP_SUBSCRIPTION_RELEASED),          /**< call context is cleared.        */
431
432                name(EXOSIP_IN_SUBSCRIPTION_NEW),            /**< announce new incoming SUBSCRIBE.*/
433                name(EXOSIP_IN_SUBSCRIPTION_RELEASED),       /**< announce end of subscription.   */
434
435                name(EXOSIP_NOTIFICATION_NOANSWER),          /**< announce no answer              */
436                name(EXOSIP_NOTIFICATION_PROCEEDING),        /**< announce a 1xx                  */
437                name(EXOSIP_NOTIFICATION_ANSWERED),          /**< announce a 200ok                */
438                name(EXOSIP_NOTIFICATION_REDIRECTED),        /**< announce a redirection          */
439                name(EXOSIP_NOTIFICATION_REQUESTFAILURE),    /**< announce a request failure      */
440                name(EXOSIP_NOTIFICATION_SERVERFAILURE),     /**< announce a server failure       */
441                name(EXOSIP_NOTIFICATION_GLOBALFAILURE)     /**< announce a global failure       */
442
443};
444
445#undef name
446
447
448
449phcall_t ph_calls[PH_MAX_CALLS];
450
451/*
452//#define FORCE_VAD   1
453#define FORCE_CNG   1
454 */
455static struct osip_list ph_audio_payloads;
456static struct osip_list ph_video_payloads;
457
458
459ph_config_t phcfg = {
460                /* public ip addr */ "",
461                /* local ip addr */ "",
462                /* local audio rtp port */"10600",
463                /* local audio rtcp port */ "10900",
464                /* local audio rtp port */"10700",
465                /* local audio rtcp port */ "11000",
466                /* local video rtp port */ "10800",
467                /* local video rtcp port */ "11100",
468                /* sipport  */ "5060",
469                /* public sip port */ "",
470                /* sip transport */ IPPROTO_UDP,
471                /* nattype */  "" ,
472                /* codecs */   "" ,"",
473                /* asyncmode */ 0,
474                /* audio_dev_in */   "" ,
475                /* audio_dev_out */   "" ,
476                /* softboost */ 0,
477                /* no media */ 0,
478                /* no aec */ 0,
479                /* vad */ 0,
480                /* cng */ 0,
481                /* hdx mode */ 0,
482                /* nat_refresh_udp_time */ 0,
483                /* nat_refresh_tcp_time */ 0,
484                /* nat_refresh_time_shift */ 0,
485                /* ptime */ 0,
486                /* jitterdepth */0,
487                /* stream_timeout */0,
488                /* nodefaultline */0,
489                /* autoredir */0,
490                /* stunserver */  "80.118.132.74",
491                0
492};
493
494static const char *
495ph_get_event_type_str(int winfo)
496{
497        if (winfo >= sizeof(presencenames)/sizeof(presencenames[0]))
498                return NULL;
499        return presencenames[winfo];
500} 
501
502PHAPI_EXPORT ph_config_t *ph_get_config()
503{
504        return &phcfg;
505}
506
507static int _is_video_enabled(int streams) 
508{
509        return (streams & (PH_STREAM_VIDEO_RX | PH_STREAM_VIDEO_TX));
510}
511
512
513static int _is_audio_enabled(int streams) 
514{
515        return (streams & PH_STREAM_AUDIO);
516}
517
518static char *ph_ipv4tostr(char *buf, size_t s, const StunAddress4 addr)
519{
520        uint32_t ip = addr.addr;
521
522        snprintf(buf, s, "%d.%d.%d.%d", (ip >> 24) & 255,  (ip >> 16) & 255, (ip >> 8) & 255, ip & 255);
523
524        return buf;
525
526}
527
528static int 
529ph_port_inuse(int port)
530{
531        int i;
532        phcall_t *ca;
533
534        /* scan all active calls and check that the given port is inuse */
535        for(i=0; i<PH_MAX_CALLS;  i++)
536        {
537                ca = &ph_calls[i];
538                if (ca->cid != -1)
539                {
540                        /* active call */
541                        if(ca->loc_sdp_audio_port == port || port == ca->loc_sdp_video_port)
542                                return 1;
543                }
544        }
545
546        return 0;
547}
548
549static void 
550_get_local_audio_sdp_port(char buf[])
551{
552
553        /* <MINHPQ>
554         * To get arround the problem of connect in winsock ( connect returns
555         * an error: 10048: Address already in use connect is called an the local address is in used
556         * within the last 2 or 4 minutes), we should not bind the rtp socket to a specific local port. Hence,
557         * we should return "0" here to let the system choose a random port number.
558         */
559
560        /* base port number*/
561        int port = atoi(phcfg.local_audio_rtp_port);
562
563        buf[0] = 0;
564
565        if (port <= 0)
566                port = 10600 + random() % 4096;
567
568        while(1)
569        {
570                if (!ph_port_inuse(port))
571                {
572                        sprintf(buf, "%d", port);
573                        return;
574                }
575                else
576                        port += 2;    /* try next pair */
577        }
578}
579
580static void 
581_get_local_video_sdp_port(char buf[]) 
582{
583        int port = atoi(phcfg.local_video_rtp_port);
584
585        buf[0] = 0;
586
587        if (port <= 0)
588                port = 10600 + random() % 4096;
589        else
590                port += 2;
591
592        while(1)
593        {
594                if (!ph_port_inuse(port))
595                {
596                        sprintf(buf, "%d", port);
597                        return;
598                }
599                else
600                        port += 2;    /* try next pair */
601        }
602}
603
604
605
606static char *
607_get_local_sip_port()
608{
609        return phcfg.sipport;
610}
611
612static char *
613_get_public_sip_port()
614{
615        if (ph_nat_sip_port_str[0])
616                return ph_nat_sip_port_str;
617        return _get_local_sip_port();
618}
619
620phcall_t *
621ph_locate_call_by_cid(int cid)
622{
623        phcall_t *ca;
624
625        for(ca = ph_calls; ca < &ph_calls[PH_MAX_CALLS];  ca++)
626        {
627                if (ca->cid == cid)
628                        return ca;
629        }
630        return 0;
631}
632
633#if 0
634void phReleaseTerminatedCalls()
635{
636        phcall_t *ca;
637        for(ca = ph_calls; ca < &ph_calls[PH_MAX_CALLS];  ca++)
638        {
639                if ((ca->cid != -1) && (ph_media_is_stream_stopped(ca) == 1))
640                        ph_release_call(ca);
641        }
642}
643#endif
644
645
646phcall_t *
647ph_locate_call_by_rcid(int cid)
648{
649        phcall_t *ca;
650
651
652        for(ca = ph_calls; ca < &ph_calls[PH_MAX_CALLS];  ca++)
653        {
654                if (ca->rcid == cid)
655                        return ca;
656        }
657
658        return 0;
659}
660
661phcall_t *
662ph_locate_call_by_rdid(int did)
663{
664        phcall_t *ca;
665
666
667        for(ca = ph_calls; ca < &ph_calls[PH_MAX_CALLS];  ca++)
668        {
669                if (ca->rdid == did)
670                        return ca;
671        }
672
673        return 0;
674}
675
676
677phcall_t *
678ph_allocate_call(int cid)
679{
680        phcall_t *ca = ph_locate_call_by_cid(-1);
681
682        if (!ca)
683                return 0;
684
685        ca->redirs = 0;
686        ca->cid = cid;
687        osip_list_init(&ca->audio_payloads);
688        if (osip_list_clone(&ph_audio_payloads, &ca->audio_payloads, sdp_payload_clone))
689           return 0;
690        osip_list_init(&ca->video_payloads);
691        if (osip_list_clone(&ph_video_payloads, &ca->video_payloads, sdp_payload_clone))
692           return 0;
693        return ca;
694}
695
696
697phcall_t *
698ph_locate_call(eXosip_event_t *je, int creatit)
699{
700        phcall_t *ca, *found = 0, *newca = 0;
701        osip_header_t *hdr = 0;
702
703
704        /* lookup matching call descriptor */
705        for (ca = ph_calls; ca < &ph_calls[PH_MAX_CALLS]; ca++)
706        {
707                if (ca->cid == -1 && !newca)
708                        newca = ca;
709
710                if (ca->cid == je->cid)
711                {
712                        found = ca;
713                        break;
714                }
715        }
716
717        ca = found;
718
719        if (!ca) /* we didn't find a matching call descriptor */
720        {
721                if (creatit)
722                {
723                        /* allocate a new one */
724                        if (!newca)
725                                return 0; /* !!! BUG !!! */
726                        ca = newca;
727                        memset(ca, 0, sizeof(*ca));
728                        ca->cid = -2;
729                }
730        }
731
732        if (!ca)
733                return 0;
734
735
736        /* update the call information */
737
738        if (!ca->localrefer)
739        {
740                ca->cid = je->cid;
741                ca->did = je->did;
742                ca->tid = je->tid;
743        }
744
745        if (je->response)
746        {
747                osip_message_header_get_byname(je->response, "Accept-Contact", 0, &hdr);
748                if (hdr && !strcmp(hdr->hvalue, "*;+g.oma.sip-im"))
749                        ca->nego_mflags = PH_STREAM_DATA;
750        }
751
752        if (creatit)
753        {
754                if (osip_list_size(&ca->audio_payloads) == 0) {
755                        osip_list_init(&ca->audio_payloads);
756                        osip_list_clone(&ph_audio_payloads, &ca->audio_payloads, sdp_payload_clone);
757                }
758                if (osip_list_size(&ca->video_payloads) == 0) {
759                        osip_list_init(&ca->video_payloads);
760                        osip_list_clone(&ph_video_payloads, &ca->video_payloads, sdp_payload_clone);
761                }
762                osip_list_init(&ca->result_audio_payloads);
763                osip_list_init(&ca->result_video_payloads);
764
765                if (je->request && MSG_IS_INVITE(je->request) && !ca->remote_sdp && !ca->state == PH_CALLER)
766                {
767                        char *sdp = ph_req_get_body(je->request);
768
769                        if (sdp)
770                        {
771                                sdp_message_init(&ca->remote_sdp);
772                                sdp_message_parse(ca->remote_sdp, sdp);
773                                if (sdp_message_m_attr_has_type(ca->remote_sdp, "audio"))
774                                        ca->nego_mflags |= PH_STREAM_AUDIO;
775                                if (sdp_message_m_attr_has_type(ca->remote_sdp, "video"))
776                                        ca->nego_mflags |= PH_STREAM_VIDEO;
777                                osip_free(sdp);
778                        }
779                }
780
781                if (je->response && MSG_IS_INVITE(je->response) && !ca->remote_sdp)
782                {
783                        char *sdp = ph_req_get_body(je->response);
784
785                        if (sdp)
786                        {
787                                sdp_message_init(&ca->remote_sdp);
788                                sdp_message_parse(ca->remote_sdp, sdp);
789                                if (sdp_message_m_attr_has_type(ca->remote_sdp, "audio"))
790                                        ca->nego_mflags |= PH_STREAM_AUDIO;
791                                if (sdp_message_m_attr_has_type(ca->remote_sdp, "video"))
792                                        ca->nego_mflags |= PH_STREAM_VIDEO;
793                                osip_free(sdp);
794                        }
795                }
796        }
797        return ca;
798}
799
800static void 
801ph_free_stream(struct ph_stream_params *sp)
802{
803        int i;
804
805        if (sp->streamtype)
806                osip_free((void*)sp->streamtype);
807        if (sp->payloads)
808                osip_free((void*)sp->payloads);
809        if (sp->streamaddr)
810                osip_free((void*)sp->streamaddr);
811
812        for(i = 0; (i < PH_STREAM_MAX_ATTRS) && sp->attrs[i]; i++)
813                osip_free((void*)sp->attrs[i]);
814        osip_free(sp);
815}
816
817
818static void 
819ph_copy_stream(struct ph_stream_params *dp, const struct ph_stream_params *sp)
820{
821        int i;
822
823        *dp = *sp;
824        if (dp->streamtype)
825                dp->streamtype = strdup(dp->streamtype);
826        if (dp->payloads)
827                dp->payloads = strdup(dp->payloads);
828        if (dp->streamaddr)
829                dp->streamaddr = strdup(dp->streamaddr);
830
831        for(i = 0; (i < PH_STREAM_MAX_ATTRS) && dp->attrs[i]; i++)
832                dp->attrs[i] = strdup(dp->attrs[i]);
833
834}
835
836static void 
837ph_deep_copy_streams(struct ph_stream_params **dp, struct ph_stream_params **sp)
838{
839        int i;
840
841        for( i = 0; i < PH_MAX_STREAMS && sp[i]; i++)
842        {
843                dp[i] = malloc(sizeof(*sp[i]));
844                ph_copy_stream(dp[i], sp[i]);
845        }
846
847        if (i < PH_MAX_STREAMS)
848                dp[i] = 0;
849}
850
851
852static void 
853ph_free_all_streams(struct ph_stream_params *sp[])
854{
855        int i;
856
857        for( i = 0; i < PH_MAX_STREAMS && sp[i]; i++)
858        {
859                ph_free_stream(sp[i]);
860        }
861}
862
863static int ph_call_hasaudio(phcall_t *ca)
864{
865        if (ca->mses && (ca->mses->activestreams & (1 << PH_MSTREAM_AUDIO1)))
866                return 1;
867        return 0;
868}
869
870static int ph_call_hasvideo(phcall_t *ca)
871{
872        if (ca->mses && (ca->mses->activestreams & (1 << PH_MSTREAM_VIDEO1)))
873                return 1;
874        return 0;
875}
876
877static int ph_call_stream_alive(phcall_t *ca)
878{
879        if (!ph_call_hasaudio(ca) && !ph_call_hasvideo(ca))
880                return 0;
881        if (phcfg.stream_timeout <= 0)
882                return 1;
883        return ph_msession_is_stream_alive(ca->mses, phcfg.stream_timeout);
884}
885
886
887static struct ph_stream_params *
888ph_find_stream(struct ph_stream_params  **streams, const char *strtype, int maxstrs);
889
890void ph_release_call(phcall_t *ca)
891{
892
893        DBG_SIP_NEGO("SIP_NEGO: ph_release_call\n");
894
895        if (ph_call_hasaudio(ca) || ph_call_hasvideo(ca))
896        {
897                ph_call_media_stop(ca);
898        }
899
900
901        if (ca->audiodev_in != phcfg.audio_dev_in)
902                if (ca->audiodev_in)
903                        osip_free(ca->audiodev_in);
904       
905        if (ca->audiodev_out != phcfg.audio_dev_out)
906                if (ca->audiodev_out)
907                        osip_free(ca->audiodev_out);
908
909        ph_free_all_streams(ca->streams);
910        if (ca->sdpctx)
911                sdp_context_free(ca->sdpctx);
912
913        osip_list_special_free(&ca->audio_payloads, sdp_payload_free);
914        osip_list_special_free(&ca->result_audio_payloads, sdp_payload_free);
915        osip_list_special_free(&ca->result_video_payloads, sdp_payload_free);
916
917        osip_list_special_free(&ca->video_payloads, sdp_payload_free);
918
919        ph_release_stream_ports(ca);
920
921        memset(ca, 0, sizeof(phcall_t));
922        ca->cid = -1;
923}
924
925int ph_has_active_calls()
926{
927        phcall_t *ca;
928        int count = 0;
929
930        for(ca = ph_calls; ca < &ph_calls[PH_MAX_CALLS];  ca++)
931        {
932                if (ca->cid != -1 && (ph_call_hasaudio(ca) || ph_call_hasvideo(ca)) )
933                {
934                        if (!ca->remotehold && !ca->localhold)
935                                count++;
936                }
937        }
938
939        return count;
940}
941
942void ph_stream_ended(void *ctx, int event)
943{
944        phcall_t *ca = (phcall_t *)ctx;
945
946        ca->closereq = 1;
947}
948
949void ph_wegot_dtmf(void *ctx, int dtmfEvent)
950{
951        phCallStateInfo_t info;
952        phcall_t *ca = (phcall_t *)ctx;
953
954        clear(info);
955
956        info.event = phDTMF;
957        info.dtmfDigit = dtmfEvent;
958        info.vlid = ca->vlid;
959        phcb->callProgress(ca->cid, &info);
960
961}
962
963void ph_qos_info_cbk(void *ctx, void * info)
964{
965        phcall_t *ca = (phcall_t *)ctx;
966        phcb->qosEvent(ca->cid, (phQosInfo_t*)info);
967}
968
969void ph_frame_display_cbk(void *ctx, void *event)
970{
971        phcall_t *ca = (phcall_t *) ctx;
972
973        phcb->onFrameReady(ca->cid, event);
974}
975
976int ph_same_str(const char *str1, const char *str2)
977{
978        if (str1 == 0)
979                return str2 == 0;
980
981        if (str2 == 0)
982                return str1 == 0;
983
984        return (0 == strcasecmp(str1, str2));
985}
986
987int ph_same_uri(const char *uristr1, const char *uristr2)
988{
989        osip_contact_t *uri1, *uri2;
990        int ret;
991
992        osip_contact_init(&uri1);
993        osip_contact_init(&uri2);
994
995        osip_contact_parse(uri1, uristr1);
996        osip_contact_parse(uri2, uristr2);
997
998        /* if we've got and invalid URI return TRUE */
999        if (!uri1 || !uri2 || !uri1->url || !uri2->url)
1000                ret = 1;
1001        else
1002                ret = ph_same_str(uri1->url->username, uri2->url->username) &&
1003                ph_same_str(uri1->url->host, uri2->url->host) &&
1004                ph_same_str(uri1->url->port, uri2->url->port);
1005
1006        osip_contact_free(uri1);
1007        osip_contact_free(uri2);
1008
1009        return ret;
1010}
1011
1012static void
1013ph_prepare_stream_ports(phcall_t *ca)
1014{
1015
1016          ca->pub_sdp_audio_port = ca->loc_sdp_audio_port;
1017          ca->pub_sdp_audio_rtcp_port = ca->loc_sdp_audio_rtcp_port;
1018          ca->pub_sdp_video_port = ca->loc_sdp_video_port;
1019          ca->pub_sdp_video_rtcp_port = ca->loc_sdp_video_rtcp_port;
1020
1021#ifdef USE_PNP
1022          if (ph_upnp_devlist) {
1023                  struct vline* vl = vlid2vline(ca->vlid);
1024                  char localip[16];
1025                  const char* udp = "UDP";
1026
1027                  if (!vl)
1028                          return;
1029
1030                  eXosip_guess_localip(AF_INET, local_ip, 16);
1031
1032
1033                  if (_is_audio_enabled(ca->nego_mstreams)) {
1034                          ph_upnp_redir_port(localip, ca->loc_sdp_audio_port, &ca->pub_sdp_audio_port, udp);
1035                          if (!(vl->mobility & PH_NORTCP_ATTR))
1036                                  ph_upnp_redir_port(localip, ca->loc_sdp_audio_rtcp_port, &ca->pub_sdp_audio_rtcp_port, udp);
1037                  }
1038#ifdef PHAPI_VIDEO_SUPPORT
1039                  if (_is_video_enabled(ca->nego_mstreams)) {
1040                          ph_upnp_redir_port(localip, ca->loc_sdp_video_port, &ca->pub_sdp_video_port, udp);
1041                          if (!(vl->mobility &  PH_NORTCP_ATTR))
1042                                  ph_upnp_redir_port(localip, ca->loc_sdp_video_rtcp_port, &ca->pub_sdp_video_rtcp_port, udp);
1043                  }
1044#endif
1045          }
1046#endif
1047}
1048static void
1049ph_release_stream_ports(phcall_t *ca)
1050{
1051#ifdef USE_PNP
1052        const char* udp = "UDP";
1053          if (ph_upnp_devlist) {
1054                  struct vline* vl = vlid2vline(ca->vlid);
1055
1056                  if (_is_audio_enabled(ca->nego_mstreams)) {
1057                          ph_upnp_release_port(ca->pub_sdp_audio_port, udp);
1058                          if (!(vl->mobility & PH_NORTCP_ATTR))
1059                                  ph_upnp_relase_port(ca->pub_sdp_audio_rtcp_port, udp);
1060                  }
1061#ifdef PHAPI_VIDEO_SUPPORT
1062                  if (_is_video_enabled(ca->nego_mstreams)) {
1063                          ph_upnp_release_port(ca->pub_sdp_video_port, udp);
1064                          if (!(vl->mobility &  PH_NORTCP_ATTR))
1065                                  ph_upnp_redir_port(ca->pub_sdp_video_rtcp_port, udp);
1066                  }
1067#endif
1068          }
1069#endif
1070}
1071
1072static int 
1073ph_req_set_body(osip_message_t *msg, const char *body, const char *mime)
1074{
1075        char clen[10];
1076
1077        snprintf(clen, 10, "%li", strlen(body));
1078        if (mime)
1079                osip_message_set_content_type(msg, mime);
1080        osip_message_set_body(msg, body, strlen(body));
1081        osip_message_set_content_length(msg, clen);
1082
1083        return 0;
1084}
1085
1086static sdp_payload_t *
1087ph_call_support_payload(const struct osip_list *codec_list, const sdp_payload_t *payload)
1088{
1089        sdp_payload_t *cur_payload;
1090
1091        int pos = 0;
1092
1093        while (!osip_list_eol(codec_list, pos))
1094        {
1095                cur_payload = (sdp_payload_t *) osip_list_get (codec_list, pos);
1096
1097                if (sdp_equal_payload(cur_payload, payload) == 0)
1098                {
1099                        return cur_payload;
1100                }
1101                pos++;
1102        }
1103        return NULL;
1104}
1105
1106int ph_accept_audio_offer(sdp_context_t *ctx, sdp_payload_t *payload)
1107{
1108        phcall_t *ca =(phcall_t*)sdp_context_get_user_pointer(ctx);
1109        struct ph_stream_params *si;
1110        sdp_payload_t *new_payload, *ca_payload;
1111        struct vline *vl;
1112
1113        if (!_is_audio_enabled(ca->user_mflags) ||
1114                        !(ca_payload = ph_call_support_payload(&ca->audio_payloads, payload)))
1115        {
1116                DBG_CODEC_LOOKUP("Refusing audio codec %i (%s)",payload->pt,payload->a_rtpmap);
1117                return -1;
1118        }
1119
1120        if (!ca->remote_sdp_audio_port)
1121        {
1122                ca->remote_sdp_audio_port = payload->remoteport;
1123                ca->remote_sdp_audio_rtcp_port = payload->remotertcpport;
1124                osip_strncpy(ca->remote_sdp_audio_ip, payload->c_addr, sizeof(ca->remote_sdp_audio_ip)-1);
1125        }
1126
1127        //maybe si->streamport is useless
1128        {
1129                si  = ph_find_stream(ca->streams, "audio", 16);
1130                if (!si->streamaddr && si->streamport == -1)
1131                {
1132                        si->streamport = ca->loc_sdp_audio_port;
1133                }
1134        }
1135
1136        vl = ph_valid_vlid(ca->vlid);
1137
1138        payload->localport = ca->pub_sdp_audio_port;
1139    payload->localrtcpport = ca->pub_sdp_audio_rtcp_port;
1140
1141        sdp_payload_clone(payload, (void **)&new_payload);
1142        if (new_payload->a_rtpmap)
1143                new_payload->a_rtpmap = osip_strdup(ca_payload->a_rtpmap);
1144
1145        //we replace external payload number by local number
1146        //new_payload->pt = ca_payload->pt;
1147        if (vl->mobility & PH_NORTCP_ATTR)
1148                new_payload->localrtcpport = 0;
1149
1150        osip_list_add(&ca->result_audio_payloads, new_payload, -1);
1151
1152        return 0;
1153}
1154
1155int ph_accept_video_offer(sdp_context_t *ctx, sdp_payload_t *payload)
1156{
1157        phcall_t *ca =(phcall_t*)sdp_context_get_user_pointer(ctx);
1158        struct ph_stream_params *si;
1159        sdp_payload_t *new_payload, *ca_payload;
1160        struct vline* vl;
1161
1162        if (!_is_video_enabled(ca->user_mflags))
1163        {
1164                DBG_CODEC_LOOKUP("Refusing video codec %i (%s)",payload->pt,payload->a_rtpmap);
1165                return -1;
1166        }
1167
1168        if (!(ca_payload = ph_call_support_payload(&ca->video_payloads, payload)))
1169        {
1170                DBG_CODEC_LOOKUP("Refusing video codec %i (%s)",payload->pt,payload->a_rtpmap);
1171                return -1;
1172        }
1173
1174        if (!ca->remote_sdp_video_port)
1175        {
1176                ca->remote_sdp_video_port = payload->remoteport;
1177                ca->remote_sdp_video_rtcp_port = payload->remotertcpport;
1178                osip_strncpy(ca->remote_sdp_video_ip, payload->c_addr, sizeof(ca->remote_sdp_video_ip)-1);
1179        }
1180
1181        //maybe si->streamport is useless ?
1182        {
1183                si  = ph_find_stream(ca->streams, "video", 16);
1184                if (!si->streamaddr && si->streamport == -1)
1185                {
1186                        si->streamport = ca->loc_sdp_video_port;
1187                }
1188        }
1189
1190        payload->localport = ca->pub_sdp_video_port;
1191        payload->localrtcpport = ca->pub_sdp_video_rtcp_port;
1192
1193        sdp_payload_clone(payload, (void**) &new_payload);
1194        if (new_payload->a_rtpmap)
1195                new_payload->a_rtpmap = osip_strdup(ca_payload->a_rtpmap);
1196
1197        //we replace external payload number by local number
1198        //new_payload->pt = ca_payload->pt;
1199
1200        vl = ph_valid_vlid(ca->vlid);
1201        if (vl->mobility & PH_NORTCP_ATTR)
1202                new_payload->localrtcpport = 0;
1203
1204        osip_list_add(&ca->result_video_payloads, new_payload, -1);
1205
1206        return 0;
1207}
1208
1209int ph_set_audio_offer(sdp_context_t *ctx)
1210{
1211        phcall_t *ca =(phcall_t*)sdp_context_get_user_pointer(ctx);
1212
1213        RtpProfile *profile = &av_profile;
1214        sdp_payload_t *cur_payload;
1215        //sdp_payload_t payload;
1216        struct vline* vl;
1217
1218        int pos = 0;
1219
1220        if (!_is_audio_enabled(ca->user_mflags))
1221                return 0;
1222
1223        vl = ph_valid_vlid(ca->vlid);
1224        while (!osip_list_eol(&ca->audio_payloads, pos))
1225        {
1226                cur_payload = (sdp_payload_t *) osip_list_get (&ca->audio_payloads, pos);
1227                cur_payload->localport = ca->pub_sdp_audio_port;
1228                cur_payload->localrtcpport = ca->pub_sdp_audio_rtcp_port;
1229
1230                if (strncasecmp(cur_payload->a_rtpmap, "iLBC",4)==0)
1231                {
1232                        /* prefer the 30 ms mode */
1233                        cur_payload->a_fmtp=osip_strdup("ptime=30");
1234                }
1235
1236                if (vl->mobility & PH_NORTCP_ATTR)
1237                        cur_payload->localrtcpport = 0;
1238
1239                sdp_context_add_audio_payload(ctx, cur_payload, phcfg.ptime);
1240                pos++;
1241        }
1242
1243        /* add telephone-event payload*/
1244        /*      sdp_payload_init(&payload);
1245        payload.pt=rtp_profile_get_payload_number_from_mime(profile,"telephone-event");
1246        payload.a_rtpmap="telephone-event/8000";
1247        payload.a_fmtp="0-11";
1248
1249        sdp_context_add_audio_payload(ctx, &payload, 0);*/
1250
1251        return 0;
1252}
1253
1254int ph_set_video_offer(sdp_context_t *ctx)
1255{
1256        phcall_t *ca =(phcall_t*)sdp_context_get_user_pointer(ctx);
1257        sdp_payload_t *cur_payload;
1258        int pos = 0;
1259        struct vline* vl;
1260
1261        if (!_is_video_enabled(ca->user_mflags))
1262                return 0;
1263
1264        vl = ph_valid_vlid(ca->vlid);
1265        while (!osip_list_eol(&ca->video_payloads, pos))
1266        {
1267                cur_payload = (sdp_payload_t *) osip_list_get (&ca->video_payloads, pos);
1268                cur_payload->localport=ca->pub_sdp_video_port;
1269                cur_payload->localrtcpport = ca->pub_sdp_video_rtcp_port;
1270                if (vl->mobility & PH_NORTCP_ATTR)
1271                        cur_payload->localrtcpport = 0;
1272
1273                sdp_context_add_video_payload(ctx, cur_payload);
1274                pos++;
1275        }
1276
1277        return 0;
1278}
1279
1280
1281int ph_read_audio_answer(sdp_context_t *ctx, sdp_payload_t *payload)
1282{
1283        phcall_t *ca =(phcall_t*)sdp_context_get_user_pointer(ctx);
1284        sdp_payload_t *new_payload, *ca_payload;
1285
1286        if (!(ca_payload = ph_call_support_payload(&ca->audio_payloads, payload)))
1287        {
1288                DBG_CODEC_LOOKUP("Refusing audio codec answered %i (%s)",payload->pt,payload->a_rtpmap);
1289                return -1;
1290        }
1291
1292        sdp_payload_clone(payload, (void**) &new_payload);
1293        if (new_payload->a_rtpmap)
1294                new_payload->a_rtpmap = osip_strdup(ca_payload->a_rtpmap);
1295
1296        //we replace external payload number by local number
1297        new_payload->pt = ca_payload->pt;
1298        osip_list_add(&ca->result_audio_payloads, new_payload, -1);
1299
1300        if (!ca->remote_sdp_audio_port) {
1301                osip_strncpy(ca->remote_sdp_audio_ip, payload->c_addr, sizeof(ca->remote_sdp_audio_ip)-1);
1302                ca->remote_sdp_audio_port = payload->remoteport;
1303                ca->remote_sdp_audio_rtcp_port = payload->remotertcpport;
1304        }
1305        return 0;
1306}
1307
1308int ph_read_video_answer(sdp_context_t *ctx, sdp_payload_t *payload)
1309{
1310        phcall_t *ca =(phcall_t*)sdp_context_get_user_pointer(ctx);
1311        sdp_payload_t *new_payload, *ca_payload;
1312
1313        if (!(ca_payload = ph_call_support_payload(&ca->video_payloads, payload)))
1314        {
1315                DBG_CODEC_LOOKUP("Refusing video codec answered %i (%s)",payload->pt,payload->a_rtpmap);
1316                return -1;
1317        }
1318
1319        sdp_payload_clone(payload, (void**) &new_payload);
1320        if (new_payload->a_rtpmap)
1321                new_payload->a_rtpmap = osip_strdup(ca_payload->a_rtpmap);
1322
1323        //we replace external payload number by local number
1324        new_payload->pt = ca_payload->pt;
1325
1326        osip_list_add(&ca->result_video_payloads, new_payload, -1);
1327
1328        if (!ca->remote_sdp_video_port) {
1329                osip_strncpy(ca->remote_sdp_video_ip, payload->c_addr, sizeof(ca->remote_sdp_video_ip)-1);
1330                ca->remote_sdp_video_port = payload->remoteport;
1331                ca->remote_sdp_audio_rtcp_port = payload->remotertcpport;
1332        }
1333        return 0;
1334}
1335
1336
1337sdp_handler_t ph_sdp_handler={
1338                ph_accept_audio_offer,   /*from remote sdp */
1339                ph_accept_video_offer,   /*from remote sdp */
1340                ph_set_audio_offer,     /*to local sdp */
1341                ph_set_video_offer,     /*to local sdp */
1342                ph_read_audio_answer,   /*from incoming answer  */
1343                ph_read_video_answer    /*from incoming answer  */
1344};
1345
1346int
1347phGetVersion()
1348{
1349        static char version[] = PHAPI_VERSION_STRING;
1350        char *subv = strstr(version, ".");
1351        int v,s,r;
1352
1353        v = atoi(version);
1354        s = atoi(subv+1);
1355        r = atoi(strstr(subv+1, ".")+1);
1356
1357        return (v << 16) | (s << 8) | r;
1358}
1359#undef stringize
1360
1361const char *
1362phGetRevision()
1363{
1364#ifdef PHAPI_REVISION
1365        return PHAPI_REVISION;
1366#else  /*!PHAPI_REVISION */
1367        return "";
1368#endif /*!PHAPI_REVISION */
1369}
1370
1371
1372
1373/*
1374
1375PHAPI_EXPORT int
1376phGetAudioVersion()
1377{
1378  int fd, ret=-1;
1379#if !defined(WIN32) && !defined(__APPLE__) && !defined(__FreeBSD__)
1380#ifndef EMBED
1381  fd = open("/dev/dsp", O_RDWR, O_NONBLOCK);
1382#else
1383  fd = open("/dev/sound/mixer0", O_RDWR, O_NONBLOCK);
1384#endif
1385  if (fd>=0)
1386
1387    {
1388#if defined(EMBED)
1389    if(0>ioctl(fd, SOUND_MIXER_PRIVATE5, &ret))
1390#else
1391      if(0>ioctl(fd, OSS_GETVERSION, &ret))
1392#endif
1393        ret = -1;
1394    close(fd);
1395    }
1396  return ret;
1397#else
1398  return 0;
1399#endif
1400} */
1401
1402PHAPI_EXPORT int
1403phGetNatInfo(char *ntstr, int ntlen, char *fwip, int fwiplen)
1404{
1405        assert(ntstr!=NULL);
1406        assert(fwip!=NULL);
1407
1408        //osip_strncpy(ntstr, ph_get_nat_type(), ntlen-1);
1409        osip_strncpy(fwip, ph_nat_router_addr, fwiplen-1);
1410        return 0;
1411}
1412
1413
1414
1415
1416PHAPI_EXPORT int
1417phSetUaString(const char *uastr)
1418{
1419        eXosip_set_user_agent(uastr);
1420        return 0;
1421}
1422
1423#define FROM_DISPLAYNAME 1
1424#define FROM_PORT 2
1425#define FROM_FORCEPORT 4
1426#define FROM_NRUSERNAME 8
1427
1428static void
1429ph_build_from2(char *buf, int n, struct vline *vl, int flags)
1430{
1431        char *un, *s;
1432        char port[32]={0};
1433        const char *uphone = "";
1434
1435        assert(buf != NULL);
1436        assert(vl != NULL);
1437
1438        if (checkmobility(vl->mobility,PH_LINE_MOBILITY_PHONE))
1439                uphone=";user=phone";
1440
1441
1442        if (flags & FROM_NRUSERNAME)
1443                un = nonempty(vl->nrusername) ? vl->nrusername : "unknown";
1444        else
1445                un = nonempty(vl->rusername) ? vl->rusername : "unknown";
1446
1447        s = nonempty(vl->server) ? vl->server : "localhost";
1448        if ((vl->port >= 0 && vl->port != 5060 && (flags & FROM_PORT)) || (vl->port == 5060 && (flags & FROM_FORCEPORT)))
1449                snprintf(port, sizeof(port), ":%d", vl->port);
1450
1451
1452        if ((flags & FROM_DISPLAYNAME) && nonempty(vl->displayname))
1453        {
1454                if (!strchr(vl->displayname, ' '))
1455                {
1456                        snprintf(buf, n, "%s <sip:%s@%s%s%s>", vl->displayname, un, s, port, uphone);
1457                }
1458                else
1459                {
1460                        snprintf(buf, n, "\"%s\" <sip:%s@%s%s%s>", vl->displayname, un, s, port, uphone);
1461                }
1462
1463        }
1464        else
1465        {
1466                snprintf(buf, n, "<sip:%s@%s%s%s>", un, s, port, uphone);
1467        }
1468}
1469
1470
1471static void
1472ph_build_from(char *buf, int n, struct vline *vl)
1473{
1474        ph_build_from2(buf, n, vl, FROM_DISPLAYNAME|FROM_NRUSERNAME);
1475}
1476
1477
1478static void
1479ph_build_contact(char *buf, int n, struct vline *vl)
1480{
1481        char fbuf[512];
1482        char *ctct;
1483
1484        ph_build_from2(fbuf, 512, vl, 0);
1485        if (!eXosip_build_contact_str(fbuf, 0, &ctct))
1486        {
1487                strncpy(buf, ctct, n);
1488                osip_free(ctct);
1489                return;
1490        }
1491        strncpy(buf, fbuf, n);
1492
1493
1494}
1495
1496
1497static int
1498ph_build_cname(char *buf, int n, struct vline *vl)
1499{
1500        char *un, *s;
1501        int res;
1502        assert(buf!=NULL);
1503        assert(vl!=NULL);
1504
1505        un = nonempty(vl->nrusername) ? vl->nrusername : "unknown";
1506        s = nonempty(vl->server) ? vl->server : "localhost";
1507
1508        res = snprintf(buf, n, "%s@%s", un, s);
1509        return res < 0 ? 1 : res >= n;
1510}
1511
1512//
1513
1514static int 
1515ph_retrieve_from(int did, char **from)
1516{
1517        osip_dialog_t *dlg = eXosip_call_get_osip_dialog(did);
1518
1519        if (did)
1520                return -1;
1521
1522        return osip_from_to_str(dlg->remote_uri, from);
1523
1524}
1525
1526#define optional(x) (x[0] ? x : 0)
1527
1528static void
1529ph_replace_contact(osip_message_t *msg, const char *ctct)
1530{
1531        osip_list_special_free(&msg->contacts, (void (*)(void *)) &osip_contact_free);
1532        osip_message_set_contact(msg, ctct);
1533}
1534
1535int
1536phLinePlaceCall_withCa(int vlid, const char *uri, void *userdata, int rcid, int streams, phcall_t *ca0, const char *adev, const char *audio_addr, const char *video_addr)
1537{
1538        int i;
1539        osip_message_t *invite;
1540        phcall_t *ca = 0;
1541        char *proxy = 0;
1542        struct vline *vl;
1543        char from[512];
1544        char  local_voice_port[16];
1545        char  local_video_port[16];
1546        char  local_ip[16];
1547
1548        DBG_SIP_NEGO("phLinePlaceCall_withCa: a new call has been placed\n");
1549
1550        local_video_port[0] = 0;
1551        local_voice_port[0] = 0;
1552
1553        if (!phIsInitialized)
1554                return -PH_NOTINIT;
1555
1556        if (!nonempty(uri))
1557                return -PH_BADARG;
1558
1559        vl = ph_valid_vlid(vlid);
1560
1561        if (!vl)
1562                return -PH_BADVLID;
1563
1564        if (rcid)
1565        {
1566                ca = ph_locate_call_by_cid(rcid);
1567                if (!ca)
1568                        return -PH_BADCID;
1569        }
1570
1571        eXosip_lock();
1572        if (!ca0)
1573                ca0 = ph_allocate_call(-2);
1574        else
1575                ca0->cid = -2;
1576        eXosip_unlock();
1577
1578        if (!ca0)
1579                return -PH_NORESOURCES;
1580
1581        if (adev)
1582                ca0->audiodev_in = osip_strdup(adev);
1583        else 
1584        {
1585                if (phcfg.audio_dev_in) {
1586                        ca0->audiodev_in = osip_strdup(phcfg.audio_dev_in);
1587                }
1588                if (phcfg.audio_dev_out) {
1589                        ca0->audiodev_out = osip_strdup(phcfg.audio_dev_out);
1590                }
1591        }
1592
1593        ca0->user_mflags = streams | (vl->mobility & PH_NOEARLY_MEDIA);
1594        ca0->nego_mflags = streams;
1595
1596        if (rcid)
1597                ca0->rcid = rcid;
1598
1599        if (audio_addr == NULL)
1600        {
1601                if (phcfg.local_ip_addr[0] == 0)
1602                {
1603                        eXosip_guess_localip(AF_INET, local_ip, 16);
1604                }
1605                else
1606                {
1607                        osip_strncpy(local_ip, phcfg.local_ip_addr, sizeof(local_ip)-1);
1608                }
1609        }
1610        else
1611                osip_strncpy(local_ip, audio_addr, sizeof(local_ip)-1);
1612
1613        ca0->vlid = ph_vline2vlid(vl);
1614        ca0->state = PH_CALLER;
1615
1616        if (streams & PH_ANONYMOUS_CALL)
1617                strcpy(from, "<sip:anonymous@anonymous.invalid>");
1618        else
1619                ph_build_from2(from, sizeof(from), vl, FROM_DISPLAYNAME | FROM_PORT | FROM_NRUSERNAME);
1620
1621        proxy = vl->proxy;
1622
1623        eXosip_lock();
1624        i = eXosip_call_build_initial_invite(&invite,
1625                        uri,
1626                        from,
1627                        proxy,
1628                        "PHAPI CALL");
1629        eXosip_unlock();
1630        if (i!=0)
1631                return -1;
1632
1633        osip_message_set_allow(invite, "INVITE, ACK, BYE, CANCEL, REFER, NOTIFY, SUBSCRIBE, REGISTER");
1634
1635        ph_apply_customizations(invite, NULL, NULL);
1636        if (streams & PH_ANONYMOUS_CALL) {
1637                osip_message_set_header(invite, "Privacy", "id");
1638                ph_replace_contact(invite, vl->contact);
1639        }
1640
1641
1642        if (_is_audio_enabled(streams))
1643        {
1644                _get_local_audio_sdp_port(local_voice_port);
1645                ca0->loc_sdp_audio_port = atoi(local_voice_port);
1646                ca0->loc_sdp_audio_rtcp_port = ca0->loc_sdp_audio_port + 1;
1647        }
1648
1649        if (_is_video_enabled(streams))
1650        {
1651                _get_local_video_sdp_port(local_video_port);
1652                ca0->loc_sdp_video_port = atoi(local_video_port);
1653                ca0->loc_sdp_video_rtcp_port = ca0->loc_sdp_video_port + 1;
1654        }
1655
1656
1657        if (streams == PH_STREAM_DATA)
1658        {
1659                osip_message_set_header(invite, "Accept-Contact", "*;g.oma.sip-im");
1660                eXosip_lock();
1661                i = eXosip_call_send_initial_invite(invite); //  userdata, NULL, 0,  0,  0, 0, 0, 0);
1662        }
1663        else
1664        {
1665                if (!ca0->sdpctx) {
1666                        ph_prepare_stream_ports(ca0);
1667                        ca0->sdpctx = sdp_handler_create_context(&ph_sdp_handler, local_ip, vl->nrusername, 0);
1668                        ca0->cfg =  &phcfg;
1669                        sdp_context_set_user_pointer(ca0->sdpctx, ca0);
1670                }
1671
1672
1673                sdp_context_build_offer(ca0->sdpctx);
1674                ca0->local_sdp = ca0->sdpctx->offer;
1675
1676                ph_req_set_body(invite, ca0->sdpctx->offerstr, "application/sdp");
1677
1678                eXosip_lock();
1679                i = eXosip_call_send_initial_invite(invite);
1680        }
1681
1682        eXosip_call_set_reference(i, userdata);
1683        ca0->cid = i;
1684        ca0->state = PH_CALLER;
1685        eXosip_unlock();
1686        return i;
1687
1688}
1689
1690PHAPI_EXPORT int
1691phLinePlaceCall2(int vlid, const char *uri, void *userdata, int rcid, int streams)
1692{
1693        return phLinePlaceCall_withCa(vlid, uri, userdata, rcid, streams, 0, 0, 0, 0);
1694}
1695
1696
1697PHAPI_EXPORT int
1698phLinePlaceCall3(int vlid, const char *uri, void *userdata, int rcid, int streams, const char *adev)
1699{
1700        return phLinePlaceCall_withCa(vlid, uri, userdata, rcid, streams, 0, adev, 0, 0);
1701}
1702
1703PHAPI_EXPORT int
1704phLinePlaceCall4(int vlid, const char *uri, void *userdata, int rcid, int streams, const char *adev, const char *audio_addr, const char *video_addr)
1705{
1706        return phLinePlaceCall_withCa(vlid, uri, userdata, rcid, streams, 0, adev, audio_addr, video_addr);
1707}
1708
1709PHAPI_EXPORT int
1710phLinePlaceMcCall(int vlid, const char *uri, void *userdata, int streams, const char *adev)
1711{
1712        if (!streams)
1713                streams = PH_STREAM_AUDIO;
1714
1715        return phLinePlaceCall_withCa(vlid, uri, userdata, 0,
1716                        streams|PH_STREAM_MCRECV, 0, adev, 0, 0);
1717}
1718
1719PHAPI_EXPORT int
1720phLinePlaceCall(int vlid, const char *uri, void *userdata, int rcid)
1721{
1722        return phLinePlaceCall_withCa(vlid, uri, userdata, rcid, PH_STREAM_AUDIO, 0, 0, 0, 0);
1723}
1724
1725PHAPI_EXPORT int
1726phLineSendMessage(int vlid, const char *uri, const char *buff, const char *mime)
1727{
1728        return phLineSendMessage2(vlid, uri, uri, buff, mime, 0);
1729}
1730
1731
1732PHAPI_EXPORT int
1733phLineSendMessage2(int vlid, const char *target, const char *uri,
1734                const char *buff, const char *mime, const char *sipcid)
1735{
1736        int i;
1737        struct vline *vl;
1738        char from[512];
1739        osip_message_t *msg;
1740
1741
1742
1743        if (!phIsInitialized)
1744                return -PH_NOTINIT;
1745
1746        vl = ph_valid_vlid(vlid);
1747        if (!vl) {
1748                return -PH_BADVLID;
1749        }
1750
1751        if ( !nonempty(uri)) {
1752                return -PH_BADARG;
1753        }
1754
1755        ph_build_from(from, sizeof(from), vl);
1756
1757        eXosip_lock();
1758        i = eXosip_message_build_request(&msg, "MESSAGE", (char *)uri,
1759                        from, vl->proxy);
1760
1761
1762        ph_req_set_body(msg, buff, mime);
1763        osip_message_set_contact(msg, vl->contact);
1764
1765        if (sipcid)
1766                osip_message_set_call_id(msg, sipcid);
1767
1768        ph_apply_customizations(msg, NULL, NULL);
1769        i = eXosip_message_send_request(msg);
1770
1771        eXosip_unlock();
1772        return i;
1773}
1774
1775PHAPI_EXPORT int
1776phCallSendMessage(int cid, const char *buff, const char *mime)
1777{
1778        int i;
1779        phcall_t *ca;
1780        osip_message_t *msg;
1781
1782        if (!phIsInitialized)
1783                return -PH_NOTINIT;
1784
1785        ca = ph_locate_call_by_cid(cid);
1786
1787        if (!ca)
1788                return -PH_BADCID;
1789
1790        eXosip_lock();
1791
1792        i = eXosip_call_build_request(ca->did, "MESSAGE", &msg);
1793        ph_req_set_body(msg, buff, mime);
1794        osip_message_set_contact(msg, ph_get_call_contact(ca));
1795        i = eXosip_call_send_request(ca->did, msg);
1796
1797        eXosip_unlock();
1798
1799        return i;
1800}
1801
1802
1803
1804
1805PHAPI_EXPORT int
1806phSendMessage(const char *from, const char *uri,
1807                const char *buff, const char *mime)
1808{
1809        int i;
1810        osip_message_t *msg;
1811
1812        if (!phIsInitialized)
1813                return -PH_NOTINIT;
1814
1815        if (!nonempty(from) || !nonempty(uri))
1816                return -PH_BADARG;
1817
1818        eXosip_lock();
1819        i = eXosip_message_build_request(&msg, "MESSAGE", uri, from, ph_get_proxy(from));
1820        ph_req_set_body(msg, buff, mime);
1821        ph_apply_customizations(msg, NULL, NULL);
1822        i = eXosip_message_send_request(msg);
1823        eXosip_unlock();
1824        return i;
1825}
1826
1827PHAPI_EXPORT int
1828phLineSubscribe(int vlid, const char *uri, const int winfo)
1829{
1830        return phLineSubscribe2(vlid, uri, winfo, NULL, 1, 600);
1831}
1832
1833PHAPI_EXPORT int
1834phLineSubscribe2(int vlid, const char *uri, const int winfo, char *data, int use_proxy, int expire)
1835{
1836        int i;
1837        struct vline *vl;
1838        char from[512];
1839        osip_message_t *msg;
1840
1841        if (!phIsInitialized)
1842                return -PH_NOTINIT;
1843
1844        vl = ph_valid_vlid(vlid);
1845
1846        if (!vl)
1847                return -PH_BADVLID;
1848
1849        ph_build_from(from, sizeof(from), vl);
1850
1851
1852        if ( !nonempty(uri))
1853                return -PH_BADARG;
1854
1855
1856        eXosip_lock();
1857        if (use_proxy)
1858                i = eXosip_subscribe_build_initial_request(&msg, uri, from, vl->proxy, ph_get_event_type_str(winfo), expire);
1859        else
1860                i = eXosip_subscribe_build_initial_request(&msg, uri, from, uri, ph_get_event_type_str(winfo), expire);
1861
1862        if (!i)
1863        {
1864                if (data)
1865                {               
1866                        osip_header_t *data_header;
1867
1868                        osip_header_init(&data_header);
1869                        osip_header_set_name(data_header, osip_strdup("X-Addressbook"));
1870                        osip_header_set_value(data_header, osip_strdup(data));
1871                        osip_list_add(&msg->headers, data_header, 0);
1872                }
1873                ph_apply_customizations(msg, NULL, NULL);
1874                i = eXosip_subscribe_send_initial_request(msg);
1875        }
1876        eXosip_unlock();
1877        return i;
1878}
1879
1880
1881PHAPI_EXPORT int
1882phLineUnsubscribe(int sid, int winfo)
1883{
1884        int i = 0;
1885        osip_message_t *sub;
1886
1887        if (!phIsInitialized)
1888                return -PH_NOTINIT;
1889
1890        eXosip_lock();
1891        if ((i = eXosip_subscribe_build_refresh_request(sid,&sub)) < 0) {
1892                eXosip_unlock();
1893                return i;
1894        }
1895        osip_message_set_expires(sub, osip_strdup("0"));
1896        osip_message_set_header(sub, "Event", ph_get_event_type_str(winfo));
1897        ph_apply_customizations(sub, NULL, NULL);
1898        if ((i = eXosip_subscribe_send_refresh_request(sid,sub)) < 0) {
1899                eXosip_unlock();
1900                return i;
1901        }
1902        eXosip_unlock();
1903        return 0;
1904}
1905
1906
1907PHAPI_EXPORT int
1908phSubscribe(const char *from, const char *to, const int winfo)
1909{
1910        int sid;
1911        osip_message_t *msg;
1912
1913        if (!phIsInitialized)
1914                return -PH_NOTINIT;
1915
1916        if (!nonempty(to) || !nonempty(from))
1917                return -PH_BADARG;
1918
1919        eXosip_lock();
1920        sid = eXosip_subscribe_build_initial_request(&msg, to, from, ph_get_proxy(from), ph_get_event_type_str(winfo), 600);
1921        if (!sid) {
1922                ph_apply_customizations(msg, NULL, NULL);
1923                sid = eXosip_subscribe_send_initial_request(msg);
1924        }
1925        eXosip_unlock();
1926        return sid;
1927}
1928
1929
1930
1931PHAPI_EXPORT int
1932phLinePublish(int vlid, const char *uri, int winfo, const char * content_type, const char * content)
1933{
1934        return phLinePublish2(vlid, uri, ph_get_event_type_str(winfo), content_type, content, 600);
1935}
1936
1937
1938
1939PHAPI_EXPORT int
1940phLinePublish2(int vlid, const char *uri, const char *evt, const char *ctt, const char *body, int expires)
1941{
1942        int i;
1943        struct vline *vl;
1944        char from[512];
1945        char expstr[16];
1946        osip_message_t *publish;
1947
1948        if (!phIsInitialized)
1949                return -PH_NOTINIT;
1950
1951        if ( !nonempty(uri))
1952                return -PH_BADARG;
1953
1954        vl = ph_valid_vlid(vlid);
1955
1956        if (!vl)
1957                return -PH_BADVLID;
1958
1959        ph_build_from(from, sizeof(from), vl);
1960
1961        snprintf(expstr, sizeof(expstr), "%d", expires);
1962
1963        eXosip_lock();
1964        i = eXosip_build_publish(&publish,  uri, from,  vl->proxy, evt, expstr, ctt, body);
1965        if (!i) {
1966                ph_apply_customizations(publish, NULL, NULL);
1967                i = eXosip_publish(publish, uri);
1968        }
1969        eXosip_unlock();
1970
1971
1972        if (i)
1973                return -PH_ERROR;
1974
1975        return i;
1976}
1977
1978
1979
1980
1981static const char  *ph_get_expires_str()
1982{
1983        // FIXME:
1984        return "1200";
1985} 
1986
1987PHAPI_EXPORT int
1988phPublish(const char *from, const char *to, const int winfo, const char * content_type, const char * content)
1989{
1990        int i;
1991        osip_message_t *msg;
1992
1993        if (!phIsInitialized)
1994                return -PH_NOTINIT;
1995
1996        if (!nonempty(to) || !nonempty(from) || !nonempty(content_type) || !nonempty(content))
1997                return -PH_BADARG;
1998
1999
2000        eXosip_lock();
2001        i = eXosip_build_publish(&msg, to, from, ph_get_proxy(from), ph_get_event_type_str(winfo), ph_get_expires_str(), content_type, content);
2002        if (!i) {
2003                ph_apply_customizations(msg, NULL, NULL);
2004                i = eXosip_publish(msg, to);
2005        }
2006
2007        eXosip_unlock();
2008        return i;
2009}
2010
2011extern void eXosip_update();
2012
2013PHAPI_EXPORT void
2014phRefresh()
2015{
2016        if (!phIsInitialized)
2017                return;
2018        eXosip_lock();
2019        eXosip_update();
2020        eXosip_unlock();
2021}
2022
2023
2024PHAPI_EXPORT int
2025phLineSendOptions(int vlid, const char *to)
2026{
2027        int i;
2028        struct vline *vl;
2029        char from[512];
2030        osip_message_t *msg;
2031
2032        if (!phIsInitialized)
2033                return -PH_NOTINIT;
2034
2035        vl = ph_valid_vlid(vlid);
2036
2037        if (!vl)
2038                return -PH_BADVLID;
2039
2040        ph_build_from(from, sizeof(from), vl);
2041
2042
2043        if (!nonempty(to))
2044                return -PH_BADARG;
2045
2046
2047        eXosip_lock();
2048        i = eXosip_options_build_request(&msg, to, from, vl->proxy);
2049        if (!i) {
2050                ph_apply_customizations(msg, NULL, NULL);
2051                i = eXosip_options_send_request(msg);
2052        }
2053
2054        eXosip_unlock();
2055
2056        if (i && (msg!=0))
2057                osip_message_free(msg);
2058
2059        return i ? PH_ERROR : i;
2060
2061}
2062
2063
2064
2065PHAPI_EXPORT int
2066phSendOptions(const char *from, const char *uri)
2067{
2068        int i;
2069        osip_message_t *req = 0;
2070
2071        if (!phIsInitialized)
2072                return -PH_NOTINIT;
2073
2074        if (!nonempty(from) || !nonempty(uri))
2075                return -PH_BADARG;
2076
2077        eXosip_lock();
2078        i = eXosip_options_build_request(&req, (char *)uri, (char*) from, ph_get_proxy(from));
2079        if (!i) {
2080                ph_apply_customizations(req, NULL, NULL);
2081                i = eXosip_options_send_request(req);
2082        }
2083        eXosip_unlock();
2084
2085        if (i && (req!=0))
2086                osip_message_free(req);
2087
2088
2089        return i ? PH_ERROR : i;
2090}
2091
2092
2093PHAPI_EXPORT int
2094phAcceptCall2(int cid, void *userData)
2095{
2096        return phAcceptCall3(cid, userData, PH_STREAM_AUDIO);
2097}
2098
2099PHAPI_EXPORT int
2100phAcceptCall3(int cid, void *userData, int streams)
2101{
2102        return phAcceptCall4(cid, userData, streams, 0, 0);
2103}
2104
2105
2106static int 
2107ph_answer_call(int cid, int tid, int status, const char *laport, const char *ctct,
2108                const char *lvport, const char  *paport, const char *pvport,
2109                const char *audio_addr, const char *video_addr, const char *uri)
2110{
2111        int i;
2112        osip_message_t *msg = 0;
2113
2114        phcall_t *ca = ph_locate_call_by_cid(cid);
2115
2116        if (!ca)
2117                return -PH_BADCID;
2118
2119        i = eXosip_call_build_answer(tid, status, &msg);
2120        if (!i) {
2121                if (ctct)
2122                        osip_message_set_contact(msg, ctct);
2123
2124                i = eXosip_call_send_answer(tid, status, msg);
2125        }
2126
2127        return i;
2128}
2129
2130
2131PHAPI_EXPORT int
2132phAcceptCall4(int cid, void *userData, int streams, const char *audio_addr, const char *video_addr)
2133{
2134        int i;
2135        phcall_t *ca;
2136        char  local_video_port[16] = "0";
2137        char  local_voice_port[16] = "0";
2138
2139        phCallStateInfo_t info;
2140        osip_message_t *msg = 0;
2141        struct vline *vl;
2142        char local_ip[16];
2143        char *remoteUri = 0;
2144
2145        DBG_SIP_NEGO("SIP NEGO: phAcceptCall4\n");
2146
2147        if (!phIsInitialized)
2148                return -PH_NOTINIT;
2149
2150        ca = ph_locate_call_by_cid(cid);
2151
2152        if (!ca)
2153                return -PH_BADCID;
2154
2155        vl = ph_valid_vlid(ca->vlid);
2156
2157        if (!vl)
2158                return -PH_BADVLID;
2159
2160        if (audio_addr == NULL)
2161        {
2162                if (phcfg.local_ip_addr[0] == 0)
2163                {
2164                        eXosip_guess_localip(AF_INET, local_ip, 16);
2165                }
2166                else
2167                {
2168                        osip_strncpy(local_ip, phcfg.local_ip_addr, sizeof(local_ip)-1);
2169                }
2170        }
2171        else
2172                osip_strncpy(local_ip, audio_addr, sizeof(local_ip)-1);
2173
2174        ca->user_mflags = streams; // trace of what the user decided
2175        ca->nego_mflags = ca->user_mflags; // current negociated media flags
2176        ca->state = PH_CALLEE_ACCEPTED;
2177
2178        //listening ports are already set by allocatePorts
2179        if (_is_video_enabled(streams))
2180        {
2181                _get_local_video_sdp_port(local_video_port);
2182                ca->loc_sdp_video_port = atoi(local_video_port);
2183                ca->loc_sdp_video_rtcp_port = ca->loc_sdp_video_port + 1;
2184        }
2185
2186        if (_is_audio_enabled(streams))
2187        {
2188                _get_local_audio_sdp_port(local_voice_port);
2189                ca->loc_sdp_audio_port = atoi(local_voice_port);
2190                ca->loc_sdp_audio_rtcp_port = ca->loc_sdp_audio_port + 1;
2191        }
2192
2193
2194        eXosip_lock();
2195        ph_retrieve_from(ca->did, &remoteUri);
2196        eXosip_unlock();
2197
2198        if (streams == PH_STREAM_DATA)
2199        {
2200                eXosip_lock();
2201                i = ph_answer_call(ca->cid, ca->tid, 200, 0, 0, 0, 0, 0, 0, 0, 0);
2202        }
2203        else
2204        {
2205                eXosip_lock();
2206
2207                i = eXosip_call_build_answer(ca->tid, 200, &msg);
2208                if (i < 0)
2209                {
2210                        eXosip_unlock();
2211                        return -1;
2212                }
2213
2214                if (!ca->sdpctx) {
2215                        ph_prepare_stream_ports(ca);
2216                        ca->sdpctx = sdp_handler_create_context(&ph_sdp_handler, local_ip, vl->nrusername, 0);
2217                        ca->cfg =  &phcfg;
2218                        sdp_context_set_user_pointer(ca->sdpctx, ca);
2219                        ca->sdpctx->offer = ca->remote_sdp;
2220                }
2221                if (sdp_context_build_answer(ca->sdpctx, ca->remote_sdp, phcfg.ptime) == NULL)
2222                {
2223                        eXosip_call_send_answer(ca->tid, 606, NULL); //error, no matching payload
2224                        eXosip_unlock();
2225                        return -1;
2226                }
2227
2228                ca->local_sdp = ca->sdpctx->answer;
2229                ph_req_set_body(msg, ca->sdpctx->answerstr, "application/sdp");
2230                i = eXosip_call_send_answer(ca->tid, 200, msg);
2231        }
2232
2233        if (i == 0 && streams != PH_STREAM_DATA)
2234        {
2235                i = ph_call_retrieve_payloads(ca, streams | PH_STREAM_CNG );
2236        }
2237
2238        eXosip_unlock();
2239
2240        if (!i && streams != PH_STREAM_DATA)
2241                i = ph_call_media_start(ca, NULL, streams, 0);
2242
2243        if (i)
2244                return i;
2245
2246        clear(info);
2247
2248        info.remoteUri = remoteUri;
2249        info.event = phCALLOK;
2250        phcb->callProgress(cid, &info);
2251
2252        if (remoteUri)
2253                osip_free(remoteUri);
2254
2255        return 0;
2256}
2257
2258PHAPI_EXPORT int
2259phAcceptMcCall(int cid, const char *adev_in, const char *adev_out, const char *audioaddr, int port)
2260{
2261        phcall_t *ca;
2262        char  local_voice_port[16] = "0";
2263        int streams = PH_STREAM_AUDIO;
2264        phCallStateInfo_t info;
2265        int i;
2266        char *remoteUri;
2267
2268        if (!phIsInitialized)
2269                return -PH_NOTINIT;
2270
2271        ca = ph_locate_call_by_cid(cid);
2272
2273        if (!ca)
2274                return -PH_BADCID;
2275
2276        snprintf(local_voice_port,16, "%d", port);
2277        eXosip_lock();
2278
2279        i = ph_answer_call(ca->cid, ca->did, 200, local_voice_port, ph_get_call_contact(ca),
2280                        NULL,NULL,NULL,
2281                        audioaddr, NULL, 0);
2282
2283        if (i == 0)
2284        {
2285                char tmp[16];
2286
2287                i = ph_call_retrieve_payloads(ca, streams);
2288
2289                _get_local_audio_sdp_port(tmp);
2290                ca->loc_sdp_audio_port = atoi(tmp);
2291                ca->remote_sdp_audio_port = port;
2292                osip_strncpy(ca->remote_sdp_audio_ip, audioaddr, sizeof(ca->remote_sdp_audio_ip)-1);
2293
2294        }
2295
2296        eXosip_unlock();
2297
2298        if (adev_in)
2299        {
2300                if (ca->audiodev_in) 
2301                        osip_free(ca->audiodev_in);
2302                ca->audiodev_in = osip_strdup(adev_in);
2303        }
2304       
2305        if (adev_out)
2306        {
2307                if (ca->audiodev_out) 
2308                        osip_free(ca->audiodev_out);
2309                ca->audiodev_out = osip_strdup(adev_out);
2310        }
2311
2312        ph_call_media_start(ca, NULL, streams|PH_STREAM_MCSEND, 0);
2313
2314        eXosip_lock();
2315        ph_retrieve_from(ca->did, &remoteUri);
2316        eXosip_unlock();
2317
2318        clear(info);
2319
2320        info.remoteUri = remoteUri;
2321        info.event = phCALLOK;
2322        phcb->callProgress(cid, &info);
2323
2324        if (remoteUri)
2325                osip_free(remoteUri);
2326
2327        return 0;
2328}
2329
2330PHAPI_EXPORT int
2331phAcceptMcCall2(int cid, int mcid)
2332{
2333        phcall_t *ca;
2334        phcall_t *mca;
2335        char  local_voice_port[16] = "0";
2336        int streams = PH_STREAM_AUDIO;
2337        phCallStateInfo_t info;
2338        int i;
2339        char *remoteUri;
2340
2341        if (!phIsInitialized)
2342                return -PH_NOTINIT;
2343
2344        ca = ph_locate_call_by_cid(cid);
2345        mca = ph_locate_call_by_cid(mcid);
2346
2347        if (!ca || !mca)
2348                return -PH_BADCID;
2349
2350        i = ph_call_retrieve_payloads(ca, streams);
2351
2352        ca->loc_sdp_audio_port = mca->loc_sdp_audio_port;
2353        ca->remote_sdp_audio_port =  mca->remote_sdp_audio_port;
2354        osip_strncpy(ca->remote_sdp_audio_ip, mca->remote_sdp_audio_ip, sizeof(ca->remote_sdp_audio_ip)-1);
2355        if (mca->audiodev_in)
2356                ca->audiodev_in = osip_strdup(mca->audiodev_in);
2357        if (mca->audiodev_out)
2358                ca->audiodev_out = osip_strdup(mca->audiodev_out);
2359
2360
2361        ph_msession_use(mca->mses);
2362        ca->mses = mca->mses;
2363
2364        ca->user_mflags = mca->user_mflags;
2365        ca->nego_mflags = mca->nego_mflags;
2366
2367        snprintf(local_voice_port,16, "%d", ca->remote_sdp_audio_port);
2368
2369
2370
2371        eXosip_lock();
2372        i = ph_answer_call(ca->cid, ca->did, 200, local_voice_port, ph_get_call_contact(ca),
2373                        NULL,NULL,NULL,
2374                        ca->remote_sdp_audio_ip, NULL, NULL);
2375
2376        ph_retrieve_from(ca->did, &remoteUri);
2377
2378        eXosip_unlock();
2379
2380
2381
2382        clear(info);
2383
2384        info.remoteUri = remoteUri;
2385        info.event = phCALLOK;
2386        phcb->callProgress(cid, &info);
2387
2388        if (remoteUri)
2389                osip_free(remoteUri);
2390
2391        return 0;
2392}
2393
2394
2395static void 
2396add_contact_param(struct vline *vl,  const char *param, const char *value, int inside)
2397{
2398        osip_contact_t *ctct;
2399
2400
2401        if (!vl->contact)
2402                return;
2403
2404        osip_contact_init(&ctct);
2405
2406        osip_contact_parse(ctct, vl->contact);
2407        if (inside)
2408                osip_uri_param_add(&ctct->url->url_params, osip_strdup(param), osip_strdup(value));
2409        else
2410                osip_contact_param_add(ctct, osip_strdup(param), osip_strdup(value));
2411
2412        osip_free(vl->contact);
2413        osip_contact_to_str(ctct, &vl->contact);
2414        osip_contact_free(ctct);
2415}
2416
2417
2418PHAPI_EXPORT int
2419phLineGetMobility(int vlid)
2420{
2421        struct vline *vl;
2422
2423        if (!phIsInitialized)
2424                return -PH_NOTINIT;
2425
2426        vl = ph_valid_vlid(vlid);
2427
2428        if (!vl)
2429                return -PH_BADVLID;
2430
2431        return vl->mobility;
2432
2433}
2434
2435PHAPI_EXPORT int
2436phLineSetUsername2(int vlid, const char* username)
2437{
2438        struct vline *vl;
2439
2440        if (!phIsInitialized)
2441                return -PH_NOTINIT;
2442
2443        vl = ph_valid_vlid(vlid);
2444
2445        if (!vl)
2446                return -PH_BADVLID;
2447
2448        osip_free(vl->nrusername);
2449        vl->nrusername = osip_strdup(username);
2450
2451        return 0;
2452}
2453
2454
2455
2456/*
2457  find and return a  stream of the given type in the 'streams'.
2458  if the stream is not found allocate a new one if there is space                       int j;
2459   in the table
2460  maxtsr specifices the size of the table
2461 */
2462static struct ph_stream_params *
2463ph_find_stream(struct ph_stream_params  **streams, const char *strtype, int maxstrs)
2464{
2465
2466        struct ph_stream_params *si, **strs = streams;
2467
2468        while(si = *strs++)
2469        {
2470                if (!strcmp(si->streamtype, strtype))
2471                        return si;
2472        }
2473
2474        if (!maxstrs)
2475                return 0;
2476
2477        if (strs - streams < (maxstrs - 1))
2478        {
2479                si = calloc(sizeof(*si), 1);
2480                si->streamtype = strdup(strtype);
2481                si->streamport = -1;
2482                strs[-1] = si;
2483                strs[0] = 0;
2484                return si;
2485        }
2486
2487        return 0;
2488}
2489
2490
2491static void 
2492ph_copy_streams_from_args(struct ph_stream_params **streams, va_list args)
2493{
2494        struct ph_stream_params *psi;
2495        int i = 0;
2496
2497        while(0 != (psi = va_arg(args, struct ph_stream_params *))) {
2498                struct ph_stream_params *esi= calloc(sizeof(*psi), 1);
2499                if (!esi)
2500                        return;
2501                streams[i] = esi;
2502                ph_copy_stream(esi, psi);
2503        }
2504
2505        if (i < PH_MAX_STREAMS)
2506                streams[i] = 0;
2507
2508}
2509
2510static int
2511ph_answer_request(int cid, int tid, int reason, const char *ctct)
2512{
2513        int i;
2514
2515        eXosip_lock();
2516        i = ph_answer_call(cid, tid, reason, 0, ctct, 0, 0, 0, 0, 0, 0);
2517        eXosip_unlock();
2518
2519        return i;
2520}
2521
2522
2523PHAPI_EXPORT int
2524phRejectCall(int cid, int reason)
2525{
2526        phcall_t *ca;
2527
2528        if (!phIsInitialized)
2529                return -PH_NOTINIT;
2530
2531        ca = ph_locate_call_by_cid(cid);
2532
2533        if (!ca)
2534                return -PH_BADCID;
2535
2536        return phRejectCall2(cid, ph_get_call_contact(ca), reason);
2537
2538}
2539
2540PHAPI_EXPORT int
2541phRejectCall2(int cid, const char *uri,int reason)
2542{
2543        int i;
2544        phcall_t *ca;
2545        phCallStateInfo_t info;
2546
2547        if (!phIsInitialized)
2548                return -PH_NOTINIT;
2549
2550        ca = ph_locate_call_by_cid(cid);
2551
2552        if (!ca)
2553                return -PH_BADCID;
2554
2555        if(!reason)
2556                reason = 302;
2557
2558        i = ph_answer_request(ca->cid, ca->tid, reason, uri);
2559
2560        ph_release_call(ca);
2561
2562        clear(info);
2563        info.event = phCALLCLOSED;
2564        phcb->callProgress(cid, &info);
2565
2566
2567        return i;
2568}
2569
2570
2571PHAPI_EXPORT int
2572phRingingCall(int cid)
2573{
2574        int i;
2575        osip_message_t *msg = 0;
2576        phcall_t *ca;
2577
2578        if (!phIsInitialized)
2579                return -PH_NOTINIT;
2580
2581        ca = ph_locate_call_by_cid(cid);
2582
2583        if (!ca)
2584                return -PH_BADCID;
2585
2586        eXosip_lock();
2587        i = eXosip_call_build_answer(ca->tid, 180, &msg);
2588        if (i < 0)
2589
2590
2591        {
2592                eXosip_unlock();
2593                return -1;
2594        }
2595
2596
2597        i = eXosip_call_send_answer(ca->tid, 180, msg);
2598        eXosip_unlock();
2599        return i;
2600}
2601
2602
2603
2604PHAPI_EXPORT int
2605phCloseCall(int cid)
2606{
2607        int i;
2608        phcall_t *ca;
2609        phCallStateInfo_t info;
2610        int did;
2611
2612        DBG_SIP_NEGO("phCloseCall %d\n", cid);
2613
2614        if (!phIsInitialized)
2615                return -PH_NOTINIT;
2616
2617        if (cid < 0)
2618                return -PH_BADCID;
2619
2620        eXosip_lock();
2621        ca = ph_locate_call_by_cid(cid);
2622
2623        if (!ca)
2624        {
2625                eXosip_unlock();
2626                return -PH_BADCID;
2627        }
2628
2629        clear(info);
2630        info.event = phCALLCLOSED;
2631
2632        if (ca->isringing)
2633        {
2634                info.event = phCALLCLOSEDandSTOPRING;
2635                ca->isringing = 0;
2636        }
2637
2638
2639        info.vlid = ca->vlid;
2640        did = ca->did;
2641
2642
2643        i = eXosip_call_terminate(cid, did);
2644
2645
2646        ph_release_call(ca);
2647
2648        eXosip_unlock();
2649
2650        if (i)
2651                return i;
2652
2653        info.userData = 0;
2654
2655        info.errorCode = 0;
2656        phcb->callProgress(cid, &info);
2657
2658        return i;
2659
2660}
2661
2662
2663PHAPI_EXPORT int phCallStartMedia(int cid, int streamFlags)
2664{
2665        phcall_t *ca;
2666
2667        if (!phIsInitialized)
2668                return -PH_NOTINIT;
2669
2670        ca = ph_locate_call_by_cid(cid);
2671
2672        if (!ca)
2673                return -PH_BADCID;
2674
2675
2676        ca->user_mflags &= ~(PH_NOMEDIA_STREAMS|PH_STREAM_AUDIO|PH_STREAM_VIDEO_TX|PH_STREAM_VIDEO_RX);
2677        ca->user_mflags |= streamFlags;
2678        ca->nego_mflags = ca->user_mflags;
2679
2680        return ph_call_media_start(ca, 0, 0, 0);
2681
2682}
2683
2684PHAPI_EXPORT int
2685phTransferCall(int cid, int tcid)
2686{
2687        phcall_t *ca;
2688        phcall_t *txca;
2689        char uri[512];
2690        osip_message_t *refer = 0;
2691        int i;
2692
2693        if (!phIsInitialized)
2694                return -PH_NOTINIT;
2695
2696        ca = ph_locate_call_by_cid(cid);
2697        txca = ph_locate_call_by_cid(tcid);
2698
2699        if (!ca || !txca)
2700                return -PH_BADCID;
2701
2702
2703        eXosip_lock();
2704        i = eXosip_call_get_referto(tcid, uri, sizeof(uri));
2705        if (i) goto err;
2706        i = eXosip_call_build_refer(ca->did, uri, &refer);
2707        if (i) goto err;
2708        ph_apply_customizations(refer, NULL, NULL);
2709        i = eXosip_call_send_request(ca->did, refer);
2710        refer = 0;
2711        if (i)  goto err;
2712
2713        ca->localrefer = 1;
2714        ca->txcid = tcid;
2715
2716
2717        eXosip_unlock();
2718
2719
2720        return 0;
2721
2722        err:
2723        eXosip_unlock();
2724
2725        if (refer)
2726                osip_message_free(refer);
2727
2728        if (i == OSIP_NOMEM)
2729                return -PH_NORESOURCES;
2730
2731        return -PH_ERROR;
2732
2733}
2734
2735
2736PHAPI_EXPORT  int
2737phSetContact(int vlid, const char *uri)
2738{
2739        return phSetContact2(vlid, uri, 1);
2740}
2741
2742PHAPI_EXPORT  int
2743phSetContact2(int vlid, const char *uri, int translate)
2744{
2745        struct vline *vl;
2746
2747        if (!phIsInitialized)
2748                return -PH_NOTINIT;
2749
2750        if (!vlid)
2751        {
2752                /* set contact for all VL */
2753                osip_strncpy(vcontact, uri, sizeof(vcontact)-1);
2754                return 0;
2755        }
2756
2757        vl = ph_valid_vlid(vlid);
2758
2759        if (!vl)
2760                return -PH_BADVLID;
2761
2762        if (vl->contact)
2763                osip_free(vl->contact);
2764
2765#if OLDOSIP
2766        if (translate)
2767        {
2768                char contact[256];
2769                eXosip_guess_contact_uri(uri, contact, sizeof(contact), 1);
2770                vl->contact = osip_strdup(contact);
2771        }
2772        else
2773#endif
2774                vl->contact = osip_strdup(uri);
2775        return 0;
2776
2777}
2778
2779
2780
2781PHAPI_EXPORT int
2782phConf(int cid1, int cid2)
2783{
2784        phcall_t *ca1;
2785        phcall_t *ca2;
2786
2787        if (!phIsInitialized)
2788                return -PH_NOTINIT;
2789
2790        ca1 = ph_locate_call_by_cid(cid1);
2791        ca2 = ph_locate_call_by_cid(cid2);
2792
2793        if(!ca1 || !ca2)
2794                return -PH_BADCFID;
2795
2796        if (0 > ph_msession_conf_start(ca1->mses, ca2->mses, ca1->audiodev_in, ca1->audiodev_out))
2797                return -PH_NORESOURCES;
2798        else
2799                return 0;
2800}
2801
2802PHAPI_EXPORT int
2803phStopConf(int cid1, int cid2)
2804{
2805        phcall_t *ca1;
2806        phcall_t *ca2;
2807
2808        if (!phIsInitialized)
2809                return -PH_NOTINIT;
2810
2811        ca1 = ph_locate_call_by_cid(cid1);
2812        ca2 = ph_locate_call_by_cid(cid2);
2813
2814        if(!ca1 || !ca2)
2815                return -PH_BADCFID;
2816
2817        if( 0 > ph_msession_conf_stop(ca1->mses, ca2->mses))
2818                return -PH_NORESOURCES;
2819        else
2820                return 0;
2821}
2822
2823#define CONF_MODE 1
2824
2825PHAPI_EXPORT int
2826phSetFollowMe(const char *uri)
2827{
2828        if (!phIsInitialized)
2829                return -PH_NOTINIT;
2830
2831        if (!uri)
2832                ph_follow_me_addr[0] = 0;
2833
2834        if (ph_find_matching_vline(uri, PHM_IGNORE_PORT))
2835                return -PH_REDIRLOOP;
2836
2837        osip_strncpy(ph_follow_me_addr, uri, sizeof(ph_follow_me_addr)-1);
2838        return 0;
2839
2840
2841}
2842
2843
2844PHAPI_EXPORT int
2845phSetBusy(int busyFlag)
2846{
2847        ph_busyFlag = busyFlag;
2848        return 0;
2849}
2850
2851
2852PHAPI_EXPORT int
2853phLineSetFollowMe(int vlid, const char *uri)
2854{
2855        struct vline *vl;
2856
2857        if (!phIsInitialized)
2858                return -PH_NOTINIT;
2859
2860        vl = ph_valid_vlid(vlid);
2861
2862        if (!vl)
2863                return -PH_BADVLID;
2864
2865        if (ph_find_matching_vline(uri, PHM_IGNORE_PORT))
2866                return -PH_REDIRLOOP;
2867
2868        if (vl->followme)
2869                osip_free(vl->followme);
2870
2871        vl->followme = osip_strdup(uri);
2872
2873        return 0;
2874
2875}
2876
2877
2878PHAPI_EXPORT int
2879phBlindTransferCall(int cid, const char *uri)
2880{
2881        int i;
2882        phcall_t *ca;
2883        osip_message_t* refer;
2884
2885        if (!phIsInitialized)
2886                return -PH_NOTINIT;
2887
2888        ca = ph_locate_call_by_cid(cid);
2889
2890        if (!ca)
2891                return -PH_BADCID;
2892
2893        if (!nonempty(uri))
2894                return -PH_BADARG;
2895
2896        if (ph_find_matching_vline(uri, PHM_IGNORE_PORT))
2897                return -PH_REDIRLOOP;
2898
2899
2900        ca->localrefer = 1;
2901        phHoldCall(cid);
2902
2903        eXosip_lock();
2904        i = eXosip_call_build_refer(ca->did, (char *)uri, &refer);
2905        if (!i)
2906                i = eXosip_call_send_request(ca->did, refer);
2907        eXosip_unlock();
2908
2909        return i;
2910
2911}
2912
2913
2914static char *ph_call_fix_media_dir(phcall_t *ca,  const char *dir)
2915{
2916        if (!ca->sdpctx)
2917                return 0;
2918
2919        if (ca->sdpctx->offer) {
2920                sdp_context_update_media_direction(ca->sdpctx, dir, 1);
2921                return ca->sdpctx->offerstr;
2922        }
2923
2924        if (ca->sdpctx->answer) {
2925                sdp_context_update_media_direction(ca->sdpctx, dir, 0);
2926                return ca->sdpctx->answerstr;
2927        }
2928
2929        return 0;
2930
2931}
2932
2933int _ph_send_reinvite(int cid)
2934{
2935        int i;
2936        osip_message_t *reinvite;
2937        phcall_t *ca;
2938               
2939        if (!phIsInitialized)
2940                return -PH_NOTINIT;
2941                                               
2942        ca = ph_locate_call_by_cid(cid);
2943                                                       
2944        if (!ca)
2945                return -PH_BADCID;
2946       
2947        eXosip_lock();
2948        if (eXosip_call_build_request(ca->did, "INVITE", &reinvite)) {
2949                eXosip_unlock();
2950                return -1;
2951        }
2952        eXosip_unlock();
2953
2954        osip_message_set_subject(reinvite, "Call reinvite");
2955        osip_message_set_allow(reinvite, "INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY, MESSAGE, SUBSCRIBE, INFO");
2956               
2957        sdp_context_build_offer(ca->sdpctx);
2958
2959        ph_set_media_direction(ca->sdpctx->offer, "audio", ph_get_local_media_direction(ca, "audio"));
2960        ph_set_media_direction(ca->sdpctx->offer, "video", ph_get_local_media_direction(ca, "video"));
2961
2962        sdp_message_to_str(ca->sdpctx->offer, &ca->sdpctx->offerstr);
2963
2964        ca->local_sdp = ca->sdpctx->offer;
2965        ca->remote_sdp = 0; // force ph_call_media_start on ph_call_answered
2966        ph_req_set_body(reinvite, ca->sdpctx->offerstr, "application/sdp");
2967
2968        eXosip_lock();
2969        i = eXosip_call_send_request(ca->did, reinvite);
2970        eXosip_unlock();
2971
2972        osip_mutex_lock(ph_media_stop_mutex);
2973        ph_call_media_stop(ca);
2974        osip_mutex_unlock(ph_media_stop_mutex);
2975
2976        return i;
2977}                                                                                       
2978
2979PHAPI_EXPORT int
2980phResumeCall(int cid)
2981{
2982        phcall_t *ca;
2983
2984        if (!phIsInitialized)
2985                return -PH_NOTINIT;
2986
2987        ca = ph_locate_call_by_cid(cid);
2988
2989        if (!ca)
2990                return -PH_BADCID;
2991
2992        ca->nego_mflags |= PH_STREAM_AUDIO_RX;
2993        ca->nego_mflags |= PH_STREAM_VIDEO_RX;
2994       
2995        ca->localhold = 0;     
2996        ca->localresume = 1;
2997               
2998        return _ph_send_reinvite(cid);
2999}
3000
3001PHAPI_EXPORT int
3002phHoldCall(int cid)
3003{
3004        phcall_t *ca;
3005
3006        if (!phIsInitialized)
3007                return -PH_NOTINIT;
3008
3009        ca = ph_locate_call_by_cid(cid);
3010
3011        if (!ca)
3012                return -PH_BADCID;
3013
3014        ca->nego_mflags &= ~PH_STREAM_AUDIO_RX;
3015        ca->nego_mflags &= ~PH_STREAM_VIDEO_RX;
3016       
3017        ca->localresume = 0;
3018        ca->localhold = 1;
3019                                                                                                               
3020        return _ph_send_reinvite(cid);
3021}
3022
3023
3024PHAPI_EXPORT int
3025phLineSetBusy(int vlid, int busyFlag)
3026{
3027        struct vline *vl;
3028
3029        if (!phIsInitialized)
3030                return -PH_NOTINIT;
3031
3032        vl = ph_valid_vlid(vlid);
3033
3034        if (!vl)
3035                return -PH_BADVLID;
3036
3037        vl->busy = busyFlag;
3038        return 0;
3039}
3040
3041PHAPI_EXPORT int
3042phAddAuthInfo(const char *username, const char *userid,
3043                const char *passwd, const char *ha1,
3044                const char *realm)
3045{
3046        int ret;
3047
3048        DBG_SIP_EVENT("Add auth info username %s userid %s passwd %s realm %s ha1 %s\n",
3049                username, userid, passwd, realm, ha1);
3050
3051        if (!phIsInitialized)
3052                return -PH_NOTINIT;
3053
3054        if (!username)
3055                return -PH_BADARG;
3056
3057        if (!userid)
3058                return -PH_BADARG;
3059
3060        if (!passwd)
3061                return -PH_BADARG;
3062
3063        eXosip_lock();
3064
3065        ret = eXosip_add_authentication_info(username, userid, passwd, ha1, realm);
3066
3067        eXosip_unlock();
3068
3069        return ret;
3070}
3071
3072static void ph_fix_reg_contact(struct vline* vl, char **rcontact)
3073{
3074        osip_contact_t* ctct = 0;
3075        char regid[16];
3076        int fixit = (PH_USE_RFC5626 == (vl->mobility & PH_USE_RFC5626));
3077
3078        *rcontact = vl->contact;
3079
3080        if (!fixit)
3081                return;
3082
3083
3084
3085        if (osip_contact_init(&ctct))
3086                return;
3087
3088        if (osip_contact_parse(ctct, vl->contact))
3089                goto err;
3090
3091        snprintf(regid, 16, "%d", ph_vline2vlid(vl) );
3092        if (osip_contact_param_add(ctct, osip_strdup("reg-id"), osip_strdup(regid)))
3093                goto err;
3094
3095        if (osip_contact_param_add(ctct, osip_strdup("+sip.instance"), osip_strdup(phcfg.sip_id)))
3096                goto err;
3097
3098        osip_contact_to_str(ctct, rcontact);
3099
3100err:
3101        osip_contact_free(ctct);
3102}
3103
3104PHAPI_EXPORT int
3105phvlRegister(int vlid)
3106{
3107        struct vline *vl;
3108        int ret = -1;
3109        char utmp[256];
3110        char stmp[256];
3111        char *server;
3112        osip_message_t *msg=0;
3113
3114        if (!phIsInitialized)
3115                return -PH_NOTINIT;
3116
3117        vl = ph_vlid2vline(vlid);
3118
3119        assert(vl!=NULL);
3120        assert(vl->rusername!=NULL);
3121        assert(vl->server!=NULL);
3122
3123        if (vl->displayname)
3124                snprintf(utmp, sizeof(utmp), "\"%s\" <sip:%s@%s>", vl->displayname, vl->rusername, vl->server);
3125        else
3126                snprintf(utmp, sizeof(utmp), "sip:%s@%s", vl->rusername, vl->server);
3127
3128        server = stmp;
3129        if (vl->port && vl->port != 5060)
3130        {
3131                /*     snprintf(stmp, sizeof(stmp), "sip:%s@%s:%d", vl->rusername, vl->server, vl->port); */
3132                snprintf(stmp, sizeof(stmp), "sip:%s:%d", vl->server, vl->port);
3133        }
3134        else
3135        {
3136                /*     snprintf(stmp, sizeof(stmp), "sip:%s@%s:%d", vl->rusername, vl->server, vl->port); */
3137                snprintf(stmp, sizeof(stmp), "sip:%s", vl->server);
3138        }
3139
3140        eXosip_lock();
3141
3142        if (vl->rid > 0) {
3143                ret = eXosip_register_build_register(vl->rid, vl->regTimeout, &msg);
3144                if (ret)
3145                        vl->rid = -2;
3146        }  else {
3147#if 1
3148                char *rcontact;
3149
3150                ph_fix_reg_contact(vl, &rcontact);
3151
3152                vl->rid = eXosip_register_build_initial_register(utmp, server, rcontact, vl->regTimeout, &msg);
3153                if (vl->proxy)
3154                        osip_message_set_route(msg, vl->proxy);
3155                if (rcontact != vl->contact)
3156                        osip_free(rcontact);
3157        }
3158#else
3159                if (vl->proxy && vl->proxy[0] == '<') {
3160                        int size = strlen(vl->proxy);
3161                        char *proxy = alloca(size-1);
3162                        strncpy(proxy, vl->proxy + 1, size - 2);
3163                        proxy[size-2] = '\0';
3164                        vl->rid = eXosip_register_build_initial_register(utmp, proxy, vl->contact, vl->regTimeout, &msg);
3165                }
3166                else
3167                {
3168                        if (vl->proxy)
3169                                vl->rid = eXosip_register_build_initial_register(utmp, vl->proxy, vl->contact, vl->regTimeout, &msg);
3170                        else
3171                                vl->rid = eXosip_register_build_initial_register(utmp, server, vl->contact, vl->regTimeout, &msg);
3172
3173                }
3174        }
3175#endif
3176
3177        if (vl->rid >= 0)
3178        {
3179                osip_message_set_allow(msg, "INVITE, ACK, BYE, CANCEL, REFER, NOTIFY, SUBSCRIBE, REGISTER, MESSAGE");
3180                ph_apply_customizations(msg, NULL, NULL);
3181                ret = eXosip_register_send_register(vl->rid, msg);
3182                msg = 0;
3183                if (ret == 0)
3184                {
3185                        ret = vl->rid;
3186                        vl->lastRegTime = time(0);
3187                }
3188        }
3189
3190        eXosip_unlock();
3191        if (msg)
3192            osip_message_free(msg);
3193        return ret;
3194
3195}
3196
3197PHAPI_EXPORT int phvlSetRegisterTimeOut(int vlid,int regTimeout)
3198{
3199        struct vline *vl;
3200
3201        if (!phIsInitialized)
3202                return -PH_NOTINIT;
3203
3204        vl = ph_vlid2vline(vlid);
3205
3206        if (vl) {
3207                vl->regTimeout = regTimeout;
3208                eXosip_register_update_timeout(vl->rid, regTimeout);
3209                return 0;
3210        }
3211        return -1;
3212}
3213
3214PHAPI_EXPORT int
3215phSendDtmf(int cid, int dtmfEvent, int mode)
3216{
3217        phcall_t *ca;
3218        char buf[64];
3219        char *ctt;
3220        int i = -1;
3221        osip_message_t *msg;
3222
3223        if (!phIsInitialized)
3224                return -PH_NOTINIT;
3225
3226        ca = ph_locate_call_by_cid(cid);
3227
3228        if (!ca)
3229                return -PH_BADCID;
3230
3231        if (mode & (PH_DTMF_MODE_SIP|PH_DTMF_MODE_SIPRELAY))
3232        {
3233                if (mode & PH_DTMF_MODE_SIP)
3234                {
3235                        ctt = "application/dtmf";
3236                        snprintf(buf, sizeof(buf), "%c", dtmfEvent);
3237                }
3238                else
3239                {
3240                        char sipEvent[3] = { 0, 0, 0 };
3241                        ctt = "application/dtmf-relay";
3242                        if (dtmfEvent == '!')
3243                        {
3244                                sipEvent[0] = '1';
3245                                sipEvent[1] = '6';
3246                        }
3247                        else
3248                                sipEvent[0] = dtmfEvent;
3249
3250                        snprintf(buf, sizeof(buf), "Signal=%s\r\nDuration=250\r\n", sipEvent);
3251                }
3252
3253                eXosip_lock();
3254
3255                i = eXosip_call_build_info(ca->did, &msg),
3256                                ph_req_set_body(msg, buf, ctt);
3257                osip_message_set_contact(msg, ph_get_call_contact(ca));
3258                ph_apply_customizations(msg, NULL, NULL);
3259                i = eXosip_call_send_request(ca->did, msg);
3260
3261                eXosip_unlock();
3262
3263                if (!(mode & PH_DTMF_MODE_ALLRTP)) /* do we need to send DTMF in RTP stream? */
3264                        return i;
3265
3266        }
3267
3268        if (!ph_call_hasaudio(ca))
3269        {
3270                if (!i)
3271                        return 0;   /*  we've managed to send using SIP INFO request */
3272
3273                return -PH_NOMEDIA;
3274        }
3275
3276        return ph_msession_send_dtmf(ca->mses, dtmfEvent, mode);
3277
3278}
3279
3280
3281PHAPI_EXPORT phStream *
3282phPlaySoundFile(const char *fileName , int loop, const char * deviceid)
3283{
3284        if (!phIsInitialized)
3285                return NULL;
3286
3287        return phms_audio_play_sound_file(fileName,loop,deviceid,phcb->soundFileStopped);
3288}
3289
3290PHAPI_EXPORT int 
3291phSetSoundFileGain( phStream * stream, float gain)
3292{
3293        if (!phIsInitialized)
3294                return -PH_NOTINIT;
3295
3296        return phms_audio_set_sound_file_gain(stream,gain);
3297}
3298
3299PHAPI_EXPORT int
3300phSendSoundFile(int cid, const char *fileName)
3301{
3302        phcall_t *ca;
3303
3304        if (!phIsInitialized)
3305                return -PH_NOTINIT;
3306
3307        ca = ph_locate_call_by_cid(cid);
3308
3309        if (!ca)
3310                return -PH_BADCID;
3311
3312        if (!ph_call_hasaudio(ca))
3313                return -PH_NOMEDIA;
3314
3315        return ph_msession_send_sound_file(ca->mses, fileName);
3316}
3317
3318PHAPI_EXPORT int
3319phStopSoundFile( phStream * stream)
3320{
3321        if (!phIsInitialized)
3322                return -PH_NOTINIT;
3323
3324        return phms_audio_stop_sound_file(stream);
3325}
3326
3327PHAPI_EXPORT int
3328phSetSpeakerVolume(int cid,  int volume)
3329{
3330#if 0
3331        phcall_t *ca = ph_locate_call_by_cid(cid);
3332
3333        if (!ca)
3334                return -PH_BADCID;
3335
3336        return(ph_media_set_spkvol(ca, volume));
3337#else
3338        return 0;
3339#endif
3340}
3341
3342
3343PHAPI_EXPORT int
3344phSetRecLevel(int cid,  int level)
3345{
3346#if 0
3347        phcall_t *ca = ph_locate_call_by_cid(cid);
3348
3349        if (!ca)
3350                return -PH_BADCID;
3351
3352        return(ph_media_set_recvol(ca, level));
3353#else
3354        return 0;
3355#endif
3356}
3357
3358
3359
3360
3361PHAPI_EXPORT int
3362phAddVline(const char* username, const char *server, const char*  proxy,  int regTimeout)
3363{
3364        return phAddVline2(NULL, username, server, proxy,  regTimeout);
3365}
3366
3367/*
3368  scrap the :port part from the host uri
3369 */
3370static const char *
3371ph_scrap_port(char *buf, int bufsize, const char *host, int *port)
3372{
3373
3374        assert(buf != 0);
3375        assert(port != 0);
3376
3377        *port = 0;
3378
3379        if (!host)
3380                return 0;
3381
3382        if (!strchr(host, ':'))
3383                return host;
3384
3385        osip_strncpy(buf, host, bufsize-1);
3386        host = strchr(buf, ':');
3387        if (host)
3388        {
3389                *( char *) host = 0;
3390                *port = atoi(host+1);
3391        }
3392
3393        return buf;
3394
3395}
3396
3397static const char emptystr[] = { 0 };
3398#define nonull(x) ((x) ? (x) : emptystr)
3399
3400PHAPI_EXPORT int
3401phAddVline2(const char *displayname, const char* username, const char *server, const char*  proxy,  int regTimeout)
3402{
3403        return phAddVline3(displayname, username, server, proxy, regTimeout, 0);
3404}
3405PHAPI_EXPORT int
3406phAddVline3(const char *displayname, const char* username, const char *server, const char*  proxy,  int regTimeout, int mobility)
3407
3408{
3409        struct vline *vl;
3410        int oldTimeout = 0;
3411        char srvbuf[256];
3412        const char *srv2;
3413        int port;
3414
3415        DBG_SIP_NEGO("AddVline3(dn = %s, un=%s, srv=%s pxy=%s regT=%d)\n", nonull(displayname), nonull(username), nonull(server),
3416                        nonull(proxy), regTimeout);
3417
3418        if (!phIsInitialized)
3419                return -PH_NOTINIT;
3420
3421        srv2 = ph_scrap_port(srvbuf, sizeof(srvbuf), server, &port);
3422
3423        if (!port)
3424                port = 5060;
3425
3426        if (!username)
3427                username = "";
3428
3429
3430        vl  = ph_find_matching_vline3(username, srv2, port, 0);
3431
3432        if (0 < regTimeout && regTimeout < 100)
3433                regTimeout = 100;
3434
3435        if (!vl)
3436        {
3437                vl = vline_alloc();
3438                if (!vl)
3439                        return -PH_NORESOURCES;
3440
3441                vl->rusername = osip_strdup(username);
3442                vl->nrusername = osip_strdup(username);
3443        }
3444        else
3445        {
3446                if (vl->proxy)
3447                {
3448                        osip_free(vl->proxy);
3449                        vl->proxy = 0;
3450                }
3451
3452                if (vl->displayname)
3453                {
3454                        osip_free(vl->displayname);
3455                        vl->displayname = 0;
3456                }
3457
3458                if (vl->contact)
3459                {
3460                        osip_free(vl->contact);
3461                        vl->contact = 0;
3462                }
3463                oldTimeout = vl->regTimeout;
3464
3465        }
3466
3467        vl->port = port;
3468
3469        if (nonempty(proxy))
3470        {
3471                if (0 == strstr(proxy, "sip:"))
3472                {
3473                        int l = 15 + strlen(proxy);
3474                        vl->proxy = osip_malloc(l);
3475                        snprintf(vl->proxy, l, "sip:%s", proxy);
3476                }
3477                else
3478                        vl->proxy = osip_strdup(proxy);
3479        }
3480
3481
3482
3483        if (nonempty(srv2) && !vl->server)
3484                vl->server = osip_strdup(srv2);
3485
3486        if (nonempty(displayname))
3487                vl->displayname = osip_strdup(displayname);
3488
3489        vl->regTimeout = regTimeout;
3490
3491        if(vcontact[0])
3492                vl->contact = osip_strdup(vcontact);
3493        else
3494        {
3495                char ctct[512];
3496
3497                ph_build_contact(ctct, sizeof(ctct), vl);
3498                vl->contact = osip_strdup(ctct);
3499
3500        }
3501
3502        if (checkmobility(mobility,PH_LINE_MOBILITY_FIXED))
3503                add_contact_param(vl, "mobility", "fixed", FALSE);
3504        else if (checkmobility(mobility, PH_LINE_MOBILITY_MOBILE))
3505                add_contact_param(vl, "mobility", "mobile", FALSE);
3506        else if (checkmobility(mobility,PH_LINE_MOBILITY_PHONE))
3507                add_contact_param(vl, "user", "phone", TRUE);
3508
3509        if ((mobility & PH_USE_RFC5626) == PH_USE_RFC5626) {
3510                eXosip_set_keepalive_hook(ph_generate_rfc5626_probe);
3511                // add_contact_param(vl, "ob", 0, TRUE);
3512        }
3513
3514        vl->mobility = mobility;
3515
3516        if (nonempty(srv2) && (oldTimeout > 0 || regTimeout > 0))
3517                phvlRegister(ph_vline2vlid(vl));
3518
3519        return ph_vline2vlid(vl);
3520}
3521
3522
3523PHAPI_EXPORT int
3524phDelVline(int vlid)
3525{
3526        struct vline *vl;
3527        phcall_t *ca;
3528
3529        if (!phIsInitialized)
3530                return -PH_NOTINIT;
3531
3532        if (!(vl = ph_valid_vlid(vlid)))
3533                return -PH_BADVLID;
3534
3535        /* forbid deletion of the lines which have pending calls */
3536        for(ca = ph_calls; ca < &ph_calls[PH_MAX_CALLS]; ca++)
3537        {
3538                if (ca->vlid == vlid && ca->cid > 0)
3539                        return -PH_VLBUSY;
3540        }
3541
3542
3543        if (vl->pub.timeout)
3544                phLinePublish2(vlid, vl->pub.uri, 0, 0, 0, 0);
3545
3546        /*
3547     if the line has an associatied timeout,
3548     it means it is regsitered on some server,
3549     so we need to unregister
3550         */
3551        if (vl->regTimeout)
3552        {
3553                osip_message_t *msg;
3554
3555                eXosip_lock();
3556                eXosip_register_build_register(vl->rid, 0, &msg);
3557                eXosip_register_send_register(vl->rid, msg);
3558                vl->regTimeout = 0;
3559                vl->used = VL_DELETING;
3560                eXosip_unlock();
3561
3562        }
3563
3564        if (vl->used != VL_DELETING)
3565                return 0;
3566
3567        return 0;
3568}
3569
3570
3571
3572PHAPI_EXPORT int phChangeAudioDeviceIn(const char *devstr)
3573{
3574        if (devstr)
3575                osip_strncpy(phcfg.audio_dev_in, devstr, sizeof(phcfg.audio_dev_in)-1);
3576
3577        return 0;
3578}
3579
3580PHAPI_EXPORT int phChangeAudioDeviceOut(const char *devstr)
3581{
3582        if (devstr)
3583                osip_strncpy(phcfg.audio_dev_out, devstr, sizeof(phcfg.audio_dev_out)-1);
3584       
3585        return 0;
3586}
3587
3588PHAPI_EXPORT int phChangeVideoDevices(const char *devstr)
3589{
3590        if (devstr)
3591                osip_strncpy(phcfg.video_config.video_device, devstr, sizeof(phcfg.video_config.video_device)-1);
3592       
3593        return 0;
3594}
3595
3596static struct vline *
3597vline_alloc()
3598{
3599        int i;
3600
3601        for(i = 0; i < PH_MAX_VLINES; i++)
3602        {
3603                struct vline *vl = ph_vlines + i;
3604
3605                if (!vl->used)
3606                {
3607                        memset(vl, 0, sizeof(*vl));
3608                        vl->used = 1;
3609                        vl->port = 0;
3610                        return vl;
3611                }
3612
3613        }
3614        return 0;
3615}
3616
3617static void
3618vline_free(struct vline *vl)
3619{
3620        if (vl->used)
3621        {
3622                osip_free(vl->rusername);
3623                osip_free(vl->nrusername);
3624                if (vl->server)
3625                        osip_free(vl->server);
3626                if (vl->proxy)
3627                        osip_free(vl->proxy);
3628                if (vl->displayname)
3629                        osip_free(vl->displayname);
3630                if (vl->followme)
3631                        osip_free(vl->followme);
3632                if (vl->contact)
3633                        osip_free(vl->contact);
3634                if (vl->pub.etag)
3635                        osip_free(vl->pub.etag);
3636                if (vl->pub.uri)
3637                        osip_free(vl->pub.uri);
3638                if (vl->pub.evt)
3639                        osip_free(vl->pub.evt);
3640                if (vl->pub.ctt)
3641                        osip_free(vl->pub.ctt);
3642                if (vl->pub.body)
3643                        osip_free(vl->pub.body);
3644
3645
3646                vl->used = 0;
3647        }
3648}
3649
3650static struct vline *
3651ph_find_vline_by_rid(int rid)
3652{
3653        int i;
3654
3655        for(i = 0; i < PH_MAX_VLINES; i++)
3656        {
3657                struct vline *vl = ph_vlines + i;
3658
3659                if (vl->used && rid == vl->rid)
3660                        return vl;
3661        }
3662        return 0;
3663}
3664
3665
3666static osip_from_t *
3667ph_parse_from(const char *userid)
3668{
3669        osip_from_t *from;
3670
3671        osip_from_init(&from);
3672        if (!from)
3673                return 0;
3674
3675        osip_from_parse(from, userid);
3676        if (from->url && from->url->port && !strcmp(from->url->port, "5060"))
3677        {
3678                osip_free(from->url->port);
3679                from->url->port = NULL;
3680        }
3681
3682        return from;
3683
3684}
3685
3686static struct vline *
3687ph_find_matching_vline(const char *userid, int ignore)
3688{
3689        osip_from_t *from;
3690        struct vline *vl;
3691        char *host;
3692        char hostport[256];
3693        char *uname;
3694
3695        hostport[0] = 0;
3696        from = ph_parse_from(userid);
3697
3698        if (!from)
3699                return 0;
3700
3701        if (from->url)
3702                uname = from->url->username;
3703        else
3704                uname = hostport;
3705
3706
3707        if (!(ignore & PHM_IGNORE_PORT) && from->url && from->url->port)
3708        {
3709                snprintf(hostport, sizeof(hostport), "%s:%s", from->url->host, from->url->port);
3710                host = hostport;
3711        }
3712        else if (ignore & PHM_IGNORE_HOST)
3713                host = 0;
3714        else if (from->url)
3715        {
3716                host = from->url->host;
3717        }
3718        else
3719                host = hostport;
3720
3721        vl = ph_find_matching_vline2(uname, host, ignore);
3722
3723        osip_from_free(from);
3724
3725        return vl;
3726
3727}
3728
3729static size_t
3730ph_generate_rfc5626_probe(int rid, const void *addr, int addrlen, char* buf, size_t bsize)
3731{
3732        struct vline*  vl = ph_find_vline_by_rid(rid);
3733        StunMessage req;
3734        int len;
3735
3736        if (!vl || !(vl->mobility & PH_USE_RFC5626))
3737                return 0;
3738
3739        memset(&req, 0, sizeof(StunMessage));
3740        stunBuildReqSimple( &req, 0, 0,0, 1);
3741    len = stunEncodeMessage( &req, buf, bsize, 0 );
3742
3743        return len;
3744
3745}
3746
3747
3748static struct vline *
3749ph_find_matching_vline2(const char *username, const char* host, int ignore)
3750{
3751        return ph_find_matching_vline3(username, host, 0, ignore);
3752}
3753
3754static struct vline *
3755ph_find_matching_vline3(const char *username, const char* host, int port, int ignore)
3756{
3757        int i;
3758        int   hostlen;
3759        int   unamelen;
3760        struct vline *vl, *defaultvl = 0;
3761
3762        if (!username)
3763                username = "";
3764
3765        hostlen = host ? strlen(host) : 0;
3766        unamelen =  strlen(username);
3767
3768        if (port == 0)
3769                port = 5060;
3770
3771        for( i = 0; i < PH_MAX_VLINES; i++)
3772        {
3773                int len;
3774                vl = ph_vlines + i;
3775
3776                if (!vl->used)
3777                        continue;
3778
3779                if (!vl->server)
3780                {
3781                        defaultvl = vl;
3782                        continue;
3783                }
3784
3785                len = strlen(vl->server);
3786
3787                if ((ignore & PHM_IGNORE_HOST) || ((len == hostlen) && !strcasecmp(host, vl->server)))
3788                {
3789                        int nrlen = strlen(vl->nrusername);
3790
3791                        len = strlen(vl->rusername);
3792
3793                        if ((len == unamelen) && !strcasecmp(username, vl->rusername) ||
3794                            (nrlen == unamelen) && !strcasecmp(username, vl->nrusername))
3795                        {
3796                                if (ignore & PHM_IGNORE_PORT)
3797                                {
3798                                        defaultvl = vl;
3799                                        break;
3800                                }
3801                                if (port == vl->port)
3802                                {
3803                                        defaultvl = vl;
3804                                        break;
3805                                }
3806                        }
3807                }
3808        }
3809
3810        return defaultvl;
3811}
3812
3813static void
3814ph_nat_refresh(struct vline *vl)
3815{
3816        char buf[128];
3817        char to[128];
3818        assert(vl!=NULL);
3819
3820        if (!(vl->mobility & PH_USE_RFC5626)) {
3821                ph_build_from(buf, sizeof(buf), vl);
3822                snprintf(to, sizeof(to), "sip:ping@%s", vl->server);
3823                phSendOptions(buf, to);
3824        }
3825
3826#if 0
3827        int port;
3828
3829
3830        osip_uri_init(&uri);
3831        osip_uri_parse(uri,  (vl->proxy && vl->proxy[0]) ? vl->proxy : vl->server);
3832
3833        port = atoi((uri->port && uri->port[0]) ? uri->port : "5060");
3834        phPing(uri->host, port, 30);
3835
3836        osip_uri_free(uri);
3837#endif
3838
3839}
3840
3841static time_t last_vline_refresh, last_nat_refresh;
3842static void
3843ph_refresh_vlines()
3844{
3845        int nat_refresh_time = ( phcfg.transport == IPPROTO_UDP ) ? phcfg.nat_refresh_udp_time : phcfg.nat_refresh_tcp_time;
3846        time_t now = time(NULL);
3847
3848        if (now - last_vline_refresh > 5)
3849        {
3850                int i;
3851                struct vline *vl;
3852
3853                for( i = 0; i < PH_MAX_VLINES; i++)
3854                {
3855                        vl = ph_vlines + i;
3856                        if (!vl->used)
3857                                continue;
3858
3859                        //it's now handled by eXosip_automatic_action() so no more need to do ti manually
3860                        /*if (vl->server && vl->server[0] && vl->regTimeout > 0)
3861                        {
3862                                if ((now - vl->lastRegTime) > (vl->regTimeout - 10))
3863                                        phvlRegister(ph_vline2vlid(vl));
3864                        }*/
3865                        if (vl->pub.timeout && (now - vl->pub.last) > (vl->pub.timeout - ph_resend_offset))
3866                        {
3867                                phLinePublish2(ph_vline2vlid(vl), vl->pub.uri, 0, 0, 0, vl->pub.timeout);
3868                        }
3869                }
3870                last_vline_refresh = time(0);
3871        }
3872
3873        //if (!phcfg.use_tunnel && phcfg.nat_refresh_time > 0)
3874        if (nat_refresh_time > 0)
3875        {
3876                int i;
3877                struct vline *vl;
3878
3879                if (now - last_nat_refresh > nat_refresh_time)
3880                {
3881                        for( i = 0; i < PH_MAX_VLINES; i++)
3882                        {
3883                                vl = ph_vlines + i;
3884                                if (!vl->used)
3885                                        continue;
3886
3887                                if (vl->server && vl->server[0] && vl->regTimeout > ph_resend_offset)
3888                                {
3889                                        ph_nat_refresh(vl);
3890                                }
3891                        }
3892
3893                        last_nat_refresh = time(0);
3894                }
3895        }
3896
3897
3898}
3899
3900
3901/*
3902  scan call marked for close and close them while delivering phCALLCLOSED to phApi client
3903 */
3904static void
3905ph_scan_calls()
3906{
3907        int i;
3908        phcall_t *ca;
3909
3910        ca = ph_calls;
3911        for(i = PH_MAX_CALLS; i; i--, ca++)
3912        {
3913                if (ca->cid > 0 &&
3914                                (ca->closereq ||
3915                                                ((ph_call_hasaudio(ca) || ph_call_hasvideo(ca)) && !ph_call_stream_alive(ca))))
3916                {
3917                        phCallStateInfo_t info;
3918                        int cid = ca->cid;
3919
3920                        clear(info);
3921                        info.vlid = ca->vlid;
3922                        info.event = phCALLCLOSED;
3923
3924                        ph_release_call(ca);
3925
3926                        phcb->callProgress(cid, &info);
3927                }
3928        }
3929
3930}
3931
3932static char *
3933ph_get_proxy(const char *userid)
3934{
3935        struct vline *vl = ph_find_matching_vline(userid, PHM_IGNORE_PORT);
3936
3937        if (!vl)
3938                return "";
3939
3940        return vl->proxy ? vl->proxy : "";
3941}
3942
3943
3944static char *
3945ph_get_call_contact(phcall_t *ca)
3946{
3947        struct vline *vl;
3948        assert(ca!=NULL);
3949
3950        vl = ph_vlid2vline(ca->vlid);
3951        if (!vl)
3952                return 0;
3953
3954        return vl->contact;
3955}
3956
3957
3958static int
3959ph_get_vline_id(const char *userid, const char *altid)
3960{
3961
3962        struct vline *vl = ph_find_matching_vline(userid, PHM_IGNORE_PORT);
3963
3964        if (vl)
3965                return ph_vline2vlid(vl);
3966
3967        if (nonempty(altid))
3968        {
3969                vl = ph_find_matching_vline(altid, PHM_IGNORE_PORT);
3970                if (vl)
3971                        return ph_vline2vlid(vl);
3972        }
3973
3974        vl = ph_find_matching_vline(userid, PHM_IGNORE_HOST|PHM_IGNORE_PORT);
3975        if (vl)
3976                return ph_vline2vlid(vl);
3977
3978
3979        if (nonempty(altid))
3980        {
3981                vl = ph_find_matching_vline(altid, PHM_IGNORE_HOST|PHM_IGNORE_PORT);
3982                if (vl)
3983                        return ph_vline2vlid(vl);
3984        }
3985
3986        return 0;
3987
3988}
3989
3990static void ph_setup_payload(const char *ptstring)
3991{
3992        PayloadType *rtppt;
3993
3994        //DBG_CODEC_LOOKUP("trying to setup audio codec in eXosip: %s\n", ptstring, 0, 0);
3995
3996        if (ph_media_supported_payload(&rtppt, ptstring))
3997        {
3998                char* fmtp = 0;
3999                if (!strncasecmp(ptstring,"telephone-event", 15))
4000                        fmtp = osip_strdup("0-11");
4001
4002
4003                sdp_payload_list_add(&ph_audio_payloads, rtp_profile_get_payload_number_from_rtpmap(&av_profile, ptstring), payload_type_get_rtpmap(rtppt), fmtp, 0);
4004                DBG_CODEC_LOOKUP("added audio codec: %s\n",ptstring);
4005        } 
4006        else
4007                DBG_CODEC_LOOKUP("unsupported audio codec : %s not found in ortp profile or not supported by mediastreamer\n", ptstring);
4008}
4009
4010#ifdef PHAPI_VIDEO_SUPPORT
4011static void ph_setup_video_payload(const char *ptstring)
4012{
4013        PayloadType *rtppt;
4014       
4015        //DBG_CODEC_LOOKUP("trying to setup video codec in eXosip: %s\n", ptstring, 0, 0);
4016
4017        if (ph_media_supported_payload(&rtppt, ptstring))
4018        {
4019                sdp_payload_list_add(&ph_video_payloads, rtp_profile_get_payload_number_from_rtpmap(&av_profile, ptstring), payload_type_get_rtpmap(rtppt), NULL, 1);
4020                DBG_CODEC_LOOKUP("added video codec: %s\n",ptstring);
4021        }
4022        else
4023                DBG_CODEC_LOOKUP("unsupported video codec :  %s not found in ortp profile or not supported by mediastreamer\n",ptstring);
4024}
4025#endif
4026
4027
4028/**
4029 * Initialize the phoneapi module
4030 */
4031
4032#ifdef OS_WIN32
4033
4034static int
4035wsock_init()
4036{
4037        WORD wVersionRequested;
4038        WSADATA wsaData;
4039        int i;
4040
4041        wVersionRequested = MAKEWORD(2,0);
4042        if(i = WSAStartup(wVersionRequested,  &wsaData))
4043        {
4044                return -1;
4045        }
4046        return 0;
4047}
4048#else
4049#define wsock_init() 0
4050#endif
4051
4052#ifdef ANDROID
4053void  and_osip_print_dbg(char *li, int fi, osip_trace_level_t level, char *chfr, va_list ap)
4054{
4055        int prio;
4056        switch(level){
4057        case OSIP_INFO3:
4058        case OSIP_INFO4:
4059                prio = ANDROID_LOG_DEBUG;
4060                break;                                               
4061        case OSIP_INFO1:
4062        case OSIP_INFO2:
4063                prio = ANDROID_LOG_INFO;
4064                break;                                               
4065        case OSIP_WARNING:
4066                prio = ANDROID_LOG_WARN;
4067                break;                                               
4068        case OSIP_ERROR:
4069                prio = ANDROID_LOG_ERROR;
4070                break;                                               
4071        case OSIP_FATAL:
4072                prio = ANDROID_LOG_FATAL;
4073                break;                                               
4074        default:
4075                prio = ANDROID_LOG_VERBOSE;
4076                break;                                               
4077        }
4078
4079        __android_log_vprint(prio, "phapi", chfr, ap);
4080}
4081#endif
4082
4083
4084static int
4085ph_debug_init()
4086{
4087        const char *dbgstr;
4088
4089        dbgstr = getenv("PH_DEBUG_LEVEL");
4090        if (dbgstr)
4091                phDebugLevel = atoi(dbgstr);
4092
4093        if (phDebugLevel > 0)
4094        {
4095                if (!phLogFileName)
4096                        phLogFileName = getenv("PH_LOG_FILENAME");
4097
4098
4099                ph_log_file = phLogFileName ? fopen (phLogFileName, "w+") : stdout;
4100
4101
4102                if (!ph_log_file)
4103                {
4104                        perror ("phapi: log file");
4105                        return -1;
4106                }
4107#ifdef ANDROID
4108        osip_trace_initialize_func(phDebugLevel, and_osip_print_dbg);
4109#else
4110        osip_trace_initialize (phDebugLevel, ph_log_file);
4111#endif
4112        }
4113
4114        return 0;
4115
4116}
4117
4118
4119static void
4120ph_avcodec_init()
4121{
4122#ifdef PHAPI_VIDEO_SUPPORT
4123        avcodec_init();
4124        avcodec_register_all();
4125        phcfg.video_config.video_line_configuration = PHAPI_VIDEO_LINE_128KBPS;
4126#endif
4127
4128}
4129
4130
4131static void
4132ph_calls_init()
4133{
4134        int i;
4135
4136        for( i = 0; i < PH_MAX_CALLS; i++)
4137                ph_calls[i].cid = -1;
4138
4139}
4140
4141static int
4142ph_tunnel_init()
4143{
4144#ifdef USE_HTTP_TUNNEL
4145        eXosip_tunnel_t *tunnel = NULL;
4146        int port;
4147        char *c;
4148        char buf[256];
4149        int tunerr;
4150
4151        if (!(phcfg.use_tunnel & PH_TUNNEL_USE))
4152                return 0;
4153
4154        http_tunnel_init_host(phcfg.httpt_server, phcfg.httpt_server_port, phcfg.use_tunnel & PH_TUNNEL_SSL);
4155        http_tunnel_init_proxy(phcfg.http_proxy,phcfg.http_proxy_port,
4156                        phcfg.http_proxy_user, phcfg.http_proxy_passwd);
4157
4158        tunnel = malloc(sizeof(eXosip_tunnel_t));
4159        if (tunnel)
4160        {
4161                osip_strncpy(buf, phcfg.proxy, sizeof(buf)-1);
4162                c = strstr(buf, ":");
4163
4164                port = 5060;
4165                if (c)
4166                {
4167                        *c++ = 0;
4168                        port = atoi(c);
4169                }
4170                tunnel->h_tunnel = http_tunnel_open(buf, port, HTTP_TUNNEL_VAR_MODE, &tunerr, -1);
4171                if (!tunnel->h_tunnel)
4172                {
4173                        if (!tunnel->h_tunnel)
4174                        {
4175                                free(tunnel);
4176                                return -PH_NOTUNNEL;
4177                        }
4178                }
4179
4180                tunnel->tunnel_recv = http_tunnel_recv;
4181                tunnel->tunnel_send = http_tunnel_send;
4182                tunnel->get_tunnel_socket = http_tunnel_get_socket;
4183                phTunnel = tunnel;
4184                ph_nat_type = TUNNEL;
4185                return 0;
4186        }
4187
4188
4189
4190
4191        return -PH_NORESOURCES;
4192#else
4193        return -1;
4194#endif
4195}
4196
4197#ifdef USE_UPNP
4198
4199static int
4200ph_upnp_add_redirection(const char * addr, char * local_port, char * extern_port, char * proto)
4201{
4202        if( UPNP_AddPortMapping(ph_upnp_urls.controlURL, ph_upnp_data.first.servicetype, extern_port,local_port, addr, 0,proto, 0) == UPNPCOMMAND_SUCCESS)
4203        {
4204                return 0;
4205        }
4206       
4207        return -1;
4208}
4209
4210static int
4211ph_upnp_remove_redirection(char * sport, char * proto)
4212{
4213        if( UPNP_DeletePortMapping(ph_upnp_urls.controlURL, ph_upnp_data.first.servicetype, sport, proto,0) == UPNPCOMMAND_SUCCESS)
4214        {
4215                return 0;
4216        }
4217       
4218        return -1;
4219}
4220
4221static int
4222ph_upnp_redirect_port(const char* addr, int lport, int* pport, const char *proto)
4223{
4224        char lpstr[16], ppstr[16];
4225
4226        sinprintf(lpstr, 16, "%d", lport);
4227
4228        if (!ph_upnp_add_redirection(addr, lpstr, pppstr, proto)) {
4229                *pport = atoi(ppstr);
4230                return 0;
4231        }
4232
4233        return -1;
4234
4235}
4236
4237static int
4238ph_upnp_release_port(int lport, const char *proto)
4239{
4240        char lpstr[16], ppstr[16];
4241
4242        sinprintf(lpstr, 16, "%d", lport);
4243
4244        if (!ph_upnp_remove_redirection(lpstr, proto)) {
4245                return 0;
4246        }
4247
4248        return -1;
4249
4250}
4251
4252
4253static int
4254ph_upnp_init()
4255{
4256        int result = -1;
4257       
4258        char lanaddr[16];
4259        struct UPNPDev * devlist = upnpDiscover(500, 0, 0, 0);
4260        if( UPNP_GetValidIGD(devlist, &ph_upnp_urls, &ph_upnp_data, lanaddr, sizeof(lanaddr)) == 1 )
4261        {
4262                if(phcfg.local_ip_addr[0] == 0)
4263                        snprintf(phcfg.local_ip_addr, sizeof(phcfg.local_ip_addr),"%s",lanaddr);
4264                       
4265                if( UPNP_GetExternalIPAddress(ph_upnp_urls.controlURL,ph_upnp_data.first.servicetype,ph_nat_router_addr) == UPNPCOMMAND_SUCCESS)
4266                {
4267                        snprintf(ph_nat_sip_port_str, sizeof(ph_nat_sip_port_str), "%s", _get_local_sip_port());
4268                       
4269                        result = ph_upnp_add_redirection(phcfg.local_ip_addr,_get_local_sip_port(),ph_nat_sip_port_str, phcfg.transport == IPPROTO_UDP ? "UDP" : "TCP");
4270                        if(!result)
4271                        {
4272                                eXosip_masquerade_contact(ph_nat_router_addr,atoi(ph_nat_sip_port_str));
4273                                ph_nat_type = UPNP;
4274                        }
4275                }
4276        }
4277        ph_upnp_devlist = devlist;
4278       
4279        return result;
4280}
4281
4282#endif
4283
4284static int
4285ph_stun_init()
4286{
4287        bool_t resPort = 0, hairpin = 0;
4288        StunAddress4 stunServerAddr;
4289        stunParseServerName(phcfg.stunserver, &stunServerAddr);
4290       
4291        ph_stun_nat_type = stunNatType( &stunServerAddr, &resPort, &hairpin,0, 0);
4292       
4293        if( ph_stun_nat_type == StunTypeConeNat || ph_stun_nat_type == StunTypeRestrictedNat || ph_stun_nat_type == StunTypePortRestrictedNat)
4294        {
4295                StunAddress4 mappedAddr;
4296                Socket  sock = stunOpenSocket(&stunServerAddr, &mappedAddr, atoi(_get_local_sip_port()), 0);
4297               
4298                if ( sock != -1 )
4299                {
4300                        ph_ipv4tostr(ph_nat_router_addr, sizeof(ph_nat_router_addr), mappedAddr);
4301                        snprintf(ph_nat_sip_port_str, sizeof(ph_nat_sip_port_str), "%d", mappedAddr.port);
4302                        closesocket(sock);
4303                       
4304                        eXosip_masquerade_contact(ph_nat_router_addr,atoi(ph_nat_sip_port_str));
4305                        ph_nat_type = STUN;
4306                       
4307                        return 0;
4308                }
4309        }
4310       
4311        return -1;
4312}
4313
4314static void
4315ph_nat_init()
4316{
4317        ph_nat_router_addr[0] = 0;
4318        ph_nat_port_str[0] = 0;
4319
4320#if 0
4321        if (!phcfg.nat_refresh_udp_time)
4322                phcfg.nat_refresh_udp_time = 15;
4323       
4324        if (!phcfg.nat_refresh_tcp_time)
4325                phcfg.nat_refresh_tcp_time = 15;
4326#endif
4327
4328#ifdef USE_UPNP
4329        if(phcfg.use_upnp)
4330        {
4331                if(!ph_upnp_init())
4332                        return;
4333        }
4334#endif
4335       
4336        if(phcfg.use_stun)
4337        {
4338                if(!ph_stun_init())
4339                        return;
4340        }
4341       
4342        if(phcfg.use_tunnel)
4343        {
4344                if(!ph_tunnel_init())
4345                        return;
4346        }
4347
4348        //nat should be open
4349        ph_nat_type = OPEN;
4350//      phcfg.nat_refresh_udp_time = 0;
4351//      phcfg.nat_refresh_tcp_time = 0;
4352       
4353        if (phcfg.local_ip_addr[0] != 0)
4354                eXosip_masquerade_contact(phcfg.local_ip_addr, atoi(_get_local_sip_port()));
4355}
4356
4357/**
4358 * @brief initialize the payload/codecs that are allowed to be handled by the SIP stack
4359 */
4360PHAPI_EXPORT void
4361ph_payloads_init()
4362{
4363        char audio_codecs[128];
4364       
4365#ifdef PHAPI_VIDEO_SUPPORT
4366        char video_codecs[128];
4367        osip_strncpy(video_codecs,phcfg.video_codecs,sizeof(phcfg.video_codecs)-1);
4368        osip_list_init(&ph_video_payloads);
4369        if (!video_codecs[0]) {
4370                ph_setup_video_payload("H263/90000");
4371        } else {
4372                char tmp[32];
4373                char *tok = strtok(video_codecs, ",");
4374
4375                while(tok) {
4376                        snprintf(tmp, sizeof(tmp), "%s/90000", tok);
4377                        ph_setup_video_payload(tmp);
4378                        tok = strtok(0, ",");
4379                }
4380        }
4381#endif
4382       
4383        // init payload/codecs for AUDIO
4384        osip_list_init(&ph_audio_payloads);
4385        osip_strncpy(audio_codecs,phcfg.audio_codecs,sizeof(phcfg.audio_codecs)-1);
4386       
4387        // add codecs out of an ENV var
4388        {
4389                char *aclist = getenv("PH_AUDIO_CODECS");
4390                if (aclist) {
4391                        osip_strncpy(audio_codecs, aclist, sizeof(audio_codecs)-1);
4392                }
4393
4394        }
4395
4396
4397        // limit codecs to G711 codecs according to compile time DEFINE
4398#ifdef G711_ONLY
4399        strcpy(audio_codecs, "PCMU/8000,PCMA/8000");
4400#endif
4401
4402        // if at this stage, no codecs are required, fix a default list
4403        if (!audio_codecs[0])
4404        {
4405                ph_setup_payload("PCMU/8000");
4406                ph_setup_payload("PCMA/8000");
4407                ph_setup_payload("GSM/8000");
4408                ph_setup_payload("ILBC/8000");
4409                ph_setup_payload("SPEEX/16000");
4410                ph_setup_payload("SPEEX/8000");
4411                ph_setup_payload("AMR/8000");
4412                ph_setup_payload("AMR-WB/16000");
4413                ph_setup_payload("G722/8000");
4414                ph_setup_payload("G726-32/8000");
4415
4416        }
4417        // phapi.h client has required a specific list of codecs
4418        else
4419        {
4420
4421                /*
4422        The list is "," separated
4423        some hacks are present to allow for :
4424        - payload usurpation
4425        - default /8000 clockrate when not specified
4426        - ... look at the code
4427                 */
4428
4429
4430                char tmp[32];
4431                char *tok = strtok(audio_codecs, ",");
4432
4433                while(tok)
4434                {
4435                        if(!strcmp(tok, "AMR-WB"))
4436                        {
4437#ifdef AMR_OVER_G729_HACK
4438                                snprintf(tmp, sizeof(tmp), "G729/8000");
4439#else
4440                                snprintf(tmp, sizeof(tmp), "%s/16000", tok);
4441#endif
4442                        }
4443#ifdef SPEEX_OVER_G729_HACK
4444                        else if(!strcmp(tok, "SPEEX/16000"))
4445                        {
4446                                snprintf(tmp, sizeof(tmp), "G729/8000");
4447                        }
4448#endif
4449                        else if (strchr(tok, '/'))
4450                                osip_strncpy(tmp, tok, sizeof(tmp)-1);
4451                        else
4452                                snprintf(tmp, sizeof(tmp), "%s/8000", tok);
4453
4454                        ph_setup_payload(tmp);
4455
4456                        tok = strtok(0, ",");
4457                }
4458        }
4459
4460        // set codec in sip stack for CNG (confort noise generator=
4461        if(phcfg.cng)
4462                ph_setup_payload("CN/8000");
4463
4464        // set codec in sip stack for DTMF
4465        ph_setup_payload("telephone-event/8000");
4466}
4467
4468static int
4469ph_get_call_id(int did, char **cid)
4470{
4471        char referto[512];
4472        char *cp, *semi;
4473        int i;
4474
4475        i = eXosip_call_get_referto(did, referto, sizeof(referto));
4476        if (i)
4477                return -PH_ERROR;
4478        cp = strstr(referto, "Replaces");
4479        if (!cp)
4480                return -PH_ERROR;
4481        cp += 9;
4482        semi = strchr(cp, ';');
4483        if (semi)
4484                *semi = 0;
4485
4486        *cid = osip_strdup(cp);
4487
4488        return *cid ? 0 : -PH_NORESOURCES;
4489}
4490
4491
4492PHAPI_EXPORT int
4493phCallGetSipCallID(int cid, char* buf, int bufsize)
4494{
4495        phcall_t *ca;
4496        char *callid;
4497        int i;
4498
4499        if (!phIsInitialized)
4500                return -PH_NOTINIT;
4501
4502        ca = ph_locate_call_by_cid(cid);
4503
4504        if (!ca)
4505                return -PH_BADCID;
4506
4507        if( bufsize  <= 0 || !buf)
4508                return -PH_BADARG;
4509
4510
4511        eXosip_lock();
4512        i = ph_get_call_id(ca->did, &callid);
4513        eXosip_unlock();
4514
4515        if(!i)
4516        {
4517                osip_strncpy(buf, callid, bufsize-1);
4518                osip_free(callid);
4519                return 0;
4520        }
4521
4522        return -PH_ERROR;
4523}
4524
4525PHAPI_EXPORT int
4526phListenAddr(int local_sip_port)
4527{
4528        int i, cpt = 0;
4529        int secure = 0;
4530        int proto = phcfg.transport;
4531
4532        for (cpt = 0; cpt < 5; cpt++)
4533        {
4534                if (phcfg.local_ip_addr[0] == 0)
4535                        i = eXosip_listen_addr(proto, NULL,local_sip_port + cpt, AF_INET, secure);
4536                else
4537                        i = eXosip_listen_addr(proto, phcfg.local_ip_addr,local_sip_port + cpt, AF_INET, secure);
4538
4539                if(!i)
4540                        break;
4541        }
4542
4543        return i;
4544}
4545
4546PHAPI_EXPORT int
4547phInit(phCallbacks_t *cbk, char * server, int asyncmode)
4548{
4549        int i;
4550        const char *tmp;
4551        int nat_refresh_time = 0;
4552
4553        if (phIsInitialized)
4554                return 0;
4555
4556        memset(vcontact, 0, sizeof(vcontact));
4557
4558        i = ph_debug_init();
4559
4560        if (i)
4561                return i;
4562
4563        tmp = getenv("EXOSIP_RESEND_OFFSET");
4564        if (tmp && strlen(tmp))
4565                ph_resend_offset = atoi(tmp);
4566
4567        ph_avcodec_init();
4568        ph_calls_init();
4569
4570        if (phcfg.use_tunnel)
4571        {
4572                i = ph_tunnel_init();
4573                if (i)
4574                        return i;
4575        }
4576
4577#ifdef FORCE_VAD
4578        /* HACK for test */
4579#ifdef EMBED
4580        phcfg.vad = VAD_VALID_MASK | (500 & VAD_THRESHOLD_MASK);
4581#else
4582        phcfg.vad = VAD_VALID_MASK | (1000 & VAD_THRESHOLD_MASK);
4583#endif
4584#endif
4585
4586#ifdef FORCE_CNG
4587        /* HACK for test */
4588        phcfg.cng = 1;
4589#endif
4590
4591
4592        ph_media_init(phcfg.plugin_path); //init ortp/ms2 payloads list, init ms2 and ortp
4593
4594        if (phcfg.use_tunnel) {
4595
4596                // ph_setup_tunnel();
4597
4598        }
4599
4600        i = eXosip_init();
4601        if (i)
4602                return -1;
4603       
4604        ph_nat_init();
4605       
4606        DBG_SIP_NEGO("NAT type: %s fw=%s \n", ph_get_nat_type(), ph_nat_router_addr);
4607
4608        if (phcfg.public_ip_addr[0])
4609        {
4610                int port = atoi(phcfg.public_sipport);
4611                eXosip_masquerade_contact(phcfg.public_ip_addr, port ? port : atoi(phcfg.sipport));
4612        }
4613
4614        i = phListenAddr(atoi(phcfg.sipport));
4615        if(i)
4616                return -1;
4617
4618        {
4619                const char * ua  = "phapi/eXosip-" PHAPI_VERSION_STRING;
4620                eXosip_set_user_agent(ua);
4621        }
4622
4623        nat_refresh_time = (phcfg.transport == IPPROTO_UDP) ? phcfg.nat_refresh_udp_time : phcfg.nat_refresh_tcp_time;
4624        eXosip_set_option(EXOSIP_OPT_UDP_KEEP_ALIVE, &nat_refresh_time);
4625        eXosip_set_option(EXOSIP_OPT_UDP_KEEP_ALIVE_ADJUST, &phcfg.nat_refresh_time_adjust);
4626
4627        eXosip_set_cbconnection_close(ph_connection_lost);
4628       
4629        memset(ph_vlines, 0, sizeof(ph_vlines));
4630
4631        ph_payloads_init(); //init phapi codecs lists
4632
4633        /* register callbacks? */
4634        phcb = cbk;
4635        phcfg.asyncmode = asyncmode;
4636        if (!asyncmode)
4637                timeout = 0;
4638        else
4639                timeout = 10;
4640
4641        ph_media_start_mutex = osip_mutex_init();
4642        ph_media_stop_mutex = osip_mutex_init();
4643        ph_custom_mutex = osip_mutex_init();
4644        osip_list_init(&ph_custom_headers);
4645
4646        ph_hdrmon_mutex = osip_mutex_init();
4647        osip_list_init(&ph_hdrmon_list);
4648
4649
4650
4651        if (asyncmode)
4652                phapithread = osip_thread_create(20000, ph_api_thread, (void*)0);
4653
4654        phIsInitialized = 1;
4655
4656        return 0;
4657}
4658
4659PHAPI_EXPORT int
4660phAudioCaptureCardList(ph_audio_card_desc_t** device_tab)
4661{
4662        if (!phIsInitialized)
4663                return -PH_NOTINIT;
4664
4665        return phms_audio_get_capture_sndcard_list(device_tab);
4666}
4667
4668PHAPI_EXPORT int
4669phAudioPlaybackCardList(ph_audio_card_desc_t** device_tab)
4670{
4671        if (!phIsInitialized)
4672                return -PH_NOTINIT;
4673
4674        return phms_audio_get_playback_sndcard_list(device_tab);
4675}
4676
4677PHAPI_EXPORT int
4678phVideoWebcamList(ph_video_web_cam_desc_t** device_tab)
4679{
4680        if (!phIsInitialized)
4681                return -PH_NOTINIT;
4682#ifdef PHAPI_VIDEO_SUPPORT     
4683        return phms_video_get_web_cam_list(device_tab);
4684#else
4685        return 0;
4686#endif
4687}
4688
4689int phTunnelConfig(const char* http_proxy, const int http_proxy_port,
4690                const char* httpt_server, const int httpt_server_port,
4691                const char *proxy_user, const char* proxy_passwd,
4692                int use_ssl, int autoconf)
4693{
4694        if (!phIsInitialized)
4695                return -PH_NOTINIT;
4696
4697        phcfg.httpt_server[0] = 0;
4698        phcfg.http_proxy[0] = 0;
4699        phcfg.use_tunnel = 0;
4700
4701        if (!httpt_server) {
4702                return -1;
4703        }
4704
4705        phcfg.http_proxy_port = http_proxy_port;
4706        if (!httpt_server_port)
4707                if (!http_proxy) {
4708                        phcfg.httpt_server_port = 80;
4709                }
4710                else {
4711                        phcfg.httpt_server_port = 443;
4712                }
4713        else
4714                phcfg.httpt_server_port = httpt_server_port;
4715
4716        if (httpt_server)
4717                osip_strncpy(phcfg.httpt_server, httpt_server, sizeof(phcfg.httpt_server)-1);
4718        if (http_proxy)
4719                osip_strncpy(phcfg.http_proxy, http_proxy, sizeof(phcfg.http_proxy)-1);
4720
4721        if (proxy_user)
4722                osip_strncpy(phcfg.http_proxy_user, proxy_user, sizeof(phcfg.http_proxy_user)-1);
4723        if (proxy_passwd)
4724                osip_strncpy(phcfg.http_proxy_passwd, proxy_passwd, sizeof(phcfg.http_proxy_passwd)-1);
4725
4726        phcfg.use_tunnel = PH_TUNNEL_USE;
4727        if (use_ssl)
4728                phcfg.use_tunnel |= PH_TUNNEL_SSL;
4729
4730        if (autoconf)
4731                phcfg.use_tunnel |= PH_TUNNEL_AUTOCONF;
4732        return 0;
4733}
4734
4735static void ph_payload_cleanup()
4736{
4737        if (osip_list_size(&ph_audio_payloads) > 0)
4738                osip_list_special_free(&ph_audio_payloads, sdp_payload_free);
4739        if (osip_list_size(&ph_video_payloads) > 0)
4740                osip_list_special_free(&ph_video_payloads, sdp_payload_free);
4741}
4742
4743/**
4744 * terminate ph api
4745 */
4746PHAPI_EXPORT void
4747phTerminate()
4748{
4749        int i;
4750
4751        DBG_SIP_EVENT("SIP NEGO: phTerminate\n");
4752        if (!phIsInitialized)
4753                return;
4754
4755        for(i = 0; i < PH_MAX_CALLS; i++)
4756                if (ph_calls[i].cid != -1)
4757                        ph_release_call(&ph_calls[i]);
4758
4759        for(i = 0; i < PH_MAX_VLINES; i++)
4760        {
4761                phDelVline(i+1);
4762        }
4763
4764        usleep(200000);
4765
4766        phPoll();
4767
4768        phIsInitialized = 0;
4769
4770        if (phapithread != NULL) {
4771                i = osip_thread_join((struct osip_thread *) phapithread);
4772                if (i != 0) {
4773                        OSIP_TRACE(osip_trace
4774                                        (__FILE__, __LINE__, OSIP_ERROR, NULL,
4775                                                        "phapithread: can't terminate thread!\n"));
4776                }
4777                osip_free(phapithread);
4778                phapithread = 0;
4779        }
4780        eXosip_quit();
4781
4782
4783        for(i = 0; i < PH_MAX_VLINES; i++)
4784        {
4785                struct vline *vl = ph_vlid2vline(i+1);
4786                if (vl)
4787                        vline_free(vl);
4788        }
4789
4790
4791#ifdef USE_HTTP_TUNNEL
4792        if (phTunnel)
4793        {
4794                http_tunnel_close(phTunnel->h_tunnel);
4795                http_tunnel_clean_up();
4796                free(phTunnel);
4797                phTunnel = 0;
4798        }
4799#endif
4800
4801        ph_media_cleanup();
4802        ph_payload_cleanup();
4803
4804        osip_mutex_destroy(ph_media_start_mutex);
4805        osip_mutex_destroy(ph_custom_mutex);
4806
4807
4808        if (phLogFileName && phDebugLevel > 0)
4809                fclose(ph_log_file);
4810        if (phDebugLevel > 0)
4811                for (i = 0; i <= phDebugLevel && i < END_TRACE_LEVEL; ++i)
4812                        TRACE_DISABLE_LEVEL(i);
4813
4814        if (phLogFileName)
4815                free(phLogFileName);
4816
4817        phLogFileName = 0;
4818
4819}
4820
4821
4822
4823/**
4824 * poll for phApi events.c
4825 */
4826PHAPI_EXPORT int
4827phPoll()
4828{
4829
4830        if (!phIsInitialized)
4831                return -PH_NOTINIT;
4832
4833        if (!phcfg.asyncmode)
4834        {
4835                if (ph_event_get() == -2)
4836                        return -2;
4837
4838                ph_keep_refreshing();
4839        }
4840        return 0;
4841}
4842
4843
4844
4845void ph_refer_notify(int did, int status, const char* msg, int final)
4846{
4847        char  statusmsg[128];
4848        osip_message_t *notify = 0;
4849        int i;
4850
4851        snprintf(statusmsg, sizeof(statusmsg), "SIP/2.0 %d %s", status, msg);
4852
4853        eXosip_lock();
4854
4855        i = eXosip_call_build_notify(did, final ? EXOSIP_SUBCRSTATE_TERMINATED : EXOSIP_SUBCRSTATE_ACTIVE, &notify);
4856        if (i)
4857                goto err;
4858
4859        osip_message_set_body(notify, statusmsg, strlen(statusmsg));
4860        osip_message_set_content_type(notify, "message/sipfrag");
4861
4862        i = eXosip_call_send_request(did, notify);
4863
4864        err:
4865        eXosip_unlock();
4866        if (i && (notify != 0))
4867                osip_message_free(notify);
4868
4869
4870}
4871char * ph_get_fixed_payload_name(int idx)
4872{
4873        if( idx == 0 )
4874                return "PCMU";
4875        else if( idx == 8 )
4876                return "PCMA";
4877        else if( idx == 9 )
4878                return "G722";
4879        else if( idx == 18 )
4880                return "G729";
4881        else if( idx == 34 )
4882                return "H263";
4883
4884        return NULL;
4885}
4886
4887static int
4888ph_call_retrieve_payloads(phcall_t *ca, int flags)
4889{
4890        int  i = 0;
4891
4892        DBG_SIP_NEGO("looking for payloads...\n");
4893        DBG_SIP_NEGO("audio...\n");
4894        if (_is_audio_enabled(flags))
4895        {
4896                const sdp_payload_t *cur_payload;
4897
4898                if (osip_list_size(&ca->result_audio_payloads) > 0)
4899                {
4900                        cur_payload = (sdp_payload_t *) osip_list_get (&ca->result_audio_payloads, 0);
4901                        ca->audio_payload = cur_payload->pt;
4902
4903                        if (cur_payload->a_rtpmap)
4904                                osip_strncpy(ca->audio_payload_name, cur_payload->a_rtpmap, sizeof(ca->audio_payload_name)-1);
4905                        else
4906                        {
4907                                char * payload_name = ph_get_fixed_payload_name(ca->audio_payload);
4908                                if(payload_name)
4909                                        osip_strncpy(ca->audio_payload_name, payload_name, sizeof(ca->audio_payload_name, payload_name)-1);
4910                        }
4911
4912                        ca->remote_ptime = cur_payload->a_ptime;
4913                }
4914        }
4915
4916        DBG_SIP_NEGO("video...\n");
4917
4918        if ((_is_video_enabled(flags)))
4919        {
4920                const sdp_payload_t *cur_payload;
4921
4922                ca->video_payload = 0;
4923                if (osip_list_size(&ca->result_video_payloads) > 0)
4924                {
4925                        cur_payload = (sdp_payload_t *) osip_list_get (&ca->result_video_payloads, 0);
4926                        ca->video_payload = cur_payload->pt;
4927                        if (cur_payload->a_rtpmap)
4928                                osip_strncpy(ca->video_payload_name, cur_payload->a_rtpmap, sizeof(ca->video_payload_name)-1);
4929                        else
4930                        {
4931                                char * payload_name = ph_get_fixed_payload_name(ca->audio_payload);
4932                                if(payload_name)
4933                                        osip_strncpy(ca->video_payload_name, payload_name, sizeof(ca->video_payload_name)-1);
4934                        }
4935
4936                        ca->remote_ptime = cur_payload->a_ptime;
4937                }
4938        }
4939
4940        DBG_SIP_NEGO("cng...\n");
4941        if(!i && phcfg.cng && (flags & PH_STREAM_CNG)) {
4942                // ca->cng = !eXosip_retrieve_negotiated_specific_payload(ca->did, PH_MEDIA_CN_PT_STR, strlen(PH_MEDIA_CN_PT_STR));
4943                // DBG_SIP_NEGO("cng: %d", ca->cng);
4944        }
4945        return i;
4946}
4947
4948
4949PHAPI_EXPORT int phCallGetCodecs(int cid, char *audioCodecBuf, int aBufLen, char *videoCodecBuf, int vBufLen)
4950{
4951        phcall_t *ca;
4952
4953        if (!phIsInitialized)
4954                return -PH_NOTINIT;
4955
4956        ca = ph_locate_call_by_cid(cid);
4957
4958        if (!ca)
4959                return -PH_BADCID;
4960
4961        if (audioCodecBuf)
4962                osip_strncpy(audioCodecBuf, ca->audio_payload_name, aBufLen-1);
4963
4964        if (videoCodecBuf)
4965                osip_strncpy(videoCodecBuf, ca->video_payload_name, vBufLen-1);
4966
4967        return 0;
4968
4969
4970}
4971
4972PHAPI_EXPORT int
4973phCallGetMediaInfo(int cid, struct ph_confirmed_media_info *mi)
4974{
4975        phcall_t *ca;
4976
4977        if (!phIsInitialized)
4978                return -PH_NOTINIT;
4979
4980        ca = ph_locate_call_by_cid(cid);
4981
4982        if (!ca)
4983                return -PH_BADCID;
4984
4985        mi->audio.localport = ca->loc_sdp_audio_port;
4986        mi->audio.remoteport = ca->remote_sdp_audio_port;
4987        osip_strncpy(mi->audio.remoteip, ca->remote_sdp_audio_ip, sizeof(mi->audio.remoteip-1));
4988        mi->video.localport = ca->loc_sdp_video_port;
4989        mi->video.remoteport = ca->remote_sdp_video_port;
4990        osip_strncpy(mi->video.remoteip, ca->remote_sdp_video_ip, sizeof(mi->video.remoteip)-1);
4991
4992        return 0;
4993
4994}
4995
4996static void
4997ph_parse_payload_mime(struct ph_media_payload_s *pt, const char *mime, int rate, int chans)
4998{
4999        const char *rp = 0;
5000        const char *cp = 0;
5001
5002        if (mime) {
5003            rp = strchr(mime, '/');
5004            strncpy(pt->string, mime, sizeof(pt->string));
5005        }
5006        pt->rate = rate;
5007        pt->chans = chans;
5008
5009
5010        if (!rp)
5011                return;
5012
5013        rp++;
5014        if (!*rp)
5015                return;
5016
5017        pt->rate = atol(rp);
5018
5019        cp = strchr(rp, '/');
5020        if (!cp)
5021                return;
5022
5023        cp++;
5024        if (!*cp)
5025                return;
5026
5027        pt->chans = atol(cp);
5028}
5029
5030
5031
5032static int
5033ph_call_media_stop(phcall_t *ca)
5034{
5035        DBG_SIP_NEGO("SIP_NEGO: ph_call_media_stop\n");
5036
5037        if (ca->mses)
5038        {
5039                if (ca->mses->refcnt == 1)
5040                {
5041                        if (!ca->audiodev_in)
5042                                ca->audiodev_in = osip_strdup(phcfg.audio_dev_in);
5043                       
5044                        if (!ca->audiodev_out)
5045                                ca->audiodev_out = osip_strdup(phcfg.audio_dev_out);
5046
5047                        if (!ph_msession_stopped(ca->mses))
5048                        {
5049                                ph_msession_stop(ca->mses, ca->audiodev_in, ca->audiodev_out,0);
5050                        }
5051                }
5052                ph_msession_free(ca->mses);
5053                ca->mses = 0;
5054        }
5055
5056        return 0;
5057
5058}
5059
5060static int
5061ph_call_media_suspend(phcall_t *ca, int localhold)
5062{
5063        if (ca->mses)
5064        {
5065                if (!ca->audiodev_in)
5066                        ca->audiodev_in = osip_strdup(phcfg.audio_dev_in);
5067
5068                ph_msession_suspend(ca->mses, PH_MSTREAM_TRAFFIC_IO, ca->audiodev_in,  ca->audiodev_out);
5069        }
5070
5071        return 0;
5072}
5073
5074
5075static int
5076ph_call_media_resume(phcall_t *ca, int localhold)
5077{
5078        if (ca->mses)
5079        {
5080                if (!ca->audiodev_in)
5081                        ca->audiodev_in = osip_strdup(phcfg.audio_dev_in);
5082               
5083                if (!ca->audiodev_out)
5084                        ca->audiodev_out = osip_strdup(phcfg.audio_dev_out);
5085               
5086                ph_msession_resume(ca->mses, PH_MSTREAM_TRAFFIC_IO, ca->audiodev_in, ca->audiodev_out, 0);
5087        }
5088
5089        return 0;
5090}
5091
5092
5093
5094static
5095struct ph_msession_s *ph_msession_new()
5096{
5097        struct ph_msession_s *= (struct ph_msession_s *)calloc(sizeof(struct ph_msession_s), 1);
5098        s->critsec_mstream_init = osip_mutex_init();
5099        s->refcnt = 1;
5100        return s;
5101}
5102
5103
5104static
5105void ph_msession_use(struct ph_msession_s *s)
5106{
5107        if (s)
5108        {
5109                osip_mutex_lock(s->critsec_mstream_init);
5110                s->refcnt++;
5111                osip_mutex_unlock(s->critsec_mstream_init);
5112        }
5113}
5114
5115static
5116void ph_msession_free(struct ph_msession_s *s)
5117{
5118        if (s)
5119        {
5120                osip_mutex_lock(s->critsec_mstream_init);
5121                if (s->refcnt-- == 1)
5122                {
5123                        osip_mutex_unlock(s->critsec_mstream_init);
5124                        osip_mutex_destroy(s->critsec_mstream_init);
5125                        free(s);
5126                        return;
5127                }
5128                osip_mutex_unlock(s->critsec_mstream_init);
5129        }
5130}
5131
5132static int
5133ph_call_media_start(phcall_t *ca, eXosip_event_t *je, int flags, int resumeflag)
5134{
5135        int use_socket;
5136        int result = 0;
5137        struct ph_msession_s *s = NULL;
5138        const char* ptime = getenv("EXOSIP_FORCE_PTIME");
5139        if (!ptime || !*ptime)
5140                ptime = "20";
5141
5142        if (!ca)
5143                return -PH_BADARG;
5144
5145        // cases when the invocation is ignored
5146        if (phcfg.nomedia || ca->remotehold)
5147        {
5148                return 0;
5149        }
5150
5151        // we will work on the media sessions of the given phcall_t
5152        s = ca->mses;
5153
5154        osip_mutex_lock(ph_media_start_mutex);
5155
5156        // init the ph_msession_s for the call if the call doesn't have one yet
5157        if (!s)
5158        {
5159                s = ca->mses = ph_msession_new();
5160                if (!s)
5161                {
5162                        osip_mutex_unlock(ph_media_start_mutex);
5163                        return -PH_NORESOURCES;
5164                }
5165                s->confflags = 0;
5166                s->confsession = NULL;
5167                s->audio_conf = NULL;
5168                s->activestreams = 0;
5169                s->dtmfCallback = ph_wegot_dtmf;
5170                s->endCallback = ph_stream_ended;
5171                s->qosInfoCbk = ph_qos_info_cbk;
5172                s->frameDisplayCbk =  ph_frame_display_cbk;
5173        }
5174        else
5175        {
5176                if(resumeflag == 0)
5177                {
5178                        if(s->activestreams)
5179                        {
5180                                osip_mutex_lock(ph_media_stop_mutex);
5181                                ph_msession_stop(s, phcfg.audio_dev_in, phcfg.audio_dev_out, 0);
5182                                osip_mutex_unlock(ph_media_stop_mutex);
5183                        }
5184                        s->confflags = 0;
5185                        s->confsession = NULL;
5186                        s->audio_conf = NULL;
5187                        s->activestreams = 0;
5188                }
5189        }
5190        s->cbkInfo = ca;
5191
5192        // we need to understand what is required from the function call
5193        // by default, nothing to do
5194        s->newstreams = 0;
5195
5196        if ( _is_video_enabled(ca->nego_mflags) && ca->video_payload && ca->remote_sdp_video_ip[0] && osip_strcasecmp(ca->remote_sdp_video_ip, "0"))
5197        {
5198                struct ph_mstream_params_s *msp = &s->streams[PH_MSTREAM_VIDEO1];
5199                int ttype;
5200
5201                // program activation of VIDEO1
5202                s->newstreams |= (1 << PH_MSTREAM_VIDEO1);
5203
5204                // define the traffic type of the stream
5205                ttype = _is_video_enabled(ca->nego_mflags);
5206                if (ttype == (PH_STREAM_VIDEO_RX | PH_STREAM_VIDEO_TX))
5207                {
5208                        msp->traffictype = PH_MSTREAM_TRAFFIC_IO;
5209                }
5210                else if (ttype == PH_STREAM_VIDEO_RX)
5211                {
5212                        msp->traffictype = PH_MSTREAM_TRAFFIC_IN;
5213                }
5214                else if (ttype == PH_STREAM_VIDEO_TX)
5215                {
5216                        msp->traffictype = PH_MSTREAM_TRAFFIC_OUT;
5217                }
5218
5219                msp->localport = ca->loc_sdp_video_port;
5220                msp->remoteport = ca->remote_sdp_video_port;
5221                msp->remotertcpport = ca->remote_sdp_video_rtcp_port;
5222                osip_strncpy(msp->remoteaddr,
5223                                ca->remote_sdp_video_ip,
5224                                sizeof(msp->remoteaddr)-1);
5225               
5226                {
5227                        const sdp_payload_t *cur_payload;
5228                        int pos = osip_list_size(&ca->result_video_payloads);
5229                        int i = 0;
5230                       
5231                        for (; i < pos ; i++)
5232                        {
5233                                cur_payload = (sdp_payload_t *) osip_list_get (&ca->result_video_payloads, i);
5234                               
5235                                msp->ipayloads[i].number = cur_payload->pt;
5236                                if(cur_payload->a_rtpmap)
5237                                        ph_parse_payload_mime(&msp->ipayloads[0], cur_payload->a_rtpmap, 90000, 1);
5238                                else
5239                                {
5240                                        char * payload_name = ph_get_fixed_payload_name(msp->ipayloads[i].number);
5241                                        if(payload_name)
5242                                                ph_parse_payload_mime(&msp->ipayloads[i], payload_name, 8000, 1);
5243                                }
5244                                msp->opayloads[i] = msp->ipayloads[i];
5245                                msp->opayloads[i].ptime = cur_payload->a_ptime;
5246                        }
5247                }
5248
5249                // define the video callback
5250               
5251
5252                // additional configuration for video
5253
5254                /* if(sdp_message_bandwidth_get(ca->remote_sdp,  ) && !phcfg.video_config.force_high_speed)
5255      {
5256      msp->video_quality = ph_get_quality_from_bitrate(ca->max_bandwidth);
5257      }
5258    else
5259    msp->video_quality = phcfg.video_config.video_line_configuration;*/
5260        }
5261
5262        if (_is_audio_enabled(ca->nego_mflags) && ca->remote_sdp_audio_ip[0] && osip_strcasecmp(ca->remote_sdp_audio_ip, "0"))
5263        {
5264                struct ph_mstream_params_s *msp = &s->streams[PH_MSTREAM_AUDIO1];
5265                int ttype = 0;
5266
5267                //TODO uncomment it after the work un payloads
5268                /*if(!strncmp(ca->audio_payload_name, "GSM", 3))
5269                {
5270                        if(30 == atoi(ptime))
5271                        {
5272                                // for GSM reset ptime to 20ms
5273                                ptime = "20";
5274                        }
5275                }*/
5276                // Set to this stream the correct ptime negociated in the SDP
5277                // If there is no ptime negociated, use the default value (20 ms)
5278                //msp->ptime = (ca && ca->ptime > 0 ? ca->ptime : atoi(ptime));
5279                msp->ptime = atoi(ptime);
5280
5281                // program activation of AUDIO1
5282                s->newstreams |= (1 << PH_MSTREAM_AUDIO1);
5283
5284                if (phcfg.vad & 0x80000000)
5285                {
5286                        msp->flags |= PH_MSTREAM_FLAG_VAD;
5287                        msp->vadthreshold = phcfg.vad & 0x7fff;
5288                }
5289
5290                if (phcfg.cng)
5291                {
5292                        msp->flags |= PH_MSTREAM_FLAG_CNG;
5293                }
5294
5295                msp->jitter = phcfg.jitterdepth;
5296
5297                if (!phcfg.noaec)
5298                {
5299                        msp->flags |= PH_MSTREAM_FLAG_AEC;
5300                }
5301
5302                ttype = _is_audio_enabled(ca->nego_mflags);
5303                if (ttype == (PH_STREAM_AUDIO_RX | PH_STREAM_AUDIO_TX))
5304                {
5305                        msp->traffictype = PH_MSTREAM_TRAFFIC_IO;
5306                }
5307                else if (ttype == PH_STREAM_AUDIO_RX)
5308                {
5309                        msp->traffictype = PH_MSTREAM_TRAFFIC_IN;
5310                }
5311                else if (ttype == PH_STREAM_AUDIO_TX)
5312                {
5313                        msp->traffictype = PH_MSTREAM_TRAFFIC_OUT;
5314                }
5315               
5316                msp->localport = ca->loc_sdp_audio_port;
5317
5318                msp->remoteport = ca->remote_sdp_audio_port;
5319                msp->remotertcpport = ca->remote_sdp_audio_rtcp_port;
5320                use_socket = 0;
5321
5322                osip_strncpy(msp->remoteaddr,
5323                                ca->remote_sdp_audio_ip,
5324                                sizeof(msp->remoteaddr)-1);
5325
5326                // SPIKE_HDX
5327                if (phcfg.hdxmode == PH_HDX_MODE_MIC)
5328                {
5329                        msp->flags |= PH_MSTREAM_FLAG_MICHDX;
5330                        msp->vadthreshold = phcfg.vad & 0x7fff;
5331                }
5332
5333                if (phcfg.hdxmode == PH_HDX_MODE_SPK)
5334                {
5335                        msp->flags |= PH_MSTREAM_FLAG_SPKHDX;
5336                        msp->vadthreshold = phcfg.vad & 0x7fff;
5337                }
5338
5339                {
5340                        const sdp_payload_t *cur_payload;
5341                        int pos = osip_list_size(&ca->result_audio_payloads);
5342                        int i = 0;
5343
5344                        for (; i < pos ; i++)
5345                        {
5346                                cur_payload = (sdp_payload_t *) osip_list_get (&ca->result_audio_payloads, i);
5347
5348                                msp->ipayloads[i].number = cur_payload->pt;
5349                                if(cur_payload->a_rtpmap)
5350                                        ph_parse_payload_mime(&msp->ipayloads[i], cur_payload->a_rtpmap, 8000, 1);
5351                                else
5352                                {
5353                                        char * payload_name = ph_get_fixed_payload_name(msp->ipayloads[i].number);
5354                                        if(payload_name)
5355                                                ph_parse_payload_mime(&msp->ipayloads[i], payload_name, 8000, 1);
5356                                }
5357                                if (!strcasecmp(msp->ipayloads[i].string, "g722"))
5358                                        msp->ipayloads[i].rate = 16000;
5359                                msp->opayloads[i] = msp->ipayloads[i];
5360                                msp->opayloads[i].ptime = cur_payload->a_ptime;
5361                        }
5362                }
5363
5364        } // end        if ( // audio is enabled
5365
5366        // take action depending on the streaming configuration
5367        if (s->newstreams || s->activestreams)
5368        {
5369                if (ph_msession_start(s, ca->audiodev_in, ca->audiodev_out, use_socket))
5370                {
5371                        DBG_SIP_NEGO("SIP_NEGO:ph_call_media_start: just called ph_msession_start\n");
5372                        result = -PH_NOMEDIA;
5373                }
5374        }
5375        else
5376        {
5377                DBG_SIP_NEGO("SIP_NEGO:ph_call_media_start: nothing to start\n");
5378                result = -PH_NOMEDIA;
5379        }
5380
5381        osip_mutex_unlock(ph_media_start_mutex);
5382
5383        return result;
5384}
5385
5386static char *
5387ph_req_get_from(osip_message_t *msg);
5388
5389
5390
5391
5392void
5393ph_call_new(eXosip_event_t *je)
5394{
5395        phCallStateInfo_t info;
5396        phcall_t *ca;
5397        struct vline *vl;
5398        char *localUri = NULL, *remoteUri= NULL, *sdp = NULL;
5399        int i;
5400
5401        clear(info);
5402        if (ph_busyFlag)
5403        {
5404                ph_answer_request(je->cid, je->tid, 486, 0);
5405                goto done;
5406        }
5407
5408        if (ph_follow_me_addr[0])
5409        {
5410                ph_answer_request(je->cid, je->tid, 302, ph_follow_me_addr);
5411                goto done;
5412        }
5413        osip_uri_to_str(je->request->req_uri, &localUri);
5414        osip_uri_to_str(osip_from_get_url(je->request->from), &remoteUri);
5415        info.vlid = ph_get_vline_id(localUri, NULL);
5416
5417        if (!info.vlid)
5418        {
5419                ph_answer_request(je->cid, je->tid, 404, 0);
5420                goto done;
5421        }
5422
5423        vl = ph_vlid2vline(info.vlid);
5424
5425        assert(vl!=NULL);
5426
5427        ca = ph_locate_call(je, 1);
5428        if (ca)
5429        {
5430                if (vl->busy)
5431                {
5432                        ph_answer_request(je->cid, je->tid, 486, vl->contact);
5433                        goto done;
5434                }
5435
5436                if (vl->followme && vl->followme[0])
5437                {
5438                        ph_answer_request(je->cid, je->tid, 302, vl->followme);
5439                        goto done;
5440                }
5441
5442                ca->vlid = info.vlid;
5443                ca->state = PH_CALLEE_RECEIVED;
5444
5445                i = ph_build_cname(ca->cname, sizeof(ca->cname), vl);
5446
5447                if (i)
5448                {
5449                        ph_answer_request(je->cid, je->tid, 400, vl->contact);
5450                        goto done;
5451                }
5452
5453                if (phcfg.audio_dev_in) {
5454                        ca->audiodev_in = osip_strdup(phcfg.audio_dev_in);
5455                }
5456               
5457                if (phcfg.audio_dev_out) {
5458                        ca->audiodev_out = osip_strdup(phcfg.audio_dev_out);
5459                }
5460
5461                info.userData = je->external_reference;
5462                info.event = phINCALL;
5463                info.remoteUri = remoteUri;
5464                info.localUri = localUri;
5465                info.streams = ca->nego_mflags;
5466                info.callinfo = 0; //je->call_info;
5467
5468                info.remoteSdp = sdp = ph_req_get_body(je->response);
5469
5470                ph_apply_header_monitor(je->request, &info.hlist);
5471
5472                phcb->callProgress(ca->cid, &info);
5473done:
5474                if (remoteUri)
5475                        osip_free(remoteUri);
5476
5477                if (localUri)
5478                        osip_free(localUri);
5479
5480                if (sdp)
5481                        osip_free(sdp);
5482
5483                if (info.hlist.elems)
5484                        osip_free(info.hlist.elems);
5485
5486        }
5487}
5488
5489#define ph_req_get_status(x) osip_message_get_status_code(x)
5490
5491
5492static char *
5493ph_req_get_to(osip_message_t *msg)
5494{
5495        char *str = 0;
5496
5497        osip_to_to_str(msg->to, &str);
5498        return str;
5499}
5500
5501static char *
5502ph_req_get_from(osip_message_t *msg)
5503{
5504        char *str = 0;
5505
5506        osip_from_to_str(msg->from, &str);
5507        return str;
5508}
5509
5510static char *
5511ph_req_get_body(osip_message_t *msg)
5512{
5513        char *str = 0;
5514        osip_body_t *body;
5515        size_t len;
5516
5517
5518        body = osip_list_get(&msg->bodies, 0);
5519        if (!body)
5520                return 0;
5521
5522        osip_body_to_str(body, &str, &len);
5523        str[len] = 0;
5524        return str;
5525}
5526
5527static osip_header_t *
5528ph_req_find_header(osip_message_t *msg, const char *hname)
5529{
5530        osip_header_t *hdr = 0;
5531
5532        osip_message_header_get_byname(msg, hname, 0, &hdr);
5533        return hdr;
5534
5535}
5536
5537static char *
5538ph_req_get_event(osip_message_t *msg)
5539{
5540        osip_header_t *hdr = 0;
5541
5542        osip_message_header_get_byname(msg, "Event", 0, &hdr);
5543
5544        if (hdr)
5545                return osip_strdup(hdr->hvalue);
5546
5547        return 0;
5548}
5549
5550static int
5551sdp_cmp(struct sdp_message* m1, struct sdp_message* m2)
5552{
5553        char *s1, *s2;
5554        int ret = -1;
5555
5556        sdp_message_to_str(m1, &s1);
5557        sdp_message_to_str(m2, &s2);
5558
5559        if (s1 && s2)
5560                ret = strcmp(s1, s2);
5561
5562        osip_free(s2);
5563        osip_free(s1);
5564
5565        return ret;
5566
5567}
5568
5569
5570void
5571ph_call_answered(eXosip_event_t *je)
5572{
5573        phCallStateInfo_t info;
5574        phcall_t *ca, *rca=0;
5575        int rdid;
5576        char *from = 0, *to=0, *sdp = 0;
5577        osip_message_t *ack;
5578
5579        DBG_SIP_NEGO("SIP NEGO: ph_call_answered\n");
5580        clear(info);
5581
5582        ca = ph_locate_call(je, 0);
5583
5584        if (!ca)
5585                return;
5586
5587        rca = ph_locate_call_by_cid(ca->rcid);
5588
5589        info.remoteSdp = sdp = ph_req_get_body(je->response);
5590
5591        //if (!ca->localhold)
5592        {
5593                const int mflags =  -1 & ~(PH_STREAM_MCSEND|PH_STREAM_MCRECV);
5594
5595                if (sdp)
5596                {       
5597                        struct sdp_message* new_sdp;
5598
5599                        sdp_message_init(&new_sdp);
5600                        sdp_message_parse(new_sdp, sdp);
5601
5602                        if (ca->remote_sdp) {
5603                                if (!sdp_cmp(new_sdp, ca->remote_sdp)) {
5604                                        sdp_message_free(new_sdp);
5605                                        DBG_SIP_NEGO("ph_call_answered: same sdp\n")
5606                                        goto same_sdp;
5607                                }
5608                                else {
5609                                        DBG_SIP_NEGO("ph_call_answered: different sdp restarting streams\n");
5610                                }
5611                                sdp_message_free(ca->remote_sdp);
5612                        }
5613                        ph_call_media_stop(ca);
5614                        ca->remote_sdp = new_sdp;
5615                        ca->sdpctx->answer = ca->remote_sdp;
5616                        osip_list_special_free(&ca->result_audio_payloads, sdp_payload_free);
5617                        osip_list_special_free(&ca->result_video_payloads, sdp_payload_free);
5618                        sdp_context_process_answer(ca->sdpctx, ca->remote_sdp);
5619                        ph_call_retrieve_payloads(ca, -1);
5620       
5621                        ph_update_nego_mflags(ca,ph_get_media_direction(new_sdp,"audio"),ph_get_media_direction(new_sdp,"video"));
5622       
5623                        if (ph_call_media_start(ca, je, mflags, ca->localresume))
5624                        {
5625                                DBG_SIP_NEGO("SIP NEGO: ph_call_answered but without stream\n");
5626                        }
5627                }
5628        }
5629same_sdp:
5630        info.localUri = from = ph_req_get_from(je->response);
5631        info.userData = je->external_reference;
5632        if (ca->localhold)
5633        {
5634                info.event = phHOLDOK;
5635        }
5636        else if (ca->localresume)
5637        {
5638                info.event = phRESUMEOK;
5639                ca->localresume = 0;
5640        }
5641        else {
5642                info.event = phCALLOK;
5643        }
5644
5645        eXosip_lock();
5646        eXosip_call_build_ack(ca->did, &ack);
5647        eXosip_call_send_ack(ca->did, ack);
5648        eXosip_unlock();
5649
5650        info.remoteUri = to = ph_req_get_to(je->response);
5651        info.vlid = ca->vlid;
5652        if (rca)
5653        {
5654                info.oldcid = rca->cid;
5655                rdid = rca->rdid;
5656        }
5657
5658        info.streams = PH_STREAM_AUDIO;
5659        if (ca->video_payload)
5660        {
5661                info.streams |= PH_STREAM_VIDEO_RX;
5662        }
5663
5664        if (!ca->localrefer)
5665        {
5666                /*
5667                 * the call back can call phCloseCall(odlcid)...  but we have rdid in
5668                 * the local var
5669                 */
5670                ph_apply_header_monitor(je->response, &info.hlist);
5671                phcb->callProgress(ca->cid, &info);
5672        }
5673
5674        if (rca)
5675        {
5676                ph_refer_notify(rdid, ph_req_get_status(je->response), "OK", 1);
5677        }
5678
5679        if (sdp)
5680                osip_free(sdp);
5681
5682        if (to)
5683                osip_free(to);
5684
5685        if (from)
5686                osip_free(from);
5687
5688        if (info.hlist.elems)
5689                osip_free(info.hlist.elems);
5690
5691}
5692
5693
5694void
5695ph_call_proceeding(eXosip_event_t *je)
5696{
5697        phCallStateInfo_t info;
5698        phcall_t *ca, *rca=0;
5699        char *to = 0;
5700        int s = 0;
5701
5702        DBG_SIP_NEGO("SIP NEGO: ph_call_proceeding\n");
5703        clear(info);
5704
5705
5706        ca = ph_locate_call(je, 1);
5707        if (!ca)
5708                return;
5709
5710        rca = ph_locate_call_by_cid(ca->rcid);
5711
5712        if (ca && !ca->localrefer && !ca->localhold && !ca->localresume)
5713        {
5714                ph_call_retrieve_payloads(ca, PH_STREAM_CNG);
5715                ph_call_media_start(ca, je, -1, 0);
5716
5717                info.userData = je->external_reference;
5718                info.event = phDIALING;
5719                info.remoteUri = to = ph_req_get_to(je->response);
5720                info.vlid = ca->vlid;
5721
5722                info.streams = ca->nego_mflags;
5723
5724                ph_apply_header_monitor(je->response, &info.hlist);
5725                phcb->callProgress(ca->cid, &info);
5726        }
5727
5728        if (rca)
5729        {
5730                ph_refer_notify(rca->rdid, s, "Proceeding", 0);
5731        }
5732
5733        if (to)
5734                free(to);
5735
5736        if (info.hlist.elems)
5737                osip_free(info.hlist.elems);
5738
5739
5740}
5741
5742void ph_callStopRinging(eXosip_event_t *je)
5743{
5744        phCallStateInfo_t info;
5745        phcall_t *ca;
5746        char *from = 0, *to = 0;
5747
5748        clear(info);
5749
5750        ca = ph_locate_call(je, 1);
5751        if (ca && ca->isringing)
5752        {
5753                ca->isringing = 0;
5754                info.event = phRINGandSTOP;
5755
5756                info.localUri = from = ph_req_get_from(je->request);
5757                info.userData = je->external_reference;
5758
5759                info.remoteUri = to = ph_req_get_to(je->request);
5760                info.vlid = ca->vlid;
5761
5762                phcb->callProgress(je->cid, &info);
5763        }
5764
5765        if (to)
5766                osip_free(to);
5767        if (from)
5768                osip_free(from);
5769
5770
5771}
5772
5773
5774//from osip_uri.c, Don't add the port number into the string
5775static int ph_uri_to_str(const osip_uri_t * url, char **dest)
5776{
5777        char *buf;
5778        size_t len;
5779        char *tmp;
5780        const char *scheme;
5781
5782        *dest = NULL;
5783        if (url == NULL)
5784                return OSIP_BADPARAMETER;
5785        if (url->host == NULL && url->string == NULL)
5786                return OSIP_BADPARAMETER;
5787        if (url->scheme == NULL && url->string != NULL)
5788                return OSIP_BADPARAMETER;
5789        if (url->string == NULL && url->scheme == NULL)
5790                scheme = "sip";                 /* default is sipurl */
5791        else
5792                scheme = url->scheme;
5793
5794        if (url->string != NULL) {
5795                buf = (char *) osip_malloc(strlen(scheme) + strlen(url->string) + 3);
5796                if (buf == NULL)
5797                        return OSIP_NOMEM;
5798                *dest = buf;
5799                sprintf(buf, "%s:", scheme);
5800                buf = buf + strlen(scheme) + 1;
5801                sprintf(buf, "%s", url->string);
5802                buf = buf + strlen(url->string);
5803                return OSIP_SUCCESS;
5804        }
5805
5806        len = strlen(scheme) + 1 + strlen(url->host) + 5;
5807        if (url->username != NULL)
5808                len = len + (strlen(url->username) * 3) + 1;    /* count escaped char */
5809        if (url->password != NULL)
5810                len = len + (strlen(url->password) * 3) + 1;
5811        if (url->port != NULL)
5812                len = len + strlen(url->port) + 3;
5813
5814        buf = (char *) osip_malloc(len);
5815        if (buf == NULL)
5816                return OSIP_NOMEM;
5817        tmp = buf;
5818
5819        sprintf(tmp, "%s:", scheme);
5820        tmp = tmp + strlen(tmp);
5821
5822        if (url->username != NULL) {
5823                char *tmp2 = __osip_uri_escape_userinfo(url->username);
5824
5825                sprintf(tmp, "%s", tmp2);
5826                osip_free(tmp2);
5827                tmp = tmp + strlen(tmp);
5828        }
5829        if (url->username != NULL) {    /* we add a '@' only when username is present... */
5830                sprintf(tmp, "@");
5831                tmp++;
5832        }
5833        if (strchr(url->host, ':') != NULL) {
5834                sprintf(tmp, "[%s]", url->host);
5835                tmp = tmp + strlen(tmp);
5836        } else {
5837                sprintf(tmp, "%s", url->host);
5838                tmp = tmp + strlen(tmp);
5839        }
5840
5841        *dest = buf;
5842        return OSIP_SUCCESS;
5843}
5844
5845
5846
5847void
5848ph_call_ringing(eXosip_event_t *je)
5849{
5850        int ret = 0;
5851        phCallStateInfo_t info;
5852        phcall_t *ca, *rca=0;
5853        char *from = 0, *to = 0;
5854        const int mflags =  -1 & ~(PH_STREAM_MCSEND|PH_STREAM_MCRECV);
5855        char *sdp = 0;
5856
5857        DBG_SIP_NEGO("SIP NEGO: ph_call_ringing\n");
5858
5859        clear(info);
5860
5861        ca = ph_locate_call(je, 1);
5862        if (!ca)
5863                return;
5864
5865        rca = ph_locate_call_by_cid(ca->rcid);
5866
5867        info.remoteSdp = sdp = ph_req_get_body(je->response);
5868
5869        if (!(ca->user_mflags & PH_NOEARLY_MEDIA) && 0 != sdp)
5870        {
5871                if (ca->remote_sdp) {
5872                        sdp_message_free(ca->remote_sdp);
5873                }
5874                sdp_message_init(&ca->remote_sdp);
5875                sdp_message_parse(ca->remote_sdp, sdp);
5876                ca->sdpctx->answer = ca->remote_sdp;
5877                sdp_context_process_answer(ca->sdpctx, ca->remote_sdp);
5878        }
5879
5880
5881        ph_call_retrieve_payloads(ca, -1);
5882
5883        ret = ph_call_media_start(ca, je, mflags, 0);
5884
5885//      ph_call_retrieve_payloads(ca, PH_STREAM_CNG);
5886
5887//      ret = ph_call_media_start(ca, je, -1, 0);
5888
5889        info.event = phRINGING;
5890        if (ret == -PH_NOMEDIA && !ph_call_hasaudio(ca) && !ca->isringing) /*  no audio and softPhone is now not ringing and has no sound */
5891        {
5892                ca->isringing = 1;
5893                info.event = phRINGandSTART;
5894        }
5895        else if (ca->isringing )
5896        {
5897                ca->isringing = 0;
5898                info.event = phRINGandSTOP;
5899        }
5900
5901        info.localUri = from = ph_req_get_from(je->response);
5902        info.userData = je->external_reference;
5903
5904        info.remoteUri = to = ph_req_get_to(je->response);
5905        info.vlid = ca->vlid;
5906
5907        info.streams = ca->nego_mflags;
5908
5909        ph_apply_header_monitor(je->response, &info.hlist);
5910
5911        phcb->callProgress(je->cid, &info);
5912
5913        if (rca)
5914        {
5915                ph_refer_notify(rca->rdid, 180, "Ringing", 0);
5916        }
5917
5918        if (sdp)
5919                osip_free(sdp);
5920
5921        if (to)
5922                osip_free(to);
5923        if (from)
5924                osip_free(from);
5925
5926        if (info.hlist.elems)
5927                osip_free(info.hlist.elems);
5928}
5929
5930
5931static void
5932ph_call_requestfailure(eXosip_event_t *je)
5933{
5934        phCallStateInfo_t info;
5935        phcall_t *ca, *rca=0;
5936        int s = 0;
5937        char *from = 0, *to = 0;
5938
5939        DBG_SIP_NEGO("call invite failure\n");
5940
5941        clear(info);
5942
5943        ca = ph_locate_call(je, 0);
5944        if (!ca)
5945                return;
5946
5947        rca = ph_locate_call_by_cid(ca->rcid);
5948        info.vlid = ca->vlid;
5949
5950        if (je->response) {
5951                s = ph_req_get_status(je->response);
5952                if (s == 407 || s == 401)
5953                        return;
5954        }
5955
5956        ph_release_call(ca);
5957
5958        if (je->response) {
5959                info.localUri = from = ph_req_get_from(je->response);
5960        }
5961
5962        info.userData = je->external_reference;
5963        if (s == 486)
5964        {
5965                info.event = phCALLBUSY;
5966                info.remoteUri = to = ph_req_get_to(je->response);
5967        }
5968        else
5969        {
5970                info.event = phCALLERROR;
5971                info.errorCode = s;
5972        }
5973
5974        ph_apply_header_monitor(je->response, &info.hlist);
5975
5976        phcb->callProgress(je->cid, &info);
5977        if (rca)
5978        {
5979                ph_refer_notify(rca->rdid, s, s == 486 ? "Busy" : "Request failure", 1);
5980        }
5981
5982        if (to)
5983                osip_free(to);
5984        if (from)
5985                osip_free(from);
5986
5987        if (info.hlist.elems)
5988                osip_free(info.hlist.elems);
5989}
5990
5991
5992void
5993ph_call_serverfailure(eXosip_event_t *je)
5994{
5995        phCallStateInfo_t info;
5996        phcall_t *ca, *rca=0;
5997        char *from = 0, *to = 0;
5998        int s = 0;
5999
6000        clear(info);
6001
6002        ca = ph_locate_call(je, 0);
6003        if (ca)
6004        {
6005                rca = ph_locate_call_by_cid(ca->rcid);
6006                info.vlid = ca->vlid;
6007                ph_release_call(ca);
6008        }
6009
6010        if (je->response) {
6011                s = ph_req_get_status(je->response);
6012                info.localUri = from = ph_req_get_from(je->response);
6013        }
6014
6015        info.userData = je->external_reference;
6016        info.event = phCALLERROR;
6017        info.errorCode = s;
6018
6019        ph_apply_header_monitor(je->response, &info.hlist);
6020
6021        phcb->callProgress(je->cid, &info);
6022
6023        if (rca)
6024        {
6025                ph_refer_notify(rca->rdid, s, "Server failure", 1);
6026        }
6027
6028        if (to)
6029                osip_free(to);
6030        if (from)
6031                osip_free(from);
6032
6033        if (info.hlist.elems)
6034                osip_free(info.hlist.elems);
6035}
6036
6037void
6038ph_call_globalfailure(eXosip_event_t *je)
6039{
6040        phCallStateInfo_t info;
6041        phcall_t *ca, *rca=0;
6042        char *from = 0, *to = 0;
6043        int s = 0;
6044
6045        clear(info);
6046
6047        ca = ph_locate_call(je, 0);
6048        if (ca)
6049        {
6050                rca = ph_locate_call_by_cid(ca->rcid);
6051                info.vlid = ca->vlid;
6052                ph_release_call(ca);
6053        }
6054
6055        s = ph_req_get_status(je->response);
6056        info.userData = je->external_reference;
6057        info.localUri = from = ph_req_get_from(je->response);
6058
6059        if (s == 600)
6060        {
6061                info.event = phCALLBUSY;
6062                info.remoteUri = to = ph_req_get_to(je->response);
6063        }
6064        else
6065        {
6066                info.event = phCALLERROR;
6067                info.errorCode = s;
6068        }
6069
6070        ph_apply_header_monitor(je->request, &info.hlist);
6071
6072        phcb->callProgress(je->cid, &info);
6073
6074        if (rca)
6075        {
6076                ph_refer_notify(rca->rdid, s, "Global failure", 1);
6077        }
6078
6079        if (to)
6080                osip_free(to);
6081        if (from)
6082                osip_free(from);
6083
6084        if (info.hlist.elems)
6085                osip_free(info.hlist.elems);
6086}
6087
6088void
6089ph_call_noanswer(eXosip_event_t *je, int alloc)
6090{
6091        phCallStateInfo_t info;
6092        phcall_t *ca, *rca=0;
6093        char *from = 0, *to = 0;
6094
6095
6096        clear(info);
6097
6098        ca = ph_locate_call(je, alloc);
6099        if (ca)
6100        {
6101                rca = ph_locate_call_by_cid(ca->rcid);
6102                info.vlid = ca->vlid;
6103                ph_release_call(ca);
6104        }
6105
6106        if (!ca && !alloc)
6107                return;
6108
6109        info.userData = je->external_reference;
6110        info.event = phNOANSWER;
6111        //      info.remoteUri = to = ph_req_get_to(je->response);
6112        //      info.localUri = from = ph_req_get_to(je->response);
6113
6114        ph_apply_header_monitor(je->request, &info.hlist);
6115
6116        phcb->callProgress(je->cid, &info);
6117
6118        if (rca)
6119        {
6120                ph_refer_notify(rca->rdid, ph_req_get_status(je->response), "No answer", 1);
6121        }
6122
6123        if (to)
6124                osip_free(to);
6125        if (from)
6126                osip_free(from);
6127
6128        if (info.hlist.elems)
6129                osip_free(info.hlist.elems);
6130}
6131
6132void
6133ph_call_message_new(eXosip_event_t *je)
6134{
6135        int i;
6136        osip_message_t *msg;
6137        int status = 405;
6138
6139
6140        if (MSG_IS_OPTIONS(je->request))
6141                status = 200;
6142
6143        eXosip_lock();
6144        i = eXosip_call_build_answer(je->tid, status, &msg);
6145
6146        if (!i)
6147                i = eXosip_call_send_answer(je->tid, status, msg);
6148        eXosip_unlock();
6149
6150}
6151
6152void
6153ph_call_closed(eXosip_event_t *je)
6154{
6155        phCallStateInfo_t info;
6156        phcall_t *ca, *rca=0;
6157
6158        clear(info);
6159
6160        ca = ph_locate_call(je, 0);
6161        if (ca)
6162        {
6163                rca = ph_locate_call_by_cid(ca->rcid);
6164                info.vlid = ca->vlid;
6165
6166
6167                ph_release_call(ca);
6168
6169                info.userData = je->external_reference;
6170                info.event = phCALLCLOSED;
6171                info.errorCode = 0;
6172
6173                ph_apply_header_monitor(je->request, &info.hlist);
6174                phcb->callProgress(je->cid, &info);
6175        }
6176
6177        if (rca)
6178        {
6179                ph_refer_notify(rca->rdid, ph_req_get_status(je->response), "Closed", 1);
6180        }
6181
6182        if (info.hlist.elems)
6183                osip_free(info.hlist.elems);
6184}
6185
6186
6187void
6188ph_call_onhold(eXosip_event_t *je)
6189{
6190        phCallStateInfo_t info;
6191        phcall_t *ca;
6192
6193        DBG_SIP_NEGO("SIP_NEGO: ph_call_onhold\n");
6194
6195        clear(info);
6196
6197        ca = ph_locate_call(je, 0);
6198
6199        if (!ca)
6200                return;
6201
6202        info.vlid = ca->vlid;
6203        /*if (ph_call_hasaudio(ca) || ph_call_hasvideo(ca))
6204        {
6205#ifndef MEDIA_SUSPEND
6206                ph_call_media_stop(ca);
6207#else
6208                ph_call_media_suspend(ca, 0);
6209#endif
6210        }*/
6211
6212        ca->remotehold = 1;
6213        info.userData = je->external_reference;
6214        info.event = phCALLHELD;
6215        phcb->callProgress(je->cid, &info);
6216}
6217
6218void
6219ph_call_offhold(eXosip_event_t *je)
6220{
6221        phCallStateInfo_t info;
6222        phcall_t *ca;
6223        int remotehold;
6224
6225        DBG_SIP_NEGO("SIP NEGO: ph_call_offhold\n");
6226
6227        ca = ph_locate_call(je, 0);
6228        if (!ca)
6229                return;
6230
6231        clear(info);
6232
6233        info.vlid = ca->vlid;
6234
6235        remotehold = ca->remotehold;
6236        ca->remotehold = 0;
6237
6238        /*if (ph_call_hasaudio(ca) || ph_call_hasvideo(ca)) {
6239                ph_call_retrieve_payloads(ca, -1);
6240                ph_call_media_resume(ca, !remotehold);
6241        }*/
6242
6243        if (remotehold) {
6244                info.userData = je->external_reference;
6245                info.event = phCALLRESUMED;
6246                info.streams = ca->nego_mflags;
6247
6248                if (phcb->callProgress) {
6249                        phcb->callProgress(ca->cid, &info);
6250                }
6251        }
6252}
6253
6254#define keywordcmp(key,str)  strncmp(key,str,strlen(key))
6255
6256int ph_set_media_direction( sdp_message_t * sdp, const char *media_type, enum ph_direction direction)
6257{
6258        int mline =0;
6259       
6260        for (mline=0; !sdp_message_endof_media (sdp, mline); mline++) 
6261        {
6262                const char * mtype = sdp_message_m_media_get(sdp, mline);
6263                if(!osip_strcasecmp(media_type, mtype))
6264                {
6265                        const char * sdir = ph_get_str_direction(direction);
6266                        sdp_message_a_attribute_del(sdp, mline, "inactive");
6267                        sdp_message_a_attribute_del(sdp, mline, "sendonly");
6268                        sdp_message_a_attribute_del(sdp, mline, "sendrecv");
6269                        sdp_message_a_attribute_add(sdp, mline, osip_strdup(sdir), 0);
6270                       
6271                        return 0;
6272                }
6273        }
6274        return -1;
6275}
6276
6277enum ph_direction ph_get_local_media_direction( phcall_t *ca, const char * media_type)
6278{
6279        if(!osip_strcasecmp(media_type, "audio"))
6280        {
6281                if(ca->nego_mflags & PH_STREAM_AUDIO_TX &&  ca->nego_mflags & PH_STREAM_AUDIO_RX)
6282                        return sendrecv;
6283                if(ca->nego_mflags & PH_STREAM_AUDIO_TX)
6284                        return sendonly;
6285                if(ca->nego_mflags & PH_STREAM_AUDIO_RX)
6286                        return recvonly;
6287        }
6288        else if(!osip_strcasecmp(media_type, "video"))
6289        {
6290                if(ca->nego_mflags & PH_STREAM_VIDEO_TX && ca->nego_mflags & PH_STREAM_VIDEO_RX)
6291                        return sendrecv;
6292                if(ca->nego_mflags & PH_STREAM_VIDEO_TX)
6293                        return sendonly;
6294                if(ca->nego_mflags & PH_STREAM_VIDEO_RX)
6295                        return recvonly;
6296        }
6297       
6298        return inactive;
6299}
6300
6301enum ph_direction ph_get_media_direction( sdp_message_t * sdp, const char * media_type)
6302{
6303        int mline = 0;
6304        for (mline=0; !sdp_message_endof_media (sdp, mline); mline++) 
6305        {
6306                int i =0;
6307                sdp_attribute_t *attr;
6308                const char * mtype = sdp_message_m_media_get(sdp, mline);
6309                if(!osip_strcasecmp(media_type, mtype))
6310                {
6311                        for (i=0;(attr=sdp_message_attribute_get(sdp,mline,i))!=NULL;i++) 
6312                        {
6313                                if ( keywordcmp("sendrecv",attr->a_att_field) == 0 )
6314                                {
6315                                        return sendrecv;
6316                                }
6317                                else if( keywordcmp("sendonly",attr->a_att_field) == 0 )
6318                                {
6319                                        return sendonly;
6320                                }
6321                                else if( keywordcmp("recvonly",attr->a_att_field) == 0 )
6322                                {
6323                                        return recvonly;
6324                                }
6325                                else if( keywordcmp("inactive",attr->a_att_field) == 0 )
6326                                {
6327                                        return inactive;
6328                                }
6329                        }
6330                       
6331                        return sendrecv;
6332                }
6333        }
6334        return inactive;
6335}
6336
6337int ph_update_nego_mflags( phcall_t *ca, enum ph_direction remote_audio_direction, enum ph_direction remote_video_direction)
6338{
6339        switch(remote_audio_direction)
6340        {
6341                case sendrecv:
6342                        ca->nego_mflags |= PH_STREAM_AUDIO;
6343                break;
6344               
6345                case sendonly:
6346                        ca->nego_mflags &= ~PH_STREAM_AUDIO_TX;
6347                        //ca->nego_mflags |= PH_STREAM_AUDIO_RX;
6348                break;
6349               
6350                case recvonly:
6351                        ca->nego_mflags &= ~PH_STREAM_AUDIO_RX;
6352                        ca->nego_mflags |= PH_STREAM_AUDIO_TX;
6353                break;
6354               
6355                case inactive:
6356                        ca->nego_mflags &= ~PH_STREAM_AUDIO;
6357                break;
6358        }
6359       
6360        switch(remote_video_direction)
6361        {
6362                case sendrecv:
6363                        ca->nego_mflags |= PH_STREAM_VIDEO;
6364                break;
6365               
6366                case sendonly:
6367                        ca->nego_mflags &= ~PH_STREAM_VIDEO_TX;
6368                        //ca->nego_mflags |= PH_STREAM_VIDEO_RX;
6369                break;
6370               
6371                case recvonly:
6372                        ca->nego_mflags &= ~PH_STREAM_VIDEO_RX;
6373                        ca->nego_mflags |= PH_STREAM_VIDEO_TX;
6374                break;
6375               
6376                case inactive:
6377                        ca->nego_mflags &= ~PH_STREAM_VIDEO;
6378                break;
6379        }
6380       
6381        return 0;
6382}
6383
6384const char * ph_get_str_direction( enum ph_direction direction) 
6385{
6386        switch(direction)
6387        {
6388                case sendrecv:
6389                        return "sendrecv";
6390                break;
6391               
6392                case sendonly:
6393                        return "sendonly";
6394                break;
6395               
6396                case recvonly:
6397                        return "recvonly";
6398                break;
6399               
6400                case inactive:
6401                        return "inactive";
6402                break;
6403        }
6404       
6405        return "";
6406}
6407
6408int
6409ph_call_reinvite(eXosip_event_t *je)
6410{
6411        int i = 0;
6412        int isHeld = 0;
6413        int mline = 0;
6414        phcall_t *ca = 0;
6415        sdp_message_t * sdp = 0;
6416        struct vline *vl;
6417        osip_message_t *msg = 0;
6418        char *body = NULL;
6419        struct ph_msession_s * msession;
6420       
6421        ca = ph_locate_call(je, 0);
6422
6423        if (!ca)
6424                return -PH_BADCID;
6425               
6426        vl = ph_valid_vlid(ca->vlid);
6427
6428        if (!vl)
6429                return -PH_BADVLID;
6430               
6431        msession = ca->mses;
6432               
6433        sdp = eXosip_get_sdp_info(je->request);
6434               
6435        ca->sdpctx->offer = ca->remote_sdp = sdp;
6436       
6437        i = eXosip_call_build_answer(ca->tid, 200, &msg);
6438        if (i < 0)
6439        {
6440                return -1;
6441        }
6442               
6443        osip_list_special_free(&ca->result_audio_payloads, sdp_payload_free);
6444        osip_list_special_free(&ca->result_video_payloads, sdp_payload_free);
6445       
6446        if (sdp_context_build_answer(ca->sdpctx, ca->remote_sdp, phcfg.ptime) == NULL)
6447        {
6448                eXosip_call_send_answer(ca->tid, 606, NULL); //error, no matching payload
6449                eXosip_unlock();
6450                return -1;
6451        }
6452       
6453        ph_call_media_stop(ca); 
6454        ph_update_nego_mflags(ca, ph_get_media_direction(sdp,"audio"), ph_get_media_direction(sdp,"video"));
6455        ph_set_media_direction(ca->sdpctx->answer, "audio", ph_get_local_media_direction(ca, "audio"));
6456        ph_set_media_direction(ca->sdpctx->answer, "video", ph_get_local_media_direction(ca, "video"));
6457       
6458        if (ca->sdpctx->answerstr!=NULL) {
6459                osip_free(ca->sdpctx->answerstr);
6460                ca->sdpctx->answerstr = 0;
6461        }
6462       
6463        sdp_message_to_str(ca->sdpctx->answer, &ca->sdpctx->answerstr);
6464
6465        ca->local_sdp = ca->sdpctx->answer;
6466        ph_req_set_body(msg, ca->sdpctx->answerstr, "application/sdp");
6467        i = eXosip_call_send_answer(ca->tid, 200, msg);
6468        ph_call_media_start(ca, je, 0, 0);
6469/*
6470        if(isHeld)
6471                ph_call_onhold(je);
6472        else
6473                ph_call_offhold(je);
6474*/                     
6475        return 0;
6476}
6477
6478static int ph_find_expires_for_vl(int vlid, osip_message_t *msg)
6479{
6480        osip_contact_t*  mctct;
6481        osip_contact_t*  lctct;
6482        struct vline *vl;
6483        int ret = 0;
6484        int pos = 0;
6485
6486        osip_contact_init(&lctct);
6487
6488        vl = ph_valid_vlid(vlid);
6489        if (!vl)
6490                return 0;
6491
6492        osip_contact_parse(lctct, vl->contact);
6493
6494        while(!osip_message_get_contact(msg, pos++, &mctct)) {
6495                osip_uri_param_t *param;
6496
6497                ret = ph_same_str(lctct->url->username, mctct->url->username) &&
6498                                ph_same_str(lctct->url->host, mctct->url->host) &&
6499                                ph_same_str(lctct->url->port, mctct->url->port);
6500                if (!ret)
6501                        continue;
6502
6503                ret = 0;
6504                if (!osip_contact_param_get_byname(mctct, "Expires", &param)) {
6505                        ret = atoi(param->gvalue);
6506                }
6507                break;
6508        }
6509        osip_contact_free(lctct);
6510        return ret;
6511}
6512
6513void ph_reg_progress(eXosip_event_t *je)
6514{
6515        int i;
6516        struct vline *vl = 0;
6517        int vlid;
6518        int mask = 0;
6519        int status;
6520
6521        vl =  ph_find_vline_by_rid(je->rid);
6522
6523        if (!vl)
6524                return;
6525
6526        if (vl->regTimeout == 0)
6527                mask = PH_UNREG_MASK;
6528        vlid = ph_vline2vlid(vl);
6529
6530        DBG_SIP_NEGO("REGPROGRESS reg=%d for vlid=%d\n", je->rid, vlid);
6531
6532        if (je->type == EXOSIP_REGISTRATION_SUCCESS)
6533        {
6534                int expires = ph_find_expires_for_vl(vlid, je->response);
6535
6536                if (expires) {
6537                        vl->regTimeout = expires;
6538                        eXosip_register_update_timeout(vl->rid, expires);
6539                }
6540
6541                phcb->regProgress(vlid, 0 | mask);
6542                if (vl->used == VL_DELETING)
6543                        vline_free(vl);
6544        }
6545        else if (je->type == EXOSIP_REGISTRATION_FAILURE)
6546        {
6547                int newtimeout = -1;
6548
6549                if (je->response)
6550                        status = ph_req_get_status(je->response);
6551                else status = -1;
6552
6553                if (status == 423)  /* Interval to brief */
6554                {
6555                        osip_header_t *hdr = ph_req_find_header(je->response, "Min-expires");
6556
6557                        if (hdr)
6558                        {
6559                                vl->regTimeout = newtimeout = atoi(hdr->hvalue);
6560                                eXosip_register_update_timeout(vl->rid, newtimeout);
6561                        }
6562                }
6563
6564                if (status == 401 || status == 407 || (newtimeout > 0))
6565                {
6566                        eXosip_lock();
6567                        i = eXosip_default_action(je);
6568                        eXosip_unlock();
6569
6570                        DBG_SIP_NEGO("Retrying reg=%d for vlid=%d i=%d t=%d\n", je->rid, vlid, i, newtimeout);
6571                }
6572
6573
6574                phcb->regProgress(vlid, mask | (status ? status : 500) );
6575
6576                if (vl->used == VL_DELETING)
6577                        vline_free(vl);
6578
6579        }
6580}
6581
6582void ph_notify_handler(eXosip_event_t *je)
6583{
6584        char *ctt = 0;
6585        char *evt = 0;
6586        char