source: trunk/third/esound/audio_alsa09.c @ 21330

Revision 21330, 12.1 KB checked in by ghudson, 19 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r21329, which included commits to RCS files with non-trunk default branches.
Line 
1/* -*- Mode: c; tab-width: 4; c-basic-offset: 4; -*-
2 *
3 *  ALSA 0.9 support for Esound
4 *  by Santiago Otero (siryurian@terra.es)
5 *
6 *
7 *  This library is free software; you can redistribute it and/or
8 *  modify it under the terms of the GNU Lesser General Public
9 *  License as published by the Free Software Foundation; either
10 *  version 2 of 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 GNU
15 *  Lesser General Public License for more details.
16 *                                                                             
17 *  You should have received a copy of the GNU Lesser General Public
18 *  License along with this library; if not, write to the Free Software
19 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
20 *
21 */
22
23
24/* Debug flag */
25int alsadbg = 0;
26/* Error flag */
27int alsaerr = 0;
28#include <alsa/asoundlib.h>
29
30/* FULL DUPLEX => two handlers */
31
32static snd_pcm_t *alsa_playback_handle = NULL;
33static snd_pcm_t *alsa_capture_handle = NULL;
34
35static snd_output_t *output = NULL;
36
37#define ACS  SND_PCM_ACCESS_RW_INTERLEAVED
38#define BUFFERSIZE 16384
39
40
41
42void print_state()
43{
44 
45        int state;
46        int err;
47 
48        snd_pcm_status_t *status;
49 
50        snd_pcm_status_alloca(&status);
51 
52        if ( (err = snd_pcm_status(alsa_playback_handle, status)) < 0) {
53                fprintf(stderr, "Error getting status:%s\n", snd_strerror(err));
54                return;
55        }
56 
57 
58        state = snd_pcm_status_get_state( status );
59        switch(state) {
60        case SND_PCM_STATE_OPEN :
61                fprintf(stderr, "SND_PCM_STATE_OPEN\n");
62                break;
63        case SND_PCM_STATE_SETUP:
64                fprintf(stderr, "SND_PCM_STATE_SETUP\n");
65                break;
66        case SND_PCM_STATE_PREPARED:
67                fprintf(stderr,"SND_PCM_STATE_PREPARED\n");
68                break;
69        case SND_PCM_STATE_RUNNING:
70                fprintf(stderr, "SND_PCM_STATE_RUNNING\n");
71                break;
72        case SND_PCM_STATE_XRUN:
73                fprintf(stderr, "SND_PCM_STATE_XRUN\n");
74                break;
75        case SND_PCM_STATE_DRAINING:
76                fprintf(stderr, "SND_PCM_STATE_DRAINING\n");
77                break;
78        case SND_PCM_STATE_PAUSED:
79                fprintf(stderr, "SND_PCM_STATE_PAUSED\n");
80                break;
81        case SND_PCM_STATE_SUSPENDED:
82                fprintf(stderr, "SND_PCM_STATE_SUSPENDED\n");
83                break;
84        default:
85                fprintf(stderr, "WARNING: unknown state %d\n", state);
86        }
87 
88}
89
90snd_pcm_t* initAlsa(char *dev, int format, int channels, int speed, int mode)
91{
92 
93        snd_pcm_t *handle;
94        snd_pcm_hw_params_t *hwparams;
95        int err;
96        int periods;
97 
98#ifdef DRIVER_ALSA_09_NEW_PCM_API
99        int t_dir=0;
100        int t_speed=speed;
101        snd_pcm_uframes_t t_bufsize=BUFFERSIZE;
102#endif
103
104        err = snd_pcm_open(&handle, dev, mode, SND_PCM_NONBLOCK);
105        if (err < 0) {
106                if (alsadbg)
107                        fprintf(stderr, "%s\n", snd_strerror(err));
108                alsaerr = -2;
109                return NULL;
110        }
111        snd_pcm_nonblock(handle, 0);
112        snd_pcm_hw_params_alloca(&hwparams);
113 
114        err = snd_pcm_hw_params_any(handle, hwparams); 
115        if (err < 0) {
116                if (alsadbg)
117                        fprintf(stderr, "%s\n", snd_strerror(err));
118                alsaerr = -1;
119                return handle;
120        }
121 
122        err = snd_pcm_hw_params_set_access(handle, hwparams, ACS);
123        if (err < 0) {
124                if (alsadbg)
125                        fprintf(stderr, "%s\n", snd_strerror(err));
126                alsaerr = -1;
127                return handle;
128        }
129 
130        err = snd_pcm_hw_params_set_format(handle, hwparams, format);
131        if (err < 0) {
132                if (alsadbg)
133                        fprintf(stderr, "%s\n", snd_strerror(err));
134                alsaerr = -1;
135                return handle;
136        }
137 
138        err = snd_pcm_hw_params_set_channels(handle, hwparams,  channels);
139        if (err < 0) {
140                if (alsadbg)
141                        fprintf(stderr, "%s\n", snd_strerror(err));
142                alsaerr = -1;
143                return handle;
144        }
145#ifndef DRIVER_ALSA_09_NEW_PCM_API
146        err = snd_pcm_hw_params_set_rate_near(handle, hwparams, speed, 0);
147#else
148    err = snd_pcm_hw_params_set_rate_near(handle, hwparams, &t_speed, &t_dir);
149#endif
150        if (err < 0) {
151                if (alsadbg)
152                        fprintf(stderr, "%s\n", snd_strerror(err));
153                alsaerr = -1;
154                return handle;
155        }
156#ifndef DRIVER_ALSA_09_NEW_PCM_API
157        if (err != speed) {
158#else
159        if (t_speed != speed) {
160#endif
161                if (alsadbg)
162                        fprintf(stderr, "Rate not avaliable %i != %i\n", speed, err);
163                alsaerr = -1;
164                return handle;
165        }
166 
167        err = snd_pcm_hw_params_set_periods_integer(handle, hwparams);
168        if (err < 0) {
169                if (alsadbg)
170                        fprintf(stderr, "%s\n", snd_strerror(err));
171                alsaerr = -1;
172                return handle;
173        }
174 
175        periods = 2;
176        err = snd_pcm_hw_params_set_periods_min(handle, hwparams, &periods, 0);
177        if (err < 0) {
178                if (alsadbg)
179                        fprintf(stderr, "%s\n", snd_strerror(err));
180                alsaerr = -1;
181                return handle;
182        }
183 
184        periods = 64;
185        err = snd_pcm_hw_params_set_periods_max(handle, hwparams, &periods, 0);
186        if (err < 0) {
187                if (alsadbg)
188                        fprintf(stderr, "%s\n", snd_strerror(err));
189                alsaerr = -1;
190                return handle;
191        }
192#ifndef DRIVER_ALSA_09_NEW_PCM_API
193        err = snd_pcm_hw_params_set_buffer_size_near(handle, hwparams, BUFFERSIZE);
194#else
195        err = snd_pcm_hw_params_set_buffer_size_near(handle, hwparams, &t_bufsize);
196#endif
197        if (err < 0) {
198                if (alsadbg)
199                        fprintf(stderr, "Buffersize:%s\n", snd_strerror(err));
200                alsaerr = -1;
201                return handle;
202        }
203        err = snd_pcm_hw_params(handle, hwparams);
204        if (err < 0) {
205                if (alsadbg)
206                        fprintf(stderr, "%s\n", snd_strerror(err));
207                alsaerr = -1;
208                return handle;
209        }
210        if (alsadbg)
211                snd_pcm_dump(handle, output);
212        alsaerr = 0;
213        return handle;
214}
215
216#define ARCH_esd_audio_devices
217
218const char *esd_audio_devices()
219{
220        int card, err;
221        static char *all_alsa_cards=0;
222        char *alsa_card_tmp;
223        snd_ctl_t *handle;
224        snd_ctl_card_info_t *info;
225
226        snd_ctl_card_info_alloca(&info);
227
228        if(all_alsa_cards)
229        {
230                free(all_alsa_cards);
231                all_alsa_cards = 0;
232        }
233
234        card = -1;
235        if(snd_card_next(&card) < 0 || card < 0)
236        {
237                /* No cards found */
238        }
239        else
240        {
241                while( card >= 0 )
242                {
243                        char name[32];
244                        sprintf( name, "hw:%d", card );
245                        err = snd_ctl_open(&handle, name, 0);
246                        if( err < 0 )
247                        {
248                                fprintf( stderr, "audio_alsa: Error: control open (%i): %s\n", card, snd_strerror(err));
249                                continue;
250                        }
251                        err = snd_ctl_card_info(handle, info);
252                        if( err < 0 )
253                        {
254                                fprintf( stderr, "audio_alsa: Error: control hardware info (%i): %s\n", card, snd_strerror(err));
255                                snd_ctl_close(handle);
256                                continue;
257                        }
258                        alsa_card_tmp = malloc(strlen(snd_ctl_card_info_get_name(info))+20);
259                        sprintf( alsa_card_tmp, "hw:%d  (%s)\n", card, snd_ctl_card_info_get_name(info) );
260                        if(all_alsa_cards)
261                        {
262                                all_alsa_cards = realloc(all_alsa_cards, strlen(all_alsa_cards)+strlen(alsa_card_tmp)+30);
263                                strcat(all_alsa_cards, "                       ");
264                                strcat(all_alsa_cards, alsa_card_tmp);
265                                free(alsa_card_tmp);
266                        }
267                        else
268                        {
269                                all_alsa_cards = alsa_card_tmp;
270                        }
271                        snd_ctl_close(handle);
272                        if(snd_card_next(&card) < 0)
273                        {
274                                break;
275                        }
276                }
277        }
278        if(all_alsa_cards)
279        {
280                return(all_alsa_cards);
281        }
282        else
283        {
284                return("No available cards found");
285        }
286}
287
288
289#define ARCH_esd_audio_open
290
291int esd_audio_open()
292{
293 
294        int channels;
295        int format;
296        int card;
297        char *dev;
298 
299        if (alsadbg)
300                fprintf(stderr, "esd_audio_open\n");
301
302 
303        if ((esd_audio_format & ESD_MASK_BITS) == ESD_BITS16)
304                format = SND_PCM_FORMAT_S16;
305        else format = SND_PCM_FORMAT_U8;
306 
307        if ((esd_audio_format & ESD_MASK_CHAN) == ESD_STEREO)
308                channels = 2;
309        else channels = 1;
310 
311 
312        snd_output_stdio_attach(&output, stderr, 0);
313 
314        if(esd_audio_device)
315        {
316                dev = (char*) malloc(strlen(esd_audio_device)+1);
317                strcpy(dev, esd_audio_device);
318        }
319        else
320        {
321                /* bind to alsa default setting */
322                dev = strdup ("default");
323        }
324
325
326        if (alsadbg)
327                fprintf(stderr, "dev=%s\n",dev);
328
329        alsa_playback_handle = initAlsa(dev, format, channels,
330                                                                        esd_audio_rate, SND_PCM_STREAM_PLAYBACK);
331        if(alsaerr)
332        {
333                if(alsaerr == -1) snd_pcm_close(alsa_playback_handle);
334                if (alsadbg)
335                        fprintf(stderr, "Error opening device for playback\n");
336
337                esd_audio_fd = -1;
338                free(dev);
339                return alsaerr;
340        }
341        if (alsadbg)
342                fprintf(stderr, "Device open for playback\n");
343
344        if ( (esd_audio_format & ESD_MASK_FUNC) == ESD_RECORD ) {
345                alsa_capture_handle = initAlsa(dev, format, channels,
346                                                                           esd_audio_rate, SND_PCM_STREAM_CAPTURE);
347                if (alsaerr) {
348                        if (alsaerr==-1) snd_pcm_close(alsa_capture_handle);
349                        if (alsadbg)
350                                fprintf(stderr, "Error opening device for capture\n");
351
352                        snd_pcm_close(alsa_playback_handle);
353                        esd_audio_fd = -1;
354                        free(dev);
355                        return alsaerr;
356                }
357
358                if (alsadbg)
359                        fprintf(stderr, "Device open for capture\n");
360
361        }
362        esd_audio_fd = 0;
363        free(dev);
364        if (alsadbg)
365                print_state();
366
367        return 0;
368}
369
370#define ARCH_esd_audio_close
371void esd_audio_close()
372{
373        if (alsadbg) {
374                fprintf(stderr, "esd_audio_close\n");
375                print_state();
376        }
377
378        if (alsa_playback_handle != NULL)
379                snd_pcm_close( alsa_playback_handle );
380        if (alsa_capture_handle != NULL)
381                snd_pcm_close(alsa_capture_handle);
382        alsa_playback_handle = NULL;
383        alsa_capture_handle = NULL;
384}
385
386#define ARCH_esd_audio_pause
387void esd_audio_pause()
388{
389 
390        return;
391}
392
393#define ARCH_esd_audio_read
394int esd_audio_read( void *buffer, int buf_size )
395{
396        int err;
397       
398        int len = snd_pcm_bytes_to_frames(alsa_capture_handle, buf_size);
399        while ( ( err = snd_pcm_readi( alsa_capture_handle, buffer, len)) < 0) {
400                if (alsadbg) {
401                        fprintf(stderr, "esd_audio_read\n");
402                        print_state();
403                }
404
405                if (err == -EPIPE) {
406                        if (alsadbg)
407                                fprintf(stderr, "EPIPE\n");
408
409                        if (( err = snd_pcm_prepare( alsa_capture_handle ) )< 0) {
410                                if (alsadbg)
411                                        fprintf(stderr, "%s\n", snd_strerror(err));
412
413                                return -1;
414                        }
415                        continue;
416                } else if ( err == -ESTRPIPE) {
417                        if (alsadbg)
418                                fprintf(stderr, "ESTRPIPE\n");
419
420                        while (( err = snd_pcm_resume(alsa_capture_handle)) == -EAGAIN)
421                                sleep(1);
422                        if (err < 0) {
423                                if (alsadbg)
424                                        fprintf(stderr, "Preparing...\n");
425                                if (snd_pcm_prepare( alsa_capture_handle) < 0)
426                                        return -1;
427                        }
428                        continue;
429                }
430   
431                err = snd_pcm_prepare(alsa_capture_handle) ;
432                if (err < 0) {
433                        if (alsadbg)
434                                fprintf(stderr, "%s\n", snd_strerror(err));
435                        return -1;
436                }
437        }
438 
439        return ( snd_pcm_frames_to_bytes(alsa_capture_handle, err) );
440}
441
442
443#define ARCH_esd_audio_write
444int esd_audio_write( void *buffer, int buf_size )
445{
446        int err;
447
448        int len = snd_pcm_bytes_to_frames(alsa_playback_handle, buf_size);
449        while ( ( err = snd_pcm_writei( alsa_playback_handle, buffer, len)) < 0) {
450                if (alsadbg) {
451                        fprintf(stderr, "esd_audio_write\n");
452                        print_state();
453                }
454
455                if (err == -EPIPE) {
456                        if (alsadbg)
457                                fprintf(stderr, "EPIPE\n");
458                        if (( err = snd_pcm_prepare( alsa_playback_handle ) )< 0) {
459                                if (alsadbg)
460                                        fprintf(stderr, "%s\n", snd_strerror(err));
461                                return -1;
462                        }
463                        continue;
464                } else  if (err == -ESTRPIPE) {
465                        if (alsadbg)
466                                fprintf(stderr, "ESTRPIPE\n");
467                        while (( err = snd_pcm_resume(alsa_playback_handle)) == -EAGAIN)
468                                sleep(1);
469                        if (err < 0) {
470                                if (alsadbg)
471                                        fprintf(stderr, "Preparing...\n");
472                                if (snd_pcm_prepare( alsa_playback_handle) < 0)
473                                        return -1;
474                        }
475                        continue;
476                }
477                err = snd_pcm_prepare(alsa_playback_handle) ;
478                if (err < 0) {
479                        if (alsadbg)
480                                fprintf(stderr, "%s\n", snd_strerror(err));
481                        return -1;
482                }
483        }
484 
485        return ( snd_pcm_frames_to_bytes(alsa_playback_handle, err) );
486}
487
488#define ARCH_esd_audio_flush
489void esd_audio_flush()
490{
491 
492        if (alsadbg) {
493                fprintf(stderr, "esd_audio_flush\n");
494                print_state();
495        }
496
497        if (alsa_playback_handle != NULL)
498                snd_pcm_drain( alsa_playback_handle );
499 
500        if (alsadbg)
501                print_state();
502 
503 
504}
Note: See TracBrowser for help on using the repository browser.