app_ices.c 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  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. struct ast_format *oreadformat;
  101. struct ast_frame *f;
  102. char filename[256]="";
  103. char *c;
  104. if (ast_strlen_zero(data)) {
  105. ast_log(LOG_WARNING, "ICES requires an argument (configfile.xml)\n");
  106. return -1;
  107. }
  108. if (pipe(fds)) {
  109. ast_log(LOG_WARNING, "Unable to create pipe\n");
  110. return -1;
  111. }
  112. ast_fd_set_flags(fds[1], O_NONBLOCK);
  113. ast_stopstream(chan);
  114. if (ast_channel_state(chan) != AST_STATE_UP)
  115. res = ast_answer(chan);
  116. if (res) {
  117. close(fds[0]);
  118. close(fds[1]);
  119. ast_log(LOG_WARNING, "Answer failed!\n");
  120. return -1;
  121. }
  122. oreadformat = ao2_bump(ast_channel_readformat(chan));
  123. res = ast_set_read_format(chan, ast_format_slin);
  124. if (res < 0) {
  125. close(fds[0]);
  126. close(fds[1]);
  127. ast_log(LOG_WARNING, "Unable to set write format to signed linear\n");
  128. ao2_cleanup(oreadformat);
  129. return -1;
  130. }
  131. if (((char *)data)[0] == '/')
  132. ast_copy_string(filename, (char *) data, sizeof(filename));
  133. else
  134. snprintf(filename, sizeof(filename), "%s/%s", ast_config_AST_CONFIG_DIR, (char *)data);
  135. /* Placeholder for options */
  136. c = strchr(filename, '|');
  137. if (c)
  138. *c = '\0';
  139. res = icesencode(filename, fds[0]);
  140. if (res >= 0) {
  141. pid = res;
  142. for (;;) {
  143. /* Wait for audio, and stream */
  144. ms = ast_waitfor(chan, -1);
  145. if (ms < 0) {
  146. ast_debug(1, "Hangup detected\n");
  147. res = -1;
  148. break;
  149. }
  150. f = ast_read(chan);
  151. if (!f) {
  152. ast_debug(1, "Null frame == hangup() detected\n");
  153. res = -1;
  154. break;
  155. }
  156. if (f->frametype == AST_FRAME_VOICE) {
  157. res = write(fds[1], f->data.ptr, f->datalen);
  158. if (res < 0) {
  159. if (errno != EAGAIN) {
  160. ast_log(LOG_WARNING, "Write failed to pipe: %s\n", strerror(errno));
  161. res = -1;
  162. ast_frfree(f);
  163. break;
  164. }
  165. }
  166. }
  167. ast_frfree(f);
  168. }
  169. }
  170. close(fds[0]);
  171. close(fds[1]);
  172. if (pid > -1)
  173. kill(pid, SIGKILL);
  174. if (!res && oreadformat)
  175. ast_set_read_format(chan, oreadformat);
  176. ao2_cleanup(oreadformat);
  177. return res;
  178. }
  179. static int unload_module(void)
  180. {
  181. return ast_unregister_application(app);
  182. }
  183. static int load_module(void)
  184. {
  185. return ast_register_application_xml(app, ices_exec);
  186. }
  187. AST_MODULE_INFO_STANDARD_EXTENDED(ASTERISK_GPL_KEY, "Encode and Stream via icecast and ices");