app_dahdibarge.c 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312
  1. /*
  2. * Asterisk -- An open source telephony toolkit.
  3. *
  4. * Copyright (C) 1999 - 2005, Digium, Inc.
  5. *
  6. * Mark Spencer <markster@digium.com>
  7. *
  8. * Special thanks to comphealth.com for sponsoring this
  9. * GPL application.
  10. *
  11. * See http://www.asterisk.org for more information about
  12. * the Asterisk project. Please do not directly contact
  13. * any of the maintainers of this project for assistance;
  14. * the project provides a web site, mailing lists and IRC
  15. * channels for your use.
  16. *
  17. * This program is free software, distributed under the terms of
  18. * the GNU General Public License Version 2. See the LICENSE file
  19. * at the top of the source tree.
  20. */
  21. /*! \file
  22. *
  23. * \brief DAHDI Barge support
  24. *
  25. * \author Mark Spencer <markster@digium.com>
  26. *
  27. * \note Special thanks to comphealth.com for sponsoring this
  28. * GPL application.
  29. *
  30. * \ingroup applications
  31. */
  32. /*** MODULEINFO
  33. <depend>dahdi</depend>
  34. <defaultenabled>no</defaultenabled>
  35. <support_level>deprecated</support_level>
  36. <replacement>app_chanspy</replacement>
  37. ***/
  38. #include "asterisk.h"
  39. ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
  40. #include <dahdi/user.h>
  41. #include "asterisk/lock.h"
  42. #include "asterisk/file.h"
  43. #include "asterisk/channel.h"
  44. #include "asterisk/pbx.h"
  45. #include "asterisk/module.h"
  46. #include "asterisk/config.h"
  47. #include "asterisk/app.h"
  48. #include "asterisk/cli.h"
  49. #include "asterisk/say.h"
  50. #include "asterisk/utils.h"
  51. /*** DOCUMENTATION
  52. <application name="DAHDIBarge" language="en_US">
  53. <synopsis>
  54. Barge in (monitor) DAHDI channel.
  55. </synopsis>
  56. <syntax>
  57. <parameter name="channel">
  58. <para>Channel to barge.</para>
  59. </parameter>
  60. </syntax>
  61. <description>
  62. <para>Barges in on a specified DAHDI <replaceable>channel</replaceable> or prompts
  63. if one is not specified. Returns <literal>-1</literal> when caller user hangs
  64. up and is independent of the state of the channel being monitored.
  65. </para>
  66. </description>
  67. </application>
  68. ***/
  69. static const char app[] = "DAHDIBarge";
  70. #define CONF_SIZE 160
  71. static int careful_write(int fd, unsigned char *data, int len)
  72. {
  73. int res;
  74. while(len) {
  75. res = write(fd, data, len);
  76. if (res < 1) {
  77. if (errno != EAGAIN) {
  78. ast_log(LOG_WARNING, "Failed to write audio data to conference: %s\n", strerror(errno));
  79. return -1;
  80. } else
  81. return 0;
  82. }
  83. len -= res;
  84. data += res;
  85. }
  86. return 0;
  87. }
  88. static int conf_run(struct ast_channel *chan, int confno, int confflags)
  89. {
  90. int fd;
  91. struct dahdi_confinfo dahdic;
  92. struct ast_frame *f;
  93. struct ast_channel *c;
  94. struct ast_frame fr;
  95. int outfd;
  96. int ms;
  97. int nfds;
  98. int res;
  99. int flags;
  100. int retrydahdi;
  101. int origfd;
  102. int ret = -1;
  103. struct dahdi_bufferinfo bi;
  104. char __buf[CONF_SIZE + AST_FRIENDLY_OFFSET];
  105. char *buf = __buf + AST_FRIENDLY_OFFSET;
  106. /* Set it into U-law mode (write) */
  107. if (ast_set_write_format_by_id(chan, AST_FORMAT_ULAW) < 0) {
  108. ast_log(LOG_WARNING, "Unable to set '%s' to write ulaw mode\n", ast_channel_name(chan));
  109. goto outrun;
  110. }
  111. /* Set it into U-law mode (read) */
  112. if (ast_set_read_format_by_id(chan, AST_FORMAT_ULAW) < 0) {
  113. ast_log(LOG_WARNING, "Unable to set '%s' to read ulaw mode\n", ast_channel_name(chan));
  114. goto outrun;
  115. }
  116. ast_indicate(chan, -1);
  117. retrydahdi = strcasecmp(ast_channel_tech(chan)->type, "DAHDI");
  118. dahdiretry:
  119. origfd = ast_channel_fd(chan, 0);
  120. if (retrydahdi) {
  121. fd = open("/dev/dahdi/pseudo", O_RDWR);
  122. if (fd < 0) {
  123. ast_log(LOG_WARNING, "Unable to open pseudo channel: %s\n", strerror(errno));
  124. goto outrun;
  125. }
  126. /* Make non-blocking */
  127. flags = fcntl(fd, F_GETFL);
  128. if (flags < 0) {
  129. ast_log(LOG_WARNING, "Unable to get flags: %s\n", strerror(errno));
  130. close(fd);
  131. goto outrun;
  132. }
  133. if (fcntl(fd, F_SETFL, flags | O_NONBLOCK)) {
  134. ast_log(LOG_WARNING, "Unable to set flags: %s\n", strerror(errno));
  135. close(fd);
  136. goto outrun;
  137. }
  138. /* Setup buffering information */
  139. memset(&bi, 0, sizeof(bi));
  140. bi.bufsize = CONF_SIZE;
  141. bi.txbufpolicy = DAHDI_POLICY_IMMEDIATE;
  142. bi.rxbufpolicy = DAHDI_POLICY_IMMEDIATE;
  143. bi.numbufs = 4;
  144. if (ioctl(fd, DAHDI_SET_BUFINFO, &bi)) {
  145. ast_log(LOG_WARNING, "Unable to set buffering information: %s\n", strerror(errno));
  146. close(fd);
  147. goto outrun;
  148. }
  149. nfds = 1;
  150. } else {
  151. /* XXX Make sure we're not running on a pseudo channel XXX */
  152. fd = ast_channel_fd(chan, 0);
  153. nfds = 0;
  154. }
  155. memset(&dahdic, 0, sizeof(dahdic));
  156. /* Check to see if we're in a conference... */
  157. dahdic.chan = 0;
  158. if (ioctl(fd, DAHDI_GETCONF, &dahdic)) {
  159. ast_log(LOG_WARNING, "Error getting conference\n");
  160. close(fd);
  161. goto outrun;
  162. }
  163. if (dahdic.confmode) {
  164. /* Whoa, already in a conference... Retry... */
  165. if (!retrydahdi) {
  166. ast_debug(1, "DAHDI channel is in a conference already, retrying with pseudo\n");
  167. retrydahdi = 1;
  168. goto dahdiretry;
  169. }
  170. }
  171. memset(&dahdic, 0, sizeof(dahdic));
  172. /* Add us to the conference */
  173. dahdic.chan = 0;
  174. dahdic.confno = confno;
  175. dahdic.confmode = DAHDI_CONF_MONITORBOTH;
  176. if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
  177. ast_log(LOG_WARNING, "Error setting conference\n");
  178. close(fd);
  179. goto outrun;
  180. }
  181. ast_debug(1, "Placed channel %s in DAHDI channel %d monitor\n", ast_channel_name(chan), confno);
  182. for(;;) {
  183. outfd = -1;
  184. ms = -1;
  185. c = ast_waitfor_nandfds(&chan, 1, &fd, nfds, NULL, &outfd, &ms);
  186. if (c) {
  187. if (ast_channel_fd(c, 0) != origfd) {
  188. if (retrydahdi) {
  189. /* Kill old pseudo */
  190. close(fd);
  191. }
  192. ast_debug(1, "Ooh, something swapped out under us, starting over\n");
  193. retrydahdi = 0;
  194. goto dahdiretry;
  195. }
  196. f = ast_read(c);
  197. if (!f)
  198. break;
  199. if ((f->frametype == AST_FRAME_DTMF) && (f->subclass.integer == '#')) {
  200. ret = 0;
  201. ast_frfree(f);
  202. break;
  203. } else if (fd != ast_channel_fd(chan, 0)) {
  204. if (f->frametype == AST_FRAME_VOICE) {
  205. if (f->subclass.format.id == AST_FORMAT_ULAW) {
  206. /* Carefully write */
  207. careful_write(fd, f->data.ptr, f->datalen);
  208. } else
  209. ast_log(LOG_WARNING, "Huh? Got a non-ulaw (%s) frame in the conference\n", ast_getformatname(&f->subclass.format));
  210. }
  211. }
  212. ast_frfree(f);
  213. } else if (outfd > -1) {
  214. res = read(outfd, buf, CONF_SIZE);
  215. if (res > 0) {
  216. memset(&fr, 0, sizeof(fr));
  217. fr.frametype = AST_FRAME_VOICE;
  218. ast_format_set(&fr.subclass.format, AST_FORMAT_ULAW, 0);
  219. fr.datalen = res;
  220. fr.samples = res;
  221. fr.data.ptr = buf;
  222. fr.offset = AST_FRIENDLY_OFFSET;
  223. if (ast_write(chan, &fr) < 0) {
  224. ast_log(LOG_WARNING, "Unable to write frame to channel: %s\n", strerror(errno));
  225. /* break; */
  226. }
  227. } else
  228. ast_log(LOG_WARNING, "Failed to read frame: %s\n", strerror(errno));
  229. }
  230. }
  231. if (fd != ast_channel_fd(chan, 0))
  232. close(fd);
  233. else {
  234. /* Take out of conference */
  235. /* Add us to the conference */
  236. dahdic.chan = 0;
  237. dahdic.confno = 0;
  238. dahdic.confmode = 0;
  239. if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
  240. ast_log(LOG_WARNING, "Error setting conference\n");
  241. }
  242. }
  243. outrun:
  244. return ret;
  245. }
  246. static int conf_exec(struct ast_channel *chan, const char *data)
  247. {
  248. int res = -1;
  249. int retrycnt = 0;
  250. int confflags = 0;
  251. int confno = 0;
  252. char confnostr[80] = "";
  253. if (!ast_strlen_zero(data)) {
  254. if ((sscanf(data, "DAHDI/%30d", &confno) != 1) &&
  255. (sscanf(data, "%30d", &confno) != 1)) {
  256. ast_log(LOG_WARNING, "DAHDIBarge Argument (if specified) must be a channel number, not '%s'\n", (char *)data);
  257. return 0;
  258. }
  259. }
  260. if (ast_channel_state(chan) != AST_STATE_UP)
  261. ast_answer(chan);
  262. while(!confno && (++retrycnt < 4)) {
  263. /* Prompt user for conference number */
  264. confnostr[0] = '\0';
  265. res = ast_app_getdata(chan, "conf-getchannel",confnostr, sizeof(confnostr) - 1, 0);
  266. if (res <0) goto out;
  267. if (sscanf(confnostr, "%30d", &confno) != 1)
  268. confno = 0;
  269. }
  270. if (confno) {
  271. /* XXX Should prompt user for pin if pin is required XXX */
  272. /* Run the conference */
  273. res = conf_run(chan, confno, confflags);
  274. }
  275. out:
  276. /* Do the conference */
  277. return res;
  278. }
  279. static int unload_module(void)
  280. {
  281. return ast_unregister_application(app);
  282. }
  283. static int load_module(void)
  284. {
  285. return ((ast_register_application_xml(app, conf_exec)) ? AST_MODULE_LOAD_FAILURE : AST_MODULE_LOAD_SUCCESS);
  286. }
  287. AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Barge in on DAHDI channel application");