blob: b4a23c74a87d7f1e46df821b0cd10af07703c233 [file] [log] [blame]
Alexandre Lision67916dd2014-01-24 13:33:04 -05001/* $Id$ */
2/*
3 * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
4 * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20#include <pjmedia/sdp.h>
21#include <pjmedia/errno.h>
22#include <pj/assert.h>
23#include <pj/string.h>
24
25
26/* Compare connection line. */
27static pj_status_t compare_conn(const pjmedia_sdp_conn *c1,
28 const pjmedia_sdp_conn *c2)
29{
30 /* Compare network type. */
31 if (pj_strcmp(&c1->net_type, &c2->net_type) != 0)
32 return PJMEDIA_SDP_ECONNNOTEQUAL;
33
34 /* Compare address type. */
35 if (pj_strcmp(&c1->addr_type, &c2->addr_type) != 0)
36 return PJMEDIA_SDP_ECONNNOTEQUAL;
37
38 /* Compare address. */
39 if (pj_strcmp(&c1->addr, &c2->addr) != 0)
40 return PJMEDIA_SDP_ECONNNOTEQUAL;
41
42 return PJ_SUCCESS;
43}
44
45/* Compare attributes array. */
46static pj_status_t compare_attr_imp(unsigned count1,
47 pjmedia_sdp_attr *const attr1[],
48 unsigned count2,
49 pjmedia_sdp_attr *const attr2[])
50{
51 pj_status_t status;
52 unsigned i;
53 const pj_str_t inactive = { "inactive", 8 };
54 const pj_str_t sendrecv = { "sendrecv", 8 };
55 const pj_str_t sendonly = { "sendonly", 8 };
56 const pj_str_t recvonly = { "recvonly", 8 };
57 const pj_str_t fmtp = { "fmtp", 4 };
58 const pj_str_t rtpmap = { "rtpmap", 6 };
59
60 /* For simplicity, we only compare the following attributes, and ignore
61 * the others:
62 * - direction, eg. inactive, sendonly, recvonly, sendrecv
63 * - fmtp for each payload.
64 * - rtpmap for each payload.
65 */
66 for (i=0; i<count1; ++i) {
67 const pjmedia_sdp_attr *a1 = attr1[i];
68
69 if (pj_strcmp(&a1->name, &inactive) == 0 ||
70 pj_strcmp(&a1->name, &sendrecv) == 0 ||
71 pj_strcmp(&a1->name, &sendonly) == 0 ||
72 pj_strcmp(&a1->name, &recvonly) == 0)
73 {
74 /* For inactive, sendrecv, sendonly, and recvonly attributes,
75 * the same attribute must be present on the other SDP.
76 */
77 const pjmedia_sdp_attr *a2;
78 a2 = pjmedia_sdp_attr_find(count2, attr2, &a1->name, NULL);
79 if (!a2)
80 return PJMEDIA_SDP_EDIRNOTEQUAL;
81
82 } else if (pj_strcmp(&a1->name, &fmtp) == 0) {
83 /* For fmtp attribute, find the fmtp attribute in the other SDP
84 * for the same payload type, and compare the fmtp param/value.
85 */
86 pjmedia_sdp_fmtp fmtp1, fmtp2;
87 const pjmedia_sdp_attr *a2;
88
89 status = pjmedia_sdp_attr_get_fmtp(a1, &fmtp1);
90 if (status != PJ_SUCCESS)
91 return PJMEDIA_SDP_EFMTPNOTEQUAL;
92
93 a2 = pjmedia_sdp_attr_find(count2, attr2, &a1->name, &fmtp1.fmt);
94 if (!a2)
95 return PJMEDIA_SDP_EFMTPNOTEQUAL;
96
97 status = pjmedia_sdp_attr_get_fmtp(a2, &fmtp2);
98 if (status != PJ_SUCCESS)
99 return PJMEDIA_SDP_EFMTPNOTEQUAL;
100
101 if (pj_strcmp(&fmtp1.fmt_param, &fmtp2.fmt_param) != 0)
102 return PJMEDIA_SDP_EFMTPNOTEQUAL;
103
104 } else if (pj_strcmp(&a1->name, &rtpmap) == 0) {
105 /* For rtpmap attribute, find rtpmap attribute on the other SDP
106 * for the same payload type, and compare both rtpmap atribute
107 * values.
108 */
109 pjmedia_sdp_rtpmap r1, r2;
110 const pjmedia_sdp_attr *a2;
111
112 status = pjmedia_sdp_attr_get_rtpmap(a1, &r1);
113 if (status != PJ_SUCCESS)
114 return PJMEDIA_SDP_ERTPMAPNOTEQUAL;
115
116 a2 = pjmedia_sdp_attr_find(count2, attr2, &a1->name, &r1.pt);
117 if (!a2)
118 return PJMEDIA_SDP_ERTPMAPNOTEQUAL;
119
120 status = pjmedia_sdp_attr_get_rtpmap(a2, &r2);
121 if (status != PJ_SUCCESS)
122 return PJMEDIA_SDP_ERTPMAPNOTEQUAL;
123
124 if (pj_strcmp(&r1.pt, &r2.pt) != 0)
125 return PJMEDIA_SDP_ERTPMAPNOTEQUAL;
126 if (pj_strcmp(&r1.enc_name, &r2.enc_name) != 0)
127 return PJMEDIA_SDP_ERTPMAPNOTEQUAL;
128 if (r1.clock_rate != r2.clock_rate)
129 return PJMEDIA_SDP_ERTPMAPNOTEQUAL;
130 if (pj_strcmp(&r1.param, &r2.param) != 0)
131 return PJMEDIA_SDP_ERTPMAPNOTEQUAL;
132 }
133 }
134
135 return PJ_SUCCESS;
136}
137
138
139/* Compare attributes array. */
140static pj_status_t compare_attr(unsigned count1,
141 pjmedia_sdp_attr *const attr1[],
142 unsigned count2,
143 pjmedia_sdp_attr *const attr2[])
144{
145 pj_status_t status;
146
147 status = compare_attr_imp(count1, attr1, count2, attr2);
148 if (status != PJ_SUCCESS)
149 return status;
150
151 status = compare_attr_imp(count2, attr2, count1, attr1);
152 if (status != PJ_SUCCESS)
153 return status;
154
155 return PJ_SUCCESS;
156}
157
158/* Compare media descriptor */
159PJ_DEF(pj_status_t) pjmedia_sdp_media_cmp( const pjmedia_sdp_media *sd1,
160 const pjmedia_sdp_media *sd2,
161 unsigned option)
162{
163 unsigned i;
164 pj_status_t status;
165
166 PJ_ASSERT_RETURN(sd1 && sd2 && option==0, PJ_EINVAL);
167
168 PJ_UNUSED_ARG(option);
169
170 /* Compare media type. */
171 if (pj_strcmp(&sd1->desc.media, &sd2->desc.media) != 0)
172 return PJMEDIA_SDP_EMEDIANOTEQUAL;
173
174 /* Compare port number. */
175 if (sd1->desc.port != sd2->desc.port)
176 return PJMEDIA_SDP_EPORTNOTEQUAL;
177
178 /* Compare port count. */
179 if (sd1->desc.port_count != sd2->desc.port_count)
180 return PJMEDIA_SDP_EPORTNOTEQUAL;
181
182 /* Compare transports. */
183 if (pj_strcmp(&sd1->desc.transport, &sd2->desc.transport) != 0)
184 return PJMEDIA_SDP_ETPORTNOTEQUAL;
185
186 /* For zeroed port media, stop comparing here */
187 if (sd1->desc.port == 0)
188 return PJ_SUCCESS;
189
190 /* Compare number of formats. */
191 if (sd1->desc.fmt_count != sd2->desc.fmt_count)
192 return PJMEDIA_SDP_EFORMATNOTEQUAL;
193
194 /* Compare formats, in order. */
195 for (i=0; i<sd1->desc.fmt_count; ++i) {
196 if (pj_strcmp(&sd1->desc.fmt[i], &sd2->desc.fmt[i]) != 0)
197 return PJMEDIA_SDP_EFORMATNOTEQUAL;
198 }
199
200 /* Compare connection line, if they exist. */
201 if (sd1->conn) {
202 if (!sd2->conn)
203 return PJMEDIA_SDP_EMEDIANOTEQUAL;
204 status = compare_conn(sd1->conn, sd2->conn);
205 } else {
206 if (sd2->conn)
207 return PJMEDIA_SDP_EMEDIANOTEQUAL;
208 }
209
210 /* Compare attributes. */
211 status = compare_attr(sd1->attr_count, sd1->attr,
212 sd2->attr_count, sd2->attr);
213 if (status != PJ_SUCCESS)
214 return status;
215
216 /* Looks equal */
217 return PJ_SUCCESS;
218}
219
220/*
221 * Compare two SDP session for equality.
222 */
223PJ_DEF(pj_status_t) pjmedia_sdp_session_cmp( const pjmedia_sdp_session *sd1,
224 const pjmedia_sdp_session *sd2,
225 unsigned option)
226{
227 unsigned i;
228 pj_status_t status;
229
230 PJ_ASSERT_RETURN(sd1 && sd2 && option==0, PJ_EINVAL);
231
232 PJ_UNUSED_ARG(option);
233
234 /* Compare the origin line. */
235 if (pj_strcmp(&sd1->origin.user, &sd2->origin.user) != 0)
236 return PJMEDIA_SDP_EORIGINNOTEQUAL;
237
238 if (sd1->origin.id != sd2->origin.id)
239 return PJMEDIA_SDP_EORIGINNOTEQUAL;
240
241 if (sd1->origin.version != sd2->origin.version)
242 return PJMEDIA_SDP_EORIGINNOTEQUAL;
243
244 if (pj_strcmp(&sd1->origin.net_type, &sd2->origin.net_type) != 0)
245 return PJMEDIA_SDP_EORIGINNOTEQUAL;
246
247 if (pj_strcmp(&sd1->origin.addr_type, &sd2->origin.addr_type) != 0)
248 return PJMEDIA_SDP_EORIGINNOTEQUAL;
249
250 if (pj_strcmp(&sd1->origin.addr, &sd2->origin.addr) != 0)
251 return PJMEDIA_SDP_EORIGINNOTEQUAL;
252
253
254 /* Compare the subject line. */
255 if (pj_strcmp(&sd1->name, &sd2->name) != 0)
256 return PJMEDIA_SDP_ENAMENOTEQUAL;
257
258 /* Compare connection line, when they exist */
259 if (sd1->conn) {
260 if (!sd2->conn)
261 return PJMEDIA_SDP_ECONNNOTEQUAL;
262 status = compare_conn(sd1->conn, sd2->conn);
263 if (status != PJ_SUCCESS)
264 return status;
265 } else {
266 if (sd2->conn)
267 return PJMEDIA_SDP_ECONNNOTEQUAL;
268 }
269
270 /* Compare time line. */
271 if (sd1->time.start != sd2->time.start)
272 return PJMEDIA_SDP_ETIMENOTEQUAL;
273
274 if (sd1->time.stop != sd2->time.stop)
275 return PJMEDIA_SDP_ETIMENOTEQUAL;
276
277 /* Compare attributes. */
278 status = compare_attr(sd1->attr_count, sd1->attr,
279 sd2->attr_count, sd2->attr);
280 if (status != PJ_SUCCESS)
281 return status;
282
283 /* Compare media lines. */
284 if (sd1->media_count != sd2->media_count)
285 return PJMEDIA_SDP_EMEDIANOTEQUAL;
286
287 for (i=0; i<sd1->media_count; ++i) {
288 status = pjmedia_sdp_media_cmp(sd1->media[i], sd2->media[i], 0);
289 if (status != PJ_SUCCESS)
290 return status;
291 }
292
293 /* Looks equal. */
294 return PJ_SUCCESS;
295}
296
297
298PJ_DEF(pj_status_t) pjmedia_sdp_conn_cmp(const pjmedia_sdp_conn *conn1,
299 const pjmedia_sdp_conn *conn2,
300 unsigned option)
301{
302 PJ_UNUSED_ARG(option);
303 return compare_conn(conn1, conn2);
304}