source: verona/phapi/phapi.c @ 301:6c407bf16b7b

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

fix merge problems

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