source: verona/phapi/phapi.c @ 294:fcfe688d3eb5

Last change on this file since 294:fcfe688d3eb5 was 294:fcfe688d3eb5, checked in by Vadim Lebedev <vadim@…>, 21 months ago

syntax error

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