14e5 /* * ximp3 A simple mp3 player * * Copyright (C) 2001 Mats Peterson * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; see the file COPYING. If not, write to * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. * * Please send any comments/bug reports to * mats_peterson@swipnet.se (Mats Peterson) */ /* * Audio output thread */ #include #include #include #include #include #include #include #include #include #include "xingmp3.h" #include "ximp3.h" #include "init.h" #include "audio.h" #include "info.h" static void err_exit(void) { exit(1); } static void out_stats(int frames, int in_bytes, int out_bytes) { double sec; int unplayed; if (ioctl(v->audio_fd, SNDCTL_DSP_GETODELAY, &unplayed) == -1) { perror("SNDCTL_DSP_GETODELAY"); err_exit(); } sec = (double)(out_bytes - unplayed) / (double)v->bytes_sec; if (v->remote) printf("@F %d %.2f\n", frames, sec); else { printf("\r Frames %6d Time %02d:%02d.%02d " "Bytes In %6d Bytes Out %6d", frames, (int)(sec / 60), (int)sec % 60, (int)(sec * 100) % 100, in_bytes, out_bytes - unplayed); fflush(stdout); } } static int read_buffer(void) { static char *p = NULL; static int toread = sizeof(PLAYBUF); fd_set readfds; struct timeval timeout; int n; if (v->n_playbufs == v->tot_playbufs) { if (! v->playing) v->playing = 1; return 0; } /* read a full buffer */ do { FD_ZERO(&readfds); FD_SET(v->pfds[0], &readfds); timeout.tv_sec = 0; timeout.tv_usec = 0; if (! (n = select(v->pfds[0] + 1, &readfds, NULL, NULL, &timeout))) return 0; if (n < 0) { perror("select"); err_exit(); } if (! p) p = (char *)&(v->playbufs[v->addbuf]); if ((n = read(v->pfds[0], p, toread)) < 0) { perror("pipe read"); err_exit(); } p += n; toread -= n; } while (toread); v->n_playbufs++; /* if last buffer, play remaining buffers now */ if (v->playbufs[v->addbuf].size == 0) { v->playing = 1; goto set_p; } v->addbuf = (v->addbuf == (v->tot_playbufs - 1)) ? 0 : v->addbuf + 1; set_p: p = (char *)&(v->playbufs[v->addbuf]); toread = sizeof(PLAYBUF); return 1; } static int play_buffer(void) { static char *p = NULL; static int towrite; fd_set writefds; struct timeval timeout; static int out_bytes = 0; audio_buf_info info; int n; if (! v->playing) return 1; /* last buffer */ if (v->playbufs[v->playbuf].size == 0) { if (v->verbose || v->remote) { int now_bytes = 0; while (1) { if (ioctl(v->audio_fd, SNDCTL_DSP_GETOSPACE, &info) == -1) { perror("SNDCTL_DSP_GETOSPACE"); err_exit(); } if ((info.bytes - now_bytes) >= PCM_BUFBYTES) { now_bytes = info.bytes; out_stats(v->playbufs[v->playbuf].frames, v->playbufs[v->playbuf].in_bytes, out_bytes); } /* Break if audio buffer empty */ if (info.bytes == v->audio_bufsize) { out_stats(v->playbufs[v->playbuf].frames, v->playbufs[v->playbuf].in_bytes, out_bytes); break; } usleep(1000); } } close(v->audio_fd); if (v->verbose && (! v->remote)) printf("\n"); v->n_playbufs = 0; v->playing = 0; out_bytes = 0; p = NULL; return 0; } /* write a full buffer */ do { FD_ZERO(&writefds); FD_SET(v->audio_fd, &writefds); timeout.tv_sec = 0; timeout.tv_usec = 0; if (! (n = select(v->audio_fd + 1, NULL, &writefds, NULL, &timeout))) return 1; if (n < 0) { perror("select"); err_exit(); } if (! p) { p = v->playbufs[v->playbuf].pcm; towrite = v->playbufs[v->playbuf].size; } if ((n = write(v->audio_fd, p, towrite)) < 0) { fprintf(stderr, "DSP write error"); err_exit(); } p += n; towrite -= n; } while (towrite); out_bytes += v->playbufs[v->playbuf].size; if (v->verbose || v->remote) { out_stats(v->playbufs[v->playbuf].frames, v->playbufs[v->playbuf].in_bytes, out_bytes); } v->playbuf = (v->playbuf == (v->tot_playbufs - 1)) ? 0 : v->playbuf + 1; v->n_playbufs--; if (! v->n_playbufs) { v->playing = 0; goto null_p; } p = v->playbufs[v->playbuf].pcm; towrite = v->playbufs[v->playbuf].size; return 1; null_p: p = NULL; return 1; } void * audio_thread(void *arg) { while (1) { while (read_buffer()); if (! play_buffer()) return NULL; usleep(1000); } } . 0