1 /**
2  * @file sdp/format.c  SDP format
3  *
4  * Copyright (C) 2010 Creytiv.com
5  */
6 #include <stdlib.h>
7 #include <string.h>
8 #include <re_types.h>
9 #include <re_fmt.h>
10 #include <re_mem.h>
11 #include <re_mbuf.h>
12 #include <re_list.h>
13 #include <re_sa.h>
14 #include <re_sdp.h>
15 #include "sdp.h"
16 
17 
destructor(void * arg)18 static void destructor(void *arg)
19 {
20 	struct sdp_format *fmt = arg;
21 
22 	list_unlink(&fmt->le);
23 
24 	if (fmt->ref)
25 		mem_deref(fmt->data);
26 
27 	mem_deref(fmt->id);
28 	mem_deref(fmt->params);
29 	mem_deref(fmt->rparams);
30 	mem_deref(fmt->name);
31 }
32 
33 
34 /**
35  * Add an SDP Format to an SDP Media line
36  *
37  * @param fmtp    Pointer to allocated SDP Format
38  * @param m       SDP Media line
39  * @param prepend True to prepend, False to append
40  * @param id      Format identifier
41  * @param name    Format name
42  * @param srate   Sampling rate
43  * @param ch      Number of channels
44  * @param ench    Optional format encode handler
45  * @param cmph    Optional format comparison handler
46  * @param data    Opaque data for handler
47  * @param ref     True to mem_ref() data
48  * @param params  Formatted parameters
49  *
50  * @return 0 if success, otherwise errorcode
51  */
sdp_format_add(struct sdp_format ** fmtp,struct sdp_media * m,bool prepend,const char * id,const char * name,uint32_t srate,uint8_t ch,sdp_fmtp_enc_h * ench,sdp_fmtp_cmp_h * cmph,void * data,bool ref,const char * params,...)52 int sdp_format_add(struct sdp_format **fmtp, struct sdp_media *m,
53 		   bool prepend, const char *id, const char *name,
54 		   uint32_t srate, uint8_t ch, sdp_fmtp_enc_h *ench,
55 		   sdp_fmtp_cmp_h *cmph, void *data, bool ref,
56 		   const char *params, ...)
57 {
58 	struct sdp_format *fmt;
59 	int err;
60 
61 	if (!m)
62 		return EINVAL;
63 
64 	if (!id && (m->dynpt > RTP_DYNPT_END))
65 		return ERANGE;
66 
67 	fmt = mem_zalloc(sizeof(*fmt), destructor);
68 	if (!fmt)
69 		return ENOMEM;
70 
71 	if (prepend)
72 		list_prepend(&m->lfmtl, &fmt->le, fmt);
73 	else
74 		list_append(&m->lfmtl, &fmt->le, fmt);
75 
76 	if (id)
77 		err = str_dup(&fmt->id, id);
78 	else
79 		err = re_sdprintf(&fmt->id, "%i", m->dynpt++);
80 	if (err)
81 		goto out;
82 
83 	if (name) {
84 		err = str_dup(&fmt->name, name);
85 		if (err)
86 			goto out;
87 	}
88 
89 	if (params) {
90 		va_list ap;
91 
92 		va_start(ap, params);
93 		err = re_vsdprintf(&fmt->params, params, ap);
94 		va_end(ap);
95 
96 		if (err)
97 			goto out;
98 	}
99 
100 	fmt->pt    = atoi(fmt->id);
101 	fmt->srate = srate;
102 	fmt->ch    = ch;
103 	fmt->ench  = ench;
104 	fmt->cmph  = cmph;
105 	fmt->data  = ref ? mem_ref(data) : data;
106 	fmt->ref   = ref;
107 	fmt->sup   = true;
108 
109  out:
110 	if (err)
111 		mem_deref(fmt);
112 	else if (fmtp)
113 		*fmtp = fmt;
114 
115 	return err;
116 }
117 
118 
sdp_format_radd(struct sdp_media * m,const struct pl * id)119 int sdp_format_radd(struct sdp_media *m, const struct pl *id)
120 {
121 	struct sdp_format *fmt;
122 	int err;
123 
124 	if (!m || !id)
125 		return EINVAL;
126 
127 	fmt = mem_zalloc(sizeof(*fmt), destructor);
128 	if (!fmt)
129 		return ENOMEM;
130 
131 	list_append(&m->rfmtl, &fmt->le, fmt);
132 
133 	err = pl_strdup(&fmt->id, id);
134 	if (err)
135 		goto out;
136 
137 	fmt->pt = atoi(fmt->id);
138 
139  out:
140 	if (err)
141 		mem_deref(fmt);
142 
143 	return err;
144 }
145 
146 
sdp_format_find(const struct list * lst,const struct pl * id)147 struct sdp_format *sdp_format_find(const struct list *lst, const struct pl *id)
148 {
149 	struct le *le;
150 
151 	if (!lst || !id)
152 		return NULL;
153 
154 	for (le=lst->head; le; le=le->next) {
155 
156 		struct sdp_format *fmt = le->data;
157 
158 		if (pl_strcmp(id, fmt->id))
159 			continue;
160 
161 		return fmt;
162 	}
163 
164 	return NULL;
165 }
166 
167 
168 /**
169  * Set the parameters of an SDP format
170  *
171  * @param fmt    SDP Format
172  * @param params Formatted parameters
173  *
174  * @return 0 if success, otherwise errorcode
175  */
sdp_format_set_params(struct sdp_format * fmt,const char * params,...)176 int sdp_format_set_params(struct sdp_format *fmt, const char *params, ...)
177 {
178 	int err = 0;
179 
180 	if (!fmt)
181 		return EINVAL;
182 
183 	fmt->params = mem_deref(fmt->params);
184 
185 	if (params) {
186 		va_list ap;
187 
188 		va_start(ap, params);
189 		err = re_vsdprintf(&fmt->params, params, ap);
190 		va_end(ap);
191 	}
192 
193 	return err;
194 }
195 
196 
197 /**
198  * Compare two SDP Formats
199  *
200  * @param fmt1 First SDP format
201  * @param fmt2 Second SDP format
202  *
203  * @return True if matching, False if not
204  */
sdp_format_cmp(const struct sdp_format * fmt1,const struct sdp_format * fmt2)205 bool sdp_format_cmp(const struct sdp_format *fmt1,
206 		    const struct sdp_format *fmt2)
207 {
208 	if (!fmt1 || !fmt2)
209 		return false;
210 
211 	if (fmt1->pt < RTP_DYNPT_START && fmt2->pt < RTP_DYNPT_START) {
212 
213 		if (!fmt1->id || !fmt2->id)
214 			return false;
215 
216 		return strcmp(fmt1->id, fmt2->id) ? false : true;
217 	}
218 
219 	if (str_casecmp(fmt1->name, fmt2->name))
220 		return false;
221 
222 	if (fmt1->srate != fmt2->srate)
223 		return false;
224 
225 	if (fmt1->ch != fmt2->ch)
226 		return false;
227 
228 	if (fmt1->cmph && !fmt1->cmph(fmt1->params, fmt2->params, fmt1->data))
229 		return false;
230 
231 	if (fmt2->cmph && !fmt2->cmph(fmt2->params, fmt1->params, fmt2->data))
232 		return false;
233 
234 	return true;
235 }
236 
237 
238 /**
239  * Print SDP Format debug information
240  *
241  * @param pf  Print function for output
242  * @param fmt SDP Format
243  *
244  * @return 0 if success, otherwise errorcode
245  */
sdp_format_debug(struct re_printf * pf,const struct sdp_format * fmt)246 int sdp_format_debug(struct re_printf *pf, const struct sdp_format *fmt)
247 {
248 	int err;
249 
250 	if (!fmt)
251 		return 0;
252 
253 	err = re_hprintf(pf, "%3s", fmt->id);
254 
255 	if (fmt->name)
256 		err |= re_hprintf(pf, " %s/%u/%u",
257 				  fmt->name, fmt->srate, fmt->ch);
258 
259 	if (fmt->params)
260 		err |= re_hprintf(pf, " (%s)", fmt->params);
261 
262 	if (fmt->sup)
263 		err |= re_hprintf(pf, " *");
264 
265 	return err;
266 }
267