Mercurial > mplayer.hg
annotate libao2/ao_alsa1x.c @ 1146:a84610bb5476
hacked aocontrol_set_device working, and cleaned up a bit
author | al3x |
---|---|
date | Sun, 17 Jun 2001 17:44:56 +0000 |
parents | 705fa4ac4fed |
children | c50cd5db2359 |
rev | line source |
---|---|
1050 | 1 /* |
2 ao_alsa9 - ALSA-0.9.x output plugin for MPlayer | |
3 | |
4 (C) Alex Beregszaszi <alex@naxine.org> | |
5 */ | |
6 | |
7 #include <errno.h> | |
8 #include <sys/asoundlib.h> | |
9 | |
10 #include "../config.h" | |
11 | |
12 #include "audio_out.h" | |
13 #include "audio_out_internal.h" | |
1058 | 14 #include "afmt.h" |
1050 | 15 |
16 extern int verbose; | |
17 | |
18 static ao_info_t info = | |
19 { | |
20 "ALSA-0.9.x audio output", | |
21 "alsa9", | |
22 "Alex Beregszaszi <alex@naxine.org>", | |
23 "under developement" | |
24 }; | |
25 | |
26 LIBAO_EXTERN(alsa9) | |
27 | |
28 /* global variables: | |
29 ao_samplerate | |
30 ao_channels | |
31 ao_format | |
32 ao_bps | |
33 ao_outburst | |
34 ao_buffersize | |
35 */ | |
36 | |
37 static snd_pcm_t *alsa_handler; | |
38 static snd_pcm_format_t alsa_format; | |
39 static snd_pcm_hw_params_t *alsa_hwparams; | |
40 static snd_pcm_sw_params_t *alsa_swparams; | |
41 static char *alsa_device; | |
42 #define ALSA_DEVICE_SIZE 48 | |
43 | |
1128 | 44 static int alsa_fragsize = 8192; /* 4096 */ |
45 static int alsa_fragcount = 8; | |
46 | |
1050 | 47 /* to set/get/query special features/parameters */ |
48 static int control(int cmd, int arg) | |
49 { | |
50 switch(cmd) | |
51 { | |
52 case AOCONTROL_GET_DEVICE: | |
1146
a84610bb5476
hacked aocontrol_set_device working, and cleaned up a bit
al3x
parents:
1129
diff
changeset
|
53 return((char *)alsa_device); /* egy kicsit brutalis, dehat :) */ |
1050 | 54 case AOCONTROL_SET_DEVICE: |
1146
a84610bb5476
hacked aocontrol_set_device working, and cleaned up a bit
al3x
parents:
1129
diff
changeset
|
55 { |
a84610bb5476
hacked aocontrol_set_device working, and cleaned up a bit
al3x
parents:
1129
diff
changeset
|
56 int ret; |
a84610bb5476
hacked aocontrol_set_device working, and cleaned up a bit
al3x
parents:
1129
diff
changeset
|
57 |
1050 | 58 strncpy(alsa_device, (char *)arg, ALSA_DEVICE_SIZE); |
1146
a84610bb5476
hacked aocontrol_set_device working, and cleaned up a bit
al3x
parents:
1129
diff
changeset
|
59 uninit(); |
a84610bb5476
hacked aocontrol_set_device working, and cleaned up a bit
al3x
parents:
1129
diff
changeset
|
60 ret = init(ao_samplerate, ao_channels, ao_format, 0); |
a84610bb5476
hacked aocontrol_set_device working, and cleaned up a bit
al3x
parents:
1129
diff
changeset
|
61 if (ret == 0) |
a84610bb5476
hacked aocontrol_set_device working, and cleaned up a bit
al3x
parents:
1129
diff
changeset
|
62 return(CONTROL_ERROR); |
a84610bb5476
hacked aocontrol_set_device working, and cleaned up a bit
al3x
parents:
1129
diff
changeset
|
63 else |
a84610bb5476
hacked aocontrol_set_device working, and cleaned up a bit
al3x
parents:
1129
diff
changeset
|
64 return(CONTROL_OK); |
a84610bb5476
hacked aocontrol_set_device working, and cleaned up a bit
al3x
parents:
1129
diff
changeset
|
65 } |
1050 | 66 } |
67 return(CONTROL_UNKNOWN); | |
68 } | |
69 | |
1128 | 70 #undef start |
71 #define buffersize | |
72 #undef buffertime | |
73 #define set_period | |
74 #undef sw_params | |
75 #undef set_start_mode | |
76 | |
1050 | 77 /* |
78 open & setup audio device | |
79 return: 1=success 0=fail | |
80 */ | |
81 static int init(int rate_hz, int channels, int format, int flags) | |
82 { | |
83 int err; | |
84 int cards = -1; | |
85 snd_pcm_info_t *alsa_info; | |
86 | |
87 printf("alsa-init: requested format: %d Hz, %d channels, %s\n", rate_hz, | |
88 channels, audio_out_format_name(format)); | |
89 | |
90 alsa_handler = NULL; | |
91 | |
92 if (verbose) | |
93 printf("alsa-init: compiled for ALSA-%s (%d)\n", SND_LIB_VERSION_STR, | |
94 SND_LIB_VERSION); | |
95 | |
96 if ((err = snd_card_next(&cards)) < 0 || cards < 0) | |
97 { | |
98 printf("alsa-init: no soundcards found: %s\n", snd_strerror(err)); | |
99 return(0); | |
100 } | |
101 | |
1128 | 102 ao_samplerate = rate_hz; |
103 ao_bps = channels; /* really this is bytes per frame so bad varname */ | |
1050 | 104 ao_format = format; |
1128 | 105 ao_channels = channels; |
1050 | 106 ao_outburst = OUTBURST; |
107 ao_buffersize = 16384; | |
108 | |
109 switch (format) | |
110 { | |
111 case AFMT_S8: | |
112 alsa_format = SND_PCM_FORMAT_S8; | |
113 break; | |
114 case AFMT_U8: | |
115 alsa_format = SND_PCM_FORMAT_U8; | |
116 break; | |
117 case AFMT_U16_LE: | |
118 alsa_format = SND_PCM_FORMAT_U16_LE; | |
119 break; | |
120 case AFMT_U16_BE: | |
121 alsa_format = SND_PCM_FORMAT_U16_BE; | |
122 break; | |
123 case AFMT_S16_LE: | |
124 alsa_format = SND_PCM_FORMAT_S16_LE; | |
125 break; | |
126 case AFMT_S16_BE: | |
127 alsa_format = SND_PCM_FORMAT_S16_BE; | |
128 break; | |
129 default: | |
130 alsa_format = SND_PCM_FORMAT_MPEG; | |
131 break; | |
132 } | |
133 | |
134 switch(alsa_format) | |
135 { | |
136 case SND_PCM_FORMAT_S16_LE: | |
137 case SND_PCM_FORMAT_U16_LE: | |
138 ao_bps *= 2; | |
139 break; | |
140 case -1: | |
141 printf("alsa-init: invalid format (%s) requested - output disabled\n", | |
142 audio_out_format_name(format)); | |
143 return(0); | |
1115
a16b569f2702
-Wall style cleanups, TEST IT, it can be working by others
al3x
parents:
1058
diff
changeset
|
144 default: |
a16b569f2702
-Wall style cleanups, TEST IT, it can be working by others
al3x
parents:
1058
diff
changeset
|
145 break; |
1050 | 146 } |
1128 | 147 |
1050 | 148 if ((err = snd_pcm_info_malloc(&alsa_info)) < 0) |
149 { | |
150 printf("alsa-init: memory allocation error: %s\n", snd_strerror(err)); | |
151 return(0); | |
152 } | |
153 | |
1146
a84610bb5476
hacked aocontrol_set_device working, and cleaned up a bit
al3x
parents:
1129
diff
changeset
|
154 if (alsa_device == NULL) |
1050 | 155 { |
1146
a84610bb5476
hacked aocontrol_set_device working, and cleaned up a bit
al3x
parents:
1129
diff
changeset
|
156 if ((alsa_device = malloc(ALSA_DEVICE_SIZE)) == NULL) |
a84610bb5476
hacked aocontrol_set_device working, and cleaned up a bit
al3x
parents:
1129
diff
changeset
|
157 { |
a84610bb5476
hacked aocontrol_set_device working, and cleaned up a bit
al3x
parents:
1129
diff
changeset
|
158 printf("alsa-init: memory allocation error: %s\n", strerror(errno)); |
a84610bb5476
hacked aocontrol_set_device working, and cleaned up a bit
al3x
parents:
1129
diff
changeset
|
159 return(0); |
a84610bb5476
hacked aocontrol_set_device working, and cleaned up a bit
al3x
parents:
1129
diff
changeset
|
160 } |
1050 | 161 |
1146
a84610bb5476
hacked aocontrol_set_device working, and cleaned up a bit
al3x
parents:
1129
diff
changeset
|
162 snprintf(alsa_device, ALSA_DEVICE_SIZE, "hw:%d,%d", |
a84610bb5476
hacked aocontrol_set_device working, and cleaned up a bit
al3x
parents:
1129
diff
changeset
|
163 snd_pcm_info_get_device(alsa_info), |
a84610bb5476
hacked aocontrol_set_device working, and cleaned up a bit
al3x
parents:
1129
diff
changeset
|
164 snd_pcm_info_get_subdevice(alsa_info)); |
1050 | 165 |
1146
a84610bb5476
hacked aocontrol_set_device working, and cleaned up a bit
al3x
parents:
1129
diff
changeset
|
166 snd_pcm_info_free(alsa_info); |
a84610bb5476
hacked aocontrol_set_device working, and cleaned up a bit
al3x
parents:
1129
diff
changeset
|
167 } |
1050 | 168 |
169 printf("alsa-init: %d soundcard%s found, using: %s\n", cards+1, | |
170 (cards >= 0) ? "" : "s", alsa_device); | |
171 | |
172 if ((err = snd_pcm_open(&alsa_handler, alsa_device, SND_PCM_STREAM_PLAYBACK, | |
173 0)) < 0) | |
174 { | |
175 printf("alsa-init: playback open error: %s\n", snd_strerror(err)); | |
176 return(0); | |
177 } | |
178 | |
179 snd_pcm_hw_params_malloc(&alsa_hwparams); | |
180 snd_pcm_sw_params_malloc(&alsa_swparams); | |
181 | |
182 if ((err = snd_pcm_hw_params_any(alsa_handler, alsa_hwparams)) < 0) | |
183 { | |
184 printf("alsa-init: unable to get initial parameters: %s\n", | |
185 snd_strerror(err)); | |
186 return(0); | |
187 } | |
188 | |
189 if ((err = snd_pcm_hw_params_set_access(alsa_handler, alsa_hwparams, | |
190 SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) | |
191 { | |
192 printf("alsa-init: unable to set access type: %s\n", | |
193 snd_strerror(err)); | |
194 return(0); | |
195 } | |
196 | |
197 if ((err = snd_pcm_hw_params_set_format(alsa_handler, alsa_hwparams, | |
198 alsa_format)) < 0) | |
199 { | |
200 printf("alsa-init: unable to set format: %s\n", | |
201 snd_strerror(err)); | |
202 return(0); | |
203 } | |
204 | |
205 if ((err = snd_pcm_hw_params_set_channels(alsa_handler, alsa_hwparams, | |
206 ao_channels)) < 0) | |
207 { | |
208 printf("alsa-init: unable to set channels: %s\n", | |
209 snd_strerror(err)); | |
210 return(0); | |
211 } | |
212 | |
1129 | 213 if ((err = snd_pcm_hw_params_set_rate(alsa_handler, alsa_hwparams, |
1050 | 214 ao_samplerate, 0)) < 0) |
215 { | |
1128 | 216 printf("alsa-init: unable to set samplerate: %s\n", |
1050 | 217 snd_strerror(err)); |
218 return(0); | |
219 } | |
220 | |
1128 | 221 #ifdef set_period |
1115
a16b569f2702
-Wall style cleanups, TEST IT, it can be working by others
al3x
parents:
1058
diff
changeset
|
222 { |
1128 | 223 if ((err = snd_pcm_hw_params_set_period_size(alsa_handler, alsa_hwparams, alsa_fragsize / 4, 0)) < 0) |
224 { | |
225 printf("alsa-init: unable to set periodsize: %s\n", | |
226 snd_strerror(err)); | |
227 return(0); | |
228 } | |
229 if ((err = snd_pcm_hw_params_set_periods(alsa_handler, alsa_hwparams, alsa_fragcount, 0)) < 0) | |
230 { | |
231 printf("alsa-init: unable to set periods: %s\n", | |
232 snd_strerror(err)); | |
233 return(0); | |
234 } | |
1115
a16b569f2702
-Wall style cleanups, TEST IT, it can be working by others
al3x
parents:
1058
diff
changeset
|
235 } |
1128 | 236 #endif |
1050 | 237 #ifdef buffersize |
238 if ((err = snd_pcm_hw_params_get_buffer_size(alsa_hwparams)) < 0) | |
239 { | |
240 printf("alsa-init: unable to get buffer size: %s\n", | |
241 snd_strerror(err)); | |
242 return(0); | |
243 } else | |
1128 | 244 { |
1050 | 245 ao_buffersize = err; |
1146
a84610bb5476
hacked aocontrol_set_device working, and cleaned up a bit
al3x
parents:
1129
diff
changeset
|
246 if (verbose) |
a84610bb5476
hacked aocontrol_set_device working, and cleaned up a bit
al3x
parents:
1129
diff
changeset
|
247 printf("alsa-init: got buffersize %i\n", ao_buffersize); |
1128 | 248 } |
1050 | 249 #endif |
250 | |
251 #ifdef buffertime | |
252 { | |
253 int alsa_buffer_time = 60; | |
254 | |
255 if ((err = snd_pcm_hw_params_set_buffer_time_near(alsa_handler, alsa_hwparams, | |
256 alsa_buffer_time, 0)) < 0) | |
257 { | |
258 printf("alsa-init: unable to set buffer time near: %s\n", | |
259 snd_strerror(err)); | |
260 return(0); | |
261 } else | |
262 alsa_buffer_time = err; | |
263 | |
264 if ((err = snd_pcm_hw_params_set_period_time_near(alsa_handler, alsa_hwparams, | |
265 alsa_buffer_time/ao_bps, 0)) < 0) | |
266 { | |
267 printf("alsa-init: unable to set period time: %s\n", | |
268 snd_strerror(err)); | |
269 return(0); | |
270 } | |
1128 | 271 printf("alsa-init: buffer_time: %d, period_time :%d\n", |
272 alsa_buffer_time, err); | |
1050 | 273 } |
274 #endif | |
275 | |
276 if ((err = snd_pcm_hw_params(alsa_handler, alsa_hwparams)) < 0) | |
277 { | |
278 printf("alsa-init: unable to set parameters: %s\n", | |
279 snd_strerror(err)); | |
280 return(0); | |
281 } | |
1128 | 282 |
283 #ifdef sw_params | |
1050 | 284 if ((err = snd_pcm_sw_params_current(alsa_handler, alsa_swparams)) < 0) |
285 { | |
286 printf("alsa-init: unable to get parameters: %s\n", | |
287 snd_strerror(err)); | |
288 return(0); | |
289 } | |
290 | |
1128 | 291 #ifdef set_start_mode |
1050 | 292 if ((err = snd_pcm_sw_params_set_start_mode(alsa_handler, alsa_swparams, |
293 SND_PCM_START_DATA)) < 0) | |
294 { | |
295 printf("alsa-init: unable to set start mode: %s\n", | |
296 snd_strerror(err)); | |
297 return(0); | |
298 } | |
1128 | 299 #endif |
1050 | 300 |
301 if ((err = snd_pcm_sw_params(alsa_handler, alsa_swparams)) < 0) | |
302 { | |
303 printf("alsa-init: unable to set parameters: %s\n", | |
304 snd_strerror(err)); | |
305 return(0); | |
306 } | |
307 | |
1128 | 308 // snd_pcm_sw_params_default(alsa_handler, alsa_swparams); |
309 #endif | |
1050 | 310 if ((err = snd_pcm_prepare(alsa_handler)) < 0) |
311 { | |
312 printf("alsa-init: pcm prepare error: %s\n", snd_strerror(err)); | |
313 return(0); | |
314 } | |
315 | |
1115
a16b569f2702
-Wall style cleanups, TEST IT, it can be working by others
al3x
parents:
1058
diff
changeset
|
316 #ifdef start |
1050 | 317 if ((err = snd_pcm_start(alsa_handler)) < 0) |
318 { | |
319 printf("alsa-init: pcm start error: %s\n", snd_strerror(err)); | |
320 if (err != -EPIPE) | |
321 return(0); | |
322 if ((err = snd_pcm_start(alsa_handler)) < 0) | |
323 { | |
324 printf("alsa-init: pcm start error: %s\n", snd_strerror(err)); | |
325 return(0); | |
326 } | |
327 } | |
1115
a16b569f2702
-Wall style cleanups, TEST IT, it can be working by others
al3x
parents:
1058
diff
changeset
|
328 #endif |
1128 | 329 printf("AUDIO: %d Hz/%d channels/%d bpf/%d bytes buffer/%s\n", |
330 ao_samplerate, ao_channels, ao_bps, ao_buffersize, | |
1050 | 331 snd_pcm_format_description(alsa_format)); |
332 return(1); | |
333 } | |
334 | |
335 /* close audio device */ | |
336 static void uninit() | |
337 { | |
338 int err; | |
339 | |
340 if (alsa_device != NULL) | |
341 free(alsa_device); | |
342 | |
343 snd_pcm_hw_params_free(alsa_hwparams); | |
344 snd_pcm_sw_params_free(alsa_swparams); | |
345 | |
346 if ((err = snd_pcm_drain(alsa_handler)) < 0) | |
347 { | |
348 printf("alsa-uninit: pcm drain error: %s\n", snd_strerror(err)); | |
349 return; | |
350 } | |
351 | |
1129 | 352 #ifdef start |
1050 | 353 if ((err = snd_pcm_reset(alsa_handler)) < 0) |
354 { | |
355 printf("alsa-uninit: pcm reset error: %s\n", snd_strerror(err)); | |
356 return; | |
357 } | |
1129 | 358 #endif |
1050 | 359 |
360 if ((err = snd_pcm_close(alsa_handler)) < 0) | |
361 { | |
362 printf("alsa-uninit: pcm close error: %s\n", snd_strerror(err)); | |
363 return; | |
364 } | |
365 } | |
366 | |
367 static void audio_pause() | |
368 { | |
369 int err; | |
370 | |
371 if ((err = snd_pcm_drain(alsa_handler)) < 0) | |
372 { | |
373 printf("alsa-pause: pcm drain error: %s\n", snd_strerror(err)); | |
374 return; | |
375 } | |
376 | |
1129 | 377 #ifdef reset |
1050 | 378 if ((err = snd_pcm_reset(alsa_handler)) < 0) |
379 { | |
380 printf("alsa-pause: pcm reset error: %s\n", snd_strerror(err)); | |
381 return; | |
382 } | |
1129 | 383 #endif |
1050 | 384 } |
385 | |
386 static void audio_resume() | |
387 { | |
388 int err; | |
389 | |
390 if ((err = snd_pcm_prepare(alsa_handler)) < 0) | |
391 { | |
392 printf("alsa-resume: pcm prepare error: %s\n", snd_strerror(err)); | |
393 return; | |
394 } | |
395 | |
1129 | 396 #ifdef start |
1050 | 397 if ((err = snd_pcm_start(alsa_handler)) < 0) |
398 { | |
399 printf("alsa-resume: pcm start error: %s\n", snd_strerror(err)); | |
400 return; | |
401 } | |
1129 | 402 #endif |
1050 | 403 } |
404 | |
405 /* stop playing and empty buffers (for seeking/pause) */ | |
406 static void reset() | |
407 { | |
408 int err; | |
409 | |
410 if ((err = snd_pcm_drain(alsa_handler)) < 0) | |
411 { | |
412 printf("alsa-reset: pcm drain error: %s\n", snd_strerror(err)); | |
413 return; | |
414 } | |
415 | |
1129 | 416 #ifdef start |
1050 | 417 if ((err = snd_pcm_reset(alsa_handler)) < 0) |
418 { | |
419 printf("alsa-reset: pcm reset error: %s\n", snd_strerror(err)); | |
420 return; | |
421 } | |
1129 | 422 #endif |
1050 | 423 |
424 if ((err = snd_pcm_prepare(alsa_handler)) < 0) | |
425 { | |
426 printf("alsa-reset: pcm prepare error: %s\n", snd_strerror(err)); | |
427 return; | |
428 } | |
429 | |
1129 | 430 #ifdef start |
1050 | 431 if ((err = snd_pcm_start(alsa_handler)) < 0) |
432 { | |
433 printf("alsa-reset: pcm start error: %s\n", snd_strerror(err)); | |
434 return; | |
435 } | |
1129 | 436 #endif |
1050 | 437 } |
438 | |
439 /* | |
440 plays 'len' bytes of 'data' | |
441 returns: number of bytes played | |
442 */ | |
443 static int play(void* data, int len, int flags) | |
444 { | |
1115
a16b569f2702
-Wall style cleanups, TEST IT, it can be working by others
al3x
parents:
1058
diff
changeset
|
445 int got_len; |
a16b569f2702
-Wall style cleanups, TEST IT, it can be working by others
al3x
parents:
1058
diff
changeset
|
446 |
1128 | 447 if ((got_len = snd_pcm_writei(alsa_handler, data, (len/ao_bps))) != (len/ao_bps)) |
1050 | 448 { |
1115
a16b569f2702
-Wall style cleanups, TEST IT, it can be working by others
al3x
parents:
1058
diff
changeset
|
449 if (got_len == -EPIPE) /* underrun? */ |
1050 | 450 { |
451 printf("alsa-play: alsa underrun, resetting stream\n"); | |
1128 | 452 if ((got_len = snd_pcm_prepare(alsa_handler)) < 0) |
1050 | 453 { |
1128 | 454 printf("alsa-play: playback prepare error: %s\n", snd_strerror(got_len)); |
1050 | 455 return(0); |
456 } | |
1128 | 457 if ((got_len = snd_pcm_writei(alsa_handler, data, (len/ao_bps))) != (len/ao_bps)) |
1050 | 458 { |
459 printf("alsa-play: write error after reset: %s - giving up\n", | |
1128 | 460 snd_strerror(got_len)); |
1050 | 461 return(0); |
462 } | |
463 return(len); /* 2nd write was ok */ | |
464 } | |
465 } | |
466 return(len); | |
467 } | |
468 | |
469 /* how many byes are free in the buffer */ | |
470 static int get_space() | |
471 { | |
472 snd_pcm_status_t *status; | |
473 int ret; | |
474 | |
475 if ((ret = snd_pcm_status_malloc(&status)) < 0) | |
476 { | |
477 printf("alsa-space: memory allocation error: %s\n", snd_strerror(ret)); | |
478 return(0); | |
479 } | |
480 | |
481 if ((ret = snd_pcm_status(alsa_handler, status)) < 0) | |
482 { | |
483 printf("alsa-space: cannot get pcm status: %s\n", snd_strerror(ret)); | |
484 return(0); | |
485 } | |
486 | |
487 switch(snd_pcm_status_get_state(status)) | |
488 { | |
489 case SND_PCM_STATE_OPEN: | |
490 case SND_PCM_STATE_PREPARED: | |
491 case SND_PCM_STATE_RUNNING: | |
492 ret = snd_pcm_status_get_avail(status) * ao_bps; | |
493 break; | |
494 default: | |
495 ret = 0; | |
496 } | |
497 | |
498 snd_pcm_status_free(status); | |
1129 | 499 |
500 if (ret < 0) | |
501 ret = 0; | |
1050 | 502 return(ret); |
503 } | |
504 | |
505 /* how many unplayed bytes are in the buffer */ | |
506 static int get_delay() | |
507 { | |
508 snd_pcm_status_t *status; | |
509 int ret; | |
510 | |
511 if ((ret = snd_pcm_status_malloc(&status)) < 0) | |
512 { | |
513 printf("alsa-delay: memory allocation error: %s\n", snd_strerror(ret)); | |
514 return(0); | |
515 } | |
516 | |
517 if ((ret = snd_pcm_status(alsa_handler, status)) < 0) | |
518 { | |
519 printf("alsa-delay: cannot get pcm status: %s\n", snd_strerror(ret)); | |
520 return(0); | |
521 } | |
522 | |
523 switch(snd_pcm_status_get_state(status)) | |
524 { | |
525 case SND_PCM_STATE_OPEN: | |
526 case SND_PCM_STATE_PREPARED: | |
527 case SND_PCM_STATE_RUNNING: | |
528 ret = snd_pcm_status_get_delay(status) * ao_bps; | |
529 break; | |
530 default: | |
531 ret = 0; | |
532 } | |
533 | |
534 snd_pcm_status_free(status); | |
1129 | 535 |
536 if (ret < 0) | |
537 ret = 0; | |
1050 | 538 return(ret); |
539 } |