#include "sal.h"
#include "offeranswer.h"
+#include "private.h"
static bool_t only_telephone_event(const MSList *l){
- PayloadType *p=(PayloadType*)l->data;
- if (strcasecmp(p->mime_type,"telephone-event")!=0){
- return FALSE;
+ for(;l!=NULL;l=l->next){
+ PayloadType *p=(PayloadType*)l->data;
+ if (strcasecmp(p->mime_type,"telephone-event")!=0){
+ return FALSE;
+ }
}
return TRUE;
}
}
static MSList *match_payloads(const MSList *local, const MSList *remote, bool_t reading_response, bool_t one_matching_codec){
- const MSList *e2;
+ const MSList *e2,*e1;
MSList *res=NULL;
PayloadType *matched;
bool_t found_codec=FALSE;
newp=payload_type_clone(matched);
if (p2->send_fmtp)
payload_type_set_send_fmtp(newp,p2->send_fmtp);
+ newp->flags|=PAYLOAD_TYPE_FLAG_CAN_RECV|PAYLOAD_TYPE_FLAG_CAN_SEND;
res=ms_list_append(res,newp);
/* we should use the remote numbering even when parsing a response */
payload_type_set_number(newp,remote_number);
Indeed despite we must sent with the remote numbering, we must be able to receive with
our local one.
*/
- newp=payload_type_clone(matched);
+ newp=payload_type_clone(newp);
payload_type_set_number(newp,local_number);
res=ms_list_append(res,newp);
}
ms_message("No match for %s/%i",p2->mime_type,p2->clock_rate);
}
}
+ if (reading_response){
+ /* add remaning local payload as CAN_RECV only so that if we are in front of a non-compliant equipment we are still able to decode the RTP stream*/
+ for(e1=local;e1!=NULL;e1=e1->next){
+ PayloadType *p1=(PayloadType*)e1->data;
+ bool_t found=FALSE;
+ for(e2=res;e2!=NULL;e2=e2->next){
+ PayloadType *p2=(PayloadType*)e2->data;
+ if (payload_type_get_number(p2)==payload_type_get_number(p1)){
+ found=TRUE;
+ break;
+ }
+ }
+ if (!found){
+ ms_message("Adding %s/%i for compatibility, just in case.",p1->mime_type,p1->clock_rate);
+ p1=payload_type_clone(p1);
+ p1->flags|=PAYLOAD_TYPE_FLAG_CAN_RECV;
+ res=ms_list_append(res,p1);
+ }
+ }
+ }
return res;
}
+static bool_t match_crypto_algo(const SalSrtpCryptoAlgo* local, const SalSrtpCryptoAlgo* remote,
+ SalSrtpCryptoAlgo* result, unsigned int* choosen_local_tag, bool_t use_local_key) {
+ int i,j;
+ for(i=0; i<SAL_CRYPTO_ALGO_MAX; i++) {
+ if (remote[i].algo == 0)
+ break;
+
+ /* Look for a local enabled crypto algo that matches one of the proposed by remote */
+ for(j=0; j<SAL_CRYPTO_ALGO_MAX; j++) {
+ if (remote[i].algo == local[j].algo) {
+ result->algo = remote[i].algo;
+ /* We're answering an SDP offer. Supply our master key, associated with the remote supplied tag */
+ if (use_local_key) {
+ strncpy(result->master_key, local[j].master_key, 41);
+ result->tag = remote[i].tag;
+ *choosen_local_tag = local[j].tag;
+ }
+ /* We received an answer to our SDP crypto proposal. Copy matching algo remote master key to result, and memorize local tag */
+ else {
+ strncpy(result->master_key, remote[i].master_key, 41);
+ result->tag = local[j].tag;
+ *choosen_local_tag = local[j].tag;
+ }
+ result->master_key[40] = '\0';
+ return TRUE;
+ }
+ }
+ }
+ return FALSE;
+}
+
static SalStreamDir compute_dir_outgoing(SalStreamDir local, SalStreamDir answered){
static void initiate_outgoing(const SalStreamDescription *local_offer,
const SalStreamDescription *remote_answer,
SalStreamDescription *result){
- if (remote_answer->port!=0)
+ if (remote_answer->rtp_port!=0)
result->payloads=match_payloads(local_offer->payloads,remote_answer->payloads,TRUE,FALSE);
- result->proto=local_offer->proto;
+ result->proto=remote_answer->proto;
result->type=local_offer->type;
result->dir=compute_dir_outgoing(local_offer->dir,remote_answer->dir);
if (result->payloads && !only_telephone_event(result->payloads)){
- strcpy(result->addr,remote_answer->addr);
- result->port=remote_answer->port;
+ strcpy(result->rtp_addr,remote_answer->rtp_addr);
+ strcpy(result->rtcp_addr,remote_answer->rtcp_addr);
+ result->rtp_port=remote_answer->rtp_port;
+ result->rtcp_port=remote_answer->rtcp_port;
result->bandwidth=remote_answer->bandwidth;
result->ptime=remote_answer->ptime;
}else{
- result->port=0;
+ result->rtp_port=0;
+ }
+ if (result->proto == SalProtoRtpSavp) {
+ /* verify crypto algo */
+ memset(result->crypto, 0, sizeof(result->crypto));
+ if (!match_crypto_algo(local_offer->crypto, remote_answer->crypto, &result->crypto[0], &result->crypto_local_tag, FALSE))
+ result->rtp_port = 0;
}
}
const SalStreamDescription *remote_offer,
SalStreamDescription *result, bool_t one_matching_codec){
result->payloads=match_payloads(local_cap->payloads,remote_offer->payloads, FALSE, one_matching_codec);
- result->proto=local_cap->proto;
+ result->proto=remote_offer->proto;
result->type=local_cap->type;
result->dir=compute_dir_incoming(local_cap->dir,remote_offer->dir);
- if (result->payloads && !only_telephone_event(result->payloads)){
- strcpy(result->addr,local_cap->addr);
- memcpy(result->candidates,local_cap->candidates,sizeof(result->candidates));
- result->port=local_cap->port;
+ if (result->payloads && !only_telephone_event(result->payloads) && (remote_offer->rtp_port!=0 || remote_offer->rtp_port==SalStreamSendOnly)){
+ strcpy(result->rtp_addr,local_cap->rtp_addr);
+ strcpy(result->rtcp_addr,local_cap->rtcp_addr);
+ result->rtp_port=local_cap->rtp_port;
+ result->rtcp_port=local_cap->rtcp_port;
result->bandwidth=local_cap->bandwidth;
- result->ptime=local_cap->ptime;
+ result->ptime=local_cap->ptime;
}else{
- result->port=0;
+ result->rtp_port=0;
+ }
+ if (result->proto == SalProtoRtpSavp) {
+ /* select crypto algo */
+ memset(result->crypto, 0, sizeof(result->crypto));
+ if (!match_crypto_algo(local_cap->crypto, remote_offer->crypto, &result->crypto[0], &result->crypto_local_tag, TRUE))
+ result->rtp_port = 0;
+
}
+ strcpy(result->ice_pwd, local_cap->ice_pwd);
+ strcpy(result->ice_ufrag, local_cap->ice_ufrag);
+ result->ice_mismatch = local_cap->ice_mismatch;
+ result->ice_completed = local_cap->ice_completed;
+ memcpy(result->ice_candidates, local_cap->ice_candidates, sizeof(result->ice_candidates));
+ memcpy(result->ice_remote_candidates, local_cap->ice_remote_candidates, sizeof(result->ice_remote_candidates));
}
/**
* and the returned response (remote).
**/
int offer_answer_initiate_outgoing(const SalMediaDescription *local_offer,
- const SalMediaDescription *remote_answer,
- SalMediaDescription *result){
- int i,j;
+ const SalMediaDescription *remote_answer,
+ SalMediaDescription *result){
+ int i,j;
+
const SalStreamDescription *ls,*rs;
- for(i=0,j=0;i<local_offer->nstreams;++i){
+ for(i=0,j=0;i<local_offer->n_total_streams;++i){
ms_message("Processing for stream %i",i);
ls=&local_offer->streams[i];
rs=sal_media_description_find_stream((SalMediaDescription*)remote_answer,ls->proto,ls->type);
- if (rs) {
+ if (rs) {
initiate_outgoing(ls,rs,&result->streams[j]);
++j;
}
else ms_warning("No matching stream for %i",i);
- }
- result->nstreams=j;
+ }
+ result->n_active_streams=j;
+ result->n_total_streams=local_offer->n_total_streams;
result->bandwidth=remote_answer->bandwidth;
strcpy(result->addr,remote_answer->addr);
return 0;
* The returned media description is an answer and should be sent to the offerer.
**/
int offer_answer_initiate_incoming(const SalMediaDescription *local_capabilities,
- const SalMediaDescription *remote_offer,
- SalMediaDescription *result, bool_t one_matching_codec){
- int i;
- const SalStreamDescription *ls,*rs;
-
- for(i=0;i<remote_offer->nstreams;++i){
+ const SalMediaDescription *remote_offer,
+ SalMediaDescription *result, bool_t one_matching_codec){
+ int i;
+ const SalStreamDescription *ls=NULL,*rs;
+
+ result->n_active_streams=0;
+ for(i=0;i<remote_offer->n_total_streams;++i){
rs=&remote_offer->streams[i];
- ms_message("Processing for stream %i",i);
- ls=sal_media_description_find_stream((SalMediaDescription*)local_capabilities,rs->proto,rs->type);
+ if (rs->proto!=SalProtoUnknown){
+ ls=sal_media_description_find_stream((SalMediaDescription*)local_capabilities,rs->proto,rs->type);
+ /* if matching failed, and remote proposes Avp only, ask for local Savp streams */
+ if (!ls && rs->proto == SalProtoRtpAvp) {
+ ls=sal_media_description_find_stream((SalMediaDescription*)local_capabilities,SalProtoRtpSavp,rs->type);
+ }
+ }else ms_warning("Unknown protocol for mline %i, declining",i);
if (ls){
- initiate_incoming(ls,rs,&result->streams[i],one_matching_codec);
- } else {
- /* create an inactive stream for the answer, as there where no matching stream a local capability */
+ initiate_incoming(ls,rs,&result->streams[i],one_matching_codec);
+ if (result->streams[i].rtp_port!=0) result->n_active_streams++;
+ }else {
+ /* create an inactive stream for the answer, as there where no matching stream in local capabilities */
result->streams[i].dir=SalStreamInactive;
- result->streams[i].port=0;
+ result->streams[i].rtp_port=0;
result->streams[i].type=rs->type;
+ result->streams[i].proto=rs->proto;
if (rs->type==SalOther){
strncpy(result->streams[i].typeother,rs->typeother,sizeof(rs->typeother)-1);
}
}
- }
- result->nstreams=i;
+ }
+ result->n_total_streams=i;
strcpy(result->username, local_capabilities->username);
strcpy(result->addr,local_capabilities->addr);
result->bandwidth=local_capabilities->bandwidth;
result->session_ver=local_capabilities->session_ver;
result->session_id=local_capabilities->session_id;
+ strcpy(result->ice_pwd, local_capabilities->ice_pwd);
+ strcpy(result->ice_ufrag, local_capabilities->ice_ufrag);
+ result->ice_lite = local_capabilities->ice_lite;
+ result->ice_completed = local_capabilities->ice_completed;
return 0;
}