Partially sync files.el from XEmacs 21.5 for wildcard support.
[sxemacs] / src / media / sound-alsa.c
1 /* sound-alsa.c - play a sound over the alsa
2
3    Copyright (C) 2006 Sebastian Freundt
4
5 This file is part of SXEmacs
6
7 SXEmacs is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
11
12 SXEmacs 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
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program.  If not, see <http://www.gnu.org/licenses/>. */
19
20
21 /* Synched up with: Not in FSF. */
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #include "lisp.h"
28
29 #include <unistd.h>
30 #include <fcntl.h>
31 #include <stdio.h>
32 #include <errno.h>
33 #include <string.h>
34
35 #include "media.h"
36 #include "sound-alsa.h"
37
38 Lisp_Object Qalsa;
39
40 #define MYSELF ADRIVER_ALSA
41
42 #define __ALSA_DEBUG__(args...)         fprintf(stderr, "ALSA " args)
43 #ifndef ALSA_DEBUG_FLAG
44 #define ALSA_DEBUG(args...)
45 #else
46 #define ALSA_DEBUG(args...)             __ALSA_DEBUG__(args)
47 #endif
48 #define ALSA_DEBUG_HW(args...)          ALSA_DEBUG("[hardware]: " args)
49 #define ALSA_DEBUG_S(args...)           ALSA_DEBUG("[stream]: " args)
50 #define ALSA_DEBUG_COE(args...)         ALSA_DEBUG("[coerce]: " args)
51 #define ALSA_DEBUG_AJ(args...)          ALSA_DEBUG("[audio-job]: " args)
52 #define ALSA_CRITICAL(args...)          __ALSA_DEBUG__("CRITICAL: " args)
53
54 \f
55 DECLARE_AUDIO_DEVICE_SIMPLE_METHS(sound_alsa);
56 DEFINE_AUDIO_DEVICE_SIMPLE(sound_alsa);
57
58 \f
59 static Lisp_Object
60 sound_alsa_mark(ad_device_data *devdata)
61 {
62         sound_alsa_data_t *sad = devdata;
63
64         mark_object(sad->device);
65
66         return Qnil;
67 }
68
69 static void
70 sound_alsa_print(Lisp_Object device, Lisp_Object pcfun, int ef)
71 {
72         sound_alsa_data_t *sad = NULL;
73         sad = get_audio_device_data(device);
74         /* cannot use incomplete or corrupt audio devices */
75         if (XAUDIO_DEVICE_DRIVER(device) != MYSELF || sad == NULL) {
76                 write_c_string(" VOID", pcfun);
77                 /* now that we are here, mark AO device as dead */
78                 XAUDIO_DEVICE_STATE(device) = ASTATE_DEAD;
79                 return;
80         }
81
82         /* info about the connected output plugin */
83         write_c_string(" :device ", pcfun);
84         if (NILP(sad->device))
85                 write_c_string("#default", pcfun);
86         else
87                 print_internal(sad->device, pcfun, ef);
88
89         if (sad->keep_open) {
90                 write_fmt_string(pcfun, " :keep-open t :handle 0x%lx",
91                                  (long unsigned int)sad->handle);
92         } else
93                 write_c_string(" :keep-open nil", pcfun);
94
95         write_fmt_str(pcfun, " :params 0x%lx", (long unsigned int)sad->hwparams);
96         return;
97 }
98
99 \f
100 static int
101 sound_alsa_open_device(sound_alsa_data_t *sad)
102 {
103         if (sad->handle == NULL) {
104                 const char *dev;
105                 if (NILP(sad->device))
106                         dev = "default";
107                 else
108                         dev = (char*)XSTRING_DATA(sad->device);
109
110                 return snd_pcm_open(&sad->handle, dev,
111                                     SND_PCM_STREAM_PLAYBACK, 0);
112         }
113
114         return 0;
115 }
116
117 static int
118 sound_alsa_init_hardware(sound_alsa_data_t *sad)
119 {
120         int err = 0;
121
122         if (sad->hwparams == NULL || sad->handle == NULL)
123                 return -1;
124
125         /* check if we can configure this device */
126         err = snd_pcm_hw_params_any(sad->handle, sad->hwparams);
127         if (err < 0)
128                 return err;
129
130         err = snd_pcm_hw_params_set_access(
131                 sad->handle, sad->hwparams, SND_PCM_ACCESS_RW_INTERLEAVED);
132
133         return err;
134 }
135
136 static void
137 sound_alsa_finish(ad_device_data *data)
138 {
139         sound_alsa_data_t *sad = data;
140
141         SXE_MUTEX_LOCK(&sad->mtx);
142         if (sad->hwparams)
143                 snd_pcm_hw_params_free(sad->hwparams);
144         sad->hwparams = NULL;
145
146         if (sad->handle) {
147                 snd_pcm_hw_free(sad->handle);
148                 snd_pcm_close(sad->handle);
149         }
150         sad->handle = NULL;
151         SXE_MUTEX_UNLOCK(&sad->mtx);
152         SXE_MUTEX_FINI(&sad->mtx);
153
154         ALSA_DEBUG("audio-device finished.\n");
155
156         return;
157 }
158
159 static ad_device_data *
160 sound_alsa_create(Lisp_Object alsa_options)
161 {
162         /* result */
163         sound_alsa_data_t *sad = NULL;
164         int keep_open = 0;
165         int err = 0;
166         /* option keywords */
167         Lisp_Object opt_device;
168         Lisp_Object opt_keepopen;
169
170         /* parse options */
171         opt_device = Fplist_get(alsa_options, Q_device, Qnil);
172         if (!NILP(opt_device) && !STRINGP(opt_device)) {
173                 wrong_type_argument(Qstringp, opt_device);
174                 return NULL;
175         }
176
177         opt_keepopen = Fplist_get(alsa_options, Q_keep_open, Qnil);
178         if (!NILP(opt_keepopen))
179                 keep_open = 1;
180
181         /* initialise and fill */
182         sad = xnew_and_zero(sound_alsa_data_t);
183         sad->device = opt_device;
184         sad->keep_open = keep_open;
185         SXE_MUTEX_INIT(&sad->mtx);
186
187         /* Open the device */
188         if ((err = sound_alsa_open_device(sad)) < 0) {
189                 xfree(sad);
190                 error(GETTEXT("audio-alsa: "
191                               "Opening ALSA device failed: %s."),
192                         snd_strerror(err));
193                 return NULL;
194         }
195
196         snd_pcm_hw_params_malloc(&sad->hwparams);
197
198         if ((err = sound_alsa_init_hardware(sad)) < 0) {
199                 sound_alsa_finish(sad);
200                 xfree(sad);
201                 error(GETTEXT("Error: audio-alsa: "
202                               "Opening ALSA device failed: %s."),
203                       snd_strerror(err));
204                 return NULL;
205         }
206
207         if (!keep_open) {
208                 snd_pcm_hw_free(sad->handle);
209                 snd_pcm_close(sad->handle);
210                 sad->handle = NULL;
211         }
212
213         return (ad_device_data*)sad;
214 }
215
216 \f
217 #ifdef EF_USE_ASYNEQ
218 static inline void
219 sound_alsa_change_volume(audio_job_t aj, audio_job_event_args_t args)
220 {
221         SXE_MUTEX_LOCK(&aj->mtx);
222         aj->volume = args->volume_args;
223         SXE_MUTEX_UNLOCK(&aj->mtx);
224 }
225
226 static inline void
227 sound_alsa_change_rate(audio_job_t aj, audio_job_event_args_t args)
228 {
229         SXE_MUTEX_LOCK(&aj->mtx);
230         aj->ratetrafo = args->rate_args;
231         SXE_MUTEX_UNLOCK(&aj->mtx);
232 }
233
234 static inline void
235 sound_alsa_change_state(audio_job_t aj, audio_job_event_args_t args)
236 {
237         SXE_MUTEX_LOCK(&aj->mtx);
238         switch (args->state_args) {
239         case aj_pause:
240                 ALSA_DEBUG_AJ("->pause state\n");
241                 aj->play_state = MTPSTATE_PAUSE;
242                 break;
243         case aj_resume:
244                 ALSA_DEBUG_AJ("->resume state\n");
245                 aj->play_state = MTPSTATE_RUN;
246                 break;
247         case aj_start:
248                 ALSA_DEBUG_AJ("->start state\n");
249                 break;
250         case aj_stop:
251                 ALSA_DEBUG_AJ("->stop state\n");
252                 aj->play_state = MTPSTATE_STOP;
253                 break;
254
255         case no_audio_job_change_states:
256         default:
257                 ALSA_DEBUG_AJ("->unknown state\n");
258                 break;
259         }
260         SXE_MUTEX_UNLOCK(&aj->mtx);
261 }
262
263 static inline void
264 sound_alsa_handle_aj_events(audio_job_t aj)
265         __attribute__((always_inline));
266 static inline void
267 sound_alsa_handle_aj_events(audio_job_t aj)
268 {
269         sound_alsa_aj_data_t *sasd;
270         audio_job_event_t ev = NULL;
271
272 #if 0
273         assert(audio_job_queue(aj));
274 #endif
275
276         SXE_MUTEX_LOCK(&aj->mtx);
277         sasd = audio_job_device_data(aj);
278         if ((ev = eq_noseeum_dequeue(audio_job_queue(aj))) == NULL) {
279                 SXE_MUTEX_UNLOCK(&aj->mtx);
280                 return;
281         }
282         SXE_MUTEX_UNLOCK(&aj->mtx);
283
284         ALSA_DEBUG_AJ("Event 0x%lx\n", (long unsigned int)ev);
285         switch (audio_job_event_kind(ev)) {
286         case aj_change_state:
287                 ALSA_DEBUG_AJ("change state event\n");
288                 sound_alsa_change_state(aj, &audio_job_event_args(ev));
289                 break;
290         case aj_change_volume:
291                 ALSA_DEBUG_AJ("change volume event\n");
292                 sound_alsa_change_volume(aj, &audio_job_event_args(ev));
293                 break;
294         case aj_change_rate:
295                 ALSA_DEBUG_AJ("change rate event\n");
296                 sound_alsa_change_rate(aj, &audio_job_event_args(ev));
297                 break;
298
299         case no_audio_job_event_kinds:
300         default:
301                 ALSA_CRITICAL("unknown event\n");
302                 break;
303         }
304         free_audio_job_event(ev);
305 }
306 #endif  /* EF_USE_ASYNEQ */
307 \f
308 static int
309 sound_alsa_prepare_device(sound_alsa_data_t *sad, sound_alsa_aj_data_t *sasd)
310 {
311         /* alsa stuff */
312         snd_pcm_state_t state;
313         snd_pcm_format_t tmpfmt[] = {
314                 SND_PCM_FORMAT_S32, SND_PCM_FORMAT_S24,
315                 SND_PCM_FORMAT_S16,
316                 SND_PCM_FORMAT_FLOAT,
317                 SND_PCM_FORMAT_U8,
318                 SND_PCM_FORMAT_UNKNOWN };
319         int err = 0, i, num_tmpfmt = sizeof(tmpfmt)/sizeof(snd_pcm_format_t);
320
321         sasd->format = SND_PCM_FORMAT_UNKNOWN;
322         sasd->channels = 0;
323
324         switch (sasd->mtap->channels) {
325         case 1:
326                 if (snd_pcm_hw_params_test_channels(
327                             sad->handle, sad->hwparams, 1) == 0) {
328                         sasd->channels = 1;
329                         ALSA_DEBUG_HW("Using MONO.\n");
330                 } else if (!snd_pcm_hw_params_test_channels(
331                                    sad->handle, sad->hwparams, 2)) {
332                         sasd->channels = 2;
333                         ADD_MEDIA_SAMPLE_EFFECT(
334                                 sasd->coe_chain, sasd->coe_ch_cnt,
335                                 MEDIA_SAMPLE_EFFECT(sxe_mse_1ch_to_2ch), NULL);
336                                 ALSA_DEBUG_HW("MONO->STEREO coerce.\n");
337                 }
338                 break;
339         case 2:
340                 if (snd_pcm_hw_params_test_channels(
341                             sad->handle, sad->hwparams, 2) == 0) {
342                         sasd->channels = 2;
343                         ALSA_DEBUG_HW("Using STEREO.\n");
344                 } else if (!snd_pcm_hw_params_test_channels(
345                                    sad->handle, sad->hwparams, 1)) {
346                         sasd->channels = 1;
347                         ADD_MEDIA_SAMPLE_EFFECT(
348                                 sasd->coe_chain, sasd->coe_ch_cnt,
349                                 MEDIA_SAMPLE_EFFECT(sxe_mse_2ch_to_1ch), NULL);
350                         ALSA_DEBUG_HW("STEREO->MONO coerce.\n");
351                 }
352                 break;
353
354                 /* more channels here */
355         default:
356                 break;
357         }
358
359         if (sasd->channels == 0 ||
360             (err = snd_pcm_hw_params_set_channels(
361                      sad->handle, sad->hwparams, sasd->channels)) < 0) {
362                 message(GETTEXT("audio-alsa: "
363                                 "Setting channels failed: %s."),
364                         snd_strerror(err));
365                 return -1;
366         }
367
368         /* now we try to set a useful format */
369         ALSA_DEBUG("trying %d formats\n", num_tmpfmt);
370         i = 0;
371         while (i < num_tmpfmt &&
372                (snd_pcm_hw_params_test_format(
373                          sad->handle, sad->hwparams, tmpfmt[i])))
374                 i++;
375         if (i == num_tmpfmt) {
376                 ALSA_DEBUG_HW("Setting sample format failed :(.\n");
377                 /* warning? */
378                 message(GETTEXT("audio-alsa: "
379                                 "Setting sample format failed."));
380                 return -1;
381         }
382
383         switch ((unsigned int)(sasd->format = tmpfmt[i])) {
384         case SND_PCM_FORMAT_U8:
385                 sasd->msf = sxe_msf_U8;
386                 sasd->framesize = sasd->channels * sizeof(uint8_t);
387                 ALSA_DEBUG_HW("Using U8.\n");
388                 break;
389         case SND_PCM_FORMAT_S16:
390                 sasd->msf = sxe_msf_S16;
391                 sasd->framesize = sasd->channels * sizeof(int16_t);
392                 ALSA_DEBUG_HW("Using S16.\n");
393                 break;
394         case SND_PCM_FORMAT_S24:
395                 sasd->msf = sxe_msf_S24;
396                 sasd->framesize = sasd->channels * sizeof(int32_t);
397                 ALSA_DEBUG_HW("Using S24.\n");
398                 break;
399         case SND_PCM_FORMAT_S32:
400                 sasd->msf = sxe_msf_S32;
401                 sasd->framesize = sasd->channels * sizeof(int32_t);
402                 ALSA_DEBUG_HW("Using S32.\n");
403                 break;
404         case SND_PCM_FORMAT_FLOAT:
405                 sasd->msf = sxe_msf_FLT;
406                 sasd->framesize = sasd->channels * sizeof(float);
407                 ALSA_DEBUG_HW("Using FLT.\n");
408                 break;
409         default:
410                 break;
411         }
412
413         /* now set the format */
414         if ((err = snd_pcm_hw_params_set_format(
415                      sad->handle, sad->hwparams, sasd->format)) < 0) {
416                 ALSA_DEBUG_HW("Setting sample format failed: %s.\n",
417                               snd_strerror(err));
418                 /* warning? */
419                 message(GETTEXT("audio-alsa: "
420                                 "Setting sample format failed: %s."),
421                         snd_strerror(err));
422                 return -1;
423         }
424
425         sasd->samplerate = sasd->mtap->samplerate;
426         if ((err = snd_pcm_hw_params_set_rate_near(
427                      sad->handle, sad->hwparams, &sasd->samplerate, 0)) < 0) {
428                 ALSA_DEBUG_HW("Setting sample rate failed: %s.\n",
429                               snd_strerror(err));
430                 /* warning? */
431                 message(GETTEXT("audio-alsa: "
432                                 "Setting sample rate failed: %s."),
433                         snd_strerror(err));
434                 return -1;
435         }
436         /* we could feed the coerce chain with the rerate module */
437         if (sasd->samplerate != sasd->mtap->samplerate)
438                 ALSA_DEBUG_HW("had to adapt samplerate, old: %d, new: %d.\n",
439                               sasd->mtap->samplerate, sasd->samplerate);
440
441         ALSA_DEBUG_HW("Using samplerate: %d.\n", sasd->samplerate);
442
443         /* now set all the params */
444         if ((err = snd_pcm_hw_params(sad->handle, sad->hwparams)) < 0) {
445                 message(GETTEXT("audio-alsa: "
446                                 "Setting parameters failed: %s."),
447                         snd_strerror(err));
448                 return -1;
449         }
450
451         if ((err = snd_pcm_prepare(sad->handle)) < 0) {
452                 message(GETTEXT("audio-alsa: "
453                                 "Cannot prepare ALSA device: %s."),
454                         snd_strerror(err));
455                 return -1;
456         }
457
458         if ((state = snd_pcm_state(sad->handle)) != SND_PCM_STATE_PREPARED) {
459                 message(GETTEXT("audio-alsa: "
460                                 "Cannot prepare ALSA device."));
461                 return -1;
462         }
463
464         return 1;
465 }
466
467 static int
468 sound_alsa_close_device(sound_alsa_data_t *sad)
469 {
470         SXE_MUTEX_LOCK(&sad->mtx);
471         sad->lock = 0;
472         if (sad->handle == NULL) {
473                 SXE_MUTEX_UNLOCK(&sad->mtx);
474                 return 0;
475         }
476
477         if (sad->keep_open) {
478                 SXE_MUTEX_UNLOCK(&sad->mtx);
479                 return 0;
480         }
481
482         /* close /dev/dsp */
483         snd_pcm_hw_free(sad->handle);
484         snd_pcm_close(sad->handle);
485
486         ALSA_DEBUG_HW("device handle closed\n");
487         sad->handle = NULL;
488         SXE_MUTEX_UNLOCK(&sad->mtx);
489
490         return 0;
491 }
492
493 static int
494 sound_alsa_play(audio_job_t aj)
495 {
496         /* stream stuff */
497         Lisp_Media_Stream *ms;
498         media_substream *mss;
499         /* thread stuff */
500         media_thread_play_state mtp;
501         /* device stuff */
502         Lisp_Object device;
503         Lisp_Audio_Device *lad = NULL;
504         sound_alsa_data_t *sad = NULL;
505         /* buffering */
506         size_t len = 0, tmplen = 0;
507         sxe_media_sample_t *tmpbuf;
508         int err = 0, i, resolution;
509         /* subthread stuff */
510         sound_alsa_aj_data_t _sasd, *sasd = &_sasd;
511         sxe_mse_volume_args _volargs, *volargs = &_volargs;
512         sxe_mse_rerate_args _rrargs, *rrargs = &_rrargs;
513         /* cache stuff */
514         int alloced_myself = 0;
515
516         SOUND_UNPACK_MT(aj, device, ms, mss, lad, sad, sasd->mtap);
517
518         SXE_MUTEX_LOCK(&sad->mtx);
519         if (sad->lock) {
520                 message(GETTEXT("audio-alsa: "
521                                 "Device locked."));
522                 /* this lock is unnecessary, we _could_ write concurrently
523                    provided that the concurrent media streams have set the ALSA
524                    device to the exact same hardware parameters.
525                    In cleartext this means, we have to convert all sample data
526                    to a common format, e.g. 48000Hz/STEREO/FLT or the like.
527                    However, I'm tired at the moment so I leave this lock here.
528                 */
529                 SXE_MUTEX_UNLOCK(&sad->mtx);
530                 return 0;
531         }
532
533         sad->lock = 1;
534
535         /* trigger alsa, the device name should be an option */
536         if ((err = sound_alsa_open_device(sad)) < 0) {
537                 ALSA_DEBUG_HW("Opening ALSA device failed: %s.",
538                               snd_strerror(err));
539                 sad->handle = NULL;
540                 /* warning? */
541                 message(GETTEXT("audio-alsa: "
542                                 "Opening ALSA device failed: %s."),
543                         snd_strerror(err));
544                 SXE_MUTEX_UNLOCK(&sad->mtx);
545                 sound_alsa_close_device(sad);
546                 return 0;
547         }
548
549         if ((err = sound_alsa_init_hardware(sad)) < 0) {
550                 ALSA_DEBUG_HW("Device not configurable: %s.\n",
551                               snd_strerror(err));
552                 /* warning? */
553                 message(GETTEXT("audio-alsa: "
554                                 "Cannot access ALSA device: %s."),
555                         snd_strerror(err));
556                 SXE_MUTEX_UNLOCK(&sad->mtx);
557                 sound_alsa_close_device(sad);
558                 return 0;
559         }
560
561         /* init the sasd */
562         sasd->samplerate = sasd->channels = 0;
563         sasd->framesize = 0;
564         sasd->coe_ch_cnt = 0;
565
566         if ((err = sound_alsa_prepare_device(sad, sasd)) < 0) {
567                 SXE_MUTEX_UNLOCK(&sad->mtx);
568                 sound_alsa_close_device(sad);
569                 return 0;
570         }
571
572         /* the volume effect */
573         ADD_MEDIA_SAMPLE_EFFECT(
574                 sasd->coe_chain, sasd->coe_ch_cnt,
575                 MEDIA_SAMPLE_EFFECT(sxe_mse_volume), volargs);
576         volargs->num_channels = sasd->channels;
577
578         /* the rerate effect */
579         ADD_MEDIA_SAMPLE_EFFECT(
580                 sasd->coe_chain, sasd->coe_ch_cnt,
581                 MEDIA_SAMPLE_EFFECT(sxe_mse_rerate), rrargs);
582         rrargs->num_channels = sasd->channels;
583         rrargs->srcrate = rrargs->tgtrate = 1;
584
585         ALSA_DEBUG_COE("have %d coerce functions in my chain.\n",
586                        sasd->coe_ch_cnt);
587
588         /* rewind it ... */
589         media_stream_meth(ms, rewind)(mss);
590
591         XAUDIO_DEVICE_STATE(device) = ASTATE_ALIVE;
592
593         /* ... and play it */
594         SXE_MUTEX_LOCK(&aj->mtx);
595         if (aj->buffer_alloc_size < SOUND_MAX_AUDIO_FRAME_SIZE) {
596                 alloced_myself = 1;
597                 aj->buffer = xmalloc_atomic(SOUND_MAX_AUDIO_FRAME_SIZE);
598                 aj->buffer_alloc_size = SOUND_MAX_AUDIO_FRAME_SIZE;
599         }
600         resolution = (sasd->samplerate * MTPSTATE_REACT_TIME) / 1000000;
601         tmpbuf = (sxe_media_sample_t*)aj->buffer;
602         SXE_MUTEX_UNLOCK(&aj->mtx);
603         SXE_MUTEX_UNLOCK(&sad->mtx);
604
605         while (aj->play_state != MTPSTATE_STOP) {
606
607 #ifdef EF_USE_ASYNEQ
608                 if (audio_job_queue(aj)) {
609                         sound_alsa_handle_aj_events(aj);
610                 }
611 #endif
612
613                 SXE_MUTEX_LOCK(&aj->mtx);
614                 mtp = aj->play_state;
615                 SXE_MUTEX_UNLOCK(&aj->mtx);
616                 switch (mtp) {
617                 case MTPSTATE_RUN:
618                         len = media_stream_meth(ms, read)(
619                                 mss, aj->buffer, resolution);
620                         if (!len) {
621                                 ALSA_DEBUG_S("finished\n");
622                                 SXE_MUTEX_LOCK(&aj->mtx);
623                                 aj->play_state = MTPSTATE_STOP;
624                                 SXE_MUTEX_UNLOCK(&aj->mtx);
625                                 break;
626                         }
627
628                         /* set up the volume args */
629                         volargs->volume[0] = volargs->volume[1] =
630                                 aj->volume;
631                         /* set up the rerate args */
632                         rrargs->tweak = aj->ratetrafo;
633
634                         /* coerce the stuff, tmplen is in samples */
635                         tmplen = sasd->channels*len;
636                         for (i = 0; i < sasd->coe_ch_cnt; i++) {
637                                 ALSA_DEBUG_COE("calling coerce "
638                                                "%d on b:0x%x l:%d\n",
639                                                i, (unsigned int)tmpbuf, tmplen);
640                                 tmplen = CALL_MEDIA_SAMPLE_EFFECT(
641                                         sasd->coe_chain, i,
642                                         tmpbuf, tmpbuf, tmplen);
643                         }
644
645                         /* bring back to S16 or U8 */
646                         MEDIA_SAMPLE_FORMAT_DOWNSAMPLE(sasd->msf)(
647                                 aj->buffer, aj->buffer, tmplen);
648
649                         snd_pcm_writei(sad->handle, aj->buffer, len);
650                         break;
651                 case MTPSTATE_PAUSE:
652                         ALSA_DEBUG("sleeping for %d\n", resolution);
653                         memset(aj->buffer, 0, resolution*sasd->framesize);
654                         snd_pcm_writei(sad->handle, aj->buffer,
655                                        resolution);
656                         break;
657
658                 case MTPSTATE_UNKNOWN:
659                 case MTPSTATE_STOP:
660                 case NUMBER_OF_MEDIA_THREAD_PLAY_STATES:
661                 default:
662                         ALSA_DEBUG("ACK, quit\n");
663                         SXE_MUTEX_LOCK(&aj->mtx);
664                         aj->play_state = MTPSTATE_STOP;
665                         SXE_MUTEX_UNLOCK(&aj->mtx);
666                         break;
667                 }
668         }
669
670 #if 0
671         snd_pcm_drain(ad);
672 #endif
673         SXE_MUTEX_LOCK(&aj->mtx);
674         aj->state = MTSTATE_FINISHED;
675
676         /* -- Close and shutdown -- */
677         if (alloced_myself && aj->buffer) {
678                 xfree(aj->buffer);
679         }
680         aj->buffer = NULL;
681         aj->buffer_alloc_size = 0;
682         SXE_MUTEX_UNLOCK(&aj->mtx);
683
684         sound_alsa_close_device(sad);
685
686         return 1;
687 }
688
689 #undef MYSELF
690
691 /* sound-alsa.c ends here */