res_format_attr_opus.c 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275
  1. /*
  2. * Asterisk -- An open source telephony toolkit.
  3. *
  4. * Copyright (C) 2013, Digium, Inc.
  5. *
  6. * Lorenzo Miniero <lorenzo@meetecho.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 Opus format attribute interface
  21. *
  22. * \author Lorenzo Miniero <lorenzo@meetecho.com>
  23. */
  24. /*** MODULEINFO
  25. <support_level>core</support_level>
  26. ***/
  27. #include "asterisk.h"
  28. ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
  29. #include "asterisk/module.h"
  30. #include "asterisk/format.h"
  31. /*!
  32. * \brief Opus attribute structure.
  33. *
  34. * \note http://tools.ietf.org/html/draft-ietf-payload-rtp-opus-00.
  35. */
  36. struct opus_attr {
  37. unsigned int maxbitrate; /* Default 64-128 kb/s for FB stereo music */
  38. unsigned int maxplayrate /* Default 48000 */;
  39. unsigned int minptime; /* Default 3, but it's 10 in format.c */
  40. unsigned int stereo; /* Default 0 */
  41. unsigned int cbr; /* Default 0 */
  42. unsigned int fec; /* Default 0 */
  43. unsigned int dtx; /* Default 0 */
  44. unsigned int spropmaxcapturerate; /* Default 48000 */
  45. unsigned int spropstereo; /* Default 0 */
  46. };
  47. static struct opus_attr default_opus_attr = {
  48. .fec = 0,
  49. .dtx = 0,
  50. .stereo = 0,
  51. };
  52. static void opus_destroy(struct ast_format *format)
  53. {
  54. struct opus_attr *attr = ast_format_get_attribute_data(format);
  55. ast_free(attr);
  56. }
  57. static int opus_clone(const struct ast_format *src, struct ast_format *dst)
  58. {
  59. struct opus_attr *original = ast_format_get_attribute_data(src);
  60. struct opus_attr *attr = ast_calloc(1, sizeof(*attr));
  61. if (!attr) {
  62. return -1;
  63. }
  64. if (original) {
  65. *attr = *original;
  66. }
  67. ast_format_set_attribute_data(dst, attr);
  68. return 0;
  69. }
  70. static struct ast_format *opus_parse_sdp_fmtp(const struct ast_format *format, const char *attributes)
  71. {
  72. struct ast_format *cloned;
  73. struct opus_attr *attr;
  74. const char *kvp;
  75. unsigned int val;
  76. cloned = ast_format_clone(format);
  77. if (!cloned) {
  78. return NULL;
  79. }
  80. attr = ast_format_get_attribute_data(cloned);
  81. if ((kvp = strstr(attributes, "maxplaybackrate")) && sscanf(kvp, "maxplaybackrate=%30u", &val) == 1) {
  82. attr->maxplayrate = val;
  83. }
  84. if ((kvp = strstr(attributes, "sprop-maxcapturerate")) && sscanf(kvp, "sprop-maxcapturerate=%30u", &val) == 1) {
  85. attr->spropmaxcapturerate = val;
  86. }
  87. if ((kvp = strstr(attributes, "minptime")) && sscanf(kvp, "minptime=%30u", &val) == 1) {
  88. attr->minptime = val;
  89. }
  90. if ((kvp = strstr(attributes, "maxaveragebitrate")) && sscanf(kvp, "maxaveragebitrate=%30u", &val) == 1) {
  91. attr->maxbitrate = val;
  92. }
  93. if ((kvp = strstr(attributes, " stereo")) && sscanf(kvp, " stereo=%30u", &val) == 1) {
  94. attr->stereo = val;
  95. }
  96. if ((kvp = strstr(attributes, ";stereo")) && sscanf(kvp, ";stereo=%30u", &val) == 1) {
  97. attr->stereo = val;
  98. }
  99. if ((kvp = strstr(attributes, "sprop-stereo")) && sscanf(kvp, "sprop-stereo=%30u", &val) == 1) {
  100. attr->spropstereo = val;
  101. }
  102. if ((kvp = strstr(attributes, "cbr")) && sscanf(kvp, "cbr=%30u", &val) == 1) {
  103. attr->cbr = val;
  104. }
  105. if ((kvp = strstr(attributes, "useinbandfec")) && sscanf(kvp, "useinbandfec=%30u", &val) == 1) {
  106. attr->fec = val;
  107. }
  108. if ((kvp = strstr(attributes, "usedtx")) && sscanf(kvp, "usedtx=%30u", &val) == 1) {
  109. attr->dtx = val;
  110. }
  111. return cloned;
  112. }
  113. static void opus_generate_sdp_fmtp(const struct ast_format *format, unsigned int payload, struct ast_str **str)
  114. {
  115. struct opus_attr *attr = ast_format_get_attribute_data(format);
  116. if (!attr) {
  117. return;
  118. }
  119. /* FIXME should we only generate attributes that were explicitly set? */
  120. ast_str_append(str, 0,
  121. "a=fmtp:%u "
  122. "maxplaybackrate=%u;"
  123. "sprop-maxcapturerate=%u;"
  124. "minptime=%u;"
  125. "maxaveragebitrate=%u;"
  126. "stereo=%d;"
  127. "sprop-stereo=%d;"
  128. "cbr=%d;"
  129. "useinbandfec=%d;"
  130. "usedtx=%d\r\n",
  131. payload,
  132. attr->maxplayrate ? attr->maxplayrate : 48000, /* maxplaybackrate */
  133. attr->spropmaxcapturerate ? attr->spropmaxcapturerate : 48000, /* sprop-maxcapturerate */
  134. attr->minptime > 10 ? attr->minptime : 10, /* minptime */
  135. attr->maxbitrate ? attr->maxbitrate : 20000, /* maxaveragebitrate */
  136. attr->stereo ? 1 : 0, /* stereo */
  137. attr->spropstereo ? 1 : 0, /* sprop-stereo */
  138. attr->cbr ? 1 : 0, /* cbr */
  139. attr->fec ? 1 : 0, /* useinbandfec */
  140. attr->dtx ? 1 : 0 /* usedtx */
  141. );
  142. }
  143. static struct ast_format *opus_getjoint(const struct ast_format *format1, const struct ast_format *format2)
  144. {
  145. struct opus_attr *attr1 = ast_format_get_attribute_data(format1);
  146. struct opus_attr *attr2 = ast_format_get_attribute_data(format2);
  147. struct ast_format *jointformat;
  148. struct opus_attr *attr_res;
  149. if (!attr1) {
  150. attr1 = &default_opus_attr;
  151. }
  152. if (!attr2) {
  153. attr2 = &default_opus_attr;
  154. }
  155. jointformat = ast_format_clone(format1);
  156. if (!jointformat) {
  157. return NULL;
  158. }
  159. attr_res = ast_format_get_attribute_data(jointformat);
  160. /* Only do dtx if both sides want it. DTX is a trade off between
  161. * computational complexity and bandwidth. */
  162. attr_res->dtx = attr1->dtx && attr2->dtx ? 1 : 0;
  163. /* Only do FEC if both sides want it. If a peer specifically requests not
  164. * to receive with FEC, it may be a waste of bandwidth. */
  165. attr_res->fec = attr1->fec && attr2->fec ? 1 : 0;
  166. /* Only do stereo if both sides want it. If a peer specifically requests not
  167. * to receive stereo signals, it may be a waste of bandwidth. */
  168. attr_res->stereo = attr1->stereo && attr2->stereo ? 1 : 0;
  169. /* FIXME: do we need to join other attributes as well, e.g., minptime, cbr, etc.? */
  170. return jointformat;
  171. }
  172. static struct ast_format *opus_set(const struct ast_format *format, const char *name, const char *value)
  173. {
  174. struct ast_format *cloned;
  175. struct opus_attr *attr;
  176. unsigned int val;
  177. if (sscanf(value, "%30u", &val) != 1) {
  178. ast_log(LOG_WARNING, "Unknown value '%s' for attribute type '%s'\n",
  179. value, name);
  180. return NULL;
  181. }
  182. cloned = ast_format_clone(format);
  183. if (!cloned) {
  184. return NULL;
  185. }
  186. attr = ast_format_get_attribute_data(cloned);
  187. if (!strcasecmp(name, "max_bitrate")) {
  188. attr->maxbitrate = val;
  189. } else if (!strcasecmp(name, "max_playrate")) {
  190. attr->maxplayrate = val;
  191. } else if (!strcasecmp(name, "minptime")) {
  192. attr->minptime = val;
  193. } else if (!strcasecmp(name, "stereo")) {
  194. attr->stereo = val;
  195. } else if (!strcasecmp(name, "cbr")) {
  196. attr->cbr = val;
  197. } else if (!strcasecmp(name, "fec")) {
  198. attr->fec = val;
  199. } else if (!strcasecmp(name, "dtx")) {
  200. attr->dtx = val;
  201. } else if (!strcasecmp(name, "sprop_capture_rate")) {
  202. attr->spropmaxcapturerate = val;
  203. } else if (!strcasecmp(name, "sprop_stereo")) {
  204. attr->spropstereo = val;
  205. } else {
  206. ast_log(LOG_WARNING, "unknown attribute type %s\n", name);
  207. }
  208. return cloned;
  209. }
  210. static struct ast_format_interface opus_interface = {
  211. .format_destroy = opus_destroy,
  212. .format_clone = opus_clone,
  213. .format_get_joint = opus_getjoint,
  214. .format_attribute_set = opus_set,
  215. .format_parse_sdp_fmtp = opus_parse_sdp_fmtp,
  216. .format_generate_sdp_fmtp = opus_generate_sdp_fmtp,
  217. };
  218. static int load_module(void)
  219. {
  220. if (ast_format_interface_register("opus", &opus_interface)) {
  221. return AST_MODULE_LOAD_DECLINE;
  222. }
  223. return AST_MODULE_LOAD_SUCCESS;
  224. }
  225. static int unload_module(void)
  226. {
  227. return 0;
  228. }
  229. AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Opus Format Attribute Module",
  230. .support_level = AST_MODULE_SUPPORT_CORE,
  231. .load = load_module,
  232. .unload = unload_module,
  233. .load_pri = AST_MODPRI_CHANNEL_DEPEND,
  234. );