3 Copyright (C) 2010 Simon MORLAT (simon.morlat@free.fr)
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.
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.
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.
21 #include "offeranswer.h"
24 static PayloadType * find_payload_type_best_match(const MSList *l, const PayloadType *refpt){
28 PayloadType *candidate=NULL;
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){
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){
41 if (fmtp_get_value(pt->recv_fmtp,"packetization-mode",value,sizeof(value))){
44 if (fmtp_get_value(refpt->recv_fmtp,"packetization-mode",value,sizeof(value))){
48 break; /*exact match */
56 static MSList *match_payloads(const MSList *local, const MSList *remote, bool_t reading_response){
60 for(e2=remote;e2!=NULL;e2=e2->next){
61 PayloadType *p2=(PayloadType*)e2->data;
62 matched=find_payload_type_best_match(local,p2);
65 int local_number=payload_type_get_number(matched);
66 int remote_number=payload_type_get_number(p2);
68 newp=payload_type_clone(matched);
70 payload_type_set_send_fmtp(newp,p2->send_fmtp);
71 res=ms_list_append(res,newp);
72 /* we should use the remote numbering even when parsing a response */
73 payload_type_set_number(newp,remote_number);
74 if (reading_response && remote_number!=local_number){
75 ms_warning("For payload type %s, proposed number was %i but the remote phone answered %i",
76 newp->mime_type, local_number, remote_number);
78 We must add this payload type with our local numbering in order to be able to receive it.
79 Indeed despite we must sent with the remote numbering, we must be able to receive with
82 newp=payload_type_clone(matched);
83 payload_type_set_number(newp,local_number);
84 res=ms_list_append(res,newp);
87 ms_message("No match for %s/%i",p2->mime_type,p2->clock_rate);
93 static bool_t only_telephone_event(const MSList *l){
94 PayloadType *p=(PayloadType*)l->data;
95 if (strcasecmp(p->mime_type,"telephone-event")!=0){
101 static SalStreamDir compute_dir(SalStreamDir local, SalStreamDir answered){
102 SalStreamDir res=local;
103 if (local==SalStreamSendRecv){
104 if (answered==SalStreamRecvOnly){
105 res=SalStreamSendOnly;
106 }else if (answered==SalStreamSendOnly){
107 res=SalStreamRecvOnly;
110 if (answered==SalStreamInactive){
111 res=SalStreamInactive;
116 static void initiate_outgoing(const SalStreamDescription *local_offer,
117 const SalStreamDescription *remote_answer,
118 SalStreamDescription *result){
119 if (remote_answer->port!=0)
120 result->payloads=match_payloads(local_offer->payloads,remote_answer->payloads,TRUE);
121 result->proto=local_offer->proto;
122 result->type=local_offer->type;
123 result->dir=compute_dir(local_offer->dir,remote_answer->dir);
125 if (result->payloads && !only_telephone_event(result->payloads)){
126 strcpy(result->addr,remote_answer->addr);
127 result->port=remote_answer->port;
128 result->bandwidth=remote_answer->bandwidth;
129 result->ptime=remote_answer->ptime;
136 static void initiate_incoming(const SalStreamDescription *local_cap,
137 const SalStreamDescription *remote_offer,
138 SalStreamDescription *result){
139 result->payloads=match_payloads(local_cap->payloads,remote_offer->payloads, FALSE);
140 result->proto=local_cap->proto;
141 result->type=local_cap->type;
142 if (remote_offer->dir==SalStreamSendOnly)
143 result->dir=SalStreamRecvOnly;
144 else if (remote_offer->dir==SalStreamRecvOnly){
145 result->dir=SalStreamSendOnly;
146 }else if (remote_offer->dir==SalStreamInactive){
147 result->dir=SalStreamInactive;
148 }else result->dir=SalStreamSendRecv;
149 if (result->payloads && !only_telephone_event(result->payloads)){
150 strcpy(result->addr,local_cap->addr);
151 result->port=local_cap->port;
152 result->bandwidth=local_cap->bandwidth;
153 result->ptime=local_cap->ptime;
160 * Returns a media description to run the streams with, based on a local offer
161 * and the returned response (remote).
163 int offer_answer_initiate_outgoing(const SalMediaDescription *local_offer,
164 const SalMediaDescription *remote_answer,
165 SalMediaDescription *result){
167 const SalStreamDescription *ls,*rs;
168 for(i=0,j=0;i<local_offer->nstreams;++i){
169 ms_message("Processing for stream %i",i);
170 ls=&local_offer->streams[i];
171 rs=sal_media_description_find_stream((SalMediaDescription*)remote_answer,ls->proto,ls->type);
173 initiate_outgoing(ls,rs,&result->streams[j]);
176 else ms_warning("No matching stream for %i",i);
179 strcpy(result->addr,remote_answer->addr);
184 * Returns a media description to run the streams with, based on the local capabilities and
185 * and the received offer.
186 * The returned media description is an answer and should be sent to the offerer.
188 int offer_answer_initiate_incoming(const SalMediaDescription *local_capabilities,
189 const SalMediaDescription *remote_offer,
190 SalMediaDescription *result){
192 const SalStreamDescription *ls,*rs;
194 for(i=0,j=0;i<remote_offer->nstreams;++i){
195 rs=&remote_offer->streams[i];
196 ms_message("Processing for stream %i",i);
197 ls=sal_media_description_find_stream((SalMediaDescription*)local_capabilities,rs->proto,rs->type);
199 initiate_incoming(ls,rs,&result->streams[j]);
204 strcpy(result->username, local_capabilities->username);
205 strcpy(result->addr,local_capabilities->addr);