• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 
2 #ifdef HAVE_CONFIG_H
3 #include "config.h"
4 #endif
5 
6 
7 #include <unistd.h>
8 #include <fcntl.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <sys/ioctl.h>
12 #include <glib.h>
13 
14 #ifdef HAVE_OSS_INCLUDE_IN_SYS
15 # include <sys/soundcard.h>
16 #else
17 # ifdef HAVE_OSS_INCLUDE_IN_ROOT
18 #  include <soundcard.h>
19 # else
20 #  ifdef HAVE_OSS_INCLUDE_IN_MACHINE
21 #   include <machine/soundcard.h>
22 #  else
23 #   error "What to include?"
24 #  endif /* HAVE_OSS_INCLUDE_IN_MACHINE */
25 # endif /* HAVE_OSS_INCLUDE_IN_ROOT */
26 #endif /* HAVE_OSS_INCLUDE_IN_SYS */
27 
28 typedef struct _Probe Probe;
29 struct _Probe
30 {
31   int fd;
32   int format;
33   int n_channels;
34   GArray *rates;
35   int min;
36   int max;
37 };
38 
39 typedef struct _Range Range;
40 struct _Range
41 {
42   int min;
43   int max;
44 };
45 
46 static gboolean probe_check (Probe * probe);
47 static int check_rate (Probe * probe, int irate);
48 static void add_range (GQueue * queue, int min, int max);
49 static void add_rate (GArray * array, int rate);
50 static int int_compare (gconstpointer a, gconstpointer b);
51 
52 int
main(int argc,char * argv[])53 main (int argc, char *argv[])
54 {
55   int fd;
56   int i;
57   Probe *probe;
58 
59   fd = open ("/dev/dsp", O_RDWR);
60   if (fd < 0) {
61     perror ("/dev/dsp");
62     exit (1);
63   }
64 
65   probe = g_new0 (Probe, 1);
66   probe->fd = fd;
67   probe->format = AFMT_S16_LE;
68   probe->n_channels = 2;
69 
70   probe_check (probe);
71   g_array_sort (probe->rates, int_compare);
72   for (i = 0; i < probe->rates->len; i++) {
73     g_print ("%d\n", g_array_index (probe->rates, int, i));
74   }
75 
76   g_array_free (probe->rates, TRUE);
77   g_free (probe);
78 
79 #if 0
80   probe = g_new0 (Probe, 1);
81   probe->fd = fd;
82   probe->format = AFMT_S16_LE;
83   probe->n_channels = 1;
84 
85   probe_check (probe);
86   for (i = 0; i < probe->rates->len; i++) {
87     g_print ("%d\n", g_array_index (probe->rates, int, i));
88   }
89 
90   probe = g_new0 (Probe, 1);
91   probe->fd = fd;
92   probe->format = AFMT_U8;
93   probe->n_channels = 2;
94 
95   probe_check (probe);
96   for (i = 0; i < probe->rates->len; i++) {
97     g_print ("%d\n", g_array_index (probe->rates, int, i));
98   }
99 
100   probe = g_new0 (Probe, 1);
101   probe->fd = fd;
102   probe->format = AFMT_U8;
103   probe->n_channels = 1;
104 
105   probe_check (probe);
106   for (i = 0; i < probe->rates->len; i++) {
107     g_print ("%d\n", g_array_index (probe->rates, int, i));
108   }
109 #endif
110 
111   return 0;
112 }
113 
114 static gboolean
probe_check(Probe * probe)115 probe_check (Probe * probe)
116 {
117   Range *range;
118   GQueue *ranges;
119   int exact_rates = 0;
120   gboolean checking_exact_rates = TRUE;
121   int n_checks = 0;
122   gboolean result = TRUE;
123 
124   ranges = g_queue_new ();
125 
126   probe->rates = g_array_new (FALSE, FALSE, sizeof (int));
127 
128   probe->min = check_rate (probe, 1000);
129   n_checks++;
130   probe->max = check_rate (probe, 100000);
131   n_checks++;
132   add_range (ranges, probe->min + 1, probe->max - 1);
133 
134   while ((range = g_queue_pop_head (ranges))) {
135     int min1;
136     int max1;
137     int mid;
138     int mid_ret;
139 
140     g_print ("checking [%d,%d]\n", range->min, range->max);
141 
142     mid = (range->min + range->max) / 2;
143     mid_ret = check_rate (probe, mid);
144     n_checks++;
145 
146     if (mid == mid_ret && checking_exact_rates) {
147       int max_exact_matches = 100;
148 
149       exact_rates++;
150       if (exact_rates > max_exact_matches) {
151         g_print ("got %d exact rates, assuming all are exact\n",
152             max_exact_matches);
153         result = FALSE;
154         g_free (range);
155         break;
156       }
157     } else {
158       checking_exact_rates = FALSE;
159     }
160 
161     /* Assume that the rate is arithmetically rounded to the nearest
162      * supported rate. */
163     if (mid == mid_ret) {
164       min1 = mid - 1;
165       max1 = mid + 1;
166     } else {
167       if (mid < mid_ret) {
168         min1 = mid - (mid_ret - mid);
169         max1 = mid_ret + 1;
170       } else {
171         min1 = mid_ret - 1;
172         max1 = mid + (mid - mid_ret);
173       }
174     }
175 
176     add_range (ranges, range->min, min1);
177     add_range (ranges, max1, range->max);
178 
179     g_free (range);
180   }
181 
182   while ((range = g_queue_pop_head (ranges))) {
183     g_free (range);
184   }
185   g_queue_free (ranges);
186 
187   return result;
188 }
189 
190 static void
add_range(GQueue * queue,int min,int max)191 add_range (GQueue * queue, int min, int max)
192 {
193   g_print ("trying to add [%d,%d]\n", min, max);
194   if (min <= max) {
195     Range *range = g_new0 (Range, 1);
196 
197     range->min = min;
198     range->max = max;
199 
200     g_queue_push_tail (queue, range);
201     //g_queue_push_head (queue, range);
202   }
203 }
204 
205 static int
check_rate(Probe * probe,int irate)206 check_rate (Probe * probe, int irate)
207 {
208   int rate;
209   int format;
210   int n_channels;
211 
212   rate = irate;
213   format = probe->format;
214   n_channels = probe->n_channels;
215 
216   ioctl (probe->fd, SNDCTL_DSP_SETFMT, &format);
217   ioctl (probe->fd, SNDCTL_DSP_CHANNELS, &n_channels);
218   ioctl (probe->fd, SNDCTL_DSP_SPEED, &rate);
219 
220   g_print ("rate %d -> %d\n", irate, rate);
221 
222   if (rate == irate - 1 || rate == irate + 1) {
223     rate = irate;
224   }
225   add_rate (probe->rates, rate);
226   return rate;
227 }
228 
229 static void
add_rate(GArray * array,int rate)230 add_rate (GArray * array, int rate)
231 {
232   int i;
233   int val;
234 
235   for (i = 0; i < array->len; i++) {
236     val = g_array_index (array, int, i);
237 
238     if (val == rate)
239       return;
240   }
241   g_print ("supported rate: %d\n", rate);
242   g_array_append_val (array, rate);
243 }
244 
245 static int
int_compare(gconstpointer a,gconstpointer b)246 int_compare (gconstpointer a, gconstpointer b)
247 {
248   const int *va = (const int *) a;
249   const int *vb = (const int *) b;
250 
251   if (*va < *vb)
252     return -1;
253   if (*va > *vb)
254     return 1;
255   return 0;
256 }
257