format_cap.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722
  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. static inline void format_cap_init(struct ast_format_cap *cap, enum ast_format_cap_flags flags)
  82. {
  83. AST_VECTOR_INIT(&cap->formats, 0);
  84. /* TODO: Look at common usage of this and determine a good starting point */
  85. AST_VECTOR_INIT(&cap->preference_order, 5);
  86. cap->framing = UINT_MAX;
  87. }
  88. struct ast_format_cap *__ast_format_cap_alloc(enum ast_format_cap_flags flags)
  89. {
  90. struct ast_format_cap *cap;
  91. cap = ao2_alloc_options(sizeof(*cap), format_cap_destroy, AO2_ALLOC_OPT_LOCK_NOLOCK);
  92. if (!cap) {
  93. return NULL;
  94. }
  95. format_cap_init(cap, flags);
  96. return cap;
  97. }
  98. 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)
  99. {
  100. struct ast_format_cap *cap;
  101. 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);
  102. if (!cap) {
  103. return NULL;
  104. }
  105. format_cap_init(cap, flags);
  106. return cap;
  107. }
  108. void ast_format_cap_set_framing(struct ast_format_cap *cap, unsigned int framing)
  109. {
  110. cap->framing = framing;
  111. }
  112. /*! \brief Destructor for format capabilities framed structure */
  113. static void format_cap_framed_destroy(void *obj)
  114. {
  115. struct format_cap_framed *framed = obj;
  116. ao2_cleanup(framed->format);
  117. }
  118. static inline int format_cap_framed_init(struct format_cap_framed *framed, struct ast_format_cap *cap, struct ast_format *format, unsigned int framing)
  119. {
  120. struct format_cap_framed_list *list;
  121. framed->framing = framing;
  122. if (ast_format_get_codec_id(format) >= AST_VECTOR_SIZE(&cap->formats)) {
  123. if (AST_VECTOR_INSERT(&cap->formats, ast_format_get_codec_id(format), format_cap_framed_list_empty)) {
  124. ao2_ref(framed, -1);
  125. return -1;
  126. }
  127. }
  128. list = AST_VECTOR_GET_ADDR(&cap->formats, ast_format_get_codec_id(format));
  129. /* Order doesn't matter for formats, so insert at the head for performance reasons */
  130. ao2_ref(framed, +1);
  131. AST_LIST_INSERT_HEAD(list, framed, entry);
  132. /* This takes the allocation reference */
  133. AST_VECTOR_APPEND(&cap->preference_order, framed);
  134. cap->framing = MIN(cap->framing, framing ? framing : ast_format_get_default_ms(format));
  135. return 0;
  136. }
  137. /*! \internal \brief Determine if \c format is in \c cap */
  138. static int format_in_format_cap(struct ast_format_cap *cap, struct ast_format *format)
  139. {
  140. struct format_cap_framed *framed;
  141. int i;
  142. for (i = 0; i < AST_VECTOR_SIZE(&cap->preference_order); i++) {
  143. framed = AST_VECTOR_GET(&cap->preference_order, i);
  144. if (ast_format_get_codec_id(format) == ast_format_get_codec_id(framed->format)) {
  145. return 1;
  146. }
  147. }
  148. return 0;
  149. }
  150. int __ast_format_cap_append(struct ast_format_cap *cap, struct ast_format *format, unsigned int framing)
  151. {
  152. struct format_cap_framed *framed;
  153. ast_assert(format != NULL);
  154. if (format_in_format_cap(cap, format)) {
  155. return 0;
  156. }
  157. framed = ao2_alloc_options(sizeof(*framed), format_cap_framed_destroy, AO2_ALLOC_OPT_LOCK_NOLOCK);
  158. if (!framed) {
  159. return -1;
  160. }
  161. framed->format = ao2_bump(format);
  162. return format_cap_framed_init(framed, cap, format, framing);
  163. }
  164. 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)
  165. {
  166. struct format_cap_framed *framed;
  167. ast_assert(format != NULL);
  168. if (format_in_format_cap(cap, format)) {
  169. return 0;
  170. }
  171. framed = ao2_alloc_options(sizeof(*framed), format_cap_framed_destroy, AO2_ALLOC_OPT_LOCK_NOLOCK);
  172. if (!framed) {
  173. return -1;
  174. }
  175. __ao2_ref_debug(format, +1, S_OR(tag, "ast_format_cap_append"), file, line, func);
  176. framed->format = format;
  177. return format_cap_framed_init(framed, cap, format, framing);
  178. }
  179. int ast_format_cap_append_by_type(struct ast_format_cap *cap, enum ast_media_type type)
  180. {
  181. int id;
  182. for (id = 1; id < ast_codec_get_max(); ++id) {
  183. struct ast_codec *codec = ast_codec_get_by_id(id);
  184. struct ast_format *format;
  185. int res;
  186. if (!codec) {
  187. continue;
  188. }
  189. if ((type != AST_MEDIA_TYPE_UNKNOWN) && codec->type != type) {
  190. ao2_ref(codec, -1);
  191. continue;
  192. }
  193. format = ast_format_create(codec);
  194. ao2_ref(codec, -1);
  195. if (!format) {
  196. return -1;
  197. }
  198. /* Use the global framing or default framing of the codec */
  199. res = ast_format_cap_append(cap, format, 0);
  200. ao2_ref(format, -1);
  201. if (res) {
  202. return -1;
  203. }
  204. }
  205. return 0;
  206. }
  207. int ast_format_cap_append_from_cap(struct ast_format_cap *dst, const struct ast_format_cap *src,
  208. enum ast_media_type type)
  209. {
  210. int idx, res = 0;
  211. for (idx = 0; (idx < AST_VECTOR_SIZE(&src->preference_order)) && !res; ++idx) {
  212. struct format_cap_framed *framed = AST_VECTOR_GET(&src->preference_order, idx);
  213. if (type == AST_MEDIA_TYPE_UNKNOWN || ast_format_get_type(framed->format) == type) {
  214. res = ast_format_cap_append(dst, framed->format, framed->framing);
  215. }
  216. }
  217. return res;
  218. }
  219. static int format_cap_replace(struct ast_format_cap *cap, struct ast_format *format, unsigned int framing)
  220. {
  221. struct format_cap_framed *framed;
  222. int i;
  223. ast_assert(format != NULL);
  224. for (i = 0; i < AST_VECTOR_SIZE(&cap->preference_order); i++) {
  225. framed = AST_VECTOR_GET(&cap->preference_order, i);
  226. if (ast_format_get_codec_id(format) == ast_format_get_codec_id(framed->format)) {
  227. ao2_t_replace(framed->format, format, "replacing with new format");
  228. framed->framing = framing;
  229. return 0;
  230. }
  231. }
  232. return -1;
  233. }
  234. void ast_format_cap_replace_from_cap(struct ast_format_cap *dst, const struct ast_format_cap *src,
  235. enum ast_media_type type)
  236. {
  237. int idx;
  238. for (idx = 0; (idx < AST_VECTOR_SIZE(&src->preference_order)); ++idx) {
  239. struct format_cap_framed *framed = AST_VECTOR_GET(&src->preference_order, idx);
  240. if (type == AST_MEDIA_TYPE_UNKNOWN || ast_format_get_type(framed->format) == type) {
  241. format_cap_replace(dst, framed->format, framed->framing);
  242. }
  243. }
  244. }
  245. int ast_format_cap_update_by_allow_disallow(struct ast_format_cap *cap, const char *list, int allowing)
  246. {
  247. int res = 0, all = 0, iter_allowing;
  248. char *parse = NULL, *this = NULL, *psize = NULL;
  249. if (!allowing && ast_strlen_zero(list)) {
  250. return 0;
  251. }
  252. parse = ast_strdupa(list);
  253. while ((this = strsep(&parse, ","))) {
  254. int framems = 0;
  255. struct ast_format *format = NULL;
  256. iter_allowing = allowing;
  257. if (*this == '!') {
  258. this++;
  259. iter_allowing = !allowing;
  260. }
  261. if ((psize = strrchr(this, ':'))) {
  262. *psize++ = '\0';
  263. ast_debug(1, "Packetization for codec: %s is %s\n", this, psize);
  264. if (!sscanf(psize, "%30d", &framems) || (framems < 0)) {
  265. framems = 0;
  266. res = -1;
  267. ast_log(LOG_WARNING, "Bad packetization value for codec %s\n", this);
  268. continue;
  269. }
  270. }
  271. all = strcasecmp(this, "all") ? 0 : 1;
  272. if (!all && !(format = ast_format_cache_get(this))) {
  273. ast_log(LOG_WARNING, "Cannot %s unknown format '%s'\n", iter_allowing ? "allow" : "disallow", this);
  274. res = -1;
  275. continue;
  276. }
  277. if (cap) {
  278. if (iter_allowing) {
  279. if (all) {
  280. ast_format_cap_append_by_type(cap, AST_MEDIA_TYPE_UNKNOWN);
  281. } else {
  282. ast_format_cap_append(cap, format, framems);
  283. }
  284. } else {
  285. if (all) {
  286. ast_format_cap_remove_by_type(cap, AST_MEDIA_TYPE_UNKNOWN);
  287. } else {
  288. ast_format_cap_remove(cap, format);
  289. }
  290. }
  291. }
  292. ao2_cleanup(format);
  293. }
  294. return res;
  295. }
  296. size_t ast_format_cap_count(const struct ast_format_cap *cap)
  297. {
  298. return AST_VECTOR_SIZE(&cap->preference_order);
  299. }
  300. struct ast_format *ast_format_cap_get_format(const struct ast_format_cap *cap, int position)
  301. {
  302. struct format_cap_framed *framed;
  303. ast_assert(position < AST_VECTOR_SIZE(&cap->preference_order));
  304. if (position >= AST_VECTOR_SIZE(&cap->preference_order)) {
  305. return NULL;
  306. }
  307. framed = AST_VECTOR_GET(&cap->preference_order, position);
  308. ast_assert(framed->format != ast_format_none);
  309. ao2_ref(framed->format, +1);
  310. return framed->format;
  311. }
  312. struct ast_format *ast_format_cap_get_best_by_type(const struct ast_format_cap *cap, enum ast_media_type type)
  313. {
  314. int i;
  315. if (type == AST_MEDIA_TYPE_UNKNOWN) {
  316. return ast_format_cap_get_format(cap, 0);
  317. }
  318. for (i = 0; i < AST_VECTOR_SIZE(&cap->preference_order); i++) {
  319. struct format_cap_framed *framed = AST_VECTOR_GET(&cap->preference_order, i);
  320. if (ast_format_get_type(framed->format) == type) {
  321. ao2_ref(framed->format, +1);
  322. ast_assert(framed->format != ast_format_none);
  323. return framed->format;
  324. }
  325. }
  326. return NULL;
  327. }
  328. unsigned int ast_format_cap_get_framing(const struct ast_format_cap *cap)
  329. {
  330. return (cap->framing != UINT_MAX) ? cap->framing : 0;
  331. }
  332. unsigned int ast_format_cap_get_format_framing(const struct ast_format_cap *cap, const struct ast_format *format)
  333. {
  334. unsigned int framing;
  335. struct format_cap_framed_list *list;
  336. struct format_cap_framed *framed, *result = NULL;
  337. if (ast_format_get_codec_id(format) >= AST_VECTOR_SIZE(&cap->formats)) {
  338. return 0;
  339. }
  340. framing = cap->framing != UINT_MAX ? cap->framing : ast_format_get_default_ms(format);
  341. list = AST_VECTOR_GET_ADDR(&cap->formats, ast_format_get_codec_id(format));
  342. AST_LIST_TRAVERSE(list, framed, entry) {
  343. enum ast_format_cmp_res res = ast_format_cmp(format, framed->format);
  344. if (res == AST_FORMAT_CMP_NOT_EQUAL) {
  345. continue;
  346. }
  347. result = framed;
  348. if (res == AST_FORMAT_CMP_EQUAL) {
  349. break;
  350. }
  351. }
  352. if (result && result->framing) {
  353. framing = result->framing;
  354. }
  355. return framing;
  356. }
  357. /*!
  358. * \brief format_cap_framed comparator for AST_VECTOR_REMOVE_CMP_ORDERED()
  359. *
  360. * \param elem Element to compare against
  361. * \param value Value to compare with the vector element.
  362. *
  363. * \return 0 if element does not match.
  364. * \return Non-zero if element matches.
  365. */
  366. #define FORMAT_CAP_FRAMED_ELEM_CMP(elem, value) ((elem)->format == (value))
  367. /*!
  368. * \brief format_cap_framed vector element cleanup.
  369. *
  370. * \param elem Element to cleanup
  371. *
  372. * \return Nothing
  373. */
  374. #define FORMAT_CAP_FRAMED_ELEM_CLEANUP(elem) ao2_cleanup((elem))
  375. int ast_format_cap_remove(struct ast_format_cap *cap, struct ast_format *format)
  376. {
  377. struct format_cap_framed_list *list;
  378. struct format_cap_framed *framed;
  379. ast_assert(format != NULL);
  380. if (ast_format_get_codec_id(format) >= AST_VECTOR_SIZE(&cap->formats)) {
  381. return -1;
  382. }
  383. list = AST_VECTOR_GET_ADDR(&cap->formats, ast_format_get_codec_id(format));
  384. AST_LIST_TRAVERSE_SAFE_BEGIN(list, framed, entry) {
  385. if (!FORMAT_CAP_FRAMED_ELEM_CMP(framed, format)) {
  386. continue;
  387. }
  388. AST_LIST_REMOVE_CURRENT(entry);
  389. FORMAT_CAP_FRAMED_ELEM_CLEANUP(framed);
  390. break;
  391. }
  392. AST_LIST_TRAVERSE_SAFE_END;
  393. return AST_VECTOR_REMOVE_CMP_ORDERED(&cap->preference_order, format,
  394. FORMAT_CAP_FRAMED_ELEM_CMP, FORMAT_CAP_FRAMED_ELEM_CLEANUP);
  395. }
  396. void ast_format_cap_remove_by_type(struct ast_format_cap *cap, enum ast_media_type type)
  397. {
  398. int idx;
  399. for (idx = 0; idx < AST_VECTOR_SIZE(&cap->formats); ++idx) {
  400. struct format_cap_framed_list *list = AST_VECTOR_GET_ADDR(&cap->formats, idx);
  401. struct format_cap_framed *framed;
  402. AST_LIST_TRAVERSE_SAFE_BEGIN(list, framed, entry) {
  403. if ((type != AST_MEDIA_TYPE_UNKNOWN) &&
  404. ast_format_get_type(framed->format) != type) {
  405. continue;
  406. }
  407. AST_LIST_REMOVE_CURRENT(entry);
  408. AST_VECTOR_REMOVE_CMP_ORDERED(&cap->preference_order, framed->format,
  409. FORMAT_CAP_FRAMED_ELEM_CMP, FORMAT_CAP_FRAMED_ELEM_CLEANUP);
  410. ao2_ref(framed, -1);
  411. }
  412. AST_LIST_TRAVERSE_SAFE_END;
  413. }
  414. }
  415. struct ast_format *ast_format_cap_get_compatible_format(const struct ast_format_cap *cap, const struct ast_format *format)
  416. {
  417. struct format_cap_framed_list *list;
  418. struct format_cap_framed *framed;
  419. struct ast_format *result = NULL;
  420. ast_assert(format != NULL);
  421. if (ast_format_get_codec_id(format) >= AST_VECTOR_SIZE(&cap->formats)) {
  422. return NULL;
  423. }
  424. list = AST_VECTOR_GET_ADDR(&cap->formats, ast_format_get_codec_id(format));
  425. AST_LIST_TRAVERSE(list, framed, entry) {
  426. enum ast_format_cmp_res res = ast_format_cmp(format, framed->format);
  427. if (res == AST_FORMAT_CMP_NOT_EQUAL) {
  428. continue;
  429. }
  430. /* Replace any current result, this one will also be a subset OR an exact match */
  431. ao2_cleanup(result);
  432. result = ast_format_joint(format, framed->format);
  433. /* If it's a match we can do no better so return asap */
  434. if (res == AST_FORMAT_CMP_EQUAL) {
  435. break;
  436. }
  437. }
  438. return result;
  439. }
  440. enum ast_format_cmp_res ast_format_cap_iscompatible_format(const struct ast_format_cap *cap,
  441. const struct ast_format *format)
  442. {
  443. enum ast_format_cmp_res res = AST_FORMAT_CMP_NOT_EQUAL;
  444. struct format_cap_framed_list *list;
  445. struct format_cap_framed *framed;
  446. ast_assert(format != NULL);
  447. if (ast_format_get_codec_id(format) >= AST_VECTOR_SIZE(&cap->formats)) {
  448. return AST_FORMAT_CMP_NOT_EQUAL;
  449. }
  450. list = AST_VECTOR_GET_ADDR(&cap->formats, ast_format_get_codec_id(format));
  451. AST_LIST_TRAVERSE(list, framed, entry) {
  452. enum ast_format_cmp_res cmp = ast_format_cmp(format, framed->format);
  453. if (cmp == AST_FORMAT_CMP_NOT_EQUAL) {
  454. continue;
  455. }
  456. res = cmp;
  457. if (res == AST_FORMAT_CMP_EQUAL) {
  458. break;
  459. }
  460. }
  461. return res;
  462. }
  463. int ast_format_cap_has_type(const struct ast_format_cap *cap, enum ast_media_type type)
  464. {
  465. int idx;
  466. for (idx = 0; idx < AST_VECTOR_SIZE(&cap->preference_order); ++idx) {
  467. struct format_cap_framed *framed = AST_VECTOR_GET(&cap->preference_order, idx);
  468. if (ast_format_get_type(framed->format) == type) {
  469. return 1;
  470. }
  471. }
  472. return 0;
  473. }
  474. int ast_format_cap_get_compatible(const struct ast_format_cap *cap1, const struct ast_format_cap *cap2,
  475. struct ast_format_cap *result)
  476. {
  477. int idx, res = 0;
  478. for (idx = 0; idx < AST_VECTOR_SIZE(&cap1->preference_order); ++idx) {
  479. struct format_cap_framed *framed = AST_VECTOR_GET(&cap1->preference_order, idx);
  480. struct ast_format *format;
  481. format = ast_format_cap_get_compatible_format(cap2, framed->format);
  482. if (!format) {
  483. continue;
  484. }
  485. res = ast_format_cap_append(result, format, framed->framing);
  486. ao2_ref(format, -1);
  487. if (res) {
  488. break;
  489. }
  490. }
  491. return res;
  492. }
  493. int ast_format_cap_iscompatible(const struct ast_format_cap *cap1, const struct ast_format_cap *cap2)
  494. {
  495. int idx;
  496. for (idx = 0; idx < AST_VECTOR_SIZE(&cap1->preference_order); ++idx) {
  497. struct format_cap_framed *framed = AST_VECTOR_GET(&cap1->preference_order, idx);
  498. if (ast_format_cap_iscompatible_format(cap2, framed->format) != AST_FORMAT_CMP_NOT_EQUAL) {
  499. return 1;
  500. }
  501. }
  502. return 0;
  503. }
  504. static int internal_format_cap_identical(const struct ast_format_cap *cap1, const struct ast_format_cap *cap2)
  505. {
  506. int idx;
  507. struct ast_format *tmp;
  508. for (idx = 0; idx < AST_VECTOR_SIZE(&cap1->preference_order); ++idx) {
  509. tmp = ast_format_cap_get_format(cap1, idx);
  510. if (ast_format_cap_iscompatible_format(cap2, tmp) != AST_FORMAT_CMP_EQUAL) {
  511. ao2_ref(tmp, -1);
  512. return 0;
  513. }
  514. ao2_ref(tmp, -1);
  515. }
  516. return 1;
  517. }
  518. int ast_format_cap_identical(const struct ast_format_cap *cap1, const struct ast_format_cap *cap2)
  519. {
  520. if (AST_VECTOR_SIZE(&cap1->preference_order) != AST_VECTOR_SIZE(&cap2->preference_order)) {
  521. return 0; /* if they are not the same size, they are not identical */
  522. }
  523. if (!internal_format_cap_identical(cap1, cap2)) {
  524. return 0;
  525. }
  526. return internal_format_cap_identical(cap2, cap1);
  527. }
  528. const char *ast_format_cap_get_names(struct ast_format_cap *cap, struct ast_str **buf)
  529. {
  530. int i;
  531. ast_str_set(buf, 0, "(");
  532. if (!AST_VECTOR_SIZE(&cap->preference_order)) {
  533. ast_str_append(buf, 0, "nothing)");
  534. return ast_str_buffer(*buf);
  535. }
  536. for (i = 0; i < AST_VECTOR_SIZE(&cap->preference_order); ++i) {
  537. int res;
  538. struct format_cap_framed *framed = AST_VECTOR_GET(&cap->preference_order, i);
  539. res = ast_str_append(buf, 0, "%s%s", ast_format_get_name(framed->format),
  540. i < AST_VECTOR_SIZE(&cap->preference_order) - 1 ? "|" : "");
  541. if (res < 0) {
  542. break;
  543. }
  544. }
  545. ast_str_append(buf, 0, ")");
  546. return ast_str_buffer(*buf);
  547. }
  548. int ast_format_cap_empty(struct ast_format_cap *cap)
  549. {
  550. int count = ast_format_cap_count(cap);
  551. if (count > 1) {
  552. return 0;
  553. }
  554. if (count == 0 || AST_VECTOR_GET(&cap->preference_order, 0)->format == ast_format_none) {
  555. return 1;
  556. }
  557. return 0;
  558. }