Mercurial > mplayer.hg
annotate libao2/ao_alsa5.c @ 5114:1f668483b7ff
faszom.
author | arpi |
---|---|
date | Fri, 15 Mar 2002 22:29:22 +0000 |
parents | 91f801a94a59 |
children | d141f1e9cc36 |
rev | line source |
---|---|
996 | 1 /* |
1046
59fc1f75e486
audio_pause/resume implementacio es kozmetikai valtoztatasok
al3x
parents:
1038
diff
changeset
|
2 ao_alsa5 - ALSA-0.5.x output plugin for MPlayer |
996 | 3 |
4 (C) Alex Beregszaszi <alex@naxine.org> | |
5 | |
6 Thanks to Arpi for helping me ;) | |
7 */ | |
8 | |
9 #include <errno.h> | |
10 #include <sys/asoundlib.h> | |
11 | |
12 #include "../config.h" | |
13 | |
14 #include "audio_out.h" | |
15 #include "audio_out_internal.h" | |
1058 | 16 #include "afmt.h" |
996 | 17 |
18 extern int verbose; | |
19 | |
20 static ao_info_t info = | |
21 { | |
22 "ALSA-0.5.x audio output", | |
23 "alsa5", | |
24 "Alex Beregszaszi <alex@naxine.org>", | |
25 "" | |
26 }; | |
27 | |
28 LIBAO_EXTERN(alsa5) | |
29 | |
30 static snd_pcm_t *alsa_handler; | |
31 static snd_pcm_format_t alsa_format; | |
32 static int alsa_rate = SND_PCM_RATE_CONTINUOUS; | |
33 | |
34 /* to set/get/query special features/parameters */ | |
35 static int control(int cmd, int arg) | |
36 { | |
37 return(CONTROL_UNKNOWN); | |
38 } | |
39 | |
40 /* | |
41 open & setup audio device | |
42 return: 1=success 0=fail | |
43 */ | |
44 static int init(int rate_hz, int channels, int format, int flags) | |
45 { | |
46 int err; | |
47 int cards = -1; | |
48 snd_pcm_channel_params_t params; | |
49 snd_pcm_channel_setup_t setup; | |
50 snd_pcm_info_t info; | |
51 snd_pcm_channel_info_t chninfo; | |
52 | |
53 printf("alsa-init: requested format: %d Hz, %d channels, %s\n", rate_hz, | |
54 channels, audio_out_format_name(format)); | |
55 | |
56 alsa_handler = NULL; | |
57 | |
58 if (verbose) | |
59 printf("alsa-init: compiled for ALSA-%s (%d)\n", SND_LIB_VERSION_STR, | |
60 SND_LIB_VERSION); | |
61 | |
62 if ((cards = snd_cards()) < 0) | |
63 { | |
64 printf("alsa-init: no soundcards found\n"); | |
65 return(0); | |
66 } | |
67 | |
3095 | 68 ao_data.format = format; |
69 ao_data.channels = channels - 1; | |
70 ao_data.samplerate = rate_hz; | |
71 ao_data.bps = ao_data.samplerate*(ao_data.channels+1); | |
72 ao_data.outburst = OUTBURST; | |
73 ao_data.buffersize = 16384; | |
996 | 74 |
75 memset(&alsa_format, 0, sizeof(alsa_format)); | |
76 switch (format) | |
77 { | |
78 case AFMT_S8: | |
79 alsa_format.format = SND_PCM_SFMT_S8; | |
80 break; | |
81 case AFMT_U8: | |
82 alsa_format.format = SND_PCM_SFMT_U8; | |
83 break; | |
84 case AFMT_U16_LE: | |
85 alsa_format.format = SND_PCM_SFMT_U16_LE; | |
86 break; | |
87 case AFMT_U16_BE: | |
88 alsa_format.format = SND_PCM_SFMT_U16_BE; | |
89 break; | |
90 case AFMT_S16_LE: | |
91 alsa_format.format = SND_PCM_SFMT_S16_LE; | |
92 break; | |
93 case AFMT_S16_BE: | |
94 alsa_format.format = SND_PCM_SFMT_S16_BE; | |
95 break; | |
96 default: | |
97 alsa_format.format = SND_PCM_SFMT_MPEG; | |
98 break; | |
99 } | |
100 | |
101 switch(alsa_format.format) | |
102 { | |
103 case SND_PCM_SFMT_S16_LE: | |
104 case SND_PCM_SFMT_U16_LE: | |
3095 | 105 ao_data.bps *= 2; |
996 | 106 break; |
107 case -1: | |
108 printf("alsa-init: invalid format (%s) requested - output disabled\n", | |
109 audio_out_format_name(format)); | |
110 return(0); | |
1111 | 111 default: |
112 break; | |
996 | 113 } |
114 | |
115 switch(rate_hz) | |
116 { | |
117 case 8000: | |
118 alsa_rate = SND_PCM_RATE_8000; | |
119 break; | |
120 case 11025: | |
121 alsa_rate = SND_PCM_RATE_11025; | |
122 break; | |
123 case 16000: | |
124 alsa_rate = SND_PCM_RATE_16000; | |
125 break; | |
126 case 22050: | |
127 alsa_rate = SND_PCM_RATE_22050; | |
128 break; | |
129 case 32000: | |
130 alsa_rate = SND_PCM_RATE_32000; | |
131 break; | |
132 case 44100: | |
133 alsa_rate = SND_PCM_RATE_44100; | |
134 break; | |
135 case 48000: | |
136 alsa_rate = SND_PCM_RATE_48000; | |
137 break; | |
138 case 88200: | |
139 alsa_rate = SND_PCM_RATE_88200; | |
140 break; | |
141 case 96000: | |
142 alsa_rate = SND_PCM_RATE_96000; | |
143 break; | |
144 case 176400: | |
145 alsa_rate = SND_PCM_RATE_176400; | |
146 break; | |
147 case 192000: | |
148 alsa_rate = SND_PCM_RATE_192000; | |
149 break; | |
150 default: | |
151 alsa_rate = SND_PCM_RATE_CONTINUOUS; | |
152 break; | |
153 } | |
154 | |
3095 | 155 alsa_format.rate = ao_data.samplerate; |
156 alsa_format.voices = ao_data.channels*2; | |
996 | 157 alsa_format.interleave = 1; |
158 | |
159 if ((err = snd_pcm_open(&alsa_handler, 0, 0, SND_PCM_OPEN_PLAYBACK)) < 0) | |
160 { | |
161 printf("alsa-init: playback open error: %s\n", snd_strerror(err)); | |
162 return(0); | |
163 } | |
164 | |
165 if ((err = snd_pcm_info(alsa_handler, &info)) < 0) | |
166 { | |
167 printf("alsa-init: pcm info error: %s\n", snd_strerror(err)); | |
168 return(0); | |
169 } | |
170 | |
171 printf("alsa-init: %d soundcard%s found, using: %s\n", cards, | |
172 (cards == 1) ? "" : "s", info.name); | |
173 | |
174 if (info.flags & SND_PCM_INFO_PLAYBACK) | |
175 { | |
3700 | 176 memset(&chninfo, 0, sizeof(chninfo)); |
996 | 177 chninfo.channel = SND_PCM_CHANNEL_PLAYBACK; |
178 if ((err = snd_pcm_channel_info(alsa_handler, &chninfo)) < 0) | |
179 { | |
180 printf("alsa-init: pcm channel info error: %s\n", snd_strerror(err)); | |
181 return(0); | |
182 } | |
3095 | 183 |
3087
08947e067d80
compiling under qnx, hope it works on all qnx release :)
alex
parents:
1111
diff
changeset
|
184 #ifndef __QNX__ |
996 | 185 if (chninfo.buffer_size) |
3095 | 186 ao_data.buffersize = chninfo.buffer_size; |
3087
08947e067d80
compiling under qnx, hope it works on all qnx release :)
alex
parents:
1111
diff
changeset
|
187 #endif |
3095 | 188 |
996 | 189 if (verbose) |
190 printf("alsa-init: setting preferred buffer size from driver: %d bytes\n", | |
3095 | 191 ao_data.buffersize); |
996 | 192 } |
193 | |
194 memset(¶ms, 0, sizeof(params)); | |
195 params.channel = SND_PCM_CHANNEL_PLAYBACK; | |
196 params.mode = SND_PCM_MODE_STREAM; | |
197 params.format = alsa_format; | |
198 params.start_mode = SND_PCM_START_DATA; | |
199 params.stop_mode = SND_PCM_STOP_ROLLOVER; | |
3095 | 200 params.buf.stream.queue_size = ao_data.buffersize; |
996 | 201 params.buf.stream.fill = SND_PCM_FILL_NONE; |
202 | |
203 if ((err = snd_pcm_channel_params(alsa_handler, ¶ms)) < 0) | |
204 { | |
205 printf("alsa-init: error setting parameters: %s\n", snd_strerror(err)); | |
206 return(0); | |
207 } | |
208 | |
209 memset(&setup, 0, sizeof(setup)); | |
210 setup.channel = SND_PCM_CHANNEL_PLAYBACK; | |
211 setup.mode = SND_PCM_MODE_STREAM; | |
212 setup.format = alsa_format; | |
3095 | 213 setup.buf.stream.queue_size = ao_data.buffersize; |
214 setup.msbits_per_sample = ao_data.bps; | |
996 | 215 |
216 if ((err = snd_pcm_channel_setup(alsa_handler, &setup)) < 0) | |
217 { | |
218 printf("alsa-init: error setting up channel: %s\n", snd_strerror(err)); | |
219 return(0); | |
220 } | |
221 | |
222 if ((err = snd_pcm_channel_prepare(alsa_handler, SND_PCM_CHANNEL_PLAYBACK)) < 0) | |
223 { | |
224 printf("alsa-init: channel prepare error: %s\n", snd_strerror(err)); | |
225 return(0); | |
226 } | |
227 | |
228 printf("AUDIO: %d Hz/%d channels/%d bps/%d bytes buffer/%s\n", | |
3095 | 229 ao_data.samplerate, ao_data.channels+1, ao_data.bps, ao_data.buffersize, |
996 | 230 snd_pcm_get_format_name(alsa_format.format)); |
231 return(1); | |
232 } | |
233 | |
234 /* close audio device */ | |
235 static void uninit() | |
236 { | |
1055 | 237 int err; |
238 | |
1046
59fc1f75e486
audio_pause/resume implementacio es kozmetikai valtoztatasok
al3x
parents:
1038
diff
changeset
|
239 if ((err = snd_pcm_playback_drain(alsa_handler)) < 0) |
59fc1f75e486
audio_pause/resume implementacio es kozmetikai valtoztatasok
al3x
parents:
1038
diff
changeset
|
240 { |
59fc1f75e486
audio_pause/resume implementacio es kozmetikai valtoztatasok
al3x
parents:
1038
diff
changeset
|
241 printf("alsa-uninit: playback drain error: %s\n", snd_strerror(err)); |
59fc1f75e486
audio_pause/resume implementacio es kozmetikai valtoztatasok
al3x
parents:
1038
diff
changeset
|
242 return; |
59fc1f75e486
audio_pause/resume implementacio es kozmetikai valtoztatasok
al3x
parents:
1038
diff
changeset
|
243 } |
59fc1f75e486
audio_pause/resume implementacio es kozmetikai valtoztatasok
al3x
parents:
1038
diff
changeset
|
244 |
59fc1f75e486
audio_pause/resume implementacio es kozmetikai valtoztatasok
al3x
parents:
1038
diff
changeset
|
245 if ((err = snd_pcm_channel_flush(alsa_handler, SND_PCM_CHANNEL_PLAYBACK)) < 0) |
59fc1f75e486
audio_pause/resume implementacio es kozmetikai valtoztatasok
al3x
parents:
1038
diff
changeset
|
246 { |
59fc1f75e486
audio_pause/resume implementacio es kozmetikai valtoztatasok
al3x
parents:
1038
diff
changeset
|
247 printf("alsa-uninit: playback flush error: %s\n", snd_strerror(err)); |
59fc1f75e486
audio_pause/resume implementacio es kozmetikai valtoztatasok
al3x
parents:
1038
diff
changeset
|
248 return; |
59fc1f75e486
audio_pause/resume implementacio es kozmetikai valtoztatasok
al3x
parents:
1038
diff
changeset
|
249 } |
59fc1f75e486
audio_pause/resume implementacio es kozmetikai valtoztatasok
al3x
parents:
1038
diff
changeset
|
250 |
59fc1f75e486
audio_pause/resume implementacio es kozmetikai valtoztatasok
al3x
parents:
1038
diff
changeset
|
251 if ((err = snd_pcm_close(alsa_handler)) < 0) |
59fc1f75e486
audio_pause/resume implementacio es kozmetikai valtoztatasok
al3x
parents:
1038
diff
changeset
|
252 { |
59fc1f75e486
audio_pause/resume implementacio es kozmetikai valtoztatasok
al3x
parents:
1038
diff
changeset
|
253 printf("alsa-uninit: pcm close error: %s\n", snd_strerror(err)); |
59fc1f75e486
audio_pause/resume implementacio es kozmetikai valtoztatasok
al3x
parents:
1038
diff
changeset
|
254 return; |
59fc1f75e486
audio_pause/resume implementacio es kozmetikai valtoztatasok
al3x
parents:
1038
diff
changeset
|
255 } |
996 | 256 } |
257 | |
258 /* stop playing and empty buffers (for seeking/pause) */ | |
259 static void reset() | |
260 { | |
261 int err; | |
262 | |
263 if ((err = snd_pcm_playback_drain(alsa_handler)) < 0) | |
264 { | |
265 printf("alsa-reset: playback drain error: %s\n", snd_strerror(err)); | |
266 return; | |
267 } | |
268 | |
269 if ((err = snd_pcm_channel_flush(alsa_handler, SND_PCM_CHANNEL_PLAYBACK)) < 0) | |
270 { | |
271 printf("alsa-reset: playback flush error: %s\n", snd_strerror(err)); | |
272 return; | |
273 } | |
274 | |
275 if ((err = snd_pcm_channel_prepare(alsa_handler, SND_PCM_CHANNEL_PLAYBACK)) < 0) | |
276 { | |
277 printf("alsa-reset: channel prepare error: %s\n", snd_strerror(err)); | |
278 return; | |
279 } | |
280 } | |
281 | |
1038
b36fb1ae4b53
applied solaris8/netbsd/other fixes patch by J¸«ärgen Keil <jk@tools.de>
arpi_esp
parents:
996
diff
changeset
|
282 /* stop playing, keep buffers (for pause) */ |
b36fb1ae4b53
applied solaris8/netbsd/other fixes patch by J¸«ärgen Keil <jk@tools.de>
arpi_esp
parents:
996
diff
changeset
|
283 static void audio_pause() |
b36fb1ae4b53
applied solaris8/netbsd/other fixes patch by J¸«ärgen Keil <jk@tools.de>
arpi_esp
parents:
996
diff
changeset
|
284 { |
1046
59fc1f75e486
audio_pause/resume implementacio es kozmetikai valtoztatasok
al3x
parents:
1038
diff
changeset
|
285 int err; |
59fc1f75e486
audio_pause/resume implementacio es kozmetikai valtoztatasok
al3x
parents:
1038
diff
changeset
|
286 |
59fc1f75e486
audio_pause/resume implementacio es kozmetikai valtoztatasok
al3x
parents:
1038
diff
changeset
|
287 if ((err = snd_pcm_playback_drain(alsa_handler)) < 0) |
59fc1f75e486
audio_pause/resume implementacio es kozmetikai valtoztatasok
al3x
parents:
1038
diff
changeset
|
288 { |
59fc1f75e486
audio_pause/resume implementacio es kozmetikai valtoztatasok
al3x
parents:
1038
diff
changeset
|
289 printf("alsa-pause: playback drain error: %s\n", snd_strerror(err)); |
59fc1f75e486
audio_pause/resume implementacio es kozmetikai valtoztatasok
al3x
parents:
1038
diff
changeset
|
290 return; |
59fc1f75e486
audio_pause/resume implementacio es kozmetikai valtoztatasok
al3x
parents:
1038
diff
changeset
|
291 } |
59fc1f75e486
audio_pause/resume implementacio es kozmetikai valtoztatasok
al3x
parents:
1038
diff
changeset
|
292 |
59fc1f75e486
audio_pause/resume implementacio es kozmetikai valtoztatasok
al3x
parents:
1038
diff
changeset
|
293 if ((err = snd_pcm_channel_flush(alsa_handler, SND_PCM_CHANNEL_PLAYBACK)) < 0) |
59fc1f75e486
audio_pause/resume implementacio es kozmetikai valtoztatasok
al3x
parents:
1038
diff
changeset
|
294 { |
59fc1f75e486
audio_pause/resume implementacio es kozmetikai valtoztatasok
al3x
parents:
1038
diff
changeset
|
295 printf("alsa-pause: playback flush error: %s\n", snd_strerror(err)); |
59fc1f75e486
audio_pause/resume implementacio es kozmetikai valtoztatasok
al3x
parents:
1038
diff
changeset
|
296 return; |
59fc1f75e486
audio_pause/resume implementacio es kozmetikai valtoztatasok
al3x
parents:
1038
diff
changeset
|
297 } |
1038
b36fb1ae4b53
applied solaris8/netbsd/other fixes patch by J¸«ärgen Keil <jk@tools.de>
arpi_esp
parents:
996
diff
changeset
|
298 } |
b36fb1ae4b53
applied solaris8/netbsd/other fixes patch by J¸«ärgen Keil <jk@tools.de>
arpi_esp
parents:
996
diff
changeset
|
299 |
b36fb1ae4b53
applied solaris8/netbsd/other fixes patch by J¸«ärgen Keil <jk@tools.de>
arpi_esp
parents:
996
diff
changeset
|
300 /* resume playing, after audio_pause() */ |
b36fb1ae4b53
applied solaris8/netbsd/other fixes patch by J¸«ärgen Keil <jk@tools.de>
arpi_esp
parents:
996
diff
changeset
|
301 static void audio_resume() |
b36fb1ae4b53
applied solaris8/netbsd/other fixes patch by J¸«ärgen Keil <jk@tools.de>
arpi_esp
parents:
996
diff
changeset
|
302 { |
1055 | 303 int err; |
1046
59fc1f75e486
audio_pause/resume implementacio es kozmetikai valtoztatasok
al3x
parents:
1038
diff
changeset
|
304 if ((err = snd_pcm_channel_prepare(alsa_handler, SND_PCM_CHANNEL_PLAYBACK)) < 0) |
59fc1f75e486
audio_pause/resume implementacio es kozmetikai valtoztatasok
al3x
parents:
1038
diff
changeset
|
305 { |
59fc1f75e486
audio_pause/resume implementacio es kozmetikai valtoztatasok
al3x
parents:
1038
diff
changeset
|
306 printf("alsa-resume: channel prepare error: %s\n", snd_strerror(err)); |
59fc1f75e486
audio_pause/resume implementacio es kozmetikai valtoztatasok
al3x
parents:
1038
diff
changeset
|
307 return; |
59fc1f75e486
audio_pause/resume implementacio es kozmetikai valtoztatasok
al3x
parents:
1038
diff
changeset
|
308 } |
1038
b36fb1ae4b53
applied solaris8/netbsd/other fixes patch by J¸«ärgen Keil <jk@tools.de>
arpi_esp
parents:
996
diff
changeset
|
309 } |
b36fb1ae4b53
applied solaris8/netbsd/other fixes patch by J¸«ärgen Keil <jk@tools.de>
arpi_esp
parents:
996
diff
changeset
|
310 |
996 | 311 /* |
312 plays 'len' bytes of 'data' | |
313 returns: number of bytes played | |
314 */ | |
315 static int play(void* data, int len, int flags) | |
316 { | |
317 if ((len = snd_pcm_write(alsa_handler, data, len)) != len) | |
318 { | |
319 if (len == -EPIPE) /* underrun? */ | |
320 { | |
321 printf("alsa-play: alsa underrun, resetting stream\n"); | |
322 if ((len = snd_pcm_channel_prepare(alsa_handler, SND_PCM_CHANNEL_PLAYBACK)) < 0) | |
323 { | |
324 printf("alsa-play: playback prepare error: %s\n", snd_strerror(len)); | |
325 return(0); | |
326 } | |
327 if ((len = snd_pcm_write(alsa_handler, data, len)) != len) | |
328 { | |
329 printf("alsa-play: write error after reset: %s - giving up\n", | |
330 snd_strerror(len)); | |
331 return(0); | |
332 } | |
333 return(len); /* 2nd write was ok */ | |
334 } | |
335 printf("alsa-play: output error: %s\n", snd_strerror(len)); | |
336 } | |
337 return(len); | |
338 } | |
339 | |
340 /* how many byes are free in the buffer */ | |
341 static int get_space() | |
342 { | |
343 snd_pcm_channel_status_t ch_stat; | |
344 | |
345 ch_stat.channel = SND_PCM_CHANNEL_PLAYBACK; | |
346 | |
347 if (snd_pcm_channel_status(alsa_handler, &ch_stat) < 0) | |
1046
59fc1f75e486
audio_pause/resume implementacio es kozmetikai valtoztatasok
al3x
parents:
1038
diff
changeset
|
348 return(0); /* error occured */ |
996 | 349 else |
350 return(ch_stat.free); | |
351 } | |
352 | |
3095 | 353 /* delay in seconds between first and last sample in buffer */ |
354 static float get_delay() | |
996 | 355 { |
356 snd_pcm_channel_status_t ch_stat; | |
357 | |
358 ch_stat.channel = SND_PCM_CHANNEL_PLAYBACK; | |
359 | |
360 if (snd_pcm_channel_status(alsa_handler, &ch_stat) < 0) | |
3095 | 361 return((float)ao_data.buffersize/(float)ao_data.bps); /* error occured */ |
996 | 362 else |
3095 | 363 return((float)ch_stat.count/(float)ao_data.bps); |
996 | 364 } |