chan_nbs.c 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275
  1. /*
  2. * Asterisk -- An open source telephony toolkit.
  3. *
  4. * Copyright (C) 1999 - 2006, 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. /*! \file
  19. *
  20. * \brief Network broadcast sound support channel driver
  21. *
  22. * \author Mark Spencer <markster@digium.com>
  23. *
  24. * \ingroup channel_drivers
  25. */
  26. /*** MODULEINFO
  27. <depend>nbs</depend>
  28. <support_level>extended</support_level>
  29. ***/
  30. #include "asterisk.h"
  31. ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
  32. #include <sys/socket.h>
  33. #include <sys/time.h>
  34. #include <arpa/inet.h>
  35. #include <fcntl.h>
  36. #include <sys/ioctl.h>
  37. #include <nbs.h>
  38. #include "asterisk/lock.h"
  39. #include "asterisk/channel.h"
  40. #include "asterisk/config.h"
  41. #include "asterisk/module.h"
  42. #include "asterisk/pbx.h"
  43. #include "asterisk/utils.h"
  44. #include "asterisk/format_cache.h"
  45. static const char tdesc[] = "Network Broadcast Sound Driver";
  46. static char context[AST_MAX_EXTENSION] = "default";
  47. static const char type[] = "NBS";
  48. /* NBS creates private structures on demand */
  49. struct nbs_pvt {
  50. NBS *nbs;
  51. struct ast_channel *owner; /* Channel we belong to, possibly NULL */
  52. char app[16]; /* Our app */
  53. char stream[80]; /* Our stream */
  54. struct ast_module_user *u; /*! for holding a reference to this module */
  55. };
  56. static struct ast_channel *nbs_request(const char *type, struct ast_format_cap *cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *data, int *cause);
  57. static int nbs_call(struct ast_channel *ast, const char *dest, int timeout);
  58. static int nbs_hangup(struct ast_channel *ast);
  59. static struct ast_frame *nbs_xread(struct ast_channel *ast);
  60. static int nbs_xwrite(struct ast_channel *ast, struct ast_frame *frame);
  61. static struct ast_channel_tech nbs_tech = {
  62. .type = type,
  63. .description = tdesc,
  64. .requester = nbs_request,
  65. .call = nbs_call,
  66. .hangup = nbs_hangup,
  67. .read = nbs_xread,
  68. .write = nbs_xwrite,
  69. };
  70. static int nbs_call(struct ast_channel *ast, const char *dest, int timeout)
  71. {
  72. struct nbs_pvt *p;
  73. p = ast_channel_tech_pvt(ast);
  74. if ((ast_channel_state(ast) != AST_STATE_DOWN) && (ast_channel_state(ast) != AST_STATE_RESERVED)) {
  75. ast_log(LOG_WARNING, "nbs_call called on %s, neither down nor reserved\n", ast_channel_name(ast));
  76. return -1;
  77. }
  78. /* When we call, it just works, really, there's no destination... Just
  79. ring the phone and wait for someone to answer */
  80. ast_debug(1, "Calling %s on %s\n", dest, ast_channel_name(ast));
  81. /* If we can't connect, return congestion */
  82. if (nbs_connect(p->nbs)) {
  83. ast_log(LOG_WARNING, "NBS Connection failed on %s\n", ast_channel_name(ast));
  84. ast_queue_control(ast, AST_CONTROL_CONGESTION);
  85. } else {
  86. ast_setstate(ast, AST_STATE_RINGING);
  87. ast_queue_control(ast, AST_CONTROL_ANSWER);
  88. }
  89. return 0;
  90. }
  91. static void nbs_destroy(struct nbs_pvt *p)
  92. {
  93. if (p->nbs)
  94. nbs_delstream(p->nbs);
  95. ast_module_user_remove(p->u);
  96. ast_free(p);
  97. }
  98. static struct nbs_pvt *nbs_alloc(const char *data)
  99. {
  100. struct nbs_pvt *p;
  101. int flags = 0;
  102. char stream[256];
  103. char *opts;
  104. ast_copy_string(stream, data, sizeof(stream));
  105. if ((opts = strchr(stream, ':'))) {
  106. *opts = '\0';
  107. opts++;
  108. } else
  109. opts = "";
  110. p = ast_calloc(1, sizeof(*p));
  111. if (p) {
  112. if (!ast_strlen_zero(opts)) {
  113. if (strchr(opts, 'm'))
  114. flags |= NBS_FLAG_MUTE;
  115. if (strchr(opts, 'o'))
  116. flags |= NBS_FLAG_OVERSPEAK;
  117. if (strchr(opts, 'e'))
  118. flags |= NBS_FLAG_EMERGENCY;
  119. if (strchr(opts, 'O'))
  120. flags |= NBS_FLAG_OVERRIDE;
  121. } else
  122. flags = NBS_FLAG_OVERSPEAK;
  123. ast_copy_string(p->stream, stream, sizeof(p->stream));
  124. p->nbs = nbs_newstream("asterisk", stream, flags);
  125. if (!p->nbs) {
  126. ast_log(LOG_WARNING, "Unable to allocate new NBS stream '%s' with flags %d\n", stream, flags);
  127. ast_free(p);
  128. p = NULL;
  129. } else {
  130. /* Set for 8000 hz mono, 640 samples */
  131. nbs_setbitrate(p->nbs, 8000);
  132. nbs_setchannels(p->nbs, 1);
  133. nbs_setblocksize(p->nbs, 640);
  134. nbs_setblocking(p->nbs, 0);
  135. }
  136. }
  137. return p;
  138. }
  139. static int nbs_hangup(struct ast_channel *ast)
  140. {
  141. struct nbs_pvt *p;
  142. p = ast_channel_tech_pvt(ast);
  143. ast_debug(1, "nbs_hangup(%s)\n", ast_channel_name(ast));
  144. if (!ast_channel_tech_pvt(ast)) {
  145. ast_log(LOG_WARNING, "Asked to hangup channel not connected\n");
  146. return 0;
  147. }
  148. nbs_destroy(p);
  149. ast_channel_tech_pvt_set(ast, NULL);
  150. ast_setstate(ast, AST_STATE_DOWN);
  151. return 0;
  152. }
  153. static struct ast_frame *nbs_xread(struct ast_channel *ast)
  154. {
  155. ast_debug(1, "Returning null frame on %s\n", ast_channel_name(ast));
  156. return &ast_null_frame;
  157. }
  158. static int nbs_xwrite(struct ast_channel *ast, struct ast_frame *frame)
  159. {
  160. struct nbs_pvt *p = ast_channel_tech_pvt(ast);
  161. if (ast_channel_state(ast) != AST_STATE_UP) {
  162. /* Don't try tos end audio on-hook */
  163. return 0;
  164. }
  165. if (nbs_write(p->nbs, frame->data.ptr, frame->datalen / 2) < 0)
  166. return -1;
  167. return 0;
  168. }
  169. static struct ast_channel *nbs_new(struct nbs_pvt *i, int state, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor)
  170. {
  171. struct ast_channel *tmp;
  172. tmp = ast_channel_alloc(1, state, 0, 0, "", "s", context, assignedids, requestor, 0, "NBS/%s", i->stream);
  173. if (tmp) {
  174. ast_channel_tech_set(tmp, &nbs_tech);
  175. ast_channel_set_fd(tmp, 0, nbs_fd(i->nbs));
  176. ast_channel_nativeformats_set(tmp, nbs_tech.capabilities);
  177. ast_channel_set_rawreadformat(tmp, ast_format_slin);
  178. ast_channel_set_rawwriteformat(tmp, ast_format_slin);
  179. ast_channel_set_writeformat(tmp, ast_format_slin);
  180. ast_channel_set_readformat(tmp, ast_format_slin);
  181. if (state == AST_STATE_RING)
  182. ast_channel_rings_set(tmp, 1);
  183. ast_channel_tech_pvt_set(tmp, i);
  184. ast_channel_context_set(tmp, context);
  185. ast_channel_exten_set(tmp, "s");
  186. ast_channel_language_set(tmp, "");
  187. i->owner = tmp;
  188. i->u = ast_module_user_add(tmp);
  189. ast_channel_unlock(tmp);
  190. if (state != AST_STATE_DOWN) {
  191. if (ast_pbx_start(tmp)) {
  192. ast_log(LOG_WARNING, "Unable to start PBX on %s\n", ast_channel_name(tmp));
  193. ast_hangup(tmp);
  194. }
  195. }
  196. } else
  197. ast_log(LOG_WARNING, "Unable to allocate channel structure\n");
  198. return tmp;
  199. }
  200. static struct ast_channel *nbs_request(const char *type, struct ast_format_cap *cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *data, int *cause)
  201. {
  202. struct nbs_pvt *p;
  203. struct ast_channel *tmp = NULL;
  204. if (ast_format_cap_iscompatible_format(cap, ast_format_slin) == AST_FORMAT_CMP_NOT_EQUAL) {
  205. struct ast_str *cap_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN);
  206. ast_log(LOG_NOTICE, "Asked to get a channel of unsupported format '%s'\n",
  207. ast_format_cap_get_names(cap, &cap_buf));
  208. return NULL;
  209. }
  210. p = nbs_alloc(data);
  211. if (p) {
  212. tmp = nbs_new(p, AST_STATE_DOWN, assignedids, requestor);
  213. if (!tmp)
  214. nbs_destroy(p);
  215. }
  216. return tmp;
  217. }
  218. static int unload_module(void)
  219. {
  220. /* First, take us out of the channel loop */
  221. ast_channel_unregister(&nbs_tech);
  222. ao2_ref(nbs_tech.capabilities, -1);
  223. nbs_tech.capabilities = NULL;
  224. return 0;
  225. }
  226. static int load_module(void)
  227. {
  228. if (!(nbs_tech.capabilities = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) {
  229. return AST_MODULE_LOAD_DECLINE;
  230. }
  231. ast_format_cap_append(nbs_tech.capabilities, ast_format_slin, 0);
  232. /* Make sure we can register our channel type */
  233. if (ast_channel_register(&nbs_tech)) {
  234. ast_log(LOG_ERROR, "Unable to register channel class %s\n", type);
  235. ao2_ref(nbs_tech.capabilities, -1);
  236. nbs_tech.capabilities = NULL;
  237. return AST_MODULE_LOAD_DECLINE;
  238. }
  239. return AST_MODULE_LOAD_SUCCESS;
  240. }
  241. AST_MODULE_INFO_STANDARD_EXTENDED(ASTERISK_GPL_KEY, "Network Broadcast Sound Support");