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