]> sjero.net Git - linphone/blob - coreapi/offeranswer.c
fix empty mline again and update ms2
[linphone] / coreapi / offeranswer.c
1 /*
2 linphone
3 Copyright (C) 2010  Simon MORLAT (simon.morlat@free.fr)
4
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.
9
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.
14
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.
18 */
19
20 #include "sal.h"
21 #include "offeranswer.h"
22
23 static bool_t only_telephone_event(const MSList *l){
24         PayloadType *p=(PayloadType*)l->data;
25         if (strcasecmp(p->mime_type,"telephone-event")!=0){
26                 return FALSE;
27         }
28         return TRUE;
29 }
30
31 static PayloadType * find_payload_type_best_match(const MSList *l, const PayloadType *refpt){
32         PayloadType *pt;
33         char value[10];
34         const MSList *elem;
35         PayloadType *candidate=NULL;
36
37         for (elem=l;elem!=NULL;elem=elem->next){
38                 pt=(PayloadType*)elem->data;
39                 /* the compare between G729 and G729A is for some stupid uncompliant phone*/
40                 if ( (strcasecmp(pt->mime_type,refpt->mime_type)==0  ||
41                     (strcasecmp(pt->mime_type, "G729") == 0 && strcasecmp(refpt->mime_type, "G729A") == 0 ))
42                         && pt->clock_rate==refpt->clock_rate){
43                         candidate=pt;
44                         /*good candidate, check fmtp for H264 */
45                         if (strcasecmp(pt->mime_type,"H264")==0){
46                                 if (pt->recv_fmtp!=NULL && refpt->recv_fmtp!=NULL){
47                                         int mode1=0,mode2=0;
48                                         if (fmtp_get_value(pt->recv_fmtp,"packetization-mode",value,sizeof(value))){
49                                                 mode1=atoi(value);
50                                         }
51                                         if (fmtp_get_value(refpt->recv_fmtp,"packetization-mode",value,sizeof(value))){
52                                                 mode2=atoi(value);
53                                         }
54                                         if (mode1==mode2)
55                                             break; /*exact match */
56                                 }
57                         }else break;
58                 }
59         }
60         return candidate;
61 }
62
63 static MSList *match_payloads(const MSList *local, const MSList *remote, bool_t reading_response, bool_t one_matching_codec){
64         const MSList *e2;
65         MSList *res=NULL;
66         PayloadType *matched;
67         bool_t found_codec=FALSE;
68         
69         for(e2=remote;e2!=NULL;e2=e2->next){
70                 PayloadType *p2=(PayloadType*)e2->data;
71                 matched=find_payload_type_best_match(local,p2);
72                 if (matched){
73                         PayloadType *newp;
74                         int local_number=payload_type_get_number(matched);
75                         int remote_number=payload_type_get_number(p2);
76
77                         if (one_matching_codec){
78                                 if (strcasecmp(matched->mime_type,"telephone-event")!=0){
79                                         if (found_codec){/* we have found a real codec already*/
80                                                 continue; /*this codec won't be added*/
81                                         }else found_codec=TRUE;
82                                 }
83                         }
84                         
85                         newp=payload_type_clone(matched);
86                         if (p2->send_fmtp)
87                                 payload_type_set_send_fmtp(newp,p2->send_fmtp);
88                         res=ms_list_append(res,newp);
89                         /* we should use the remote numbering even when parsing a response */
90                         payload_type_set_number(newp,remote_number);
91                         if (reading_response && remote_number!=local_number){
92                                 ms_warning("For payload type %s, proposed number was %i but the remote phone answered %i",
93                                           newp->mime_type, local_number, remote_number);
94                                 /*
95                                  We must add this payload type with our local numbering in order to be able to receive it.
96                                  Indeed despite we must sent with the remote numbering, we must be able to receive with
97                                  our local one.
98                                 */
99                                 newp=payload_type_clone(matched);
100                                 payload_type_set_number(newp,local_number);
101                                 res=ms_list_append(res,newp);
102                         }
103                 }else{
104                         ms_message("No match for %s/%i",p2->mime_type,p2->clock_rate);
105                 }
106         }
107         return res;
108 }
109
110
111
112 static SalStreamDir compute_dir_outgoing(SalStreamDir local, SalStreamDir answered){
113         SalStreamDir res=local;
114         if (local==SalStreamSendRecv){
115                 if (answered==SalStreamRecvOnly){
116                         res=SalStreamSendOnly;
117                 }else if (answered==SalStreamSendOnly){
118                         res=SalStreamRecvOnly;
119                 }
120         }
121         if (answered==SalStreamInactive){
122                 res=SalStreamInactive;
123         }
124         return res;
125 }
126
127 static SalStreamDir compute_dir_incoming(SalStreamDir local, SalStreamDir offered){
128         SalStreamDir res=SalStreamSendRecv;
129         if (local==SalStreamSendRecv){
130                 if (offered==SalStreamSendOnly)
131                         res=SalStreamRecvOnly;
132                 else if (offered==SalStreamRecvOnly)
133                         res=SalStreamSendOnly;
134                 else if (offered==SalStreamInactive)
135                         res=SalStreamInactive;
136                 else
137                         res=SalStreamSendRecv;
138         }else if (local==SalStreamSendOnly){
139                 if (offered==SalStreamRecvOnly || offered==SalStreamSendRecv)
140                         res=SalStreamSendOnly;
141                 else res=SalStreamInactive;
142         }else if (local==SalStreamRecvOnly){
143                 if (offered==SalStreamSendOnly || offered==SalStreamSendRecv)
144                         res=SalStreamRecvOnly;
145                 else
146                         res=SalStreamInactive;
147         }else res=SalStreamInactive;
148         return res;
149 }
150
151 static void initiate_outgoing(const SalStreamDescription *local_offer,
152                                         const SalStreamDescription *remote_answer,
153                                         SalStreamDescription *result){
154         if (remote_answer->port!=0)
155                 result->payloads=match_payloads(local_offer->payloads,remote_answer->payloads,TRUE,FALSE);
156         result->proto=local_offer->proto;
157         result->type=local_offer->type;
158         result->dir=compute_dir_outgoing(local_offer->dir,remote_answer->dir);
159
160         if (result->payloads && !only_telephone_event(result->payloads)){
161                 strcpy(result->addr,remote_answer->addr);
162                 result->port=remote_answer->port;
163                 result->bandwidth=remote_answer->bandwidth;
164                 result->ptime=remote_answer->ptime;
165         }else{
166                 result->port=0;
167         }
168 }
169
170
171 static void initiate_incoming(const SalStreamDescription *local_cap,
172                                         const SalStreamDescription *remote_offer,
173                                         SalStreamDescription *result, bool_t one_matching_codec){
174         result->payloads=match_payloads(local_cap->payloads,remote_offer->payloads, FALSE, one_matching_codec);
175         result->proto=local_cap->proto;
176         result->type=local_cap->type;
177         result->dir=compute_dir_incoming(local_cap->dir,remote_offer->dir);
178         if (result->payloads && !only_telephone_event(result->payloads)){
179                 strcpy(result->addr,local_cap->addr);
180                 result->port=local_cap->port;
181                 result->bandwidth=local_cap->bandwidth;
182                 result->ptime=local_cap->ptime; 
183         }else{
184                 result->port=0;
185         }
186 }
187
188 /**
189  * Returns a media description to run the streams with, based on a local offer
190  * and the returned response (remote).
191 **/
192 int offer_answer_initiate_outgoing(const SalMediaDescription *local_offer,
193                                                                         const SalMediaDescription *remote_answer,
194                                                         SalMediaDescription *result){
195     int i,j;
196         const SalStreamDescription *ls,*rs;
197     for(i=0,j=0;i<local_offer->nstreams;++i){
198                 ms_message("Processing for stream %i",i);
199                 ls=&local_offer->streams[i];
200                 rs=sal_media_description_find_stream((SalMediaDescription*)remote_answer,ls->proto,ls->type);
201         if (rs) {
202                         initiate_outgoing(ls,rs,&result->streams[j]);
203                         ++j;
204                 }
205                 else ms_warning("No matching stream for %i",i);
206     }
207         result->nstreams=j;
208         result->bandwidth=remote_answer->bandwidth;
209         strcpy(result->addr,remote_answer->addr);
210         return 0;
211 }
212
213 /**
214  * Returns a media description to run the streams with, based on the local capabilities and
215  * and the received offer.
216  * The returned media description is an answer and should be sent to the offerer.
217 **/
218 int offer_answer_initiate_incoming(const SalMediaDescription *local_capabilities,
219                                                 const SalMediaDescription *remote_offer,
220                                         SalMediaDescription *result, bool_t one_matching_codec){
221     int i;
222         const SalStreamDescription *ls,*rs;
223                                                         
224     for(i=0;i<remote_offer->nstreams;++i){
225                 rs=&remote_offer->streams[i];
226                 ms_message("Processing for stream %i",i);
227                 ls=sal_media_description_find_stream((SalMediaDescription*)local_capabilities,rs->proto,rs->type);
228                 if (ls){
229                 initiate_incoming(ls,rs,&result->streams[i],one_matching_codec);
230                 } else {
231                         /* create an inactive stream for the answer, as there where no matching stream a local capability */
232                         result->streams[i].dir=SalStreamInactive;
233                         result->streams[i].port=0;
234                         result->streams[i].type=rs->type;
235                         if (rs->type==SalOther){
236                                 strncpy(result->streams[i].typeother,rs->typeother,sizeof(rs->typeother)-1);
237                         }
238                 }
239     }
240         result->nstreams=i;
241         strcpy(result->username, local_capabilities->username);
242         strcpy(result->addr,local_capabilities->addr);
243         result->bandwidth=local_capabilities->bandwidth;
244         result->session_ver=local_capabilities->session_ver;
245         result->session_id=local_capabilities->session_id;
246         return 0;
247 }