return 0;
}
-static void linphone_call_init_common(LinphoneCall *call, LinphoneAddress *from, LinphoneAddress *to){
+
+static MSList *make_codec_list(const MSList *codecs, bool_t only_one_codec){
+ MSList *l=NULL;
+ const MSList *it;
+ for(it=codecs;it!=NULL;it=it->next){
+ PayloadType *pt=(PayloadType*)it->data;
+ if (pt->flags & PAYLOAD_TYPE_ENABLED){
+ l=ms_list_append(l,payload_type_clone(pt));
+ if (only_one_codec) break;
+ }
+ }
+ return l;
+}
+
+static SalMediaDescription *create_local_media_description(LinphoneCore *lc,
+ const char *localip, const char *username, bool_t only_one_codec){
+ MSList *l;
+ PayloadType *pt;
+ SalMediaDescription *md=sal_media_description_new();
+ md->nstreams=1;
+ strncpy(md->addr,localip,sizeof(md->addr));
+ strncpy(md->username,username,sizeof(md->username));
+ /*set audio capabilities */
+ strncpy(md->streams[0].addr,localip,sizeof(md->streams[0].addr));
+ md->streams[0].port=linphone_core_get_audio_port(lc);
+ md->streams[0].proto=SalProtoRtpAvp;
+ md->streams[0].type=SalAudio;
++ md->streams[0].ptime=lc->net_conf.down_ptime;
+ l=make_codec_list(lc->codecs_conf.audio_codecs,only_one_codec);
+ pt=payload_type_clone(rtp_profile_get_payload_from_mime(&av_profile,"telephone-event"));
+ l=ms_list_append(l,pt);
+ md->streams[0].payloads=l;
+
+ if (lc->dw_audio_bw>0)
+ md->streams[0].bandwidth=lc->dw_audio_bw;
+
+ if (linphone_core_video_enabled (lc)){
+ md->nstreams++;
+ md->streams[1].port=linphone_core_get_video_port(lc);
+ md->streams[1].proto=SalProtoRtpAvp;
+ md->streams[1].type=SalVideo;
+ l=make_codec_list(lc->codecs_conf.video_codecs,only_one_codec);
+ md->streams[1].payloads=l;
+ if (lc->dw_video_bw)
+ md->streams[1].bandwidth=lc->dw_video_bw;
+ }
+ return md;
+}
+
+static void linphone_call_init_common(LinphoneCall *call, LinphoneAddress *from, LinphoneAddress *to){
call->state=LCStateInit;
call->start_time=time(NULL);
call->media_start_time=0;
int linphone_core_get_upload_bandwidth(const LinphoneCore *lc){
return lc->net_conf.upload_bw;
}
-void linphone_core_set_download_ptime(LinphoneCore *lc, int ptime);
-
+ /**
+ * set audio packetization time linphone expect to received from peer
+ */
- lc->down_ptime=ptime;
+ void linphone_core_set_download_ptime(LinphoneCore *lc, int ptime) {
- return lc->down_ptime;
++ lc->net_conf.down_ptime=ptime;
+ }
++
+ int linphone_core_get_download_ptime(LinphoneCore *lc) {
++ return lc->net_conf.down_ptime;
+ }
+
/**
* Returns liblinphone's version as a string.
int linphone_proxy_config_normalize_number(LinphoneProxyConfig *cfg, const char *username, char *result, size_t result_len);
+void linphone_core_text_received(LinphoneCore *lc, const char *from, const char *msg);
+
+void linphone_core_start_media_streams(LinphoneCore *lc, struct _LinphoneCall *call);
+void linphone_core_stop_media_streams(LinphoneCore *lc, struct _LinphoneCall *call);
+const char * linphone_core_get_identity(LinphoneCore *lc);
+const char * linphone_core_get_route(LinphoneCore *lc);
+bool_t linphone_core_interpret_url(LinphoneCore *lc, const char *url, LinphoneAddress **real_parsed_url, char **route);
+void linphone_core_start_waiting(LinphoneCore *lc, const char *purpose);
+void linphone_core_update_progress(LinphoneCore *lc, const char *purpose, float progresses);
+void linphone_core_stop_waiting(LinphoneCore *lc);
+
+int linphone_core_start_invite(LinphoneCore *lc, LinphoneCall *call, LinphoneProxyConfig *dest_proxy);
+
+extern SalCallbacks linphone_sal_callbacks;
+
+
+struct _LinphoneProxyConfig
+{
+ struct _LinphoneCore *lc;
+ char *reg_proxy;
+ char *reg_identity;
+ char *reg_route;
+ char *realm;
+ int expires;
+ int reg_time;
+ SalOp *op;
+ char *type;
+ struct _SipSetupContext *ssctx;
+ int auth_failures;
+ char *dial_prefix;
+ bool_t commit;
+ bool_t reg_sendregister;
+ bool_t registered;
+ bool_t publish;
+ bool_t dial_escape_plus;
+};
+
+struct _LinphoneAuthInfo
+{
+ char *username;
+ char *realm;
+ char *userid;
+ char *passwd;
+ char *ha1;
+ int usecount;
+ bool_t works;
+};
+
+struct _LinphoneChatRoom{
+ struct _LinphoneCore *lc;
+ char *peer;
+ char *route;
+ LinphoneAddress *peer_url;
+ void * user_data;
+};
+
+struct _LinphoneFriend{
+ LinphoneAddress *uri;
+ SalOp *insub;
+ SalOp *outsub;
+ LinphoneSubscribePolicy pol;
+ LinphoneOnlineStatus status;
+ struct _LinphoneCore *lc;
+ BuddyInfo *info;
+ char *refkey;
+ bool_t subscribe;
+ bool_t inc_subscribe_pending;
+};
+
+typedef struct sip_config
+{
+ char *contact;
+ char *guessed_contact;
+ int sip_port;
+ MSList *proxies;
+ MSList *deleted_proxies;
+ int inc_timeout; /*timeout after an un-answered incoming call is rejected*/
+ bool_t use_info;
+ bool_t use_rfc2833; /*force RFC2833 to be sent*/
+ bool_t guess_hostname;
+ bool_t loopback_only;
+ bool_t ipv6_enabled;
+ bool_t sdp_200_ack;
+ bool_t only_one_codec; /*in SDP answers*/
+ bool_t register_only_when_network_is_up;
+ bool_t ping_with_options;
+} sip_config_t;
+
+typedef struct rtp_config
+{
+ int audio_rtp_port;
+ int video_rtp_port;
+ int audio_jitt_comp; /*jitter compensation*/
+ int video_jitt_comp; /*jitter compensation*/
+ int nortp_timeout;
+}rtp_config_t;
+
+
+
+typedef struct net_config
+{
+ char *nat_address;
+ char *stun_server;
+ char *relay;
+ int download_bw;
+ int upload_bw;
+ int firewall_policy;
+ int mtu;
++ int down_ptime;
+ bool_t nat_sdp_only;
+}net_config_t;
+
+
+typedef struct sound_config
+{
+ struct _MSSndCard * ring_sndcard; /* the playback sndcard currently used */
+ struct _MSSndCard * play_sndcard; /* the playback sndcard currently used */
+ struct _MSSndCard * capt_sndcard; /* the capture sndcard currently used */
+ const char **cards;
+ int latency; /* latency in samples of the current used sound device */
+ char rec_lev;
+ char play_lev;
+ char ring_lev;
+ char soft_play_lev;
+ char source;
+ char *local_ring;
+ char *remote_ring;
+ bool_t ec;
+ bool_t ea;
+ bool_t agc;
+} sound_config_t;
+
+typedef struct codecs_config
+{
+ MSList *audio_codecs; /* list of audio codecs in order of preference*/
+ MSList *video_codecs; /* for later use*/
+}codecs_config_t;
+
+typedef struct video_config{
+ struct _MSWebCam *device;
+ const char **cams;
+ MSVideoSize vsize;
+ bool_t capture;
+ bool_t show_local;
+ bool_t display;
+ bool_t selfview; /*during calls*/
+}video_config_t;
+
+typedef struct ui_config
+{
+ int is_daemon;
+ int is_applet;
+ unsigned int timer_id; /* the timer id for registration */
+}ui_config_t;
+
+
+
+typedef struct autoreplier_config
+{
+ int enabled;
+ int after_seconds; /* accept the call after x seconds*/
+ int max_users; /* maximum number of user that can call simultaneously */
+ int max_rec_time; /* the max time of incoming voice recorded */
+ int max_rec_msg; /* maximum number of recorded messages */
+ const char *message; /* the path of the file to be played */
+}autoreplier_config_t;
+
+
+struct _LinphoneCore
+{
+ LinphoneCoreVTable vtable;
+ Sal *sal;
+ struct _LpConfig *config;
+ net_config_t net_conf;
+ sip_config_t sip_conf;
+ rtp_config_t rtp_conf;
+ sound_config_t sound_conf;
+ video_config_t video_conf;
+ codecs_config_t codecs_conf;
+ ui_config_t ui_conf;
+ autoreplier_config_t autoreplier_conf;
+ LinphoneProxyConfig *default_proxy;
+ MSList *friends;
+ MSList *auth_info;
+ struct _RingStream *ringstream;
+ LCCallbackObj preview_finished_cb;
+ struct _LinphoneCall *call; /* the current call, in the future it will be a list of calls (conferencing)*/
+ MSList *queued_calls; /* used by the autoreplier */
+ MSList *call_logs;
+ MSList *chatrooms;
+ int max_call_logs;
+ int missed_calls;
+ struct _AudioStream *audiostream; /**/
+ struct _VideoStream *videostream;
+ struct _VideoStream *previewstream;
+ RtpTransport *a_rtp,*a_rtcp;
+ MSList *bl_reqs;
+ MSList *subscribers; /* unknown subscribers */
+ int minutes_away;
+ LinphoneOnlineStatus presence_mode;
+ LinphoneOnlineStatus prev_mode;
+ char *alt_contact;
+ void *data;
+ char *play_file;
+ char *rec_file;
+ time_t prevtime;
+ int dw_audio_bw;
+ int up_audio_bw;
+ int dw_video_bw;
+ int up_video_bw;
+ int audio_bw;
+ gstate_t gstate_power;
+ gstate_t gstate_reg;
+ gstate_t gstate_call;
+ LinphoneWaitingCallback wait_cb;
+ void *wait_ctx;
+ bool_t use_files;
+ bool_t apply_nat_settings;
+ bool_t ready;
+ bool_t bl_refresh;
+ bool_t preview_finished;
+ bool_t auto_net_state_mon;
+ bool_t network_reachable;
+};
+
#endif /* _PRIVATE_H */
--- /dev/null
+/*
+linphone
+Copyright (C) 2010 Simon MORLAT (simon.morlat@free.fr)
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+
+#include "ortp/b64.h"
+#include "sal.h"
+#include <eXosip2/eXosip.h>
+
+#define keywordcmp(key,b) strncmp(key,b,sizeof(key))
+
+#ifdef FOR_LATER
+
+static char *make_relay_session_id(const char *username, const char *relay){
+ /*ideally this should be a hash of the parameters with a random part*/
+ char tmp[128];
+ int s1=(int)random();
+ int s2=(int)random();
+ long long int res=((long long int)s1)<<32 | (long long int) s2;
+ void *src=&res;
+ b64_encode(src, sizeof(long long int), tmp, sizeof(tmp));
+ return osip_strdup(tmp);
+}
+
+
+static void add_relay_info(sdp_message_t *sdp, int mline, const char *relay, const char *relay_session_id){
+
+ if (relay) sdp_message_a_attribute_add(sdp, mline,
+ osip_strdup ("relay-addr"),osip_strdup(relay));
+ if (relay_session_id) sdp_message_a_attribute_add(sdp, mline,
+ osip_strdup ("relay-session-id"), osip_strdup(relay_session_id));
+}
+
+#endif
+
+static char * int_2char(int a){
+ char *p=osip_malloc(16);
+ snprintf(p,16,"%i",a);
+ return p;
+}
+
+/* return the value of attr "field" for payload pt at line pos (field=rtpmap,fmtp...)*/
+static const char *sdp_message_a_attr_value_get_with_pt(sdp_message_t *sdp,int pos,int pt,const char *field)
+{
+ int i,tmppt=0,scanned=0;
+ char *tmp;
+ sdp_attribute_t *attr;
+ for (i=0;(attr=sdp_message_attribute_get(sdp,pos,i))!=NULL;i++){
+ if (keywordcmp(field,attr->a_att_field)==0 && attr->a_att_value!=NULL){
+ int nb = sscanf(attr->a_att_value,"%i %n",&tmppt,&scanned);
+ /* the return value may depend on how %n is interpreted by the libc: see manpage*/
+ if (nb == 1 || nb==2 ){
+ if (pt==tmppt){
+ tmp=attr->a_att_value+scanned;
+ if (strlen(tmp)>0)
+ return tmp;
+ }
+ }else ms_warning("sdp has a strange a= line (%s) nb=%i",attr->a_att_value,nb);
+ }
+ }
+ return NULL;
+}
+
+#ifdef FOR_LATER
+/* return the value of attr "field" */
+static const char *sdp_message_a_attr_value_get(sdp_message_t *sdp,int pos,const char *field)
+{
+ int i;
+ sdp_attribute_t *attr;
+ for (i=0;(attr=sdp_message_attribute_get(sdp,pos,i))!=NULL;i++){
+ if (keywordcmp(field,attr->a_att_field)==0 && attr->a_att_value!=NULL){
+ return attr->a_att_value;
+ }
+ }
+ return NULL;
+}
+#endif
+
+static int _sdp_message_get_a_ptime(sdp_message_t *sdp, int mline){
+ int i,ret;
+ sdp_attribute_t *attr;
+ for (i=0;(attr=sdp_message_attribute_get(sdp,mline,i))!=NULL;i++){
+ if (keywordcmp("ptime",attr->a_att_field)==0){
+ int nb = sscanf(attr->a_att_value,"%i",&ret);
+ /* the return value may depend on how %n is interpreted by the libc: see manpage*/
+ if (nb == 1){
+ return ret;
+ }else ms_warning("sdp has a strange a=ptime line (%s) ",attr->a_att_value);
+ }
+ }
+ return 0;
+}
+
+static sdp_message_t *create_generic_sdp(const SalMediaDescription *desc)
+{
+ sdp_message_t *local;
+ int inet6;
+
+ sdp_message_init (&local);
+ if (strchr(desc->addr,':')!=NULL){
+ inet6=1;
+ }else inet6=0;
+ sdp_message_v_version_set (local, osip_strdup ("0"));
+ sdp_message_o_origin_set (local, osip_strdup (desc->username),
+ osip_strdup ("123456"), osip_strdup ("654321"),
+ osip_strdup ("IN"), inet6 ? osip_strdup("IP6") : osip_strdup ("IP4"),
+ osip_strdup (desc->addr));
+ sdp_message_s_name_set (local, osip_strdup ("A conversation"));
+ sdp_message_c_connection_add (local, -1,
+ osip_strdup ("IN"), inet6 ? osip_strdup ("IP6") : osip_strdup ("IP4"),
+ osip_strdup (desc->addr), NULL, NULL);
+ sdp_message_t_time_descr_add (local, osip_strdup ("0"), osip_strdup ("0"));
+ return local;
+}
+
+
+
+static void add_payload(sdp_message_t *msg, int line, const PayloadType *pt)
+{
+ char attr[256];
+ sdp_message_m_payload_add (msg,line, int_2char (payload_type_get_number(pt)));
+ if (pt->channels>0)
+ snprintf (attr,sizeof(attr),"%i %s/%i/%i", payload_type_get_number(pt),
+ pt->mime_type, pt->clock_rate,pt->channels);
+ else
+ snprintf (attr,sizeof(attr),"%i %s/%i", payload_type_get_number(pt),
+ pt->mime_type, pt->clock_rate);
+ sdp_message_a_attribute_add (msg, line,
+ osip_strdup ("rtpmap"), osip_strdup(attr));
+
+ if (pt->recv_fmtp != NULL)
+ {
+ snprintf (attr,sizeof(attr),"%i %s", payload_type_get_number(pt),pt->recv_fmtp);
+ sdp_message_a_attribute_add (msg, line, osip_strdup ("fmtp"),
+ osip_strdup(attr));
+ }
+}
+
+
+static void add_line(sdp_message_t *msg, int lineno, const SalStreamDescription *desc){
+ const char *mt=desc->type==SalAudio ? "audio" : "video";
+ const MSList *elem;
+ const char *addr;
+ int port;
+ if (desc->candidates[0].addr[0]!='\0'){
+ addr=desc->candidates[0].addr;
+ port=desc->candidates[0].port;
+ }else{
+ addr=desc->addr;
+ port=desc->port;
+ }
+ /*only add a c= line within the stream description if address are differents*/
+ if (strcmp(addr,sdp_message_c_addr_get(msg, -1, 0))!=0){
+ bool_t inet6;
+ if (strchr(addr,':')!=NULL){
+ inet6=TRUE;
+ }else inet6=FALSE;
+ sdp_message_c_connection_add (msg, lineno,
+ osip_strdup ("IN"), inet6 ? osip_strdup ("IP6") : osip_strdup ("IP4"),
+ osip_strdup (addr), NULL, NULL);
+ }
+ sdp_message_m_media_add (msg, osip_strdup (mt),
+ int_2char (port), NULL,
+ osip_strdup ("RTP/AVP"));
+ if (desc->bandwidth>0) sdp_message_b_bandwidth_add (msg, lineno, osip_strdup ("AS"),
+ int_2char(desc->bandwidth));
++ if (desc->ptime>0) sdp_message_a_attribute_add(msg,lineno,osip_strdup("ptime"),
++ int_2char(desc->ptime));
+ for(elem=desc->payloads;elem!=NULL;elem=elem->next){
+ add_payload(msg, lineno, (PayloadType*)elem->data);
+ }
+}
+
+sdp_message_t *media_description_to_sdp(const SalMediaDescription *desc){
+ int i;
+ sdp_message_t *msg=create_generic_sdp(desc);
+ for(i=0;i<desc->nstreams;++i){
+ add_line(msg,i,&desc->streams[i]);
+ }
+ return msg;
+}
+
+static int payload_type_fill_from_rtpmap(PayloadType *pt, const char *rtpmap){
+ if (rtpmap==NULL){
+ PayloadType *refpt=rtp_profile_get_payload(&av_profile,payload_type_get_number(pt));
+ if (refpt){
+ pt->mime_type=ms_strdup(refpt->mime_type);
+ pt->clock_rate=refpt->clock_rate;
+ }else{
+ ms_error("payload number %i has no rtpmap and is unknown in AV Profile, ignored.",
+ payload_type_get_number(pt));
+ return -1;
+ }
+ }else{
+ char *mime=ms_strdup(rtpmap);
+ char *p=strchr(mime,'/');
+ if (p){
+ char *chans;
+ *p='\0';
+ p++;
+ chans=strchr(p,'/');
+ if (chans){
+ *chans='\0';
+ chans++;
+ pt->channels=atoi(chans);
+ }else pt->channels=1;
+ pt->clock_rate=atoi(p);
+ }
+ pt->mime_type=mime;
+ }
+ return 0;
+}
+
+int sdp_to_media_description(sdp_message_t *msg, SalMediaDescription *desc){
+ int i,j;
+ const char *mtype,*proto,*port,*addr,*number;
+ sdp_bandwidth_t *sbw=NULL;
+
+ addr=sdp_message_c_addr_get (msg, -1, 0);
+ if (addr)
+ strncpy(desc->addr,addr,sizeof(desc->addr));
+ /* for each m= line */
+ for (i=0; !sdp_message_endof_media (msg, i) && i<SAL_MEDIA_DESCRIPTION_MAX_STREAMS; i++)
+ {
+ SalStreamDescription *stream=&desc->streams[i];
+
+ memset(stream,0,sizeof(*stream));
+ mtype = sdp_message_m_media_get(msg, i);
+ proto = sdp_message_m_proto_get (msg, i);
+ port = sdp_message_m_port_get(msg, i);
+ stream->proto=SalProtoUnknown;
+ if (proto){
+ if (strcasecmp(proto,"RTP/AVP")==0)
+ stream->proto=SalProtoRtpAvp;
+ else if (strcasecmp(proto,"RTP/SAVP")==0){
+ stream->proto=SalProtoRtpSavp;
+ }
+ }
+ addr = sdp_message_c_addr_get (msg, i, 0);
+ if (addr != NULL)
+ strncpy(stream->addr,addr,sizeof(stream->addr));
+ if (port)
+ stream->port=atoi(port);
+
+ stream->ptime=_sdp_message_get_a_ptime(msg,i);
+ if (strcasecmp("audio", mtype) == 0){
+ stream->type=SalAudio;
+ }else if (strcasecmp("video", mtype) == 0){
+ stream->type=SalVideo;
+ }else stream->type=SalOther;
+ for(j=0;(sbw=sdp_message_bandwidth_get(msg,i,j))!=NULL;++j){
+ if (strcasecmp(sbw->b_bwtype,"AS")==0) stream->bandwidth=atoi(sbw->b_bandwidth);
+ }
+ /* for each payload type */
+ for (j=0;((number=sdp_message_m_payload_get (msg, i,j)) != NULL); j++){
+ const char *rtpmap,*fmtp;
+ int ptn=atoi(number);
+ PayloadType *pt=payload_type_new();
+ payload_type_set_number(pt,ptn);
+ /* get the rtpmap associated to this codec, if any */
+ rtpmap=sdp_message_a_attr_value_get_with_pt(msg, i,ptn,"rtpmap");
+ payload_type_fill_from_rtpmap(pt,rtpmap);
+ /* get the fmtp, if any */
+ fmtp=sdp_message_a_attr_value_get_with_pt(msg, i, ptn,"fmtp");
+ payload_type_set_send_fmtp(pt,fmtp);
+ stream->payloads=ms_list_append(stream->payloads,pt);
+ ms_message("Found payload %s/%i fmtp=%s",pt->mime_type,pt->clock_rate,
+ pt->send_fmtp ? pt->send_fmtp : "");
+ }
+ }
+ desc->nstreams=i;
+ return 0;
+}