]> sjero.net Git - linphone/blob - coreapi/offeranswer.c
workaround for stupid phone using "G729A" submime type.
[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
24 static PayloadType * find_payload_type_best_match(const MSList *l, const PayloadType *refpt){
25         PayloadType *pt;
26         char value[10];
27         const MSList *elem;
28         PayloadType *candidate=NULL;
29
30         for (elem=l;elem!=NULL;elem=elem->next){
31                 pt=(PayloadType*)elem->data;
32                 /* the compare between G729 and G729A is for some stupid uncompliant phone*/
33                 if (strcasecmp(pt->mime_type,refpt->mime_type)==0  ||
34                     ((strcasecmp(pt->mime_type, "G729") == 0 && strcasecmp(refpt->mime_type, "G729A") == 0 ))
35                         && pt->clock_rate==refpt->clock_rate){
36                         candidate=pt;
37                         /*good candidate, check fmtp for H264 */
38                         if (strcasecmp(pt->mime_type,"H264")==0){
39                                 if (pt->recv_fmtp!=NULL && refpt->recv_fmtp!=NULL){
40                                         int mode1=0,mode2=0;
41                                         if (fmtp_get_value(pt->recv_fmtp,"packetization-mode",value,sizeof(value))){
42                                                 mode1=atoi(value);
43                                         }
44                                         if (fmtp_get_value(refpt->recv_fmtp,"packetization-mode",value,sizeof(value))){
45                                                 mode2=atoi(value);
46                                         }
47                                         if (mode1==mode2)
48                                             break; /*exact match */
49                                 }
50                         }else break;
51                 }
52         }
53         return candidate;
54 }
55
56 static MSList *match_payloads(const MSList *local, const MSList *remote){
57         const MSList *e2;
58         MSList *res=NULL;
59         PayloadType *matched;
60         for(e2=remote;e2!=NULL;e2=e2->next){
61                 PayloadType *p2=(PayloadType*)e2->data;
62                 matched=find_payload_type_best_match(local,p2);
63                 if (matched){
64                         matched=payload_type_clone(matched);
65                         if (p2->send_fmtp)
66                                 payload_type_set_send_fmtp(matched,p2->send_fmtp);
67                         res=ms_list_append(res,matched);
68                         payload_type_set_number(matched,payload_type_get_number(p2));
69                 }else{
70                         ms_message("No match for %s/%i",p2->mime_type,p2->clock_rate);
71                 }
72         }
73         return res;
74 }
75
76 static bool_t only_telephone_event(const MSList *l){
77         PayloadType *p=(PayloadType*)l->data;
78         if (strcasecmp(p->mime_type,"telephone-event")!=0){
79                 return FALSE;
80         }
81         return TRUE;
82 }
83
84 static void initiate_outgoing(const SalStreamDescription *local_offer,
85                                         const SalStreamDescription *remote_answer,
86                                         SalStreamDescription *result){
87         if (remote_answer->port!=0)
88                 result->payloads=match_payloads(local_offer->payloads,remote_answer->payloads);
89         result->proto=local_offer->proto;
90         result->type=local_offer->type;
91         result->dir=local_offer->dir;
92
93         if (result->payloads && !only_telephone_event(result->payloads)){
94                 strcpy(result->addr,remote_answer->addr);
95                 result->port=remote_answer->port;
96                 result->bandwidth=remote_answer->bandwidth;
97                 result->ptime=remote_answer->ptime;
98         }else{
99                 result->port=0;
100         }
101 }
102
103
104 static void initiate_incoming(const SalStreamDescription *local_cap,
105                                         const SalStreamDescription *remote_offer,
106                                         SalStreamDescription *result){
107         result->payloads=match_payloads(local_cap->payloads,remote_offer->payloads);
108         result->proto=local_cap->proto;
109         result->type=local_cap->type;
110         if (remote_offer->dir==SalStreamSendOnly)
111                 result->dir=SalStreamRecvOnly;
112         else if (remote_offer->dir==SalStreamRecvOnly){
113                 result->dir=SalStreamSendOnly;
114         }else if (remote_offer->dir==SalStreamInactive){
115                 result->dir=SalStreamInactive;
116         }else result->dir=SalStreamSendRecv;
117         if (result->payloads && !only_telephone_event(result->payloads)){
118                 strcpy(result->addr,local_cap->addr);
119                 result->port=local_cap->port;
120                 result->bandwidth=local_cap->bandwidth;
121                 result->ptime=local_cap->ptime;         
122         }else{
123                 result->port=0;
124         }
125 }
126
127 /**
128  * Returns a media description to run the streams with, based on a local offer
129  * and the returned response (remote).
130 **/
131 int offer_answer_initiate_outgoing(const SalMediaDescription *local_offer,
132                                                                         const SalMediaDescription *remote_answer,
133                                                         SalMediaDescription *result){
134     int i,j;
135         const SalStreamDescription *ls,*rs;
136     for(i=0,j=0;i<local_offer->nstreams;++i){
137                 ms_message("Processing for stream %i",i);
138                 ls=&local_offer->streams[i];
139                 rs=sal_media_description_find_stream(remote_answer,ls->proto,ls->type);
140         if (rs) {
141                         initiate_outgoing(ls,rs,&result->streams[j]);
142                         ++j;
143                 }
144                 else ms_warning("No matching stream for %i",i);
145     }
146         result->nstreams=j;
147         strcpy(result->addr,remote_answer->addr);
148         return 0;
149 }
150
151 /**
152  * Returns a media description to run the streams with, based on the local capabilities and
153  * and the received offer.
154  * The returned media description is an answer and should be sent to the offerer.
155 **/
156 int offer_answer_initiate_incoming(const SalMediaDescription *local_capabilities,
157                                                 const SalMediaDescription *remote_offer,
158                                         SalMediaDescription *result){
159     int i,j;
160         const SalStreamDescription *ls,*rs;
161                                                         
162     for(i=0,j=0;i<remote_offer->nstreams;++i){
163                 rs=&remote_offer->streams[i];
164                 ms_message("Processing for stream %i",i);
165                 ls=sal_media_description_find_stream(local_capabilities,rs->proto,rs->type);
166                 if (ls){
167                 initiate_incoming(ls,rs,&result->streams[j]);
168                         ++j;
169                 }
170     }
171         result->nstreams=j;
172         strcpy(result->username, local_capabilities->username);
173         strcpy(result->addr,local_capabilities->addr);
174         return 0;
175 }
176