format_cap.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776
  1. /*
  2. * Asterisk -- An open source telephony toolkit.
  3. *
  4. * Copyright (C) 2014, 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. /*! \file
  19. *
  20. * \brief Format Capabilities API
  21. *
  22. * \author Joshua Colp <jcolp@digium.com>
  23. */
  24. /*** MODULEINFO
  25. <support_level>core</support_level>
  26. ***/
  27. #include "asterisk.h"
  28. ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
  29. #include "asterisk/logger.h"
  30. #include "asterisk/format.h"
  31. #include "asterisk/format_cap.h"
  32. #include "asterisk/format_cache.h"
  33. #include "asterisk/codec.h"
  34. #include "asterisk/astobj2.h"
  35. #include "asterisk/strings.h"
  36. #include "asterisk/vector.h"
  37. #include "asterisk/linkedlists.h"
  38. #include "asterisk/utils.h"
  39. /*! \brief Structure used for capability formats, adds framing */
  40. struct format_cap_framed {
  41. /*! \brief A pointer to the format */
  42. struct ast_format *format;
  43. /*! \brief The format framing size */
  44. unsigned int framing;
  45. /*! \brief Linked list information */
  46. AST_LIST_ENTRY(format_cap_framed) entry;
  47. };
  48. /*! \brief Format capabilities structure, holds formats + preference order + etc */
  49. struct ast_format_cap {
  50. /*! \brief Vector of formats, indexed using the codec identifier */
  51. AST_VECTOR(, struct format_cap_framed_list) formats;
  52. /*! \brief Vector of formats, added in preference order */
  53. AST_VECTOR(, struct format_cap_framed *) preference_order;
  54. /*! \brief Global framing size, applies to all formats if no framing present on format */
  55. unsigned int framing;
  56. };
  57. /*! \brief Linked list for formats */
  58. AST_LIST_HEAD_NOLOCK(format_cap_framed_list, format_cap_framed);
  59. /*! \brief Dummy empty list for when we are inserting a new list */
  60. static const struct format_cap_framed_list format_cap_framed_list_empty = AST_LIST_HEAD_NOLOCK_INIT_VALUE;
  61. /*! \brief Destructor for format capabilities structure */
  62. static void format_cap_destroy(void *obj)
  63. {
  64. struct ast_format_cap *cap = obj;
  65. int idx;
  66. for (idx = 0; idx < AST_VECTOR_SIZE(&cap->formats); idx++) {
  67. struct format_cap_framed_list *list = AST_VECTOR_GET_ADDR(&cap->formats, idx);
  68. struct format_cap_framed *framed;
  69. while ((framed = AST_LIST_REMOVE_HEAD(list, entry))) {
  70. ao2_ref(framed, -1);
  71. }
  72. }
  73. AST_VECTOR_FREE(&cap->formats);
  74. for (idx = 0; idx < AST_VECTOR_SIZE(&cap->preference_order); idx++) {
  75. struct format_cap_framed *framed = AST_VECTOR_GET(&cap->preference_order, idx);
  76. /* This will always be non-null, unlike formats */
  77. ao2_ref(framed, -1);
  78. }
  79. AST_VECTOR_FREE(&cap->preference_order);
  80. }
  81. /*
  82. * \brief Initialize values on an ast_format_cap
  83. *
  84. * \param cap ast_format_cap to initialize
  85. * \param flags Unused.
  86. * \retval 0 Success
  87. * \retval -1 Failure
  88. */
  89. static inline int format_cap_init(struct ast_format_cap *cap, enum ast_format_cap_flags flags)
  90. {
  91. if (AST_VECTOR_INIT(&cap->formats, 0)) {
  92. return -1;
  93. }
  94. /* TODO: Look at common usage of this and determine a good starting point */
  95. if (AST_VECTOR_INIT(&cap->preference_order, 5)) {
  96. return -1;
  97. }
  98. cap->framing = UINT_MAX;
  99. return 0;
  100. }
  101. struct ast_format_cap *__ast_format_cap_alloc(enum ast_format_cap_flags flags)
  102. {
  103. struct ast_format_cap *cap;
  104. cap = ao2_alloc_options(sizeof(*cap), format_cap_destroy, AO2_ALLOC_OPT_LOCK_NOLOCK);
  105. if (!cap) {
  106. return NULL;
  107. }
  108. if (format_cap_init(cap, flags)) {
  109. ao2_ref(cap, -1);
  110. return NULL;
  111. }
  112. return cap;
  113. }
  114. struct ast_format_cap *__ast_format_cap_alloc_debug(enum ast_format_cap_flags flags, const char *tag, const char *file, int line, const char *func)
  115. {
  116. struct ast_format_cap *cap;
  117. cap = __ao2_alloc_debug(sizeof(*cap), format_cap_destroy, AO2_ALLOC_OPT_LOCK_NOLOCK, S_OR(tag, "ast_format_cap_alloc"), file, line, func, 1);
  118. if (!cap) {
  119. return NULL;
  120. }
  121. if (format_cap_init(cap, flags)) {
  122. ao2_ref(cap, -1);
  123. return NULL;
  124. }
  125. return cap;
  126. }
  127. void ast_format_cap_set_framing(struct ast_format_cap *cap, unsigned int framing)
  128. {
  129. cap->framing = framing;
  130. }
  131. /*! \brief Destructor for format capabilities framed structure */
  132. static void format_cap_framed_destroy(void *obj)
  133. {
  134. struct format_cap_framed *framed = obj;
  135. ao2_cleanup(framed->format);
  136. }
  137. static inline int format_cap_framed_init(struct format_cap_framed *framed, struct ast_format_cap *cap, struct ast_format *format, unsigned int framing)
  138. {
  139. struct format_cap_framed_list *list;
  140. framed->framing = framing;
  141. if (ast_format_get_codec_id(format) >= AST_VECTOR_SIZE(&cap->formats)) {
  142. if (AST_VECTOR_REPLACE(&cap->formats, ast_format_get_codec_id(format), format_cap_framed_list_empty)) {
  143. ao2_ref(framed, -1);
  144. return -1;
  145. }
  146. }
  147. list = AST_VECTOR_GET_ADDR(&cap->formats, ast_format_get_codec_id(format));
  148. /* This takes the allocation reference */
  149. if (AST_VECTOR_APPEND(&cap->preference_order, framed)) {
  150. ao2_ref(framed, -1);
  151. return -1;
  152. }
  153. /* Order doesn't matter for formats, so insert at the head for performance reasons */
  154. ao2_ref(framed, +1);
  155. AST_LIST_INSERT_HEAD(list, framed, entry);
  156. cap->framing = MIN(cap->framing, framing ? framing : ast_format_get_default_ms(format));
  157. return 0;
  158. }
  159. /*! \internal \brief Determine if \c format is in \c cap */
  160. static int format_in_format_cap(struct ast_format_cap *cap, struct ast_format *format)
  161. {
  162. struct format_cap_framed *framed;
  163. int i;
  164. for (i = 0; i < AST_VECTOR_SIZE(&cap->preference_order); i++) {
  165. framed = AST_VECTOR_GET(&cap->preference_order, i);
  166. if (ast_format_get_codec_id(format) == ast_format_get_codec_id(framed->format)) {
  167. return 1;
  168. }
  169. }
  170. return 0;
  171. }
  172. int __ast_format_cap_append(struct ast_format_cap *cap, struct ast_format *format, unsigned int framing)
  173. {
  174. struct format_cap_framed *framed;
  175. ast_assert(format != NULL);
  176. if (format_in_format_cap(cap, format)) {
  177. return 0;
  178. }
  179. framed = ao2_alloc_options(sizeof(*framed), format_cap_framed_destroy, AO2_ALLOC_OPT_LOCK_NOLOCK);
  180. if (!framed) {
  181. return -1;
  182. }
  183. framed->format = ao2_bump(format);
  184. return format_cap_framed_init(framed, cap, format, framing);
  185. }
  186. int __ast_format_cap_append_debug(struct ast_format_cap *cap, struct ast_format *format, unsigned int framing, const char *tag, const char *file, int line, const char *func)
  187. {
  188. struct format_cap_framed *framed;
  189. ast_assert(format != NULL);
  190. if (format_in_format_cap(cap, format)) {
  191. return 0;
  192. }
  193. framed = ao2_alloc_options(sizeof(*framed), format_cap_framed_destroy, AO2_ALLOC_OPT_LOCK_NOLOCK);
  194. if (!framed) {
  195. return -1;
  196. }
  197. __ao2_ref_debug(format, +1, S_OR(tag, "ast_format_cap_append"), file, line, func);
  198. framed->format = format;
  199. return format_cap_framed_init(framed, cap, format, framing);
  200. }
  201. int ast_format_cap_append_by_type(struct ast_format_cap *cap, enum ast_media_type type)
  202. {
  203. int id;
  204. for (id = 1; id < ast_codec_get_max(); ++id) {
  205. struct ast_codec *codec = ast_codec_get_by_id(id);
  206. struct ast_codec *codec2 = NULL;
  207. struct ast_format *format;
  208. int res;
  209. if (!codec) {
  210. continue;
  211. }
  212. if ((type != AST_MEDIA_TYPE_UNKNOWN) && codec->type != type) {
  213. ao2_ref(codec, -1);
  214. continue;
  215. }
  216. format = ast_format_cache_get(codec->name);
  217. if (format == ast_format_none) {
  218. ao2_ref(format, -1);
  219. ao2_ref(codec, -1);
  220. continue;
  221. }
  222. if (format) {
  223. codec2 = ast_format_get_codec(format);
  224. }
  225. if (codec != codec2) {
  226. ao2_cleanup(format);
  227. format = ast_format_create(codec);
  228. }
  229. ao2_cleanup(codec2);
  230. ao2_ref(codec, -1);
  231. if (!format) {
  232. return -1;
  233. }
  234. /* Use the global framing or default framing of the codec */
  235. res = ast_format_cap_append(cap, format, 0);
  236. ao2_ref(format, -1);
  237. if (res) {
  238. return -1;
  239. }
  240. }
  241. return 0;
  242. }
  243. int ast_format_cap_append_from_cap(struct ast_format_cap *dst, const struct ast_format_cap *src,
  244. enum ast_media_type type)
  245. {
  246. int idx, res = 0;
  247. for (idx = 0; (idx < AST_VECTOR_SIZE(&src->preference_order)) && !res; ++idx) {
  248. struct format_cap_framed *framed = AST_VECTOR_GET(&src->preference_order, idx);
  249. if (type == AST_MEDIA_TYPE_UNKNOWN || ast_format_get_type(framed->format) == type) {
  250. res = ast_format_cap_append(dst, framed->format, framed->framing);
  251. }
  252. }
  253. return res;
  254. }
  255. static int format_cap_replace(struct ast_format_cap *cap, struct ast_format *format, unsigned int framing)
  256. {
  257. struct format_cap_framed *framed;
  258. int i;
  259. ast_assert(format != NULL);
  260. for (i = 0; i < AST_VECTOR_SIZE(&cap->preference_order); i++) {
  261. framed = AST_VECTOR_GET(&cap->preference_order, i);
  262. if (ast_format_get_codec_id(format) == ast_format_get_codec_id(framed->format)) {
  263. ao2_t_replace(framed->format, format, "replacing with new format");
  264. framed->framing = framing;
  265. return 0;
  266. }
  267. }
  268. return -1;
  269. }
  270. void ast_format_cap_replace_from_cap(struct ast_format_cap *dst, const struct ast_format_cap *src,
  271. enum ast_media_type type)
  272. {
  273. int idx;
  274. for (idx = 0; (idx < AST_VECTOR_SIZE(&src->preference_order)); ++idx) {
  275. struct format_cap_framed *framed = AST_VECTOR_GET(&src->preference_order, idx);
  276. if (type == AST_MEDIA_TYPE_UNKNOWN || ast_format_get_type(framed->format) == type) {
  277. format_cap_replace(dst, framed->format, framed->framing);
  278. }
  279. }
  280. }
  281. int ast_format_cap_update_by_allow_disallow(struct ast_format_cap *cap, const char *list, int allowing)
  282. {
  283. int res = 0, all = 0, iter_allowing;
  284. char *parse = NULL, *this = NULL, *psize = NULL;
  285. if (!allowing && ast_strlen_zero(list)) {
  286. return 0;
  287. }
  288. parse = ast_strdupa(list);
  289. /* If the list is being fed to us as a result of ast_format_cap_get_names,
  290. * strip off the parenthesis and immediately apply the inverse of the
  291. * allowing option
  292. */
  293. if (parse[0] == '(' && parse[strlen(parse) - 1] == ')') {
  294. parse++;
  295. parse[strlen(parse) - 1] = '\0';
  296. if (allowing) {
  297. ast_format_cap_remove_by_type(cap, AST_MEDIA_TYPE_UNKNOWN);
  298. } else {
  299. ast_format_cap_append_by_type(cap, AST_MEDIA_TYPE_UNKNOWN);
  300. }
  301. }
  302. while ((this = ast_strip(strsep(&parse, ",|")))) {
  303. int framems = 0;
  304. struct ast_format *format = NULL;
  305. iter_allowing = allowing;
  306. if (*this == '!') {
  307. this++;
  308. iter_allowing = !allowing;
  309. }
  310. if ((psize = strrchr(this, ':'))) {
  311. *psize++ = '\0';
  312. ast_debug(1, "Packetization for codec: %s is %s\n", this, psize);
  313. if (!sscanf(psize, "%30d", &framems) || (framems < 0)) {
  314. framems = 0;
  315. res = -1;
  316. ast_log(LOG_WARNING, "Bad packetization value for codec %s\n", this);
  317. continue;
  318. }
  319. }
  320. all = strcasecmp(this, "all") ? 0 : 1;
  321. if (!all && !(format = ast_format_cache_get(this))) {
  322. ast_log(LOG_WARNING, "Cannot %s unknown format '%s'\n", iter_allowing ? "allow" : "disallow", this);
  323. res = -1;
  324. continue;
  325. }
  326. if (cap) {
  327. if (iter_allowing) {
  328. if (all) {
  329. ast_format_cap_append_by_type(cap, AST_MEDIA_TYPE_UNKNOWN);
  330. } else {
  331. ast_format_cap_append(cap, format, framems);
  332. }
  333. } else {
  334. if (all) {
  335. ast_format_cap_remove_by_type(cap, AST_MEDIA_TYPE_UNKNOWN);
  336. } else {
  337. ast_format_cap_remove(cap, format);
  338. }
  339. }
  340. }
  341. ao2_cleanup(format);
  342. }
  343. return res;
  344. }
  345. size_t ast_format_cap_count(const struct ast_format_cap *cap)
  346. {
  347. return AST_VECTOR_SIZE(&cap->preference_order);
  348. }
  349. struct ast_format *ast_format_cap_get_format(const struct ast_format_cap *cap, int position)
  350. {
  351. struct format_cap_framed *framed;
  352. ast_assert(position < AST_VECTOR_SIZE(&cap->preference_order));
  353. if (position >= AST_VECTOR_SIZE(&cap->preference_order)) {
  354. return NULL;
  355. }
  356. framed = AST_VECTOR_GET(&cap->preference_order, position);
  357. ast_assert(framed->format != ast_format_none);
  358. ao2_ref(framed->format, +1);
  359. return framed->format;
  360. }
  361. struct ast_format *ast_format_cap_get_best_by_type(const struct ast_format_cap *cap, enum ast_media_type type)
  362. {
  363. int i;
  364. if (type == AST_MEDIA_TYPE_UNKNOWN) {
  365. return ast_format_cap_get_format(cap, 0);
  366. }
  367. for (i = 0; i < AST_VECTOR_SIZE(&cap->preference_order); i++) {
  368. struct format_cap_framed *framed = AST_VECTOR_GET(&cap->preference_order, i);
  369. if (ast_format_get_type(framed->format) == type) {
  370. ao2_ref(framed->format, +1);
  371. ast_assert(framed->format != ast_format_none);
  372. return framed->format;
  373. }
  374. }
  375. return NULL;
  376. }
  377. unsigned int ast_format_cap_get_framing(const struct ast_format_cap *cap)
  378. {
  379. return (cap->framing != UINT_MAX) ? cap->framing : 0;
  380. }
  381. unsigned int ast_format_cap_get_format_framing(const struct ast_format_cap *cap, const struct ast_format *format)
  382. {
  383. unsigned int framing;
  384. struct format_cap_framed_list *list;
  385. struct format_cap_framed *framed, *result = NULL;
  386. if (ast_format_get_codec_id(format) >= AST_VECTOR_SIZE(&cap->formats)) {
  387. return 0;
  388. }
  389. framing = cap->framing != UINT_MAX ? cap->framing : ast_format_get_default_ms(format);
  390. list = AST_VECTOR_GET_ADDR(&cap->formats, ast_format_get_codec_id(format));
  391. AST_LIST_TRAVERSE(list, framed, entry) {
  392. enum ast_format_cmp_res res = ast_format_cmp(format, framed->format);
  393. if (res == AST_FORMAT_CMP_NOT_EQUAL) {
  394. continue;
  395. }
  396. result = framed;
  397. if (res == AST_FORMAT_CMP_EQUAL) {
  398. break;
  399. }
  400. }
  401. if (result && result->framing) {
  402. framing = result->framing;
  403. }
  404. return framing;
  405. }
  406. /*!
  407. * \brief format_cap_framed comparator for AST_VECTOR_REMOVE_CMP_ORDERED()
  408. *
  409. * \param elem Element to compare against
  410. * \param value Value to compare with the vector element.
  411. *
  412. * \return 0 if element does not match.
  413. * \return Non-zero if element matches.
  414. */
  415. #define FORMAT_CAP_FRAMED_ELEM_CMP(elem, value) ((elem)->format == (value))
  416. /*!
  417. * \brief format_cap_framed vector element cleanup.
  418. *
  419. * \param elem Element to cleanup
  420. *
  421. * \return Nothing
  422. */
  423. #define FORMAT_CAP_FRAMED_ELEM_CLEANUP(elem) ao2_cleanup((elem))
  424. int ast_format_cap_remove(struct ast_format_cap *cap, struct ast_format *format)
  425. {
  426. struct format_cap_framed_list *list;
  427. struct format_cap_framed *framed;
  428. ast_assert(format != NULL);
  429. if (ast_format_get_codec_id(format) >= AST_VECTOR_SIZE(&cap->formats)) {
  430. return -1;
  431. }
  432. list = AST_VECTOR_GET_ADDR(&cap->formats, ast_format_get_codec_id(format));
  433. AST_LIST_TRAVERSE_SAFE_BEGIN(list, framed, entry) {
  434. if (!FORMAT_CAP_FRAMED_ELEM_CMP(framed, format)) {
  435. continue;
  436. }
  437. AST_LIST_REMOVE_CURRENT(entry);
  438. FORMAT_CAP_FRAMED_ELEM_CLEANUP(framed);
  439. break;
  440. }
  441. AST_LIST_TRAVERSE_SAFE_END;
  442. return AST_VECTOR_REMOVE_CMP_ORDERED(&cap->preference_order, format,
  443. FORMAT_CAP_FRAMED_ELEM_CMP, FORMAT_CAP_FRAMED_ELEM_CLEANUP);
  444. }
  445. void ast_format_cap_remove_by_type(struct ast_format_cap *cap, enum ast_media_type type)
  446. {
  447. int idx;
  448. for (idx = 0; idx < AST_VECTOR_SIZE(&cap->formats); ++idx) {
  449. struct format_cap_framed_list *list = AST_VECTOR_GET_ADDR(&cap->formats, idx);
  450. struct format_cap_framed *framed;
  451. AST_LIST_TRAVERSE_SAFE_BEGIN(list, framed, entry) {
  452. if ((type != AST_MEDIA_TYPE_UNKNOWN) &&
  453. ast_format_get_type(framed->format) != type) {
  454. continue;
  455. }
  456. AST_LIST_REMOVE_CURRENT(entry);
  457. AST_VECTOR_REMOVE_CMP_ORDERED(&cap->preference_order, framed->format,
  458. FORMAT_CAP_FRAMED_ELEM_CMP, FORMAT_CAP_FRAMED_ELEM_CLEANUP);
  459. ao2_ref(framed, -1);
  460. }
  461. AST_LIST_TRAVERSE_SAFE_END;
  462. }
  463. }
  464. struct ast_format *ast_format_cap_get_compatible_format(const struct ast_format_cap *cap, const struct ast_format *format)
  465. {
  466. struct format_cap_framed_list *list;
  467. struct format_cap_framed *framed;
  468. struct ast_format *result = NULL;
  469. ast_assert(format != NULL);
  470. if (ast_format_get_codec_id(format) >= AST_VECTOR_SIZE(&cap->formats)) {
  471. return NULL;
  472. }
  473. list = AST_VECTOR_GET_ADDR(&cap->formats, ast_format_get_codec_id(format));
  474. AST_LIST_TRAVERSE(list, framed, entry) {
  475. enum ast_format_cmp_res res = ast_format_cmp(format, framed->format);
  476. if (res == AST_FORMAT_CMP_NOT_EQUAL) {
  477. continue;
  478. }
  479. /* Replace any current result, this one will also be a subset OR an exact match */
  480. ao2_cleanup(result);
  481. result = ast_format_joint(format, framed->format);
  482. /* If it's a match we can do no better so return asap */
  483. if (res == AST_FORMAT_CMP_EQUAL) {
  484. break;
  485. }
  486. }
  487. return result;
  488. }
  489. enum ast_format_cmp_res ast_format_cap_iscompatible_format(const struct ast_format_cap *cap,
  490. const struct ast_format *format)
  491. {
  492. enum ast_format_cmp_res res = AST_FORMAT_CMP_NOT_EQUAL;
  493. struct format_cap_framed_list *list;
  494. struct format_cap_framed *framed;
  495. ast_assert(format != NULL);
  496. if (ast_format_get_codec_id(format) >= AST_VECTOR_SIZE(&cap->formats)) {
  497. return AST_FORMAT_CMP_NOT_EQUAL;
  498. }
  499. list = AST_VECTOR_GET_ADDR(&cap->formats, ast_format_get_codec_id(format));
  500. AST_LIST_TRAVERSE(list, framed, entry) {
  501. enum ast_format_cmp_res cmp = ast_format_cmp(format, framed->format);
  502. if (cmp == AST_FORMAT_CMP_NOT_EQUAL) {
  503. continue;
  504. }
  505. res = cmp;
  506. if (res == AST_FORMAT_CMP_EQUAL) {
  507. break;
  508. }
  509. }
  510. return res;
  511. }
  512. int ast_format_cap_has_type(const struct ast_format_cap *cap, enum ast_media_type type)
  513. {
  514. int idx;
  515. for (idx = 0; idx < AST_VECTOR_SIZE(&cap->preference_order); ++idx) {
  516. struct format_cap_framed *framed = AST_VECTOR_GET(&cap->preference_order, idx);
  517. if (ast_format_get_type(framed->format) == type) {
  518. return 1;
  519. }
  520. }
  521. return 0;
  522. }
  523. int ast_format_cap_get_compatible(const struct ast_format_cap *cap1, const struct ast_format_cap *cap2,
  524. struct ast_format_cap *result)
  525. {
  526. int idx, res = 0;
  527. for (idx = 0; idx < AST_VECTOR_SIZE(&cap1->preference_order); ++idx) {
  528. struct format_cap_framed *framed = AST_VECTOR_GET(&cap1->preference_order, idx);
  529. struct ast_format *format;
  530. format = ast_format_cap_get_compatible_format(cap2, framed->format);
  531. if (!format) {
  532. continue;
  533. }
  534. res = ast_format_cap_append(result, format, framed->framing);
  535. ao2_ref(format, -1);
  536. if (res) {
  537. break;
  538. }
  539. }
  540. return res;
  541. }
  542. int ast_format_cap_iscompatible(const struct ast_format_cap *cap1, const struct ast_format_cap *cap2)
  543. {
  544. int idx;
  545. for (idx = 0; idx < AST_VECTOR_SIZE(&cap1->preference_order); ++idx) {
  546. struct format_cap_framed *framed = AST_VECTOR_GET(&cap1->preference_order, idx);
  547. if (ast_format_cap_iscompatible_format(cap2, framed->format) != AST_FORMAT_CMP_NOT_EQUAL) {
  548. return 1;
  549. }
  550. }
  551. return 0;
  552. }
  553. static int internal_format_cap_identical(const struct ast_format_cap *cap1, const struct ast_format_cap *cap2)
  554. {
  555. int idx;
  556. struct ast_format *tmp;
  557. for (idx = 0; idx < AST_VECTOR_SIZE(&cap1->preference_order); ++idx) {
  558. tmp = ast_format_cap_get_format(cap1, idx);
  559. if (ast_format_cap_iscompatible_format(cap2, tmp) != AST_FORMAT_CMP_EQUAL) {
  560. ao2_ref(tmp, -1);
  561. return 0;
  562. }
  563. ao2_ref(tmp, -1);
  564. }
  565. return 1;
  566. }
  567. int ast_format_cap_identical(const struct ast_format_cap *cap1, const struct ast_format_cap *cap2)
  568. {
  569. if (AST_VECTOR_SIZE(&cap1->preference_order) != AST_VECTOR_SIZE(&cap2->preference_order)) {
  570. return 0; /* if they are not the same size, they are not identical */
  571. }
  572. if (!internal_format_cap_identical(cap1, cap2)) {
  573. return 0;
  574. }
  575. return internal_format_cap_identical(cap2, cap1);
  576. }
  577. const char *ast_format_cap_get_names(struct ast_format_cap *cap, struct ast_str **buf)
  578. {
  579. int i;
  580. ast_str_set(buf, 0, "(");
  581. if (!cap || !AST_VECTOR_SIZE(&cap->preference_order)) {
  582. ast_str_append(buf, 0, "nothing)");
  583. return ast_str_buffer(*buf);
  584. }
  585. for (i = 0; i < AST_VECTOR_SIZE(&cap->preference_order); ++i) {
  586. int res;
  587. struct format_cap_framed *framed = AST_VECTOR_GET(&cap->preference_order, i);
  588. res = ast_str_append(buf, 0, "%s%s", ast_format_get_name(framed->format),
  589. i < AST_VECTOR_SIZE(&cap->preference_order) - 1 ? "|" : "");
  590. if (res < 0) {
  591. break;
  592. }
  593. }
  594. ast_str_append(buf, 0, ")");
  595. return ast_str_buffer(*buf);
  596. }
  597. int ast_format_cap_empty(struct ast_format_cap *cap)
  598. {
  599. int count = ast_format_cap_count(cap);
  600. if (count > 1) {
  601. return 0;
  602. }
  603. if (count == 0 || AST_VECTOR_GET(&cap->preference_order, 0)->format == ast_format_none) {
  604. return 1;
  605. }
  606. return 0;
  607. }