source: contrib/API/lib/unipcm.c@ 742

Last change on this file since 742 was 541, checked in by David Azarewicz, 15 years ago

Initial import

File size: 32.5 KB
Line 
1/*
2 * This file is part of uniaud.dll.
3 *
4 * Copyright (c) 2010 Mensys BV
5 * Copyright (c) 2007 Vlad Stelmahovsky aka Vladest
6 *
7 * This library is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU Lesser General Public License as
9 * published by the Free Software Foundation, either version 3 of
10 * 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
15 * GNU Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License and the GNU General Public License along with this library.
19 * If not, see <http://www.gnu.org/licenses/>.
20 */
21#define INCL_DOS
22#define INCL_DOSERRORS
23#include <os2.h>
24#include <stdlib.h>
25#include <stdio.h>
26#include <string.h>
27
28#include "internal.h"
29#include "unidef.h"
30#include "resample.h"
31
32#define MAX_AUDIO_PACKET_SIZE (128 * 1024)
33
34#undef samples_to_bytes
35#undef bytes_to_samples
36#define samples_to_bytes(a) ((a*pcm->doublesamplesize)/2)
37#define bytes_to_samples(a) (pcm->doublesamplesize ? ((a*2)/pcm->doublesamplesize) : a)
38
39//#define FDUMP
40int uniaud_is_pcm_spdif(int card_id, int pcm_id);
41/*
42 * Refine hardware parameters from driver
43 */
44int _uniaud_pcm_refine_hw_params(uniaud_pcm *pcm, snd_pcm_hw_params_t *pparams)
45{
46 ioctl_pcm io_pcm = {0};
47 ULONG io_pcm_len, len;
48 APIRET rc = 0;
49
50 io_pcm.deviceid = pcm->uni_handle;
51
52 rc = DosDevIOCtl(pcm->uni_file, CAT_IOCTL_OSS32, IOCTL_OSS32_PCM_REFINEHWPARAMS,
53 &io_pcm, sizeof(io_pcm), &io_pcm_len,
54 pparams, sizeof(snd_pcm_hw_params_t), &len);
55 if (rc == NO_ERROR)
56 {
57 return io_pcm.ret;
58 } else
59 return UNIAUD_ERROR_IN_DRIVER;
60}
61
62/*
63 * Set hardware parameters to driver
64 */
65int _uniaud_pcm_set_hw_params(uniaud_pcm *pcm, snd_pcm_hw_params_t *pparams)
66{
67 ioctl_pcm io_pcm = {0};
68 ULONG io_pcm_len, len;
69 APIRET rc = 0;
70
71 io_pcm.deviceid = pcm->uni_handle;
72
73 rc = DosDevIOCtl(pcm->uni_file, CAT_IOCTL_OSS32, IOCTL_OSS32_PCM_SETHWPARAMS,
74 &io_pcm, sizeof(io_pcm), &io_pcm_len,
75 pparams, sizeof(snd_pcm_hw_params_t), &len);
76
77 if (rc == NO_ERROR) {
78 return io_pcm.ret;
79 } else return UNIAUD_ERROR_IN_DRIVER;
80}
81
82/*
83 * Set software parameters to driver
84 */
85int _uniaud_pcm_set_sw_params(uniaud_pcm *pcm, snd_pcm_sw_params_t *pparams)
86{
87 ioctl_pcm io_pcm = {0};
88 ULONG io_pcm_len, len;
89 APIRET rc = 0;
90
91 io_pcm.deviceid = pcm->uni_handle;
92
93 rc = DosDevIOCtl(pcm->uni_file, CAT_IOCTL_OSS32, IOCTL_OSS32_PCM_SETSWPARAMS,
94 &io_pcm, sizeof(io_pcm), &io_pcm_len,
95 pparams, sizeof(snd_pcm_sw_params_t), &len);
96 if (rc == NO_ERROR)
97 {
98 return io_pcm.ret;
99 } else
100 return UNIAUD_ERROR_IN_DRIVER;
101}
102
103#if 0
104static unsigned rates[] = {
105 /* ATTENTION: these values depend on the definition in pcm.h! */
106 5512, 8000, 11025, 16000, 22050, 32000, 44100, 48000,
107 64000, 88200, 96000, 176400, 192000
108};
109#endif
110
111int uniaud_pcm_set_params(uniaud_pcm *pcm, int channels, int sample_rate, int pcm_format)
112{
113 snd_pcm_hw_params_t params = {0};
114 snd_pcm_sw_params_t swparams = {0};
115 snd_pcm_sframes_t buffer_size;
116 snd_pcm_uframes_t period_size;
117 int period_bytes, period_bytes_max, period_bytes_min;
118 int need_resample = 0;
119 int is_spdif = 0;
120
121 int samplesize = uniaud_pcm_format_size(pcm_format, 1);
122
123 int periods, periods_min, periods_max;
124 int ret, ch_min, ch_max, err, srate_min, srate_max;
125 int SecondPass = 0;
126 int new_sample_rate, new_channels, new_format; // for resampling
127
128 //printf("channels=%i sample_rate=%i, pcm_format=%i samplesize=%i\n", channels, sample_rate, pcm_format, samplesize);
129
130 is_spdif = uniaud_is_pcm_spdif(pcm->card_id, pcm->instance);
131 if (is_spdif < 0) return is_spdif;
132
133 err = snd_pcm_hw_params_any(pcm, &params);
134 if (err < 0) {
135 printf("Broken configuration for playback: no configurations available: %i\n", err);
136 return err;
137 }
138
139 new_channels = channels;
140
141 ch_min = ((snd_interval_t*)hw_param_interval((&params), SNDRV_PCM_HW_PARAM_CHANNELS))->min;
142 ch_max = ((snd_interval_t*)hw_param_interval((&params), SNDRV_PCM_HW_PARAM_CHANNELS))->max;
143 srate_min = ((snd_interval_t*)hw_param_interval((&params), SNDRV_PCM_HW_PARAM_RATE))->min;
144 srate_max = ((snd_interval_t*)hw_param_interval((&params), SNDRV_PCM_HW_PARAM_RATE))->max;
145
146 if (pcm->type == PCM_TYPE_WRITE && ch_min > channels) {
147 need_resample = 1;
148 new_channels = ch_min;
149 }
150 if (pcm->type == PCM_TYPE_WRITE && ch_max > channels && channels == 5) {
151 channels = 6;
152 new_channels = 6;
153 }
154
155 if (DebugMode) {
156 printf("channels supported: %i to %i\n", ch_min, ch_max);
157 printf("sample rate supported: %i to %i\n", srate_min, srate_max);
158 }
159
160 new_sample_rate = sample_rate;
161
162 if (pcm->type == PCM_TYPE_WRITE && (srate_min == srate_max) && srate_min != sample_rate) {
163 new_sample_rate = srate_min;
164 need_resample = 1;
165 }
166
167 if (pcm->type == PCM_TYPE_WRITE && (sample_rate < srate_min || sample_rate > srate_max)) {
168 if (sample_rate > srate_max) new_sample_rate = srate_max;
169 else if (sample_rate < srate_min) new_sample_rate = srate_min;
170 need_resample = 1;
171 }
172
173 new_format = pcm_format;
174
175 if (pcm_format < SNDRV_PCM_FORMAT_S16_LE) {
176 new_format = SNDRV_PCM_FORMAT_S16_LE;
177 samplesize = uniaud_pcm_format_size(new_format, 1);
178 need_resample = 1;
179 }
180
181 if (DebugMode) printf("need_resample=%i new_sample_rate=%i new_format=%i\n", need_resample, new_sample_rate, new_format);
182
183 _snd_pcm_hw_param_set(&params, SNDRV_PCM_HW_PARAM_ACCESS, SNDRV_PCM_ACCESS_RW_INTERLEAVED, 0);
184
185 ret = _uniaud_pcm_refine_hw_params(pcm, &params);
186 if (ret != 0) {
187 printf("interleaved refine err: %i\n", ret);
188 return ret;
189 }
190
191 _snd_pcm_hw_param_set(&params, SNDRV_PCM_HW_PARAM_FORMAT, new_format, 0);
192 ret = _uniaud_pcm_refine_hw_params(pcm, &params);
193 if (ret != 0) {
194 printf("format refine err: %i, format: %i\n", ret, new_format);
195 return ret;
196 }
197
198 _snd_pcm_hw_param_set(&params, SNDRV_PCM_HW_PARAM_CHANNELS, new_channels, 0);
199 ret = _uniaud_pcm_refine_hw_params(pcm, &params);
200 if (ret != 0) {
201 printf("channels refine err: %i\n", ret);
202 return ret;
203 }
204
205 _snd_pcm_hw_param_set(&params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS, samplesize*8, 0);
206 ret = _uniaud_pcm_refine_hw_params(pcm, &params);
207 if (ret != 0) {
208 printf("sample bits refine err: %i\n", ret);
209 return ret;
210 }
211
212 _snd_pcm_hw_param_set(&params, SNDRV_PCM_HW_PARAM_FRAME_BITS, samplesize*new_channels*8, 0);
213 ret = _uniaud_pcm_refine_hw_params(pcm, &params);
214 if (ret != 0) {
215 printf("frame bits refine err: %i\n", ret);
216 return ret;
217 }
218
219 _snd_pcm_hw_param_set(&params, SNDRV_PCM_HW_PARAM_RATE, new_sample_rate, 0);
220
221 ret = _uniaud_pcm_refine_hw_params(pcm, &params);
222
223 if (ret != 0) {
224 printf("rate refine err: %i, %i, %i, %i, %i\n", ret, new_sample_rate, new_channels, samplesize, new_format);
225 return ret;
226 }
227
228 if (is_spdif) {
229 period_size = 6144/4; /*1536/4*/ /* spdif frame size */
230 } else {
231 period_size = new_sample_rate/64; //64 ints per sec
232 //((snd_interval_t*)hw_param_interval((&params), SNDRV_PCM_HW_PARAM_PERIOD_BYTES))->max;
233 period_size = (period_size + 63) & ~(63);
234 // align to channels number
235 if (pcm->type == PCM_TYPE_WRITE) period_size = ((period_size + 6)/6)*6;
236 }
237
238 period_bytes=period_size*uniaud_pcm_format_size(new_format, new_channels);
239 period_bytes_max = ((snd_interval_t*)hw_param_interval((&params), SNDRV_PCM_HW_PARAM_PERIOD_BYTES))->max;
240 //printf("period_bytes=%i period_bytes_max=%i\n", period_bytes, period_bytes_max);
241 if (period_bytes_max < period_bytes) {
242 period_bytes = period_bytes_max;
243 period_size = period_bytes/uniaud_pcm_format_size(new_format, new_channels);
244 }
245 period_bytes_min = ((snd_interval_t*)hw_param_interval((&params), SNDRV_PCM_HW_PARAM_PERIOD_BYTES))->min;
246 //printf("period_bytes=%i period_size=%i period_bytes_min=%i\n", period_bytes, period_size, period_bytes_min);
247 if (period_bytes < period_bytes_min) {
248 period_bytes = period_bytes_min;
249 period_size = period_bytes/uniaud_pcm_format_size(new_format, new_channels);
250 }
251 //buffer_size = period_size*8;
252 buffer_size = ((snd_interval_t*)hw_param_interval((&params), SNDRV_PCM_HW_PARAM_BUFFER_BYTES))->max;
253 //printf("period_bytes=%i period_size=%i buffer_size=%i\n", period_bytes, period_size, buffer_size);
254 if(period_bytes) {
255 periods = buffer_size/period_bytes;
256 }
257 periods_min = ((snd_interval_t*)hw_param_interval((&params), SNDRV_PCM_HW_PARAM_PERIODS))->min;
258 periods_max = ((snd_interval_t*)hw_param_interval((&params), SNDRV_PCM_HW_PARAM_PERIODS))->max;
259#if 0
260 if (periods > periods_max) {
261 periods = periods_max;
262 //buffer_size =
263 }
264#else
265 periods = periods_min*new_channels;
266 period_bytes = ((snd_interval_t*)hw_param_interval((&params), SNDRV_PCM_HW_PARAM_PERIOD_BYTES))->min;
267 period_bytes *=4;
268 period_size = period_bytes/uniaud_pcm_format_size(new_format, new_channels);
269#endif
270 periods &= ~1;
271 if (periods > 3) periods = ((periods - 3) /3) * 3;
272 if (!periods) periods = periods_min*new_channels;
273
274 if (DebugMode) {
275 printf("periods min = %i\n",periods_min);
276 printf("period_size = %i\n",period_size);
277 printf("period_bytes = %i\n",period_bytes);
278 printf("periods = %i\n",periods);
279 printf("buffer_size = %i\n",period_bytes*periods);
280 }
281
282again:
283 _snd_pcm_hw_params_any(&params);
284 _snd_pcm_hw_param_set(&params, SNDRV_PCM_HW_PARAM_ACCESS, SNDRV_PCM_ACCESS_RW_INTERLEAVED, 0);
285 _snd_pcm_hw_param_set(&params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS, samplesize*8, 0);
286 _snd_pcm_hw_param_set(&params, SNDRV_PCM_HW_PARAM_FRAME_BITS, samplesize*new_channels*8, 0);
287 _snd_pcm_hw_param_set(&params, SNDRV_PCM_HW_PARAM_FORMAT, new_format, 0);
288 _snd_pcm_hw_param_set(&params, SNDRV_PCM_HW_PARAM_CHANNELS, new_channels, 0);
289 _snd_pcm_hw_param_set(&params, SNDRV_PCM_HW_PARAM_RATE, new_sample_rate, 0);
290
291 _snd_pcm_hw_param_set(&params, SNDRV_PCM_HW_PARAM_PERIODS, periods, 0);
292 _snd_pcm_hw_param_set(&params, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, period_size*periods, 0);
293 _snd_pcm_hw_param_set(&params, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, period_bytes*periods, 0);
294 _snd_pcm_hw_param_set(&params, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, period_size, 0);
295 _snd_pcm_hw_param_set(&params, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, period_bytes, 0);
296
297 ret = _uniaud_pcm_set_hw_params(pcm, &params);
298
299 if (ret) printf("set_hw_params error %i\n", ret);
300
301 if (ret == -77) { /* bad state */
302 uniaud_pcm_prepare(pcm);
303 if (!SecondPass) {
304 SecondPass = TRUE;
305 goto again;
306 }
307 }
308
309 if (ret != 0) return ret;
310
311 //printf("bufsize: %i\n",buffer_size);
312
313 pcm->period_size = period_bytes;
314 pcm->bufsize = period_bytes*periods;
315 pcm->periods = periods;
316
317 if (pcm->type == PCM_TYPE_WRITE) {
318 swparams.avail_min = period_size;
319 swparams.period_step = 1;
320 if(periods <= 2)
321 swparams.silence_size = (period_size/2);
322 else
323 swparams.silence_size = period_size;
324
325 swparams.silence_threshold = swparams.silence_size;
326 swparams.sleep_min = 0;
327 swparams.start_threshold = 1;//period_size;
328 swparams.stop_threshold = period_size*periods;
329 swparams.tstamp_mode = SNDRV_PCM_TSTAMP_NONE;
330 swparams.xfer_align = period_size;
331 // swparams.boundary = buffer_size;
332 // while (swparams.boundary * 2 <= LONG_MAX - buffer_size)
333 // swparams.boundary *= 2;
334 ret = _uniaud_pcm_set_sw_params(pcm, &swparams);
335 if (ret) printf("set_sw_params error %i\n", ret);
336 }
337
338 if (need_resample) {
339 int resample_size;
340 pcm->resample = audio_resample_init(new_channels, channels, new_sample_rate, sample_rate);
341
342 if (!pcm->resample) ret = -UNIAUD_ERROR_RESAMPLE_INIT;
343
344 resample_size = (int)(((float)pcm->bufsize * pcm->resample->ratio)+1);
345 if (DebugMode) printf("resample: in: sr: %i, ch: %i, out: sr: %i, ch: %i, ratio: %f\n",
346 sample_rate, channels, new_sample_rate, new_channels, pcm->resample->ratio);
347 pcm->resample_buf = malloc(MAX_AUDIO_PACKET_SIZE*2);
348 if (!pcm->resample_buf) ret = -UNIAUD_ERROR_RESAMPLE_INIT;
349
350 pcm->orig_channels = channels;
351 pcm->orig_rate = sample_rate;
352 pcm->orig_format = pcm_format;
353 }
354
355 pcm->rate = new_sample_rate;
356 pcm->channels = new_channels;
357 pcm->format = new_format;
358
359 return ret;
360
361}
362
363int _uniaud_pcm_reinit(uniaud_pcm *pcm)
364{
365 snd_pcm_hw_params_t params = {0};
366 snd_pcm_sw_params_t swparams = {0};
367 int err, ret, period_size, samplesize;
368
369 if (!pcm) return -10000;
370
371 samplesize = uniaud_pcm_format_size(pcm->format, 1);
372 period_size = pcm->period_size/uniaud_pcm_format_size(pcm->format, pcm->channels);
373
374 err = uniaud_pcm_prepare(pcm);
375 if (err != 0) {
376 printf("reinit prepare error %i\n", err);
377 }
378
379 err = snd_pcm_hw_params_any(pcm, &params);
380 if (err < 0) {
381 printf("Broken configuration for playback: no configurations available: %i\n", err);
382 return err;
383 }
384
385 _snd_pcm_hw_param_set(&params, SNDRV_PCM_HW_PARAM_ACCESS,
386 SNDRV_PCM_ACCESS_RW_INTERLEAVED, 0);
387 _snd_pcm_hw_param_set(&params, SNDRV_PCM_HW_PARAM_FORMAT,
388 pcm->format, 0);
389 _snd_pcm_hw_param_set(&params, SNDRV_PCM_HW_PARAM_CHANNELS,
390 pcm->channels, 0);
391 _snd_pcm_hw_param_set(&params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS,
392 samplesize*8, 0);
393 _snd_pcm_hw_param_set(&params, SNDRV_PCM_HW_PARAM_FRAME_BITS,
394 samplesize*pcm->channels*8, 0);
395 _snd_pcm_hw_param_set(&params, SNDRV_PCM_HW_PARAM_RATE,
396 pcm->rate, 0);
397
398 ret = _uniaud_pcm_refine_hw_params(pcm, &params);
399
400 if (ret != 0)
401 {
402 printf("reinit refine err: %i\n", ret);
403 return ret;
404 }
405
406//again:
407 _snd_pcm_hw_params_any(&params);
408 _snd_pcm_hw_param_set(&params, SNDRV_PCM_HW_PARAM_ACCESS,
409 SNDRV_PCM_ACCESS_RW_INTERLEAVED, 0);
410 _snd_pcm_hw_param_set(&params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS,
411 samplesize*8, 0);
412 _snd_pcm_hw_param_set(&params, SNDRV_PCM_HW_PARAM_FRAME_BITS,
413 samplesize*pcm->channels*8, 0);
414 _snd_pcm_hw_param_set(&params, SNDRV_PCM_HW_PARAM_FORMAT,
415 pcm->format, 0);
416 _snd_pcm_hw_param_set(&params, SNDRV_PCM_HW_PARAM_CHANNELS,
417 pcm->channels, 0);
418 _snd_pcm_hw_param_set(&params, SNDRV_PCM_HW_PARAM_RATE,
419 pcm->rate, 0);
420
421 _snd_pcm_hw_param_set(&params, SNDRV_PCM_HW_PARAM_PERIODS,
422 pcm->periods, 0);
423 _snd_pcm_hw_param_set(&params, SNDRV_PCM_HW_PARAM_BUFFER_SIZE,
424 period_size*pcm->periods, 0);
425 _snd_pcm_hw_param_set(&params, SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
426 pcm->period_size*pcm->periods, 0);
427 _snd_pcm_hw_param_set(&params, SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
428 period_size, 0);
429 _snd_pcm_hw_param_set(&params, SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
430 pcm->period_size, 0);
431
432 ret = _uniaud_pcm_set_hw_params(pcm, &params);
433
434 if (ret != 0)
435 {
436 printf("reinit hw set err3: %i\n", ret);
437 return ret;
438 }
439
440 if (pcm->type == PCM_TYPE_WRITE)
441 {
442 swparams.avail_min = pcm->period_size;
443 swparams.period_step = 1;
444 if(pcm->periods <= 2)
445 swparams.silence_size = (pcm->period_size/2);
446 else
447 swparams.silence_size = pcm->period_size;
448
449 swparams.silence_threshold = swparams.silence_size;
450 swparams.sleep_min = 0;
451 swparams.start_threshold = 1;//period_size;
452 swparams.stop_threshold = pcm->period_size*pcm->periods;
453 swparams.tstamp_mode = SNDRV_PCM_TSTAMP_NONE;
454 swparams.xfer_align = pcm->period_size;
455 // swparams.boundary = buffer_size;
456 // while (swparams.boundary * 2 <= LONG_MAX - buffer_size)
457 // swparams.boundary *= 2;
458 ret = _uniaud_pcm_set_sw_params(pcm, &swparams);
459 if (ret !=0) printf("set_sw_params error: %i\n", ret);
460 }
461 err = uniaud_pcm_prepare(pcm);
462 if (err != 0) {
463 printf("reinit prepare error %i\n", err);
464 }
465
466 return ret;
467}
468
469int uniaud_close_all_pcms_16(void);
470
471int _uniaud_pcm_open(int card_id, int type, int pcm_instance, int access_flag,
472 int sample_rate, int channels, int pcm_format,
473 uniaud_pcm **pcm)
474{
475 HFILE hFile = 0;
476 uniaud_pcm *pcm_l = NULL;
477 ioctl_pcm io_pcm = {0};
478 ULONG io_pcm_len, len;
479 APIRET rc = 0;
480
481 /* checking cards range */
482 if (card_id < 0 || card_id >= cards_num) // counting cards from 0
483 return -UNIAUD_INVALID_CARD;
484
485 pcm_l = malloc(sizeof(uniaud_pcm));
486
487 if (!pcm_l)
488 return -UNIAUD_MEMORY_ERROR;
489
490 memset(pcm_l, 0, sizeof(uniaud_pcm));
491
492 /*
493 filling ioctl structure
494 */
495 io_pcm.deviceid = card_id;
496 io_pcm.streamtype = type;
497 io_pcm.pcm = pcm_instance;
498
499 if ((int)(hFile = DriverOpen()) >= 0)
500 {
501 rc = DosDevIOCtl(hFile, CAT_IOCTL_OSS32, IOCTL_OSS32_PCM_OPEN,
502 &io_pcm, sizeof(io_pcm), &io_pcm_len,
503 &pcm_l->uni_handle, sizeof(pcm_l->uni_handle), &len);
504 if (rc == NO_ERROR) { /* all ok */
505 if ((int)io_pcm.ret == 0) {
506 UniInst[card_id].opened_flag++;
507 pcm_l->card_id = card_id;
508 pcm_l->type = type;
509 pcm_l->uni_file = hFile;
510 pcm_l->format = pcm_format;
511 pcm_l->instance = pcm_instance;
512 if (!uniaud_pcm_set_params(pcm_l, channels, sample_rate, pcm_format)) {
513 if (pcm) {
514 pcm_l->multi_buf = malloc(pcm_l->bufsize);
515 *pcm = (void *)pcm_l;
516 }
517 return io_pcm.ret;
518 } else {
519 uniaud_pcm_close(pcm_l);
520 return -UNIAUD_ERROR_INVALID_PCM_PARAMS;
521 }
522 } else {
523 printf("ret=%i\n", (int)io_pcm.ret);
524 DosClose(hFile);
525 return -UNIAUD_PCM_OPEN_ERROR;
526 }
527 } else {
528 DosClose(hFile);
529 return -UNIAUD_ERROR_IN_DRIVER;
530 }
531 } else
532 return -UNIAUD_ALSA32OPEN_ERROR;
533}
534
535static inline uint32_t load24bit(void* data, int pos) {
536#if WORDS_BIGENDIAN
537 return (((uint32_t)((uint8_t*)data)[3*pos])<<24) |
538 (((uint32_t)((uint8_t*)data)[3*pos+1])<<16) |
539 (((uint32_t)((uint8_t*)data)[3*pos+2])<<8);
540#else
541 return (((uint32_t)((uint8_t*)data)[3*pos])<<8) |
542 (((uint32_t)((uint8_t*)data)[3*pos+1])<<16) |
543 (((uint32_t)((uint8_t*)data)[3*pos+2])<<24);
544#endif
545}
546
547static inline void store24bit(void* data, int pos, uint32_t expanded_value) {
548#if WORDS_BIGENDIAN
549 ((uint8_t*)data)[3*pos]=expanded_value>>24;
550 ((uint8_t*)data)[3*pos+1]=expanded_value>>16;
551 ((uint8_t*)data)[3*pos+2]=expanded_value>>8;
552#else
553 ((uint8_t*)data)[3*pos]=expanded_value>>8;
554 ((uint8_t*)data)[3*pos+1]=expanded_value>>16;
555 ((uint8_t*)data)[3*pos+2]=expanded_value>>24;
556#endif
557}
558
559
560static void change_bps(void* in, void* out, int len, int inbps, int outbps)
561{
562 register int i;
563 switch(inbps){
564 case(1):
565 switch(outbps){
566 case(2):
567 for(i=0;i<len;i++)
568 ((uint16_t*)out)[i]=((uint16_t)((uint8_t*)in)[i] - 0x80)<<8;
569 break;
570 case(3):
571 for(i=0;i<len;i++)
572 store24bit(out, i, ((uint32_t)((uint8_t*)in)[i])<<24);
573 break;
574 case(4):
575 for(i=0;i<len;i++)
576 ((uint32_t*)out)[i]=((uint32_t)((uint8_t*)in)[i])<<24;
577 break;
578 }
579 break;
580 case(2):
581 switch(outbps){
582 case(1):
583 for(i=0;i<len;i++)
584 ((uint8_t*)out)[i]=(uint8_t)((((uint16_t*)in)[i])>>8);
585 break;
586 case(3):
587 for(i=0;i<len;i++)
588 store24bit(out, i, ((uint32_t)((uint16_t*)in)[i])<<16);
589 break;
590 case(4):
591 for(i=0;i<len;i++)
592 ((uint32_t*)out)[i]=((uint32_t)((uint16_t*)in)[i])<<16;
593 break;
594 }
595 break;
596 case(3):
597 switch(outbps){
598 case(1):
599 for(i=0;i<len;i++)
600 ((uint8_t*)out)[i]=(uint8_t)(load24bit(in, i)>>24);
601 break;
602 case(2):
603 for(i=0;i<len;i++)
604 ((uint16_t*)out)[i]=(uint16_t)(load24bit(in, i)>>16);
605 break;
606 case(4):
607 for(i=0;i<len;i++)
608 ((uint32_t*)out)[i]=(uint32_t)load24bit(in, i);
609 break;
610 }
611 break;
612 case(4):
613 switch(outbps){
614 case(1):
615 for(i=0;i<len;i++)
616 ((uint8_t*)out)[i]=(uint8_t)((((uint32_t*)in)[i])>>24);
617 break;
618 case(2):
619 for(i=0;i<len;i++)
620 ((uint16_t*)out)[i]=(uint16_t)((((uint32_t*)in)[i])>>16);
621 break;
622 case(3):
623 for(i=0;i<len;i++)
624 store24bit(out, i, ((uint32_t*)in)[i]);
625 break;
626 }
627 break;
628 }
629}
630
631static int tot_ret = 0;
632
633int _uniaud_pcm_write(uniaud_pcm *pcm, char* buffer, int size)
634{
635 ioctl_pcm io_pcm = {0};
636 ULONG io_pcm_len, len;
637 APIRET rc = 0;
638 int samplesize, orig_samplesize;
639 int wsize, ret_size, in_size, out_size;
640 static float divider;
641 char *buf = NULL;
642
643 if (!pcm || !buffer || size <= 0/* || size >= (64*1024-1)*/)
644 return -UNIAUD_ERROR_INVALID_PCM_PARAMS;
645
646 if (pcm->resample) {
647#if 1
648 if (pcm->orig_format && (pcm->orig_format != pcm->format)) {
649 buf = pcm->resample_buf + MAX_AUDIO_PACKET_SIZE;
650 if (buf) {
651 in_size = uniaud_pcm_format_size(pcm->orig_format, 1);
652 out_size = uniaud_pcm_format_size(pcm->format, 1);
653 change_bps(buffer, buf, size, in_size, out_size);
654 //printf("bps: in %i -> out %i\n",in_size, out_size);
655 }
656 }
657#endif
658 orig_samplesize = uniaud_pcm_format_size(pcm->format, pcm->orig_channels);
659 samplesize = uniaud_pcm_format_size(pcm->format, pcm->channels);
660 if (pcm->resample_size == 0) {
661 //printf("format: %i, orig format: %i chans: %i, ssize: %i\n",pcm->format, pcm->orig_format,
662 // pcm->channels, samplesize);fflush(stdout);
663 if (!buf) {
664 pcm->resample_size = audio_resample(pcm->resample,
665 (short *)pcm->resample_buf,
666 (short *)buffer, size/orig_samplesize);
667 } else {
668 pcm->resample_size = audio_resample(pcm->resample,
669 (short *)pcm->resample_buf,
670 (short *)buf, (size*(out_size/in_size))/orig_samplesize);
671 //free(buf);
672 }
673 pcm->resample_size *= samplesize;
674 pcm->resample_written = 0;
675 tot_ret = 0;
676 divider = (float)pcm->resample_size/(float)size;
677 //if (divider < 1.0f)
678 // divider = 2.0f;
679 // printf("res size: %i, size: %i, divider %f\n",pcm->resample_size, size, divider);
680 }
681
682 io_pcm_len = sizeof(io_pcm);
683 //while(written < out_samples)
684 {
685 memset(&io_pcm,0,sizeof(io_pcm));
686 wsize = pcm->resample_size-pcm->resample_written;
687 //if (wsize > pcm->period_size) wsize = pcm->period_size;
688 if (wsize > pcm->bufsize || wsize <= 0)
689 wsize = pcm->bufsize;
690 io_pcm.deviceid = pcm->uni_handle;
691 io_pcm.size = wsize;
692 len = wsize;
693
694
695 rc = DosDevIOCtl(pcm->uni_file, CAT_IOCTL_OSS32, IOCTL_OSS32_PCM_WRITE,
696 &io_pcm, sizeof(io_pcm), &io_pcm_len,
697 pcm->resample_buf+pcm->resample_written, wsize, &len);
698
699 if (rc == NO_ERROR) {
700 if ((int)io_pcm.ret > 0) {
701 int shift;
702 pcm->resample_written += (int)io_pcm.ret;//out_samples; //??????
703 ret_size = (int)((float)io_pcm.ret/divider);
704 shift = ret_size % orig_samplesize;
705 if (shift != 0) {
706 //printf("shift by: %i bytes\n", shift);
707 ret_size = ret_size - shift + orig_samplesize; // correcting
708 }
709 tot_ret +=ret_size;
710 //printf("phys ret: %i size: %i, ret: %i total ret = %i\r",(int)io_pcm.ret, size, ret_size, tot_ret);fflush(stdout);
711 if (pcm->resample_written >= pcm->resample_size) {
712 pcm->resample_size = 0; // whole resample buffer written
713 }
714 return ret_size;
715 //_uniaud_pcm_wait(pcm, 1000);
716 } else {
717 //if ((int)io_pcm.ret == -11)
718 // continue;
719 //return (int)io_pcm.ret;
720 return pcm->resample_written > 0 ? pcm->resample_written : (int)io_pcm.ret;
721 }
722 } else {
723 // printf("rc=%i, pcm len: %i, ret len %i\n", rc, sizeof(io_pcm), io_pcm_len);
724 // printf("data len: %i, ret len %i\n", size, len);
725 return -UNIAUD_ERROR_IN_DRIVER;
726 }
727 }// while
728 // printf("input size: %i, out size: %i, written: %i\n", size, out_samples, written);
729 return size;
730 } else {
731 io_pcm.deviceid = pcm->uni_handle;
732 io_pcm.size = size;
733 io_pcm_len = sizeof(io_pcm);
734 len = size;
735
736 rc = DosDevIOCtl(pcm->uni_file, CAT_IOCTL_OSS32, IOCTL_OSS32_PCM_WRITE,
737 &io_pcm, sizeof(io_pcm), &io_pcm_len,
738 buffer, size, &len);
739 if (rc == NO_ERROR)
740 return io_pcm.ret;
741 else {
742 // printf("rc=%i, pcm len: %i, ret len %i\n", rc, sizeof(io_pcm), io_pcm_len);
743 // printf("data len: %i, ret len %i\n", size, len);
744 return -UNIAUD_ERROR_IN_DRIVER;
745 }
746 }
747}
748
749int uniaud_pcm_read(uniaud_pcm *pcm, char* buffer, int size)
750{
751 ioctl_pcm io_pcm = {0};
752 ULONG io_pcm_len, len;
753 APIRET rc = 0;
754
755 if (!pcm || !buffer || size <= 0)
756 return -UNIAUD_ERROR_INVALID_PCM_PARAMS;
757
758 io_pcm.deviceid = pcm->uni_handle;
759 io_pcm.size = size;
760
761 rc = DosDevIOCtl(pcm->uni_file, CAT_IOCTL_OSS32, IOCTL_OSS32_PCM_READ,
762 &io_pcm, sizeof(io_pcm), &io_pcm_len,
763 buffer, size, &len);
764
765 if (rc == NO_ERROR)
766 return io_pcm.ret;
767 else
768 return -UNIAUD_ERROR_IN_DRIVER;
769}
770
771int _uniaud_pcm_prepare(uniaud_pcm *pcm)
772{
773 ioctl_pcm io_pcm = {0};
774 ULONG io_pcm_len;
775 APIRET rc = 0;
776
777 if (!pcm)
778 return -UNIAUD_ERROR_INVALID_PCM_PARAMS;
779
780 io_pcm.deviceid = pcm->uni_handle;
781
782 rc = DosDevIOCtl(pcm->uni_file, CAT_IOCTL_OSS32, IOCTL_OSS32_PCM_PREPARE,
783 &io_pcm, sizeof(io_pcm), &io_pcm_len,
784 NULL, 0, NULL);
785 if (rc == NO_ERROR)
786 return io_pcm.ret;
787 else
788 return -UNIAUD_ERROR_IN_DRIVER;
789}
790
791int _uniaud_pcm_start(uniaud_pcm *pcm)
792{
793 ioctl_pcm io_pcm = {0};
794 ULONG io_pcm_len;
795 APIRET rc = 0;
796
797 if (!pcm)
798 return -UNIAUD_ERROR_INVALID_PCM_PARAMS;
799
800 io_pcm.deviceid = pcm->uni_handle;
801
802 rc = DosDevIOCtl(pcm->uni_file, CAT_IOCTL_OSS32, IOCTL_OSS32_PCM_START,
803 &io_pcm, sizeof(io_pcm), &io_pcm_len,
804 NULL, 0, NULL);
805 if (rc == NO_ERROR)
806 return io_pcm.ret;
807 else
808 return -UNIAUD_ERROR_IN_DRIVER;
809}
810
811int _uniaud_pcm_drop(uniaud_pcm *pcm)
812{
813 ioctl_pcm io_pcm = {0};
814 ULONG io_pcm_len;
815 APIRET rc = 0;
816
817 if (!pcm)
818 return -UNIAUD_ERROR_INVALID_PCM_PARAMS;
819
820 io_pcm.deviceid = pcm->uni_handle;
821
822 rc = DosDevIOCtl(pcm->uni_file, CAT_IOCTL_OSS32, IOCTL_OSS32_PCM_DROP,
823 &io_pcm, sizeof(io_pcm), &io_pcm_len,
824 NULL, 0, NULL);
825 //printf("drop ret: %i\n", io_pcm.ret);
826 if (rc == NO_ERROR)
827 return io_pcm.ret;
828 else
829 return -UNIAUD_ERROR_IN_DRIVER;
830}
831
832int _uniaud_pcm_resume(uniaud_pcm *pcm)
833{
834 ioctl_pcm io_pcm = {0};
835 ULONG io_pcm_len;
836 APIRET rc = 0;
837
838 if (!pcm)
839 return -UNIAUD_ERROR_INVALID_PCM_PARAMS;
840
841 io_pcm.deviceid = pcm->uni_handle;
842
843 rc = DosDevIOCtl(pcm->uni_file, CAT_IOCTL_OSS32, IOCTL_OSS32_PCM_RESUME,
844 &io_pcm, sizeof(io_pcm), &io_pcm_len,
845 NULL, 0, NULL);
846 if (rc == NO_ERROR)
847 return io_pcm.ret;
848 else
849 return -UNIAUD_ERROR_IN_DRIVER;
850}
851
852int _uniaud_pcm_pause(uniaud_pcm *pcm)
853{
854 ioctl_pcm io_pcm = {0};
855 ULONG io_pcm_len;
856 APIRET rc = 0;
857
858 if (!pcm)
859 return -UNIAUD_ERROR_INVALID_PCM_PARAMS;
860
861 io_pcm.deviceid = pcm->uni_handle;
862
863 rc = DosDevIOCtl(pcm->uni_file, CAT_IOCTL_OSS32, IOCTL_OSS32_PCM_PAUSE,
864 &io_pcm, sizeof(io_pcm), &io_pcm_len,
865 NULL, 0, NULL);
866 if (rc == NO_ERROR)
867 return io_pcm.ret;
868 else
869 return -UNIAUD_ERROR_IN_DRIVER;
870}
871
872int uniaud_pcm_status(uniaud_pcm *pcm, snd_pcm_status_t *status)
873{
874 ioctl_pcm io_pcm = {0};
875 ULONG io_pcm_len, len;
876 APIRET rc = 0;
877
878 if (!pcm || !status)
879 return -UNIAUD_ERROR_INVALID_PCM_PARAMS;
880
881 io_pcm.deviceid = pcm->uni_handle;
882
883 rc = DosDevIOCtl(pcm->uni_file, CAT_IOCTL_OSS32, IOCTL_OSS32_PCM_STATUS,
884 &io_pcm, sizeof(io_pcm), &io_pcm_len,
885 status, sizeof(snd_pcm_status_t), &len);
886 if (rc == NO_ERROR)
887 return io_pcm.ret;
888 else
889 return -UNIAUD_ERROR_IN_DRIVER;
890}
891
892int uniaud_pcm_state(uniaud_pcm *pcm)
893{
894 snd_pcm_status_t status;
895
896 if (uniaud_pcm_status(pcm, &status) == 0)
897 return status.state;
898 else
899 return -UNIAUD_ERROR_INVALID_PCM_PARAMS;
900}
901
902/* wait for interrupt from pcm */
903int _uniaud_pcm_wait(uniaud_pcm *pcm, int timeout)
904{
905 ioctl_pcm io_pcm = {0};
906 ULONG io_pcm_len;
907 APIRET rc = 0;
908 APIRET rc1 = 0;
909 PTIB ptib = NULL; /* Thread information block structure */
910 PPIB ppib = NULL; /* Process information block structure */
911 int prio_class = 2, prio_delta = 0;
912
913 if (!pcm)
914 return -UNIAUD_ERROR_INVALID_PCM_PARAMS;
915
916 io_pcm.deviceid = pcm->uni_handle;
917 io_pcm.streamtype = timeout;
918
919 /*
920 we have to temporary set priority to timecritical
921 for precesiouse clock ticks
922 */
923 rc1 = DosGetInfoBlocks(&ptib, &ppib);
924
925 if (rc1 == NO_ERROR)
926 {
927 // get current priority
928 DosSetPriority (PRTYS_THREAD, PRTYC_TIMECRITICAL, 31L, 0L);
929 prio_class = ((ptib->tib_ptib2->tib2_ulpri) >> 8) & 0x00FF;
930 prio_delta = (ptib->tib_ptib2->tib2_ulpri) & 0x001F;
931 if (!prio_delta) prio_delta = -31; /* stupid workaround */
932 }
933
934 rc = DosDevIOCtl(pcm->uni_file, CAT_IOCTL_OSS32, IOCTL_OSS32_PCM_WAIT_INT,
935 &io_pcm, sizeof(io_pcm), &io_pcm_len,
936 NULL, 0, NULL);
937
938 // return current priority back
939 if (rc1 == NO_ERROR)
940 DosSetPriority (PRTYS_THREAD, prio_class, prio_delta, 0L);
941
942 if (rc == NO_ERROR) {
943 //printf("wait ret=%i\n", io_pcm.ret);
944 return io_pcm.ret;
945 } else {
946 //printf("wait rc=%i\n", rc);
947 return -UNIAUD_ERROR_IN_DRIVER;
948 }
949}
950
951int _uniaud_pcm_close(uniaud_pcm *pcm)
952{
953 ULONG len;
954 APIRET rc = 0;
955 int card_id;
956
957 if (pcm) {
958 card_id = pcm->card_id;
959
960 rc = DosDevIOCtl(pcm->uni_file, CAT_IOCTL_OSS32, IOCTL_OSS32_PCM_CLOSE,
961 &pcm->uni_handle, sizeof(pcm->uni_handle), &len,
962 NULL, 0, NULL);
963 DosClose(pcm->uni_file);
964 if (rc != NO_ERROR)
965 return -UNIAUD_ERROR_IN_DRIVER;
966
967 UniInst[card_id].opened_flag--;
968
969 if (pcm->multi_buf)
970 free(pcm->multi_buf);
971 if (pcm->resample)
972 audio_resample_close(pcm->resample);
973
974 free(pcm);
975 return UNIAUD_NO_ERROR;
976 }
977 return UNIAUD_NO_ERROR;
978}
979
980int uniaud_close_all_pcms(int unlock)
981{
982 HFILE hFile = 0;
983 ULONG len;
984 APIRET rc = 0;
985
986 if ((int)(hFile = DriverOpen()) >= 0) {
987 rc = DosDevIOCtl(hFile, CAT_IOCTL_OSS32, IOCTL_OSS32_PCM_CLOSE_ALL,
988 &unlock, sizeof(unlock), &len,
989 NULL, 0, NULL);
990 DosClose(hFile);
991 if (rc != NO_ERROR)
992 return -UNIAUD_ERROR_IN_DRIVER;
993 } else return -UNIAUD_ALSA32OPEN_ERROR;
994
995 return UNIAUD_NO_ERROR;
996}
997
998int uniaud_close_all_pcms_16(void)
999{
1000 HFILE hFile = 0;
1001 //ULONG len;
1002 APIRET rc = 0;
1003
1004 if ((int)(hFile = DriverOpen()) >= 0) {
1005 rc = DosDevIOCtl(hFile, CAT_IOCTL_OSS32, IOCTL_OSS32_PCM_CLOSE_16,
1006 NULL, 0, NULL,
1007 NULL, 0, NULL);
1008 DosClose(hFile);
1009 if (rc != NO_ERROR)
1010 return -UNIAUD_ERROR_IN_DRIVER;
1011 } else
1012 return -UNIAUD_ALSA32OPEN_ERROR;
1013
1014 return UNIAUD_NO_ERROR;
1015}
1016
1017int uniaud_get_pcm_instances(int card_id)
1018{
1019 HFILE hFile = 0;
1020 //ULONG usAction;
1021 ULONG len;
1022 ULONG id_len;
1023 ULONG rc;
1024 int pcms = 0;
1025
1026 /* checking cards range */
1027 if (card_id < 0 || card_id >= cards_num) // counting cards from 0
1028 return -UNIAUD_INVALID_CARD;
1029
1030 if ((int)(hFile = DriverOpen()) >= 0) {
1031 rc = DosDevIOCtl(hFile, CAT_IOCTL_OSS32, IOCTL_OSS32_GET_PCM_NUM,
1032 &card_id, sizeof(card_id), &id_len,
1033 &pcms, sizeof(pcms), &len);
1034 DosClose(hFile);
1035 if (rc != 0)
1036 return -UNIAUD_ERROR_IN_DRIVER;
1037
1038 return pcms;
1039 }
1040 else
1041 return -UNIAUD_ALSA32OPEN_ERROR;
1042}
1043
1044int uniaud_pcm_get_caps(int card_id, POSS32_DEVCAPS pcaps)
1045{
1046 HFILE hFile = 0;
1047 //ULONG usAction;
1048 ULONG len;
1049 ULONG id_len;
1050 ULONG rc;
1051
1052 /* checking cards range */
1053 if (card_id < 0 || card_id >= cards_num) // counting cards from 0
1054 return -UNIAUD_INVALID_CARD;
1055
1056 if (!pcaps)
1057 return -UNIAUD_INVALID_PARAMETER;
1058
1059 if ((int)(hFile = DriverOpen()) >= 0) {
1060 rc = DosDevIOCtl(hFile, CAT_IOCTL_OSS32, IOCTL_OSS32_PCM_CAPS,
1061 &card_id, sizeof(card_id), &id_len,
1062 &pcaps, sizeof(pcaps), &len);
1063 DosClose(hFile);
1064 if (rc != 0)
1065 return -UNIAUD_ERROR_IN_DRIVER;
1066
1067 return UNIAUD_NO_ERROR;
1068 }
1069 else
1070 return -UNIAUD_ALSA32OPEN_ERROR;
1071}
1072
1073int uniaud_pcm_find_pcm_for_chan(POSS32_DEVCAPS pcaps, int pcms, int type, int channels)
1074{
1075 int i;
1076 POSS32_DEVCAPS pcaps1 = pcaps;
1077 WAVE_CAPS *wc;
1078 int sel_pcm = -1;
1079
1080 if (!pcaps || pcms <= 0) return -UNIAUD_INVALID_PARAMETER;
1081
1082 for (i=0; i<pcms;i++) {
1083 switch(type) {
1084 case 0: // play
1085 wc = &pcaps1->waveOutCaps;
1086 break;
1087 case 1: // record
1088 wc = &pcaps1->waveInCaps;
1089 break;
1090 }
1091 if (wc->ulMaxChannels >= channels) {
1092 sel_pcm = i;
1093 break;
1094 }
1095 pcaps1++;
1096 }
1097
1098 if (sel_pcm == -1) return -UNIAUD_INVALID_PARAMETER;
1099
1100 return sel_pcm;
1101}
1102
1103int uniaud_pcm_find_max_chan(POSS32_DEVCAPS pcaps, int pcms, int type)
1104{
1105 int i;
1106 POSS32_DEVCAPS pcaps1 = pcaps;
1107 WAVE_CAPS *wc;
1108 int max_chan = 0;
1109
1110 if (!pcaps || pcms <= 0) return -UNIAUD_INVALID_PARAMETER;
1111
1112 for (i=0; i<pcms;i++) {
1113 switch(type) {
1114 case 0: // play
1115 wc = &pcaps1->waveOutCaps;
1116 break;
1117 case 1: // record
1118 wc = &pcaps1->waveInCaps;
1119 break;
1120 }
1121 if (wc->ulMaxChannels > max_chan)
1122 max_chan = wc->ulMaxChannels;
1123 pcaps1++;
1124 }
1125
1126 return max_chan;
1127}
1128
1129int uniaud_pcm_set_pcm(int pcm)
1130{
1131 //int i;
1132 HFILE hFile = 0;
1133 //ULONG usAction;
1134 ULONG len;
1135 ULONG rc;
1136
1137 if (pcm < 0) return -UNIAUD_INVALID_PARAMETER;
1138
1139
1140 if ((int)(hFile = DriverOpen()) >= 0) {
1141 len = sizeof(pcm);
1142 rc = DosDevIOCtl(hFile, CAT_IOCTL_OSS32, IOCTL_OSS32_SET_PCM,
1143 &pcm, sizeof(pcm), &len, NULL, 0, NULL);
1144 DosClose(hFile);
1145 if (rc != 0)
1146 return -UNIAUD_ERROR_IN_DRIVER;
1147 }
1148 return UNIAUD_NO_ERROR;
1149}
1150
Note: See TracBrowser for help on using the repository browser.