format_cap.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682
  1. /*
  2. * Asterisk -- An open source telephony toolkit.
  3. *
  4. * Copyright (C) 2010, Digium, Inc.
  5. *
  6. * David Vossel <dvossel@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. * \file
  20. * \brief Format Capability API
  21. *
  22. * \author David Vossel <dvossel@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/_private.h"
  30. #include "asterisk/format.h"
  31. #include "asterisk/format_cap.h"
  32. #include "asterisk/frame.h"
  33. #include "asterisk/astobj2.h"
  34. #include "asterisk/utils.h"
  35. #define FORMAT_STR_BUFSIZE 256
  36. struct ast_format_cap {
  37. /* The capabilities structure is just an ao2 container of ast_formats */
  38. struct ao2_container *formats;
  39. struct ao2_iterator it;
  40. /*! TRUE if the formats container created without a lock. */
  41. struct ast_flags flags;
  42. unsigned int string_cache_valid;
  43. char format_strs[0];
  44. };
  45. /*! format exists within capabilities structure if it is identical to
  46. * another format, or if the format is a proper subset of another format. */
  47. static int cmp_cb(void *obj, void *arg, int flags)
  48. {
  49. struct ast_format *format1 = arg;
  50. struct ast_format *format2 = obj;
  51. enum ast_format_cmp_res res = ast_format_cmp(format1, format2);
  52. return ((res == AST_FORMAT_CMP_EQUAL) ||
  53. (res == AST_FORMAT_CMP_SUBSET)) ?
  54. CMP_MATCH | CMP_STOP :
  55. 0;
  56. }
  57. static int hash_cb(const void *obj, const int flags)
  58. {
  59. const struct ast_format *format = obj;
  60. return format->id;
  61. }
  62. struct ast_format_cap *ast_format_cap_alloc(enum ast_format_cap_flags flags)
  63. {
  64. struct ast_format_cap *cap;
  65. unsigned int alloc_size;
  66. alloc_size = sizeof(*cap);
  67. if (flags & AST_FORMAT_CAP_FLAG_CACHE_STRINGS) {
  68. alloc_size += FORMAT_STR_BUFSIZE;
  69. }
  70. cap = ast_calloc(1, alloc_size);
  71. if (!cap) {
  72. return NULL;
  73. }
  74. ast_set_flag(&cap->flags, flags);
  75. cap->formats = ao2_container_alloc_options(
  76. (flags & AST_FORMAT_CAP_FLAG_NOLOCK) ?
  77. AO2_ALLOC_OPT_LOCK_NOLOCK :
  78. AO2_ALLOC_OPT_LOCK_MUTEX,
  79. 11, hash_cb, cmp_cb);
  80. if (!cap->formats) {
  81. ast_free(cap);
  82. return NULL;
  83. }
  84. return cap;
  85. }
  86. void *ast_format_cap_destroy(struct ast_format_cap *cap)
  87. {
  88. if (!cap) {
  89. return NULL;
  90. }
  91. ao2_ref(cap->formats, -1);
  92. ast_free(cap);
  93. return NULL;
  94. }
  95. static void format_cap_add(struct ast_format_cap *cap, const struct ast_format *format)
  96. {
  97. struct ast_format *fnew;
  98. if (!format || !format->id) {
  99. return;
  100. }
  101. if (!(fnew = ao2_alloc(sizeof(struct ast_format), NULL))) {
  102. return;
  103. }
  104. ast_format_copy(fnew, format);
  105. ao2_link(cap->formats, fnew);
  106. ao2_ref(fnew, -1);
  107. }
  108. void ast_format_cap_add(struct ast_format_cap *cap, const struct ast_format *format)
  109. {
  110. format_cap_add(cap, format);
  111. cap->string_cache_valid = 0;
  112. }
  113. void ast_format_cap_add_all_by_type(struct ast_format_cap *cap, enum ast_format_type type)
  114. {
  115. int x;
  116. size_t f_len = 0;
  117. const struct ast_format_list *f_list = ast_format_list_get(&f_len);
  118. for (x = 0; x < f_len; x++) {
  119. if (AST_FORMAT_GET_TYPE(f_list[x].format.id) == type) {
  120. format_cap_add(cap, &f_list[x].format);
  121. }
  122. }
  123. cap->string_cache_valid = 0;
  124. ast_format_list_destroy(f_list);
  125. }
  126. void ast_format_cap_add_all(struct ast_format_cap *cap)
  127. {
  128. int x;
  129. size_t f_len = 0;
  130. const struct ast_format_list *f_list = ast_format_list_get(&f_len);
  131. for (x = 0; x < f_len; x++) {
  132. format_cap_add(cap, &f_list[x].format);
  133. }
  134. cap->string_cache_valid = 0;
  135. ast_format_list_destroy(f_list);
  136. }
  137. static int append_cb(void *obj, void *arg, int flag)
  138. {
  139. struct ast_format_cap *result = (struct ast_format_cap *) arg;
  140. struct ast_format *format = (struct ast_format *) obj;
  141. if (!ast_format_cap_iscompatible(result, format)) {
  142. format_cap_add(result, format);
  143. }
  144. return 0;
  145. }
  146. void ast_format_cap_append(struct ast_format_cap *dst, const struct ast_format_cap *src)
  147. {
  148. ao2_callback(src->formats, OBJ_NODATA, append_cb, dst);
  149. dst->string_cache_valid = 0;
  150. }
  151. static int copy_cb(void *obj, void *arg, int flag)
  152. {
  153. struct ast_format_cap *result = (struct ast_format_cap *) arg;
  154. struct ast_format *format = (struct ast_format *) obj;
  155. format_cap_add(result, format);
  156. return 0;
  157. }
  158. static void format_cap_remove_all(struct ast_format_cap *cap)
  159. {
  160. ao2_callback(cap->formats, OBJ_NODATA | OBJ_MULTIPLE | OBJ_UNLINK, NULL, NULL);
  161. }
  162. void ast_format_cap_copy(struct ast_format_cap *dst, const struct ast_format_cap *src)
  163. {
  164. format_cap_remove_all(dst);
  165. ao2_callback(src->formats, OBJ_NODATA, copy_cb, dst);
  166. dst->string_cache_valid = 0;
  167. }
  168. struct ast_format_cap *ast_format_cap_dup(const struct ast_format_cap *cap)
  169. {
  170. struct ast_format_cap *dst;
  171. dst = ast_format_cap_alloc(ast_test_flag(&cap->flags, AST_FLAGS_ALL));
  172. if (!dst) {
  173. return NULL;
  174. }
  175. ao2_callback(cap->formats, OBJ_NODATA, copy_cb, dst);
  176. dst->string_cache_valid = 0;
  177. return dst;
  178. }
  179. int ast_format_cap_is_empty(const struct ast_format_cap *cap)
  180. {
  181. if (!cap) {
  182. return 1;
  183. }
  184. return ao2_container_count(cap->formats) == 0 ? 1 : 0;
  185. }
  186. static int find_exact_cb(void *obj, void *arg, int flag)
  187. {
  188. struct ast_format *format1 = (struct ast_format *) arg;
  189. struct ast_format *format2 = (struct ast_format *) obj;
  190. return (ast_format_cmp(format1, format2) == AST_FORMAT_CMP_EQUAL) ? CMP_MATCH : 0;
  191. }
  192. int ast_format_cap_remove(struct ast_format_cap *cap, struct ast_format *format)
  193. {
  194. struct ast_format *fremove;
  195. fremove = ao2_callback(cap->formats, OBJ_POINTER | OBJ_UNLINK, find_exact_cb, format);
  196. if (fremove) {
  197. ao2_ref(fremove, -1);
  198. cap->string_cache_valid = 0;
  199. return 0;
  200. }
  201. return -1;
  202. }
  203. struct multiple_by_id_data {
  204. struct ast_format *format;
  205. int match_found;
  206. };
  207. static int multiple_by_id_cb(void *obj, void *arg, int flag)
  208. {
  209. struct multiple_by_id_data *data = arg;
  210. struct ast_format *format = obj;
  211. int res;
  212. res = (format->id == data->format->id) ? CMP_MATCH : 0;
  213. if (res) {
  214. data->match_found = 1;
  215. }
  216. return res;
  217. }
  218. int ast_format_cap_remove_byid(struct ast_format_cap *cap, enum ast_format_id id)
  219. {
  220. struct ast_format format = {
  221. .id = id,
  222. };
  223. struct multiple_by_id_data data = {
  224. .format = &format,
  225. .match_found = 0,
  226. };
  227. ao2_callback(cap->formats,
  228. OBJ_NODATA | OBJ_MULTIPLE | OBJ_UNLINK,
  229. multiple_by_id_cb,
  230. &data);
  231. /* match_found will be set if at least one item was removed */
  232. if (data.match_found) {
  233. cap->string_cache_valid = 0;
  234. return 0;
  235. }
  236. return -1;
  237. }
  238. static int multiple_by_type_cb(void *obj, void *arg, int flag)
  239. {
  240. int *type = arg;
  241. struct ast_format *format = obj;
  242. return ((AST_FORMAT_GET_TYPE(format->id)) == *type) ? CMP_MATCH : 0;
  243. }
  244. void ast_format_cap_remove_bytype(struct ast_format_cap *cap, enum ast_format_type type)
  245. {
  246. ao2_callback(cap->formats,
  247. OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE,
  248. multiple_by_type_cb,
  249. &type);
  250. cap->string_cache_valid = 0;
  251. }
  252. void ast_format_cap_remove_all(struct ast_format_cap *cap)
  253. {
  254. format_cap_remove_all(cap);
  255. cap->string_cache_valid = 0;
  256. }
  257. void ast_format_cap_set(struct ast_format_cap *cap, struct ast_format *format)
  258. {
  259. format_cap_remove_all(cap);
  260. format_cap_add(cap, format);
  261. cap->string_cache_valid = 0;
  262. }
  263. int ast_format_cap_get_compatible_format(const struct ast_format_cap *cap, const struct ast_format *format, struct ast_format *result)
  264. {
  265. struct ast_format *f;
  266. struct ast_format_cap *tmp_cap = (struct ast_format_cap *) cap;
  267. f = ao2_find(tmp_cap->formats, format, OBJ_POINTER);
  268. if (f) {
  269. ast_format_copy(result, f);
  270. ao2_ref(f, -1);
  271. return 1;
  272. }
  273. ast_format_clear(result);
  274. return 0;
  275. }
  276. int ast_format_cap_iscompatible(const struct ast_format_cap *cap, const struct ast_format *format)
  277. {
  278. struct ast_format *f;
  279. struct ast_format_cap *tmp_cap = (struct ast_format_cap *) cap;
  280. if (!tmp_cap) {
  281. return 0;
  282. }
  283. f = ao2_find(tmp_cap->formats, format, OBJ_POINTER);
  284. if (f) {
  285. ao2_ref(f, -1);
  286. return 1;
  287. }
  288. return 0;
  289. }
  290. struct byid_data {
  291. struct ast_format *result;
  292. enum ast_format_id id;
  293. };
  294. static int find_best_byid_cb(void *obj, void *arg, int flag)
  295. {
  296. struct ast_format *format = obj;
  297. struct byid_data *data = arg;
  298. if (data->id != format->id) {
  299. return 0;
  300. }
  301. if (!data->result->id || (ast_format_rate(data->result) < ast_format_rate(format))) {
  302. ast_format_copy(data->result, format);
  303. }
  304. return 0;
  305. }
  306. int ast_format_cap_best_byid(const struct ast_format_cap *cap, enum ast_format_id id, struct ast_format *result)
  307. {
  308. struct byid_data data;
  309. data.result = result;
  310. data.id = id;
  311. ast_format_clear(result);
  312. ao2_callback(cap->formats,
  313. OBJ_MULTIPLE | OBJ_NODATA,
  314. find_best_byid_cb,
  315. &data);
  316. return result->id ? 1 : 0;
  317. }
  318. /*! \internal
  319. * \brief this struct is just used for the ast_format_cap_joint function so we can provide
  320. * both a format and a result ast_format_cap structure as arguments to the find_joint_cb
  321. * ao2 callback function.
  322. */
  323. struct find_joint_data {
  324. /*! format to compare to for joint capabilities */
  325. struct ast_format *format;
  326. /*! if joint formmat exists with above format, add it to the result container */
  327. struct ast_format_cap *joint_cap;
  328. int joint_found;
  329. };
  330. static int find_joint_cb(void *obj, void *arg, int flag)
  331. {
  332. struct ast_format *format = obj;
  333. struct find_joint_data *data = arg;
  334. struct ast_format tmp = { 0, };
  335. if (!ast_format_joint(format, data->format, &tmp)) {
  336. if (data->joint_cap) {
  337. ast_format_cap_add(data->joint_cap, &tmp);
  338. }
  339. data->joint_found++;
  340. }
  341. return 0;
  342. }
  343. int ast_format_cap_has_joint(const struct ast_format_cap *cap1, const struct ast_format_cap *cap2)
  344. {
  345. struct ao2_iterator it;
  346. struct ast_format *tmp;
  347. struct find_joint_data data = {
  348. .joint_found = 0,
  349. .joint_cap = NULL,
  350. };
  351. it = ao2_iterator_init(cap1->formats, 0);
  352. while ((tmp = ao2_iterator_next(&it))) {
  353. data.format = tmp;
  354. ao2_callback(cap2->formats,
  355. OBJ_MULTIPLE | OBJ_NODATA,
  356. find_joint_cb,
  357. &data);
  358. ao2_ref(tmp, -1);
  359. }
  360. ao2_iterator_destroy(&it);
  361. return data.joint_found ? 1 : 0;
  362. }
  363. int ast_format_cap_identical(const struct ast_format_cap *cap1, const struct ast_format_cap *cap2)
  364. {
  365. struct ao2_iterator it;
  366. struct ast_format *tmp;
  367. if (ao2_container_count(cap1->formats) != ao2_container_count(cap2->formats)) {
  368. return 0; /* if they are not the same size, they are not identical */
  369. }
  370. it = ao2_iterator_init(cap1->formats, 0);
  371. while ((tmp = ao2_iterator_next(&it))) {
  372. if (!ast_format_cap_iscompatible(cap2, tmp)) {
  373. ao2_ref(tmp, -1);
  374. ao2_iterator_destroy(&it);
  375. return 0;
  376. }
  377. ao2_ref(tmp, -1);
  378. }
  379. ao2_iterator_destroy(&it);
  380. return 1;
  381. }
  382. struct ast_format_cap *ast_format_cap_joint(const struct ast_format_cap *cap1, const struct ast_format_cap *cap2)
  383. {
  384. struct ao2_iterator it;
  385. struct ast_format_cap *result = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_NOLOCK);
  386. struct ast_format *tmp;
  387. struct find_joint_data data = {
  388. .joint_found = 0,
  389. .joint_cap = result,
  390. };
  391. if (!result) {
  392. return NULL;
  393. }
  394. it = ao2_iterator_init(cap1->formats, 0);
  395. while ((tmp = ao2_iterator_next(&it))) {
  396. data.format = tmp;
  397. ao2_callback(cap2->formats,
  398. OBJ_MULTIPLE | OBJ_NODATA,
  399. find_joint_cb,
  400. &data);
  401. ao2_ref(tmp, -1);
  402. }
  403. ao2_iterator_destroy(&it);
  404. if (ao2_container_count(result->formats)) {
  405. return result;
  406. }
  407. result = ast_format_cap_destroy(result);
  408. return NULL;
  409. }
  410. static int joint_copy_helper(const struct ast_format_cap *cap1, const struct ast_format_cap *cap2, struct ast_format_cap *result, int append)
  411. {
  412. struct ao2_iterator it;
  413. struct ast_format *tmp;
  414. struct find_joint_data data = {
  415. .joint_cap = result,
  416. .joint_found = 0,
  417. };
  418. if (!append) {
  419. format_cap_remove_all(result);
  420. }
  421. it = ao2_iterator_init(cap1->formats, 0);
  422. while ((tmp = ao2_iterator_next(&it))) {
  423. data.format = tmp;
  424. ao2_callback(cap2->formats,
  425. OBJ_MULTIPLE | OBJ_NODATA,
  426. find_joint_cb,
  427. &data);
  428. ao2_ref(tmp, -1);
  429. }
  430. ao2_iterator_destroy(&it);
  431. result->string_cache_valid = 0;
  432. return ao2_container_count(result->formats) ? 1 : 0;
  433. }
  434. int ast_format_cap_joint_append(const struct ast_format_cap *cap1, const struct ast_format_cap *cap2, struct ast_format_cap *result)
  435. {
  436. return joint_copy_helper(cap1, cap2, result, 1);
  437. }
  438. int ast_format_cap_joint_copy(const struct ast_format_cap *cap1, const struct ast_format_cap *cap2, struct ast_format_cap *result)
  439. {
  440. return joint_copy_helper(cap1, cap2, result, 0);
  441. }
  442. struct ast_format_cap *ast_format_cap_get_type(const struct ast_format_cap *cap, enum ast_format_type ftype)
  443. {
  444. struct ao2_iterator it;
  445. struct ast_format_cap *result = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_NOLOCK);
  446. struct ast_format *tmp;
  447. if (!result) {
  448. return NULL;
  449. }
  450. /* for each format in cap1, see if that format is
  451. * compatible with cap2. If so copy it to the result */
  452. it = ao2_iterator_init(cap->formats, 0);
  453. while ((tmp = ao2_iterator_next(&it))) {
  454. if (AST_FORMAT_GET_TYPE(tmp->id) == ftype) {
  455. /* copy format */
  456. ast_format_cap_add(result, tmp);
  457. }
  458. ao2_ref(tmp, -1);
  459. }
  460. ao2_iterator_destroy(&it);
  461. if (ao2_container_count(result->formats)) {
  462. return result;
  463. }
  464. result = ast_format_cap_destroy(result);
  465. return NULL;
  466. }
  467. int ast_format_cap_has_type(const struct ast_format_cap *cap, enum ast_format_type type)
  468. {
  469. struct ao2_iterator it;
  470. struct ast_format *tmp;
  471. it = ao2_iterator_init(cap->formats, 0);
  472. while ((tmp = ao2_iterator_next(&it))) {
  473. if (AST_FORMAT_GET_TYPE(tmp->id) == type) {
  474. ao2_ref(tmp, -1);
  475. ao2_iterator_destroy(&it);
  476. return 1;
  477. }
  478. ao2_ref(tmp, -1);
  479. }
  480. ao2_iterator_destroy(&it);
  481. return 0;
  482. }
  483. void ast_format_cap_iter_start(struct ast_format_cap *cap)
  484. {
  485. /* We can unconditionally lock even if the container has no lock. */
  486. ao2_lock(cap->formats);
  487. cap->it = ao2_iterator_init(cap->formats, AO2_ITERATOR_DONTLOCK);
  488. }
  489. void ast_format_cap_iter_end(struct ast_format_cap *cap)
  490. {
  491. ao2_iterator_destroy(&cap->it);
  492. /* We can unconditionally unlock even if the container has no lock. */
  493. ao2_unlock(cap->formats);
  494. }
  495. int ast_format_cap_iter_next(struct ast_format_cap *cap, struct ast_format *format)
  496. {
  497. struct ast_format *tmp = ao2_iterator_next(&cap->it);
  498. if (!tmp) {
  499. return -1;
  500. }
  501. ast_format_copy(format, tmp);
  502. ao2_ref(tmp, -1);
  503. return 0;
  504. }
  505. static char *getformatname_multiple(char *buf, size_t size, struct ast_format_cap *cap)
  506. {
  507. int x;
  508. unsigned len;
  509. char *start, *end = buf;
  510. struct ast_format tmp_fmt;
  511. size_t f_len;
  512. const struct ast_format_list *f_list = ast_format_list_get(&f_len);
  513. if (!size) {
  514. f_list = ast_format_list_destroy(f_list);
  515. return buf;
  516. }
  517. snprintf(end, size, "(");
  518. len = strlen(end);
  519. end += len;
  520. size -= len;
  521. start = end;
  522. for (x = 0; x < f_len; x++) {
  523. ast_format_copy(&tmp_fmt, &f_list[x].format);
  524. if (ast_format_cap_iscompatible(cap, &tmp_fmt)) {
  525. snprintf(end, size, "%s|", f_list[x].name);
  526. len = strlen(end);
  527. end += len;
  528. size -= len;
  529. }
  530. }
  531. if (start == end) {
  532. ast_copy_string(start, "nothing)", size);
  533. } else if (size > 1) {
  534. *(end - 1) = ')';
  535. }
  536. f_list = ast_format_list_destroy(f_list);
  537. return buf;
  538. }
  539. char *ast_getformatname_multiple(char *buf, size_t size, struct ast_format_cap *cap)
  540. {
  541. if (ast_test_flag(&cap->flags, AST_FORMAT_CAP_FLAG_CACHE_STRINGS)) {
  542. if (!cap->string_cache_valid) {
  543. getformatname_multiple(cap->format_strs, FORMAT_STR_BUFSIZE, cap);
  544. cap->string_cache_valid = 1;
  545. }
  546. ast_copy_string(buf, cap->format_strs, size);
  547. return buf;
  548. }
  549. return getformatname_multiple(buf, size, cap);
  550. }
  551. uint64_t ast_format_cap_to_old_bitfield(const struct ast_format_cap *cap)
  552. {
  553. uint64_t res = 0;
  554. struct ao2_iterator it;
  555. struct ast_format *tmp;
  556. it = ao2_iterator_init(cap->formats, 0);
  557. while ((tmp = ao2_iterator_next(&it))) {
  558. res |= ast_format_to_old_bitfield(tmp);
  559. ao2_ref(tmp, -1);
  560. }
  561. ao2_iterator_destroy(&it);
  562. return res;
  563. }
  564. void ast_format_cap_from_old_bitfield(struct ast_format_cap *dst, uint64_t src)
  565. {
  566. uint64_t tmp = 0;
  567. int x;
  568. struct ast_format tmp_format = { 0, };
  569. format_cap_remove_all(dst);
  570. for (x = 0; x < 64; x++) {
  571. tmp = (1ULL << x);
  572. if (tmp & src) {
  573. format_cap_add(dst, ast_format_from_old_bitfield(&tmp_format, tmp));
  574. }
  575. }
  576. dst->string_cache_valid = 0;
  577. }