Mercurial > mplayer.hg
annotate libao2/ao_alsa.c @ 16429:84174804804b
Updates to NUT spec:
1. remove average_bitrate
2. add other_stream_header, for subtitles and metadata
3. add max_pts to index
4. index_ptr - a 64 bit integer to say the total length of all index packets
5. specify how to write "multiple" indexes
6. change forward_ptr behavior, starts right after forward_ptr, ends after
checksum
7. remove stream_id <-> stream_class limitation.
8. time_base_nom must also be non zero.
9. rename time_base_nom and time_base_denom, now timebase means the length
of a tick, not amounts of ticks
10. remove (old?) sample_rate_mul stuff.
11. specify what exactly the checksum covers.
12. specify that stream classes which have multiple streams must have an
info packet.. (in new Semantic requirements section)
13. Rename 'timestamp' to pts.
14. Change date of draft...
15. Add myself to authors...
author | ods15 |
---|---|
date | Fri, 09 Sep 2005 10:26:21 +0000 |
parents | aa7829aa8428 |
children | 3473cbf126d7 |
rev | line source |
---|---|
12465 | 1 /* |
2 ao_alsa9/1.x - ALSA-0.9.x-1.x output plugin for MPlayer | |
3 | |
4 (C) Alex Beregszaszi | |
5 | |
6 modified for real alsa-0.9.0-support by Zsolt Barat <joy@streamminister.de> | |
7 additional AC3 passthrough support by Andy Lo A Foe <andy@alsaplayer.org> | |
8 08/22/2002 iec958-init rewritten and merged with common init, zsolt | |
9 04/13/2004 merged with ao_alsa1.x, fixes provided by Jindrich Makovicka | |
10 04/25/2004 printfs converted to mp_msg, Zsolt. | |
11 | |
12 Any bugreports regarding to this driver are welcome. | |
13 */ | |
14 | |
15 #include <errno.h> | |
16 #include <sys/time.h> | |
17 #include <stdlib.h> | |
18 #include <math.h> | |
19 #include <string.h> | |
20 #include <sys/poll.h> | |
21 | |
14123 | 22 #include "config.h" |
14328 | 23 #include "subopt-helper.h" |
14123 | 24 #include "mixer.h" |
25 #include "mp_msg.h" | |
12465 | 26 |
27 #define ALSA_PCM_NEW_HW_PARAMS_API | |
28 #define ALSA_PCM_NEW_SW_PARAMS_API | |
29 | |
30 #if HAVE_SYS_ASOUNDLIB_H | |
31 #include <sys/asoundlib.h> | |
32 #elif HAVE_ALSA_ASOUNDLIB_H | |
33 #include <alsa/asoundlib.h> | |
34 #else | |
35 #error "asoundlib.h is not in sys/ or alsa/ - please bugreport" | |
36 #endif | |
37 | |
38 | |
39 #include "audio_out.h" | |
40 #include "audio_out_internal.h" | |
14245 | 41 #include "libaf/af_format.h" |
12465 | 42 |
43 static ao_info_t info = | |
44 { | |
45 "ALSA-0.9.x-1.x audio output", | |
46 "alsa", | |
47 "Alex Beregszaszi, Zsolt Barat <joy@streamminister.de>", | |
48 "under developement" | |
49 }; | |
50 | |
51 LIBAO_EXTERN(alsa) | |
52 | |
53 static snd_pcm_t *alsa_handler; | |
54 static snd_pcm_format_t alsa_format; | |
55 static snd_pcm_hw_params_t *alsa_hwparams; | |
56 static snd_pcm_sw_params_t *alsa_swparams; | |
57 | |
58 /* possible 4096, original 8192 | |
59 * was only needed for calculating chunksize? */ | |
60 static int alsa_fragsize = 4096; | |
61 /* 16 sets buffersize to 16 * chunksize is as default 1024 | |
62 * which seems to be good avarge for most situations | |
63 * so buffersize is 16384 frames by default */ | |
64 static int alsa_fragcount = 16; | |
65 static snd_pcm_uframes_t chunk_size = 1024;//is alsa_fragsize / 4 | |
66 | |
67 #define MIN_CHUNK_SIZE 1024 | |
68 | |
69 static size_t bits_per_sample, bytes_per_sample, bits_per_frame; | |
70 static size_t chunk_bytes; | |
71 | |
72 int ao_mmap = 0; | |
73 int ao_noblock = 0; | |
74 int first = 1; | |
75 | |
76 static int open_mode; | |
77 static int set_block_mode; | |
78 static int alsa_can_pause = 0; | |
79 | |
12747 | 80 #define ALSA_DEVICE_SIZE 256 |
12465 | 81 |
82 #undef BUFFERTIME | |
12805
0b154063a3ca
fixes provided by reimar drfinger. mixer, subdevice parsing, alsa#help,
joyping
parents:
12747
diff
changeset
|
83 #define SET_CHUNKSIZE |
12465 | 84 #undef USE_POLL |
85 | |
86 /* to set/get/query special features/parameters */ | |
87 static int control(int cmd, void *arg) | |
88 { | |
89 switch(cmd) { | |
90 case AOCONTROL_QUERY_FORMAT: | |
91 return CONTROL_TRUE; | |
92 #ifndef WORDS_BIGENDIAN | |
93 case AOCONTROL_GET_VOLUME: | |
94 case AOCONTROL_SET_VOLUME: | |
95 { | |
96 ao_control_vol_t *vol = (ao_control_vol_t *)arg; | |
97 | |
98 int err; | |
99 snd_mixer_t *handle; | |
100 snd_mixer_elem_t *elem; | |
101 snd_mixer_selem_id_t *sid; | |
102 | |
12747 | 103 static char *mix_name = "PCM"; |
104 static char *card = "default"; | |
13434 | 105 static int mix_index = 0; |
12465 | 106 |
107 long pmin, pmax; | |
108 long get_vol, set_vol; | |
12805
0b154063a3ca
fixes provided by reimar drfinger. mixer, subdevice parsing, alsa#help,
joyping
parents:
12747
diff
changeset
|
109 float f_multi; |
12465 | 110 |
13434 | 111 if(mixer_channel) { |
112 char *test_mix_index; | |
113 | |
114 mix_name = strdup(mixer_channel); | |
115 if (test_mix_index = strchr(mix_name, ',')){ | |
116 *test_mix_index = 0; | |
117 test_mix_index++; | |
118 mix_index = strtol(test_mix_index, &test_mix_index, 0); | |
119 | |
120 if (*test_mix_index){ | |
121 mp_msg(MSGT_AO,MSGL_ERR, | |
122 "alsa-control: invalid mixer index. Defaulting to 0\n"); | |
123 mix_index = 0 ; | |
124 } | |
125 } | |
126 } | |
12747 | 127 if(mixer_device) card = mixer_device; |
12465 | 128 |
14245 | 129 if(ao_data.format == AF_FORMAT_AC3) |
12465 | 130 return CONTROL_TRUE; |
131 | |
132 //allocate simple id | |
133 snd_mixer_selem_id_alloca(&sid); | |
134 | |
135 //sets simple-mixer index and name | |
13434 | 136 snd_mixer_selem_id_set_index(sid, mix_index); |
12465 | 137 snd_mixer_selem_id_set_name(sid, mix_name); |
138 | |
13434 | 139 if (mixer_channel) { |
140 free(mix_name); | |
141 mix_name = NULL; | |
142 } | |
143 | |
12465 | 144 if ((err = snd_mixer_open(&handle, 0)) < 0) { |
145 mp_msg(MSGT_AO,MSGL_ERR,"alsa-control: mixer open error: %s\n", snd_strerror(err)); | |
146 return CONTROL_ERROR; | |
147 } | |
148 | |
149 if ((err = snd_mixer_attach(handle, card)) < 0) { | |
150 mp_msg(MSGT_AO,MSGL_ERR,"alsa-control: mixer attach %s error: %s\n", | |
151 card, snd_strerror(err)); | |
152 snd_mixer_close(handle); | |
153 return CONTROL_ERROR; | |
154 } | |
155 | |
156 if ((err = snd_mixer_selem_register(handle, NULL, NULL)) < 0) { | |
157 mp_msg(MSGT_AO,MSGL_ERR,"alsa-control: mixer register error: %s\n", snd_strerror(err)); | |
158 snd_mixer_close(handle); | |
159 return CONTROL_ERROR; | |
160 } | |
161 err = snd_mixer_load(handle); | |
162 if (err < 0) { | |
163 mp_msg(MSGT_AO,MSGL_ERR,"alsa-control: mixer load error: %s\n", snd_strerror(err)); | |
164 snd_mixer_close(handle); | |
165 return CONTROL_ERROR; | |
166 } | |
167 | |
168 elem = snd_mixer_find_selem(handle, sid); | |
169 if (!elem) { | |
170 mp_msg(MSGT_AO,MSGL_ERR,"alsa-control: unable to find simple control '%s',%i\n", | |
171 snd_mixer_selem_id_get_name(sid), snd_mixer_selem_id_get_index(sid)); | |
172 snd_mixer_close(handle); | |
173 return CONTROL_ERROR; | |
174 } | |
175 | |
176 snd_mixer_selem_get_playback_volume_range(elem,&pmin,&pmax); | |
12811
d5f8efddac6c
volume calc fixes for mixer, by reimar dffinger, 10l reverse by me
joyping
parents:
12805
diff
changeset
|
177 f_multi = (100 / (float)(pmax - pmin)); |
12465 | 178 |
179 if (cmd == AOCONTROL_SET_VOLUME) { | |
180 | |
12811
d5f8efddac6c
volume calc fixes for mixer, by reimar dffinger, 10l reverse by me
joyping
parents:
12805
diff
changeset
|
181 set_vol = vol->left / f_multi + pmin + 0.5; |
12465 | 182 |
183 //setting channels | |
184 if ((err = snd_mixer_selem_set_playback_volume(elem, 0, set_vol)) < 0) { | |
185 mp_msg(MSGT_AO,MSGL_ERR,"alsa-control: error setting left channel, %s\n", | |
186 snd_strerror(err)); | |
187 return CONTROL_ERROR; | |
188 } | |
12805
0b154063a3ca
fixes provided by reimar drfinger. mixer, subdevice parsing, alsa#help,
joyping
parents:
12747
diff
changeset
|
189 mp_msg(MSGT_AO,MSGL_DBG2,"left=%li, ", set_vol); |
0b154063a3ca
fixes provided by reimar drfinger. mixer, subdevice parsing, alsa#help,
joyping
parents:
12747
diff
changeset
|
190 |
12811
d5f8efddac6c
volume calc fixes for mixer, by reimar dffinger, 10l reverse by me
joyping
parents:
12805
diff
changeset
|
191 set_vol = vol->right / f_multi + pmin + 0.5; |
12805
0b154063a3ca
fixes provided by reimar drfinger. mixer, subdevice parsing, alsa#help,
joyping
parents:
12747
diff
changeset
|
192 |
12465 | 193 if ((err = snd_mixer_selem_set_playback_volume(elem, 1, set_vol)) < 0) { |
194 mp_msg(MSGT_AO,MSGL_ERR,"alsa-control: error setting right channel, %s\n", | |
195 snd_strerror(err)); | |
196 return CONTROL_ERROR; | |
197 } | |
12805
0b154063a3ca
fixes provided by reimar drfinger. mixer, subdevice parsing, alsa#help,
joyping
parents:
12747
diff
changeset
|
198 mp_msg(MSGT_AO,MSGL_DBG2,"right=%li, pmin=%li, pmax=%li, mult=%f\n", |
0b154063a3ca
fixes provided by reimar drfinger. mixer, subdevice parsing, alsa#help,
joyping
parents:
12747
diff
changeset
|
199 set_vol, pmin, pmax, f_multi); |
12465 | 200 } |
201 else { | |
202 snd_mixer_selem_get_playback_volume(elem, 0, &get_vol); | |
12811
d5f8efddac6c
volume calc fixes for mixer, by reimar dffinger, 10l reverse by me
joyping
parents:
12805
diff
changeset
|
203 vol->left = (get_vol - pmin) * f_multi; |
12805
0b154063a3ca
fixes provided by reimar drfinger. mixer, subdevice parsing, alsa#help,
joyping
parents:
12747
diff
changeset
|
204 snd_mixer_selem_get_playback_volume(elem, 1, &get_vol); |
12811
d5f8efddac6c
volume calc fixes for mixer, by reimar dffinger, 10l reverse by me
joyping
parents:
12805
diff
changeset
|
205 vol->right = (get_vol - pmin) * f_multi; |
12465 | 206 |
12805
0b154063a3ca
fixes provided by reimar drfinger. mixer, subdevice parsing, alsa#help,
joyping
parents:
12747
diff
changeset
|
207 mp_msg(MSGT_AO,MSGL_DBG2,"left=%f, right=%f\n",vol->left,vol->right); |
12465 | 208 } |
209 snd_mixer_close(handle); | |
210 return CONTROL_OK; | |
211 } | |
212 #endif | |
213 | |
214 } //end switch | |
215 return(CONTROL_UNKNOWN); | |
216 } | |
217 | |
14328 | 218 static void parse_device (char *dest, const char *src, int len) |
12805
0b154063a3ca
fixes provided by reimar drfinger. mixer, subdevice parsing, alsa#help,
joyping
parents:
12747
diff
changeset
|
219 { |
0b154063a3ca
fixes provided by reimar drfinger. mixer, subdevice parsing, alsa#help,
joyping
parents:
12747
diff
changeset
|
220 char *tmp; |
14328 | 221 memmove(dest, src, len); |
222 dest[len] = 0; | |
12805
0b154063a3ca
fixes provided by reimar drfinger. mixer, subdevice parsing, alsa#help,
joyping
parents:
12747
diff
changeset
|
223 while ((tmp = strrchr(dest, '.'))) |
0b154063a3ca
fixes provided by reimar drfinger. mixer, subdevice parsing, alsa#help,
joyping
parents:
12747
diff
changeset
|
224 tmp[0] = ','; |
12919
aba44b58dea7
Use = instead if # in ALSA device name, as # irritates our config-parser.
reimar
parents:
12819
diff
changeset
|
225 while ((tmp = strrchr(dest, '='))) |
12805
0b154063a3ca
fixes provided by reimar drfinger. mixer, subdevice parsing, alsa#help,
joyping
parents:
12747
diff
changeset
|
226 tmp[0] = ':'; |
0b154063a3ca
fixes provided by reimar drfinger. mixer, subdevice parsing, alsa#help,
joyping
parents:
12747
diff
changeset
|
227 } |
0b154063a3ca
fixes provided by reimar drfinger. mixer, subdevice parsing, alsa#help,
joyping
parents:
12747
diff
changeset
|
228 |
0b154063a3ca
fixes provided by reimar drfinger. mixer, subdevice parsing, alsa#help,
joyping
parents:
12747
diff
changeset
|
229 static void print_help () |
0b154063a3ca
fixes provided by reimar drfinger. mixer, subdevice parsing, alsa#help,
joyping
parents:
12747
diff
changeset
|
230 { |
0b154063a3ca
fixes provided by reimar drfinger. mixer, subdevice parsing, alsa#help,
joyping
parents:
12747
diff
changeset
|
231 mp_msg (MSGT_AO, MSGL_FATAL, |
0b154063a3ca
fixes provided by reimar drfinger. mixer, subdevice parsing, alsa#help,
joyping
parents:
12747
diff
changeset
|
232 "\n-ao alsa commandline help:\n" |
12919
aba44b58dea7
Use = instead if # in ALSA device name, as # irritates our config-parser.
reimar
parents:
12819
diff
changeset
|
233 "Example: mplayer -ao alsa:mmap:device=hw=0.3\n" |
12805
0b154063a3ca
fixes provided by reimar drfinger. mixer, subdevice parsing, alsa#help,
joyping
parents:
12747
diff
changeset
|
234 " sets mmap-mode and first card fourth device\n" |
0b154063a3ca
fixes provided by reimar drfinger. mixer, subdevice parsing, alsa#help,
joyping
parents:
12747
diff
changeset
|
235 "\nOptions:\n" |
0b154063a3ca
fixes provided by reimar drfinger. mixer, subdevice parsing, alsa#help,
joyping
parents:
12747
diff
changeset
|
236 " mmap\n" |
0b154063a3ca
fixes provided by reimar drfinger. mixer, subdevice parsing, alsa#help,
joyping
parents:
12747
diff
changeset
|
237 " Set memory-mapped mode, experimental\n" |
0b154063a3ca
fixes provided by reimar drfinger. mixer, subdevice parsing, alsa#help,
joyping
parents:
12747
diff
changeset
|
238 " noblock\n" |
0b154063a3ca
fixes provided by reimar drfinger. mixer, subdevice parsing, alsa#help,
joyping
parents:
12747
diff
changeset
|
239 " Sets non-blocking mode\n" |
0b154063a3ca
fixes provided by reimar drfinger. mixer, subdevice parsing, alsa#help,
joyping
parents:
12747
diff
changeset
|
240 " device=<device-name>\n" |
12919
aba44b58dea7
Use = instead if # in ALSA device name, as # irritates our config-parser.
reimar
parents:
12819
diff
changeset
|
241 " Sets device (change , to . and : to =)\n"); |
12805
0b154063a3ca
fixes provided by reimar drfinger. mixer, subdevice parsing, alsa#help,
joyping
parents:
12747
diff
changeset
|
242 } |
12465 | 243 |
14328 | 244 static int str_maxlen(strarg_t *str) { |
245 if (str->len > ALSA_DEVICE_SIZE) | |
246 return 0; | |
247 return 1; | |
248 } | |
249 | |
12465 | 250 /* |
251 open & setup audio device | |
252 return: 1=success 0=fail | |
253 */ | |
254 static int init(int rate_hz, int channels, int format, int flags) | |
255 { | |
256 int err; | |
257 int cards = -1; | |
258 snd_pcm_info_t *alsa_info; | |
259 char *str_block_mode; | |
260 int dir = 0; | |
14328 | 261 int block; |
262 strarg_t device; | |
12465 | 263 snd_pcm_uframes_t bufsize; |
14328 | 264 opt_t subopts[] = { |
265 {"mmap", OPT_ARG_BOOL, &ao_mmap, NULL}, | |
266 {"block", OPT_ARG_BOOL, &block, NULL}, | |
267 {"device", OPT_ARG_STR, &device, (opt_test_f)str_maxlen}, | |
268 {NULL} | |
269 }; | |
270 | |
12747 | 271 char alsa_device[ALSA_DEVICE_SIZE + 1]; |
272 // make sure alsa_device is null-terminated even when using strncpy etc. | |
273 memset(alsa_device, 0, ALSA_DEVICE_SIZE + 1); | |
12465 | 274 |
14249 | 275 mp_msg(MSGT_AO,MSGL_V,"alsa-init: requested format: %d Hz, %d channels, %x\n", rate_hz, |
276 channels, format); | |
12465 | 277 alsa_handler = NULL; |
278 mp_msg(MSGT_AO,MSGL_V,"alsa-init: compiled for ALSA-%s\n", SND_LIB_VERSION_STR); | |
279 | |
280 if ((err = snd_card_next(&cards)) < 0 || cards < 0) | |
281 { | |
282 mp_msg(MSGT_AO,MSGL_ERR,"alsa-init: no soundcards found: %s\n", snd_strerror(err)); | |
283 return(0); | |
284 } | |
285 | |
286 ao_data.samplerate = rate_hz; | |
287 ao_data.format = format; | |
288 ao_data.channels = channels; | |
289 ao_data.outburst = OUTBURST; | |
290 | |
291 switch (format) | |
292 { | |
14245 | 293 case AF_FORMAT_S8: |
12465 | 294 alsa_format = SND_PCM_FORMAT_S8; |
295 break; | |
14245 | 296 case AF_FORMAT_U8: |
12465 | 297 alsa_format = SND_PCM_FORMAT_U8; |
298 break; | |
14245 | 299 case AF_FORMAT_U16_LE: |
12465 | 300 alsa_format = SND_PCM_FORMAT_U16_LE; |
301 break; | |
14245 | 302 case AF_FORMAT_U16_BE: |
12465 | 303 alsa_format = SND_PCM_FORMAT_U16_BE; |
304 break; | |
305 #ifndef WORDS_BIGENDIAN | |
14245 | 306 case AF_FORMAT_AC3: |
12465 | 307 #endif |
14245 | 308 case AF_FORMAT_S16_LE: |
12465 | 309 alsa_format = SND_PCM_FORMAT_S16_LE; |
310 break; | |
311 #ifdef WORDS_BIGENDIAN | |
14245 | 312 case AF_FORMAT_AC3: |
12465 | 313 #endif |
14245 | 314 case AF_FORMAT_S16_BE: |
12465 | 315 alsa_format = SND_PCM_FORMAT_S16_BE; |
316 break; | |
14245 | 317 case AF_FORMAT_S32_LE: |
12465 | 318 alsa_format = SND_PCM_FORMAT_S32_LE; |
319 break; | |
14245 | 320 case AF_FORMAT_S32_BE: |
12465 | 321 alsa_format = SND_PCM_FORMAT_S32_BE; |
322 break; | |
14245 | 323 case AF_FORMAT_FLOAT_LE: |
12570 | 324 alsa_format = SND_PCM_FORMAT_FLOAT_LE; |
325 break; | |
12465 | 326 |
327 default: | |
14251 | 328 alsa_format = SND_PCM_FORMAT_MPEG; //? default should be -1 |
12465 | 329 break; |
330 } | |
331 | |
12805
0b154063a3ca
fixes provided by reimar drfinger. mixer, subdevice parsing, alsa#help,
joyping
parents:
12747
diff
changeset
|
332 //subdevice parsing |
14328 | 333 // set defaults |
334 ao_mmap = 0; | |
335 block = 1; | |
12465 | 336 /* switch for spdif |
337 * sets opening sequence for SPDIF | |
338 * sets also the playback and other switches 'on the fly' | |
339 * while opening the abstract alias for the spdif subdevice | |
340 * 'iec958' | |
341 */ | |
14245 | 342 if (format == AF_FORMAT_AC3) { |
12465 | 343 unsigned char s[4]; |
344 | |
345 s[0] = IEC958_AES0_NONAUDIO | | |
346 IEC958_AES0_CON_EMPHASIS_NONE; | |
347 s[1] = IEC958_AES1_CON_ORIGINAL | | |
348 IEC958_AES1_CON_PCM_CODER; | |
349 s[2] = 0; | |
350 s[3] = IEC958_AES3_CON_FS_48000; | |
351 | |
12747 | 352 snprintf(alsa_device, ALSA_DEVICE_SIZE, |
14612 | 353 "iec958:{CARD 0 AES0 0x%02x AES1 0x%02x AES2 0x%02x AES3 0x%02x}", |
12747 | 354 s[0], s[1], s[2], s[3]); |
14328 | 355 device.str = alsa_device; |
12465 | 356 |
12747 | 357 mp_msg(MSGT_AO,MSGL_V,"alsa-spdif-init: playing AC3, %i channels\n", channels); |
12465 | 358 } |
13661
07dc40f25068
Only use S/PDIF output when no other alsa device is set, allows to use
reimar
parents:
13434
diff
changeset
|
359 else |
14328 | 360 /* in any case for multichannel playback we should select |
361 * appropriate device | |
362 */ | |
363 switch (channels) { | |
364 case 1: | |
365 case 2: | |
366 device.str = "default"; | |
367 mp_msg(MSGT_AO,MSGL_V,"alsa-init: setup for 1/2 channel(s)\n"); | |
368 break; | |
369 case 4: | |
370 if (alsa_format == SND_PCM_FORMAT_FLOAT_LE) | |
371 // hack - use the converter plugin | |
372 device.str = "plug:surround40"; | |
373 else | |
374 device.str = "surround40"; | |
375 mp_msg(MSGT_AO,MSGL_V,"alsa-init: device set to surround40\n"); | |
376 break; | |
377 case 6: | |
378 if (alsa_format == SND_PCM_FORMAT_FLOAT_LE) | |
379 device.str = "plug:surround51"; | |
380 else | |
381 device.str = "surround51"; | |
382 mp_msg(MSGT_AO,MSGL_V,"alsa-init: device set to surround51\n"); | |
383 break; | |
384 default: | |
385 device.str = "default"; | |
386 mp_msg(MSGT_AO,MSGL_ERR,"alsa-init: %d channels are not supported\n",channels); | |
387 } | |
388 device.len = strlen(device.str); | |
389 if (subopt_parse(ao_subdevice, subopts) != 0) { | |
390 print_help(); | |
391 return 0; | |
392 } | |
393 ao_noblock = !block; | |
394 parse_device(alsa_device, device.str, device.len); | |
12465 | 395 |
396 mp_msg(MSGT_AO,MSGL_INFO,"alsa-init: %d soundcard%s found, using: %s\n", cards+1,(cards >= 0) ? "" : "s", alsa_device); | |
397 | |
398 //setting modes for block or nonblock-mode | |
399 if (ao_noblock) { | |
400 open_mode = SND_PCM_NONBLOCK; | |
401 set_block_mode = 1; | |
402 str_block_mode = "nonblock-mode"; | |
403 } | |
404 else { | |
405 open_mode = 0; | |
406 set_block_mode = 0; | |
407 str_block_mode = "block-mode"; | |
408 } | |
409 | |
410 //sets buff/chunksize if its set manually | |
411 if (ao_data.buffersize) { | |
412 switch (ao_data.buffersize) | |
413 { | |
414 case 1: | |
415 alsa_fragcount = 16; | |
416 chunk_size = 512; | |
417 mp_msg(MSGT_AO,MSGL_V,"alsa-init: buffersize set manually to 8192\n"); | |
418 mp_msg(MSGT_AO,MSGL_V,"alsa-init: chunksize set manually to 512\n"); | |
419 break; | |
420 case 2: | |
421 alsa_fragcount = 8; | |
422 chunk_size = 1024; | |
423 mp_msg(MSGT_AO,MSGL_V,"alsa-init: buffersize set manually to 8192\n"); | |
424 mp_msg(MSGT_AO,MSGL_V,"alsa-init: chunksize set manually to 1024\n"); | |
425 break; | |
426 case 3: | |
427 alsa_fragcount = 32; | |
428 chunk_size = 512; | |
429 mp_msg(MSGT_AO,MSGL_V,"alsa-init: buffersize set manually to 16384\n"); | |
430 mp_msg(MSGT_AO,MSGL_V,"alsa-init: chunksize set manually to 512\n"); | |
431 break; | |
432 case 4: | |
433 alsa_fragcount = 16; | |
434 chunk_size = 1024; | |
435 mp_msg(MSGT_AO,MSGL_V,"alsa-init: buffersize set manually to 16384\n"); | |
436 mp_msg(MSGT_AO,MSGL_V,"alsa-init: chunksize set manually to 1024\n"); | |
437 break; | |
438 default: | |
439 alsa_fragcount = 16; | |
440 if (ao_mmap) | |
441 chunk_size = 512; | |
442 else | |
443 chunk_size = 1024; | |
444 break; | |
445 } | |
446 } | |
447 | |
448 if (!alsa_handler) { | |
449 //modes = 0, SND_PCM_NONBLOCK, SND_PCM_ASYNC | |
450 if ((err = snd_pcm_open(&alsa_handler, alsa_device, SND_PCM_STREAM_PLAYBACK, open_mode)) < 0) | |
451 { | |
452 if (err != -EBUSY && ao_noblock) { | |
453 mp_msg(MSGT_AO,MSGL_INFO,"alsa-init: open in nonblock-mode failed, trying to open in block-mode\n"); | |
454 if ((err = snd_pcm_open(&alsa_handler, alsa_device, SND_PCM_STREAM_PLAYBACK, 0)) < 0) { | |
455 mp_msg(MSGT_AO,MSGL_ERR,"alsa-init: playback open error: %s\n", snd_strerror(err)); | |
456 return(0); | |
457 } else { | |
458 set_block_mode = 0; | |
459 str_block_mode = "block-mode"; | |
460 } | |
461 } else { | |
462 mp_msg(MSGT_AO,MSGL_ERR,"alsa-init: playback open error: %s\n", snd_strerror(err)); | |
463 return(0); | |
464 } | |
465 } | |
466 | |
467 if ((err = snd_pcm_nonblock(alsa_handler, set_block_mode)) < 0) { | |
468 mp_msg(MSGT_AO,MSGL_ERR,"alsa-init: error set block-mode %s\n", snd_strerror(err)); | |
469 } else { | |
470 mp_msg(MSGT_AO,MSGL_V,"alsa-init: pcm opend in %s\n", str_block_mode); | |
471 } | |
472 | |
473 snd_pcm_hw_params_alloca(&alsa_hwparams); | |
474 snd_pcm_sw_params_alloca(&alsa_swparams); | |
475 | |
476 // setting hw-parameters | |
477 if ((err = snd_pcm_hw_params_any(alsa_handler, alsa_hwparams)) < 0) | |
478 { | |
479 mp_msg(MSGT_AO,MSGL_ERR,"alsa-init: unable to get initial parameters: %s\n", | |
480 snd_strerror(err)); | |
481 return(0); | |
482 } | |
483 | |
484 if (ao_mmap) { | |
485 snd_pcm_access_mask_t *mask = alloca(snd_pcm_access_mask_sizeof()); | |
486 snd_pcm_access_mask_none(mask); | |
487 snd_pcm_access_mask_set(mask, SND_PCM_ACCESS_MMAP_INTERLEAVED); | |
488 snd_pcm_access_mask_set(mask, SND_PCM_ACCESS_MMAP_NONINTERLEAVED); | |
489 snd_pcm_access_mask_set(mask, SND_PCM_ACCESS_MMAP_COMPLEX); | |
490 err = snd_pcm_hw_params_set_access_mask(alsa_handler, alsa_hwparams, mask); | |
491 mp_msg(MSGT_AO,MSGL_INFO,"alsa-init: mmap set\n"); | |
492 } else { | |
493 err = snd_pcm_hw_params_set_access(alsa_handler, alsa_hwparams, | |
494 SND_PCM_ACCESS_RW_INTERLEAVED); | |
495 } | |
496 if (err < 0) { | |
497 mp_msg(MSGT_AO,MSGL_ERR,"alsa-init: unable to set access type: %s\n", | |
498 snd_strerror(err)); | |
499 return (0); | |
500 } | |
501 | |
502 /* workaround for nonsupported formats | |
503 sets default format to S16_LE if the given formats aren't supported */ | |
504 if ((err = snd_pcm_hw_params_test_format(alsa_handler, alsa_hwparams, | |
505 alsa_format)) < 0) | |
506 { | |
507 mp_msg(MSGT_AO,MSGL_INFO, | |
14264 | 508 "alsa-init: format %s are not supported by hardware, trying default\n", af_fmt2str_short(format)); |
12465 | 509 alsa_format = SND_PCM_FORMAT_S16_LE; |
14245 | 510 ao_data.format = AF_FORMAT_S16_LE; |
12465 | 511 } |
512 | |
513 if ((err = snd_pcm_hw_params_set_format(alsa_handler, alsa_hwparams, | |
514 alsa_format)) < 0) | |
515 { | |
516 mp_msg(MSGT_AO,MSGL_ERR,"alsa-init: unable to set format: %s\n", | |
517 snd_strerror(err)); | |
16308
41278ab73e9b
set the nearest number of channels, return(0) upon errors
henry
parents:
14849
diff
changeset
|
518 return(0); |
12465 | 519 } |
520 | |
16308
41278ab73e9b
set the nearest number of channels, return(0) upon errors
henry
parents:
14849
diff
changeset
|
521 if ((err = snd_pcm_hw_params_set_channels_near(alsa_handler, alsa_hwparams, |
41278ab73e9b
set the nearest number of channels, return(0) upon errors
henry
parents:
14849
diff
changeset
|
522 &ao_data.channels)) < 0) |
12465 | 523 { |
524 mp_msg(MSGT_AO,MSGL_ERR,"alsa-init: unable to set channels: %s\n", | |
525 snd_strerror(err)); | |
16308
41278ab73e9b
set the nearest number of channels, return(0) upon errors
henry
parents:
14849
diff
changeset
|
526 return(0); |
12465 | 527 } |
528 | |
529 if ((err = snd_pcm_hw_params_set_rate_near(alsa_handler, alsa_hwparams, | |
530 &ao_data.samplerate, &dir)) < 0) | |
531 { | |
532 mp_msg(MSGT_AO,MSGL_ERR,"alsa-init: unable to set samplerate-2: %s\n", | |
533 snd_strerror(err)); | |
534 return(0); | |
535 } | |
536 | |
16309 | 537 ao_data.bps = ao_data.channels * ao_data.samplerate; |
538 | |
539 //setting bw according to the input-format. resolution seems to be always s16_le or | |
540 //u16_le so 32bit is probably obsolet. | |
541 switch(alsa_format) | |
542 { | |
543 case SND_PCM_FORMAT_S8: | |
544 case SND_PCM_FORMAT_U8: | |
545 ao_data.bps *= 1; | |
546 break; | |
547 case SND_PCM_FORMAT_S16_LE: | |
548 case SND_PCM_FORMAT_U16_LE: | |
549 case SND_PCM_FORMAT_S16_BE: | |
550 case SND_PCM_FORMAT_U16_BE: | |
551 ao_data.bps *= 2; | |
552 break; | |
553 case SND_PCM_FORMAT_S32_LE: | |
554 case SND_PCM_FORMAT_S32_BE: | |
555 case SND_PCM_FORMAT_FLOAT_LE: | |
556 ao_data.bps *= 4; | |
557 break; | |
558 case -1: | |
559 mp_msg(MSGT_AO,MSGL_ERR,"alsa-init: invalid format (%s) requested - output disabled\n",af_fmt2str_short(format)); | |
560 return(0); | |
561 break; | |
562 default: | |
563 ao_data.bps *= 2; | |
564 mp_msg(MSGT_AO,MSGL_WARN,"alsa-init: couldn't convert to right format. setting bps to: %d", ao_data.bps); | |
565 } | |
566 | |
567 bytes_per_sample = ao_data.bps / ao_data.samplerate; | |
568 | |
12465 | 569 #ifdef BUFFERTIME |
570 { | |
571 int alsa_buffer_time = 500000; /* original 60 */ | |
572 int alsa_period_time; | |
573 alsa_period_time = alsa_buffer_time/4; | |
574 if ((err = snd_pcm_hw_params_set_buffer_time_near(alsa_handler, alsa_hwparams, | |
575 &alsa_buffer_time, &dir)) < 0) | |
576 { | |
577 mp_msg(MSGT_AO,MSGL_ERR,"alsa-init: unable to set buffer time near: %s\n", | |
578 snd_strerror(err)); | |
579 return(0); | |
580 } else | |
581 alsa_buffer_time = err; | |
582 | |
583 if ((err = snd_pcm_hw_params_set_period_time_near(alsa_handler, alsa_hwparams, | |
584 &alsa_period_time, &dir)) < 0) | |
585 /* original: alsa_buffer_time/ao_data.bps */ | |
586 { | |
587 mp_msg(MSGT_AO,MSGL_ERR,"alsa-init: unable to set period time: %s\n", | |
588 snd_strerror(err)); | |
589 } | |
590 mp_msg(MSGT_AO,MSGL_INFO,"alsa-init: buffer_time: %d, period_time :%d\n", | |
591 alsa_buffer_time, err); | |
592 } | |
593 #endif//end SET_BUFFERTIME | |
594 | |
595 #ifdef SET_CHUNKSIZE | |
596 { | |
597 //set chunksize | |
598 dir=0; | |
599 if ((err = snd_pcm_hw_params_set_period_size_near(alsa_handler, alsa_hwparams, | |
600 &chunk_size, &dir)) < 0) | |
601 { | |
602 mp_msg(MSGT_AO,MSGL_ERR,"alsa-init: unable to set periodsize(%d): %s\n", | |
603 chunk_size, snd_strerror(err)); | |
604 } | |
605 else { | |
606 mp_msg(MSGT_AO,MSGL_V,"alsa-init: chunksize set to %i\n", chunk_size); | |
607 } | |
608 if ((err = snd_pcm_hw_params_set_periods_near(alsa_handler, alsa_hwparams, | |
609 &alsa_fragcount, &dir)) < 0) { | |
610 mp_msg(MSGT_AO,MSGL_ERR,"alsa-init: unable to set periods: %s\n", | |
611 snd_strerror(err)); | |
612 } | |
613 else { | |
614 mp_msg(MSGT_AO,MSGL_V,"alsa-init: fragcount=%i\n", alsa_fragcount); | |
615 } | |
616 } | |
617 #endif//end SET_CHUNKSIZE | |
618 | |
619 /* finally install hardware parameters */ | |
620 if ((err = snd_pcm_hw_params(alsa_handler, alsa_hwparams)) < 0) | |
621 { | |
622 mp_msg(MSGT_AO,MSGL_ERR,"alsa-init: unable to set hw-parameters: %s\n", | |
623 snd_strerror(err)); | |
624 } | |
625 // end setting hw-params | |
626 | |
627 | |
628 // gets buffersize for control | |
629 if ((err = snd_pcm_hw_params_get_buffer_size(alsa_hwparams, &bufsize)) < 0) | |
630 { | |
631 mp_msg(MSGT_AO,MSGL_ERR,"alsa-init: unable to get buffersize: %s\n", snd_strerror(err)); | |
632 } | |
633 else { | |
634 ao_data.buffersize = bufsize * bytes_per_sample; | |
635 mp_msg(MSGT_AO,MSGL_V,"alsa-init: got buffersize=%i\n", ao_data.buffersize); | |
636 } | |
637 | |
638 // setting sw-params (only avail-min) if noblocking mode was choosed | |
639 if (ao_noblock) | |
640 { | |
641 | |
642 if ((err = snd_pcm_sw_params_current(alsa_handler, alsa_swparams)) < 0) | |
643 { | |
644 mp_msg(MSGT_AO,MSGL_ERR,"alsa-init: unable to get parameters: %s\n", | |
645 snd_strerror(err)); | |
646 | |
647 } | |
648 | |
649 //set min available frames to consider pcm ready (4) | |
650 //increased for nonblock-mode should be set dynamically later | |
651 if ((err = snd_pcm_sw_params_set_avail_min(alsa_handler, alsa_swparams, 4)) < 0) | |
652 { | |
653 mp_msg(MSGT_AO,MSGL_ERR,"alsa-init: unable to set avail_min %s\n", | |
654 snd_strerror(err)); | |
655 } | |
656 | |
657 if ((err = snd_pcm_sw_params(alsa_handler, alsa_swparams)) < 0) | |
658 { | |
659 mp_msg(MSGT_AO,MSGL_ERR,"alsa-init: unable to install sw-params\n"); | |
660 } | |
661 | |
662 bits_per_sample = snd_pcm_format_physical_width(alsa_format); | |
16309 | 663 bits_per_frame = bits_per_sample * ao_data.channels; |
12465 | 664 chunk_bytes = chunk_size * bits_per_frame / 8; |
665 | |
666 mp_msg(MSGT_AO,MSGL_V,"alsa-init: bits per sample (bps)=%i, bits per frame (bpf)=%i, chunk_bytes=%i\n",bits_per_sample,bits_per_frame,chunk_bytes);} | |
667 //end swparams | |
668 | |
669 if ((err = snd_pcm_prepare(alsa_handler)) < 0) | |
670 { | |
671 mp_msg(MSGT_AO,MSGL_ERR,"alsa-init: pcm prepare error: %s\n", snd_strerror(err)); | |
672 } | |
673 | |
674 mp_msg(MSGT_AO,MSGL_INFO,"alsa: %d Hz/%d channels/%d bpf/%d bytes buffer/%s\n", | |
675 ao_data.samplerate, ao_data.channels, bytes_per_sample, ao_data.buffersize, | |
676 snd_pcm_format_description(alsa_format)); | |
677 | |
678 } // end switch alsa_handler (spdif) | |
679 alsa_can_pause = snd_pcm_hw_params_can_pause(alsa_hwparams); | |
680 return(1); | |
681 } // end init | |
682 | |
683 | |
684 /* close audio device */ | |
685 static void uninit(int immed) | |
686 { | |
687 | |
688 if (alsa_handler) { | |
689 int err; | |
690 | |
14849
d313f591d1a4
aos should respect the immed uninit flag (quit immediatly vs waiting till file
reimar
parents:
14612
diff
changeset
|
691 if (!immed) |
d313f591d1a4
aos should respect the immed uninit flag (quit immediatly vs waiting till file
reimar
parents:
14612
diff
changeset
|
692 snd_pcm_drain(alsa_handler); |
d313f591d1a4
aos should respect the immed uninit flag (quit immediatly vs waiting till file
reimar
parents:
14612
diff
changeset
|
693 |
12465 | 694 if (!ao_noblock) { |
695 if ((err = snd_pcm_drop(alsa_handler)) < 0) | |
696 { | |
697 mp_msg(MSGT_AO,MSGL_ERR,"alsa-uninit: pcm drop error: %s\n", snd_strerror(err)); | |
698 return; | |
699 } | |
700 } | |
701 | |
702 if ((err = snd_pcm_close(alsa_handler)) < 0) | |
703 { | |
704 mp_msg(MSGT_AO,MSGL_ERR,"alsa-uninit: pcm close error: %s\n", snd_strerror(err)); | |
705 return; | |
706 } | |
707 else { | |
708 alsa_handler = NULL; | |
709 mp_msg(MSGT_AO,MSGL_INFO,"alsa-uninit: pcm closed\n"); | |
710 } | |
711 } | |
712 else { | |
713 mp_msg(MSGT_AO,MSGL_ERR,"alsa-uninit: no handler defined!\n"); | |
714 } | |
715 } | |
716 | |
717 static void audio_pause() | |
718 { | |
719 int err; | |
720 | |
721 if (alsa_can_pause) { | |
722 if ((err = snd_pcm_pause(alsa_handler, 1)) < 0) | |
723 { | |
724 mp_msg(MSGT_AO,MSGL_ERR,"alsa-pause: pcm pause error: %s\n", snd_strerror(err)); | |
725 return; | |
726 } | |
727 mp_msg(MSGT_AO,MSGL_V,"alsa-pause: pause supported by hardware\n"); | |
728 } else { | |
729 if ((err = snd_pcm_drop(alsa_handler)) < 0) | |
730 { | |
731 mp_msg(MSGT_AO,MSGL_ERR,"alsa-pause: pcm drop error: %s\n", snd_strerror(err)); | |
732 return; | |
733 } | |
734 } | |
735 } | |
736 | |
737 static void audio_resume() | |
738 { | |
739 int err; | |
740 | |
741 if (alsa_can_pause) { | |
742 if ((err = snd_pcm_pause(alsa_handler, 0)) < 0) | |
743 { | |
744 mp_msg(MSGT_AO,MSGL_ERR,"alsa-resume: pcm resume error: %s\n", snd_strerror(err)); | |
745 return; | |
746 } | |
747 mp_msg(MSGT_AO,MSGL_V,"alsa-resume: resume supported by hardware\n"); | |
748 } else { | |
749 if ((err = snd_pcm_prepare(alsa_handler)) < 0) | |
750 { | |
751 mp_msg(MSGT_AO,MSGL_ERR,"alsa-resume: pcm prepare error: %s\n", snd_strerror(err)); | |
752 return; | |
753 } | |
754 } | |
755 } | |
756 | |
757 /* stop playing and empty buffers (for seeking/pause) */ | |
758 static void reset() | |
759 { | |
760 int err; | |
761 | |
762 if ((err = snd_pcm_drop(alsa_handler)) < 0) | |
763 { | |
764 mp_msg(MSGT_AO,MSGL_ERR,"alsa-reset: pcm drop error: %s\n", snd_strerror(err)); | |
765 return; | |
766 } | |
767 if ((err = snd_pcm_prepare(alsa_handler)) < 0) | |
768 { | |
769 mp_msg(MSGT_AO,MSGL_ERR,"alsa-reset: pcm prepare error: %s\n", snd_strerror(err)); | |
770 return; | |
771 } | |
772 return; | |
773 } | |
774 | |
775 #ifdef USE_POLL | |
776 static int wait_for_poll(snd_pcm_t *handle, struct pollfd *ufds, unsigned int count) | |
777 { | |
778 unsigned short revents; | |
779 | |
780 while (1) { | |
781 poll(ufds, count, -1); | |
782 snd_pcm_poll_descriptors_revents(handle, ufds, count, &revents); | |
783 if (revents & POLLERR) | |
784 return -EIO; | |
785 if (revents & POLLOUT) | |
786 return 0; | |
787 } | |
788 } | |
789 #endif | |
790 | |
791 #ifndef timersub | |
792 #define timersub(a, b, result) \ | |
793 do { \ | |
794 (result)->tv_sec = (a)->tv_sec - (b)->tv_sec; \ | |
795 (result)->tv_usec = (a)->tv_usec - (b)->tv_usec; \ | |
796 if ((result)->tv_usec < 0) { \ | |
797 --(result)->tv_sec; \ | |
798 (result)->tv_usec += 1000000; \ | |
799 } \ | |
800 } while (0) | |
801 #endif | |
802 | |
803 /* I/O error handler */ | |
804 static int xrun(u_char *str_mode) | |
805 { | |
806 int err; | |
807 snd_pcm_status_t *status; | |
808 | |
809 snd_pcm_status_alloca(&status); | |
810 | |
811 if ((err = snd_pcm_status(alsa_handler, status))<0) { | |
812 mp_msg(MSGT_AO,MSGL_ERR,"status error: %s", snd_strerror(err)); | |
813 return(0); | |
814 } | |
815 | |
816 if (snd_pcm_status_get_state(status) == SND_PCM_STATE_XRUN) { | |
817 struct timeval now, diff, tstamp; | |
818 gettimeofday(&now, 0); | |
819 snd_pcm_status_get_trigger_tstamp(status, &tstamp); | |
820 timersub(&now, &tstamp, &diff); | |
821 mp_msg(MSGT_AO,MSGL_INFO,"alsa-%s: xrun of at least %.3f msecs. resetting stream\n", | |
822 str_mode, | |
823 diff.tv_sec * 1000 + diff.tv_usec / 1000.0); | |
824 } | |
825 | |
826 if ((err = snd_pcm_prepare(alsa_handler))<0) { | |
827 mp_msg(MSGT_AO,MSGL_ERR,"xrun: prepare error: %s", snd_strerror(err)); | |
828 return(0); | |
829 } | |
830 | |
831 return(1); /* ok, data should be accepted again */ | |
832 } | |
833 | |
834 static int play_normal(void* data, int len); | |
835 static int play_mmap(void* data, int len); | |
836 | |
837 static int play(void* data, int len, int flags) | |
838 { | |
839 int result; | |
840 if (ao_mmap) | |
841 result = play_mmap(data, len); | |
842 else | |
843 result = play_normal(data, len); | |
844 | |
845 return result; | |
846 } | |
847 | |
848 /* | |
849 plays 'len' bytes of 'data' | |
850 returns: number of bytes played | |
851 modified last at 29.06.02 by jp | |
852 thanxs for marius <marius@rospot.com> for giving us the light ;) | |
853 */ | |
854 | |
855 static int play_normal(void* data, int len) | |
856 { | |
857 | |
858 //bytes_per_sample is always 4 for 2 chn S16_LE | |
859 int num_frames = len / bytes_per_sample; | |
860 char *output_samples = (char *)data; | |
861 snd_pcm_sframes_t res = 0; | |
862 | |
863 //mp_msg(MSGT_AO,MSGL_ERR,"alsa-play: frames=%i, len=%i\n",num_frames,len); | |
864 | |
865 if (!alsa_handler) { | |
866 mp_msg(MSGT_AO,MSGL_ERR,"alsa-play: device configuration error"); | |
867 return 0; | |
868 } | |
869 | |
870 while (num_frames > 0) { | |
871 | |
872 res = snd_pcm_writei(alsa_handler, (void *)output_samples, num_frames); | |
873 | |
874 if (res == -EAGAIN) { | |
875 snd_pcm_wait(alsa_handler, 1000); | |
876 } | |
877 else if (res == -EPIPE) { /* underrun */ | |
878 if (xrun("play") <= 0) { | |
879 mp_msg(MSGT_AO,MSGL_ERR,"alsa-play: xrun reset error"); | |
880 return(0); | |
881 } | |
882 } | |
883 else if (res == -ESTRPIPE) { /* suspend */ | |
884 mp_msg(MSGT_AO,MSGL_INFO,"alsa-play: pcm in suspend mode. trying to resume\n"); | |
885 while ((res = snd_pcm_resume(alsa_handler)) == -EAGAIN) | |
886 sleep(1); | |
887 } | |
888 else if (res < 0) { | |
889 mp_msg(MSGT_AO,MSGL_INFO,"alsa-play: unknown status, trying to reset soundcard\n"); | |
890 if ((res = snd_pcm_prepare(alsa_handler)) < 0) { | |
891 mp_msg(MSGT_AO,MSGL_ERR,"alsa-play: snd prepare error"); | |
892 return(0); | |
893 break; | |
894 } | |
895 } | |
896 | |
897 if (res > 0) { | |
898 | |
899 /* output_samples += ao_data.channels * res; */ | |
900 output_samples += res * bytes_per_sample; | |
901 | |
902 num_frames -= res; | |
903 } | |
904 | |
905 } //end while | |
906 | |
907 if (res < 0) { | |
908 mp_msg(MSGT_AO,MSGL_ERR,"alsa-play: write error %s", snd_strerror(res)); | |
909 return 0; | |
910 } | |
12805
0b154063a3ca
fixes provided by reimar drfinger. mixer, subdevice parsing, alsa#help,
joyping
parents:
12747
diff
changeset
|
911 return len - len % bytes_per_sample; |
12465 | 912 } |
913 | |
914 /* mmap-mode mainly based on descriptions by Joshua Haberman <joshua@haberman.com> | |
915 * 'An overview of the ALSA API' http://people.debian.org/~joshua/x66.html | |
916 * and some help by Paul Davis <pbd@op.net> */ | |
917 | |
918 static int play_mmap(void* data, int len) | |
919 { | |
920 snd_pcm_sframes_t commitres, frames_available; | |
921 snd_pcm_uframes_t frames_transmit, size, offset; | |
922 const snd_pcm_channel_area_t *area; | |
923 void *outbuffer; | |
12805
0b154063a3ca
fixes provided by reimar drfinger. mixer, subdevice parsing, alsa#help,
joyping
parents:
12747
diff
changeset
|
924 int result; |
12465 | 925 |
926 #ifdef USE_POLL //seems not really be needed | |
927 struct pollfd *ufds; | |
928 int count; | |
929 | |
930 count = snd_pcm_poll_descriptors_count (alsa_handler); | |
931 ufds = malloc(sizeof(struct pollfd) * count); | |
932 snd_pcm_poll_descriptors(alsa_handler, ufds, count); | |
933 | |
934 //first wait_for_poll | |
935 if (err = (wait_for_poll(alsa_handler, ufds, count) < 0)) { | |
936 if (snd_pcm_state(alsa_handler) == SND_PCM_STATE_XRUN || | |
937 snd_pcm_state(alsa_handler) == SND_PCM_STATE_SUSPENDED) { | |
938 xrun("play"); | |
939 } | |
940 } | |
941 #endif | |
942 | |
943 outbuffer = alloca(ao_data.buffersize); | |
944 | |
945 //don't trust get_space() ;) | |
946 frames_available = snd_pcm_avail_update(alsa_handler) * bytes_per_sample; | |
947 if (frames_available < 0) | |
948 xrun("play"); | |
949 | |
950 if (frames_available < 4) { | |
951 if (first) { | |
952 first = 0; | |
953 snd_pcm_start(alsa_handler); | |
954 } | |
955 else { //FIXME should break and return 0? | |
956 snd_pcm_wait(alsa_handler, -1); | |
957 first = 1; | |
958 } | |
959 } | |
960 | |
961 /* len is simply the available bufferspace got by get_space() | |
962 * but real avail_buffer in frames is ab/bytes_per_sample */ | |
963 size = len / bytes_per_sample; | |
964 | |
965 //mp_msg(MSGT_AO,MSGL_V,"len: %i size %i, f_avail %i, bps %i ...\n", len, size, frames_available, bytes_per_sample); | |
966 | |
967 frames_transmit = size; | |
968 | |
969 /* prepare areas and set sw-pointers | |
970 * frames_transmit returns the real available buffer-size | |
971 * sometimes != frames_available cause of ringbuffer 'emulation' */ | |
972 snd_pcm_mmap_begin(alsa_handler, &area, &offset, &frames_transmit); | |
973 | |
974 /* this is specific to interleaved streams (or non-interleaved | |
975 * streams with only one channel) */ | |
976 outbuffer = ((char *) area->addr + (area->first + area->step * offset) / 8); //8 | |
977 | |
978 //write data | |
979 memcpy(outbuffer, data, (frames_transmit * bytes_per_sample)); | |
980 | |
981 commitres = snd_pcm_mmap_commit(alsa_handler, offset, frames_transmit); | |
982 | |
983 if (commitres < 0 || commitres != frames_transmit) { | |
984 if (snd_pcm_state(alsa_handler) == SND_PCM_STATE_XRUN || | |
985 snd_pcm_state(alsa_handler) == SND_PCM_STATE_SUSPENDED) { | |
986 xrun("play"); | |
987 } | |
988 } | |
989 | |
990 //mp_msg(MSGT_AO,MSGL_V,"mmap ft: %i, cres: %i\n", frames_transmit, commitres); | |
991 | |
992 /* err = snd_pcm_area_copy(&area, offset, &data, offset, len, alsa_format); */ | |
993 /* if (err < 0) { */ | |
994 /* mp_msg(MSGT_AO,MSGL_ERR,"area-copy-error\n"); */ | |
995 /* return 0; */ | |
996 /* } */ | |
997 | |
998 | |
999 //calculate written frames! | |
1000 result = commitres * bytes_per_sample; | |
1001 | |
1002 | |
1003 /* if (verbose) { */ | |
1004 /* if (len == result) */ | |
1005 /* mp_msg(MSGT_AO,MSGL_V,"result: %i, frames written: %i ...\n", result, frames_transmit); */ | |
1006 /* else */ | |
1007 /* mp_msg(MSGT_AO,MSGL_V,"result: %i, frames written: %i, result != len ...\n", result, frames_transmit); */ | |
1008 /* } */ | |
1009 | |
1010 //mplayer doesn't like -result | |
1011 if (result < 0) | |
1012 result = 0; | |
1013 | |
1014 #ifdef USE_POLL | |
1015 free(ufds); | |
1016 #endif | |
1017 | |
1018 return result; | |
1019 } | |
1020 | |
1021 /* how many byes are free in the buffer */ | |
1022 static int get_space() | |
1023 { | |
1024 snd_pcm_status_t *status; | |
1025 int ret; | |
1026 char *str_status; | |
1027 | |
1028 //snd_pcm_sframes_t avail_frames = 0; | |
1029 | |
12747 | 1030 snd_pcm_status_alloca(&status); |
12465 | 1031 |
1032 if ((ret = snd_pcm_status(alsa_handler, status)) < 0) | |
1033 { | |
1034 mp_msg(MSGT_AO,MSGL_ERR,"alsa-space: cannot get pcm status: %s\n", snd_strerror(ret)); | |
1035 return(0); | |
1036 } | |
1037 | |
1038 switch(snd_pcm_status_get_state(status)) | |
1039 { | |
1040 case SND_PCM_STATE_OPEN: | |
1041 str_status = "open"; | |
12805
0b154063a3ca
fixes provided by reimar drfinger. mixer, subdevice parsing, alsa#help,
joyping
parents:
12747
diff
changeset
|
1042 ret = snd_pcm_status_get_avail(status) * bytes_per_sample; |
0b154063a3ca
fixes provided by reimar drfinger. mixer, subdevice parsing, alsa#help,
joyping
parents:
12747
diff
changeset
|
1043 break; |
12465 | 1044 case SND_PCM_STATE_PREPARED: |
1045 str_status = "prepared"; | |
1046 first = 1; | |
1047 ret = snd_pcm_status_get_avail(status) * bytes_per_sample; | |
1048 if (ret == 0) //ugly workaround for hang in mmap-mode | |
1049 ret = 10; | |
1050 break; | |
1051 case SND_PCM_STATE_RUNNING: | |
1052 ret = snd_pcm_status_get_avail(status) * bytes_per_sample; | |
1053 //avail_frames = snd_pcm_avail_update(alsa_handler) * bytes_per_sample; | |
1054 if (str_status != "open" && str_status != "prepared") | |
1055 str_status = "running"; | |
1056 break; | |
1057 case SND_PCM_STATE_PAUSED: | |
1058 mp_msg(MSGT_AO,MSGL_V,"alsa-space: paused"); | |
1059 str_status = "paused"; | |
1060 ret = 0; | |
1061 break; | |
1062 case SND_PCM_STATE_XRUN: | |
1063 xrun("space"); | |
1064 str_status = "xrun"; | |
1065 first = 1; | |
1066 ret = 0; | |
1067 break; | |
1068 default: | |
1069 str_status = "undefined"; | |
1070 ret = snd_pcm_status_get_avail(status) * bytes_per_sample; | |
1071 if (ret <= 0) { | |
1072 xrun("space"); | |
1073 } | |
1074 } | |
1075 | |
12811
d5f8efddac6c
volume calc fixes for mixer, by reimar dffinger, 10l reverse by me
joyping
parents:
12805
diff
changeset
|
1076 if (snd_pcm_status_get_state(status) != SND_PCM_STATE_RUNNING) |
12819
e28849cfac27
removed status in debug_msg as it is nonsens anyway.
joyping
parents:
12811
diff
changeset
|
1077 mp_msg(MSGT_AO,MSGL_V,"alsa-space: free space = %i, %s --\n", ret, str_status); |
12465 | 1078 |
1079 if (ret < 0) { | |
1080 mp_msg(MSGT_AO,MSGL_ERR,"negative value!!\n"); | |
1081 ret = 0; | |
1082 } | |
1083 | |
1084 // workaround for too small value returned | |
1085 if (ret < MIN_CHUNK_SIZE) | |
1086 ret = 0; | |
1087 | |
1088 return(ret); | |
1089 } | |
1090 | |
1091 /* delay in seconds between first and last sample in buffer */ | |
1092 static float get_delay() | |
1093 { | |
1094 | |
1095 if (alsa_handler) { | |
1096 | |
1097 snd_pcm_status_t *status; | |
1098 float ret; | |
1099 | |
12747 | 1100 snd_pcm_status_alloca(&status); |
12465 | 1101 |
1102 if ((ret = snd_pcm_status(alsa_handler, status)) < 0) | |
1103 { | |
1104 mp_msg(MSGT_AO,MSGL_ERR,"alsa-delay: cannot get pcm status: %s\n", snd_strerror(ret)); | |
1105 } | |
1106 | |
1107 switch(snd_pcm_status_get_state(status)) | |
1108 { | |
1109 case SND_PCM_STATE_OPEN: | |
1110 case SND_PCM_STATE_PREPARED: | |
1111 case SND_PCM_STATE_RUNNING: | |
1112 ret = (float)snd_pcm_status_get_delay(status)/(float)ao_data.samplerate; | |
1113 break; | |
1114 default: | |
1115 ret = 0; | |
1116 } | |
1117 | |
1118 | |
1119 if (ret < 0) | |
1120 ret = 0; | |
1121 return(ret); | |
1122 | |
1123 } else { | |
1124 return(0); | |
1125 } | |
1126 } |