From: rjk@greenend.org.uk <> Date: Fri, 5 Oct 2007 14:32:01 +0000 (+0100) Subject: OSS backend for playrtp X-Git-Tag: debian-1_5_99dev8~134 X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~mdw/git/disorder/commitdiff_plain/cfa7dda12a65898b5eab2ed504fd765fef5c7527 OSS backend for playrtp --- diff --git a/clients/Makefile.am b/clients/Makefile.am index c1b578c..b49961e 100644 --- a/clients/Makefile.am +++ b/clients/Makefile.am @@ -35,7 +35,7 @@ disorderfm_LDADD=$(LIBOBJS) ../lib/libdisorder.a $(LIBGC) $(LIBICONV) disorderfm_DEPENDENCIES=$(LIBOBJS) ../lib/libdisorder.a disorder_playrtp_SOURCES=playrtp.c playrtp.h playrtp-mem.c \ - playrtp-alsa.c playrtp-coreaudio.c + playrtp-alsa.c playrtp-coreaudio.c playrtp-oss.c disorder_playrtp_LDADD=$(LIBOBJS) ../lib/libdisorder.a \ $(LIBASOUND) $(COREAUDIO) disorder_playrtp_DEPENDENCIES=$(LIBOBJS) ../lib/libdisorder.a diff --git a/clients/playrtp-oss.c b/clients/playrtp-oss.c new file mode 100644 index 0000000..a59e749 --- /dev/null +++ b/clients/playrtp-oss.c @@ -0,0 +1,193 @@ +/* + * This file is part of DisOrder. + * Copyright (C) 2007 Richard Kettlewell + * + * 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; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ +/** @file clients/playrtp-oss.c + * @brief RTP player - OSS support + */ + +#include + +#if HAVE_SYS_SOUNDCARD_H +#include "types.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mem.h" +#include "log.h" +#include "vector.h" +#include "heap.h" +#include "syscalls.h" +#include "playrtp.h" + +/** @brief /dev/dsp (or whatever) */ +static int playrtp_oss_fd = -1; + +/** @brief Open and configure the OSS audio device */ +static void playrtp_oss_enable(void) { + if(playrtp_oss_fd == -1) { + int rate = 44100, stereo = 1, format = AFMT_S16_BE; + if(!device) { + if(access("/dev/dsp", W_OK) == 0) + device = "/dev/dsp"; + else if(access("/dev/audio", W_OK) == 0) + device = "/dev/audio"; + else + fatal(0, "cannot determine default audio device"); + } + if((playrtp_oss_fd = open(device, O_WRONLY)) < 0) + fatal(errno, "error opening %s", device); + if(ioctl(playrtp_oss_fd, SNDCTL_DSP_SETFMT, &format) < 0) + fatal(errno, "ioctl SNDCTL_DSP_SETFMT"); + if(ioctl(playrtp_oss_fd, SNDCTL_DSP_STEREO, &stereo) < 0) + fatal(errno, "ioctl SNDCTL_DSP_STEREO"); + if(ioctl(playrtp_oss_fd, SNDCTL_DSP_SPEED, &rate) < 0) + fatal(errno, "ioctl SNDCTL_DSP_SPEED"); + if(rate != 44100) + error(0, "asking for 44100Hz, got %dHz", rate); + nonblock(playrtp_oss_fd); + } +} + +/** @brief Wait until the audio device can accept more data */ +static void playrtp_oss_wait(void) { + struct pollfd fds[1]; + int n; + + do { + fds[0].fd = playrtp_oss_fd; + fds[0].events = POLLOUT; + while((n = poll(fds, 1, -1)) < 0 && errno == EINTR) + ; + if(n < 0) + fatal(errno, "calling poll"); + } while(!(fds[0].revents & (POLLOUT|POLLERR))); +} + +/** @brief Close the OSS output device + * @param hard If nonzero, drop pending data + */ +static void playrtp_oss_disable(int hard) { + if(hard) + if(ioctl(playrtp_oss_fd, SNDCTL_DSP_RESET, 0) < 0) + error(errno, "ioctl SNDCTL_DSP_RESET"); + xclose(playrtp_oss_fd); + playrtp_oss_fd = -1; +} + +/** @brief Write samples to OSS output device + * @param data Pointer to sample data + * @param nsamples Number of samples + * @return 0 on success, non-0 on error + */ +static int playrtp_oss_write(const void *data, size_t samples) { + const ssize_t nbyteswritten = write(playrtp_oss_fd, data, + samples * sizeof (int16_t)); + + if(nbyteswritten < 0) { + switch(errno) { + case EAGAIN: + case EINTR: + return 0; + default: + error(errno, "error writing to %s", device); + return -1; + } + } else { + next_timestamp += nbyteswritten / 2; + return 0; + } +} + +/** @brief Play some data from packet @p p + * + * @p p is assumed to contain @ref next_timestamp. + */ +static int playrtp_oss_play(const struct packet *p) { + return playrtp_oss_write(p->samples_raw + next_timestamp - p->timestamp, + (p->timestamp + p->nsamples) - next_timestamp); +} + +/** @brief Play some silence before packet @p p + * + * @p p is assumed to be entirely before @ref next_timestamp. + */ +static int playrtp_oss_infill(const struct packet *p) { + static const uint16_t zeros[INFILL_SAMPLES]; + size_t samples_available = INFILL_SAMPLES; + + if(p && samples_available > p->timestamp - next_timestamp) + samples_available = p->timestamp - next_timestamp; + return playrtp_oss_write(zeros, samples_available); +} + +/** @brief OSS backend for playrtp */ +void playrtp_oss(void) { + int escape; + const struct packet *p; + + pthread_mutex_lock(&lock); + for(;;) { + /* Wait for the buffer to fill up a bit */ + playrtp_fill_buffer(); + playrtp_oss_enable(); + escape = 0; + info("Playing..."); + /* Keep playing until the buffer empties out, we get an error */ + while((nsamples >= minbuffer + || (nsamples > 0 + && contains(pheap_first(&packets), next_timestamp))) + && !escape) { + /* Wait until we can play more */ + pthread_mutex_unlock(&lock); + playrtp_oss_wait(); + pthread_mutex_lock(&lock); + /* Device is ready for more data, find something to play */ + p = playrtp_next_packet(); + /* Play it or play some silence */ + if(contains(p, next_timestamp)) + escape = playrtp_oss_play(p); + else + escape = playrtp_oss_infill(p); + } + active = 0; + /* We stop playing for a bit until the buffer re-fills */ + pthread_mutex_unlock(&lock); + playrtp_oss_disable(escape); + pthread_mutex_lock(&lock); + } +} + +#endif + +/* +Local Variables: +c-basic-offset:2 +comment-column:40 +fill-column:79 +indent-tabs-mode:nil +End: +*/ diff --git a/clients/playrtp.c b/clients/playrtp.c index b9f1529..2a4dc86 100644 --- a/clients/playrtp.c +++ b/clients/playrtp.c @@ -469,13 +469,11 @@ int main(int argc, char **argv) { #if HAVE_ALSA_ASOUNDLIB_H case 'a': backend = playrtp_alsa; break; #endif -#if 0 #if HAVE_SYS_SOUNDCARD_H case 'o': backend = playrtp_oss; break; #endif #if HAVE_COREAUDIO_AUDIOHARDWARE_H case 'c': backend = playrtp_coreaudio; break; -#endif #endif default: fatal(0, "invalid option"); }