• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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., 51 Franklin St, Fifth Floor,
20  * Boston, MA 02110-1301, 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 
31 #ifdef HAVE_OSS_INCLUDE_IN_SYS
32 # include <sys/soundcard.h>
33 #else
34 # ifdef HAVE_OSS_INCLUDE_IN_ROOT
35 #  include <soundcard.h>
36 # else
37 #  ifdef HAVE_OSS_INCLUDE_IN_MACHINE
38 #   include <machine/soundcard.h>
39 #  else
40 #   error "What to include?"
41 #  endif /* HAVE_OSS_INCLUDE_IN_MACHINE */
42 # endif /* HAVE_OSS_INCLUDE_IN_ROOT */
43 #endif /* HAVE_OSS_INCLUDE_IN_SYS */
44 
45 #include <sys/time.h>
46 #include <sys/ioctl.h>
47 #include <pthread.h>
48 
49 #include "gstossdmabuffer.h"
50 
51 GST_DEBUG_CATEGORY_EXTERN (oss_debug);
52 #define GST_CAT_DEFAULT oss_debug
53 
54 static void gst_ossdmabuffer_class_init (GstOssDMABufferClass * klass);
55 static void gst_ossdmabuffer_init (GstOssDMABuffer * ossdmabuffer);
56 static void gst_ossdmabuffer_dispose (GObject * object);
57 static void gst_ossdmabuffer_finalize (GObject * object);
58 
59 static gboolean gst_ossdmabuffer_acquire (GstRingBuffer * buf,
60     GstRingBufferSpec * spec);
61 static gboolean gst_ossdmabuffer_release (GstRingBuffer * buf);
62 static gboolean gst_ossdmabuffer_play (GstRingBuffer * buf);
63 static gboolean gst_ossdmabuffer_stop (GstRingBuffer * buf);
64 
65 static GstRingBufferClass *parent_class = NULL;
66 
67 GType
gst_ossdmabuffer_get_type(void)68 gst_ossdmabuffer_get_type (void)
69 {
70   static GType ossdmabuffer_type = 0;
71 
72   if (!ossdmabuffer_type) {
73     static const GTypeInfo ossdmabuffer_info = {
74       sizeof (GstOssDMABufferClass),
75       NULL,
76       NULL,
77       (GClassInitFunc) gst_ossdmabuffer_class_init,
78       NULL,
79       NULL,
80       sizeof (GstOssDMABuffer),
81       0,
82       (GInstanceInitFunc) gst_ossdmabuffer_init,
83       NULL
84     };
85 
86     ossdmabuffer_type =
87         g_type_register_static (GST_TYPE_RINGBUFFER, "GstOssDMABuffer",
88         &ossdmabuffer_info, 0);
89   }
90   return ossdmabuffer_type;
91 }
92 
93 static void
gst_ossdmabuffer_class_init(GstOssDMABufferClass * klass)94 gst_ossdmabuffer_class_init (GstOssDMABufferClass * klass)
95 {
96   GObjectClass *gobject_class;
97   GstObjectClass *gstobject_class;
98   GstRingBufferClass *gstringbuffer_class;
99 
100   gobject_class = (GObjectClass *) klass;
101   gstobject_class = (GstObjectClass *) klass;
102   gstringbuffer_class = (GstRingBufferClass *) klass;
103 
104   parent_class = g_type_class_peek_parent (klass);
105 
106   gobject_class->dispose = gst_ossdmabuffer_dispose;
107   gobject_class->finalize = gst_ossdmabuffer_finalize;
108 
109   gstringbuffer_class->acquire = gst_ossdmabuffer_acquire;
110   gstringbuffer_class->release = gst_ossdmabuffer_release;
111   gstringbuffer_class->play = gst_ossdmabuffer_play;
112   gstringbuffer_class->stop = gst_ossdmabuffer_stop;
113 }
114 
115 static void
gst_ossdmabuffer_init(GstOssDMABuffer * ossdmabuffer)116 gst_ossdmabuffer_init (GstOssDMABuffer * ossdmabuffer)
117 {
118   ossdmabuffer->cond = g_cond_new ();
119   ossdmabuffer->element = g_object_new (GST_TYPE_OSSELEMENT, NULL);
120 }
121 
122 static void
gst_ossdmabuffer_dispose(GObject * object)123 gst_ossdmabuffer_dispose (GObject * object)
124 {
125   G_OBJECT_CLASS (parent_class)->dispose (object);
126 }
127 
128 static void
gst_ossdmabuffer_finalize(GObject * object)129 gst_ossdmabuffer_finalize (GObject * object)
130 {
131   GstOssDMABuffer *obuf = (GstOssDMABuffer *) object;
132 
133   g_cond_free (obuf->cond);
134 
135   G_OBJECT_CLASS (parent_class)->finalize (object);
136 }
137 
138 static void
gst_ossdmabuffer_func(GstRingBuffer * buf)139 gst_ossdmabuffer_func (GstRingBuffer * buf)
140 {
141   fd_set writeset;
142   struct count_info count;
143   GstOssDMABuffer *obuf = (GstOssDMABuffer *) buf;
144 
145   GST_OBJECT_LOCK (buf);
146   while (obuf->running) {
147     if (buf->state == GST_RINGBUFFER_STATE_PLAYING) {
148       int segsize;
149 
150       GST_OBJECT_UNLOCK (buf);
151 
152       segsize = buf->spec.segsize;
153 
154       FD_ZERO (&writeset);
155       FD_SET (obuf->fd, &writeset);
156 
157       select (obuf->fd + 1, NULL, &writeset, NULL, NULL);
158 
159       if (ioctl (obuf->fd, SNDCTL_DSP_GETOPTR, &count) == -1) {
160         perror ("GETOPTR");
161         continue;
162       }
163 
164       if (count.blocks > buf->spec.segtotal)
165         count.blocks = buf->spec.segtotal;
166 
167       gst_ringbuffer_callback (buf, count.blocks);
168 
169       GST_OBJECT_LOCK (buf);
170     } else {
171       GST_OSSDMABUFFER_SIGNAL (obuf);
172       GST_OSSDMABUFFER_WAIT (obuf);
173     }
174   }
175   GST_OBJECT_UNLOCK (buf);
176 }
177 
178 static gboolean
gst_ossdmabuffer_acquire(GstRingBuffer * buf,GstRingBufferSpec * spec)179 gst_ossdmabuffer_acquire (GstRingBuffer * buf, GstRingBufferSpec * spec)
180 {
181   int tmp;
182   struct audio_buf_info info;
183   GstOssDMABuffer *obuf = (GstOssDMABuffer *) buf;
184   caddr_t mmap_buf;
185   int mode;
186   gint size;
187   gboolean parsed;
188 
189   parsed = gst_osselement_parse_caps (obuf->element, spec->caps);
190   if (!parsed)
191     return FALSE;
192 
193   mode = O_RDWR;
194   mode |= O_NONBLOCK;
195 
196   obuf->fd = open ("/dev/dsp", mode, 0);
197   if (obuf->fd == -1) {
198     perror ("OPEN");
199     return FALSE;
200   }
201   //obuf->frag = 0x00040008;
202   obuf->frag = 0xffff000a;
203 
204   tmp = obuf->element->format;
205   if (ioctl (obuf->fd, SNDCTL_DSP_SETFMT, &tmp) == -1) {
206     perror ("SETFMT");
207     return FALSE;
208   }
209 
210   tmp = obuf->element->channels;
211   if (ioctl (obuf->fd, SNDCTL_DSP_STEREO, &tmp) == -1) {
212     perror ("STEREO");
213     return FALSE;
214   }
215 
216   tmp = obuf->element->channels;
217   if (ioctl (obuf->fd, SNDCTL_DSP_CHANNELS, &tmp) == -1) {
218     perror ("CHANNELS");
219     return FALSE;
220   }
221 
222   tmp = obuf->element->rate;
223   if (ioctl (obuf->fd, SNDCTL_DSP_SPEED, &tmp) == -1) {
224     perror ("SPEED");
225     return FALSE;
226   }
227 
228   if (ioctl (obuf->fd, SNDCTL_DSP_GETCAPS, &obuf->caps) == -1) {
229     perror ("/dev/dsp");
230     fprintf (stderr, "Sorry but your sound driver is too old\n");
231     return FALSE;
232   }
233 
234   if (!(obuf->caps & DSP_CAP_TRIGGER) || !(obuf->caps & DSP_CAP_MMAP)) {
235     fprintf (stderr, "Sorry but your soundcard can't do this\n");
236     return FALSE;
237   }
238 
239   if (ioctl (obuf->fd, SNDCTL_DSP_SETFRAGMENT, &obuf->frag) == -1) {
240     perror ("SETFRAGMENT");
241     return FALSE;
242   }
243 
244   if (ioctl (obuf->fd, SNDCTL_DSP_GETOSPACE, &info) == -1) {
245     perror ("GETOSPACE");
246     return FALSE;
247   }
248 
249   buf->spec.segsize = info.fragsize;
250   buf->spec.segtotal = info.fragstotal;
251   size = info.fragsize * info.fragstotal;
252   g_print ("segsize %d, segtotal %d\n", info.fragsize, info.fragstotal);
253 
254   mmap_buf = (caddr_t) mmap (NULL, size, PROT_WRITE,
255       MAP_FILE | MAP_SHARED, obuf->fd, 0);
256 
257   if ((caddr_t) mmap_buf == (caddr_t) - 1) {
258     perror ("mmap (write)");
259     return FALSE;
260   }
261 
262   buf->data = gst_buffer_new ();
263   GST_BUFFER_DATA (buf->data) = mmap_buf;
264   GST_BUFFER_SIZE (buf->data) = size;
265   GST_BUFFER_FLAG_SET (buf->data, GST_BUFFER_DONTFREE);
266 
267   tmp = 0;
268   if (ioctl (obuf->fd, SNDCTL_DSP_SETTRIGGER, &tmp) == -1) {
269     perror ("SETTRIGGER");
270     return FALSE;
271   }
272 
273   GST_OBJECT_LOCK (obuf);
274   obuf->running = TRUE;
275   obuf->thread = g_thread_create ((GThreadFunc) gst_ossdmabuffer_func,
276       buf, TRUE, NULL);
277   GST_OSSDMABUFFER_WAIT (obuf);
278   GST_OBJECT_UNLOCK (obuf);
279 
280   return TRUE;
281 }
282 
283 static gboolean
gst_ossdmabuffer_release(GstRingBuffer * buf)284 gst_ossdmabuffer_release (GstRingBuffer * buf)
285 {
286   GstOssDMABuffer *obuf = (GstOssDMABuffer *) buf;
287 
288   gst_buffer_unref (buf->data);
289 
290   GST_OBJECT_LOCK (obuf);
291   obuf->running = FALSE;
292   GST_OSSDMABUFFER_SIGNAL (obuf);
293   GST_OBJECT_UNLOCK (obuf);
294 
295   g_thread_join (obuf->thread);
296 
297   return TRUE;
298 }
299 
300 static gboolean
gst_ossdmabuffer_play(GstRingBuffer * buf)301 gst_ossdmabuffer_play (GstRingBuffer * buf)
302 {
303   int tmp;
304   GstOssDMABuffer *obuf;
305 
306   obuf = (GstOssDMABuffer *) buf;
307 
308   tmp = PCM_ENABLE_OUTPUT;
309   if (ioctl (obuf->fd, SNDCTL_DSP_SETTRIGGER, &tmp) == -1) {
310     perror ("SETTRIGGER");
311   }
312   GST_OSSDMABUFFER_SIGNAL (obuf);
313 
314   return TRUE;
315 }
316 
317 static gboolean
gst_ossdmabuffer_stop(GstRingBuffer * buf)318 gst_ossdmabuffer_stop (GstRingBuffer * buf)
319 {
320   int tmp;
321   GstOssDMABuffer *obuf;
322 
323   obuf = (GstOssDMABuffer *) buf;
324 
325   tmp = 0;
326   if (ioctl (obuf->fd, SNDCTL_DSP_SETTRIGGER, &tmp) == -1) {
327     perror ("SETTRIGGER");
328   }
329   GST_OSSDMABUFFER_WAIT (obuf);
330   buf->playseg = 0;
331 
332   return TRUE;
333 }
334