*.*: Ran scripts/update-macros. Oh yes.
[platform/upstream/gst-plugins-good.git] / sys / oss / gstossdmabuffer.c
1 /* GStreamer
2  * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
3  *                    2005 Wim Taymans <wim@fluendo.com>
4  *
5  * gstossdmabuffer.c: 
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public
18  * License along with this library; if not, write to the
19  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20  * Boston, MA 02111-1307, USA.
21  */
22
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <unistd.h>
26 #include <fcntl.h>
27 #include <string.h>
28 #include <sys/types.h>
29 #include <sys/mman.h>
30 #include <sys/soundcard.h>
31 #include <sys/time.h>
32 #include <sys/ioctl.h>
33 #include <pthread.h>
34
35 #include "gstossdmabuffer.h"
36
37 GST_DEBUG_CATEGORY_EXTERN (oss_debug);
38 #define GST_CAT_DEFAULT oss_debug
39
40 static void gst_ossdmabuffer_class_init (GstOssDMABufferClass * klass);
41 static void gst_ossdmabuffer_init (GstOssDMABuffer * ossdmabuffer);
42 static void gst_ossdmabuffer_dispose (GObject * object);
43 static void gst_ossdmabuffer_finalize (GObject * object);
44
45 static gboolean gst_ossdmabuffer_acquire (GstRingBuffer * buf,
46     GstRingBufferSpec * spec);
47 static gboolean gst_ossdmabuffer_release (GstRingBuffer * buf);
48 static gboolean gst_ossdmabuffer_play (GstRingBuffer * buf);
49 static gboolean gst_ossdmabuffer_stop (GstRingBuffer * buf);
50
51 static GstRingBufferClass *parent_class = NULL;
52
53 GType
54 gst_ossdmabuffer_get_type (void)
55 {
56   static GType ossdmabuffer_type = 0;
57
58   if (!ossdmabuffer_type) {
59     static const GTypeInfo ossdmabuffer_info = {
60       sizeof (GstOssDMABufferClass),
61       NULL,
62       NULL,
63       (GClassInitFunc) gst_ossdmabuffer_class_init,
64       NULL,
65       NULL,
66       sizeof (GstOssDMABuffer),
67       0,
68       (GInstanceInitFunc) gst_ossdmabuffer_init,
69       NULL
70     };
71
72     ossdmabuffer_type =
73         g_type_register_static (GST_TYPE_RINGBUFFER, "GstOssDMABuffer",
74         &ossdmabuffer_info, 0);
75   }
76   return ossdmabuffer_type;
77 }
78
79 static void
80 gst_ossdmabuffer_class_init (GstOssDMABufferClass * klass)
81 {
82   GObjectClass *gobject_class;
83   GstObjectClass *gstobject_class;
84   GstRingBufferClass *gstringbuffer_class;
85
86   gobject_class = (GObjectClass *) klass;
87   gstobject_class = (GstObjectClass *) klass;
88   gstringbuffer_class = (GstRingBufferClass *) klass;
89
90   parent_class = g_type_class_ref (GST_TYPE_RINGBUFFER);
91
92   gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_ossdmabuffer_dispose);
93   gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_ossdmabuffer_finalize);
94
95   gstringbuffer_class->acquire = gst_ossdmabuffer_acquire;
96   gstringbuffer_class->release = gst_ossdmabuffer_release;
97   gstringbuffer_class->play = gst_ossdmabuffer_play;
98   gstringbuffer_class->stop = gst_ossdmabuffer_stop;
99 }
100
101 static void
102 gst_ossdmabuffer_init (GstOssDMABuffer * ossdmabuffer)
103 {
104   ossdmabuffer->cond = g_cond_new ();
105   ossdmabuffer->element = g_object_new (GST_TYPE_OSSELEMENT, NULL);
106 }
107
108 static void
109 gst_ossdmabuffer_dispose (GObject * object)
110 {
111   G_OBJECT_CLASS (parent_class)->dispose (object);
112 }
113
114 static void
115 gst_ossdmabuffer_finalize (GObject * object)
116 {
117   GstOssDMABuffer *obuf = (GstOssDMABuffer *) object;
118
119   g_cond_free (obuf->cond);
120
121   G_OBJECT_CLASS (parent_class)->finalize (object);
122 }
123
124 static void
125 gst_ossdmabuffer_func (GstRingBuffer * buf)
126 {
127   fd_set writeset;
128   struct count_info count;
129   GstOssDMABuffer *obuf = (GstOssDMABuffer *) buf;
130
131   GST_OBJECT_LOCK (buf);
132   while (obuf->running) {
133     if (buf->state == GST_RINGBUFFER_STATE_PLAYING) {
134       int segsize;
135
136       GST_OBJECT_UNLOCK (buf);
137
138       segsize = buf->spec.segsize;
139
140       FD_ZERO (&writeset);
141       FD_SET (obuf->fd, &writeset);
142
143       select (obuf->fd + 1, NULL, &writeset, NULL, NULL);
144
145       if (ioctl (obuf->fd, SNDCTL_DSP_GETOPTR, &count) == -1) {
146         perror ("GETOPTR");
147         continue;
148       }
149
150       if (count.blocks > buf->spec.segtotal)
151         count.blocks = buf->spec.segtotal;
152
153       gst_ringbuffer_callback (buf, count.blocks);
154
155       GST_OBJECT_LOCK (buf);
156     } else {
157       GST_OSSDMABUFFER_SIGNAL (obuf);
158       GST_OSSDMABUFFER_WAIT (obuf);
159     }
160   }
161   GST_OBJECT_UNLOCK (buf);
162 }
163
164 static gboolean
165 gst_ossdmabuffer_acquire (GstRingBuffer * buf, GstRingBufferSpec * spec)
166 {
167   int tmp;
168   struct audio_buf_info info;
169   GstOssDMABuffer *obuf = (GstOssDMABuffer *) buf;;
170   caddr_t mmap_buf;
171   int mode;
172   gint size;
173   gboolean parsed;
174
175   parsed = gst_osselement_parse_caps (obuf->element, spec->caps);
176   if (!parsed)
177     return FALSE;
178
179   mode = O_RDWR;
180   mode |= O_NONBLOCK;
181
182   obuf->fd = open ("/dev/dsp", mode, 0);
183   if (obuf->fd == -1) {
184     perror ("OPEN");
185     return FALSE;
186   }
187   //obuf->frag = 0x00040008;
188   obuf->frag = 0xffff000a;
189
190   tmp = obuf->element->format;
191   if (ioctl (obuf->fd, SNDCTL_DSP_SETFMT, &tmp) == -1) {
192     perror ("SETFMT");
193     return FALSE;
194   }
195
196   tmp = obuf->element->channels;
197   if (ioctl (obuf->fd, SNDCTL_DSP_STEREO, &tmp) == -1) {
198     perror ("STEREO");
199     return FALSE;
200   }
201
202   tmp = obuf->element->channels;
203   if (ioctl (obuf->fd, SNDCTL_DSP_CHANNELS, &tmp) == -1) {
204     perror ("CHANNELS");
205     return FALSE;
206   }
207
208   tmp = obuf->element->rate;
209   if (ioctl (obuf->fd, SNDCTL_DSP_SPEED, &tmp) == -1) {
210     perror ("SPEED");
211     return FALSE;
212   }
213
214   if (ioctl (obuf->fd, SNDCTL_DSP_GETCAPS, &obuf->caps) == -1) {
215     perror ("/dev/dsp");
216     fprintf (stderr, "Sorry but your sound driver is too old\n");
217     return FALSE;
218   }
219
220   if (!(obuf->caps & DSP_CAP_TRIGGER) || !(obuf->caps & DSP_CAP_MMAP)) {
221     fprintf (stderr, "Sorry but your soundcard can't do this\n");
222     return FALSE;
223   }
224
225   if (ioctl (obuf->fd, SNDCTL_DSP_SETFRAGMENT, &obuf->frag) == -1) {
226     perror ("SETFRAGMENT");
227     return FALSE;
228   }
229
230   if (ioctl (obuf->fd, SNDCTL_DSP_GETOSPACE, &info) == -1) {
231     perror ("GETOSPACE");
232     return FALSE;
233   }
234
235   buf->spec.segsize = info.fragsize;
236   buf->spec.segtotal = info.fragstotal;
237   size = info.fragsize * info.fragstotal;
238   g_print ("segsize %d, segtotal %d\n", info.fragsize, info.fragstotal);
239
240   mmap_buf = (caddr_t) mmap (NULL, size, PROT_WRITE,
241       MAP_FILE | MAP_SHARED, obuf->fd, 0);
242
243   if ((caddr_t) mmap_buf == (caddr_t) - 1) {
244     perror ("mmap (write)");
245     return FALSE;
246   }
247
248   buf->data = gst_buffer_new ();
249   GST_BUFFER_DATA (buf->data) = mmap_buf;
250   GST_BUFFER_SIZE (buf->data) = size;
251   GST_BUFFER_FLAG_SET (buf->data, GST_BUFFER_DONTFREE);
252
253   tmp = 0;
254   if (ioctl (obuf->fd, SNDCTL_DSP_SETTRIGGER, &tmp) == -1) {
255     perror ("SETTRIGGER");
256     return FALSE;
257   }
258
259   GST_OBJECT_LOCK (obuf);
260   obuf->running = TRUE;
261   obuf->thread = g_thread_create ((GThreadFunc) gst_ossdmabuffer_func,
262       buf, TRUE, NULL);
263   GST_OSSDMABUFFER_WAIT (obuf);
264   GST_OBJECT_UNLOCK (obuf);
265
266   return TRUE;
267 }
268
269 static gboolean
270 gst_ossdmabuffer_release (GstRingBuffer * buf)
271 {
272   GstOssDMABuffer *obuf = (GstOssDMABuffer *) buf;;
273
274   gst_buffer_unref (buf->data);
275
276   GST_OBJECT_LOCK (obuf);
277   obuf->running = FALSE;
278   GST_OSSDMABUFFER_SIGNAL (obuf);
279   GST_OBJECT_UNLOCK (obuf);
280
281   g_thread_join (obuf->thread);
282
283   return TRUE;
284 }
285
286 static gboolean
287 gst_ossdmabuffer_play (GstRingBuffer * buf)
288 {
289   int tmp;
290   GstOssDMABuffer *obuf;
291
292   obuf = (GstOssDMABuffer *) buf;
293
294   tmp = PCM_ENABLE_OUTPUT;
295   if (ioctl (obuf->fd, SNDCTL_DSP_SETTRIGGER, &tmp) == -1) {
296     perror ("SETTRIGGER");
297   }
298   GST_OSSDMABUFFER_SIGNAL (obuf);
299
300   return TRUE;
301 }
302
303 static gboolean
304 gst_ossdmabuffer_stop (GstRingBuffer * buf)
305 {
306   int tmp;
307   GstOssDMABuffer *obuf;
308
309   obuf = (GstOssDMABuffer *) buf;
310
311   tmp = 0;
312   if (ioctl (obuf->fd, SNDCTL_DSP_SETTRIGGER, &tmp) == -1) {
313     perror ("SETTRIGGER");
314   }
315   GST_OSSDMABUFFER_WAIT (obuf);
316   buf->playseg = 0;
317
318   return TRUE;
319 }