Shut set but unused warnings.
[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         SXE_SET_UNUSED(sasd);
279
280         if ((ev = eq_noseeum_dequeue(audio_job_queue(aj))) == NULL) {
281                 SXE_MUTEX_UNLOCK(&aj->mtx);
282                 return;
283         }
284         SXE_MUTEX_UNLOCK(&aj->mtx);
285
286         ALSA_DEBUG_AJ("Event 0x%lx\n", (long unsigned int)ev);
287         switch (audio_job_event_kind(ev)) {
288         case aj_change_state:
289                 ALSA_DEBUG_AJ("change state event\n");
290                 sound_alsa_change_state(aj, &audio_job_event_args(ev));
291                 break;
292         case aj_change_volume:
293                 ALSA_DEBUG_AJ("change volume event\n");
294                 sound_alsa_change_volume(aj, &audio_job_event_args(ev));
295                 break;
296         case aj_change_rate:
297                 ALSA_DEBUG_AJ("change rate event\n");
298                 sound_alsa_change_rate(aj, &audio_job_event_args(ev));
299                 break;
300
301         case no_audio_job_event_kinds:
302         default:
303                 ALSA_CRITICAL("unknown event\n");
304                 break;
305         }
306         free_audio_job_event(ev);
307 }
308 #endif  /* EF_USE_ASYNEQ */
309 \f
310 static int
311 sound_alsa_prepare_device(sound_alsa_data_t *sad, sound_alsa_aj_data_t *sasd)
312 {
313         /* alsa stuff */
314         snd_pcm_state_t state;
315         snd_pcm_format_t tmpfmt[] = {
316                 SND_PCM_FORMAT_S32, SND_PCM_FORMAT_S24,
317                 SND_PCM_FORMAT_S16,
318                 SND_PCM_FORMAT_FLOAT,
319                 SND_PCM_FORMAT_U8,
320                 SND_PCM_FORMAT_UNKNOWN };
321         int err = 0, i, num_tmpfmt = sizeof(tmpfmt)/sizeof(snd_pcm_format_t);
322
323         sasd->format = SND_PCM_FORMAT_UNKNOWN;
324         sasd->channels = 0;
325
326         switch (sasd->mtap->channels) {
327         case 1:
328                 if (snd_pcm_hw_params_test_channels(
329                             sad->handle, sad->hwparams, 1) == 0) {
330                         sasd->channels = 1;
331                         ALSA_DEBUG_HW("Using MONO.\n");
332                 } else if (!snd_pcm_hw_params_test_channels(
333                                    sad->handle, sad->hwparams, 2)) {
334                         sasd->channels = 2;
335                         ADD_MEDIA_SAMPLE_EFFECT(
336                                 sasd->coe_chain, sasd->coe_ch_cnt,
337                                 MEDIA_SAMPLE_EFFECT(sxe_mse_1ch_to_2ch), NULL);
338                                 ALSA_DEBUG_HW("MONO->STEREO coerce.\n");
339                 }
340                 break;
341         case 2:
342                 if (snd_pcm_hw_params_test_channels(
343                             sad->handle, sad->hwparams, 2) == 0) {
344                         sasd->channels = 2;
345                         ALSA_DEBUG_HW("Using STEREO.\n");
346                 } else if (!snd_pcm_hw_params_test_channels(
347                                    sad->handle, sad->hwparams, 1)) {
348                         sasd->channels = 1;
349                         ADD_MEDIA_SAMPLE_EFFECT(
350                                 sasd->coe_chain, sasd->coe_ch_cnt,
351                                 MEDIA_SAMPLE_EFFECT(sxe_mse_2ch_to_1ch), NULL);
352                         ALSA_DEBUG_HW("STEREO->MONO coerce.\n");
353                 }
354                 break;
355
356                 /* more channels here */
357         default:
358                 break;
359         }
360
361         if (sasd->channels == 0 ||
362             (err = snd_pcm_hw_params_set_channels(
363                      sad->handle, sad->hwparams, sasd->channels)) < 0) {
364                 message(GETTEXT("audio-alsa: "
365                                 "Setting channels failed: %s."),
366                         snd_strerror(err));
367                 return -1;
368         }
369
370         /* now we try to set a useful format */
371         ALSA_DEBUG("trying %d formats\n", num_tmpfmt);
372         i = 0;
373         while (i < num_tmpfmt &&
374                (snd_pcm_hw_params_test_format(
375                          sad->handle, sad->hwparams, tmpfmt[i])))
376                 i++;
377         if (i == num_tmpfmt) {
378                 ALSA_DEBUG_HW("Setting sample format failed :(.\n");
379                 /* warning? */
380                 message(GETTEXT("audio-alsa: "
381                                 "Setting sample format failed."));
382                 return -1;
383         }
384
385         switch ((unsigned int)(sasd->format = tmpfmt[i])) {
386         case SND_PCM_FORMAT_U8:
387                 sasd->msf = sxe_msf_U8;
388                 sasd->framesize = sasd->channels * sizeof(uint8_t);
389                 ALSA_DEBUG_HW("Using U8.\n");
390                 break;
391         case SND_PCM_FORMAT_S16:
392                 sasd->msf = sxe_msf_S16;
393                 sasd->framesize = sasd->channels * sizeof(int16_t);
394                 ALSA_DEBUG_HW("Using S16.\n");
395                 break;
396         case SND_PCM_FORMAT_S24:
397                 sasd->msf = sxe_msf_S24;
398                 sasd->framesize = sasd->channels * sizeof(int32_t);
399                 ALSA_DEBUG_HW("Using S24.\n");
400                 break;
401         case SND_PCM_FORMAT_S32:
402                 sasd->msf = sxe_msf_S32;
403                 sasd->framesize = sasd->channels * sizeof(int32_t);
404                 ALSA_DEBUG_HW("Using S32.\n");
405                 break;
406         case SND_PCM_FORMAT_FLOAT:
407                 sasd->msf = sxe_msf_FLT;
408                 sasd->framesize = sasd->channels * sizeof(float);
409                 ALSA_DEBUG_HW("Using FLT.\n");
410                 break;
411         default:
412                 break;
413         }
414
415         /* now set the format */
416         if ((err = snd_pcm_hw_params_set_format(
417                      sad->handle, sad->hwparams, sasd->format)) < 0) {
418                 ALSA_DEBUG_HW("Setting sample format failed: %s.\n",
419                               snd_strerror(err));
420                 /* warning? */
421                 message(GETTEXT("audio-alsa: "
422                                 "Setting sample format failed: %s."),
423                         snd_strerror(err));
424                 return -1;
425         }
426
427         sasd->samplerate = sasd->mtap->samplerate;
428         if ((err = snd_pcm_hw_params_set_rate_near(
429                      sad->handle, sad->hwparams, &sasd->samplerate, 0)) < 0) {
430                 ALSA_DEBUG_HW("Setting sample rate failed: %s.\n",
431                               snd_strerror(err));
432                 /* warning? */
433                 message(GETTEXT("audio-alsa: "
434                                 "Setting sample rate failed: %s."),
435                         snd_strerror(err));
436                 return -1;
437         }
438         /* we could feed the coerce chain with the rerate module */
439         if (sasd->samplerate != sasd->mtap->samplerate)
440                 ALSA_DEBUG_HW("had to adapt samplerate, old: %d, new: %d.\n",
441                               sasd->mtap->samplerate, sasd->samplerate);
442
443         ALSA_DEBUG_HW("Using samplerate: %d.\n", sasd->samplerate);
444
445         /* now set all the params */
446         if ((err = snd_pcm_hw_params(sad->handle, sad->hwparams)) < 0) {
447                 message(GETTEXT("audio-alsa: "
448                                 "Setting parameters failed: %s."),
449                         snd_strerror(err));
450                 return -1;
451         }
452
453         if ((err = snd_pcm_prepare(sad->handle)) < 0) {
454                 message(GETTEXT("audio-alsa: "
455                                 "Cannot prepare ALSA device: %s."),
456                         snd_strerror(err));
457                 return -1;
458         }
459
460         if ((state = snd_pcm_state(sad->handle)) != SND_PCM_STATE_PREPARED) {
461                 message(GETTEXT("audio-alsa: "
462                                 "Cannot prepare ALSA device."));
463                 return -1;
464         }
465
466         return 1;
467 }
468
469 static int
470 sound_alsa_close_device(sound_alsa_data_t *sad)
471 {
472         SXE_MUTEX_LOCK(&sad->mtx);
473         sad->lock = 0;
474         if (sad->handle == NULL) {
475                 SXE_MUTEX_UNLOCK(&sad->mtx);
476                 return 0;
477         }
478
479         if (sad->keep_open) {
480                 SXE_MUTEX_UNLOCK(&sad->mtx);
481                 return 0;
482         }
483
484         /* close /dev/dsp */
485         snd_pcm_hw_free(sad->handle);
486         snd_pcm_close(sad->handle);
487
488         ALSA_DEBUG_HW("device handle closed\n");
489         sad->handle = NULL;
490         SXE_MUTEX_UNLOCK(&sad->mtx);
491
492         return 0;
493 }
494
495 static int
496 sound_alsa_play(audio_job_t aj)
497 {
498         /* stream stuff */
499         Lisp_Media_Stream *ms;
500         media_substream *mss;
501         /* thread stuff */
502         media_thread_play_state mtp;
503         /* device stuff */
504         Lisp_Object device;
505         Lisp_Audio_Device *lad = NULL;
506         sound_alsa_data_t *sad = NULL;
507         /* buffering */
508         size_t len = 0, tmplen = 0;
509         sxe_media_sample_t *tmpbuf;
510         int err = 0, i, resolution;
511         /* subthread stuff */
512         sound_alsa_aj_data_t _sasd, *sasd = &_sasd;
513         sxe_mse_volume_args _volargs, *volargs = &_volargs;
514         sxe_mse_rerate_args _rrargs, *rrargs = &_rrargs;
515         /* cache stuff */
516         int alloced_myself = 0;
517
518         SOUND_UNPACK_MT(aj, device, ms, mss, lad, sad, sasd->mtap);
519
520         SXE_MUTEX_LOCK(&sad->mtx);
521         if (sad->lock) {
522                 message(GETTEXT("audio-alsa: "
523                                 "Device locked."));
524                 /* this lock is unnecessary, we _could_ write concurrently
525                    provided that the concurrent media streams have set the ALSA
526                    device to the exact same hardware parameters.
527                    In cleartext this means, we have to convert all sample data
528                    to a common format, e.g. 48000Hz/STEREO/FLT or the like.
529                    However, I'm tired at the moment so I leave this lock here.
530                 */
531                 SXE_MUTEX_UNLOCK(&sad->mtx);
532                 return 0;
533         }
534
535         sad->lock = 1;
536
537         /* trigger alsa, the device name should be an option */
538         if ((err = sound_alsa_open_device(sad)) < 0) {
539                 ALSA_DEBUG_HW("Opening ALSA device failed: %s.",
540                               snd_strerror(err));
541                 sad->handle = NULL;
542                 /* warning? */
543                 message(GETTEXT("audio-alsa: "
544                                 "Opening ALSA device failed: %s."),
545                         snd_strerror(err));
546                 SXE_MUTEX_UNLOCK(&sad->mtx);
547                 sound_alsa_close_device(sad);
548                 return 0;
549         }
550
551         if ((err = sound_alsa_init_hardware(sad)) < 0) {
552                 ALSA_DEBUG_HW("Device not configurable: %s.\n",
553                               snd_strerror(err));
554                 /* warning? */
555                 message(GETTEXT("audio-alsa: "
556                                 "Cannot access ALSA device: %s."),
557                         snd_strerror(err));
558                 SXE_MUTEX_UNLOCK(&sad->mtx);
559                 sound_alsa_close_device(sad);
560                 return 0;
561         }
562
563         /* init the sasd */
564         sasd->samplerate = sasd->channels = 0;
565         sasd->framesize = 0;
566         sasd->coe_ch_cnt = 0;
567
568         if ((err = sound_alsa_prepare_device(sad, sasd)) < 0) {
569                 SXE_MUTEX_UNLOCK(&sad->mtx);
570                 sound_alsa_close_device(sad);
571                 return 0;
572         }
573
574         /* the volume effect */
575         ADD_MEDIA_SAMPLE_EFFECT(
576                 sasd->coe_chain, sasd->coe_ch_cnt,
577                 MEDIA_SAMPLE_EFFECT(sxe_mse_volume), volargs);
578         volargs->num_channels = sasd->channels;
579
580         /* the rerate effect */
581         ADD_MEDIA_SAMPLE_EFFECT(
582                 sasd->coe_chain, sasd->coe_ch_cnt,
583                 MEDIA_SAMPLE_EFFECT(sxe_mse_rerate), rrargs);
584         rrargs->num_channels = sasd->channels;
585         rrargs->srcrate = rrargs->tgtrate = 1;
586
587         ALSA_DEBUG_COE("have %d coerce functions in my chain.\n",
588                        sasd->coe_ch_cnt);
589
590         /* rewind it ... */
591         media_stream_meth(ms, rewind)(mss);
592
593         XAUDIO_DEVICE_STATE(device) = ASTATE_ALIVE;
594
595         /* ... and play it */
596         SXE_MUTEX_LOCK(&aj->mtx);
597         if (aj->buffer_alloc_size < SOUND_MAX_AUDIO_FRAME_SIZE) {
598                 alloced_myself = 1;
599                 aj->buffer = xmalloc_atomic(SOUND_MAX_AUDIO_FRAME_SIZE);
600                 aj->buffer_alloc_size = SOUND_MAX_AUDIO_FRAME_SIZE;
601         }
602         resolution = (sasd->samplerate * MTPSTATE_REACT_TIME) / 1000000;
603         tmpbuf = (sxe_media_sample_t*)aj->buffer;
604         SXE_MUTEX_UNLOCK(&aj->mtx);
605         SXE_MUTEX_UNLOCK(&sad->mtx);
606
607         while (aj->play_state != MTPSTATE_STOP) {
608
609 #ifdef EF_USE_ASYNEQ
610                 if (audio_job_queue(aj)) {
611                         sound_alsa_handle_aj_events(aj);
612                 }
613 #endif
614
615                 SXE_MUTEX_LOCK(&aj->mtx);
616                 mtp = aj->play_state;
617                 SXE_MUTEX_UNLOCK(&aj->mtx);
618                 switch (mtp) {
619                 case MTPSTATE_RUN:
620                         len = media_stream_meth(ms, read)(
621                                 mss, aj->buffer, resolution);
622                         if (!len) {
623                                 ALSA_DEBUG_S("finished\n");
624                                 SXE_MUTEX_LOCK(&aj->mtx);
625                                 aj->play_state = MTPSTATE_STOP;
626                                 SXE_MUTEX_UNLOCK(&aj->mtx);
627                                 break;
628                         }
629
630                         /* set up the volume args */
631                         volargs->volume[0] = volargs->volume[1] =
632                                 aj->volume;
633                         /* set up the rerate args */
634                         rrargs->tweak = aj->ratetrafo;
635
636                         /* coerce the stuff, tmplen is in samples */
637                         tmplen = sasd->channels*len;
638                         for (i = 0; i < sasd->coe_ch_cnt; i++) {
639                                 ALSA_DEBUG_COE("calling coerce "
640                                                "%d on b:0x%x l:%d\n",
641                                                i, (unsigned int)tmpbuf, tmplen);
642                                 tmplen = CALL_MEDIA_SAMPLE_EFFECT(
643                                         sasd->coe_chain, i,
644                                         tmpbuf, tmpbuf, tmplen);
645                         }
646
647                         /* bring back to S16 or U8 */
648                         MEDIA_SAMPLE_FORMAT_DOWNSAMPLE(sasd->msf)(
649                                 aj->buffer, aj->buffer, tmplen);
650
651                         snd_pcm_writei(sad->handle, aj->buffer, len);
652                         break;
653                 case MTPSTATE_PAUSE:
654                         ALSA_DEBUG("sleeping for %d\n", resolution);
655                         memset(aj->buffer, 0, resolution*sasd->framesize);
656                         snd_pcm_writei(sad->handle, aj->buffer,
657                                        resolution);
658                         break;
659
660                 case MTPSTATE_UNKNOWN:
661                 case MTPSTATE_STOP:
662                 case NUMBER_OF_MEDIA_THREAD_PLAY_STATES:
663                 default:
664                         ALSA_DEBUG("ACK, quit\n");
665                         SXE_MUTEX_LOCK(&aj->mtx);
666                         aj->play_state = MTPSTATE_STOP;
667                         SXE_MUTEX_UNLOCK(&aj->mtx);
668                         break;
669                 }
670         }
671
672 #if 0
673         snd_pcm_drain(ad);
674 #endif
675         SXE_MUTEX_LOCK(&aj->mtx);
676         aj->state = MTSTATE_FINISHED;
677
678         /* -- Close and shutdown -- */
679         if (alloced_myself && aj->buffer) {
680                 xfree(aj->buffer);
681         }
682         aj->buffer = NULL;
683         aj->buffer_alloc_size = 0;
684         SXE_MUTEX_UNLOCK(&aj->mtx);
685
686         sound_alsa_close_device(sad);
687
688         return 1;
689 }
690
691 #undef MYSELF
692
693 /* sound-alsa.c ends here */