buffer.c 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. /*
  2. * buffer.c
  3. *
  4. * Oliver Fromme <oliver.fromme@heim3.tu-clausthal.de>
  5. * Mon Apr 14 03:53:18 MET DST 1997
  6. */
  7. #include <stdlib.h>
  8. #include <errno.h>
  9. #include "mpg123.h"
  10. int outburst = MAXOUTBURST;
  11. int preload;
  12. static int intflag = FALSE;
  13. static int usr1flag = FALSE;
  14. static void catch_interrupt (void)
  15. {
  16. intflag = TRUE;
  17. }
  18. static void catch_usr1 (void)
  19. {
  20. usr1flag = TRUE;
  21. }
  22. /* Interfaces to writer process */
  23. extern void buffer_sig(int signal, int block);
  24. void buffer_ignore_lowmem(void)
  25. {
  26. #ifndef NOXFERMEM
  27. if(buffermem->wakeme[XF_READER])
  28. xfermem_putcmd(buffermem->fd[XF_WRITER], XF_CMD_WAKEUP);
  29. #endif
  30. }
  31. void buffer_end(void)
  32. {
  33. #ifndef NOXFERMEM
  34. xfermem_putcmd(buffermem->fd[XF_WRITER], XF_CMD_TERMINATE);
  35. #endif
  36. }
  37. void buffer_resync(void)
  38. {
  39. buffer_sig(SIGINT, TRUE);
  40. }
  41. void buffer_reset(void)
  42. {
  43. buffer_sig(SIGUSR1, TRUE);
  44. }
  45. void buffer_start(void)
  46. {
  47. buffer_sig(SIGCONT, FALSE);
  48. }
  49. void buffer_stop(void)
  50. {
  51. buffer_sig(SIGSTOP, FALSE);
  52. }
  53. extern int buffer_pid;
  54. void buffer_sig(int signal, int block)
  55. {
  56. #ifndef NOXFERMEM
  57. kill(buffer_pid, signal);
  58. if (!buffermem || !block)
  59. return;
  60. if(xfermem_block(XF_WRITER, buffermem) != XF_CMD_WAKEUP)
  61. perror("Could not resync/reset buffers");
  62. #endif
  63. return;
  64. }
  65. #ifndef NOXFERMEM
  66. void buffer_loop(struct audio_info_struct *ai, sigset_t *oldsigset)
  67. {
  68. int bytes;
  69. int my_fd = buffermem->fd[XF_READER];
  70. txfermem *xf = buffermem;
  71. int done = FALSE;
  72. catchsignal (SIGINT, catch_interrupt);
  73. catchsignal (SIGUSR1, catch_usr1);
  74. sigprocmask (SIG_SETMASK, oldsigset, NULL);
  75. if (param.outmode == DECODE_AUDIO) {
  76. if (audio_open(ai) < 0) {
  77. perror("audio");
  78. exit(1);
  79. }
  80. }
  81. for (;;) {
  82. if (intflag) {
  83. intflag = FALSE;
  84. if (param.outmode == DECODE_AUDIO)
  85. audio_queueflush (ai);
  86. xf->readindex = xf->freeindex;
  87. if (xf->wakeme[XF_WRITER])
  88. xfermem_putcmd(my_fd, XF_CMD_WAKEUP);
  89. }
  90. if (usr1flag) {
  91. usr1flag = FALSE;
  92. /* close and re-open in order to flush
  93. * the device's internal buffer before
  94. * changing the sample rate. [OF]
  95. */
  96. /* writer must block when sending SIGUSR1
  97. * or we will lose all data processed
  98. * in the meantime! [dk]
  99. */
  100. xf->readindex = xf->freeindex;
  101. /* We've nailed down the new starting location -
  102. * writer is now safe to go on. [dk]
  103. */
  104. if (xf->wakeme[XF_WRITER])
  105. xfermem_putcmd(my_fd, XF_CMD_WAKEUP);
  106. if (param.outmode == DECODE_AUDIO) {
  107. audio_close (ai);
  108. ai->rate = xf->buf[0];
  109. ai->channels = xf->buf[1];
  110. ai->format = xf->buf[2];
  111. if (audio_open(ai) < 0) {
  112. perror("audio");
  113. exit(1);
  114. }
  115. }
  116. }
  117. if ( (bytes = xfermem_get_usedspace(xf)) < outburst ) {
  118. /* if we got a buffer underrun we first
  119. * fill 1/8 of the buffer before continue/start
  120. * playing */
  121. preload = xf->size>>3;
  122. if(preload < outburst)
  123. preload = outburst;
  124. }
  125. if(bytes < preload) {
  126. int cmd;
  127. if (done && !bytes) {
  128. break;
  129. }
  130. if(!done) {
  131. cmd = xfermem_block(XF_READER, xf);
  132. switch(cmd) {
  133. /* More input pending. */
  134. case XF_CMD_WAKEUP_INFO:
  135. continue;
  136. /* Yes, we know buffer is low but
  137. * know we don't care.
  138. */
  139. case XF_CMD_WAKEUP:
  140. break; /* Proceed playing. */
  141. case XF_CMD_TERMINATE:
  142. /* Proceed playing without
  143. * blocking any further.
  144. */
  145. done=TRUE;
  146. break;
  147. case -1:
  148. if(errno==EINTR)
  149. continue;
  150. perror("Yuck! Error in buffer handling...");
  151. done = TRUE;
  152. xf->readindex = xf->freeindex;
  153. xfermem_putcmd(xf->fd[XF_READER], XF_CMD_TERMINATE);
  154. break;
  155. default:
  156. fprintf(stderr, "\nEh!? Received unknown command 0x%x in buffer process. Tell Daniel!\n", cmd);
  157. }
  158. }
  159. }
  160. preload = outburst; /* set preload to lower mark */
  161. if (bytes > xf->size - xf->readindex)
  162. bytes = xf->size - xf->readindex;
  163. if (bytes > outburst)
  164. bytes = outburst;
  165. if (param.outmode == DECODE_FILE)
  166. bytes = write(OutputDescriptor, xf->data + xf->readindex, bytes);
  167. else if (param.outmode == DECODE_AUDIO)
  168. bytes = audio_play_samples(ai,
  169. (unsigned char *) (xf->data + xf->readindex), bytes);
  170. if(bytes < 0) {
  171. bytes = 0;
  172. if(errno != EINTR) {
  173. perror("Ouch ... error while writing audio data: ");
  174. /*
  175. * done==TRUE tells writer process to stop
  176. * sending data. There might be some latency
  177. * involved when resetting readindex to
  178. * freeindex so we might need more than one
  179. * cycle to terminate. (The number of cycles
  180. * should be finite unless I managed to mess
  181. * up something. ;-) [dk]
  182. */
  183. done = TRUE;
  184. xf->readindex = xf->freeindex;
  185. xfermem_putcmd(xf->fd[XF_READER], XF_CMD_TERMINATE);
  186. }
  187. }
  188. xf->readindex = (xf->readindex + bytes) % xf->size;
  189. if (xf->wakeme[XF_WRITER])
  190. xfermem_putcmd(my_fd, XF_CMD_WAKEUP);
  191. }
  192. if (param.outmode == DECODE_AUDIO)
  193. audio_close (ai);
  194. }
  195. #endif
  196. /* EOF */