format_pref.c 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345
  1. /*
  2. * Asterisk -- An open source telephony toolkit.
  3. *
  4. * Copyright (C) 2010, Digium, Inc.
  5. *
  6. * Mark Spencer <markster@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 Preference API
  21. */
  22. /*** MODULEINFO
  23. <support_level>core</support_level>
  24. ***/
  25. #include "asterisk.h"
  26. ASTERISK_FILE_VERSION(__FILE__, "$Revision$");
  27. #include "asterisk/_private.h"
  28. #include "asterisk/frame.h"
  29. #include "asterisk/channel.h"
  30. #include "asterisk/utils.h"
  31. void ast_codec_pref_convert(struct ast_codec_pref *pref, char *buf, size_t size, int right)
  32. {
  33. size_t f_len;
  34. const struct ast_format_list *f_list = ast_format_list_get(&f_len);
  35. int x, differential = (int) 'A', mem;
  36. char *from, *to;
  37. /* TODO re-evaluate this function. It is using the order of the formats specified
  38. * in the global format list in a way that may not be safe. */
  39. if (right) {
  40. from = pref->order;
  41. to = buf;
  42. mem = size;
  43. } else {
  44. to = pref->order;
  45. from = buf;
  46. mem = AST_CODEC_PREF_SIZE;
  47. }
  48. memset(to, 0, mem);
  49. for (x = 0; x < AST_CODEC_PREF_SIZE; x++) {
  50. if (!from[x]) {
  51. break;
  52. }
  53. to[x] = right ? (from[x] + differential) : (from[x] - differential);
  54. if (!right && to[x] && (to[x] < f_len)) {
  55. ast_format_copy(&pref->formats[x], &f_list[to[x]-1].format);
  56. }
  57. }
  58. ast_format_list_destroy(f_list);
  59. }
  60. int ast_codec_pref_string(struct ast_codec_pref *pref, char *buf, size_t size)
  61. {
  62. int x;
  63. struct ast_format format;
  64. size_t total_len, slen;
  65. const char *formatname;
  66. memset(buf, 0, size);
  67. total_len = size;
  68. buf[0] = '(';
  69. total_len--;
  70. for (x = 0; x < AST_CODEC_PREF_SIZE; x++) {
  71. if (total_len <= 0)
  72. break;
  73. if (!(ast_codec_pref_index(pref, x, &format)))
  74. break;
  75. if ((formatname = ast_getformatname(&format))) {
  76. slen = strlen(formatname);
  77. if (slen > total_len)
  78. break;
  79. strncat(buf, formatname, total_len - 1); /* safe */
  80. total_len -= slen;
  81. }
  82. if (total_len && x < AST_CODEC_PREF_SIZE - 1 && ast_codec_pref_index(pref, x + 1, &format)) {
  83. strncat(buf, "|", total_len - 1); /* safe */
  84. total_len--;
  85. }
  86. }
  87. if (total_len) {
  88. strncat(buf, ")", total_len - 1); /* safe */
  89. total_len--;
  90. }
  91. return size - total_len;
  92. }
  93. struct ast_format *ast_codec_pref_index(struct ast_codec_pref *pref, int idx, struct ast_format *result)
  94. {
  95. if ((idx >= 0) && (idx < sizeof(pref->order)) && pref->formats[idx].id) {
  96. ast_format_copy(result, &pref->formats[idx]);
  97. } else {
  98. ast_format_clear(result);
  99. return NULL;
  100. }
  101. return result;
  102. }
  103. /*! \brief Remove codec from pref list */
  104. void ast_codec_pref_remove(struct ast_codec_pref *pref, struct ast_format *format)
  105. {
  106. struct ast_codec_pref oldorder;
  107. int x, y = 0;
  108. size_t f_len = 0;
  109. const struct ast_format_list *f_list;
  110. if (!pref->order[0]) {
  111. return;
  112. }
  113. f_list = ast_format_list_get(&f_len);
  114. memcpy(&oldorder, pref, sizeof(oldorder));
  115. memset(pref, 0, sizeof(*pref));
  116. for (x = 0; x < f_len; x++) {
  117. if (!oldorder.order[x]) {
  118. break;
  119. }
  120. if (ast_format_cmp(&f_list[oldorder.order[x]-1].format, format) == AST_FORMAT_CMP_NOT_EQUAL) {
  121. pref->order[y] = oldorder.order[x];
  122. ast_format_copy(&pref->formats[y], &oldorder.formats[x]);
  123. pref->framing[y++] = oldorder.framing[x];
  124. }
  125. }
  126. ast_format_list_destroy(f_list);
  127. }
  128. /*! \brief Append codec to list */
  129. int ast_codec_pref_append(struct ast_codec_pref *pref, struct ast_format *format)
  130. {
  131. int x, newindex = 0;
  132. size_t f_len = 0;
  133. const struct ast_format_list *f_list = ast_format_list_get(&f_len);
  134. ast_codec_pref_remove(pref, format);
  135. for (x = 0; x < f_len; x++) {
  136. if (ast_format_cmp(&f_list[x].format, format) == AST_FORMAT_CMP_EQUAL) {
  137. newindex = x + 1;
  138. break;
  139. }
  140. }
  141. if (newindex) {
  142. for (x = 0; x < f_len; x++) {
  143. if (!pref->order[x]) {
  144. pref->order[x] = newindex;
  145. ast_format_copy(&pref->formats[x], format);
  146. break;
  147. }
  148. }
  149. }
  150. ast_format_list_destroy(f_list);
  151. return x;
  152. }
  153. /*! \brief Prepend codec to list */
  154. void ast_codec_pref_prepend(struct ast_codec_pref *pref, struct ast_format *format, int only_if_existing)
  155. {
  156. int x, newindex = 0;
  157. size_t f_len = 0;
  158. const struct ast_format_list *f_list = ast_format_list_get(&f_len);
  159. /* First step is to get the codecs "index number" */
  160. for (x = 0; x < f_len; x++) {
  161. if (ast_format_cmp(&f_list[x].format, format) == AST_FORMAT_CMP_EQUAL) {
  162. newindex = x + 1;
  163. break;
  164. }
  165. }
  166. /* Done if its unknown */
  167. if (!newindex) {
  168. ast_format_list_destroy(f_list);
  169. return;
  170. }
  171. /* Now find any existing occurrence, or the end */
  172. for (x = 0; x < AST_CODEC_PREF_SIZE; x++) {
  173. if (!pref->order[x] || pref->order[x] == newindex)
  174. break;
  175. }
  176. /* If we failed to find any occurrence, set to the end */
  177. if (x == AST_CODEC_PREF_SIZE) {
  178. --x;
  179. }
  180. if (only_if_existing && !pref->order[x]) {
  181. ast_format_list_destroy(f_list);
  182. return;
  183. }
  184. /* Move down to make space to insert - either all the way to the end,
  185. or as far as the existing location (which will be overwritten) */
  186. for (; x > 0; x--) {
  187. pref->order[x] = pref->order[x - 1];
  188. pref->framing[x] = pref->framing[x - 1];
  189. ast_format_copy(&pref->formats[x], &pref->formats[x - 1]);
  190. }
  191. /* And insert the new entry */
  192. pref->order[0] = newindex;
  193. pref->framing[0] = 0; /* ? */
  194. ast_format_copy(&pref->formats[0], format);
  195. ast_format_list_destroy(f_list);
  196. }
  197. /*! \brief Set packet size for codec */
  198. int ast_codec_pref_setsize(struct ast_codec_pref *pref, struct ast_format *format, int framems)
  199. {
  200. int x, idx = -1;
  201. size_t f_len = 0;
  202. const struct ast_format_list *f_list = ast_format_list_get(&f_len);
  203. for (x = 0; x < f_len; x++) {
  204. if (ast_format_cmp(&f_list[x].format, format) == AST_FORMAT_CMP_EQUAL) {
  205. idx = x;
  206. break;
  207. }
  208. }
  209. if (idx < 0) {
  210. ast_format_list_destroy(f_list);
  211. return -1;
  212. }
  213. /* size validation */
  214. if (!framems)
  215. framems = f_list[idx].def_ms;
  216. if (f_list[idx].inc_ms && framems % f_list[idx].inc_ms) /* avoid division by zero */
  217. framems -= framems % f_list[idx].inc_ms;
  218. if (framems < f_list[idx].min_ms)
  219. framems = f_list[idx].min_ms;
  220. if (framems > f_list[idx].max_ms)
  221. framems = f_list[idx].max_ms;
  222. for (x = 0; x < f_len; x++) {
  223. if (pref->order[x] == (idx + 1)) {
  224. pref->framing[x] = framems;
  225. break;
  226. }
  227. }
  228. ast_format_list_destroy(f_list);
  229. return x;
  230. }
  231. /*! \brief Get packet size for codec */
  232. struct ast_format_list ast_codec_pref_getsize(struct ast_codec_pref *pref, struct ast_format *format)
  233. {
  234. int x, idx = -1, framems = 0;
  235. struct ast_format_list fmt = { { 0, }, };
  236. size_t f_len = 0;
  237. const struct ast_format_list *f_list = ast_format_list_get(&f_len);
  238. for (x = 0; x < f_len; x++) {
  239. if (ast_format_cmp(&f_list[x].format, format) == AST_FORMAT_CMP_EQUAL) {
  240. fmt = f_list[x];
  241. idx = x;
  242. break;
  243. }
  244. }
  245. if (idx < 0) {
  246. ast_log(AST_LOG_WARNING, "Format %s unknown; unable to get preferred codec packet size\n", ast_getformatname(format));
  247. ast_format_list_destroy(f_list);
  248. return fmt;
  249. }
  250. for (x = 0; x < f_len; x++) {
  251. if (pref->order[x] == (idx + 1)) {
  252. framems = pref->framing[x];
  253. break;
  254. }
  255. }
  256. /* size validation */
  257. if (!framems)
  258. framems = f_list[idx].def_ms;
  259. if (f_list[idx].inc_ms && framems % f_list[idx].inc_ms) /* avoid division by zero */
  260. framems -= framems % f_list[idx].inc_ms;
  261. if (framems < f_list[idx].min_ms)
  262. framems = f_list[idx].min_ms;
  263. if (framems > f_list[idx].max_ms)
  264. framems = f_list[idx].max_ms;
  265. fmt.cur_ms = framems;
  266. ast_format_list_destroy(f_list);
  267. return fmt;
  268. }
  269. /*! \brief Pick a codec */
  270. struct ast_format *ast_codec_choose(struct ast_codec_pref *pref, struct ast_format_cap *cap, int find_best, struct ast_format *result)
  271. {
  272. int x, slot, found = 0;
  273. size_t f_len = 0;
  274. const struct ast_format_list *f_list = ast_format_list_get(&f_len);
  275. for (x = 0; x < f_len; x++) {
  276. slot = pref->order[x];
  277. if (!slot)
  278. break;
  279. if (ast_format_cap_get_compatible_format(cap, &f_list[slot-1].format, result)) {
  280. found = 1; /*format is found and stored in result */
  281. break;
  282. }
  283. }
  284. ast_format_list_destroy(f_list);
  285. if (found && (AST_FORMAT_GET_TYPE(result->id) == AST_FORMAT_TYPE_AUDIO)) {
  286. return result;
  287. }
  288. ast_format_clear(result);
  289. ast_debug(4, "Could not find preferred codec - %s\n", find_best ? "Going for the best codec" : "Returning zero codec");
  290. return find_best ? ast_best_codec(cap, result) : NULL;
  291. }