source: trunk/third/esound/audio_osf.c @ 20226

Revision 20226, 11.0 KB checked in by ghudson, 21 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r20225, which included commits to RCS files with non-trunk default branches.
RevLine 
[20225]1/* Driver for Compaq Tru64 UNIX using MMS */
2
3#include <unistd.h>
4#include <assert.h>
5#include <strings.h>
6#include <mme/mme_api.h>
7#include <errno.h>
8#include "esd.h"
9#include "config.h"
10
11static HWAVEOUT hWaveOut = NULL;
12static HWAVEIN hWaveIn = NULL;
13static unsigned long nWaiting = 0;
14static unsigned int sleep_delay = 50000;
15static void *record_buf = NULL;
16static unsigned long record_out = 0;
17
18/*
19 * Sometime we run out of memory because too much data has been accepted by
20 * waveOutWrite but not yet played.  Most drivers don't let the data get this big
21 * because they are limited by the normal I/O buffers (fopen, fsync, etc.).
22 * This also has the affect of making esd_audio_flush() take a long time.
23 * To avoid running out of memory unnecessarily, we impose a limit on how much
24 * can be buffered at one time.
25 */
26#if !defined(ESD_OUT_BUFFER_PCT)
27#define ESD_OUT_BUFFER_PCT 0.5
28#endif
29static unsigned long nWaitingMax = (unsigned long) -1L;
30void
31reduce_buffered_data()
32{
33    do {
34        if (mmeCheckForCallbacks() == TRUE)
35            mmeProcessCallbacks();
36        if (nWaiting > nWaitingMax)
37            usleep(sleep_delay);
38    } while (nWaiting > nWaitingMax);
39}
40
41void CALLBACK waveInCallbackFunction(HWAVEIN hWaveIn, UINT uMsg,
42                                     DWORD dwInstance,
43                                     LPARAM lParam1, LPARAM lParam2);
44void CALLBACK waveOutCallbackFunction(HWAVEOUT hWaveOut, UINT uMsg,
45                                      DWORD dwInstance,
46                                      LPARAM lParam1, LPARAM lParam2);
47
48void
49_mmeFreeMem(void *ptr, char *name)
50{
51    if (ptr == NULL)
52        return;
53    if (mmeFreeMem(ptr) != TRUE)
54        fprintf(stderr, "esd: warning: unable to free %s\n", name);
55}
56#define mmeFreeMem(x) _mmeFreeMem(x,#x)
57
58void
59mmePrintError(int in, UINT uError)
60{
61    MMRESULT result;
62    LPSTR lpText;
63    UINT uSize = MAXERRORLENGTH;
64
65    lpText = mmeAllocMem(uSize);
66    if (lpText == NULL)
67        result = ~MMSYSERR_NOERROR;
68    else if (in)
69        result = waveInGetErrorText(uError, lpText, uSize);
70    else
71        result = waveOutGetErrorText(uError, lpText, uSize);
72    if (result != MMSYSERR_NOERROR) {
73        fprintf(stderr, "esd: MME error #%u occurred\n", uError);
74        return;
75    }
76    fprintf(stderr, "esd: %s\n", lpText);
77    mmeFreeMem(lpText);
78}
79#define mmePrintInError(x)      mmePrintError(1,x)
80#define mmePrintOutError(x)     mmePrintError(0,x)
81
82void *
83_mmeAllocMem(size_t size)
84{
85    void *ptr;
86
87    if((ptr = mmeAllocMem(size)) == NULL)
88        fprintf(stderr, "esd: not enough room to allocated %lu bytes!\n", size);
89    return ptr;
90}
91#define mmeAllocMem(x)  _mmeAllocMem(x)
92
93#define ARCH_esd_audio_devices
94const char *esd_audio_devices()
95{
96    static char *str = NULL;
97    UINT nDevs, i;
98    LPWAVEOUTCAPS lpOutCaps = NULL;
99    LPWAVEINCAPS lpInCaps = NULL;
100    MMRESULT result;
101    size_t str_size;
102    int record = 0;
103    static const char *unknown = "(unknown)";
104    static const char *none = "(none)";
105
106    if (str != NULL)
107        free(str);
108    if (esd_audio_format & ESD_MASK_MODE == ESD_STREAM &&
109        esd_audio_format & ESD_MASK_FUNC == ESD_RECORD)
110        record = 1;
111    if (record)
112        nDevs = waveInGetNumDevs();
113    else
114        nDevs = waveOutGetNumDevs();
115    if (nDevs == 0)
116        return none;
117    if (record)
118        lpInCaps = mmeAllocMem(sizeof(WAVEINCAPS));
119    else
120        lpOutCaps = mmeAllocMem(sizeof(WAVEOUTCAPS));
121    if (lpInCaps == NULL && lpOutCaps == NULL)
122        return unknown;
123    str_size = nDevs * (MAXPNAMELEN + 15);
124    if ((str = malloc (str_size)) == NULL) {
125        mmeFreeMem(lpInCaps);
126        mmeFreeMem(lpOutCaps);
127        return unknown;
128    }
129    str[0] = '\0';
130    for (i=0; i<nDevs; i++) {
131        if (record)
132            result = waveInGetDevCaps(i, lpInCaps, sizeof(WAVEINCAPS));
133        else
134            result = waveOutGetDevCaps(i, lpOutCaps, sizeof(WAVEOUTCAPS));
135        if (result != MMSYSERR_NOERROR) {
136            mmePrintError(record, result);
137            continue;
138        }
139        snprintf(str, str_size, "%s%s%d (%s)", str, str[0] ? ", " : "",
140                 i, record ? lpInCaps->szPname : lpOutCaps->szPname);
141    }
142    mmeFreeMem(lpInCaps);
143    mmeFreeMem(lpOutCaps);
144    return str;
145}
146
147#define ARCH_esd_audio_open
148int esd_audio_open()
149{
150    UINT uDeviceID;
151    LPWAVEFORMATEX waveFormat;
152    MMRESULT result;
153    int record = 0;
154
155    switch (esd_audio_format & ESD_MASK_MODE) {
156        case ESD_STREAM:
157            switch (esd_audio_format & ESD_MASK_FUNC) {
158                case ESD_MONITOR:
159                case ESD_PLAY:
160                    break;
161                case ESD_RECORD:
162                    record = 1;
163                    break;
164                default:
165                    fprintf(stderr, "esd: desired functionality unknown\n");
166                    return -1;
167            }
168            break;
169        case ESD_SAMPLE:
170            switch (esd_audio_format & ESD_MASK_FUNC) {
171                case ESD_LOOP:
172                    break;
173                case ESD_STOP:
174                default:
175                    fprintf(stderr, "esd: desired functionality unknown\n");
176                    return -1;
177            }
178            break;
179        case ESD_ADPCM:
180            fprintf(stderr, "esd: desired functionality unimplemented\n");
181            return -1;
182        default:
183            fprintf(stderr, "esd: desired functionality unknown\n");
184            return -1;
185    }
186
187    if ((record && hWaveIn != NULL) || hWaveOut != NULL) {
188        fprintf(stderr, "esd: already opened (multiples not allowed)\n");
189        return -1;
190    }
191    if (esd_audio_device == NULL)
192        uDeviceID = WAVE_MAPPER;
193    else if(sscanf(esd_audio_device, "%u", &uDeviceID) != 1) {
194        fprintf(stderr, "esd: invalid device ID specified\n");
195        return -1;
196    }
197
198    if ((waveFormat = mmeAllocMem(sizeof(WAVEFORMATEX))) == NULL)
199        return -1;
200    waveFormat->wFormatTag = WAVE_FORMAT_PCM;
201    switch (esd_audio_format & ESD_MASK_BITS) {
202        case ESD_BITS8:
203            waveFormat->wBitsPerSample = 8;
204            break;
205        case ESD_BITS16:
206            waveFormat->wBitsPerSample = 16;
207            break;
208        default:
209            fprintf(stderr, "esd: unknown bits per sample\n");
210            return -1;
211    }
212    switch (esd_audio_format & ESD_MASK_CHAN) {
213        case ESD_MONO:
214            waveFormat->nChannels = 1;
215            break;
216        case ESD_STEREO:
217            waveFormat->nChannels = 2;
218            break;
219        default:
220            fprintf(stderr, "esd: unknown channel setup\n");
221            return -1;
222    }
223    waveFormat->nSamplesPerSec = esd_audio_rate;
224    nWaitingMax = esd_audio_rate * ESD_OUT_BUFFER_PCT;
225    waveFormat->nAvgBytesPerSec = waveFormat->nSamplesPerSec *
226        waveFormat->nChannels * waveFormat->wBitsPerSample/8;
227    waveFormat->nBlockAlign = waveFormat->nChannels * waveFormat->wBitsPerSample/8;
228
229    if (record)
230        result = waveInOpen(&hWaveIn, uDeviceID, (void *)waveFormat,
231                            waveInCallbackFunction, NULL, CALLBACK_FUNCTION);
232    else
233        result = waveOutOpen(&hWaveOut, uDeviceID, (void *)waveFormat,
234                             waveOutCallbackFunction, NULL,
235                             CALLBACK_FUNCTION | WAVE_OPEN_SHAREABLE);
236    mmeFreeMem(waveFormat);
237    if (result != MMSYSERR_NOERROR) {
238        fprintf(stderr, "esd: unable to open audio device\n");
239        mmePrintError(record, result);
240        if (result == MMSYSERR_BADDEVICEID)
241            fprintf(stderr, "esd: valid devices: %s\n", esd_audio_devices());
242        return -1;
243    }
244    if (record)
245        result = waveInStart(hWaveIn);
246    else
247        result = waveOutReset(hWaveOut);
248    if (result != MMSYSERR_NOERROR)
249        mmePrintError(record, result);
250    return 0;
251}
252
253#define ARCH_esd_audio_close
254void esd_audio_close()
255{
256    MMRESULT result;
257
258    if (hWaveIn != NULL) {
259        result = waveInStop(hWaveIn);
260        if (result != MMSYSERR_NOERROR)
261            result = waveInReset(hWaveIn);
262        if (result != MMSYSERR_NOERROR)
263            result = waveInClose(hWaveIn);
264        if (result != MMSYSERR_NOERROR)
265            hWaveIn = NULL;
266        if (result != MMSYSERR_NOERROR)
267            mmePrintOutError(result);
268    }
269    if (hWaveOut != NULL) {
270        esd_audio_flush();
271        result = waveOutReset(hWaveOut);
272        if (result != MMSYSERR_NOERROR)
273            mmePrintOutError(result);
274        result = waveOutClose(hWaveOut);
275        if (result != MMSYSERR_NOERROR)
276            hWaveOut = NULL;
277        if (result != MMSYSERR_NOERROR)
278            mmePrintOutError(result);
279    }
280}
281
282#define ARCH_esd_audio_flush
283void esd_audio_flush()
284{
285    if (hWaveOut == NULL)
286        return;
287    if (hWaveIn == NULL) ;
288    do {
289        if (mmeCheckForCallbacks() == TRUE)
290            mmeProcessCallbacks();
291        if (nWaiting > 0)
292            usleep(sleep_delay);
293    } while (nWaiting > 0);
294    return;
295}
296
297#define ARCH_esd_audio_write
298int esd_audio_write(void *buffer, int buf_size)
299{
300    MMRESULT result;
301    LPWAVEHDR lpWaveOutHdr;
302    void *b;
303
304    if (hWaveOut == NULL) {
305        fprintf(stderr, "esd: output device not open!\n");
306        return -1;
307    }
308
309    /* Process pending data first */
310    if (mmeCheckForCallbacks() == TRUE)
311        mmeProcessCallbacks();
312    if (nWaiting > nWaitingMax)
313        reduce_buffered_data();
314
315    /* Make a copy of the buffer */
316    if ((b = mmeAllocBuffer((size_t)buf_size)) == NULL)
317        return -1;
318    bcopy(buffer, b, buf_size);
319   
320    if ((lpWaveOutHdr = mmeAllocMem(sizeof(WAVEHDR))) == NULL)
321        return -1;
322    lpWaveOutHdr->dwBufferLength = buf_size;
323    lpWaveOutHdr->lpData = b;
324
325    result = waveOutWrite(hWaveOut, lpWaveOutHdr, sizeof(WAVEHDR));
326    mmeFreeMem(lpWaveOutHdr);
327    if (result != MMSYSERR_NOERROR) {
328        mmePrintOutError(result);
329        return -1;
330    }
331    nWaiting += buf_size;
332
333    /* Take the chance to process any pending data */
334    if (mmeCheckForCallbacks() == TRUE)
335        mmeProcessCallbacks();
336    if (nWaiting > nWaitingMax)
337        reduce_buffered_data();
338
339    return 0;
340}
341
342#define ARCH_esd_audio_read
343int esd_audio_read(void *buffer, int buf_size) {
344    MMRESULT result;
345    LPWAVEHDR lpWaveInHdr;
346
347    if (hWaveIn == NULL) {
348        fprintf(stderr, "esd: input device never opened!\n");
349        return 0;
350    }
351    if ((lpWaveInHdr = mmeAllocMem(sizeof(WAVEHDR))) == NULL)
352        return 0;
353    lpWaveInHdr->dwBufferLength = (UINT) buf_size;
354    if ((lpWaveInHdr->lpData = mmeAllocMem(lpWaveInHdr->dwBufferLength)) == NULL) {
355        mmeFreeMem(lpWaveInHdr);
356        return 0;
357    }
358    result = waveInAddBuffer(hWaveIn, lpWaveInHdr, sizeof(WAVEHDR));
359    if (result != MMSYSERR_NOERROR) {
360        mmePrintInError(result);
361        return 0;
362    }
363    mmeFreeMem(lpWaveInHdr);
364    record_buf = buffer;
365    record_out = 0;
366    do {
367        if (mmeCheckForCallbacks() == TRUE)
368            mmeProcessCallbacks();
369        if (record_out == 0)
370            usleep(10000);      /* Use a fairly low latency */
371    } while (record_out == 0);
372    return record_out;
373}
374
375#define ARCH_esd_audio_pause
376void esd_audio_pause()
377{
378#if 0
379    /* Is this really right, or do they want a mute ? */
380    /* How is the stream "unpaused" anyway? */
381    MMRESULT result;
382    //fprintf(stderr, "In esd_audio_pause()\n");
383    if (hWaveOut == NULL)
384        return;
385    result = waveOutPause(hWaveOut);
386    if (result != MMSYSERR_NOERROR) {
387        mmePrintOutError(result);
388        return;
389    }
390#endif
391    return;
392}
393
394void CALLBACK waveOutCallbackFunction(HWAVEOUT hWaveOut, UINT uMsg,
395                                      DWORD dwInstance,
396                                      LPARAM lParam1, LPARAM lParam2)
397{
398    switch (uMsg) {
399        case WOM_CLOSE:
400        case WOM_OPEN:
401            break;
402        case WOM_DONE:
403            nWaiting -= ((LPWAVEHDR)lParam1)->dwBufferLength;
404            mmeFreeBuffer(((LPWAVEHDR)lParam1)->lpData);
405            break;
406        default:
407            fprintf(stderr, "esd: unknown message #%u given to callback function\n", uMsg);
408            break;
409    }
410}
411
412void CALLBACK waveInCallbackFunction(HWAVEIN hWaveIn, UINT uMsg,
413                                     DWORD dwInstance,
414                                     LPARAM lParam1, LPARAM lParam2)
415{
416    switch (uMsg) {
417        case WIM_CLOSE:
418            break;
419        case WIM_OPEN:
420            break;
421        case WIM_DATA:
422            bcopy(((LPWAVEHDR)lParam1)->lpData, record_buf,
423                  ((LPWAVEHDR)lParam1)->dwBufferLength);
424            record_out = ((LPWAVEHDR)lParam1)->dwBufferLength;
425            mmeFreeBuffer(((LPWAVEHDR)lParam1)->lpData);
426            break;
427        default:
428            fprintf(stderr, "esd: unknown message #%u given to callback function\n", uMsg);
429            break;
430    }
431}
Note: See TracBrowser for help on using the repository browser.