app_mp3.c 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  1. /*
  2. * Asterisk -- A telephony toolkit for Linux.
  3. *
  4. * Silly application to play an MP3 file -- uses mpg123
  5. *
  6. * Copyright (C) 1999, Mark Spencer
  7. *
  8. * Mark Spencer <markster@linux-support.net>
  9. *
  10. * This program is free software, distributed under the terms of
  11. * the GNU General Public License
  12. */
  13. #include <asterisk/lock.h>
  14. #include <asterisk/file.h>
  15. #include <asterisk/logger.h>
  16. #include <asterisk/channel.h>
  17. #include <asterisk/frame.h>
  18. #include <asterisk/pbx.h>
  19. #include <asterisk/module.h>
  20. #include <asterisk/translate.h>
  21. #include <string.h>
  22. #include <stdio.h>
  23. #include <signal.h>
  24. #include <stdlib.h>
  25. #include <unistd.h>
  26. #include <fcntl.h>
  27. #include <pthread.h>
  28. #include <sys/time.h>
  29. #define LOCAL_MPG_123 "/usr/local/bin/mpg123"
  30. #define MPG_123 "/usr/bin/mpg123"
  31. static char *tdesc = "Silly MP3 Application";
  32. static char *app = "MP3Player";
  33. static char *synopsis = "Play an MP3 file or stream";
  34. static char *descrip =
  35. " MP3Player(location) Executes mpg123 to play the given location\n"
  36. "which typically would be a filename or a URL. Returns -1 on\n"
  37. "hangup or 0 otherwise. User can exit by pressing any key\n.";
  38. STANDARD_LOCAL_USER;
  39. LOCAL_USER_DECL;
  40. static int mp3play(char *filename, int fd)
  41. {
  42. int res;
  43. int x;
  44. res = fork();
  45. if (res < 0)
  46. ast_log(LOG_WARNING, "Fork failed\n");
  47. if (res)
  48. return res;
  49. dup2(fd, STDOUT_FILENO);
  50. for (x=0;x<256;x++) {
  51. if (x != STDOUT_FILENO)
  52. close(x);
  53. }
  54. /* Execute mpg123, but buffer if it's a net connection */
  55. if (strncmp(filename, "http://", 7)) {
  56. /* Most commonly installed in /usr/local/bin */
  57. execl(LOCAL_MPG_123, "mpg123", "-q", "-s", "-b", "1024", "--mono", "-r", "8000", filename, (char *)NULL);
  58. /* But many places has it in /usr/bin */
  59. execl(MPG_123, "mpg123", "-q", "-s", "-b", "1024", "--mono", "-r", "8000", filename, (char *)NULL);
  60. /* As a last-ditch effort, try to use PATH */
  61. execlp("mpg123", "mpg123", "-q", "-s", "-b", "1024", "--mono", "-r", "8000", filename, (char *)NULL);
  62. }
  63. else {
  64. /* Most commonly installed in /usr/local/bin */
  65. execl(MPG_123, "mpg123", "-q", "-s", "--mono", "-r", "8000", filename, (char *)NULL);
  66. /* But many places has it in /usr/bin */
  67. execl(LOCAL_MPG_123, "mpg123", "-q", "-s", "--mono", "-r", "8000", filename, (char *)NULL);
  68. /* As a last-ditch effort, try to use PATH */
  69. execlp("mpg123", "mpg123", "-q", "-s", "--mono", "-r", "8000", filename, (char *)NULL);
  70. }
  71. ast_log(LOG_WARNING, "Execute of mpg123 failed\n");
  72. return -1;
  73. }
  74. static int timed_read(int fd, void *data, int datalen)
  75. {
  76. int res;
  77. fd_set fds;
  78. struct timeval tv = { 2, 0 }; /* Wait no more than 2 seconds */
  79. FD_ZERO(&fds);
  80. FD_SET(fd, &fds);
  81. res = ast_select(fd + 1, &fds, NULL, NULL, &tv);
  82. if (res < 1) {
  83. ast_log(LOG_NOTICE, "Selected timed out/errored out with %d\n", res);
  84. return -1;
  85. }
  86. return read(fd, data, datalen);
  87. }
  88. static int mp3_exec(struct ast_channel *chan, void *data)
  89. {
  90. int res=0;
  91. struct localuser *u;
  92. int fds[2];
  93. int ms = -1;
  94. int pid = -1;
  95. int owriteformat;
  96. struct timeval last;
  97. struct ast_frame *f;
  98. struct myframe {
  99. struct ast_frame f;
  100. char offset[AST_FRIENDLY_OFFSET];
  101. short frdata[160];
  102. } myf;
  103. last.tv_usec = 0;
  104. last.tv_sec = 0;
  105. if (!data) {
  106. ast_log(LOG_WARNING, "MP3 Playback requires an argument (filename)\n");
  107. return -1;
  108. }
  109. if (pipe(fds)) {
  110. ast_log(LOG_WARNING, "Unable to create pipe\n");
  111. return -1;
  112. }
  113. LOCAL_USER_ADD(u);
  114. ast_stopstream(chan);
  115. owriteformat = chan->writeformat;
  116. res = ast_set_write_format(chan, AST_FORMAT_SLINEAR);
  117. if (res < 0) {
  118. ast_log(LOG_WARNING, "Unable to set write format to signed linear\n");
  119. return -1;
  120. }
  121. res = mp3play((char *)data, fds[1]);
  122. /* Wait 1000 ms first */
  123. ms = 1000;
  124. if (res >= 0) {
  125. pid = res;
  126. /* Order is important -- there's almost always going to be mp3... we want to prioritize the
  127. user */
  128. for (;;) {
  129. ms = ast_waitfor(chan, ms);
  130. if (ms < 0) {
  131. ast_log(LOG_DEBUG, "Hangup detected\n");
  132. res = -1;
  133. break;
  134. }
  135. if (ms) {
  136. f = ast_read(chan);
  137. if (!f) {
  138. ast_log(LOG_DEBUG, "Null frame == hangup() detected\n");
  139. res = -1;
  140. break;
  141. }
  142. if (f->frametype == AST_FRAME_DTMF) {
  143. ast_log(LOG_DEBUG, "User pressed a key\n");
  144. ast_frfree(f);
  145. res = 0;
  146. break;
  147. }
  148. ast_frfree(f);
  149. } else {
  150. res = timed_read(fds[0], myf.frdata, sizeof(myf.frdata));
  151. if (res > 0) {
  152. myf.f.frametype = AST_FRAME_VOICE;
  153. myf.f.subclass = AST_FORMAT_SLINEAR;
  154. myf.f.datalen = res;
  155. myf.f.samples = res / 2;
  156. myf.f.mallocd = 0;
  157. myf.f.offset = AST_FRIENDLY_OFFSET;
  158. myf.f.src = __PRETTY_FUNCTION__;
  159. myf.f.data = myf.frdata;
  160. if (ast_write(chan, &myf.f) < 0) {
  161. res = -1;
  162. break;
  163. }
  164. } else {
  165. ast_log(LOG_DEBUG, "No more mp3\n");
  166. res = 0;
  167. break;
  168. }
  169. ms = res / 16;
  170. }
  171. }
  172. }
  173. close(fds[0]);
  174. close(fds[1]);
  175. LOCAL_USER_REMOVE(u);
  176. if (pid > -1)
  177. kill(pid, SIGKILL);
  178. if (!res && owriteformat)
  179. ast_set_write_format(chan, owriteformat);
  180. return res;
  181. }
  182. int unload_module(void)
  183. {
  184. STANDARD_HANGUP_LOCALUSERS;
  185. return ast_unregister_application(app);
  186. }
  187. int load_module(void)
  188. {
  189. return ast_register_application(app, mp3_exec, synopsis, descrip);
  190. }
  191. char *description(void)
  192. {
  193. return tdesc;
  194. }
  195. int usecount(void)
  196. {
  197. int res;
  198. STANDARD_USECOUNT(res);
  199. return res;
  200. }
  201. char *key()
  202. {
  203. return ASTERISK_GPL_KEY;
  204. }