2004-12-16 11:34:54 +00:00
|
|
|
/* GStreamer
|
|
|
|
* Copyright (C) 2004 David Schleef
|
|
|
|
* 2004 Toni Willberg <toniw@iki.fi>
|
|
|
|
*
|
|
|
|
* oss_probe.c:
|
|
|
|
*
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Library General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2 of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* Library General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Library General Public
|
|
|
|
* License along with this library; if not, write to the
|
|
|
|
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
|
|
|
* Boston, MA 02111-1307, USA.
|
|
|
|
*/
|
2004-03-23 04:01:27 +00:00
|
|
|
|
2004-06-07 13:40:08 +00:00
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
#include "config.h"
|
|
|
|
#endif
|
|
|
|
|
2004-03-23 04:01:27 +00:00
|
|
|
#include <unistd.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <sys/ioctl.h>
|
|
|
|
#include <glib.h>
|
|
|
|
|
2004-06-07 13:40:08 +00:00
|
|
|
#ifdef HAVE_OSS_INCLUDE_IN_SYS
|
|
|
|
#include <sys/soundcard.h>
|
|
|
|
#else
|
|
|
|
|
|
|
|
#ifdef HAVE_OSS_INCLUDE_IN_ROOT
|
|
|
|
#include <soundcard.h>
|
|
|
|
#else
|
|
|
|
|
|
|
|
#include <machine/soundcard.h>
|
|
|
|
|
|
|
|
#endif /* HAVE_OSS_INCLUDE_IN_ROOT */
|
|
|
|
|
|
|
|
#endif /* HAVE_OSS_INCLUDE_IN_SYS */
|
|
|
|
|
2004-03-23 04:01:27 +00:00
|
|
|
typedef struct _Probe Probe;
|
|
|
|
struct _Probe
|
|
|
|
{
|
|
|
|
int fd;
|
|
|
|
int format;
|
|
|
|
int n_channels;
|
|
|
|
GArray *rates;
|
2004-03-23 04:42:57 +00:00
|
|
|
int min;
|
|
|
|
int max;
|
2004-03-23 04:01:27 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
typedef struct _Range Range;
|
|
|
|
struct _Range
|
|
|
|
{
|
|
|
|
int min;
|
|
|
|
int max;
|
|
|
|
};
|
|
|
|
|
|
|
|
static gboolean probe_check (Probe * probe);
|
|
|
|
static int check_rate (Probe * probe, int irate);
|
2004-03-23 04:42:57 +00:00
|
|
|
static void add_range (GQueue * queue, int min, int max);
|
2004-03-23 04:01:27 +00:00
|
|
|
static void add_rate (GArray * array, int rate);
|
2004-03-23 04:42:57 +00:00
|
|
|
static int int_compare (gconstpointer a, gconstpointer b);
|
2004-03-23 04:01:27 +00:00
|
|
|
|
|
|
|
int
|
|
|
|
main (int argc, char *argv[])
|
|
|
|
{
|
|
|
|
int fd;
|
2004-12-16 11:34:54 +00:00
|
|
|
int i, ret;
|
2004-03-23 04:01:27 +00:00
|
|
|
Probe *probe;
|
|
|
|
|
2004-12-16 11:34:54 +00:00
|
|
|
gboolean mono_supported = FALSE;
|
|
|
|
gboolean stereo_supported = FALSE;
|
|
|
|
|
2004-03-23 04:01:27 +00:00
|
|
|
fd = open ("/dev/dsp", O_RDWR);
|
|
|
|
if (fd < 0) {
|
|
|
|
perror ("/dev/dsp");
|
|
|
|
exit (1);
|
|
|
|
}
|
|
|
|
|
|
|
|
probe = g_new0 (Probe, 1);
|
|
|
|
probe->fd = fd;
|
|
|
|
probe->format = AFMT_S16_LE;
|
2004-12-16 11:34:54 +00:00
|
|
|
|
|
|
|
/* check if the device supports mono, stereo or both */
|
|
|
|
probe->n_channels = 1;
|
|
|
|
ret = ioctl (fd, SNDCTL_DSP_CHANNELS, &probe->n_channels);
|
|
|
|
if (probe->n_channels == 1)
|
|
|
|
mono_supported = TRUE;
|
|
|
|
|
2004-03-23 04:01:27 +00:00
|
|
|
probe->n_channels = 2;
|
2004-12-16 11:34:54 +00:00
|
|
|
ret = ioctl (fd, SNDCTL_DSP_CHANNELS, &probe->n_channels);
|
|
|
|
if (probe->n_channels == 2)
|
|
|
|
stereo_supported = TRUE;
|
|
|
|
|
|
|
|
if (mono_supported && stereo_supported) {
|
|
|
|
g_print ("The device supports mono and stereo.\n");
|
|
|
|
} else if (mono_supported) {
|
|
|
|
g_print ("The device supports only mono.\n");
|
|
|
|
} else if (stereo_supported) {
|
|
|
|
g_print ("The device supports only stereo.\n");
|
|
|
|
} else {
|
|
|
|
/* exit with error */
|
|
|
|
g_error
|
|
|
|
("The device doesn't support mono or stereo. This should not happen.\n");
|
|
|
|
}
|
2004-03-23 04:01:27 +00:00
|
|
|
|
|
|
|
probe_check (probe);
|
2004-03-23 04:42:57 +00:00
|
|
|
g_array_sort (probe->rates, int_compare);
|
2004-03-23 04:01:27 +00:00
|
|
|
for (i = 0; i < probe->rates->len; i++) {
|
|
|
|
g_print ("%d\n", g_array_index (probe->rates, int, i));
|
|
|
|
}
|
|
|
|
|
2004-03-23 04:42:57 +00:00
|
|
|
g_array_free (probe->rates, TRUE);
|
|
|
|
g_free (probe);
|
|
|
|
|
2004-03-23 04:01:27 +00:00
|
|
|
#if 0
|
|
|
|
probe = g_new0 (Probe, 1);
|
|
|
|
probe->fd = fd;
|
|
|
|
probe->format = AFMT_S16_LE;
|
|
|
|
probe->n_channels = 1;
|
|
|
|
|
|
|
|
probe_check (probe);
|
|
|
|
for (i = 0; i < probe->rates->len; i++) {
|
|
|
|
g_print ("%d\n", g_array_index (probe->rates, int, i));
|
|
|
|
}
|
|
|
|
|
|
|
|
probe = g_new0 (Probe, 1);
|
|
|
|
probe->fd = fd;
|
|
|
|
probe->format = AFMT_U8;
|
|
|
|
probe->n_channels = 2;
|
|
|
|
|
|
|
|
probe_check (probe);
|
|
|
|
for (i = 0; i < probe->rates->len; i++) {
|
|
|
|
g_print ("%d\n", g_array_index (probe->rates, int, i));
|
|
|
|
}
|
|
|
|
|
|
|
|
probe = g_new0 (Probe, 1);
|
|
|
|
probe->fd = fd;
|
|
|
|
probe->format = AFMT_U8;
|
|
|
|
probe->n_channels = 1;
|
|
|
|
|
|
|
|
probe_check (probe);
|
|
|
|
for (i = 0; i < probe->rates->len; i++) {
|
|
|
|
g_print ("%d\n", g_array_index (probe->rates, int, i));
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
probe_check (Probe * probe)
|
|
|
|
{
|
|
|
|
Range *range;
|
2004-03-23 04:42:57 +00:00
|
|
|
GQueue *ranges;
|
2004-03-23 04:01:27 +00:00
|
|
|
int exact_rates = 0;
|
|
|
|
gboolean checking_exact_rates = TRUE;
|
|
|
|
int n_checks = 0;
|
2004-03-23 04:42:57 +00:00
|
|
|
gboolean result = TRUE;
|
|
|
|
|
|
|
|
ranges = g_queue_new ();
|
2004-03-23 04:01:27 +00:00
|
|
|
|
|
|
|
probe->rates = g_array_new (FALSE, FALSE, sizeof (int));
|
|
|
|
|
2004-03-23 04:42:57 +00:00
|
|
|
probe->min = check_rate (probe, 1000);
|
2004-03-23 04:01:27 +00:00
|
|
|
n_checks++;
|
2004-03-23 04:42:57 +00:00
|
|
|
probe->max = check_rate (probe, 100000);
|
2004-03-23 04:01:27 +00:00
|
|
|
n_checks++;
|
2004-03-23 04:42:57 +00:00
|
|
|
add_range (ranges, probe->min + 1, probe->max - 1);
|
|
|
|
|
|
|
|
while ((range = g_queue_pop_head (ranges))) {
|
|
|
|
int min1;
|
|
|
|
int max1;
|
|
|
|
int mid;
|
|
|
|
int mid_ret;
|
|
|
|
|
|
|
|
g_print ("checking [%d,%d]\n", range->min, range->max);
|
|
|
|
|
|
|
|
mid = (range->min + range->max) / 2;
|
|
|
|
mid_ret = check_rate (probe, mid);
|
|
|
|
n_checks++;
|
|
|
|
|
|
|
|
if (mid == mid_ret && checking_exact_rates) {
|
|
|
|
int max_exact_matches = 100;
|
|
|
|
|
|
|
|
exact_rates++;
|
|
|
|
if (exact_rates > max_exact_matches) {
|
|
|
|
g_print ("got %d exact rates, assuming all are exact\n",
|
|
|
|
max_exact_matches);
|
|
|
|
result = FALSE;
|
|
|
|
g_free (range);
|
|
|
|
break;
|
2004-03-23 04:01:27 +00:00
|
|
|
}
|
2004-03-23 04:42:57 +00:00
|
|
|
} else {
|
|
|
|
checking_exact_rates = FALSE;
|
|
|
|
}
|
2004-03-23 04:01:27 +00:00
|
|
|
|
2004-03-23 04:42:57 +00:00
|
|
|
/* Assume that the rate is arithmetically rounded to the nearest
|
|
|
|
* supported rate. */
|
|
|
|
if (mid == mid_ret) {
|
|
|
|
min1 = mid - 1;
|
|
|
|
max1 = mid + 1;
|
|
|
|
} else {
|
2004-03-23 04:01:27 +00:00
|
|
|
if (mid < mid_ret) {
|
|
|
|
min1 = mid - (mid_ret - mid);
|
|
|
|
max1 = mid_ret + 1;
|
|
|
|
} else {
|
|
|
|
min1 = mid_ret - 1;
|
|
|
|
max1 = mid + (mid - mid_ret);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-03-23 04:42:57 +00:00
|
|
|
add_range (ranges, range->min, min1);
|
|
|
|
add_range (ranges, max1, range->max);
|
2004-03-23 04:01:27 +00:00
|
|
|
|
2004-03-23 04:42:57 +00:00
|
|
|
g_free (range);
|
2004-03-23 04:01:27 +00:00
|
|
|
}
|
|
|
|
|
2004-03-23 04:42:57 +00:00
|
|
|
while ((range = g_queue_pop_head (ranges))) {
|
|
|
|
g_free (range);
|
|
|
|
}
|
|
|
|
g_queue_free (ranges);
|
|
|
|
|
|
|
|
return result;
|
2004-03-23 04:01:27 +00:00
|
|
|
}
|
|
|
|
|
2004-03-23 04:42:57 +00:00
|
|
|
static void
|
|
|
|
add_range (GQueue * queue, int min, int max)
|
2004-03-23 04:01:27 +00:00
|
|
|
{
|
2004-03-23 04:42:57 +00:00
|
|
|
g_print ("trying to add [%d,%d]\n", min, max);
|
|
|
|
if (min <= max) {
|
|
|
|
Range *range = g_new0 (Range, 1);
|
2004-03-23 04:01:27 +00:00
|
|
|
|
2004-03-23 04:42:57 +00:00
|
|
|
range->min = min;
|
|
|
|
range->max = max;
|
2004-03-23 04:01:27 +00:00
|
|
|
|
2004-03-23 04:42:57 +00:00
|
|
|
g_queue_push_tail (queue, range);
|
|
|
|
//g_queue_push_head (queue, range);
|
|
|
|
}
|
2004-03-23 04:01:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
check_rate (Probe * probe, int irate)
|
|
|
|
{
|
|
|
|
int rate;
|
|
|
|
int format;
|
|
|
|
int n_channels;
|
|
|
|
|
|
|
|
rate = irate;
|
|
|
|
format = probe->format;
|
|
|
|
n_channels = probe->n_channels;
|
|
|
|
|
|
|
|
ioctl (probe->fd, SNDCTL_DSP_SETFMT, &format);
|
|
|
|
ioctl (probe->fd, SNDCTL_DSP_CHANNELS, &n_channels);
|
|
|
|
ioctl (probe->fd, SNDCTL_DSP_SPEED, &rate);
|
|
|
|
|
|
|
|
g_print ("rate %d -> %d\n", irate, rate);
|
|
|
|
|
|
|
|
if (rate == irate - 1 || rate == irate + 1) {
|
|
|
|
rate = irate;
|
|
|
|
}
|
2004-03-23 04:42:57 +00:00
|
|
|
add_rate (probe->rates, rate);
|
2004-03-23 04:01:27 +00:00
|
|
|
return rate;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
add_rate (GArray * array, int rate)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
int val;
|
|
|
|
|
|
|
|
for (i = 0; i < array->len; i++) {
|
|
|
|
val = g_array_index (array, int, i);
|
|
|
|
|
|
|
|
if (val == rate)
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
g_print ("supported rate: %d\n", rate);
|
|
|
|
g_array_append_val (array, rate);
|
|
|
|
}
|
2004-03-23 04:42:57 +00:00
|
|
|
|
|
|
|
static int
|
|
|
|
int_compare (gconstpointer a, gconstpointer b)
|
|
|
|
{
|
|
|
|
const int *va = (const int *) a;
|
|
|
|
const int *vb = (const int *) b;
|
|
|
|
|
|
|
|
if (*va < *vb)
|
|
|
|
return -1;
|
|
|
|
if (*va > *vb)
|
|
|
|
return 1;
|
|
|
|
return 0;
|
|
|
|
}
|