2 * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
3 * 2000 Wim Taymans <wim.taymans@chello.be>
5 * gstosshelper.c: OSS helper routines
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.
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.
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.
27 #include "gst/gst-i18n-plugin.h"
28 #include <sys/types.h>
30 #include <sys/ioctl.h>
36 #ifdef HAVE_OSS_INCLUDE_IN_SYS
37 # include <sys/soundcard.h>
39 # ifdef HAVE_OSS_INCLUDE_IN_ROOT
40 # include <soundcard.h>
42 # ifdef HAVE_OSS_INCLUDE_IN_MACHINE
43 # include <machine/soundcard.h>
45 # error "What to include?"
46 # endif /* HAVE_OSS_INCLUDE_IN_MACHINE */
47 # endif /* HAVE_OSS_INCLUDE_IN_ROOT */
48 #endif /* HAVE_OSS_INCLUDE_IN_SYS */
50 #include <gst/interfaces/propertyprobe.h>
52 #include "gstosshelper.h"
53 #include "gstossmixer.h"
55 GST_DEBUG_CATEGORY_EXTERN (oss_debug);
56 #define GST_CAT_DEFAULT oss_debug
58 typedef struct _GstOssProbe GstOssProbe;
69 typedef struct _GstOssRange GstOssRange;
76 static GstStructure *gst_oss_helper_get_format_structure (unsigned int
78 static gboolean gst_oss_helper_rate_probe_check (GstOssProbe * probe);
79 static int gst_oss_helper_rate_check_rate (GstOssProbe * probe, int irate);
80 static void gst_oss_helper_rate_add_range (GQueue * queue, int min, int max);
81 static void gst_oss_helper_rate_add_rate (GArray * array, int rate);
82 static int gst_oss_helper_rate_int_compare (gconstpointer a, gconstpointer b);
85 gst_oss_helper_probe_caps (gint fd)
90 GstStructure *structure;
91 unsigned int format_bit;
92 unsigned int format_mask;
95 /* FIXME test make sure we're not currently playing */
96 /* FIXME test both mono and stereo */
98 format_mask = AFMT_U8 | AFMT_S8;
100 if (G_BYTE_ORDER == G_LITTLE_ENDIAN)
101 format_mask |= AFMT_S16_LE | AFMT_U16_LE;
103 format_mask |= AFMT_S16_BE | AFMT_U16_BE;
105 caps = gst_caps_new_empty ();
107 /* assume that the most significant bit of format_mask is 0 */
108 for (format_bit = 1 << 31; format_bit > 0; format_bit >>= 1) {
109 if (format_bit & format_mask) {
110 GValue rate_value = { 0 };
112 probe = g_new0 (GstOssProbe, 1);
114 probe->format = format_bit;
115 probe->n_channels = 2;
117 ret = gst_oss_helper_rate_probe_check (probe);
118 if (probe->min == -1 || probe->max == -1) {
119 g_array_free (probe->rates, TRUE);
125 GValue value = { 0 };
127 g_array_sort (probe->rates, gst_oss_helper_rate_int_compare);
129 g_value_init (&rate_value, GST_TYPE_LIST);
130 g_value_init (&value, G_TYPE_INT);
132 for (i = 0; i < probe->rates->len; i++) {
133 g_value_set_int (&value, g_array_index (probe->rates, int, i));
135 gst_value_list_append_value (&rate_value, &value);
138 g_value_unset (&value);
141 g_value_init (&rate_value, GST_TYPE_INT_RANGE);
142 gst_value_set_int_range (&rate_value, probe->min, probe->max);
145 g_array_free (probe->rates, TRUE);
148 structure = gst_oss_helper_get_format_structure (format_bit);
149 gst_structure_set (structure, "channels", GST_TYPE_INT_RANGE, 1, 2, NULL);
150 gst_structure_set_value (structure, "rate", &rate_value);
151 g_value_unset (&rate_value);
153 gst_caps_append_structure (caps, structure);
157 if (gst_caps_is_empty (caps)) {
158 /* fixme: make user-visible */
159 GST_WARNING ("Your OSS device could not be probed correctly");
162 GST_DEBUG ("probed caps: %" GST_PTR_FORMAT, caps);
167 static GstStructure *
168 gst_oss_helper_get_format_structure (unsigned int format_bit)
170 GstStructure *structure;
175 switch (format_bit) {
182 endianness = G_LITTLE_ENDIAN;
187 endianness = G_BIG_ENDIAN;
197 endianness = G_LITTLE_ENDIAN;
202 endianness = G_BIG_ENDIAN;
207 g_assert_not_reached ();
211 structure = gst_structure_new ("audio/x-raw-int",
212 "width", G_TYPE_INT, width,
213 "depth", G_TYPE_INT, width, "signed", G_TYPE_BOOLEAN, sign, NULL);
216 gst_structure_set (structure, "endianness", G_TYPE_INT, endianness, NULL);
223 gst_oss_helper_rate_probe_check (GstOssProbe * probe)
228 gboolean checking_exact_rates = TRUE;
230 gboolean result = TRUE;
232 ranges = g_queue_new ();
234 probe->rates = g_array_new (FALSE, FALSE, sizeof (int));
236 probe->min = gst_oss_helper_rate_check_rate (probe, 1000);
238 probe->max = gst_oss_helper_rate_check_rate (probe, 100000);
239 /* a little bug workaround */
243 max = gst_oss_helper_rate_check_rate (probe, 48000);
244 if (max > probe->max) {
246 ("Driver bug recognized (driver does not round rates correctly). Please file a bug report.");
251 if (probe->min == -1 || probe->max == -1) {
252 /* This is a workaround for drivers that return -EINVAL (or another
253 * error) for rates outside of [8000,48000]. If this fails, the
254 * driver is seriously buggy, and probably doesn't work with other
255 * media libraries/apps. */
256 probe->min = gst_oss_helper_rate_check_rate (probe, 8000);
257 probe->max = gst_oss_helper_rate_check_rate (probe, 48000);
259 if (probe->min == -1 || probe->max == -1) {
260 GST_DEBUG ("unexpected check_rate error");
263 gst_oss_helper_rate_add_range (ranges, probe->min + 1, probe->max - 1);
265 while ((range = g_queue_pop_head (ranges))) {
271 GST_DEBUG ("checking [%d,%d]", range->min, range->max);
273 mid = (range->min + range->max) / 2;
274 mid_ret = gst_oss_helper_rate_check_rate (probe, mid);
276 /* FIXME ioctl returned an error. do something */
277 GST_DEBUG ("unexpected check_rate error");
281 if (mid == mid_ret && checking_exact_rates) {
282 int max_exact_matches = 20;
285 if (exact_rates > max_exact_matches) {
286 GST_DEBUG ("got %d exact rates, assuming all are exact",
293 checking_exact_rates = FALSE;
296 /* Assume that the rate is arithmetically rounded to the nearest
298 if (mid == mid_ret) {
303 min1 = mid - (mid_ret - mid);
307 max1 = mid + (mid - mid_ret);
311 gst_oss_helper_rate_add_range (ranges, range->min, min1);
312 gst_oss_helper_rate_add_range (ranges, max1, range->max);
317 while ((range = g_queue_pop_head (ranges))) {
320 g_queue_free (ranges);
326 gst_oss_helper_rate_add_range (GQueue * queue, int min, int max)
329 GstOssRange *range = g_new0 (GstOssRange, 1);
334 g_queue_push_tail (queue, range);
335 /* push_head also works, but has different probing behavior */
336 /*g_queue_push_head (queue, range); */
341 gst_oss_helper_rate_check_rate (GstOssProbe * probe, int irate)
349 format = probe->format;
350 n_channels = probe->n_channels;
352 GST_LOG ("checking format %d, channels %d, rate %d",
353 format, n_channels, rate);
354 ret = ioctl (probe->fd, SNDCTL_DSP_SETFMT, &format);
355 if (ret < 0 || format != probe->format) {
356 GST_DEBUG ("unsupported format: %d (%d)", probe->format, format);
359 ret = ioctl (probe->fd, SNDCTL_DSP_CHANNELS, &n_channels);
360 if (ret < 0 || n_channels != probe->n_channels) {
361 GST_DEBUG ("unsupported channels: %d (%d)", probe->n_channels, n_channels);
364 ret = ioctl (probe->fd, SNDCTL_DSP_SPEED, &rate);
366 GST_DEBUG ("unsupported rate: %d (%d)", irate, rate);
370 GST_DEBUG ("rate %d -> %d", irate, rate);
372 if (rate == irate - 1 || rate == irate + 1) {
375 gst_oss_helper_rate_add_rate (probe->rates, rate);
380 gst_oss_helper_rate_add_rate (GArray * array, int rate)
385 for (i = 0; i < array->len; i++) {
386 val = g_array_index (array, int, i);
391 GST_DEBUG ("supported rate: %d", rate);
392 g_array_append_val (array, rate);
396 gst_oss_helper_rate_int_compare (gconstpointer a, gconstpointer b)
398 const int *va = (const int *) a;
399 const int *vb = (const int *) b;