1 /* GStreamer OSS4 audio plugin
2  * Copyright (C) 2007-2008 Tim-Philipp Müller <tim centricular net>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
17  * Boston, MA 02110-1301, USA.
18  */
19 
20 /* FIXME 0.11: suppress warnings for deprecated API such as GValueArray
21  * with newer GLib versions (>= 2.31.0) */
22 #define GLIB_DISABLE_DEPRECATION_WARNINGS
23 
24 #ifdef HAVE_CONFIG_H
25 #include "config.h"
26 #endif
27 
28 #include <sys/ioctl.h>
29 #include <sys/types.h>
30 #include <sys/stat.h>
31 #include <fcntl.h>
32 #include <unistd.h>
33 #include <string.h>
34 
35 #include "gst/gst-i18n-plugin.h"
36 #include <gst/audio/audio.h>
37 
38 #include "oss4-audio.h"
39 #include "oss4-property-probe.h"
40 #include "oss4-sink.h"
41 #include "oss4-source.h"
42 #include "oss4-soundcard.h"
43 
44 GST_DEBUG_CATEGORY (oss4mixer_debug);
45 GST_DEBUG_CATEGORY (oss4sink_debug);
46 GST_DEBUG_CATEGORY (oss4src_debug);
47 GST_DEBUG_CATEGORY (oss4_debug);
48 
49 #define GST_CAT_DEFAULT oss4_debug
50 
51 typedef struct
52 {
53   const GstAudioRingBufferFormatType gst_rbfmt;
54   const GstAudioFormat gst_rfmt;
55   const gint oss_fmt;
56   const gchar name[16];
57 } GstOss4AudioFormat;
58 
59 /* *INDENT-OFF* */
60 static const GstOss4AudioFormat fmt_map[] = {
61   /* note: keep sorted by preference, prefered formats first */
62   {
63   GST_AUDIO_RING_BUFFER_FORMAT_TYPE_MU_LAW, 0,
64       AFMT_MU_LAW, "audio/x-mulaw"}, {
65   GST_AUDIO_RING_BUFFER_FORMAT_TYPE_A_LAW, 0,
66       AFMT_A_LAW, "audio/x-alaw"}, {
67   GST_AUDIO_RING_BUFFER_FORMAT_TYPE_RAW, GST_AUDIO_FORMAT_S32LE,
68       AFMT_S32_LE, "audio/x-raw"}, {
69   GST_AUDIO_RING_BUFFER_FORMAT_TYPE_RAW, GST_AUDIO_FORMAT_S32BE,
70       AFMT_S32_BE, "audio/x-raw"}, {
71   GST_AUDIO_RING_BUFFER_FORMAT_TYPE_RAW, GST_AUDIO_FORMAT_S24_32LE,
72       AFMT_S24_LE, "audio/x-raw"}, {
73   GST_AUDIO_RING_BUFFER_FORMAT_TYPE_RAW, GST_AUDIO_FORMAT_S24_32BE,
74       AFMT_S24_BE, "audio/x-raw"}, {
75   GST_AUDIO_RING_BUFFER_FORMAT_TYPE_RAW, GST_AUDIO_FORMAT_S24LE,
76       AFMT_S24_PACKED, "audio/x-raw"}, {
77   GST_AUDIO_RING_BUFFER_FORMAT_TYPE_RAW, GST_AUDIO_FORMAT_S16LE,
78       AFMT_S16_LE, "audio/x-raw"}, {
79   GST_AUDIO_RING_BUFFER_FORMAT_TYPE_RAW, GST_AUDIO_FORMAT_S16BE,
80       AFMT_S16_BE, "audio/x-raw"}, {
81   GST_AUDIO_RING_BUFFER_FORMAT_TYPE_RAW, GST_AUDIO_FORMAT_U16LE,
82       AFMT_U16_LE, "audio/x-raw"}, {
83   GST_AUDIO_RING_BUFFER_FORMAT_TYPE_RAW, GST_AUDIO_FORMAT_U16BE,
84       AFMT_U16_BE, "audio/x-raw"}, {
85   GST_AUDIO_RING_BUFFER_FORMAT_TYPE_RAW, GST_AUDIO_FORMAT_S8,
86       AFMT_S8, "audio/x-raw"}, {
87   GST_AUDIO_RING_BUFFER_FORMAT_TYPE_RAW, GST_AUDIO_FORMAT_U8,
88       AFMT_U8, "audio/x-raw"}
89 };
90 /* *INDENT-ON* */
91 
92 /* formats we assume the OSS4 layer can always handle and convert internally */
93 #define CONVERTIBLE_FORMATS (   \
94     AFMT_MU_LAW | AFMT_A_LAW |  \
95     AFMT_S32_LE | AFMT_S32_BE | \
96     AFMT_S24_LE | AFMT_S24_BE | \
97     AFMT_S24_PACKED |           \
98     AFMT_S16_LE | AFMT_S16_BE | \
99     AFMT_U16_LE | AFMT_U16_BE | \
100     AFMT_S8 | AFMT_U8 )
101 
102 static void
gst_oss4_append_format_to_caps(const GstOss4AudioFormat * fmt,GstCaps * caps)103 gst_oss4_append_format_to_caps (const GstOss4AudioFormat * fmt, GstCaps * caps)
104 {
105   GstStructure *s;
106 
107   s = gst_structure_new_empty (fmt->name);
108   if (fmt->gst_rbfmt == GST_AUDIO_RING_BUFFER_FORMAT_TYPE_RAW) {
109     gst_structure_set (s, "format", G_TYPE_STRING,
110         gst_audio_format_to_string (fmt->gst_rfmt),
111         "layout", G_TYPE_STRING, "interleaved", NULL);
112   }
113   gst_caps_append_structure (caps, s);
114 }
115 
116 static gint
gst_oss4_audio_get_oss_format(GstAudioRingBufferFormatType fmt,GstAudioFormat rfmt)117 gst_oss4_audio_get_oss_format (GstAudioRingBufferFormatType fmt,
118     GstAudioFormat rfmt)
119 {
120   guint i;
121 
122   for (i = 0; i < G_N_ELEMENTS (fmt_map); ++i) {
123     if (fmt_map[i].gst_rbfmt == fmt && fmt_map[i].gst_rfmt == rfmt)
124       return fmt_map[i].oss_fmt;
125   }
126   return 0;
127 }
128 
129 /* These are pretty random */
130 #define GST_OSS4_MIN_SAMPLE_RATE 1
131 #define GST_OSS4_MAX_SAMPLE_RATE 192000
132 
133 static gboolean
gst_oss4_audio_detect_rates(GstObject * obj,oss_audioinfo * ai,GstCaps * caps)134 gst_oss4_audio_detect_rates (GstObject * obj, oss_audioinfo * ai,
135     GstCaps * caps)
136 {
137   GValue val = { 0, };
138   int minrate, maxrate, i;
139 
140   minrate = ai->min_rate;
141   maxrate = ai->max_rate;
142 
143   /* sanity check */
144   if (minrate > maxrate) {
145     GST_WARNING_OBJECT (obj, "min_rate %d > max_rate %d (buggy driver?)",
146         minrate, maxrate);
147     maxrate = ai->min_rate;     /* swap */
148     minrate = ai->max_rate;
149   }
150 
151   /* limit to something sensible */
152   if (minrate < GST_OSS4_MIN_SAMPLE_RATE)
153     minrate = GST_OSS4_MIN_SAMPLE_RATE;
154   if (maxrate > GST_OSS4_MAX_SAMPLE_RATE)
155     maxrate = GST_OSS4_MAX_SAMPLE_RATE;
156 
157   if (maxrate < GST_OSS4_MIN_SAMPLE_RATE) {
158     GST_WARNING_OBJECT (obj, "max_rate < %d, which makes no sense",
159         GST_OSS4_MIN_SAMPLE_RATE);
160     return FALSE;
161   }
162 
163   GST_LOG_OBJECT (obj, "min_rate %d, max_rate %d (originally: %d, %d)",
164       minrate, maxrate, ai->min_rate, ai->max_rate);
165 
166   if ((ai->caps & PCM_CAP_FREERATE)) {
167     GST_LOG_OBJECT (obj, "device supports any sample rate between min and max");
168     if (minrate == maxrate) {
169       g_value_init (&val, G_TYPE_INT);
170       g_value_set_int (&val, maxrate);
171     } else {
172       g_value_init (&val, GST_TYPE_INT_RANGE);
173       gst_value_set_int_range (&val, minrate, maxrate);
174     }
175   } else {
176     GST_LOG_OBJECT (obj, "%d sample rates:", ai->nrates);
177     g_value_init (&val, GST_TYPE_LIST);
178     for (i = 0; i < ai->nrates; ++i) {
179       GST_LOG_OBJECT (obj, " rate: %d", ai->rates[i]);
180 
181       if (ai->rates[i] >= minrate && ai->rates[i] <= maxrate) {
182         GValue rate_val = { 0, };
183 
184         g_value_init (&rate_val, G_TYPE_INT);
185         g_value_set_int (&rate_val, ai->rates[i]);
186         gst_value_list_append_value (&val, &rate_val);
187         g_value_unset (&rate_val);
188       }
189     }
190 
191     if (gst_value_list_get_size (&val) == 0) {
192       g_value_unset (&val);
193       return FALSE;
194     }
195   }
196 
197   for (i = 0; i < gst_caps_get_size (caps); ++i) {
198     GstStructure *s;
199 
200     s = gst_caps_get_structure (caps, i);
201     gst_structure_set_value (s, "rate", &val);
202   }
203 
204   g_value_unset (&val);
205 
206   return TRUE;
207 }
208 
209 static void
gst_oss4_audio_get_channel_layout(GstObject * obj,guint64 layout,guint num_channels,GstAudioChannelPosition * ch_layout)210 gst_oss4_audio_get_channel_layout (GstObject * obj, guint64 layout,
211     guint num_channels, GstAudioChannelPosition * ch_layout)
212 {
213   const GstAudioChannelPosition pos_map[16] = {
214     GST_AUDIO_CHANNEL_POSITION_NONE,    /* 0 = dunno          */
215     GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,      /* 1 = left           */
216     GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,     /* 2 = right          */
217     GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,    /* 3 = center         */
218     GST_AUDIO_CHANNEL_POSITION_LFE1,    /* 4 = lfe            */
219     GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT,       /* 5 = left surround  */
220     GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT,      /* 6 = right surround */
221     GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,       /* 7 = left rear      */
222     GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT,      /* 8 = right rear     */
223     GST_AUDIO_CHANNEL_POSITION_NONE,
224     GST_AUDIO_CHANNEL_POSITION_NONE,
225     GST_AUDIO_CHANNEL_POSITION_NONE,
226     GST_AUDIO_CHANNEL_POSITION_NONE,
227     GST_AUDIO_CHANNEL_POSITION_NONE,
228     GST_AUDIO_CHANNEL_POSITION_NONE,
229     GST_AUDIO_CHANNEL_POSITION_NONE
230   };
231   guint speaker_pos;            /* speaker position as defined by OSS */
232   guint i;
233 
234   for (i = 0; i < num_channels; ++i) {
235     /* layout contains up to 16 speaker positions, with each taking up 4 bits */
236     speaker_pos = (guint) ((layout >> (i * 4)) & 0x0f);
237 
238     /* if it's a channel position that's unknown to us, set all to NONE and
239      * bail out */
240     if (G_UNLIKELY (pos_map[speaker_pos] == GST_AUDIO_CHANNEL_POSITION_NONE))
241       goto no_layout;
242 
243     ch_layout[i] = pos_map[speaker_pos];
244   }
245 
246   return;
247 
248 no_layout:
249   {
250     /* only warn if it's really unknown, position 0 is ok and represents NONE
251      * (in which case we also just set all others to NONE ignoring the other
252      * positions in the OSS-given layout, because that's what we currently
253      * require in GStreamer) */
254     if (speaker_pos != 0) {
255       GST_WARNING_OBJECT (obj, "unknown OSS channel position %x", ch_layout[i]);
256     }
257     for (i = 0; i < num_channels; ++i) {
258       ch_layout[i] = GST_AUDIO_CHANNEL_POSITION_NONE;
259     }
260     return;
261   }
262 }
263 
264 static void
gst_oss4_audio_set_ringbuffer_channel_layout(GstObject * obj,gint fd,GstAudioRingBufferSpec * spec)265 gst_oss4_audio_set_ringbuffer_channel_layout (GstObject * obj, gint fd,
266     GstAudioRingBufferSpec * spec)
267 {
268   guint num_channels;
269   guint64 layout = 0;
270   GstAudioRingBuffer *rb;
271   GstAudioChannelPosition ch_layout[8] = { 0, };
272 
273   num_channels = GST_AUDIO_INFO_CHANNELS (&spec->info);
274   if (num_channels < 3 || num_channels > 8)
275     return;
276 
277   if (spec->type != GST_AUDIO_RING_BUFFER_FORMAT_TYPE_RAW)
278     return;
279 
280   if (GST_IS_OSS4_SINK (obj)) {
281     rb = GST_AUDIO_BASE_SINK (obj)->ringbuffer;
282   } else if (GST_IS_OSS4_SOURCE (obj)) {
283     rb = GST_AUDIO_BASE_SRC (obj)->ringbuffer;
284   } else
285     g_return_if_reached ();
286 
287   /* -1 = get info for currently open device (fd). This will fail with
288    * OSS build <= 1013 because of a bug in OSS */
289   if (ioctl (fd, SNDCTL_DSP_GET_CHNORDER, &layout) == -1) {
290     GST_WARNING_OBJECT (obj, "couldn't query channel layout, assuming default");
291     layout = CHNORDER_NORMAL;
292   }
293   GST_DEBUG_OBJECT (obj, "channel layout: %08" G_GINT64_MODIFIER "x", layout);
294 
295 
296   gst_oss4_audio_get_channel_layout (obj, layout, num_channels, ch_layout);
297   gst_audio_ring_buffer_set_channel_positions (rb, ch_layout);
298 
299   return;
300 }
301 
302 static void
gst_oss4_audio_add_channel_layout(GstObject * obj,guint64 layout,guint num_channels,GstStructure * s)303 gst_oss4_audio_add_channel_layout (GstObject * obj, guint64 layout,
304     guint num_channels, GstStructure * s)
305 {
306   GstAudioChannelPosition ch_layout[8] = { 0, };
307   guint64 mask;
308 
309   g_return_if_fail (num_channels <= G_N_ELEMENTS (ch_layout));
310 
311   gst_oss4_audio_get_channel_layout (obj, layout, num_channels, ch_layout);
312   if (gst_audio_channel_positions_to_mask (ch_layout, num_channels, FALSE,
313           &mask))
314     gst_structure_set (s, "channel-mask", GST_TYPE_BITMASK, mask, NULL);
315 
316   return;
317 }
318 
319 /* arbitrary max. limit */
320 #define GST_OSS4_MIN_CHANNELS 1
321 #define GST_OSS4_MAX_CHANNELS 4096
322 
323 /* takes ownership of the input caps */
324 static GstCaps *
gst_oss4_audio_detect_channels(GstObject * obj,int fd,oss_audioinfo * ai,GstCaps * in_caps)325 gst_oss4_audio_detect_channels (GstObject * obj, int fd, oss_audioinfo * ai,
326     GstCaps * in_caps)
327 {
328   const gchar *forced_layout;
329   GstStructure *s = NULL;
330   guint64 layout = 0;
331   GstCaps *chan_caps = NULL;
332   GstCaps *out_caps = NULL;
333   int minchans, maxchans;
334   int c, i, j;
335 
336   /* GST_OSS4_CHANNEL_LAYOUT environment variable: may be used to force a
337    * particular channel layout (if it contains an odd number of channel
338    * positions it will also make us advertise a channel layout for that
339    * channel count, even if we'd usually skip it; this is especially useful
340    * for folks with 2.1 speakers, I guess) */
341   forced_layout = g_getenv ("GST_OSS4_CHANNEL_LAYOUT");
342 
343   minchans = ai->min_channels;
344   maxchans = ai->max_channels;
345 
346   /* sanity check */
347   if (minchans > maxchans) {
348     GST_WARNING_OBJECT (obj, "min_chans %d > max_chans %d (buggy driver?)",
349         minchans, maxchans);
350     maxchans = ai->min_channels;        /* swap */
351     minchans = ai->max_channels;
352   }
353 
354   /* limit to something sensible */
355   if (minchans < GST_OSS4_MIN_CHANNELS)
356     minchans = GST_OSS4_MIN_CHANNELS;
357   if (maxchans > GST_OSS4_MAX_CHANNELS)
358     maxchans = GST_OSS4_MAX_CHANNELS;
359 
360   if (maxchans < GST_OSS4_MIN_CHANNELS) {
361     GST_WARNING_OBJECT (obj, "max_chans < %d, which makes no sense",
362         GST_OSS4_MIN_CHANNELS);
363     gst_caps_unref (in_caps);
364     return NULL;
365   }
366 
367   GST_LOG_OBJECT (obj, "min_channels %d, max_channels %d (originally: %d, %d)",
368       minchans, maxchans, ai->min_channels, ai->max_channels);
369 
370   chan_caps = gst_caps_new_empty ();
371 
372   /* first do the simple cases: mono + stereo (channel layout implied) */
373   if (minchans == 1 && maxchans == 1)
374     s = gst_structure_new ("x", "channels", G_TYPE_INT, 1, NULL);
375   else if (minchans == 2 && maxchans >= 2)
376     s = gst_structure_new ("x", "channels", G_TYPE_INT, 2, NULL);
377   else if (minchans == 1 && maxchans >= 2)
378     s = gst_structure_new ("x", "channels", GST_TYPE_INT_RANGE, 1, 2, NULL);
379   gst_caps_append_structure (chan_caps, s);
380   s = NULL;
381 
382   /* TODO: we assume all drivers use a left/right layout for stereo here */
383   if (maxchans <= 2)
384     goto done;
385 
386   if (ioctl (fd, SNDCTL_DSP_GET_CHNORDER, &layout) == -1) {
387     GST_WARNING_OBJECT (obj, "couldn't query channel layout, assuming default");
388     layout = CHNORDER_NORMAL;
389   }
390   GST_DEBUG_OBJECT (obj, "channel layout: %08" G_GINT64_MODIFIER "x", layout);
391 
392   /* e.g. forced 2.1 layout would be GST_OSS4_CHANNEL_LAYOUT=421 */
393   if (forced_layout != NULL && *forced_layout != '\0') {
394     guint layout_len;
395 
396     layout_len = strlen (forced_layout);
397     if (layout_len >= minchans && layout_len <= maxchans) {
398       layout = g_ascii_strtoull (forced_layout, NULL, 16);
399       maxchans = layout_len;
400       GST_DEBUG_OBJECT (obj, "forced channel layout: %08" G_GINT64_MODIFIER "x"
401           " ('%s'), maxchans now %d", layout, forced_layout, maxchans);
402     } else {
403       GST_WARNING_OBJECT (obj, "ignoring forced channel layout: layout has %d "
404           "channel positions but maxchans is %d", layout_len, maxchans);
405     }
406   }
407 
408   /* need to advertise channel layouts for anything >2 and <=8 channels */
409   for (c = MAX (3, minchans); c <= MIN (maxchans, 8); c++) {
410     /* "The min_channels and max_channels fields define the limits for the
411      * number of channels. However some devices don't support all channels
412      * within this range. It's possible that the odd values (3, 5, 7, 9, etc).
413      * are not supported. There is currently no way to check for this other
414      * than checking if SNDCTL_DSP_CHANNELS accepts the requested value.
415      * Another approach is trying to avoid using odd number of channels."
416      *
417      * So, we don't know for sure if these odd values are supported:
418      */
419     if ((c == 3 || c == 5 || c == 7) && (c != maxchans)) {
420       GST_LOG_OBJECT (obj, "not adding layout with %d channels", c);
421       continue;
422     }
423 
424     s = gst_structure_new ("x", "channels", G_TYPE_INT, c, NULL);
425     gst_oss4_audio_add_channel_layout (obj, layout, c, s);
426     GST_LOG_OBJECT (obj, "c=%u, appending struct %" GST_PTR_FORMAT, c, s);
427     gst_caps_append_structure (chan_caps, s);
428     s = NULL;
429   }
430 
431   if (maxchans <= 8)
432     goto done;
433 
434   /* for everything >8 channels, CHANNEL_POSITION_NONE is implied. */
435   if (minchans == maxchans || maxchans == 9) {
436     s = gst_structure_new ("x", "channels", G_TYPE_INT, maxchans, NULL);
437   } else {
438     s = gst_structure_new ("x", "channels", GST_TYPE_INT_RANGE,
439         MAX (9, minchans), maxchans, NULL);
440   }
441   gst_caps_append_structure (chan_caps, s);
442   s = NULL;
443 
444 done:
445 
446   GST_LOG_OBJECT (obj, "channel structures: %" GST_PTR_FORMAT, chan_caps);
447 
448   out_caps = gst_caps_new_empty ();
449 
450   /* combine each structure in the input caps with each channel caps struct */
451   for (i = 0; i < gst_caps_get_size (in_caps); ++i) {
452     const GstStructure *in_s;
453 
454     in_s = gst_caps_get_structure (in_caps, i);
455 
456     for (j = 0; j < gst_caps_get_size (chan_caps); ++j) {
457       const GstStructure *chan_s;
458       const GValue *val;
459 
460       s = gst_structure_copy (in_s);
461       chan_s = gst_caps_get_structure (chan_caps, j);
462       if ((val = gst_structure_get_value (chan_s, "channels")))
463         gst_structure_set_value (s, "channels", val);
464       if ((val = gst_structure_get_value (chan_s, "channel-mask")))
465         gst_structure_set_value (s, "channel-mask", val);
466 
467       gst_caps_append_structure (out_caps, s);
468       s = NULL;
469     }
470   }
471 
472   gst_caps_unref (in_caps);
473   gst_caps_unref (chan_caps);
474   return out_caps;
475 }
476 
477 GstCaps *
gst_oss4_audio_probe_caps(GstObject * obj,int fd)478 gst_oss4_audio_probe_caps (GstObject * obj, int fd)
479 {
480   oss_audioinfo ai = { 0, };
481   gboolean output;
482   GstCaps *caps;
483   int nonnative_formats = 0;
484   int formats, i;
485 
486   output = GST_IS_OSS4_SINK (obj);
487 
488   /* -1 = get info for currently open device (fd). This will fail with
489    * OSS build <= 1013 because of a bug in OSS */
490   ai.dev = -1;
491   if (ioctl (fd, SNDCTL_ENGINEINFO, &ai) == -1)
492     goto engineinfo_failed;
493 
494   formats = (output) ? ai.oformats : ai.iformats;
495 
496   GST_LOG_OBJECT (obj, "%s formats : 0x%08x", (output) ? "out" : "in", formats);
497 
498   caps = gst_caps_new_empty ();
499 
500   /* first list all the formats natively supported */
501   for (i = 0; i < G_N_ELEMENTS (fmt_map); ++i) {
502     if ((formats & fmt_map[i].oss_fmt)) {
503       gst_oss4_append_format_to_caps (&fmt_map[i], caps);
504     } else if ((fmt_map[i].oss_fmt & CONVERTIBLE_FORMATS)) {
505       nonnative_formats |= fmt_map[i].oss_fmt;
506     }
507   }
508 
509   GST_LOG_OBJECT (obj, "adding non-native %s formats : 0x%08x",
510       (output) ? "out" : "in", nonnative_formats);
511 
512   /* now append non-native formats for which conversion would be needed */
513   for (i = 0; i < G_N_ELEMENTS (fmt_map); ++i) {
514     if ((nonnative_formats & fmt_map[i].oss_fmt)) {
515       gst_oss4_append_format_to_caps (&fmt_map[i], caps);
516     }
517   }
518 
519   caps = gst_caps_simplify (caps);
520   GST_LOG_OBJECT (obj, "formats: %" GST_PTR_FORMAT, caps);
521 
522   if (!gst_oss4_audio_detect_rates (obj, &ai, caps))
523     goto detect_rates_failed;
524 
525   caps = gst_oss4_audio_detect_channels (obj, fd, &ai, caps);
526   if (caps == NULL)
527     goto detect_channels_failed;
528 
529   GST_LOG_OBJECT (obj, "probed caps: %" GST_PTR_FORMAT, caps);
530 
531   return caps;
532 
533 /* ERRORS */
534 engineinfo_failed:
535   {
536     GST_WARNING ("ENGINEINFO supported formats probe failed: %s",
537         g_strerror (errno));
538     return NULL;
539   }
540 detect_rates_failed:
541   {
542     GST_WARNING_OBJECT (obj, "failed to detect supported sample rates");
543     gst_caps_unref (caps);
544     return NULL;
545   }
546 detect_channels_failed:
547   {
548     GST_WARNING_OBJECT (obj, "failed to detect supported channels");
549     gst_caps_unref (caps);
550     return NULL;
551   }
552 }
553 
554 GstCaps *
gst_oss4_audio_get_template_caps(void)555 gst_oss4_audio_get_template_caps (void)
556 {
557   GstCaps *caps;
558   gint i;
559 
560   caps = gst_caps_new_empty ();
561 
562   for (i = 0; i < G_N_ELEMENTS (fmt_map); ++i) {
563     gst_oss4_append_format_to_caps (&fmt_map[i], caps);
564   }
565 
566   caps = gst_caps_simplify (caps);
567 
568   for (i = 0; i < gst_caps_get_size (caps); ++i) {
569     GstStructure *s;
570 
571     s = gst_caps_get_structure (caps, i);
572     gst_structure_set (s, "rate", GST_TYPE_INT_RANGE, GST_OSS4_MIN_SAMPLE_RATE,
573         GST_OSS4_MAX_SAMPLE_RATE, "channels", GST_TYPE_INT_RANGE,
574         GST_OSS4_MIN_CHANNELS, GST_OSS4_MAX_CHANNELS, NULL);
575   }
576 
577   return caps;
578 }
579 
580 /* called by gst_oss4_sink_prepare() and gst_oss4_source_prepare() */
581 gboolean
gst_oss4_audio_set_format(GstObject * obj,int fd,GstAudioRingBufferSpec * spec)582 gst_oss4_audio_set_format (GstObject * obj, int fd,
583     GstAudioRingBufferSpec * spec)
584 {
585   struct audio_buf_info info = { 0, };
586   int ofmt, fmt, chans, rate, width;
587 
588   fmt = gst_oss4_audio_get_oss_format (spec->type,
589       GST_AUDIO_INFO_FORMAT (&spec->info));
590 
591   if (fmt == 0)
592     goto wrong_format;
593 
594   ofmt = fmt;
595   chans = GST_AUDIO_INFO_CHANNELS (&spec->info);
596   rate = GST_AUDIO_INFO_RATE (&spec->info);
597   width = GST_AUDIO_INFO_WIDTH (&spec->info);
598 
599   if (spec->type == GST_AUDIO_RING_BUFFER_FORMAT_TYPE_RAW &&
600       width != 32 && width != 24 && width != 16 && width != 8) {
601     goto dodgy_width;
602   }
603 
604   /* format */
605   GST_LOG_OBJECT (obj, "setting format: %d", fmt);
606   if (ioctl (fd, SNDCTL_DSP_SETFMT, &fmt) == -1)
607     goto set_format_failed;
608 
609   /* channels */
610   GST_LOG_OBJECT (obj, "setting channels: %d", chans);
611   if (ioctl (fd, SNDCTL_DSP_CHANNELS, &chans) == -1)
612     goto set_channels_failed;
613 
614   /* rate */
615   GST_LOG_OBJECT (obj, "setting rate: %d", rate);
616   if (ioctl (fd, SNDCTL_DSP_SPEED, &rate) == -1)
617     goto set_rate_failed;
618 
619   GST_DEBUG_OBJECT (obj, "effective format   : %d", fmt);
620   GST_DEBUG_OBJECT (obj, "effective channels : %d", chans);
621   GST_DEBUG_OBJECT (obj, "effective rate     : %d", rate);
622 
623   /* make sure format, channels, and rate are the ones we requested */
624   if (fmt != ofmt || chans != GST_AUDIO_INFO_CHANNELS (&spec->info) ||
625       rate != GST_AUDIO_INFO_RATE (&spec->info)) {
626     /* This shouldn't happen, but hey */
627     goto format_not_what_was_requested;
628   }
629 
630   if (GST_IS_OSS4_SOURCE (obj)) {
631     if (ioctl (fd, SNDCTL_DSP_GETISPACE, &info) == -1)
632       goto get_ispace_failed;
633   } else {
634     if (ioctl (fd, SNDCTL_DSP_GETOSPACE, &info) == -1)
635       goto get_ospace_failed;
636   }
637 
638   spec->segsize = info.fragsize;
639 
640   /* we add some extra fragments -- this helps us account for delays due to
641    * conversion buffer, streams queueing, etc.  It is important that these
642    * be taken into account because otherwise the delay counter can wind up
643    * being too large, and the buffer will wrap.  */
644   spec->segtotal = info.fragstotal + 4;
645 
646   GST_DEBUG_OBJECT (obj, "got segsize: %d, segtotal: %d, value: %08x",
647       spec->segsize, spec->segtotal, info.fragsize);
648 
649   gst_oss4_audio_set_ringbuffer_channel_layout (obj, fd, spec);
650 
651   return TRUE;
652 
653 /* ERRORS */
654 wrong_format:
655   {
656     GST_ELEMENT_ERROR (obj, RESOURCE, SETTINGS, (NULL),
657         ("Unable to get format (%d, %d)", spec->type,
658             GST_AUDIO_INFO_FORMAT (&spec->info)));
659     return FALSE;
660   }
661 dodgy_width:
662   {
663     GST_ELEMENT_ERROR (obj, RESOURCE, SETTINGS, (NULL),
664         ("unexpected width %d", width));
665     return FALSE;
666   }
667 set_format_failed:
668   {
669     GST_ELEMENT_ERROR (obj, RESOURCE, SETTINGS, (NULL),
670         ("DSP_SETFMT(%d) failed: %s", fmt, g_strerror (errno)));
671     return FALSE;
672   }
673 set_channels_failed:
674   {
675     GST_ELEMENT_ERROR (obj, RESOURCE, SETTINGS, (NULL),
676         ("DSP_CHANNELS(%d) failed: %s", chans, g_strerror (errno)));
677     return FALSE;
678   }
679 set_rate_failed:
680   {
681     GST_ELEMENT_ERROR (obj, RESOURCE, SETTINGS, (NULL),
682         ("DSP_SPEED(%d) failed: %s", rate, g_strerror (errno)));
683     return FALSE;
684   }
685 get_ospace_failed:
686   {
687     GST_ELEMENT_ERROR (obj, RESOURCE, SETTINGS, (NULL),
688         ("DSP_GETOSPACE failed: %s", g_strerror (errno)));
689     return FALSE;
690   }
691 get_ispace_failed:
692   {
693     GST_ELEMENT_ERROR (obj, RESOURCE, SETTINGS, (NULL),
694         ("DSP_GETISPACE failed: %s", g_strerror (errno)));
695     return FALSE;
696   }
697 format_not_what_was_requested:
698   {
699     GST_ELEMENT_ERROR (obj, RESOURCE, SETTINGS, (NULL),
700         ("Format actually configured wasn't the one we requested. This is "
701             "probably either a bug in the driver or in the format probing code."));
702     return FALSE;
703   }
704 }
705 
706 int
gst_oss4_audio_get_version(GstObject * obj,int fd)707 gst_oss4_audio_get_version (GstObject * obj, int fd)
708 {
709   gint ver = 0;
710 
711   /* we use the old ioctl here on purpose instead of SNDCTL_SYSINFO */
712   if (ioctl (fd, OSS_GETVERSION, &ver) < 0) {
713     GST_LOG_OBJECT (obj, "OSS_GETVERSION failed: %s", g_strerror (errno));
714     return -1;
715   }
716   GST_LOG_OBJECT (obj, "OSS version: 0x%08x", ver);
717   return ver;
718 }
719 
720 gboolean
gst_oss4_audio_check_version(GstObject * obj,int fd)721 gst_oss4_audio_check_version (GstObject * obj, int fd)
722 {
723   return (gst_oss4_audio_get_version (obj, fd) >= GST_MIN_OSS4_VERSION);
724 }
725 
726 gchar *
gst_oss4_audio_find_device(GstObject * oss)727 gst_oss4_audio_find_device (GstObject * oss)
728 {
729   GValueArray *arr;
730   gchar *ret = NULL;
731 
732   arr = gst_oss4_property_probe_get_values (GST_OBJECT (oss), "device");
733 
734   if (arr != NULL) {
735     if (arr->n_values > 0) {
736       const GValue *val;
737 
738       val = g_value_array_get_nth (arr, 0);
739       ret = g_value_dup_string (val);
740     }
741     g_value_array_free (arr);
742   }
743 
744   GST_LOG_OBJECT (oss, "first device found: %s", GST_STR_NULL (ret));
745 
746   return ret;
747 }
748 
749 static gboolean
plugin_init(GstPlugin * plugin)750 plugin_init (GstPlugin * plugin)
751 {
752   gint rank;
753 
754   GST_DEBUG_CATEGORY_INIT (oss4sink_debug, "oss4sink", 0, "OSS4 audio sink");
755   GST_DEBUG_CATEGORY_INIT (oss4src_debug, "oss4src", 0, "OSS4 audio src");
756   GST_DEBUG_CATEGORY_INIT (oss4mixer_debug, "oss4mixer", 0, "OSS4 mixer");
757   GST_DEBUG_CATEGORY_INIT (oss4_debug, "oss4", 0, "OSS4 plugin");
758 
759 #ifdef ENABLE_NLS
760   GST_DEBUG ("binding text domain %s to locale dir %s", GETTEXT_PACKAGE,
761       LOCALEDIR);
762   bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
763   bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
764 #endif
765 
766   /* we want a higher rank than the legacy OSS elements have now */
767   rank = GST_RANK_SECONDARY + 1;
768 
769   if (!gst_element_register (plugin, "oss4sink", rank, GST_TYPE_OSS4_SINK) ||
770       !gst_element_register (plugin, "oss4src", rank, GST_TYPE_OSS4_SOURCE)) {
771     return FALSE;
772   }
773 
774   return TRUE;
775 }
776 
777 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
778     GST_VERSION_MINOR,
779     oss4,
780     "Open Sound System (OSS) version 4 support for GStreamer",
781     plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
782