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