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*/
159 bool_t sal_stream_description_equals(const SalStreamDescription *sd1, const SalStreamDescription *sd2){
160 if (sd1->proto!=sd2->proto) return FALSE;
161 if (sd1->type!=sd2->type) return FALSE;
162 if (strcmp(sd1->addr,sd2->addr)!=0) return FALSE;
163 if (sd1->port!=sd2->port) return FALSE;
164 if (!payload_list_equals(sd1->payloads,sd2->payloads)) return FALSE;
165 if (sd1->bandwidth!=sd2->bandwidth) return FALSE;
166 if (sd1->ptime!=sd2->ptime) return FALSE;
167 /* compare candidates: TODO */
168 if (sd1->dir!=sd2->dir) return FALSE;
172 bool_t sal_media_description_equals(const SalMediaDescription *md1, const SalMediaDescription *md2){
175 if (strcmp(md1->addr,md2->addr)!=0) return FALSE;
176 if (md1->nstreams!=md2->nstreams) return FALSE;
177 if (md1->bandwidth!=md2->bandwidth) return FALSE;
178 for(i=0;i<md1->nstreams;++i){
179 if (!sal_stream_description_equals(&md1->streams[i],&md2->streams[i]))
185 static void assign_string(char **str, const char *arg){
194 void sal_op_set_contact(SalOp *op, const char *contact){
195 assign_string(&((SalOpBase*)op)->contact,contact);
198 void sal_op_set_route(SalOp *op, const char *route){
199 assign_string(&((SalOpBase*)op)->route,route);
202 void sal_op_set_from(SalOp *op, const char *from){
203 assign_string(&((SalOpBase*)op)->from,from);
206 void sal_op_set_to(SalOp *op, const char *to){
207 assign_string(&((SalOpBase*)op)->to,to);
210 void sal_op_set_user_pointer(SalOp *op, void *up){
211 ((SalOpBase*)op)->user_pointer=up;
214 Sal *sal_op_get_sal(const SalOp *op){
215 return ((SalOpBase*)op)->root;
218 const char *sal_op_get_from(const SalOp *op){
219 return ((SalOpBase*)op)->from;
222 const char *sal_op_get_to(const SalOp *op){
223 return ((SalOpBase*)op)->to;
226 const char *sal_op_get_contact(const SalOp *op){
227 return ((SalOpBase*)op)->contact;
230 const char *sal_op_get_route(const SalOp *op){
231 return ((SalOpBase*)op)->route;
234 const char *sal_op_get_remote_ua(const SalOp *op){
235 return ((SalOpBase*)op)->remote_ua;
238 void *sal_op_get_user_pointer(const SalOp *op){
239 return ((SalOpBase*)op)->user_pointer;
242 const char *sal_op_get_proxy(const SalOp *op){
243 return ((SalOpBase*)op)->route;
246 const char *sal_op_get_network_origin(const SalOp *op){
247 return ((SalOpBase*)op)->origin;
250 void __sal_op_init(SalOp *b, Sal *sal){
251 memset(b,0,sizeof(SalOpBase));
252 ((SalOpBase*)b)->root=sal;
255 void __sal_op_set_network_origin(SalOp *op, const char *origin){
256 assign_string(&((SalOpBase*)op)->origin,origin);
260 void __sal_op_free(SalOp *op){
261 SalOpBase *b=(SalOpBase *)op;
283 ms_free(b->remote_ua);
287 sal_media_description_unref(b->local_media);
289 sal_media_description_unref(b->remote_media);
293 SalAuthInfo* sal_auth_info_new() {
294 return ms_new0(SalAuthInfo,1);
297 SalAuthInfo* sal_auth_info_clone(const SalAuthInfo* auth_info) {
298 SalAuthInfo* new_auth_info=sal_auth_info_new();
299 new_auth_info->username=auth_info->username?ms_strdup(auth_info->username):NULL;
300 new_auth_info->userid=auth_info->userid?ms_strdup(auth_info->userid):NULL;
301 new_auth_info->realm=auth_info->realm?ms_strdup(auth_info->realm):NULL;
302 new_auth_info->password=auth_info->password?ms_strdup(auth_info->password):NULL;
303 return new_auth_info;
306 void sal_auth_info_delete(const SalAuthInfo* auth_info) {
307 if (auth_info->username) ms_free(auth_info->username);
308 if (auth_info->userid) ms_free(auth_info->userid);
309 if (auth_info->realm) ms_free(auth_info->realm);
310 if (auth_info->password) ms_free(auth_info->password);
311 ms_free((void*)auth_info);