Build Fix -- Remove some duplicate symbol defs to appease ld.
[sxemacs] / src / media / sound.c
1 /* New Generation Sound Functions.
2    Copyright (C) 2006 Sebastian Freundt
3
4 This file is part of SXEmacs
5
6 SXEmacs is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
10
11 SXEmacs is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program.  If not, see <http://www.gnu.org/licenses/>. */
18
19
20 /* Inspired by XEmacs' sound.c written by Jamie Zawinski */
21
22 /* Synched up with: Not in FSF. */
23
24 #include <config.h>
25 #include <time.h>
26 #include "lisp.h"
27
28 #include "syssignal.h"
29
30 #include "buffer.h"
31
32 #include "ui/device.h"
33 #include "ui/redisplay.h"
34 #include "sysdep.h"
35
36 #include "sysfile.h"
37 #include "opaque.h"
38 #include "semaphore.h"
39
40 #include "media.h"
41 #include "sound.h"
42
43 Fixnum bell_volume;
44 Fixnum bell_inhibit_time;
45 Lisp_Object Vsound_alist;
46 Lisp_Object Vsynchronous_sounds;
47 Lisp_Object Vnative_sound_only_on_console;
48 Lisp_Object Q_volume, Q_pitch, Q_duration, Q_sound;
49 Lisp_Object Q_server, Q_client, Q_keep_open;
50 Lisp_Object Qplay_sound;
51
52 #ifdef HAVE_AO_SOUND
53 #include "sound-ao.h"
54 #endif
55 #ifdef HAVE_POLYP_SOUND
56 #include "sound-polyp.h"
57 #endif
58 #ifdef HAVE_PULSE_SOUND
59 #include "sound-pulse.h"
60 #endif
61 #ifdef HAVE_ESD_SOUND
62 #include "sound-esd.h"
63 #endif
64 #ifdef HAVE_NAS_SOUND
65 #include "sound-nas.h"
66 #endif
67 #ifdef HAVE_JACK_SOUND
68 #include "sound-jack.h"
69 #endif
70 #ifdef HAVE_ALSA_SOUND
71 #include "sound-alsa.h"
72 #endif
73 #ifdef HAVE_OSS_SOUND
74 #include "sysproc.h"
75 #include "sound-oss.h"
76 #endif
77
78 /* for CHECK_NUMBER and COMPARABLEP */
79 #include "ent/ent.h"
80
81 Lisp_Object Qaudio_devicep;
82 Lisp_Object Qaudio_jobp;
83 Lisp_Object Vdefault_audio_device;
84
85 static audio_job_t make_audio_job(Lisp_Object, Lisp_Object, Lisp_Object);
86 static Lisp_Object make_audio_asyneq_job(audio_job_t);
87 static inline void finish_audio_job_data(audio_job_t);
88 static inline void
89 exec_sentinel(void *job, Lisp_Object, Lisp_Object, Lisp_Object);
90
91 #ifdef EF_USE_ASYNEQ
92 #include "events/worker-asyneq.h"
93
94 /*****************************************************************/
95 /*                      Audio Jobs                               */
96 /*****************************************************************/
97 /* sound-mst handler */
98 \f
99 static void
100 mark_audio_job(worker_job_t job)
101 {
102         audio_job_t aj;
103
104         aj = audio_job(job);
105         if (aj == NULL) {
106                 return;
107         }
108
109         SOUND_DEBUG_AJ("Marking audio job 0x%lx (job 0x%lx)\n",
110                        (long unsigned int)aj,
111                        (long unsigned int)job);
112         SXE_MUTEX_LOCK(&aj->mtx);
113         mark_object(aj->stream);
114         mark_object(aj->device);
115         mark_object(aj->result);
116         mark_object(aj->sentinel);
117         SXE_MUTEX_UNLOCK(&aj->mtx);
118         return;
119 }
120
121 static void
122 print_audio_job(worker_job_t job, Lisp_Object pcf)
123 {
124         audio_job_t aj = audio_job(job);
125         SXE_MUTEX_LOCK(&aj->mtx);
126         write_fmt_string(pcf, " carrying  #<audio-job 0x%lx>", (long unsigned int)aj);
127         SXE_MUTEX_UNLOCK(&aj->mtx);
128         return;
129 }
130
131 static void
132 finish_audio_job(worker_job_t job)
133 {
134         audio_job_t aj;
135
136         lock_worker_job(job);
137         aj = audio_job(job);
138
139         SOUND_DEBUG_AJ("Finishing audio job 0x%lx (job 0x%lx)\n",
140                        (long unsigned int)aj,
141                        (long unsigned int)job);
142         if (aj) {
143                 finish_audio_job_data(aj);
144         }
145         worker_job_data(job) = NULL;
146         unlock_worker_job(job);
147         return;
148 }
149
150 static void
151 audio_job_handle(worker_job_t job)
152 {
153         /* thread-safe */
154         /* usually called from aux threads */
155         audio_job_t aj;
156         Lisp_Object device;
157 #if !defined HAVE_BDWGC || !defined EF_USE_BDWGC
158         Lisp_Object ljob = (Lisp_Object)job;
159 #endif  /* !BDWGC */
160         int(*playfun)(audio_job_t);
161         struct gcpro gcpro1;
162
163         GCPRO1(ljob);
164         lock_worker_job(job);
165         aj = audio_job(job);
166         SXE_MUTEX_LOCK(&aj->mtx);
167         SOUND_DEBUG_AJ("inherit scratch buffer 0x%lx (sz=%ld)\n",
168                        (long unsigned int)worker_job_buffer(job),
169                        (long int)worker_job_buffer_alloc_size(job));
170         aj->buffer = worker_job_buffer(job);
171         aj->buffer_alloc_size = worker_job_buffer_alloc_size(job);
172         device = audio_job_device(job);
173         SOUND_DEBUG_MT("starting thread 0x%lx@0x%lx\n",
174                        (long unsigned int)aj,
175                        (long unsigned int)job);
176         aj->play_state = MTPSTATE_RUN;
177
178         SOUND_DEBUG_AJ("fetching play function\n");
179         playfun = XAUDIO_DEVICE(device)->meths->play;
180         SOUND_DEBUG_AJ("fetched 0x%lx\n", (long unsigned int)playfun);
181
182         SXE_MUTEX_UNLOCK(&aj->mtx);
183         SOUND_DEBUG_AJ("calling play function\n");
184         (void)playfun(aj);
185         SOUND_DEBUG_AJ("play function finished\n");
186         unlock_worker_job(job);
187         UNGCPRO;
188         return;
189 }
190
191 static void
192 audio_job_started(worker_job_t job)
193 {
194         if (NILP(audio_job_sentinel(job) /* sentinel */)) {
195                 return;
196         }
197         /* called from main thread */
198         exec_sentinel(job, audio_job_stream(job), intern("started"),
199                       audio_job_sentinel(job));
200         return;
201 }
202
203 static void
204 audio_job_finished(worker_job_t job)
205 {
206         if (NILP(audio_job_sentinel(job) /* sentinel */)) {
207                 return;
208         }
209         /* called from main thread */
210         exec_sentinel(job, audio_job_stream(job), intern("finished"),
211                       audio_job_sentinel(job));
212         return;
213 }
214
215 static struct work_handler_s audio_job_handler = {
216         mark_audio_job, print_audio_job, finish_audio_job,
217         audio_job_handle, audio_job_started, audio_job_finished
218 };
219
220 static Lisp_Object
221 make_audio_asyneq_job(audio_job_t aj)
222 {
223         /* create a job digestible by the asyneq */
224         Lisp_Object job = Qnil;
225         struct gcpro gcpro1;
226         worker_job_t j;
227
228         GCPRO1(job);
229         j = make_worker_job(&audio_job_handler);
230         job = wrap_object(j);
231         XWORKER_JOB_DATA(job) = aj;
232         /* the scratch buffer thingie */
233         SXE_MUTEX_LOCK(&aj->mtx);
234         aj->buffer = XWORKER_JOB_BUFFER(job);
235         aj->buffer_alloc_size = XWORKER_JOB_BUFFER_ALLOC_SIZE(job);
236         /* generate an event queue for job control */
237         audio_job_queue(aj) = make_noseeum_event_queue();
238         SXE_MUTEX_UNLOCK(&aj->mtx);
239         UNGCPRO;
240         return job;
241 }
242
243 \f
244 DEFUN("set-audio-job-sentinel", Fset_audio_job_sentinel, 2, 2, 0, /*
245 Give JOB the sentinel SENTINEL; `nil' for none.
246 The sentinel is called as a function whenever the stream state changes.
247
248 The function should take three (optional four) arguments
249   (JOB STREAM STATE &optional OLD-STATE)
250 where
251 - JOB is the worker job object currently coping with the stream,
252 - STREAM is bound to the stream object, and
253 - STATE is one of 'unknown, 'started, 'paused, 'stopped, 'finished
254   and indicates the current state of the job
255 - OLD-STATE is again one of the above state symbols but indicates
256   the previous state of the job.
257 */
258       (job, sentinel))
259 {
260         CHECK_AUDIO_JOB(job);
261         XAUDIO_JOB_SENTINEL(job) = sentinel;
262         return sentinel;
263 }
264
265 DEFUN("play-media-stream&", Fplay_media_streamX,
266       1, 4, 0, /*
267 Play the media stream STREAM on an audio device DEVICE.
268
269 Optional second argument DEVICE must be an audio device
270 created by `make-audio-device'.
271 If omitted DEVICE defaults to the value of `default-audio-device'.
272
273 Optional third argument SENTINEL specifies a lisp function to be
274 called whenever the stream state changes.  The function should
275 take three (optional four) arguments
276   (JOB STREAM STATE &optional OLD-STATE)
277 where
278 - JOB is the worker job object currently coping with the stream,
279 - STREAM is bound to the stream object, and
280 - STATE is one of 'unknown, 'started, 'paused, 'stopped and indicates
281   the current state of the job
282 - OLD-STATE is again one of the above state symbols but indicates
283   the previous state of the job.
284
285 See also `set-media-thread-sentinel'.
286
287 Optional fourth argument VOLUME specifies an intial value for
288 the playback volume.
289 */
290       (stream, device, sentinel, volume))
291 {
292         audio_job_t aj;
293         Lisp_Object job = Qnil;
294         int vol;
295         struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
296
297         CHECK_MEDIA_STREAM(stream);
298
299         if (NILP(device))
300                 device = Vdefault_audio_device;
301         else
302                 CHECK_AUDIO_DEVICE(device);
303
304         /* hm, it's useful to stop here if default-audio-device is nil,
305          * i merely spit out a warning and return nil, that should suffice
306          */
307         if (NILP(device)) {
308                 warn_when_safe(
309                         Qdevice, Qnotice,
310                         GETTEXT("play-media-stream: "
311                                 "no device specified, "
312                                 "consider setting `default-audio-device'."));
313                 return Qnil;
314         }
315
316         if (!NILP(volume)) {
317                 CHECK_NUMBER(volume);
318                 volume = Fcoerce_number(volume, Qint, Qnil);
319                 vol = XINT(volume);
320                 if (vol < MEDIA_SAMPLE_VOLUME_MIN)
321                         vol = 0;
322                 else if (vol > MEDIA_SAMPLE_VOLUME_MAX)
323                         vol = MEDIA_SAMPLE_VOLUME_MAX;
324         } else
325                 vol = MEDIA_SAMPLE_VOLUME_NORM;
326
327         GCPRO4(job, device, stream, sentinel);
328         /* create the job data object */
329         aj = make_audio_job(stream, device, sentinel);
330         if (aj == Qnull_pointer) {
331                 UNGCPRO;
332                 return Qnil;
333         }
334         aj->volume = vol;
335         aj->ratetrafo = 1.0;
336         /* now prepare the job to dispatch */
337         job = make_audio_asyneq_job(aj);
338         /* add some props */
339         /* ... and dispatch it */
340         eq_enqueue(delegate_eq, job);
341         /* brag about new jobs in the queue */
342         eq_queue_trigger_all(delegate_eq);
343         UNGCPRO;
344         return job;
345 }
346 #endif  /* EF_USE_ASYNEQ */
347
348 \f
349 /* media thread sentinels */
350 static Lisp_Object
351 exec_sentinel_unwind(Lisp_Object SXE_UNUSED(datum))
352 {
353         return Qnil;
354 }
355
356 static inline void
357 exec_sentinel(void *job, Lisp_Object stream,
358               Lisp_Object state, Lisp_Object sentinel)
359 {
360         /* This function can GC */
361         /* called from main thread */
362         Lisp_Object funcell[4] = {sentinel, (Lisp_Object)job, stream, state};
363         int speccount = specpdl_depth();
364         struct gcpro gcpro1;
365
366         GCPROn(funcell, countof(funcell));
367
368         record_unwind_protect(exec_sentinel_unwind, Qnil);
369         /* call the funcell */
370         Ffuncall(countof(funcell), funcell);
371         /* reset to previous state */
372         restore_match_data();
373         UNGCPRO;
374         unbind_to(speccount, Qnil);
375         return;
376 }
377
378 static inline audio_job_t
379 allocate_audio_job(void)
380 {
381         audio_job_t aj = xnew(struct audio_job_s);
382         SOUND_DEBUG_AJ("allocated: 0x%lx\n", (long unsigned int)aj);
383         return aj;
384 }
385
386 static audio_job_t
387 make_audio_job(Lisp_Object stream, Lisp_Object device, Lisp_Object sentinel)
388 {
389         audio_job_t aj = NULL;
390         media_substream *mss;
391
392         /* traverse the substreams, try to find the first audio stream */
393         for (mss = XMEDIA_STREAM_FIRST(stream);
394              mss && media_substream_type(mss) != MTYPE_AUDIO;
395              mss = media_substream_next(mss));
396
397         if (mss == NULL) {
398                 /* throw error */
399                 return Qnull_pointer;
400         }
401
402         aj = allocate_audio_job();
403         aj->stream = stream;
404         aj->device = device;
405         aj->substream = mss;
406         aj->result = Qnil;
407         aj->sentinel = sentinel;
408
409         aj->state = MTSTATE_UNKNOWN;
410         aj->play_state = MTPSTATE_UNKNOWN;
411         SXE_MUTEX_INIT(&aj->mtx);
412 #ifdef EF_USE_ASYNEQ
413         audio_job_queue(aj) = NULL;
414 #endif
415
416         aj->job_device_data = NULL;
417         aj->job_stream_data = NULL;
418
419         aj->buffer = NULL;
420         aj->buffer_alloc_size = 0;
421
422         SOUND_DEBUG_AJ("created: 0x%lx stream 0x%lx device 0x%lx sentinel 0x%lx\n",
423                        (long unsigned int)aj, (long unsigned int)stream,
424                        (long unsigned int)device, (long unsigned int) sentinel);
425         return aj;
426 }
427
428 static inline void
429 finish_audio_job_data(audio_job_t aj)
430 {
431         SOUND_DEBUG_AJ("finishing: 0x%lx\n", (long unsigned int)aj);
432         SXE_MUTEX_LOCK(&aj->mtx);
433         if (audio_job_device_data(aj)) {
434                 SOUND_DEBUG_AJ("audio-job device data still alive. Bug?\n");
435                 audio_job_device_data(aj) = NULL;
436         }
437         if (audio_job_stream_data(aj)) {
438                 SOUND_DEBUG_AJ("audio-job stream data still alive. Bug?\n");
439                 audio_job_stream_data(aj) = NULL;
440         }
441
442         if (aj->buffer) {
443                 SOUND_CRITICAL("strange, buffer is non-NULL: 0x%lx\n",
444                                (long unsigned int)aj->buffer);
445                 /* xfree(aj->buffer); */
446         }
447         aj->buffer_alloc_size = 0;
448
449 #ifdef EF_USE_ASYNEQ
450         if (audio_job_queue(aj)) {
451                 SOUND_DEBUG_AJ("finishing audio job queue\n");
452                 free_event_queue(audio_job_queue(aj));
453         }
454         audio_job_queue(aj) = (void*)0xB16B00B5;
455 #endif  /* EF_USE_ASYNEQ */
456
457         aj->resolution = 0;
458         aj->framesize = 0;
459         aj->channels = 0;
460         aj->volume = 0;
461         SXE_MUTEX_UNLOCK(&aj->mtx);
462         SXE_MUTEX_FINI(&aj->mtx);
463
464         SOUND_DEBUG_AJ("finished: 0x%lx\n", (long unsigned int)aj);
465         xfree(aj);
466 }
467
468 #if defined __GNUC__
469 static int
470 sound_DO_NOT_play_stream(audio_job_t mst)
471         __attribute__((unused));
472 #endif
473 static int
474 sound_DO_NOT_play_stream(audio_job_t mst)
475 {
476         /* just a dummy function */
477         return 0;
478 }
479
480 DEFUN("play-media-stream-synchronously", Fplay_media_stream_synchronously,
481       1, 4, 0, /*
482 Play the media stream STREAM on an audio device synchronously.
483 This function disregards the value of `synchronous-sounds',
484 instead streams will always be played in synchronous mode.
485
486 Optional second argument DEVICE must be an audio device
487 created by `make-audio-device'.
488 If omitted DEVICE defaults to the value of `default-audio-device'.
489
490 Optional third argument SENTINEL specifies a lisp function to be
491 called after the stream playback finishes.  The function should
492 take one argument (STREAM) where STREAM is bound to the
493 media stream which finished.  See `set-media-thread-sentinel'.
494
495 Optional fourth argument VOLUME specifies an intial value for
496 the playback volume.
497 */
498       (stream, device, sentinel, volume))
499 {
500         audio_job_t aj;
501         int vol;
502
503         CHECK_MEDIA_STREAM(stream);
504
505         if (NILP(device))
506                 device = Vdefault_audio_device;
507         else
508                 CHECK_AUDIO_DEVICE(device);
509
510         /* hm, it's useful to stop here if default-audio-device is nil,
511          * i merely spit out a warning and return nil, that should suffice
512          */
513         if (NILP(device)) {
514                 warn_when_safe(
515                         Qdevice, Qnotice,
516                         GETTEXT("play-media-stream: "
517                                 "no device specified, "
518                                 "consider setting `default-audio-device'."));
519                 return Qnil;
520         }
521
522         if (!NILP(volume)) {
523                 CHECK_NUMBER(volume);
524                 volume = Fcoerce_number(volume, Qint, Qnil);
525                 vol = XINT(volume);
526                 if (vol < MEDIA_SAMPLE_VOLUME_MIN)
527                         vol = 0;
528                 else if (vol > MEDIA_SAMPLE_VOLUME_MAX)
529                         vol = MEDIA_SAMPLE_VOLUME_MAX;
530         } else {
531                 vol = MEDIA_SAMPLE_VOLUME_NORM;
532         }
533
534         aj = make_audio_job(stream, device, Qnil);
535         if (aj == Qnull_pointer) {
536                 SOUND_DEBUG_AJ("audio job is void ... cancelling play\n");
537                 return Qnil;
538         }
539         aj->volume = vol;
540         aj->ratetrafo = 1.0;
541         aj->play_state = MTPSTATE_RUN;
542
543 #if defined EF_USE_ASYNEQ
544         aj->queue = NULL;
545 #endif
546
547         SOUND_DEBUG_AJ("sync calling play meth\n");
548         XAUDIO_DEVICE(device)->meths->play(aj);
549
550         if (!NILP(sentinel)) {
551                 exec_sentinel(
552                         (void*)Qnil, stream, intern("finished"), sentinel);
553         }
554
555         finish_audio_job_data(aj);
556
557         return Qt;
558 }
559
560 \f
561 #ifdef EF_USE_ASYNEQ
562 struct audio_job_event_s pause_event = {aj_change_state, {aj_pause}, 0};
563 struct audio_job_event_s resume_event = {aj_change_state, {aj_resume}, 0};
564 struct audio_job_event_s start_event = {aj_change_state, {aj_start}, 0};
565 struct audio_job_event_s stop_event = {aj_change_state, {aj_stop}, 0};
566 struct audio_job_event_s volnorm_event = {
567         aj_change_volume, {MEDIA_SAMPLE_VOLUME_NORM}, 0};
568 struct audio_job_event_s volmute_event = {
569         aj_change_volume, {MEDIA_SAMPLE_VOLUME_MIN}, 0};
570
571 DEFUN("pause-audio-job", Fpause_audio_job, 1, 1, 0, /*
572 Pause the audio job JOB.
573 Optionally JOB can be 'all in which case all running
574 media threads are paused.
575 */
576       (job))
577 {
578         if (!EQ(job, Qall)) {
579                 CHECK_AUDIO_JOB(job);
580                 /* connect to job's queue and place a PAUSE event there */
581                 if (XAUDIO_JOB_QUEUE(job)) {
582                         eq_noseeum_enqueue(XAUDIO_JOB_QUEUE(job), &pause_event);
583                 }
584         }
585         return Qt;
586 }
587
588 DEFUN("resume-audio-job", Fresume_audio_job, 1, 1, 0, /*
589 Resume a paused audio job JOB.
590 Optionally JOB can be 'all in which case all paused
591 media threads are resumed.
592 */
593       (job))
594 {
595         if (!EQ(job, Qall)) {
596                 CHECK_AUDIO_JOB(job);
597                 /* connect to job's queue and place a RESUME event there */
598                 if (XAUDIO_JOB_QUEUE(job)) {
599                         eq_noseeum_enqueue(XAUDIO_JOB_QUEUE(job),
600                                            &resume_event);
601                 }
602         }
603         return Qt;
604 }
605
606 DEFUN("stop-audio-job", Fstop_audio_job, 1, 1, 0, /*
607 Stop a audio job JOB.
608 Optionally JOB can be 'all in which case all media threads
609 are stopped.
610 */
611       (job))
612 {
613         if (!EQ(job, Qall)) {
614                 CHECK_AUDIO_JOB(job);
615                 /* connect to job's queue and place a STOP event there */
616                 if (XAUDIO_JOB_QUEUE(job)) {
617                         eq_noseeum_enqueue(XAUDIO_JOB_QUEUE(job), &stop_event);
618                 }
619         }
620         return Qt;
621 }
622
623 DEFUN("set-audio-job-volume", Fset_audio_job_volume, 1, 2, 0, /*
624 Set the volume of the audio job JOB to VOLUME.
625
626 JOB is assumed to be a media thread object with an audio substream.
627 Optionally JOB can be 'all in which case the volume change
628 applies to all (currently handled) media threads.
629
630 VOLUME is either a comparable number (see `comparablep') or
631 a vector of comparable numbers.
632 In the former case VOLUME sets the master volume of all channels.
633 In the latter case VOLUME sets the volumes channelwise.
634
635 Any volume value is coerced to an integer.
636 A volume of 128 is the norm.
637 A volume of 0 is muting the respective channels.
638 Volumes greater than 128 cause an amplification of the stream,
639 255 is the maximal volume value.  Note that clipping may occur.
640 */
641       (job, volume))
642 {
643         int vol = 0;
644         Lisp_Object tmpv = Qnil;
645
646         CHECK_AUDIO_JOB(job);
647         if (volume == Qt) {
648                 if (XAUDIO_JOB_QUEUE(job)) {
649                         eq_noseeum_enqueue(
650                                 XAUDIO_JOB_QUEUE(job), &volnorm_event);
651                 }
652                 return make_int(MEDIA_SAMPLE_VOLUME_NORM);
653         } else if (volume == Qnil) {
654                 if (XAUDIO_JOB_QUEUE(job)) {
655                         eq_noseeum_enqueue(
656                                 XAUDIO_JOB_QUEUE(job), &volmute_event);
657                 }
658                 return make_int(MEDIA_SAMPLE_VOLUME_NORM);
659         } else if (COMPARABLEP(volume)) {
660                 volume = Fcoerce_number(volume, Qint, Qnil);
661                 vol = XINT(volume);
662
663                 if (vol < 0)
664                         vol = MEDIA_SAMPLE_VOLUME_MIN;
665                 else if (vol > MEDIA_SAMPLE_VOLUME_MAX)
666                         vol = MEDIA_SAMPLE_VOLUME_MAX;
667         } else if (VECTORP(volume)) {
668                 tmpv = XVECTOR_DATA(volume)[0];
669                 tmpv = Fcoerce_number(tmpv, Qint, Qnil);
670                 vol = XINT(tmpv);
671
672                 if (vol < 0)
673                         vol = MEDIA_SAMPLE_VOLUME_MIN;
674                 else if (vol > MEDIA_SAMPLE_VOLUME_MAX)
675                         vol = MEDIA_SAMPLE_VOLUME_MAX;
676         } else {
677                 return wrong_type_argument(Qnumberp, volume);
678         }
679
680         /* place an VOLCHANGE event in job's queue */
681         if (XAUDIO_JOB_QUEUE(job)) {
682                 audio_job_event_t aje = make_audio_job_event(aj_change_volume);
683                 audio_job_event_args(aje).volume_args = vol;
684                 eq_noseeum_enqueue(XAUDIO_JOB_QUEUE(job), aje);
685         }
686         return volume;
687 }
688
689 DEFUN("audio-job-volume", Faudio_job_volume, 1, 1, 0, /*
690 Return the current volume of audio job JOB.
691 */
692       (job))
693 {
694         CHECK_AUDIO_JOB(job);
695
696         return make_int(XAUDIO_JOB(job)->volume);
697 }
698
699 DEFUN("set-audio-job-rate", Fset_audio_job_rate, 1, 2, 0, /*
700 Set the rate of audio job JOB to RATE.
701
702 If RATE is `t' or `nil', reset the rate to 1.0.
703 */
704       (job, rate))
705 {
706         float ratetrafo;
707
708         CHECK_AUDIO_JOB(job);
709         if (rate == Qt || rate == Qnil) {
710                 ratetrafo = 1.0;
711         } else if (COMPARABLEP(rate)) {
712                 rate = Fcoerce_number(rate, Qfloat, Qnil);
713                 ratetrafo = XFLOAT_DATA(rate);
714
715                 if (ratetrafo <= 0.5)
716                         ratetrafo = 0.5;
717                 else if (ratetrafo > 2.0)
718                         ratetrafo = 2.0;
719         } else {
720                 return wrong_type_argument(Qnumberp, rate);
721         }
722
723         /* place a rate change event in job's queue */
724         if (XAUDIO_JOB_QUEUE(job)) {
725                 audio_job_event_t aje = make_audio_job_event(aj_change_rate);
726                 audio_job_event_args(aje).rate_args = ratetrafo;
727                 eq_noseeum_enqueue(XAUDIO_JOB_QUEUE(job), aje);
728         }
729         return rate;
730 }
731
732 DEFUN("audio-job-rate", Faudio_job_rate, 1, 1, 0, /*
733 Return the current rate of audio job JOB.
734 */
735       (job))
736 {
737         CHECK_AUDIO_JOB(job);
738
739         return make_float(XAUDIO_JOB(job)->ratetrafo);
740 }
741 #endif  /* EF_USE_ASYNEQ */
742
743 \f
744 DEFUN("ding", Fding, 0, 3, 0,   /*
745 Beep, or flash the frame.
746 Also, unless an argument is given,
747 terminate any keyboard macro currently executing.
748 When called from lisp, the second argument is what sound to make, and
749 the third argument is the device to make it in (defaults to the selected
750 device), but may also be an audio device created by `make-audio-device'.
751 */
752       (arg, sound, device))
753 {
754         static time_t last_bell_time;
755         static struct device *last_bell_device;
756         time_t now;
757         struct device *d = decode_device(device);
758         struct gcpro gcpro1, gcpro2, gcpro3;
759
760         GCPRO3(arg, sound, device);
761
762         /* XSETDEVICE(device, d); */
763         now = time(0);
764
765         if (NILP(arg) && !NILP(Vexecuting_macro))
766                 /* Stop executing a keyboard macro. */
767                 error
768                     ("Keyboard macro terminated by a command ringing the bell");
769
770         if (d == last_bell_device && now - last_bell_time < bell_inhibit_time) {
771                 return Qnil;
772         } else if (!NILP(Vvisible_bell) && DEVMETH(d, flash, (d))) {
773                 ;
774         } else if (NILP(sound)) {
775                 DEVMETH(d, ring_bell, (d, bell_volume, -1, -1));
776         } else if (!NILP(Ffboundp(Qplay_sound))) {
777                 call3(Qplay_sound, sound, Qnil, device);
778         }
779
780         last_bell_time = now;
781         last_bell_device = d;
782         RETURN_UNGCPRO(Qnil);
783 }
784
785 \f
786 /* LEGACY */
787 DEFUN("device-sound-enabled-p", Fdevice_sound_enabled_p, 0, 1, 0,       /*
788 Return t if DEVICE is able to play sound.  Defaults to selected device.
789 */
790       (device))
791 {
792         if (DEVICEP(device)) {
793 #ifdef HAVE_NAS_SOUND
794                 if (DEVICE_CONNECTED_TO_NAS_P(decode_device(device)))
795                         return Qt;
796 #endif
797 #ifdef HAVE_OSS_SOUND
798                 if (DEVICE_ON_CONSOLE_P(decode_device(device)))
799                         return Qt;
800 #endif
801         }
802
803         if (NILP(device))
804                 device = Vdefault_audio_device;
805
806         if (!NILP(device) &&
807             AUDIO_DEVICEP(device) &&
808             XAUDIO_DEVICE_STATE(device) != ASTATE_DEAD)
809                 return Qt;
810
811         return Qnil;
812 }
813
814 /* LEGACY */
815 DEFUN("wait-for-sounds", Fwait_for_sounds, 0, 1, 0,     /*
816 Wait for all sounds to finish playing on DEVICE.
817 */
818       (device))
819 {
820         return Qnil;
821 }
822
823 /* LEGACY */
824 DEFUN("connected-to-nas-p", Fconnected_to_nas_p, 0, 1, 0,       /*
825 Return t if connected to NAS server for sounds on DEVICE.
826 */
827       (device))
828 {
829 #ifdef HAVE_NAS_SOUND
830         return DEVICE_CONNECTED_TO_NAS_P(decode_device(device)) ? Qt : Qnil;
831 #else
832         return Qnil;
833 #endif
834 }
835
836 \f
837 /*****************************************************************/
838 /*                      audio device hack                        */
839 /*****************************************************************/
840 /* Indeed the console->device->frame->window structure is not what I'd call
841  * applicable to audio devices. That is why this seamless fake here exists :)
842  * -hroptatyr
843  */
844 static Lisp_Object
845 audio_device_mark(Lisp_Object obj)
846 {
847         if (XAUDIO_DEVICE_METH(obj, mark))
848                 return XAUDIO_DEVICE_METH(obj, mark)(
849                         XAUDIO_DEVICE_DATA(obj));
850
851         return Qnil;
852 }
853
854 static void
855 audio_device_finalise(void *header, int for_disksave)
856 {
857         Lisp_Audio_Device *ad = (Lisp_Audio_Device*)header;
858
859         SOUND_DEBUG_DEV("GCor asked me to finalise: 0x%lx\n",
860                         (long unsigned int)ad);
861
862         if ( ad == NULL )
863                 return;
864
865         if (audio_device_data(ad) &&
866             audio_device_meth(ad, finish))
867                 audio_device_meth(ad, finish)(audio_device_data(ad));
868
869         if (audio_device_data(ad))
870                 xfree(audio_device_data(ad));
871         audio_device_data(ad) = NULL;
872
873         /* avoid some warning */
874         if (for_disksave);
875 }
876
877 static void
878 audio_device_print(Lisp_Object obj, Lisp_Object printcharfun, int escapeflag)
879 {
880         write_c_string("#<audio-device :type ", printcharfun);
881
882
883         switch (XAUDIO_DEVICE_DRIVER(obj)) {
884         case ADRIVER_OSS:
885                 write_c_string("oss", printcharfun);
886                 break;
887
888         case ADRIVER_NAS:
889                 write_c_string("nas", printcharfun);
890                 break;
891
892         case ADRIVER_ESD:
893                 write_c_string("esd", printcharfun);
894                 break;
895
896         case ADRIVER_POLYP:
897                 write_c_string("polyp", printcharfun);
898                 break;
899
900         case ADRIVER_PULSE:
901                 write_c_string("pulse", printcharfun);
902                 break;
903
904         case ADRIVER_AO:
905                 write_c_string("ao", printcharfun);
906                 break;
907
908         case ADRIVER_JACK:
909                 write_c_string("jack", printcharfun);
910                 break;
911
912         case ADRIVER_ALSA:
913                 write_c_string("alsa", printcharfun);
914                 break;
915
916         case NUMBER_OF_AUDIO_DRIVERS:
917         case ADRIVER_UNKNOWN:
918         default:
919                 write_c_string("unknown", printcharfun);
920                 break;
921         }
922
923         if (XAUDIO_DEVICE_METH(obj, print)) {
924                 XAUDIO_DEVICE_METH(obj, print)(obj, printcharfun, escapeflag);
925         }
926
927         /* info about the general state */
928         write_c_string(" :device-state ", printcharfun);
929         switch (XAUDIO_DEVICE_STATE(obj)) {
930         case ASTATE_DEAD:
931         case ASTATE_SUSPENDED:
932                 write_c_string("#dead", printcharfun);
933                 break;
934         case ASTATE_ALIVE:
935                 write_c_string("#ready", printcharfun);
936                 break;
937
938         case NUMBER_OF_AUDIO_STATES:
939         case ASTATE_UNKNOWN:
940         default:
941                 write_c_string("#unknown", printcharfun);
942                 break;
943         }
944
945         write_c_string(">", printcharfun);
946 }
947
948 static int
949 audio_device_equal(Lisp_Object obj1, Lisp_Object obj2, int depth)
950 {
951         return Qnil;
952
953         /* less warnings */
954         if (depth || obj1 || obj2);
955 }
956
957 static unsigned long
958 audio_device_hash (Lisp_Object obj, int SXE_UNUSED(depth))
959 {
960         return (unsigned long)obj;
961         /* audio_device_hashcode(XAUDIO_DEVICE_DATA(obj)); */
962 }
963
964 static const struct lrecord_description audio_device_description[] = {
965         { XD_INT, offsetof(Lisp_Audio_Device, driver) },
966         { XD_INT, offsetof(Lisp_Audio_Device, state) },
967         { XD_OPAQUE_PTR, offsetof(Lisp_Audio_Device, device_data) },
968         { XD_END }
969 };
970
971 DEFINE_LRECORD_IMPLEMENTATION("audio_device", audio_device,
972                               audio_device_mark, audio_device_print,
973                               audio_device_finalise,
974                               audio_device_equal, audio_device_hash,
975                               audio_device_description,
976                               Lisp_Audio_Device);
977
978 static Lisp_Audio_Device *
979 audio_device_allocate(void)
980 {
981         Lisp_Audio_Device *ad;
982
983         ad = alloc_lcrecord_type(Lisp_Audio_Device, &lrecord_audio_device);
984         return ad;
985 }
986
987 audio_driver decode_audio_type(Lisp_Object type)
988 {
989         audio_driver ad = ADRIVER_UNKNOWN;
990
991         if (0);
992 #ifdef HAVE_OSS_SOUND
993         else if (EQ(type, Qoss))
994                 ad = ADRIVER_OSS;
995 #endif
996 #ifdef HAVE_NAS_SOUND
997         else if (EQ(type, Qnas))
998                 ad = ADRIVER_NAS;
999 #endif
1000 #ifdef HAVE_ESD_SOUND
1001         else if (EQ(type, Qesd))
1002                 ad = ADRIVER_ESD;
1003 #endif
1004 #ifdef HAVE_POLYP_SOUND
1005         else if (EQ(type, Qpolyp))
1006                 ad = ADRIVER_POLYP;
1007 #endif
1008 #ifdef HAVE_PULSE_SOUND
1009         else if (EQ(type, Qpulse))
1010                 ad = ADRIVER_PULSE;
1011 #endif
1012 #ifdef HAVE_AO_SOUND
1013         else if (EQ(type, Qao))
1014                 ad = ADRIVER_AO;
1015 #endif
1016 #ifdef HAVE_JACK_SOUND
1017         else if (EQ(type, Qjack))
1018                 ad = ADRIVER_JACK;
1019 #endif
1020 #ifdef HAVE_ALSA_SOUND
1021         else if (EQ(type, Qalsa))
1022                 ad = ADRIVER_ALSA;
1023 #endif
1024
1025         return ad;
1026 }
1027
1028 audio_driver decode_audio_device(Lisp_Object device)
1029 {
1030         struct device *d = NULL;
1031         audio_driver ad = ADRIVER_UNKNOWN;
1032
1033         if (NILP(device) && !NILP(Vdefault_audio_device))
1034                 device = Vdefault_audio_device;
1035
1036         if (AUDIO_DEVICEP(device)) {
1037                 ad = XAUDIO_DEVICE_DRIVER(device);
1038
1039         } else if (DEVICEP(device) || NILP(device)) {
1040                 d = decode_device(device);
1041
1042                 if (0);
1043 #ifdef HAVE_NAS_SOUND
1044                 else if (DEVICE_CONNECTED_TO_NAS_P(d))
1045                         ad = ADRIVER_NAS;
1046 #endif
1047 #ifdef HAVE_AO_SOUND
1048                 else if (DEVICE_CONNECTED_TO_AO_P(d))
1049                         ad = ADRIVER_AO;
1050 #endif
1051 #ifdef HAVE_PULSE_SOUND
1052                 else if (DEVICE_CONNECTED_TO_PULSE_P(d))
1053                         ad = ADRIVER_PULSE;
1054 #endif
1055 #ifdef HAVE_POLYP_SOUND
1056                 else if (DEVICE_CONNECTED_TO_POLYP_P(d))
1057                         ad = ADRIVER_POLYP;
1058 #endif
1059 #ifdef HAVE_ESD_SOUND
1060                 else if (DEVICE_CONNECTED_TO_ESD_P(d))
1061                         ad = ADRIVER_ESD;
1062 #endif
1063 #ifdef HAVE_ALSA_SOUND
1064                 else if (DEVICE_CONNECTED_TO_ALSA_P(d))
1065                         ad = ADRIVER_ALSA;
1066 #endif
1067 #ifdef HAVE_OSS_SOUND
1068                 else if (NILP(Vnative_sound_only_on_console) ||
1069                          DEVICE_ON_CONSOLE_P(d))
1070                         ad = ADRIVER_OSS;
1071 #endif
1072         }
1073
1074         return ad;
1075 }
1076
1077 void *get_audio_device_data(Lisp_Object device)
1078 {
1079         if (AUDIO_DEVICEP(device))
1080                 return XAUDIO_DEVICE_DATA(device);
1081         else
1082                 return NULL;
1083 }
1084
1085 Lisp_Audio_Device *get_audio_device(Lisp_Object device)
1086 {
1087         if (AUDIO_DEVICEP(device))
1088                 return XAUDIO_DEVICE(device);
1089         else
1090                 return NULL;
1091 }
1092
1093 \f
1094 static Lisp_Object
1095 make_audio_device(Lisp_Object type)
1096 {
1097         Lisp_Audio_Device *ad;
1098         Lisp_Object lad;
1099
1100         CHECK_SYMBOL(type);
1101
1102         ad = audio_device_allocate();
1103         audio_device_driver(ad) = decode_audio_type(type);
1104         audio_device_data(ad) = NULL;
1105         XSETAUDIO_DEVICE(lad, ad);
1106         XAUDIO_DEVICE_STATE(lad) = ASTATE_UNKNOWN;
1107
1108         return lad;
1109 }
1110
1111 DEFUN("make-audio-device", Fmake_audio_device, 1, MANY, 0,      /*
1112 DRIVER &rest DEVICE-OPTIONS
1113
1114 Create a new device to output audio via DRIVER.
1115 DRIVER should be a symbol out of 'oss, 'nas, 'esd, 'pulse,
1116 'jack, 'alsa, or 'ao.
1117
1118 The rest arguments may be used to pass options to the selected
1119 output driver. These should be `:keyword value' pairs.
1120
1121 Valid keywords for ALSA are:
1122 :device - the name of the hardware interface (default: "default"),
1123   you may want to try "plughw:0,0" first
1124 :keep-open - whether to exclusively reserve the device.
1125   Note this may prevent other applications from using the device.
1126
1127 Valid keywords for (deprecated) OSS are:
1128 :device - the name of the hardware interface (default: "/dev/dsp")
1129 :keep-open - whether to exclusively reserve the device.
1130   Note this may prevent other applications from using the device.
1131
1132 Valid keywords for ESD are:
1133 :server - to use a distant ESD daemon (e.g. "my.machine.box:16001")
1134 The default for ESD output is to use a locally running daemon and
1135 to connect to it via unix domain sockets.
1136
1137 Valid keywords for Pulse are:
1138 :server - the host name to connect to (default: "localhost")
1139 :sink - the name of the sink to connect to (e.g. "output")
1140 :source - the name of the source to record from (e.g. "mic_in")
1141 :client - how to call the client on the server (default "SXEmacs")
1142 :role - a one-word description of the "type" of media to be played
1143   on the server. It can be one of:
1144           "video" - for movie/video streams
1145           "music" - for music streams (like mp3's, oga's etc)
1146            "game" - for audio from games
1147           "event" - for event sounds (this is the default)
1148           "phone" - for VoIP and Instant Messaging audio
1149       "animation" - for animations
1150      "production" - for audio production applications
1151            "a11y" - for accessibility applications
1152 :stream - how to call the stream on the server (e.g. "fancy-sound")
1153 :immediate - connect to sink immediately and keep the connection
1154   alive as long as the audio device exists (default `t')
1155 :threaded - initiate a threaded mainloop (default `t')
1156 :force - if non-nil the device object is created even though the
1157   pulse mainloop could not be started; if `nil' any mainloop failure
1158   results in an error.  This can be useful if you want to have an
1159   audio device object although the server is not (yet) up or not
1160   (yet) accepting connections from you. (default `nil')
1161
1162 Valid keywords for Jack are:
1163 :server - the jack server to connect to (default "default")
1164 :client - how to call the client on the server (default "SXEmacs")
1165
1166 Valid keywords for AO are:
1167 :driver - the name of the output driver (e.g. "alsa", "esd", etc.)
1168 :options - a list of AO suboptions (see AO documentation)
1169 The default for AO output is to pass nothing and entirely use the
1170 system and user configuration files.
1171
1172 Valid keywords for NAS are:
1173 :server - the NAS server to connect to.  This can be either:
1174   - an X display string like "localhost:0.0", the X display string
1175     the current frame is on can be obtained by the function
1176     `device-connection'
1177   - or a SXEmacs device name like "localhost-11-0" which can be
1178     obtained by `device-name'
1179   - or a SXEmacs device object, obtainable by `frame-device', like
1180     #<x-device on "localhost:11.0" 0xee4>
1181 If the :server keyword is omitted SXEmacs tries to determine a
1182 sensible default in this order:
1183   - use the frame device of the current frame
1184   - use the frame device of the initial frame
1185   - use the display specified in $AUDIOSERVER
1186   - use the display specified in $DISPLAY
1187   - try "localhost:0.0"
1188
1189 */
1190       (int nargs, Lisp_Object *args))
1191 {
1192         Lisp_Object ad, driver, device_options = Qnil;
1193         audio_driver dev_driver;
1194         ad_device_data *device_data = NULL;
1195
1196         driver = args[0];
1197
1198         CHECK_SYMBOL(driver);
1199         ad = make_audio_device(driver);
1200
1201         dev_driver = XAUDIO_DEVICE_DRIVER(ad);
1202
1203         switch (dev_driver) {
1204         case ADRIVER_NAS:
1205 #ifdef HAVE_NAS_SOUND
1206                 XAUDIO_DEVICE_METHS(ad) = sound_nas;
1207                 break;
1208 #endif
1209         case ADRIVER_ALSA:
1210 #ifdef HAVE_ALSA_SOUND
1211                 XAUDIO_DEVICE_METHS(ad) = sound_alsa;
1212                 break;
1213 #endif
1214         case ADRIVER_OSS:
1215 #ifdef HAVE_OSS_SOUND
1216                 XAUDIO_DEVICE_METHS(ad) = sound_oss;
1217                 break;
1218 #endif
1219         case ADRIVER_AO:
1220 #ifdef HAVE_AO_SOUND
1221                 XAUDIO_DEVICE_METHS(ad) = sound_ao;
1222                 break;
1223 #endif
1224         case ADRIVER_POLYP:
1225         case ADRIVER_PULSE:
1226 #ifdef HAVE_PULSE_SOUND
1227                 XAUDIO_DEVICE_METHS(ad) = sound_pulse;
1228                 break;
1229 #endif
1230         case ADRIVER_ESD:
1231 #ifdef HAVE_ESD_SOUND
1232                 XAUDIO_DEVICE_METHS(ad) = sound_esd;
1233                 break;
1234 #endif
1235         case ADRIVER_JACK:
1236 #ifdef HAVE_JACK_SOUND
1237                 XAUDIO_DEVICE_METHS(ad) = sound_jack;
1238                 break;
1239 #endif
1240         case ADRIVER_UNKNOWN:
1241         case NUMBER_OF_AUDIO_DRIVERS:
1242         default:
1243                 return Qnil;
1244                 break;
1245         }
1246
1247         {
1248                 Lisp_Object tmp = Flist(nargs, args);
1249                 device_options = XCDR(tmp);
1250         }
1251
1252         if (XAUDIO_DEVICE_METH(ad, create) &&
1253             !(device_data = XAUDIO_DEVICE_METH(ad, create)(device_options))) {
1254                 XAUDIO_DEVICE_STATE(ad) = ASTATE_DEAD;
1255         }
1256         XAUDIO_DEVICE_DATA(ad) = device_data;
1257         return ad;
1258 }
1259
1260 DEFUN("audio-device-p", Faudio_device_p, 1, 1, 0, /*
1261 Return non-nil if OBJECT is an audio-device.
1262 */
1263       (object))
1264 {
1265         if (AUDIO_DEVICEP(object))
1266                 return Qt;
1267         else
1268                 return Qnil;
1269 }
1270
1271 #if 0
1272 DEFUN("delete-audio-device", Fdelete_audio_device, 1, 1, 0, /*
1273 Deinitialise the audio device DEVICE and free its resources.
1274 */
1275       (device))
1276 {
1277         CHECK_AUDIO_DEVICE(device);
1278
1279         audio_device_finalise(XAUDIO_DEVICE(device), 0);
1280         return device;
1281 }
1282 #endif
1283
1284 \f
1285 void syms_of_sound(void)
1286 {
1287         INIT_LRECORD_IMPLEMENTATION(audio_device);
1288
1289         defkeyword(&Q_volume, ":volume");
1290         defkeyword(&Q_pitch, ":pitch");
1291         defkeyword(&Q_duration, ":duration");
1292         defkeyword(&Q_sound, ":sound");
1293
1294         /* located in sound.el */
1295         defsymbol(&Qplay_sound, "play-sound");
1296
1297 #ifdef HAVE_NAS_SOUND
1298         defsymbol(&Qnas, "nas");
1299 #endif
1300 #ifdef HAVE_ESD_SOUND
1301         defsymbol(&Qesd, "esd");
1302 #endif
1303 #ifdef HAVE_POLYP_SOUND
1304         defsymbol(&Qpolyp, "polyp");
1305 #endif
1306 #ifdef HAVE_PULSE_SOUND
1307         defsymbol(&Qpulse, "pulse");
1308 #endif
1309 #ifdef HAVE_AO_SOUND
1310         defsymbol(&Qao, "ao");
1311 #endif
1312 #ifdef HAVE_ALSA_SOUND
1313         defsymbol(&Qalsa, "alsa");
1314 #endif
1315 #ifdef HAVE_JACK_SOUND
1316         defsymbol(&Qjack, "jack");
1317 #endif
1318 #ifdef HAVE_OSS_SOUND
1319         defsymbol(&Qoss, "oss");
1320 #endif
1321         defsymbol(&Qaudio_devicep, "audio-device-p");
1322         defsymbol(&Qaudio_jobp, "audio-job-p");
1323
1324         /* some more symbols */
1325         defsymbol(&Q_device, ":device");
1326         defsymbol(&Q_keep_open, ":keep-open");
1327         defsymbol(&Q_server, ":server");
1328         defsymbol(&Q_client, ":client");
1329
1330         DEFSUBR(Fplay_media_stream_synchronously);
1331 #ifdef EF_USE_ASYNEQ
1332         DEFSUBR(Fplay_media_streamX);
1333         DEFSUBR(Fset_audio_job_sentinel);
1334         DEFSUBR(Fpause_audio_job);
1335         DEFSUBR(Fresume_audio_job);
1336         DEFSUBR(Fstop_audio_job);
1337         DEFSUBR(Fset_audio_job_volume);
1338         DEFSUBR(Faudio_job_volume);
1339         DEFSUBR(Fset_audio_job_rate);
1340         DEFSUBR(Faudio_job_rate);
1341 #endif
1342
1343         DEFSUBR(Fding);
1344         DEFSUBR(Fwait_for_sounds);
1345         DEFSUBR(Fconnected_to_nas_p);
1346         DEFSUBR(Fdevice_sound_enabled_p);
1347
1348         /* audio device fake */
1349         DEFSUBR(Fmake_audio_device);
1350         DEFSUBR(Faudio_device_p);
1351 #if 0
1352         DEFSUBR(Fdelete_audio_device); /* too dangerous atm */
1353 #endif
1354 }
1355
1356 void vars_of_sound(void)
1357 {
1358 #ifdef HAVE_OSS_SOUND
1359 #  if 0
1360         Fprovide(intern("native-sound")); /* for compatibility */
1361         /* transition time is over! */
1362 #  endif
1363         Fprovide(intern("oss-sound"));
1364 #endif
1365 #ifdef HAVE_NAS_SOUND
1366         Fprovide(intern("nas-sound"));
1367 #endif
1368 #ifdef HAVE_ESD_SOUND
1369         Fprovide(intern("esd-sound"));
1370 #endif
1371 #ifdef HAVE_POLYP_SOUND
1372         Fprovide(intern("polyp-sound"));
1373 #endif
1374 #ifdef HAVE_PULSE_SOUND
1375         Fprovide(intern("pulse-sound"));
1376 #endif
1377 #ifdef HAVE_AO_SOUND
1378         Fprovide(intern("ao-sound"));
1379 #endif
1380 #ifdef HAVE_ALSA_SOUND
1381         Fprovide(intern("alsa-sound"));
1382 #endif
1383         Fprovide(intern("audio"));
1384
1385         DEFVAR_INT("bell-volume", &bell_volume  /*
1386 *How loud to be, from 0 to 255, where 127 is the norm (100%).
1387 Values above raise the volume and values below lower it.
1388                                                  */ );
1389         bell_volume = 63;
1390
1391         DEFVAR_INT("bell-inhibit-time", &bell_inhibit_time      /*
1392 *Don't ring the bell on the same device more than once within this many seconds.
1393                                                                  */ );
1394         bell_inhibit_time = 0;
1395
1396         DEFVAR_LISP("sound-alist", &Vsound_alist        /*
1397 An alist associating names with sounds.
1398 When `beep' or `ding' is called with one of the name symbols, the associated
1399 sound will be generated instead of the standard beep.
1400
1401 Each element of `sound-alist' is a list describing a sound.
1402 The first element of the list is the name of the sound being defined.
1403 Subsequent elements of the list are alternating keyword/value pairs:
1404
1405 Keyword: Value:
1406 -------  -----
1407 sound    A string of raw sound data (deprecated), or the name of another
1408          sound to play.   The symbol `t' here means use the default X beep.
1409 volume   An integer from 0-100, defaulting to `bell-volume'
1410 pitch    If using the default X beep, the pitch (Hz) to generate.
1411 duration If using the default X beep, the duration (milliseconds).
1412 stream   A media stream object containing the sound.
1413
1414 You should probably add things to this list by calling the function
1415 load-sound-file.
1416
1417 Note: SXEmacs must be built with sound support for your system.  Not all
1418 systems support sound.
1419 Note: The pitch, duration, and volume options are available everywhere,
1420 but many X servers ignore the `pitch' option.
1421
1422 The following beep-types are used by SXEmacs itself:
1423
1424 auto-save-error  when an auto-save does not succeed
1425 command-error    when the emacs command loop catches an error
1426 undefined-key    when you type a key that is undefined
1427 undefined-click  when you use an undefined mouse-click combination
1428 no-completion    during completing-read
1429 y-or-n-p         when you type something other than 'y' or 'n'
1430 yes-or-no-p      when you type something other than 'yes' or 'no'
1431 default          used when nothing else is appropriate.
1432
1433 Other lisp packages may use other beep types, but these are the ones that
1434 the C kernel of Emacs uses.
1435                                                          */ );
1436         Vsound_alist = Qnil;
1437
1438         DEFVAR_LISP("synchronous-sounds", &Vsynchronous_sounds  /*
1439 Play sounds synchronously, if non-nil.
1440 Only applies if SXEmacs has been compiled with a threading library.
1441 Otherwise, sounds are always played synchronously.
1442                                                                  */ );
1443         Vsynchronous_sounds = Qt;
1444
1445         DEFVAR_LISP("native-sound-only-on-console", &Vnative_sound_only_on_console      /*
1446 Non-nil value means play sounds only if SXEmacs is running
1447 on the system console.
1448 Nil means always play sounds, even if running on a non-console tty
1449 or a secondary X display.
1450
1451 This variable only applies to native sound support.
1452                                                                                          */ );
1453         Vnative_sound_only_on_console = Qt;
1454
1455         DEFVAR_LISP("default-audio-device", &Vdefault_audio_device      /*
1456 Default audio device to use.
1457                                                                          */ );
1458         Vdefault_audio_device = Qnil;
1459 }
1460
1461 /* sound.c ends here */