1
/* $Id: sdp_cmp.c 3553 2011-05-05 06:14:19Z nanang $ */
3
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
4
* Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
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.
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.
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
20
#include <pjmedia/sdp.h>
21
#include <pjmedia/errno.h>
22
#include <pj/assert.h>
23
#include <pj/string.h>
26
/* Compare connection line. */
27
static pj_status_t compare_conn(const pjmedia_sdp_conn *c1,
28
const pjmedia_sdp_conn *c2)
30
/* Compare network type. */
31
if (pj_strcmp(&c1->net_type, &c2->net_type) != 0)
32
return PJMEDIA_SDP_ECONNNOTEQUAL;
34
/* Compare address type. */
35
if (pj_strcmp(&c1->addr_type, &c2->addr_type) != 0)
36
return PJMEDIA_SDP_ECONNNOTEQUAL;
38
/* Compare address. */
39
if (pj_strcmp(&c1->addr, &c2->addr) != 0)
40
return PJMEDIA_SDP_ECONNNOTEQUAL;
45
/* Compare attributes array. */
46
static pj_status_t compare_attr_imp(unsigned count1,
47
pjmedia_sdp_attr *const attr1[],
49
pjmedia_sdp_attr *const attr2[])
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 };
60
/* For simplicity, we only compare the following attributes, and ignore
62
* - direction, eg. inactive, sendonly, recvonly, sendrecv
63
* - fmtp for each payload.
64
* - rtpmap for each payload.
66
for (i=0; i<count1; ++i) {
67
const pjmedia_sdp_attr *a1 = attr1[i];
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)
74
/* For inactive, sendrecv, sendonly, and recvonly attributes,
75
* the same attribute must be present on the other SDP.
77
const pjmedia_sdp_attr *a2;
78
a2 = pjmedia_sdp_attr_find(count2, attr2, &a1->name, NULL);
80
return PJMEDIA_SDP_EDIRNOTEQUAL;
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.
86
pjmedia_sdp_fmtp fmtp1, fmtp2;
87
const pjmedia_sdp_attr *a2;
89
status = pjmedia_sdp_attr_get_fmtp(a1, &fmtp1);
90
if (status != PJ_SUCCESS)
91
return PJMEDIA_SDP_EFMTPNOTEQUAL;
93
a2 = pjmedia_sdp_attr_find(count2, attr2, &a1->name, &fmtp1.fmt);
95
return PJMEDIA_SDP_EFMTPNOTEQUAL;
97
status = pjmedia_sdp_attr_get_fmtp(a2, &fmtp2);
98
if (status != PJ_SUCCESS)
99
return PJMEDIA_SDP_EFMTPNOTEQUAL;
101
if (pj_strcmp(&fmtp1.fmt_param, &fmtp2.fmt_param) != 0)
102
return PJMEDIA_SDP_EFMTPNOTEQUAL;
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
109
pjmedia_sdp_rtpmap r1, r2;
110
const pjmedia_sdp_attr *a2;
112
status = pjmedia_sdp_attr_get_rtpmap(a1, &r1);
113
if (status != PJ_SUCCESS)
114
return PJMEDIA_SDP_ERTPMAPNOTEQUAL;
116
a2 = pjmedia_sdp_attr_find(count2, attr2, &a1->name, &r1.pt);
118
return PJMEDIA_SDP_ERTPMAPNOTEQUAL;
120
status = pjmedia_sdp_attr_get_rtpmap(a2, &r2);
121
if (status != PJ_SUCCESS)
122
return PJMEDIA_SDP_ERTPMAPNOTEQUAL;
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;
139
/* Compare attributes array. */
140
static pj_status_t compare_attr(unsigned count1,
141
pjmedia_sdp_attr *const attr1[],
143
pjmedia_sdp_attr *const attr2[])
147
status = compare_attr_imp(count1, attr1, count2, attr2);
148
if (status != PJ_SUCCESS)
151
status = compare_attr_imp(count2, attr2, count1, attr1);
152
if (status != PJ_SUCCESS)
158
/* Compare media descriptor */
159
PJ_DEF(pj_status_t) pjmedia_sdp_media_cmp( const pjmedia_sdp_media *sd1,
160
const pjmedia_sdp_media *sd2,
166
PJ_ASSERT_RETURN(sd1 && sd2 && option==0, PJ_EINVAL);
168
PJ_UNUSED_ARG(option);
170
/* Compare media type. */
171
if (pj_strcmp(&sd1->desc.media, &sd2->desc.media) != 0)
172
return PJMEDIA_SDP_EMEDIANOTEQUAL;
174
/* Compare port number. */
175
if (sd1->desc.port != sd2->desc.port)
176
return PJMEDIA_SDP_EPORTNOTEQUAL;
178
/* Compare port count. */
179
if (sd1->desc.port_count != sd2->desc.port_count)
180
return PJMEDIA_SDP_EPORTNOTEQUAL;
182
/* Compare transports. */
183
if (pj_strcmp(&sd1->desc.transport, &sd2->desc.transport) != 0)
184
return PJMEDIA_SDP_ETPORTNOTEQUAL;
186
/* For zeroed port media, stop comparing here */
187
if (sd1->desc.port == 0)
190
/* Compare number of formats. */
191
if (sd1->desc.fmt_count != sd2->desc.fmt_count)
192
return PJMEDIA_SDP_EFORMATNOTEQUAL;
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;
200
/* Compare connection line, if they exist. */
203
return PJMEDIA_SDP_EMEDIANOTEQUAL;
204
status = compare_conn(sd1->conn, sd2->conn);
207
return PJMEDIA_SDP_EMEDIANOTEQUAL;
210
/* Compare attributes. */
211
status = compare_attr(sd1->attr_count, sd1->attr,
212
sd2->attr_count, sd2->attr);
213
if (status != PJ_SUCCESS)
221
* Compare two SDP session for equality.
223
PJ_DEF(pj_status_t) pjmedia_sdp_session_cmp( const pjmedia_sdp_session *sd1,
224
const pjmedia_sdp_session *sd2,
230
PJ_ASSERT_RETURN(sd1 && sd2 && option==0, PJ_EINVAL);
232
PJ_UNUSED_ARG(option);
234
/* Compare the origin line. */
235
if (pj_strcmp(&sd1->origin.user, &sd2->origin.user) != 0)
236
return PJMEDIA_SDP_EORIGINNOTEQUAL;
238
if (sd1->origin.id != sd2->origin.id)
239
return PJMEDIA_SDP_EORIGINNOTEQUAL;
241
if (sd1->origin.version != sd2->origin.version)
242
return PJMEDIA_SDP_EORIGINNOTEQUAL;
244
if (pj_strcmp(&sd1->origin.net_type, &sd2->origin.net_type) != 0)
245
return PJMEDIA_SDP_EORIGINNOTEQUAL;
247
if (pj_strcmp(&sd1->origin.addr_type, &sd2->origin.addr_type) != 0)
248
return PJMEDIA_SDP_EORIGINNOTEQUAL;
250
if (pj_strcmp(&sd1->origin.addr, &sd2->origin.addr) != 0)
251
return PJMEDIA_SDP_EORIGINNOTEQUAL;
254
/* Compare the subject line. */
255
if (pj_strcmp(&sd1->name, &sd2->name) != 0)
256
return PJMEDIA_SDP_ENAMENOTEQUAL;
258
/* Compare connection line, when they exist */
261
return PJMEDIA_SDP_ECONNNOTEQUAL;
262
status = compare_conn(sd1->conn, sd2->conn);
263
if (status != PJ_SUCCESS)
267
return PJMEDIA_SDP_ECONNNOTEQUAL;
270
/* Compare time line. */
271
if (sd1->time.start != sd2->time.start)
272
return PJMEDIA_SDP_ETIMENOTEQUAL;
274
if (sd1->time.stop != sd2->time.stop)
275
return PJMEDIA_SDP_ETIMENOTEQUAL;
277
/* Compare attributes. */
278
status = compare_attr(sd1->attr_count, sd1->attr,
279
sd2->attr_count, sd2->attr);
280
if (status != PJ_SUCCESS)
283
/* Compare media lines. */
284
if (sd1->media_count != sd2->media_count)
285
return PJMEDIA_SDP_EMEDIANOTEQUAL;
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)