diff options
author | Andy Wingo <wingo@pobox.com> | 2005-07-08 11:19:19 +0000 |
---|---|---|
committer | Andy Wingo <wingo@pobox.com> | 2005-07-08 11:19:19 +0000 |
commit | 6fc2023e8fec8c86ba1008edfd68e8998729318b (patch) | |
tree | 83d01640f8ff7789ac5894c16cb5245b3bd57c8b /sys/oss/gstossdmabuffer.c | |
parent | 266b874436d0b23d96d07bc09ad52e363c275b58 (diff) |
sys/oss/: Port from THREADED+wim's fixes.
Original commit message from CVS:
2005-07-08 Andy Wingo <wingo@pobox.com>
* sys/oss/: Port from THREADED+wim's fixes.
Diffstat (limited to 'sys/oss/gstossdmabuffer.c')
-rw-r--r-- | sys/oss/gstossdmabuffer.c | 316 |
1 files changed, 316 insertions, 0 deletions
diff --git a/sys/oss/gstossdmabuffer.c b/sys/oss/gstossdmabuffer.c new file mode 100644 index 00000000..47e06d12 --- /dev/null +++ b/sys/oss/gstossdmabuffer.c @@ -0,0 +1,316 @@ +/* GStreamer + * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu> + * 2005 Wim Taymans <wim@fluendo.com> + * + * gstossdmabuffer.c: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <fcntl.h> +#include <string.h> +#include <sys/types.h> +#include <sys/mman.h> +#include <sys/soundcard.h> +#include <sys/time.h> +#include <sys/ioctl.h> +#include <pthread.h> + +#include "gstossdmabuffer.h" + +static void gst_ossdmabuffer_class_init (GstOssDMABufferClass * klass); +static void gst_ossdmabuffer_init (GstOssDMABuffer * ossdmabuffer); +static void gst_ossdmabuffer_dispose (GObject * object); +static void gst_ossdmabuffer_finalize (GObject * object); + +static gboolean gst_ossdmabuffer_acquire (GstRingBuffer * buf, + GstRingBufferSpec * spec); +static gboolean gst_ossdmabuffer_release (GstRingBuffer * buf); +static gboolean gst_ossdmabuffer_play (GstRingBuffer * buf); +static gboolean gst_ossdmabuffer_stop (GstRingBuffer * buf); + +static GstRingBufferClass *parent_class = NULL; + +GType +gst_ossdmabuffer_get_type (void) +{ + static GType ossdmabuffer_type = 0; + + if (!ossdmabuffer_type) { + static const GTypeInfo ossdmabuffer_info = { + sizeof (GstOssDMABufferClass), + NULL, + NULL, + (GClassInitFunc) gst_ossdmabuffer_class_init, + NULL, + NULL, + sizeof (GstOssDMABuffer), + 0, + (GInstanceInitFunc) gst_ossdmabuffer_init, + NULL + }; + + ossdmabuffer_type = + g_type_register_static (GST_TYPE_RINGBUFFER, "GstOssDMABuffer", + &ossdmabuffer_info, 0); + } + return ossdmabuffer_type; +} + +static void +gst_ossdmabuffer_class_init (GstOssDMABufferClass * klass) +{ + GObjectClass *gobject_class; + GstObjectClass *gstobject_class; + GstRingBufferClass *gstringbuffer_class; + + gobject_class = (GObjectClass *) klass; + gstobject_class = (GstObjectClass *) klass; + gstringbuffer_class = (GstRingBufferClass *) klass; + + parent_class = g_type_class_ref (GST_TYPE_RINGBUFFER); + + gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_ossdmabuffer_dispose); + gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_ossdmabuffer_finalize); + + gstringbuffer_class->acquire = gst_ossdmabuffer_acquire; + gstringbuffer_class->release = gst_ossdmabuffer_release; + gstringbuffer_class->play = gst_ossdmabuffer_play; + gstringbuffer_class->stop = gst_ossdmabuffer_stop; +} + +static void +gst_ossdmabuffer_init (GstOssDMABuffer * ossdmabuffer) +{ + ossdmabuffer->cond = g_cond_new (); + ossdmabuffer->element = g_object_new (GST_TYPE_OSSELEMENT, NULL); +} + +static void +gst_ossdmabuffer_dispose (GObject * object) +{ + G_OBJECT_CLASS (parent_class)->dispose (object); +} + +static void +gst_ossdmabuffer_finalize (GObject * object) +{ + GstOssDMABuffer *obuf = (GstOssDMABuffer *) object; + + g_cond_free (obuf->cond); + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static void +gst_ossdmabuffer_func (GstRingBuffer * buf) +{ + fd_set writeset; + struct count_info count; + GstOssDMABuffer *obuf = (GstOssDMABuffer *) buf; + + GST_LOCK (buf); + while (obuf->running) { + if (buf->state == GST_RINGBUFFER_STATE_PLAYING) { + int segsize; + + GST_UNLOCK (buf); + + segsize = buf->spec.segsize; + + FD_ZERO (&writeset); + FD_SET (obuf->fd, &writeset); + + select (obuf->fd + 1, NULL, &writeset, NULL, NULL); + + if (ioctl (obuf->fd, SNDCTL_DSP_GETOPTR, &count) == -1) { + perror ("GETOPTR"); + continue; + } + + if (count.blocks > buf->spec.segtotal) + count.blocks = buf->spec.segtotal; + + gst_ringbuffer_callback (buf, count.blocks); + + GST_LOCK (buf); + } else { + GST_OSSDMABUFFER_SIGNAL (obuf); + GST_OSSDMABUFFER_WAIT (obuf); + } + } + GST_UNLOCK (buf); +} + +static gboolean +gst_ossdmabuffer_acquire (GstRingBuffer * buf, GstRingBufferSpec * spec) +{ + int tmp; + struct audio_buf_info info; + GstOssDMABuffer *obuf = (GstOssDMABuffer *) buf;; + caddr_t mmap_buf; + int mode; + gint size; + gboolean parsed; + + parsed = gst_osselement_parse_caps (obuf->element, spec->caps); + if (!parsed) + return FALSE; + + mode = O_RDWR; + mode |= O_NONBLOCK; + + obuf->fd = open ("/dev/dsp", mode, 0); + if (obuf->fd == -1) { + perror ("OPEN"); + return FALSE; + } + //obuf->frag = 0x00040008; + obuf->frag = 0xffff000a; + + tmp = obuf->element->format; + if (ioctl (obuf->fd, SNDCTL_DSP_SETFMT, &tmp) == -1) { + perror ("SETFMT"); + return FALSE; + } + + tmp = obuf->element->channels; + if (ioctl (obuf->fd, SNDCTL_DSP_STEREO, &tmp) == -1) { + perror ("STEREO"); + return FALSE; + } + + tmp = obuf->element->channels; + if (ioctl (obuf->fd, SNDCTL_DSP_CHANNELS, &tmp) == -1) { + perror ("CHANNELS"); + return FALSE; + } + + tmp = obuf->element->rate; + if (ioctl (obuf->fd, SNDCTL_DSP_SPEED, &tmp) == -1) { + perror ("SPEED"); + return FALSE; + } + + if (ioctl (obuf->fd, SNDCTL_DSP_GETCAPS, &obuf->caps) == -1) { + perror ("/dev/dsp"); + fprintf (stderr, "Sorry but your sound driver is too old\n"); + return FALSE; + } + + if (!(obuf->caps & DSP_CAP_TRIGGER) || !(obuf->caps & DSP_CAP_MMAP)) { + fprintf (stderr, "Sorry but your soundcard can't do this\n"); + return FALSE; + } + + if (ioctl (obuf->fd, SNDCTL_DSP_SETFRAGMENT, &obuf->frag) == -1) { + perror ("SETFRAGMENT"); + return FALSE; + } + + if (ioctl (obuf->fd, SNDCTL_DSP_GETOSPACE, &info) == -1) { + perror ("GETOSPACE"); + return FALSE; + } + + buf->spec.segsize = info.fragsize; + buf->spec.segtotal = info.fragstotal; + size = info.fragsize * info.fragstotal; + g_print ("segsize %d, segtotal %d\n", info.fragsize, info.fragstotal); + + mmap_buf = (caddr_t) mmap (NULL, size, PROT_WRITE, + MAP_FILE | MAP_SHARED, obuf->fd, 0); + + if ((caddr_t) mmap_buf == (caddr_t) - 1) { + perror ("mmap (write)"); + return FALSE; + } + + buf->data = gst_buffer_new (); + GST_BUFFER_DATA (buf->data) = mmap_buf; + GST_BUFFER_SIZE (buf->data) = size; + GST_BUFFER_FLAG_SET (buf->data, GST_BUFFER_DONTFREE); + + tmp = 0; + if (ioctl (obuf->fd, SNDCTL_DSP_SETTRIGGER, &tmp) == -1) { + perror ("SETTRIGGER"); + return FALSE; + } + + GST_LOCK (obuf); + obuf->running = TRUE; + obuf->thread = g_thread_create ((GThreadFunc) gst_ossdmabuffer_func, + buf, TRUE, NULL); + GST_OSSDMABUFFER_WAIT (obuf); + GST_UNLOCK (obuf); + + return TRUE; +} + +static gboolean +gst_ossdmabuffer_release (GstRingBuffer * buf) +{ + GstOssDMABuffer *obuf = (GstOssDMABuffer *) buf;; + + gst_buffer_unref (buf->data); + + GST_LOCK (obuf); + obuf->running = FALSE; + GST_OSSDMABUFFER_SIGNAL (obuf); + GST_UNLOCK (obuf); + + g_thread_join (obuf->thread); + + return TRUE; +} + +static gboolean +gst_ossdmabuffer_play (GstRingBuffer * buf) +{ + int tmp; + GstOssDMABuffer *obuf; + + obuf = (GstOssDMABuffer *) buf; + + tmp = PCM_ENABLE_OUTPUT; + if (ioctl (obuf->fd, SNDCTL_DSP_SETTRIGGER, &tmp) == -1) { + perror ("SETTRIGGER"); + } + GST_OSSDMABUFFER_SIGNAL (obuf); + + return TRUE; +} + +static gboolean +gst_ossdmabuffer_stop (GstRingBuffer * buf) +{ + int tmp; + GstOssDMABuffer *obuf; + + obuf = (GstOssDMABuffer *) buf; + + tmp = 0; + if (ioctl (obuf->fd, SNDCTL_DSP_SETTRIGGER, &tmp) == -1) { + perror ("SETTRIGGER"); + } + GST_OSSDMABUFFER_WAIT (obuf); + buf->playseg = 0; + + return TRUE; +} |