]> sjero.net Git - linphone/blob - coreapi/offeranswer.c
Merge branch 'master' of git.sv.gnu.org:/srv/git/linphone
[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(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 void initiate_outgoing(const SalStreamDescription *local_offer,
128                                         const SalStreamDescription *remote_answer,
129                                         SalStreamDescription *result){
130         if (remote_answer->port!=0)
131                 result->payloads=match_payloads(local_offer->payloads,remote_answer->payloads,TRUE,FALSE);
132         result->proto=local_offer->proto;
133         result->type=local_offer->type;
134         result->dir=compute_dir(local_offer->dir,remote_answer->dir);
135
136         if (result->payloads && !only_telephone_event(result->payloads)){
137                 strcpy(result->addr,remote_answer->addr);
138                 result->port=remote_answer->port;
139                 result->bandwidth=remote_answer->bandwidth;
140                 result->ptime=remote_answer->ptime;
141         }else{
142                 result->port=0;
143         }
144 }
145
146
147 static void initiate_incoming(const SalStreamDescription *local_cap,
148                                         const SalStreamDescription *remote_offer,
149                                         SalStreamDescription *result, bool_t one_matching_codec){
150         result->payloads=match_payloads(local_cap->payloads,remote_offer->payloads, FALSE, one_matching_codec);
151         result->proto=local_cap->proto;
152         result->type=local_cap->type;
153         if (remote_offer->dir==SalStreamSendOnly)
154                 result->dir=SalStreamRecvOnly;
155         else if (remote_offer->dir==SalStreamRecvOnly){
156                 result->dir=SalStreamSendOnly;
157         }else if (remote_offer->dir==SalStreamInactive){
158                 result->dir=SalStreamInactive;
159         }else result->dir=SalStreamSendRecv;
160         if (result->payloads && !only_telephone_event(result->payloads)){
161                 strcpy(result->addr,local_cap->addr);
162                 result->port=local_cap->port;
163                 result->bandwidth=local_cap->bandwidth;
164                 result->ptime=local_cap->ptime;         
165         }else{
166                 result->port=0;
167         }
168 }
169
170 /**
171  * Returns a media description to run the streams with, based on a local offer
172  * and the returned response (remote).
173 **/
174 int offer_answer_initiate_outgoing(const SalMediaDescription *local_offer,
175                                                                         const SalMediaDescription *remote_answer,
176                                                         SalMediaDescription *result){
177     int i,j;
178         const SalStreamDescription *ls,*rs;
179     for(i=0,j=0;i<local_offer->nstreams;++i){
180                 ms_message("Processing for stream %i",i);
181                 ls=&local_offer->streams[i];
182                 rs=sal_media_description_find_stream((SalMediaDescription*)remote_answer,ls->proto,ls->type);
183         if (rs) {
184                         initiate_outgoing(ls,rs,&result->streams[j]);
185                         ++j;
186                 }
187                 else ms_warning("No matching stream for %i",i);
188     }
189         result->nstreams=j;
190         strcpy(result->addr,remote_answer->addr);
191         return 0;
192 }
193
194 /**
195  * Returns a media description to run the streams with, based on the local capabilities and
196  * and the received offer.
197  * The returned media description is an answer and should be sent to the offerer.
198 **/
199 int offer_answer_initiate_incoming(const SalMediaDescription *local_capabilities,
200                                                 const SalMediaDescription *remote_offer,
201                                         SalMediaDescription *result, bool_t one_matching_codec){
202     int i,j;
203         const SalStreamDescription *ls,*rs;
204                                                         
205     for(i=0,j=0;i<remote_offer->nstreams;++i){
206                 rs=&remote_offer->streams[i];
207                 ms_message("Processing for stream %i",i);
208                 ls=sal_media_description_find_stream((SalMediaDescription*)local_capabilities,rs->proto,rs->type);
209                 if (ls){
210                 initiate_incoming(ls,rs,&result->streams[j],one_matching_codec);
211                         ++j;
212                 }
213     }
214         result->nstreams=j;
215         strcpy(result->username, local_capabilities->username);
216         strcpy(result->addr,local_capabilities->addr);
217         return 0;
218 }
219