app_ices.c 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  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. * 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 Stream to an icecast server via ICES (see contrib/asterisk-ices.xml)
  21. *
  22. * \author Mark Spencer <markster@digium.com>
  23. *
  24. * ICES - http://www.icecast.org/ices.php
  25. *
  26. * \ingroup applications
  27. */
  28. /*** MODULEINFO
  29. <support_level>extended</support_level>
  30. ***/
  31. #include "asterisk.h"
  32. ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
  33. #include <signal.h>
  34. #include <fcntl.h>
  35. #include <sys/time.h>
  36. #include "asterisk/paths.h" /* use ast_config_AST_CONFIG_DIR */
  37. #include "asterisk/lock.h"
  38. #include "asterisk/file.h"
  39. #include "asterisk/channel.h"
  40. #include "asterisk/frame.h"
  41. #include "asterisk/pbx.h"
  42. #include "asterisk/module.h"
  43. #include "asterisk/translate.h"
  44. #include "asterisk/app.h"
  45. #include "asterisk/format_cache.h"
  46. /*** DOCUMENTATION
  47. <application name="ICES" language="en_US">
  48. <synopsis>
  49. Encode and stream using 'ices'.
  50. </synopsis>
  51. <syntax>
  52. <parameter name="config" required="true">
  53. <para>ICES configuration file.</para>
  54. </parameter>
  55. </syntax>
  56. <description>
  57. <para>Streams to an icecast server using ices (available separately).
  58. A configuration file must be supplied for ices (see contrib/asterisk-ices.xml).</para>
  59. <note><para>ICES version 2 client and server required.</para></note>
  60. </description>
  61. </application>
  62. ***/
  63. #define path_BIN "/usr/bin/"
  64. #define path_LOCAL "/usr/local/bin/"
  65. static char *app = "ICES";
  66. static int icesencode(char *filename, int fd)
  67. {
  68. int res;
  69. res = ast_safe_fork(0);
  70. if (res < 0)
  71. ast_log(LOG_WARNING, "Fork failed\n");
  72. if (res) {
  73. return res;
  74. }
  75. if (ast_opt_high_priority)
  76. ast_set_priority(0);
  77. dup2(fd, STDIN_FILENO);
  78. ast_close_fds_above_n(STDERR_FILENO);
  79. /* Most commonly installed in /usr/local/bin
  80. * But many places has it in /usr/bin
  81. * As a last-ditch effort, try to use PATH
  82. */
  83. execl(path_LOCAL "ices2", "ices", filename, SENTINEL);
  84. execl(path_BIN "ices2", "ices", filename, SENTINEL);
  85. execlp("ices2", "ices", filename, SENTINEL);
  86. ast_debug(1, "Couldn't find ices version 2, attempting to use ices version 1.\n");
  87. execl(path_LOCAL "ices", "ices", filename, SENTINEL);
  88. execl(path_BIN "ices", "ices", filename, SENTINEL);
  89. execlp("ices", "ices", filename, SENTINEL);
  90. ast_log(LOG_WARNING, "Execute of ices failed, could not find command.\n");
  91. close(fd);
  92. _exit(0);
  93. }
  94. static int ices_exec(struct ast_channel *chan, const char *data)
  95. {
  96. int res = 0;
  97. int fds[2];
  98. int ms = -1;
  99. int pid = -1;
  100. int flags;
  101. struct ast_format *oreadformat;
  102. struct ast_frame *f;
  103. char filename[256]="";
  104. char *c;
  105. if (ast_strlen_zero(data)) {
  106. ast_log(LOG_WARNING, "ICES requires an argument (configfile.xml)\n");
  107. return -1;
  108. }
  109. if (pipe(fds)) {
  110. ast_log(LOG_WARNING, "Unable to create pipe\n");
  111. return -1;
  112. }
  113. flags = fcntl(fds[1], F_GETFL);
  114. fcntl(fds[1], F_SETFL, flags | O_NONBLOCK);
  115. ast_stopstream(chan);
  116. if (ast_channel_state(chan) != AST_STATE_UP)
  117. res = ast_answer(chan);
  118. if (res) {
  119. close(fds[0]);
  120. close(fds[1]);
  121. ast_log(LOG_WARNING, "Answer failed!\n");
  122. return -1;
  123. }
  124. oreadformat = ao2_bump(ast_channel_readformat(chan));
  125. res = ast_set_read_format(chan, ast_format_slin);
  126. if (res < 0) {
  127. close(fds[0]);
  128. close(fds[1]);
  129. ast_log(LOG_WARNING, "Unable to set write format to signed linear\n");
  130. ao2_cleanup(oreadformat);
  131. return -1;
  132. }
  133. if (((char *)data)[0] == '/')
  134. ast_copy_string(filename, (char *) data, sizeof(filename));
  135. else
  136. snprintf(filename, sizeof(filename), "%s/%s", ast_config_AST_CONFIG_DIR, (char *)data);
  137. /* Placeholder for options */
  138. c = strchr(filename, '|');
  139. if (c)
  140. *c = '\0';
  141. res = icesencode(filename, fds[0]);
  142. if (res >= 0) {
  143. pid = res;
  144. for (;;) {
  145. /* Wait for audio, and stream */
  146. ms = ast_waitfor(chan, -1);
  147. if (ms < 0) {
  148. ast_debug(1, "Hangup detected\n");
  149. res = -1;
  150. break;
  151. }
  152. f = ast_read(chan);
  153. if (!f) {
  154. ast_debug(1, "Null frame == hangup() detected\n");
  155. res = -1;
  156. break;
  157. }
  158. if (f->frametype == AST_FRAME_VOICE) {
  159. res = write(fds[1], f->data.ptr, f->datalen);
  160. if (res < 0) {
  161. if (errno != EAGAIN) {
  162. ast_log(LOG_WARNING, "Write failed to pipe: %s\n", strerror(errno));
  163. res = -1;
  164. ast_frfree(f);
  165. break;
  166. }
  167. }
  168. }
  169. ast_frfree(f);
  170. }
  171. }
  172. close(fds[0]);
  173. close(fds[1]);
  174. if (pid > -1)
  175. kill(pid, SIGKILL);
  176. if (!res && oreadformat)
  177. ast_set_read_format(chan, oreadformat);
  178. ao2_cleanup(oreadformat);
  179. return res;
  180. }
  181. static int unload_module(void)
  182. {
  183. return ast_unregister_application(app);
  184. }
  185. static int load_module(void)
  186. {
  187. return ast_register_application_xml(app, ices_exec);
  188. }
  189. AST_MODULE_INFO_STANDARD_EXTENDED(ASTERISK_GPL_KEY, "Encode and Stream via icecast and ices");