]> sjero.net Git - linphone/commitdiff
Merge branch 'master' into dev_sal
authorSimon Morlat <simon.morlat@linphone.org>
Mon, 15 Mar 2010 14:10:42 +0000 (15:10 +0100)
committerSimon Morlat <simon.morlat@linphone.org>
Mon, 15 Mar 2010 14:10:42 +0000 (15:10 +0100)
Conflicts:
coreapi/linphonecore.h

1  2 
coreapi/exevents.c
coreapi/linphonecore.c
coreapi/linphonecore.h
coreapi/private.h
coreapi/sal_eXosip2_sdp.c
gtk-glade/main.c

Simple merge
index 1ed8b9428de1d6497ecdad3e5cb8e935f9adfae6,62adf68fc1f35fdccde6e73e3aabaf249e195161..ddb09892c2a10f9d82c97d40a0762a3c2d127984
@@@ -62,55 -74,7 +62,56 @@@ int lc_callback_obj_invoke(LCCallbackOb
        return 0;
  }
  
 -static void  linphone_call_init_common(LinphoneCall *call, LinphoneAddress *from, LinphoneAddress *to){
 +
 +static MSList *make_codec_list(const MSList *codecs, bool_t only_one_codec){
 +      MSList *l=NULL;
 +      const MSList *it;
 +      for(it=codecs;it!=NULL;it=it->next){
 +              PayloadType *pt=(PayloadType*)it->data;
 +              if (pt->flags & PAYLOAD_TYPE_ENABLED){
 +                      l=ms_list_append(l,payload_type_clone(pt));
 +                      if (only_one_codec) break;
 +              }
 +      }
 +      return l;
 +}
 +
 +static SalMediaDescription *create_local_media_description(LinphoneCore *lc, 
 +              const char *localip, const char *username, bool_t only_one_codec){
 +      MSList *l;
 +      PayloadType *pt;
 +      SalMediaDescription *md=sal_media_description_new();
 +      md->nstreams=1;
 +      strncpy(md->addr,localip,sizeof(md->addr));
 +      strncpy(md->username,username,sizeof(md->username));
 +      /*set audio capabilities */
 +      strncpy(md->streams[0].addr,localip,sizeof(md->streams[0].addr));
 +      md->streams[0].port=linphone_core_get_audio_port(lc);
 +      md->streams[0].proto=SalProtoRtpAvp;
 +      md->streams[0].type=SalAudio;
++      md->streams[0].ptime=lc->net_conf.down_ptime;
 +      l=make_codec_list(lc->codecs_conf.audio_codecs,only_one_codec);
 +      pt=payload_type_clone(rtp_profile_get_payload_from_mime(&av_profile,"telephone-event"));
 +      l=ms_list_append(l,pt);
 +      md->streams[0].payloads=l;
 +      
 +      if (lc->dw_audio_bw>0)
 +              md->streams[0].bandwidth=lc->dw_audio_bw;
 +
 +      if (linphone_core_video_enabled (lc)){
 +              md->nstreams++;
 +              md->streams[1].port=linphone_core_get_video_port(lc);
 +              md->streams[1].proto=SalProtoRtpAvp;
 +              md->streams[1].type=SalVideo;
 +              l=make_codec_list(lc->codecs_conf.video_codecs,only_one_codec);
 +              md->streams[1].payloads=l;
 +              if (lc->dw_video_bw)
 +                      md->streams[1].bandwidth=lc->dw_video_bw;
 +      }
 +      return md;
 +}
 +
 +static void linphone_call_init_common(LinphoneCall *call, LinphoneAddress *from, LinphoneAddress *to){
        call->state=LCStateInit;
        call->start_time=time(NULL);
        call->media_start_time=0;
@@@ -943,6 -858,18 +947,17 @@@ int linphone_core_get_download_bandwidt
  int linphone_core_get_upload_bandwidth(const LinphoneCore *lc){
        return lc->net_conf.upload_bw;
  }
 -void linphone_core_set_download_ptime(LinphoneCore *lc, int ptime);
 -
+ /**
+  * set audio packetization time linphone expect to received from peer
+  */
 -      lc->down_ptime=ptime;
+ void linphone_core_set_download_ptime(LinphoneCore *lc, int ptime) {
 -      return lc->down_ptime;
++      lc->net_conf.down_ptime=ptime;
+ }
++
+ int  linphone_core_get_download_ptime(LinphoneCore *lc) {
++      return lc->net_conf.down_ptime;
+ }
  
  /**
   * Returns liblinphone's version as a string.
index c9f072f6ebaa9502e9b9d010303077d070eed7f6,6c8f0e208eb8caed1a2c97c4a63daf8cb4c7ca38..56c34c0a240ffc8bfd88023211d455d93931fb77
@@@ -450,6 -662,10 +450,7 @@@ typedef struct _LinphoneCore LinphoneCo
         */
        bool_t auto_net_state_mon;
        bool_t network_reachable;
 -} LinphoneCore;
 -
 -
+       int down_ptime;
  
  /* THE main API */
  
index 25341d94d7bfdb227ca5eb43384b6f177f8f1812,93b1c77be124f3152749e45728c73d0b56e8c23d..84b4d07787e2ea71456b6ceb087ecacb3336bdca
@@@ -171,228 -194,4 +171,229 @@@ void linphone_proxy_config_write_to_con
  
  int linphone_proxy_config_normalize_number(LinphoneProxyConfig *cfg, const char *username, char *result, size_t result_len);
  
 +void linphone_core_text_received(LinphoneCore *lc, const char *from, const char *msg);
 +
 +void linphone_core_start_media_streams(LinphoneCore *lc, struct _LinphoneCall *call);
 +void linphone_core_stop_media_streams(LinphoneCore *lc, struct _LinphoneCall *call);
 +const char * linphone_core_get_identity(LinphoneCore *lc);
 +const char * linphone_core_get_route(LinphoneCore *lc);
 +bool_t linphone_core_interpret_url(LinphoneCore *lc, const char *url, LinphoneAddress **real_parsed_url, char **route);
 +void linphone_core_start_waiting(LinphoneCore *lc, const char *purpose);
 +void linphone_core_update_progress(LinphoneCore *lc, const char *purpose, float progresses);
 +void linphone_core_stop_waiting(LinphoneCore *lc);
 +
 +int linphone_core_start_invite(LinphoneCore *lc, LinphoneCall *call, LinphoneProxyConfig *dest_proxy);
 +
 +extern SalCallbacks linphone_sal_callbacks;
 +
 +
 +struct _LinphoneProxyConfig
 +{
 +      struct _LinphoneCore *lc;
 +      char *reg_proxy;
 +      char *reg_identity;
 +      char *reg_route;
 +      char *realm;
 +      int expires;
 +      int reg_time;
 +      SalOp *op;
 +      char *type;
 +      struct _SipSetupContext *ssctx;
 +      int auth_failures;
 +      char *dial_prefix;
 +      bool_t commit;
 +      bool_t reg_sendregister;
 +      bool_t registered;
 +      bool_t publish;
 +      bool_t dial_escape_plus;
 +};
 +
 +struct _LinphoneAuthInfo 
 +{
 +      char *username;
 +      char *realm;
 +      char *userid;
 +      char *passwd;
 +      char *ha1;
 +      int usecount;
 +      bool_t works;
 +};
 +
 +struct _LinphoneChatRoom{
 +      struct _LinphoneCore *lc;
 +      char  *peer;
 +      char *route;
 +      LinphoneAddress *peer_url;
 +      void * user_data;
 +};
 +
 +struct _LinphoneFriend{
 +      LinphoneAddress *uri;
 +      SalOp *insub;
 +      SalOp *outsub;
 +      LinphoneSubscribePolicy pol;
 +      LinphoneOnlineStatus status;
 +      struct _LinphoneCore *lc;
 +      BuddyInfo *info;
 +      char *refkey;
 +      bool_t subscribe;
 +      bool_t inc_subscribe_pending;
 +};    
 +
 +typedef struct sip_config
 +{
 +      char *contact;
 +      char *guessed_contact;
 +      int sip_port;
 +      MSList *proxies;
 +      MSList *deleted_proxies;
 +      int inc_timeout;        /*timeout after an un-answered incoming call is rejected*/
 +      bool_t use_info;
 +      bool_t use_rfc2833;     /*force RFC2833 to be sent*/
 +      bool_t guess_hostname;
 +      bool_t loopback_only;
 +      bool_t ipv6_enabled;
 +      bool_t sdp_200_ack;
 +      bool_t only_one_codec; /*in SDP answers*/
 +      bool_t register_only_when_network_is_up;
 +      bool_t ping_with_options;
 +} sip_config_t;
 +
 +typedef struct rtp_config
 +{
 +      int audio_rtp_port;
 +      int video_rtp_port;
 +      int audio_jitt_comp;  /*jitter compensation*/
 +      int video_jitt_comp;  /*jitter compensation*/
 +      int nortp_timeout;
 +}rtp_config_t;
 +
 +
 +
 +typedef struct net_config
 +{
 +      char *nat_address;
 +      char *stun_server;
 +      char *relay;
 +      int download_bw;
 +      int upload_bw;
 +      int firewall_policy;
 +      int mtu;
++      int down_ptime;
 +      bool_t nat_sdp_only;
 +}net_config_t;
 +
 +
 +typedef struct sound_config
 +{
 +      struct _MSSndCard * ring_sndcard;       /* the playback sndcard currently used */
 +      struct _MSSndCard * play_sndcard;       /* the playback sndcard currently used */
 +      struct _MSSndCard * capt_sndcard; /* the capture sndcard currently used */
 +      const char **cards;
 +      int latency;    /* latency in samples of the current used sound device */
 +      char rec_lev;
 +      char play_lev;
 +      char ring_lev;
 +      char soft_play_lev;
 +      char source;
 +      char *local_ring;
 +      char *remote_ring;
 +      bool_t ec;
 +      bool_t ea;
 +      bool_t agc;
 +} sound_config_t;
 +
 +typedef struct codecs_config
 +{
 +      MSList *audio_codecs;  /* list of audio codecs in order of preference*/
 +      MSList *video_codecs;   /* for later use*/
 +}codecs_config_t;
 +
 +typedef struct video_config{
 +      struct _MSWebCam *device;
 +      const char **cams;
 +      MSVideoSize vsize;
 +      bool_t capture;
 +      bool_t show_local;
 +      bool_t display;
 +      bool_t selfview; /*during calls*/
 +}video_config_t;
 +
 +typedef struct ui_config
 +{
 +      int is_daemon;
 +      int is_applet;
 +      unsigned int timer_id;  /* the timer id for registration */
 +}ui_config_t;
 +
 +
 +
 +typedef struct autoreplier_config
 +{
 +      int enabled;
 +      int after_seconds;              /* accept the call after x seconds*/
 +      int max_users;                  /* maximum number of user that can call simultaneously */
 +      int max_rec_time;       /* the max time of incoming voice recorded */
 +      int max_rec_msg;                /* maximum number of recorded messages */
 +      const char *message;            /* the path of the file to be played */
 +}autoreplier_config_t;
 +
 +
 +struct _LinphoneCore
 +{
 +      LinphoneCoreVTable vtable;
 +      Sal *sal;
 +      struct _LpConfig *config;
 +      net_config_t net_conf;
 +      sip_config_t sip_conf;
 +      rtp_config_t rtp_conf;
 +      sound_config_t sound_conf;
 +      video_config_t video_conf;
 +      codecs_config_t codecs_conf;
 +      ui_config_t ui_conf;
 +      autoreplier_config_t autoreplier_conf;
 +      LinphoneProxyConfig *default_proxy;
 +      MSList *friends;
 +      MSList *auth_info;
 +      struct _RingStream *ringstream;
 +      LCCallbackObj preview_finished_cb;
 +      struct _LinphoneCall *call;   /* the current call, in the future it will be a list of calls (conferencing)*/
 +      MSList *queued_calls;   /* used by the autoreplier */
 +      MSList *call_logs;
 +      MSList *chatrooms;
 +      int max_call_logs;
 +      int missed_calls;
 +      struct _AudioStream *audiostream;  /**/
 +      struct _VideoStream *videostream;
 +      struct _VideoStream *previewstream;
 +      RtpTransport *a_rtp,*a_rtcp;
 +      MSList *bl_reqs;
 +      MSList *subscribers;    /* unknown subscribers */
 +      int minutes_away;
 +      LinphoneOnlineStatus presence_mode;
 +      LinphoneOnlineStatus prev_mode;
 +      char *alt_contact;
 +      void *data;
 +      char *play_file;
 +      char *rec_file;
 +      time_t prevtime;
 +      int dw_audio_bw;
 +      int up_audio_bw;
 +      int dw_video_bw;
 +      int up_video_bw;
 +      int audio_bw;
 +      gstate_t gstate_power;
 +      gstate_t gstate_reg;
 +      gstate_t gstate_call;
 +      LinphoneWaitingCallback wait_cb;
 +      void *wait_ctx;
 +      bool_t use_files;
 +      bool_t apply_nat_settings;
 +      bool_t ready;
 +      bool_t bl_refresh;
 +      bool_t preview_finished;
 +      bool_t auto_net_state_mon;
 +      bool_t network_reachable;
 +};
 +
  #endif /* _PRIVATE_H */
index c1a1761cc414b24ff6da258d03d5529e75cd3e0a,0000000000000000000000000000000000000000..5804287659a8a78293cfe9d82c0f06c41f4fe75e
mode 100644,000000..100644
--- /dev/null
@@@ -1,286 -1,0 +1,288 @@@
 +/*
 +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
 +
 +static 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...)*/
 +static const 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;
 +}
 +
 +#ifdef FOR_LATER
 +/* return the value of attr "field" */
 +static const 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;
 +}
 +#endif
 +
 +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;
 +}
 +
 +
 +
 +static 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)));
 +      if (pt->channels>0)
 +              snprintf (attr,sizeof(attr),"%i %s/%i/%i", payload_type_get_number(pt), 
 +                      pt->mime_type, pt->clock_rate,pt->channels);
 +      else
 +              snprintf (attr,sizeof(attr),"%i %s/%i", payload_type_get_number(pt), 
 +                      pt->mime_type, pt->clock_rate);
 +      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==SalAudio ? "audio" : "video";
 +      const MSList *elem;
 +      const char *addr;
 +      int port;
 +      if (desc->candidates[0].addr[0]!='\0'){
 +              addr=desc->candidates[0].addr;
 +              port=desc->candidates[0].port;
 +      }else{
 +              addr=desc->addr;
 +              port=desc->port;
 +      }
 +      /*only add a c= line within the stream description if address are differents*/
 +      if (strcmp(addr,sdp_message_c_addr_get(msg, -1, 0))!=0){
 +              bool_t inet6;
 +              if (strchr(addr,':')!=NULL){
 +                      inet6=TRUE;
 +              }else inet6=FALSE;
 +              sdp_message_c_connection_add (msg, lineno,
 +                            osip_strdup ("IN"), inet6 ? osip_strdup ("IP6") : osip_strdup ("IP4"),
 +                            osip_strdup (addr), NULL, NULL);
 +      }
 +      sdp_message_m_media_add (msg, osip_strdup (mt),
 +                               int_2char (port), NULL,
 +                               osip_strdup ("RTP/AVP"));
 +      if (desc->bandwidth>0) sdp_message_b_bandwidth_add (msg, lineno, osip_strdup ("AS"),
 +                                   int_2char(desc->bandwidth));
++      if (desc->ptime>0) sdp_message_a_attribute_add(msg,lineno,osip_strdup("ptime"),
++                              int_2char(desc->ptime));
 +      for(elem=desc->payloads;elem!=NULL;elem=elem->next){
 +              add_payload(msg, lineno, (PayloadType*)elem->data);
 +      }
 +}
 +
 +sdp_message_t *media_description_to_sdp(const SalMediaDescription *desc){
 +      int i;
 +      sdp_message_t *msg=create_generic_sdp(desc);
 +      for(i=0;i<desc->nstreams;++i){
 +              add_line(msg,i,&desc->streams[i]);
 +      }
 +      return msg;
 +}
 +
 +static int payload_type_fill_from_rtpmap(PayloadType *pt, const char *rtpmap){
 +      if (rtpmap==NULL){
 +              PayloadType *refpt=rtp_profile_get_payload(&av_profile,payload_type_get_number(pt));
 +              if (refpt){
 +                      pt->mime_type=ms_strdup(refpt->mime_type);
 +                      pt->clock_rate=refpt->clock_rate;
 +              }else{
 +                      ms_error("payload number %i has no rtpmap and is unknown in AV Profile, ignored.",
 +                          payload_type_get_number(pt));
 +                      return -1;
 +              }
 +      }else{
 +              char *mime=ms_strdup(rtpmap);
 +              char *p=strchr(mime,'/');
 +              if (p){
 +                      char *chans;
 +                      *p='\0';
 +                      p++;
 +                      chans=strchr(p,'/');
 +                      if (chans){
 +                              *chans='\0';
 +                              chans++;
 +                              pt->channels=atoi(chans);
 +                      }else pt->channels=1;
 +                      pt->clock_rate=atoi(p);
 +              }
 +              pt->mime_type=mime;
 +      }
 +      return 0;
 +}
 +
 +int sdp_to_media_description(sdp_message_t *msg, SalMediaDescription *desc){
 +      int i,j;
 +      const char *mtype,*proto,*port,*addr,*number;
 +      sdp_bandwidth_t *sbw=NULL;
 +      
 +      addr=sdp_message_c_addr_get (msg, -1, 0);
 +      if (addr)
 +              strncpy(desc->addr,addr,sizeof(desc->addr));
 +      /* for each m= line */
 +      for (i=0; !sdp_message_endof_media (msg, i) && i<SAL_MEDIA_DESCRIPTION_MAX_STREAMS; i++)
 +      {
 +              SalStreamDescription *stream=&desc->streams[i];
 +              
 +              memset(stream,0,sizeof(*stream));
 +              mtype = sdp_message_m_media_get(msg, i);
 +              proto = sdp_message_m_proto_get (msg, i);
 +              port = sdp_message_m_port_get(msg, i);
 +              stream->proto=SalProtoUnknown;
 +              if (proto){
 +                      if (strcasecmp(proto,"RTP/AVP")==0)
 +                              stream->proto=SalProtoRtpAvp;
 +                      else if (strcasecmp(proto,"RTP/SAVP")==0){
 +                              stream->proto=SalProtoRtpSavp;
 +                      }
 +              }
 +              addr = sdp_message_c_addr_get (msg, i, 0);
 +              if (addr != NULL)
 +                      strncpy(stream->addr,addr,sizeof(stream->addr));
 +              if (port)
 +                      stream->port=atoi(port);
 +              
 +              stream->ptime=_sdp_message_get_a_ptime(msg,i);
 +              if (strcasecmp("audio", mtype) == 0){
 +                      stream->type=SalAudio;
 +              }else if (strcasecmp("video", mtype) == 0){
 +                      stream->type=SalVideo;
 +              }else stream->type=SalOther;
 +              for(j=0;(sbw=sdp_message_bandwidth_get(msg,i,j))!=NULL;++j){
 +                      if (strcasecmp(sbw->b_bwtype,"AS")==0) stream->bandwidth=atoi(sbw->b_bandwidth);
 +              }
 +              /* for each payload type */
 +              for (j=0;((number=sdp_message_m_payload_get (msg, i,j)) != NULL); j++){
 +                      const char *rtpmap,*fmtp;
 +                      int ptn=atoi(number);
 +                      PayloadType *pt=payload_type_new();
 +                      payload_type_set_number(pt,ptn);
 +                      /* get the rtpmap associated to this codec, if any */
 +                      rtpmap=sdp_message_a_attr_value_get_with_pt(msg, i,ptn,"rtpmap");
 +                      payload_type_fill_from_rtpmap(pt,rtpmap);
 +                      /* get the fmtp, if any */
 +                      fmtp=sdp_message_a_attr_value_get_with_pt(msg, i, ptn,"fmtp");
 +                      payload_type_set_send_fmtp(pt,fmtp);
 +                      stream->payloads=ms_list_append(stream->payloads,pt);
 +                      ms_message("Found payload %s/%i fmtp=%s",pt->mime_type,pt->clock_rate,
 +                          pt->send_fmtp ? pt->send_fmtp : "");
 +              }
 +      }
 +      desc->nstreams=i;
 +      return 0;
 +}
Simple merge