3 Copyright (C) 2010 Simon MORLAT (simon.morlat@free.fr)
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License
7 as published by the Free Software Foundation; either version 2
8 of the License, or (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21 This header files defines the Signaling Abstraction Layer.
22 The purpose of this layer is too allow experiment different call signaling
23 protocols and implementations under linphone, for example SIP, JINGLE...
28 SalMediaDescription *sal_media_description_new(){
29 SalMediaDescription *md=ms_new0(SalMediaDescription,1);
34 static void sal_media_description_destroy(SalMediaDescription *md){
36 for(i=0;i<SAL_MEDIA_DESCRIPTION_MAX_STREAMS;i++){
37 ms_list_for_each(md->streams[i].payloads,(void (*)(void *))payload_type_destroy);
38 ms_list_free(md->streams[i].payloads);
39 md->streams[i].payloads=NULL;
44 void sal_media_description_ref(SalMediaDescription *md){
48 void sal_media_description_unref(SalMediaDescription *md){
51 sal_media_description_destroy (md);
55 SalStreamDescription *sal_media_description_find_stream(SalMediaDescription *md,
56 SalMediaProto proto, SalStreamType type){
58 for(i=0;i<md->nstreams;++i){
59 SalStreamDescription *ss=&md->streams[i];
60 if (ss->proto==proto && ss->type==type) return ss;
65 bool_t sal_media_description_empty(const SalMediaDescription *md){
67 for(i=0;i<md->nstreams;++i){
68 const SalStreamDescription *ss=&md->streams[i];
69 if (ss->port!=0) return FALSE;
74 void sal_media_description_set_dir(SalMediaDescription *md, SalStreamDir stream_dir){
76 for(i=0;i<md->nstreams;++i){
77 SalStreamDescription *ss=&md->streams[i];
83 static bool_t is_null_address(const char *addr){
84 return strcmp(addr,"0.0.0.0")==0 || strcmp(addr,"::0")==0;
87 /*check for the presence of at least one stream with requested direction */
88 static bool_t has_dir(const SalMediaDescription *md, SalStreamDir stream_dir){
91 /* we are looking for at least one stream with requested direction, inactive streams are ignored*/
92 for(i=0;i<md->nstreams;++i){
93 const SalStreamDescription *ss=&md->streams[i];
94 if (ss->dir==stream_dir) return TRUE;
95 if (stream_dir==SalStreamSendOnly && (is_null_address(md->addr) || is_null_address(ss->addr)))
101 bool_t sal_media_description_has_dir(const SalMediaDescription *md, SalStreamDir stream_dir){
102 if (stream_dir==SalStreamRecvOnly){
103 if (has_dir(md,SalStreamSendOnly) || has_dir(md,SalStreamSendRecv)) return FALSE;
105 }else if (stream_dir==SalStreamSendOnly){
106 if (has_dir(md,SalStreamRecvOnly) || has_dir(md,SalStreamSendRecv)) return FALSE;
108 }else if (stream_dir==SalStreamSendRecv){
109 return has_dir(md,SalStreamSendRecv);
111 /*SalStreamInactive*/
112 if (has_dir(md,SalStreamSendOnly) || has_dir(md,SalStreamSendRecv) || has_dir(md,SalStreamRecvOnly))
120 static bool_t fmtp_equals(const char *p1, const char *p2){
121 if (p1 && p2 && strcmp(p1,p2)==0) return TRUE;
122 if (p1==NULL && p2==NULL) return TRUE;
127 static bool_t payload_type_equals(const PayloadType *p1, const PayloadType *p2){
128 if (p1->type!=p2->type) return FALSE;
129 if (strcmp(p1->mime_type,p2->mime_type)!=0) return FALSE;
130 if (p1->clock_rate!=p2->clock_rate) return FALSE;
131 if (p1->channels!=p2->channels) return FALSE;
133 Do not compare fmtp right now: they are modified internally when the call is started
136 if (!fmtp_equals(p1->recv_fmtp,p2->recv_fmtp) ||
137 !fmtp_equals(p1->send_fmtp,p2->send_fmtp))
143 static bool_t payload_list_equals(const MSList *l1, const MSList *l2){
144 const MSList *e1,*e2;
145 for(e1=l1,e2=l2;e1!=NULL && e2!=NULL; e1=e1->next,e2=e2->next){
146 PayloadType *p1=(PayloadType*)e1->data;
147 PayloadType *p2=(PayloadType*)e2->data;
148 if (!payload_type_equals(p1,p2))
151 if (e1!=NULL || e2!=NULL){
152 /*means one list is longer than the other*/
158 bool_t sal_stream_description_equals(const SalStreamDescription *sd1, const SalStreamDescription *sd2){
159 if (sd1->proto!=sd2->proto) return FALSE;
160 if (sd1->type!=sd2->type) return FALSE;
161 if (strcmp(sd1->addr,sd2->addr)!=0) return FALSE;
162 if (sd1->port!=sd2->port) return FALSE;
163 if (!payload_list_equals(sd1->payloads,sd2->payloads)) return FALSE;
164 if (sd1->bandwidth!=sd2->bandwidth) return FALSE;
165 if (sd1->ptime!=sd2->ptime) return FALSE;
166 /* compare candidates: TODO */
167 if (sd1->dir!=sd2->dir) return FALSE;
171 bool_t sal_media_description_equals(const SalMediaDescription *md1, const SalMediaDescription *md2){
174 if (strcmp(md1->addr,md2->addr)!=0) return FALSE;
175 if (md1->nstreams!=md2->nstreams) return FALSE;
176 if (md1->bandwidth!=md2->bandwidth) return FALSE;
177 for(i=0;i<md1->nstreams;++i){
178 if (!sal_stream_description_equals(&md1->streams[i],&md2->streams[i]))
184 static void assign_string(char **str, const char *arg){
193 void sal_op_set_contact(SalOp *op, const char *contact){
194 assign_string(&((SalOpBase*)op)->contact,contact);
197 void sal_op_set_route(SalOp *op, const char *route){
198 assign_string(&((SalOpBase*)op)->route,route);
201 void sal_op_set_from(SalOp *op, const char *from){
202 assign_string(&((SalOpBase*)op)->from,from);
205 void sal_op_set_to(SalOp *op, const char *to){
206 assign_string(&((SalOpBase*)op)->to,to);
209 void sal_op_set_user_pointer(SalOp *op, void *up){
210 ((SalOpBase*)op)->user_pointer=up;
213 Sal *sal_op_get_sal(const SalOp *op){
214 return ((SalOpBase*)op)->root;
217 const char *sal_op_get_from(const SalOp *op){
218 return ((SalOpBase*)op)->from;
221 const char *sal_op_get_to(const SalOp *op){
222 return ((SalOpBase*)op)->to;
225 const char *sal_op_get_contact(const SalOp *op){
226 return ((SalOpBase*)op)->contact;
229 const char *sal_op_get_route(const SalOp *op){
230 return ((SalOpBase*)op)->route;
233 const char *sal_op_get_remote_ua(const SalOp *op){
234 return ((SalOpBase*)op)->remote_ua;
237 void *sal_op_get_user_pointer(const SalOp *op){
238 return ((SalOpBase*)op)->user_pointer;
241 const char *sal_op_get_proxy(const SalOp *op){
242 return ((SalOpBase*)op)->route;
245 const char *sal_op_get_network_origin(const SalOp *op){
246 return ((SalOpBase*)op)->origin;
249 void __sal_op_init(SalOp *b, Sal *sal){
250 memset(b,0,sizeof(SalOpBase));
251 ((SalOpBase*)b)->root=sal;
254 void __sal_op_set_network_origin(SalOp *op, const char *origin){
255 assign_string(&((SalOpBase*)op)->origin,origin);
259 void __sal_op_free(SalOp *op){
260 SalOpBase *b=(SalOpBase *)op;
282 ms_free(b->remote_ua);
286 sal_media_description_unref(b->local_media);
288 sal_media_description_unref(b->remote_media);
292 SalAuthInfo* sal_auth_info_new() {
293 return ms_new0(SalAuthInfo,1);
296 SalAuthInfo* sal_auth_info_clone(const SalAuthInfo* auth_info) {
297 SalAuthInfo* new_auth_info=sal_auth_info_new();
298 new_auth_info->username=auth_info->username?ms_strdup(auth_info->username):NULL;
299 new_auth_info->userid=auth_info->userid?ms_strdup(auth_info->userid):NULL;
300 new_auth_info->realm=auth_info->realm?ms_strdup(auth_info->realm):NULL;
301 new_auth_info->password=auth_info->password?ms_strdup(auth_info->password):NULL;
302 return new_auth_info;
305 void sal_auth_info_delete(const SalAuthInfo* auth_info) {
306 if (auth_info->username) ms_free(auth_info->username);
307 if (auth_info->userid) ms_free(auth_info->userid);
308 if (auth_info->realm) ms_free(auth_info->realm);
309 if (auth_info->password) ms_free(auth_info->password);
310 ms_free((void*)auth_info);