app_ices.c 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  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. /*** DOCUMENTATION
  46. <application name="ICES" language="en_US">
  47. <synopsis>
  48. Encode and stream using 'ices'.
  49. </synopsis>
  50. <syntax>
  51. <parameter name="config" required="true">
  52. <para>ICES configuration file.</para>
  53. </parameter>
  54. </syntax>
  55. <description>
  56. <para>Streams to an icecast server using ices (available separately).
  57. A configuration file must be supplied for ices (see contrib/asterisk-ices.xml).</para>
  58. <note><para>ICES version 2 client and server required.</para></note>
  59. </description>
  60. </application>
  61. ***/
  62. #define path_BIN "/usr/bin/"
  63. #define path_LOCAL "/usr/local/bin/"
  64. static char *app = "ICES";
  65. static int icesencode(char *filename, int fd)
  66. {
  67. int res;
  68. res = ast_safe_fork(0);
  69. if (res < 0)
  70. ast_log(LOG_WARNING, "Fork failed\n");
  71. if (res) {
  72. return res;
  73. }
  74. if (ast_opt_high_priority)
  75. ast_set_priority(0);
  76. dup2(fd, STDIN_FILENO);
  77. ast_close_fds_above_n(STDERR_FILENO);
  78. /* Most commonly installed in /usr/local/bin
  79. * But many places has it in /usr/bin
  80. * As a last-ditch effort, try to use PATH
  81. */
  82. execl(path_LOCAL "ices2", "ices", filename, SENTINEL);
  83. execl(path_BIN "ices2", "ices", filename, SENTINEL);
  84. execlp("ices2", "ices", filename, SENTINEL);
  85. ast_debug(1, "Couldn't find ices version 2, attempting to use ices version 1.\n");
  86. execl(path_LOCAL "ices", "ices", filename, SENTINEL);
  87. execl(path_BIN "ices", "ices", filename, SENTINEL);
  88. execlp("ices", "ices", filename, SENTINEL);
  89. ast_log(LOG_WARNING, "Execute of ices failed, could not find command.\n");
  90. close(fd);
  91. _exit(0);
  92. }
  93. static int ices_exec(struct ast_channel *chan, const char *data)
  94. {
  95. int res = 0;
  96. int fds[2];
  97. int ms = -1;
  98. int pid = -1;
  99. int flags;
  100. struct ast_format oreadformat;
  101. struct ast_frame *f;
  102. char filename[256]="";
  103. char *c;
  104. ast_format_clear(&oreadformat);
  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. ast_format_copy(&oreadformat, ast_channel_readformat(chan));
  125. res = ast_set_read_format_by_id(chan, AST_FORMAT_SLINEAR);
  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. return -1;
  131. }
  132. if (((char *)data)[0] == '/')
  133. ast_copy_string(filename, (char *) data, sizeof(filename));
  134. else
  135. snprintf(filename, sizeof(filename), "%s/%s", ast_config_AST_CONFIG_DIR, (char *)data);
  136. /* Placeholder for options */
  137. c = strchr(filename, '|');
  138. if (c)
  139. *c = '\0';
  140. res = icesencode(filename, fds[0]);
  141. if (res >= 0) {
  142. pid = res;
  143. for (;;) {
  144. /* Wait for audio, and stream */
  145. ms = ast_waitfor(chan, -1);
  146. if (ms < 0) {
  147. ast_debug(1, "Hangup detected\n");
  148. res = -1;
  149. break;
  150. }
  151. f = ast_read(chan);
  152. if (!f) {
  153. ast_debug(1, "Null frame == hangup() detected\n");
  154. res = -1;
  155. break;
  156. }
  157. if (f->frametype == AST_FRAME_VOICE) {
  158. res = write(fds[1], f->data.ptr, f->datalen);
  159. if (res < 0) {
  160. if (errno != EAGAIN) {
  161. ast_log(LOG_WARNING, "Write failed to pipe: %s\n", strerror(errno));
  162. res = -1;
  163. ast_frfree(f);
  164. break;
  165. }
  166. }
  167. }
  168. ast_frfree(f);
  169. }
  170. }
  171. close(fds[0]);
  172. close(fds[1]);
  173. if (pid > -1)
  174. kill(pid, SIGKILL);
  175. if (!res && oreadformat.id)
  176. ast_set_read_format(chan, &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(ASTERISK_GPL_KEY, "Encode and Stream via icecast and ices");