Commit | Line | Data |
---|---|---|
ef79bbde P |
1 | /*************************************************************************** |
2 | alsa.c - description | |
3 | ------------------- | |
4 | begin : Sat Mar 01 2003 | |
5 | copyright : (C) 2002 by Pete Bernert | |
6 | email : BlackDove@addcom.de | |
7 | ***************************************************************************/ | |
8 | /*************************************************************************** | |
9 | * * | |
10 | * This program is free software; you can redistribute it and/or modify * | |
11 | * it under the terms of the GNU General Public License as published by * | |
12 | * the Free Software Foundation; either version 2 of the License, or * | |
13 | * (at your option) any later version. See also the license.txt file for * | |
14 | * additional informations. * | |
15 | * * | |
16 | ***************************************************************************/ | |
17 | ||
07c13dfd | 18 | #include <stdio.h> |
ef79bbde P |
19 | #define ALSA_PCM_NEW_HW_PARAMS_API |
20 | #define ALSA_PCM_NEW_SW_PARAMS_API | |
21 | #include <alsa/asoundlib.h> | |
07c13dfd | 22 | #include "out.h" |
ef79bbde P |
23 | |
24 | static snd_pcm_t *handle = NULL; | |
25 | static snd_pcm_uframes_t buffer_size; | |
26 | ||
27 | // SETUP SOUND | |
07c13dfd | 28 | static int alsa_init(void) |
ef79bbde P |
29 | { |
30 | snd_pcm_hw_params_t *hwparams; | |
31 | snd_pcm_status_t *status; | |
32 | unsigned int pspeed; | |
33 | int pchannels; | |
34 | int format; | |
35 | unsigned int buffer_time = 100000; | |
36 | unsigned int period_time = buffer_time / 4; | |
37 | int err; | |
38 | ||
97ea4077 | 39 | pchannels=2; |
ef79bbde P |
40 | |
41 | pspeed = 44100; | |
42 | format = SND_PCM_FORMAT_S16; | |
43 | ||
44 | if ((err = snd_pcm_open(&handle, "default", | |
45 | SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK)) < 0) | |
46 | { | |
47 | printf("Audio open error: %s\n", snd_strerror(err)); | |
07c13dfd | 48 | return -1; |
ef79bbde P |
49 | } |
50 | ||
51 | if((err = snd_pcm_nonblock(handle, 0))<0) | |
52 | { | |
53 | printf("Can't set blocking moded: %s\n", snd_strerror(err)); | |
07c13dfd | 54 | return -1; |
ef79bbde P |
55 | } |
56 | ||
57 | snd_pcm_hw_params_alloca(&hwparams); | |
58 | ||
59 | if((err=snd_pcm_hw_params_any(handle, hwparams))<0) | |
60 | { | |
61 | printf("Broken configuration for this PCM: %s\n", snd_strerror(err)); | |
07c13dfd | 62 | return -1; |
ef79bbde P |
63 | } |
64 | ||
65 | if((err=snd_pcm_hw_params_set_access(handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED))<0) | |
66 | { | |
67 | printf("Access type not available: %s\n", snd_strerror(err)); | |
07c13dfd | 68 | return -1; |
ef79bbde P |
69 | } |
70 | ||
71 | if((err=snd_pcm_hw_params_set_format(handle, hwparams, format))<0) | |
72 | { | |
73 | printf("Sample format not available: %s\n", snd_strerror(err)); | |
07c13dfd | 74 | return -1; |
ef79bbde P |
75 | } |
76 | ||
77 | if((err=snd_pcm_hw_params_set_channels(handle, hwparams, pchannels))<0) | |
78 | { | |
79 | printf("Channels count not available: %s\n", snd_strerror(err)); | |
07c13dfd | 80 | return -1; |
ef79bbde P |
81 | } |
82 | ||
83 | if((err=snd_pcm_hw_params_set_rate_near(handle, hwparams, &pspeed, 0))<0) | |
84 | { | |
85 | printf("Rate not available: %s\n", snd_strerror(err)); | |
07c13dfd | 86 | return -1; |
ef79bbde P |
87 | } |
88 | ||
89 | if((err=snd_pcm_hw_params_set_buffer_time_near(handle, hwparams, &buffer_time, 0))<0) | |
90 | { | |
91 | printf("Buffer time error: %s\n", snd_strerror(err)); | |
07c13dfd | 92 | return -1; |
ef79bbde P |
93 | } |
94 | ||
95 | if((err=snd_pcm_hw_params_set_period_time_near(handle, hwparams, &period_time, 0))<0) | |
96 | { | |
97 | printf("Period time error: %s\n", snd_strerror(err)); | |
07c13dfd | 98 | return -1; |
ef79bbde P |
99 | } |
100 | ||
101 | if((err=snd_pcm_hw_params(handle, hwparams))<0) | |
102 | { | |
103 | printf("Unable to install hw params: %s\n", snd_strerror(err)); | |
07c13dfd | 104 | return -1; |
ef79bbde P |
105 | } |
106 | ||
107 | snd_pcm_status_alloca(&status); | |
108 | if((err=snd_pcm_status(handle, status))<0) | |
109 | { | |
110 | printf("Unable to get status: %s\n", snd_strerror(err)); | |
07c13dfd | 111 | return -1; |
ef79bbde P |
112 | } |
113 | ||
114 | buffer_size = snd_pcm_status_get_avail(status); | |
07c13dfd | 115 | return 0; |
ef79bbde P |
116 | } |
117 | ||
118 | // REMOVE SOUND | |
07c13dfd | 119 | static void alsa_finish(void) |
ef79bbde P |
120 | { |
121 | if(handle != NULL) | |
122 | { | |
123 | snd_pcm_drop(handle); | |
124 | snd_pcm_close(handle); | |
125 | handle = NULL; | |
126 | } | |
127 | } | |
128 | ||
129 | // GET BYTES BUFFERED | |
07c13dfd | 130 | static int alsa_busy(void) |
ef79bbde | 131 | { |
07c13dfd | 132 | int l; |
ef79bbde P |
133 | |
134 | if (handle == NULL) // failed to open? | |
f8edb5bc | 135 | return 1; |
ef79bbde P |
136 | l = snd_pcm_avail(handle); |
137 | if (l < 0) return 0; | |
138 | if (l < buffer_size / 2) // can we write in at least the half of fragments? | |
f8edb5bc | 139 | l = 1; // -> no? wait |
ef79bbde P |
140 | else l = 0; // -> else go on |
141 | ||
142 | return l; | |
143 | } | |
144 | ||
145 | // FEED SOUND DATA | |
07c13dfd | 146 | static void alsa_feed(void *pSound, int lBytes) |
ef79bbde P |
147 | { |
148 | if (handle == NULL) return; | |
149 | ||
150 | if (snd_pcm_state(handle) == SND_PCM_STATE_XRUN) | |
151 | snd_pcm_prepare(handle); | |
97ea4077 | 152 | snd_pcm_writei(handle,pSound, lBytes / 4); |
ef79bbde | 153 | } |
07c13dfd | 154 | |
155 | void out_register_alsa(struct out_driver *drv) | |
156 | { | |
157 | drv->name = "alsa"; | |
158 | drv->init = alsa_init; | |
159 | drv->finish = alsa_finish; | |
160 | drv->busy = alsa_busy; | |
161 | drv->feed = alsa_feed; | |
162 | } |