webrtc/nice: Support domain name as connection-address of ICE candidate
[platform/upstream/gstreamer.git] / subprojects / gst-plugins-good / sys / oss / gstosshelper.c
1 /* GStreamer
2  * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
3  *                    2000 Wim Taymans <wim.taymans@chello.be>
4  *
5  * gstosshelper.c: OSS helper routines
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 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26
27 #include <glib/gi18n-lib.h>
28 #include <sys/types.h>
29 #include <sys/stat.h>
30 #include <sys/ioctl.h>
31 #include <fcntl.h>
32 #include <unistd.h>
33 #include <errno.h>
34 #include <string.h>
35
36 #ifdef HAVE_OSS_INCLUDE_IN_SYS
37 # include <sys/soundcard.h>
38 #else
39 # ifdef HAVE_OSS_INCLUDE_IN_ROOT
40 #  include <soundcard.h>
41 # else
42 #  ifdef HAVE_OSS_INCLUDE_IN_MACHINE
43 #   include <machine/soundcard.h>
44 #  else
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 */
49
50 #include "gstosshelper.h"
51
52 GST_DEBUG_CATEGORY_EXTERN (oss_debug);
53 #define GST_CAT_DEFAULT oss_debug
54
55 typedef struct _GstOssProbe GstOssProbe;
56 struct _GstOssProbe
57 {
58   int fd;
59   int format;
60   int n_channels;
61   GArray *rates;
62   int min;
63   int max;
64 };
65
66 typedef struct _GstOssRange GstOssRange;
67 struct _GstOssRange
68 {
69   int min;
70   int max;
71 };
72
73 static GstStructure *gst_oss_helper_get_format_structure (unsigned int
74     format_bit);
75 static gboolean gst_oss_helper_rate_probe_check (GstOssProbe * probe);
76 static int gst_oss_helper_rate_check_rate (GstOssProbe * probe, int irate);
77 static void gst_oss_helper_rate_add_range (GQueue * queue, int min, int max);
78 static void gst_oss_helper_rate_add_rate (GArray * array, int rate);
79 static int gst_oss_helper_rate_int_compare (gconstpointer a, gconstpointer b);
80
81 GstCaps *
82 gst_oss_helper_probe_caps (gint fd)
83 {
84 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
85   const guint probe_formats[] = { AFMT_S16_LE, AFMT_U16_LE, AFMT_U8, AFMT_S8 };
86 #else
87   const guint probe_formats[] = { AFMT_S16_BE, AFMT_U16_BE, AFMT_U8, AFMT_S8 };
88 #endif
89   GstOssProbe *probe;
90   int i, f;
91   gboolean ret;
92   GstStructure *structure;
93   GstCaps *caps;
94
95   /* FIXME test make sure we're not currently playing */
96   /* FIXME test both mono and stereo */
97
98   caps = gst_caps_new_empty ();
99
100   /* assume that the most significant bit of format_mask is 0 */
101   for (f = 0; f < G_N_ELEMENTS (probe_formats); ++f) {
102     GValue rate_value = { 0 };
103
104     probe = g_new0 (GstOssProbe, 1);
105     probe->fd = fd;
106     probe->format = probe_formats[f];
107     /* FIXME: this is not working for all cards, see bug #518474 */
108     probe->n_channels = 2;
109
110     ret = gst_oss_helper_rate_probe_check (probe);
111     if (probe->min == -1 || probe->max == -1) {
112       g_array_free (probe->rates, TRUE);
113       g_free (probe);
114       continue;
115     }
116
117     if (ret) {
118       GValue value = { 0 };
119
120       g_array_sort (probe->rates, gst_oss_helper_rate_int_compare);
121
122       g_value_init (&rate_value, GST_TYPE_LIST);
123       g_value_init (&value, G_TYPE_INT);
124
125       for (i = 0; i < probe->rates->len; i++) {
126         g_value_set_int (&value, g_array_index (probe->rates, int, i));
127
128         gst_value_list_append_value (&rate_value, &value);
129       }
130
131       g_value_unset (&value);
132     } else {
133       /* one big range */
134       g_value_init (&rate_value, GST_TYPE_INT_RANGE);
135       gst_value_set_int_range (&rate_value, probe->min, probe->max);
136     }
137
138     g_array_free (probe->rates, TRUE);
139     g_free (probe);
140
141     structure = gst_oss_helper_get_format_structure (probe_formats[f]);
142     gst_structure_set (structure, "channels", GST_TYPE_INT_RANGE, 1, 2, NULL);
143     gst_structure_set_value (structure, "rate", &rate_value);
144     g_value_unset (&rate_value);
145
146     gst_caps_append_structure (caps, structure);
147   }
148
149   if (gst_caps_is_empty (caps)) {
150     /* fixme: make user-visible */
151     GST_WARNING ("Your OSS device could not be probed correctly");
152   } else {
153     caps = gst_caps_simplify (caps);
154   }
155
156   GST_DEBUG ("probed caps: %" GST_PTR_FORMAT, caps);
157
158   return caps;
159 }
160
161 static GstStructure *
162 gst_oss_helper_get_format_structure (unsigned int format_bit)
163 {
164   GstStructure *structure;
165   const gchar *format;
166
167   switch (format_bit) {
168     case AFMT_U8:
169       format = "U8";
170       break;
171     case AFMT_S16_LE:
172       format = "S16LE";
173       break;
174     case AFMT_S16_BE:
175       format = "S16BE";
176       break;
177     case AFMT_S8:
178       format = "S8";
179       break;
180     case AFMT_U16_LE:
181       format = "U16LE";
182       break;
183     case AFMT_U16_BE:
184       format = "U16BE";
185       break;
186     default:
187       g_assert_not_reached ();
188       return NULL;
189   }
190
191   structure = gst_structure_new ("audio/x-raw",
192       "format", G_TYPE_STRING, format,
193       "layout", G_TYPE_STRING, "interleaved", NULL);
194
195   return structure;
196 }
197
198 static gboolean
199 gst_oss_helper_rate_probe_check (GstOssProbe * probe)
200 {
201   GstOssRange *range;
202   GQueue *ranges;
203   int exact_rates = 0;
204   gboolean checking_exact_rates = TRUE;
205   gboolean result = TRUE;
206
207   ranges = g_queue_new ();
208
209   probe->rates = g_array_new (FALSE, FALSE, sizeof (int));
210
211   probe->min = gst_oss_helper_rate_check_rate (probe, 1000);
212   probe->max = gst_oss_helper_rate_check_rate (probe, 100000);
213   /* a little bug workaround */
214   {
215     int max;
216
217     max = gst_oss_helper_rate_check_rate (probe, 48000);
218     if (max > probe->max) {
219       GST_ERROR
220           ("Driver bug recognized (driver does not round rates correctly).  Please file a bug report.");
221       probe->max = max;
222     }
223   }
224   if (probe->min == -1 || probe->max == -1) {
225     /* This is a workaround for drivers that return -EINVAL (or another
226      * error) for rates outside of [8000,48000].  If this fails, the
227      * driver is seriously buggy, and probably doesn't work with other
228      * media libraries/apps.  */
229     probe->min = gst_oss_helper_rate_check_rate (probe, 8000);
230     probe->max = gst_oss_helper_rate_check_rate (probe, 48000);
231   }
232   if (probe->min == -1 || probe->max == -1) {
233     GST_DEBUG ("unexpected check_rate error");
234     return FALSE;
235   }
236   gst_oss_helper_rate_add_range (ranges, probe->min + 1, probe->max - 1);
237
238   while ((range = g_queue_pop_head (ranges))) {
239     int min1;
240     int max1;
241     int mid;
242     int mid_ret;
243
244     GST_DEBUG ("checking [%d,%d]", range->min, range->max);
245
246     mid = (range->min + range->max) / 2;
247     mid_ret = gst_oss_helper_rate_check_rate (probe, mid);
248     if (mid_ret == -1) {
249       /* FIXME ioctl returned an error.  do something */
250       GST_DEBUG ("unexpected check_rate error");
251     }
252
253     if (mid == mid_ret && checking_exact_rates) {
254       int max_exact_matches = 20;
255
256       exact_rates++;
257       if (exact_rates > max_exact_matches) {
258         GST_DEBUG ("got %d exact rates, assuming all are exact",
259             max_exact_matches);
260         result = FALSE;
261         g_free (range);
262         break;
263       }
264     } else {
265       checking_exact_rates = FALSE;
266     }
267
268     /* Assume that the rate is arithmetically rounded to the nearest
269      * supported rate. */
270     if (mid == mid_ret) {
271       min1 = mid - 1;
272       max1 = mid + 1;
273     } else {
274       if (mid < mid_ret) {
275         min1 = mid - (mid_ret - mid);
276         max1 = mid_ret + 1;
277       } else {
278         min1 = mid_ret - 1;
279         max1 = mid + (mid - mid_ret);
280       }
281     }
282
283     gst_oss_helper_rate_add_range (ranges, range->min, min1);
284     gst_oss_helper_rate_add_range (ranges, max1, range->max);
285
286     g_free (range);
287   }
288
289   while ((range = g_queue_pop_head (ranges))) {
290     g_free (range);
291   }
292   g_queue_free (ranges);
293
294   return result;
295 }
296
297 static void
298 gst_oss_helper_rate_add_range (GQueue * queue, int min, int max)
299 {
300   if (min <= max) {
301     GstOssRange *range = g_new0 (GstOssRange, 1);
302
303     range->min = min;
304     range->max = max;
305
306     g_queue_push_tail (queue, range);
307     /* push_head also works, but has different probing behavior */
308     /*g_queue_push_head (queue, range); */
309   }
310 }
311
312 static int
313 gst_oss_helper_rate_check_rate (GstOssProbe * probe, int irate)
314 {
315   int rate;
316   int format;
317   int n_channels;
318   int ret;
319
320   rate = irate;
321   format = probe->format;
322   n_channels = probe->n_channels;
323
324   GST_LOG ("checking format %d, channels %d, rate %d",
325       format, n_channels, rate);
326   ret = ioctl (probe->fd, SNDCTL_DSP_SETFMT, &format);
327   if (ret < 0 || format != probe->format) {
328     GST_DEBUG ("unsupported format: %d (%d)", probe->format, format);
329     return -1;
330   }
331   ret = ioctl (probe->fd, SNDCTL_DSP_CHANNELS, &n_channels);
332   if (ret < 0 || n_channels != probe->n_channels) {
333     GST_DEBUG ("unsupported channels: %d (%d)", probe->n_channels, n_channels);
334     return -1;
335   }
336   ret = ioctl (probe->fd, SNDCTL_DSP_SPEED, &rate);
337   if (ret < 0) {
338     GST_DEBUG ("unsupported rate: %d (%d)", irate, rate);
339     return -1;
340   }
341
342   GST_DEBUG ("rate %d -> %d", irate, rate);
343
344   if (rate == irate - 1 || rate == irate + 1) {
345     rate = irate;
346   }
347   gst_oss_helper_rate_add_rate (probe->rates, rate);
348   return rate;
349 }
350
351 static void
352 gst_oss_helper_rate_add_rate (GArray * array, int rate)
353 {
354   int i;
355   int val;
356
357   for (i = 0; i < array->len; i++) {
358     val = g_array_index (array, int, i);
359
360     if (val == rate)
361       return;
362   }
363   GST_DEBUG ("supported rate: %d", rate);
364   g_array_append_val (array, rate);
365 }
366
367 static int
368 gst_oss_helper_rate_int_compare (gconstpointer a, gconstpointer b)
369 {
370   const int *va = (const int *) a;
371   const int *vb = (const int *) b;
372
373   if (*va < *vb)
374     return -1;
375   if (*va > *vb)
376     return 1;
377   return 0;
378 }
379
380 gchar *
381 gst_oss_helper_get_card_name (const gchar * mixer_name)
382 {
383 #ifdef SOUND_MIXER_INFO
384   struct mixer_info minfo;
385 #endif
386   gint fd;
387   gchar *name = NULL;
388
389   GST_INFO ("Opening mixer for device %s", mixer_name);
390   fd = open (mixer_name, O_RDWR);
391   if (fd == -1)
392     goto open_failed;
393
394   /* get name, not fatal */
395 #ifdef SOUND_MIXER_INFO
396   if (ioctl (fd, SOUND_MIXER_INFO, &minfo) == 0) {
397     name = g_strdup (minfo.name);
398     GST_INFO ("Card name = %s", GST_STR_NULL (name));
399   } else
400 #endif
401   {
402     name = g_strdup ("Unknown");
403     GST_INFO ("Unknown card name");
404   }
405
406   close (fd);
407   return name;
408
409   /* ERRORS */
410 open_failed:
411   {
412     /* this is valid. OSS devices don't need to expose a mixer */
413     GST_DEBUG ("Failed to open mixer device %s, mixing disabled: %s",
414         mixer_name, strerror (errno));
415     return NULL;
416   }
417 }