Transfers: Make Asterisk set ATTENDEDTRANSFER/BLINDTRANSFER more reliably
[asterisk/asterisk.git] / res / res_format_attr_h263.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2012, Digium, Inc.
5  *
6  * Joshua Colp <jcolp@digium.com>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  *
18  */
19
20 /*! \file
21  *
22  * \brief H.263 Format Attribute Module
23  *
24  * \author\verbatim Joshua Colp <jcolp@digium.com> \endverbatim
25  *
26  * This is a format attribute module for the H.263 codec.
27  * \ingroup applications
28  */
29
30 /*** MODULEINFO
31         <support_level>core</support_level>
32  ***/
33
34 #include "asterisk.h"
35
36 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
37
38 #include "asterisk/module.h"
39 #include "asterisk/format.h"
40
41 enum h263_attr_keys {
42         H263_ATTR_KEY_SQCIF,       /*!< Minimum picture interval for SQCIF resolution */
43         H263_ATTR_KEY_QCIF,        /*!< Minimum picture interval for QCIF resolution */
44         H263_ATTR_KEY_CIF,         /*!< Minimum picture interval for CIF resolution */
45         H263_ATTR_KEY_CIF4,        /*!< Minimum picture interval for CIF4 resolution */
46         H263_ATTR_KEY_CIF16,       /*!< Minimum picture interval for CIF16 resolution */
47         H263_ATTR_KEY_VGA,         /*!< Minimum picture interval for VGA resolution */
48         H263_ATTR_KEY_CUSTOM_XMAX, /*!< Custom resolution (Xmax) */
49         H263_ATTR_KEY_CUSTOM_YMAX, /*!< Custom resolution (Ymax) */
50         H263_ATTR_KEY_CUSTOM_MPI,  /*!< Custom resolution (MPI) */
51         H263_ATTR_KEY_F,           /*!< F annex support */
52         H263_ATTR_KEY_I,           /*!< I annex support */
53         H263_ATTR_KEY_J,           /*!< J annex support */
54         H263_ATTR_KEY_T,           /*!< T annex support */
55         H263_ATTR_KEY_K,           /*!< K annex support */
56         H263_ATTR_KEY_N,           /*!< N annex support */
57         H263_ATTR_KEY_P_SUB1,      /*!< Reference picture resampling (sub mode 1) */
58         H263_ATTR_KEY_P_SUB2,      /*!< Reference picture resampling (sub mode 2) */
59         H263_ATTR_KEY_P_SUB3,      /*!< Reference picture resampling (sub mode 3) */
60         H263_ATTR_KEY_P_SUB4,      /*!< Reference picture resampling (sub mode 4) */
61         H263_ATTR_KEY_PAR_WIDTH,   /*!< Pixel aspect ratio (width) */
62         H263_ATTR_KEY_PAR_HEIGHT,  /*!< Pixel aspect ratio (height) */
63         H263_ATTR_KEY_BPP,         /*!< Bits per picture maximum */
64         H263_ATTR_KEY_HRD,         /*!< Hypothetical reference decoder status */
65         H263_ATTR_KEY_END,         /*!< End terminator for list */
66 };
67
68 static int h263_format_attr_get_joint(const struct ast_format_attr *fattr1, const struct ast_format_attr *fattr2, struct ast_format_attr *result)
69 {
70         int i;
71
72         /* These are all receiver options so we just copy over what they sent */
73         for (i = H263_ATTR_KEY_SQCIF; i < H263_ATTR_KEY_END; i++) {
74                 result->format_attr[i] = fattr1->format_attr[i] ? fattr1->format_attr[i] : fattr2->format_attr[i];
75         }
76
77         return 0;
78 }
79
80 static int h263_format_attr_sdp_parse(struct ast_format_attr *format_attr, const char *attributes)
81 {
82         char *attribs = ast_strdupa(attributes), *attrib;
83
84         while ((attrib = strsep(&attribs, ";"))) {
85                 unsigned int val, val2 = 0, val3 = 0, val4 = 0;
86
87                 if (sscanf(attrib, "SQCIF=%30u", &val) == 1) {
88                         format_attr->format_attr[H263_ATTR_KEY_SQCIF] = val;
89                 } else if (sscanf(attrib, "QCIF=%30u", &val) == 1) {
90                         format_attr->format_attr[H263_ATTR_KEY_QCIF] = val;
91                 } else if (sscanf(attrib, "CIF=%30u", &val) == 1) {
92                         format_attr->format_attr[H263_ATTR_KEY_CIF] = val;
93                 } else if (sscanf(attrib, "CIF4=%30u", &val) == 1) {
94                         format_attr->format_attr[H263_ATTR_KEY_CIF4] = val;
95                 } else if (sscanf(attrib, "CIF16=%30u", &val) == 1) {
96                         format_attr->format_attr[H263_ATTR_KEY_CIF16] = val;
97                 } else if (sscanf(attrib, "VGA=%30u", &val) == 1) {
98                         format_attr->format_attr[H263_ATTR_KEY_VGA] = val;
99                 } else if (sscanf(attrib, "CUSTOM=%30u,%30u,%30u", &val, &val2, &val3) == 3) {
100                         format_attr->format_attr[H263_ATTR_KEY_CUSTOM_XMAX] = val;
101                         format_attr->format_attr[H263_ATTR_KEY_CUSTOM_YMAX] = val2;
102                         format_attr->format_attr[H263_ATTR_KEY_CUSTOM_MPI] = val3;
103                 } else if (sscanf(attrib, "F=%30u", &val) == 1) {
104                         format_attr->format_attr[H263_ATTR_KEY_F] = val;
105                 } else if (sscanf(attrib, "I=%30u", &val) == 1) {
106                         format_attr->format_attr[H263_ATTR_KEY_I] = val;
107                 } else if (sscanf(attrib, "J=%30u", &val) == 1) {
108                         format_attr->format_attr[H263_ATTR_KEY_J] = val;
109                 } else if (sscanf(attrib, "T=%30u", &val) == 1) {
110                         format_attr->format_attr[H263_ATTR_KEY_T] = val;
111                 } else if (sscanf(attrib, "K=%30u", &val) == 1) {
112                         format_attr->format_attr[H263_ATTR_KEY_K] = val;
113                 } else if (sscanf(attrib, "N=%30u", &val) == 1) {
114                         format_attr->format_attr[H263_ATTR_KEY_N] = val;
115                 } else if (sscanf(attrib, "PAR=%30u:%30u", &val, &val2) == 2) {
116                         format_attr->format_attr[H263_ATTR_KEY_PAR_WIDTH] = val;
117                         format_attr->format_attr[H263_ATTR_KEY_PAR_HEIGHT] = val2;
118                 } else if (sscanf(attrib, "BPP=%30u", &val) == 1) {
119                         format_attr->format_attr[H263_ATTR_KEY_BPP] = val;
120                 } else if (sscanf(attrib, "HRD=%30u", &val) == 1) {
121                         format_attr->format_attr[H263_ATTR_KEY_HRD] = val;
122                 } else if (sscanf(attrib, "P=%30u,%30u,%30u,%30u", &val, &val2, &val3, &val4) > 0) {
123                         format_attr->format_attr[H263_ATTR_KEY_P_SUB1] = val;
124                         format_attr->format_attr[H263_ATTR_KEY_P_SUB2] = val2;
125                         format_attr->format_attr[H263_ATTR_KEY_P_SUB3] = val3;
126                         format_attr->format_attr[H263_ATTR_KEY_P_SUB4] = val4;
127                 }
128         }
129
130         return 0;
131 }
132
133 /*! \brief Helper function which converts a key enum into a string value for SDP */
134 static const char *h263_attr_key_to_str(enum h263_attr_keys key, const struct ast_format_attr *format_attr)
135 {
136         switch (key) {
137         case H263_ATTR_KEY_SQCIF:
138                 return format_attr->format_attr[key] ? "SQCIF" : NULL;
139         case H263_ATTR_KEY_QCIF:
140                 return format_attr->format_attr[key] ? "QCIF" : NULL;
141         case H263_ATTR_KEY_CIF:
142                 return format_attr->format_attr[key] ? "CIF" : NULL;
143         case H263_ATTR_KEY_CIF4:
144                 return format_attr->format_attr[key] ? "CIF4" : NULL;
145         case H263_ATTR_KEY_CIF16:
146                 return format_attr->format_attr[key] ? "CIF16" : NULL;
147         case H263_ATTR_KEY_VGA:
148                 return format_attr->format_attr[key] ? "VGA" : NULL;
149         case H263_ATTR_KEY_F:
150                 return "F";
151         case H263_ATTR_KEY_I:
152                 return "I";
153         case H263_ATTR_KEY_J:
154                 return "J";
155         case H263_ATTR_KEY_T:
156                 return "T";
157         case H263_ATTR_KEY_K:
158                 return "K";
159         case H263_ATTR_KEY_N:
160                 return "N";
161         case H263_ATTR_KEY_BPP:
162                 return "BPP";
163         case H263_ATTR_KEY_HRD:
164                 return "HRD";
165         case H263_ATTR_KEY_CUSTOM_XMAX:
166         case H263_ATTR_KEY_CUSTOM_YMAX:
167         case H263_ATTR_KEY_CUSTOM_MPI:
168         case H263_ATTR_KEY_P_SUB1:
169         case H263_ATTR_KEY_P_SUB2:
170         case H263_ATTR_KEY_P_SUB3:
171         case H263_ATTR_KEY_P_SUB4:
172         case H263_ATTR_KEY_PAR_WIDTH:
173         case H263_ATTR_KEY_PAR_HEIGHT:
174         case H263_ATTR_KEY_END:
175         default:
176                 return NULL;
177         }
178
179         return NULL;
180 }
181
182 static void h263_format_attr_sdp_generate(const struct ast_format_attr *format_attr, unsigned int payload, struct ast_str **str)
183 {
184         int i, added = 0;
185
186         for (i = H263_ATTR_KEY_SQCIF; i < H263_ATTR_KEY_END; i++) {
187                 const char *name;
188
189                 if (i == H263_ATTR_KEY_CUSTOM_XMAX) {
190                         if (!format_attr->format_attr[H263_ATTR_KEY_CUSTOM_XMAX] || !format_attr->format_attr[H263_ATTR_KEY_CUSTOM_YMAX] ||
191                             !format_attr->format_attr[H263_ATTR_KEY_CUSTOM_MPI]) {
192                                 continue;
193                         }
194
195                         if (!added) {
196                                 ast_str_append(str, 0, "a=fmtp:%d CUSTOM=%u,%u,%u", payload, format_attr->format_attr[H263_ATTR_KEY_CUSTOM_XMAX],
197                                                format_attr->format_attr[H263_ATTR_KEY_CUSTOM_YMAX], format_attr->format_attr[H263_ATTR_KEY_CUSTOM_MPI]);
198                                 added = 1;
199                         } else {
200                                 ast_str_append(str, 0, ";CUSTOM=%u,%u,%u", format_attr->format_attr[H263_ATTR_KEY_CUSTOM_XMAX],
201                                                format_attr->format_attr[H263_ATTR_KEY_CUSTOM_YMAX], format_attr->format_attr[H263_ATTR_KEY_CUSTOM_MPI]);
202                         }
203                 } else if (i == H263_ATTR_KEY_PAR_WIDTH) {
204                         if (!format_attr->format_attr[H263_ATTR_KEY_PAR_WIDTH] || !format_attr->format_attr[H263_ATTR_KEY_PAR_HEIGHT]) {
205                                 continue;
206                         }
207
208                         if (!added) {
209                                 ast_str_append(str, 0, "a=fmtp:%d PAR=%u:%u", payload, format_attr->format_attr[H263_ATTR_KEY_PAR_WIDTH],
210                                                format_attr->format_attr[H263_ATTR_KEY_PAR_HEIGHT]);
211                                 added = 1;
212                         } else {
213                                 ast_str_append(str, 0, ";PAR=%u:%u", format_attr->format_attr[H263_ATTR_KEY_PAR_WIDTH],
214                                                format_attr->format_attr[H263_ATTR_KEY_PAR_HEIGHT]);
215                         }
216                 } else if (i == H263_ATTR_KEY_P_SUB1) {
217                         if (!format_attr->format_attr[H263_ATTR_KEY_P_SUB1]) {
218                                 continue;
219                         }
220
221                         if (!added) {
222                                 ast_str_append(str, 0, "a=fmtp:%d P=%u", payload, format_attr->format_attr[H263_ATTR_KEY_P_SUB1]);
223                                 added = 1;
224                         } else {
225                                 ast_str_append(str, 0, ";P=%u", format_attr->format_attr[H263_ATTR_KEY_P_SUB1]);
226                         }
227
228                         if (format_attr->format_attr[H263_ATTR_KEY_P_SUB2]) {
229                                 ast_str_append(str, 0, ",%u", format_attr->format_attr[H263_ATTR_KEY_P_SUB2]);
230                         }
231                         if (format_attr->format_attr[H263_ATTR_KEY_P_SUB3]) {
232                                 ast_str_append(str, 0, ",%u", format_attr->format_attr[H263_ATTR_KEY_P_SUB3]);
233                         }
234                         if (format_attr->format_attr[H263_ATTR_KEY_P_SUB4]) {
235                                 ast_str_append(str, 0, ",%u", format_attr->format_attr[H263_ATTR_KEY_P_SUB4]);
236                         }
237
238                 } else if ((name = h263_attr_key_to_str(i, format_attr))) {
239                         if (!added) {
240                                 ast_str_append(str, 0, "a=fmtp:%d %s=%u", payload, name, format_attr->format_attr[i]);
241                                 added = 1;
242                         } else {
243                                 ast_str_append(str, 0, ";%s=%u", name, format_attr->format_attr[i]);
244                         }
245                 }
246         }
247
248         if (added) {
249                 ast_str_append(str, 0, "\r\n");
250         }
251
252         return;
253 }
254
255 static struct ast_format_attr_interface h263_format_attr_interface = {
256         .id = AST_FORMAT_H263,
257         .format_attr_get_joint = h263_format_attr_get_joint,
258         .format_attr_sdp_parse = h263_format_attr_sdp_parse,
259         .format_attr_sdp_generate = h263_format_attr_sdp_generate,
260 };
261
262 static struct ast_format_attr_interface h263p_format_attr_interface = {
263         .id = AST_FORMAT_H263_PLUS,
264         .format_attr_get_joint = h263_format_attr_get_joint,
265         .format_attr_sdp_parse = h263_format_attr_sdp_parse,
266         .format_attr_sdp_generate = h263_format_attr_sdp_generate,
267 };
268
269 static int unload_module(void)
270 {
271         ast_format_attr_unreg_interface(&h263_format_attr_interface);
272         ast_format_attr_unreg_interface(&h263p_format_attr_interface);
273
274         return 0;
275 }
276
277 static int load_module(void)
278 {
279         if (ast_format_attr_reg_interface(&h263_format_attr_interface)) {
280                 return AST_MODULE_LOAD_DECLINE;
281         }
282
283         if (ast_format_attr_reg_interface(&h263p_format_attr_interface)) {
284                 ast_format_attr_unreg_interface(&h263_format_attr_interface);
285                 return AST_MODULE_LOAD_DECLINE;
286         }
287
288         return AST_MODULE_LOAD_SUCCESS;
289 }
290
291 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "H.263 Format Attribute Module",
292         .load = load_module,
293         .unload = unload_module,
294         .load_pri = AST_MODPRI_DEFAULT,
295 );