res_format_attr_opus.c 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261
  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 void opus_destroy(struct ast_format *format)
  48. {
  49. struct opus_attr *attr = ast_format_get_attribute_data(format);
  50. ast_free(attr);
  51. }
  52. static int opus_clone(const struct ast_format *src, struct ast_format *dst)
  53. {
  54. struct opus_attr *original = ast_format_get_attribute_data(src);
  55. struct opus_attr *attr = ast_calloc(1, sizeof(*attr));
  56. if (!attr) {
  57. return -1;
  58. }
  59. if (original) {
  60. *attr = *original;
  61. }
  62. ast_format_set_attribute_data(dst, attr);
  63. return 0;
  64. }
  65. static struct ast_format *opus_parse_sdp_fmtp(const struct ast_format *format, const char *attributes)
  66. {
  67. struct ast_format *cloned;
  68. struct opus_attr *attr;
  69. const char *kvp;
  70. unsigned int val;
  71. cloned = ast_format_clone(format);
  72. if (!cloned) {
  73. return NULL;
  74. }
  75. attr = ast_format_get_attribute_data(cloned);
  76. if ((kvp = strstr(attributes, "maxplaybackrate")) && sscanf(kvp, "maxplaybackrate=%30u", &val) == 1) {
  77. attr->maxplayrate = val;
  78. }
  79. if ((kvp = strstr(attributes, "sprop-maxcapturerate")) && sscanf(kvp, "sprop-maxcapturerate=%30u", &val) == 1) {
  80. attr->spropmaxcapturerate = val;
  81. }
  82. if ((kvp = strstr(attributes, "minptime")) && sscanf(kvp, "minptime=%30u", &val) == 1) {
  83. attr->minptime = val;
  84. }
  85. if ((kvp = strstr(attributes, "maxaveragebitrate")) && sscanf(kvp, "maxaveragebitrate=%30u", &val) == 1) {
  86. attr->maxbitrate = val;
  87. }
  88. if ((kvp = strstr(attributes, " stereo")) && sscanf(kvp, " stereo=%30u", &val) == 1) {
  89. attr->stereo = val;
  90. }
  91. if ((kvp = strstr(attributes, ";stereo")) && sscanf(kvp, ";stereo=%30u", &val) == 1) {
  92. attr->stereo = val;
  93. }
  94. if ((kvp = strstr(attributes, "sprop-stereo")) && sscanf(kvp, "sprop-stereo=%30u", &val) == 1) {
  95. attr->spropstereo = val;
  96. }
  97. if ((kvp = strstr(attributes, "cbr")) && sscanf(kvp, "cbr=%30u", &val) == 1) {
  98. attr->cbr = val;
  99. }
  100. if ((kvp = strstr(attributes, "useinbandfec")) && sscanf(kvp, "useinbandfec=%30u", &val) == 1) {
  101. attr->fec = val;
  102. }
  103. if ((kvp = strstr(attributes, "usedtx")) && sscanf(kvp, "usedtx=%30u", &val) == 1) {
  104. attr->dtx = val;
  105. }
  106. return 0;
  107. }
  108. static void opus_generate_sdp_fmtp(const struct ast_format *format, unsigned int payload, struct ast_str **str)
  109. {
  110. struct opus_attr *attr = ast_format_get_attribute_data(format);
  111. if (!attr) {
  112. return;
  113. }
  114. /* FIXME should we only generate attributes that were explicitly set? */
  115. ast_str_append(str, 0,
  116. "a=fmtp:%u "
  117. "maxplaybackrate=%u;"
  118. "sprop-maxcapturerate=%u;"
  119. "minptime=%u;"
  120. "maxaveragebitrate=%u;"
  121. "stereo=%d;"
  122. "sprop-stereo=%d;"
  123. "cbr=%d;"
  124. "useinbandfec=%d;"
  125. "usedtx=%d\r\n",
  126. payload,
  127. attr->maxplayrate ? attr->maxplayrate : 48000, /* maxplaybackrate */
  128. attr->spropmaxcapturerate ? attr->spropmaxcapturerate : 48000, /* sprop-maxcapturerate */
  129. attr->minptime > 10 ? attr->minptime : 10, /* minptime */
  130. attr->maxbitrate ? attr->maxbitrate : 20000, /* maxaveragebitrate */
  131. attr->stereo ? 1 : 0, /* stereo */
  132. attr->spropstereo ? 1 : 0, /* sprop-stereo */
  133. attr->cbr ? 1 : 0, /* cbr */
  134. attr->fec ? 1 : 0, /* useinbandfec */
  135. attr->dtx ? 1 : 0 /* usedtx */
  136. );
  137. }
  138. static struct ast_format *opus_getjoint(const struct ast_format *format1, const struct ast_format *format2)
  139. {
  140. struct opus_attr *attr1 = ast_format_get_attribute_data(format1);
  141. struct opus_attr *attr2 = ast_format_get_attribute_data(format2);
  142. struct ast_format *jointformat;
  143. struct opus_attr *attr_res;
  144. jointformat = ast_format_clone(format1);
  145. if (!jointformat) {
  146. return NULL;
  147. }
  148. attr_res = ast_format_get_attribute_data(jointformat);
  149. /* Only do dtx if both sides want it. DTX is a trade off between
  150. * computational complexity and bandwidth. */
  151. attr_res->dtx = attr1->dtx && attr2->dtx ? 1 : 0;
  152. /* Only do FEC if both sides want it. If a peer specifically requests not
  153. * to receive with FEC, it may be a waste of bandwidth. */
  154. attr_res->fec = attr1->fec && attr2->fec ? 1 : 0;
  155. /* Only do stereo if both sides want it. If a peer specifically requests not
  156. * to receive stereo signals, it may be a waste of bandwidth. */
  157. attr_res->stereo = attr1->stereo && attr2->stereo ? 1 : 0;
  158. /* FIXME: do we need to join other attributes as well, e.g., minptime, cbr, etc.? */
  159. return jointformat;
  160. }
  161. static struct ast_format *opus_set(const struct ast_format *format, const char *name, const char *value)
  162. {
  163. struct ast_format *cloned;
  164. struct opus_attr *attr;
  165. unsigned int val;
  166. if (sscanf(value, "%30u", &val) != 1) {
  167. ast_log(LOG_WARNING, "Unknown value '%s' for attribute type '%s'\n",
  168. value, name);
  169. return NULL;
  170. }
  171. cloned = ast_format_clone(format);
  172. if (!cloned) {
  173. return NULL;
  174. }
  175. attr = ast_format_get_attribute_data(cloned);
  176. if (!strcasecmp(name, "max_bitrate")) {
  177. attr->maxbitrate = val;
  178. } else if (!strcasecmp(name, "max_playrate")) {
  179. attr->maxplayrate = val;
  180. } else if (!strcasecmp(name, "minptime")) {
  181. attr->minptime = val;
  182. } else if (!strcasecmp(name, "stereo")) {
  183. attr->stereo = val;
  184. } else if (!strcasecmp(name, "cbr")) {
  185. attr->cbr = val;
  186. } else if (!strcasecmp(name, "fec")) {
  187. attr->fec = val;
  188. } else if (!strcasecmp(name, "dtx")) {
  189. attr->dtx = val;
  190. } else if (!strcasecmp(name, "sprop_capture_rate")) {
  191. attr->spropmaxcapturerate = val;
  192. } else if (!strcasecmp(name, "sprop_stereo")) {
  193. attr->spropstereo = val;
  194. } else {
  195. ast_log(LOG_WARNING, "unknown attribute type %s\n", name);
  196. }
  197. return cloned;
  198. }
  199. static struct ast_format_interface opus_interface = {
  200. .format_destroy = opus_destroy,
  201. .format_clone = opus_clone,
  202. .format_get_joint = opus_getjoint,
  203. .format_attribute_set = opus_set,
  204. .format_parse_sdp_fmtp = opus_parse_sdp_fmtp,
  205. .format_generate_sdp_fmtp = opus_generate_sdp_fmtp,
  206. };
  207. static int load_module(void)
  208. {
  209. if (ast_format_interface_register("opus", &opus_interface)) {
  210. return AST_MODULE_LOAD_DECLINE;
  211. }
  212. return AST_MODULE_LOAD_SUCCESS;
  213. }
  214. static int unload_module(void)
  215. {
  216. return 0;
  217. }
  218. AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Opus Format Attribute Module",
  219. .support_level = AST_MODULE_SUPPORT_CORE,
  220. .load = load_module,
  221. .unload = unload_module,
  222. .load_pri = AST_MODPRI_CHANNEL_DEPEND,
  223. );