format_cap.c 19 KB

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