mirror of
https://gitlab.linphone.org/BC/public/linphone-iphone.git
synced 2026-01-29 17:29:20 +00:00
SAL (signaling abstraction layer) in progress.
This commit is contained in:
parent
1d96392aa4
commit
39ff61f803
6 changed files with 619 additions and 0 deletions
|
|
@ -16,6 +16,9 @@ lib_LTLIBRARIES=liblinphone.la
|
|||
liblinphone_la_SOURCES=\
|
||||
linphonecore.c linphonecore.h private.h\
|
||||
exevents.c exevents.h \
|
||||
offeranswer.c offeranswer.h\
|
||||
sal_eXosip2.c sal.h \
|
||||
sal_eXosip2_sdp.c \
|
||||
misc.c \
|
||||
address.c \
|
||||
enum.c enum.h \
|
||||
|
|
|
|||
142
linphone/coreapi/offeranswer.c
Normal file
142
linphone/coreapi/offeranswer.c
Normal file
|
|
@ -0,0 +1,142 @@
|
|||
/*
|
||||
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 "sal.h"
|
||||
#include "offeranswer.h"
|
||||
|
||||
|
||||
static PayloadType * find_payload_type_best_match(const MSList *l, const PayloadType *refpt){
|
||||
PayloadType *pt;
|
||||
char value[10];
|
||||
const MSList *elem;
|
||||
PayloadType *candidate=NULL;
|
||||
|
||||
for (elem=l;elem!=NULL;elem=elem->next){
|
||||
pt=(PayloadType*)elem->data;
|
||||
if (strcasecmp(pt->mime_type,refpt->mime_type)==0 && pt->clock_rate==refpt->clock_rate){
|
||||
candidate=pt;
|
||||
/*good candidate, check fmtp for H264 */
|
||||
if (strcasecmp(pt->mime_type,"H264")==0){
|
||||
if (pt->recv_fmtp!=NULL && refpt->recv_fmtp!=NULL){
|
||||
int mode1=0,mode2=0;
|
||||
if (fmtp_get_value(pt->recv_fmtp,"packetization-mode",value,sizeof(value))){
|
||||
mode1=atoi(value);
|
||||
}
|
||||
if (fmtp_get_value(refpt->recv_fmtp,"packetization-mode",value,sizeof(value))){
|
||||
mode2=atoi(value);
|
||||
}
|
||||
if (mode1==mode2)
|
||||
break; /*exact match */
|
||||
}
|
||||
}else break;
|
||||
}
|
||||
}
|
||||
return candidate;
|
||||
}
|
||||
|
||||
static MSList *match_payloads(const MSList *local, const MSList *remote){
|
||||
const MSList *e2;
|
||||
MSList *res=NULL;
|
||||
PayloadType *matched;
|
||||
for(e2=remote;e2!=NULL;e2=e2->next){
|
||||
PayloadType *p2=(PayloadType*)e2->data;
|
||||
matched=find_payload_type_best_match(local,p2);
|
||||
if (matched){
|
||||
matched=payload_type_clone(matched);
|
||||
if (p2->recv_fmtp)
|
||||
payload_type_set_send_fmtp(matched,p2->recv_fmtp);
|
||||
res=ms_list_append(res,matched);
|
||||
payload_type_set_number(matched,payload_type_get_number(p2));
|
||||
}else{
|
||||
ms_message("No match for %s/%i",p2->mime_type,p2->clock_rate);
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static bool_t only_telephone_event(const MSList *l){
|
||||
for(;l!=NULL;l=l->next){
|
||||
PayloadType *p=(PayloadType*)l->data;
|
||||
if (strcasecmp(p->mime_type,"telephone-event")!=0){
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void initiate_outgoing(const SalStreamDescription *local_offer,
|
||||
const SalStreamDescription *remote_answer,
|
||||
SalStreamDescription *result){
|
||||
result->payloads=match_payloads(local_offer->payloads,remote_answer->payloads);
|
||||
if (result->payloads && !only_telephone_event(result->payloads)){
|
||||
result->port=remote_answer->port;
|
||||
result->bandwidth=remote_answer->bandwidth;
|
||||
result->ptime=remote_answer->ptime;
|
||||
}else{
|
||||
result->port=0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void initiate_incoming(const SalStreamDescription *local_cap,
|
||||
const SalStreamDescription *remote_offer,
|
||||
SalStreamDescription *result){
|
||||
result->payloads=match_payloads(local_cap->payloads,remote_offer->payloads);
|
||||
if (result->payloads && !only_telephone_event(result->payloads)){
|
||||
result->port=remote_offer->port;
|
||||
result->bandwidth=remote_offer->bandwidth;
|
||||
result->ptime=remote_offer->ptime;
|
||||
}else{
|
||||
result->port=0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a media description to run the streams with, based on a local offer
|
||||
* and the returned response (remote).
|
||||
**/
|
||||
int offer_answer_initiate_outgoing(const SalMediaDescription *local_offer,
|
||||
const SalMediaDescription *remote_answer,
|
||||
SalMediaDescription *result){
|
||||
int i;
|
||||
for(i=0;i<local_offer->nstreams;++i){
|
||||
initiate_outgoing(&local_offer->streams[i],&remote_answer->streams[i],&result->streams[i]);
|
||||
}
|
||||
result->nstreams=local_offer->nstreams;
|
||||
strcpy(result->addr,remote_answer->addr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a media description to run the streams with, based on the local capabilities and
|
||||
* and the received offer.
|
||||
* 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){
|
||||
int i;
|
||||
for(i=0;i<local_capabilities->nstreams;++i){
|
||||
initiate_incoming(&local_capabilities->streams[i],&remote_offer->streams[i],&result->streams[i]);
|
||||
}
|
||||
result->nstreams=local_capabilities->nstreams;
|
||||
strcpy(result->addr,remote_offer->addr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
47
linphone/coreapi/offeranswer.h
Normal file
47
linphone/coreapi/offeranswer.h
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef offeranswer_h
|
||||
#define offeranswer_h
|
||||
|
||||
/**
|
||||
This header files defines the SDP offer answer API.
|
||||
It can be used by implementations of SAL directly.
|
||||
**/
|
||||
|
||||
|
||||
/**
|
||||
* Returns a media description to run the streams with, based on a local offer
|
||||
* and the returned response (remote).
|
||||
**/
|
||||
int offer_answer_initiate_outgoing(const SalMediaDescription *local_offer,
|
||||
const SalMediaDescription *remote_answer,
|
||||
SalMediaDescription *result);
|
||||
|
||||
/**
|
||||
* Returns a media description to run the streams with, based on the local capabilities and
|
||||
* and the received offer.
|
||||
* 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);
|
||||
|
||||
#endif
|
||||
|
||||
104
linphone/coreapi/sal.h
Normal file
104
linphone/coreapi/sal.h
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
/**
|
||||
This header files defines the Signaling Abstraction Layer.
|
||||
The purpose of this layer is too allow experiment different call signaling
|
||||
protocols and implementations under linphone, for example SIP, JINGLE...
|
||||
**/
|
||||
|
||||
#ifndef sal_h
|
||||
#define sal_h
|
||||
|
||||
#include "mediastreamer2/mscommon.h"
|
||||
|
||||
struct Sal;
|
||||
|
||||
typedef struct Sal Sal;
|
||||
|
||||
struct SalOp;
|
||||
|
||||
typedef struct SalOp SalOp;
|
||||
|
||||
Sal * sal_init();
|
||||
void sal_uninit(Sal* sal);
|
||||
|
||||
typedef enum {
|
||||
SAL_TRANSPORT_DATAGRAM,
|
||||
SAL_TRANSPORT_STREAM
|
||||
}SalTransport;
|
||||
|
||||
typedef enum {
|
||||
SAL_AUDIO,
|
||||
SAL_VIDEO,
|
||||
SAL_OTHER
|
||||
} SalStreamType;
|
||||
|
||||
typedef struct SalStreamDescription{
|
||||
SalStreamType type;
|
||||
int port;
|
||||
MSList *payloads; //<list of PayloadType
|
||||
int bandwidth;
|
||||
int ptime;
|
||||
} SalStreamDescription;
|
||||
|
||||
typedef struct SalMediaDescription{
|
||||
char addr[64];
|
||||
char username[64];
|
||||
int nstreams;
|
||||
SalStreamDescription streams[2];
|
||||
} SalMediaDescription;
|
||||
|
||||
void sal_media_description_free(SalMediaDescription *md);
|
||||
|
||||
typedef enum SalError{
|
||||
SalErrorNetwork,
|
||||
SalErrorMedia,
|
||||
SalErrorAuth,
|
||||
SalErrorForbidden
|
||||
} SalError;
|
||||
|
||||
typedef void (*SalOnCallReceived)(SalOp *op);
|
||||
typedef void (*SalOnCallRinging)(SalOp *op);
|
||||
typedef void (*SalOnCallAccepted)(SalOp *op);
|
||||
typedef void (*SalOnCallTerminated)(SalOp *op);
|
||||
typedef void (*SalOnCallFailure)(SalOp *op, SalError error, const char *details);
|
||||
|
||||
int sal_listen_port(Sal *ctx, const char *addr, int port, SalTransport tr, int is_secure);
|
||||
void sal_set_user_agent(Sal *ctx, const char *user_agent);
|
||||
void sal_use_session_timers(Sal *ctx, int expires);
|
||||
|
||||
SalOp * sal_call_create(Sal *sal, const char *from, const char *to, const char *route, const char *contact);
|
||||
int sal_call_set_local_media_description(SalOp *h, const SalMediaDescription *desc);
|
||||
int sal_call(SalOp *h);
|
||||
int sal_call_accept(SalOp*h);
|
||||
int sal_call_get_final_media_description(SalOp *h, SalMediaDescription *result);
|
||||
int sal_call_terminate(SalOp *h);
|
||||
|
||||
int sal_iterate(Sal *sal);
|
||||
|
||||
SalOp *sal_register_create(Sal *ctx, const char *from, const char *contact, int expires);
|
||||
int sal_register(SalOp *h);
|
||||
|
||||
void sal_op_release(SalOp *h);
|
||||
|
||||
#define payload_type_set_number(pt,n) (pt)->user_data=(void*)((long)n);
|
||||
#define payload_type_get_number(pt) ((int)(long)(pt)->user_data)
|
||||
|
||||
#endif
|
||||
153
linphone/coreapi/sal_eXosip2.c
Normal file
153
linphone/coreapi/sal_eXosip2.c
Normal file
|
|
@ -0,0 +1,153 @@
|
|||
/*
|
||||
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 "sal.h"
|
||||
#include <eXosip2/eXosip.h>
|
||||
|
||||
extern char *media_description_to_sdp(const SalMediaDescription *sal);
|
||||
|
||||
struct Sal{
|
||||
int running;
|
||||
int session_expires;
|
||||
};
|
||||
|
||||
struct SalOp{
|
||||
int cid;
|
||||
int did;
|
||||
int tid;
|
||||
osip_message_t *request;
|
||||
};
|
||||
|
||||
static SalOp * sal_op_new(){
|
||||
SalOp *op=ms_new(SalOp,1);
|
||||
op->cid=op->did=op->tid=-1;
|
||||
op->request=NULL;
|
||||
return op;
|
||||
}
|
||||
|
||||
void sal_op_release(SalOp *op){
|
||||
ms_free(op);
|
||||
}
|
||||
|
||||
Sal * sal_init(){
|
||||
eXosip_init();
|
||||
return ms_new0(Sal,1);
|
||||
}
|
||||
|
||||
void sal_uninit(Sal* sal){
|
||||
eXosip_quit();
|
||||
ms_free(sal);
|
||||
}
|
||||
|
||||
|
||||
int sal_listen_port(Sal *ctx, const char *addr, int port, SalTransport tr, int is_secure){
|
||||
int err;
|
||||
bool_t ipv6;
|
||||
int proto=IPPROTO_UDP;
|
||||
|
||||
if (ctx->running) eXosip_quit();
|
||||
eXosip_init();
|
||||
err=0;
|
||||
eXosip_set_option(13,&err); /*13=EXOSIP_OPT_SRV_WITH_NAPTR, as it is an enum value, we can't use it unless we are sure of the
|
||||
version of eXosip, which is not the case*/
|
||||
/*see if it looks like an IPv6 address*/
|
||||
ipv6=strchr(addr,':')!=NULL;
|
||||
eXosip_enable_ipv6(ipv6);
|
||||
|
||||
if (tr!=SAL_TRANSPORT_DATAGRAM || is_secure){
|
||||
ms_fatal("SIP over TCP or TLS or DTLS is not supported yet.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
err=eXosip_listen_addr(proto, addr, port, ipv6 ? PF_INET6 : PF_INET, 0);
|
||||
return err;
|
||||
}
|
||||
|
||||
void sal_set_user_agent(Sal *ctx, const char *user_agent){
|
||||
eXosip_set_user_agent(user_agent);
|
||||
}
|
||||
|
||||
void sal_use_session_timers(Sal *ctx, int expires){
|
||||
ctx->session_expires=expires;
|
||||
}
|
||||
|
||||
SalOp * sal_call_create(Sal *sal, const char *from, const char *to, const char *route, const char *contact){
|
||||
int err;
|
||||
SalOp *op;
|
||||
osip_message_t *invite=NULL;
|
||||
err=eXosip_call_build_initial_invite(&invite,to,from,
|
||||
route,"Phone call");
|
||||
if (err!=0){
|
||||
ms_error("Could not create call.");
|
||||
return NULL;
|
||||
}
|
||||
if (contact)
|
||||
osip_message_set_contact(invite,contact);
|
||||
if (sal->session_expires!=0){
|
||||
osip_message_set_header(invite, "Session-expires", "200");
|
||||
osip_message_set_supported(invite, "timer");
|
||||
}
|
||||
op=sal_op_new();
|
||||
op->request=invite;
|
||||
return op;
|
||||
}
|
||||
|
||||
static void set_sdp(osip_message_t *sip, const SalMediaDescription *desc){
|
||||
int sdplen;
|
||||
char clen[10];
|
||||
char *sdp=media_description_to_sdp(desc);
|
||||
|
||||
if (sdp==NULL) {
|
||||
ms_error("Fail to print sdp message !");
|
||||
return;
|
||||
}
|
||||
sdplen=strlen(sdp);
|
||||
snprintf(clen,sizeof(clen),"%i",sdplen);
|
||||
osip_message_set_body(sip,sdp,sdplen);
|
||||
osip_message_set_content_type(sip,"application/sdp");
|
||||
osip_message_set_content_length(sip,clen);
|
||||
osip_free(sdp);
|
||||
}
|
||||
|
||||
int sal_call_set_local_media_description(SalOp *h, const SalMediaDescription *desc){
|
||||
set_sdp(h->request,desc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sal_call(SalOp *h){
|
||||
int err;
|
||||
eXosip_lock();
|
||||
err=eXosip_call_send_initial_invite(h->request);
|
||||
eXosip_unlock();
|
||||
h->cid=err;
|
||||
if (err<0){
|
||||
ms_error("Fail to send invite !");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sal_call_accept(SalOp*h);
|
||||
int sal_call_get_final_media_description(SalOp *h, SalMediaDescription *result);
|
||||
int sal_call_terminate(SalOp *h);
|
||||
|
||||
int sal_iterate(Sal *sal);
|
||||
|
||||
SalOp *sal_register_create(Sal *ctx, const char *from, const char *contact, int expires);
|
||||
int sal_register(SalOp *h);
|
||||
170
linphone/coreapi/sal_eXosip2_sdp.c
Normal file
170
linphone/coreapi/sal_eXosip2_sdp.c
Normal file
|
|
@ -0,0 +1,170 @@
|
|||
/*
|
||||
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
|
||||
|
||||
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...)*/
|
||||
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;
|
||||
}
|
||||
|
||||
/* return the value of attr "field" */
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
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)));
|
||||
snprintf (attr,sizeof(attr),"%i %s", payload_type_get_number(pt), pt->mime_type);
|
||||
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==SAL_AUDIO ? "audio" : "video";
|
||||
const MSList *elem;
|
||||
sdp_message_m_media_add (msg, osip_strdup (mt),
|
||||
int_2char (desc->port), NULL,
|
||||
osip_strdup ("RTP/AVP"));
|
||||
sdp_message_b_bandwidth_add (msg, lineno, osip_strdup ("AS"),
|
||||
int_2char(desc->bandwidth));
|
||||
for(elem=desc->payloads;elem!=NULL;elem=elem->next){
|
||||
add_payload(msg, lineno, (PayloadType*)elem->data);
|
||||
}
|
||||
}
|
||||
|
||||
char *media_description_to_sdp(const SalMediaDescription *desc){
|
||||
int i;
|
||||
char *tmp;
|
||||
sdp_message_t *msg=create_generic_sdp(desc);
|
||||
for(i=0;i<desc->nstreams;++i){
|
||||
add_line(msg,i,&desc->streams[i]);
|
||||
}
|
||||
sdp_message_to_str(msg,&tmp);
|
||||
return tmp;
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue