format_cap.c 15 KB

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