SalStreamDescription *sal_media_description_find_stream(SalMediaDescription *md,
SalMediaProto proto, SalStreamType type){
int i;
- for(i=0;i<md->nstreams;++i){
+ for(i=0;i<md->n_active_streams;++i){
SalStreamDescription *ss=&md->streams[i];
if (ss->proto==proto && ss->type==type) return ss;
}
}
bool_t sal_media_description_empty(const SalMediaDescription *md){
- int i;
- for(i=0;i<md->nstreams;++i){
- const SalStreamDescription *ss=&md->streams[i];
- if (ss->rtp_port!=0) return FALSE;
- }
+ if (md->n_active_streams > 0) return FALSE;
return TRUE;
}
void sal_media_description_set_dir(SalMediaDescription *md, SalStreamDir stream_dir){
int i;
- for(i=0;i<md->nstreams;++i){
+ for(i=0;i<md->n_active_streams;++i){
SalStreamDescription *ss=&md->streams[i];
ss->dir=stream_dir;
}
int i;
/* we are looking for at least one stream with requested direction, inactive streams are ignored*/
- for(i=0;i<md->nstreams;++i){
+ for(i=0;i<md->n_active_streams;++i){
const SalStreamDescription *ss=&md->streams[i];
if (ss->dir==stream_dir) return TRUE;
/*compatibility check for phones that only used the null address and no attributes */
if (strcmp(p1->mime_type,p2->mime_type)!=0) return FALSE;
if (p1->clock_rate!=p2->clock_rate) return FALSE;
if (p1->channels!=p2->channels) return FALSE;
+ if (payload_type_get_number(p1) != payload_type_get_number(p2)) return FALSE;
/*
Do not compare fmtp right now: they are modified internally when the call is started
*/
return TRUE;
}
+static bool_t is_recv_only(PayloadType *p){
+ return (p->flags & PAYLOAD_TYPE_FLAG_CAN_RECV) && ! (p->flags & PAYLOAD_TYPE_FLAG_CAN_SEND);
+}
+
static bool_t payload_list_equals(const MSList *l1, const MSList *l2){
const MSList *e1,*e2;
for(e1=l1,e2=l2;e1!=NULL && e2!=NULL; e1=e1->next,e2=e2->next){
if (!payload_type_equals(p1,p2))
return FALSE;
}
+ if (e1!=NULL){
+ /*skip possible recv-only payloads*/
+ for(;e1!=NULL && is_recv_only((PayloadType*)e1->data);e1=e1->next){
+ ms_message("Skipping recv-only payload type...");
+ }
+ }
if (e1!=NULL || e2!=NULL){
/*means one list is longer than the other*/
return FALSE;
return TRUE;
}
-bool_t sal_stream_description_equals(const SalStreamDescription *sd1, const SalStreamDescription *sd2){
- if (sd1->proto!=sd2->proto) return FALSE;
- if (sd1->type!=sd2->type) return FALSE;
- if (strcmp(sd1->rtp_addr,sd2->rtp_addr)!=0) return FALSE;
- if (sd1->rtp_port!=sd2->rtp_port) return FALSE;
- if (strcmp(sd1->rtcp_addr,sd2->rtcp_addr)!=0) return FALSE;
- if (sd1->rtcp_port!=sd2->rtcp_port) return FALSE;
- if (!payload_list_equals(sd1->payloads,sd2->payloads)) return FALSE;
- if (sd1->bandwidth!=sd2->bandwidth) return FALSE;
- if (sd1->ptime!=sd2->ptime) return FALSE;
- /* compare candidates: TODO */
- if (sd1->dir!=sd2->dir) return FALSE;
- return TRUE;
+int sal_stream_description_equals(const SalStreamDescription *sd1, const SalStreamDescription *sd2) {
+ int result = SAL_MEDIA_DESCRIPTION_UNCHANGED;
+ int i;
+
+ /* A different proto should result in SAL_MEDIA_DESCRIPTION_NETWORK_CHANGED but the encryption change
+ needs a stream restart for now, so use SAL_MEDIA_DESCRIPTION_CODEC_CHANGED */
+ if (sd1->proto != sd2->proto) result |= SAL_MEDIA_DESCRIPTION_CODEC_CHANGED;
+ for (i = 0; i < SAL_CRYPTO_ALGO_MAX; i++) {
+ if ((sd1->crypto[i].tag != sd2->crypto[i].tag)
+ || (sd1->crypto[i].algo != sd2->crypto[i].algo)
+ || (strncmp(sd1->crypto[i].master_key, sd2->crypto[i].master_key, sizeof(sd1->crypto[i].master_key) - 1))) {
+ result |= SAL_MEDIA_DESCRIPTION_CRYPTO_CHANGED;
+ }
+ }
+
+ if (sd1->type != sd2->type) result |= SAL_MEDIA_DESCRIPTION_CODEC_CHANGED;
+ if (strcmp(sd1->rtp_addr, sd2->rtp_addr) != 0) result |= SAL_MEDIA_DESCRIPTION_NETWORK_CHANGED;
+ if (sd1->rtp_port != sd2->rtp_port) {
+ if ((sd1->rtp_port == 0) || (sd2->rtp_port == 0)) result |= SAL_MEDIA_DESCRIPTION_CODEC_CHANGED;
+ else result |= SAL_MEDIA_DESCRIPTION_NETWORK_CHANGED;
+ }
+ if (strcmp(sd1->rtcp_addr, sd2->rtcp_addr) != 0) result |= SAL_MEDIA_DESCRIPTION_NETWORK_CHANGED;
+ if (sd1->rtcp_port != sd2->rtcp_port) result |= SAL_MEDIA_DESCRIPTION_NETWORK_CHANGED;
+ if (!payload_list_equals(sd1->payloads, sd2->payloads)) result |= SAL_MEDIA_DESCRIPTION_CODEC_CHANGED;
+ if (sd1->bandwidth != sd2->bandwidth) result |= SAL_MEDIA_DESCRIPTION_CODEC_CHANGED;
+ if (sd1->ptime != sd2->ptime) result |= SAL_MEDIA_DESCRIPTION_CODEC_CHANGED;
+ if (sd1->dir != sd2->dir) result |= SAL_MEDIA_DESCRIPTION_CODEC_CHANGED;
+
+ return result;
}
-bool_t sal_media_description_equals(const SalMediaDescription *md1, const SalMediaDescription *md2){
+int sal_media_description_equals(const SalMediaDescription *md1, const SalMediaDescription *md2) {
+ int result = SAL_MEDIA_DESCRIPTION_UNCHANGED;
int i;
-
- if (strcmp(md1->addr,md2->addr)!=0) return FALSE;
- if (md1->nstreams!=md2->nstreams) return FALSE;
- if (md1->bandwidth!=md2->bandwidth) return FALSE;
- for(i=0;i<md1->nstreams;++i){
- if (!sal_stream_description_equals(&md1->streams[i],&md2->streams[i]))
- return FALSE;
+
+ if (strcmp(md1->addr, md2->addr) != 0) result |= SAL_MEDIA_DESCRIPTION_NETWORK_CHANGED;
+ if (md1->n_total_streams != md2->n_total_streams) result |= SAL_MEDIA_DESCRIPTION_CODEC_CHANGED;
+ if (md1->bandwidth != md2->bandwidth) result |= SAL_MEDIA_DESCRIPTION_CODEC_CHANGED;
+ for(i = 0; i < md1->n_total_streams; ++i){
+ result |= sal_stream_description_equals(&md1->streams[i], &md2->streams[i]);
}
- return TRUE;
+ return result;
}
static void assign_string(char **str, const char *arg){
return ((SalOpBase*)op)->contact;
}
+const char *sal_op_get_remote_contact(const SalOp *op){
+ return ((SalOpBase*)op)->remote_contact;
+}
+
const char *sal_op_get_route(const SalOp *op){
return ((SalOpBase*)op)->route;
}
assign_string(&((SalOpBase*)op)->origin,origin);
}
+void __sal_op_set_remote_contact(SalOp *op, const char *ct){
+ assign_string(&((SalOpBase*)op)->remote_contact,ct);
+}
void __sal_op_free(SalOp *op){
SalOpBase *b=(SalOpBase *)op;
ms_free(b->remote_ua);
b->remote_ua=NULL;
}
+ if (b->remote_contact){
+ ms_free(b->remote_contact);
+ b->remote_contact=NULL;
+ }
if (b->local_media)
sal_media_description_unref(b->local_media);
if (b->remote_media)
sal_media_description_unref(b->remote_media);
if (b->call_id)
- ms_free((void*)b->call_id);
+ ms_free(b->call_id);
+ if (b->custom_headers)
+ sal_custom_header_free(b->custom_headers);
ms_free(op);
}
ms_free((void*)auth_info);
}
+SalCustomHeader *sal_custom_header_append(SalCustomHeader *ch, const char *name, const char *value){
+ SalCustomHeader *h=ms_new0(SalCustomHeader,1);
+ h->header_name=ms_strdup(name);
+ h->header_value=ms_strdup(value);
+ h->node.data=h;
+ return (SalCustomHeader*)ms_list_append_link((MSList*)ch,(MSList*)h);
+}
+
+const char *sal_custom_header_find(const SalCustomHeader *ch, const char *name){
+ const MSList *it;
+ for (it=(const MSList*)ch;it!=NULL;it=it->next){
+ const SalCustomHeader *itch=(const SalCustomHeader *)it;
+ if (strcasecmp(itch->header_name,name)==0)
+ return itch->header_value;
+ }
+ return NULL;
+}
+
+static void sal_custom_header_uninit(SalCustomHeader *ch){
+ ms_free(ch->header_name);
+ ms_free(ch->header_value);
+}
+
+void sal_custom_header_free(SalCustomHeader *ch){
+ ms_list_for_each((MSList*)ch,(void (*)(void*))sal_custom_header_uninit);
+ ms_list_free((MSList *)ch);
+}
+
+SalCustomHeader *sal_custom_header_clone(const SalCustomHeader *ch){
+ const MSList *it;
+ SalCustomHeader *ret=NULL;
+ for (it=(const MSList*)ch;it!=NULL;it=it->next){
+ const SalCustomHeader *itch=(const SalCustomHeader *)it;
+ ret=sal_custom_header_append(ret,itch->header_name,itch->header_value);
+ }
+ return ret;
+}
+
+const SalCustomHeader *sal_op_get_custom_header(SalOp *op){
+ SalOpBase *b=(SalOpBase *)op;
+ return b->custom_headers;
+}
+
+/*
+ * Warning: this function takes owneship of the custom headers
+ */
+void sal_op_set_custom_header(SalOp *op, SalCustomHeader* ch){
+ SalOpBase *b=(SalOpBase *)op;
+ if (b->custom_headers){
+ sal_custom_header_free(b->custom_headers);
+ b->custom_headers=NULL;
+ }
+ b->custom_headers=ch;
+}
+
+
+