#include #include #include #include #include #include #include typedef struct _Probe Probe; struct _Probe { int fd; int format; int n_channels; GArray *rates; int min; int max; }; typedef struct _Range Range; struct _Range { int min; int max; }; static gboolean probe_check (Probe * probe); static int check_rate (Probe * probe, int irate); static void add_range (GQueue * queue, int min, int max); static void add_rate (GArray * array, int rate); static int int_compare (gconstpointer a, gconstpointer b); int main (int argc, char *argv[]) { int fd; int i; Probe *probe; 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; probe->n_channels = 2; probe_check (probe); g_array_sort (probe->rates, int_compare); for (i = 0; i < probe->rates->len; i++) { g_print ("%d\n", g_array_index (probe->rates, int, i)); } g_array_free (probe->rates, TRUE); g_free (probe); #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; GQueue *ranges; int exact_rates = 0; gboolean checking_exact_rates = TRUE; int n_checks = 0; gboolean result = TRUE; ranges = g_queue_new (); probe->rates = g_array_new (FALSE, FALSE, sizeof (int)); probe->min = check_rate (probe, 1000); n_checks++; probe->max = check_rate (probe, 100000); n_checks++; 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; } } else { checking_exact_rates = FALSE; } /* Assume that the rate is arithmetically rounded to the nearest * supported rate. */ if (mid == mid_ret) { min1 = mid - 1; max1 = mid + 1; } else { if (mid < mid_ret) { min1 = mid - (mid_ret - mid); max1 = mid_ret + 1; } else { min1 = mid_ret - 1; max1 = mid + (mid - mid_ret); } } add_range (ranges, range->min, min1); add_range (ranges, max1, range->max); g_free (range); } while ((range = g_queue_pop_head (ranges))) { g_free (range); } g_queue_free (ranges); return result; } static void add_range (GQueue * queue, int min, int max) { g_print ("trying to add [%d,%d]\n", min, max); if (min <= max) { Range *range = g_new0 (Range, 1); range->min = min; range->max = max; g_queue_push_tail (queue, range); //g_queue_push_head (queue, range); } } 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; } add_rate (probe->rates, rate); 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); } 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; }