1 /* New Generation Sound Functions.
2 Copyright (C) 2006 Sebastian Freundt
4 This file is part of SXEmacs
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.
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.
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/>. */
20 /* Inspired by XEmacs' sound.c written by Jamie Zawinski */
22 /* Synched up with: Not in FSF. */
28 #include "syssignal.h"
32 #include "ui/device.h"
33 #include "ui/redisplay.h"
38 #include "semaphore.h"
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_device, Q_server, Q_client, Q_keep_open;
50 Lisp_Object Qplay_sound;
55 #ifdef HAVE_ARTS_SOUND
56 #include "sound-arts.h"
58 #ifdef HAVE_POLYP_SOUND
59 #include "sound-polyp.h"
61 #ifdef HAVE_PULSE_SOUND
62 #include "sound-pulse.h"
65 #include "sound-esd.h"
68 #include "sound-nas.h"
70 #ifdef HAVE_JACK_SOUND
71 #include "sound-jack.h"
73 #ifdef HAVE_ALSA_SOUND
74 #include "sound-alsa.h"
78 #include "sound-oss.h"
81 Lisp_Object Qaudio_devicep;
82 Lisp_Object Qaudio_jobp;
83 Lisp_Object Vdefault_audio_device;
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);
89 exec_sentinel(void *job, Lisp_Object, Lisp_Object, Lisp_Object);
92 #include "events/worker-asyneq.h"
94 /*****************************************************************/
96 /*****************************************************************/
97 /* sound-mst handler */
100 mark_audio_job(worker_job_t job)
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);
122 print_audio_job(worker_job_t job, Lisp_Object pcf)
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);
132 finish_audio_job(worker_job_t job)
136 lock_worker_job(job);
139 SOUND_DEBUG_AJ("Finishing audio job 0x%lx (job 0x%lx)\n",
140 (long unsigned int)aj,
141 (long unsigned int)job);
143 finish_audio_job_data(aj);
145 worker_job_data(job) = NULL;
146 unlock_worker_job(job);
151 audio_job_handle(worker_job_t job)
154 /* usually called from aux threads */
157 #if !defined HAVE_BDWGC || !defined EF_USE_BDWGC
158 Lisp_Object ljob = (Lisp_Object)job;
160 int(*playfun)(audio_job_t);
164 lock_worker_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;
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);
182 SXE_MUTEX_UNLOCK(&aj->mtx);
183 SOUND_DEBUG_AJ("calling play function\n");
185 SOUND_DEBUG_AJ("play function finished\n");
186 unlock_worker_job(job);
192 audio_job_started(worker_job_t job)
194 if (NILP(audio_job_sentinel(job) /* sentinel */)) {
197 /* called from main thread */
198 exec_sentinel(job, audio_job_stream(job), intern("started"),
199 audio_job_sentinel(job));
204 audio_job_finished(worker_job_t job)
206 if (NILP(audio_job_sentinel(job) /* sentinel */)) {
209 /* called from main thread */
210 exec_sentinel(job, audio_job_stream(job), intern("finished"),
211 audio_job_sentinel(job));
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
221 make_audio_asyneq_job(audio_job_t aj)
223 /* create a job digestible by the asyneq */
224 Lisp_Object job = Qnil;
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);
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.
248 The function should take three (optional four) arguments
249 (JOB STREAM STATE &optional OLD-STATE)
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.
260 CHECK_AUDIO_JOB(job);
261 XAUDIO_JOB_SENTINEL(job) = sentinel;
265 DEFUN("play-media-stream&", Fplay_media_streamX,
267 Play the media stream STREAM on an audio device DEVICE.
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'.
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)
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.
285 See also `set-media-thread-sentinel'.
287 Optional fourth argument VOLUME specifies an intial value for
290 (stream, device, sentinel, volume))
293 Lisp_Object job = Qnil;
295 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
297 CHECK_MEDIA_STREAM(stream);
300 device = Vdefault_audio_device;
302 CHECK_AUDIO_DEVICE(device);
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
310 GETTEXT("play-media-stream: "
311 "no device specified, "
312 "consider setting `default-audio-device'."));
317 CHECK_NUMBER(volume);
318 volume = Fcoerce_number(volume, Qint, Qnil);
320 if (vol < MEDIA_SAMPLE_VOLUME_MIN)
322 else if (vol > MEDIA_SAMPLE_VOLUME_MAX)
323 vol = MEDIA_SAMPLE_VOLUME_MAX;
325 vol = MEDIA_SAMPLE_VOLUME_NORM;
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) {
336 /* now prepare the job to dispatch */
337 job = make_audio_asyneq_job(aj);
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);
346 #endif /* EF_USE_ASYNEQ */
349 /* media thread sentinels */
351 exec_sentinel_unwind(Lisp_Object SXE_UNUSED(datum))
357 exec_sentinel(void *job, Lisp_Object stream,
358 Lisp_Object state, Lisp_Object sentinel)
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();
366 GCPROn(funcell, countof(funcell));
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();
374 unbind_to(speccount, Qnil);
378 static inline audio_job_t
379 allocate_audio_job(void)
381 audio_job_t aj = xnew(struct audio_job_s);
382 SOUND_DEBUG_AJ("allocated: 0x%lx\n", (long unsigned int)aj);
387 make_audio_job(Lisp_Object stream, Lisp_Object device, Lisp_Object sentinel)
389 audio_job_t aj = NULL;
390 media_substream *mss;
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));
399 return Qnull_pointer;
402 aj = allocate_audio_job();
407 aj->sentinel = sentinel;
409 aj->state = MTSTATE_UNKNOWN;
410 aj->play_state = MTPSTATE_UNKNOWN;
412 SXE_MUTEX_INIT(&aj->mtx);
413 audio_job_queue(aj) = NULL;
416 aj->job_device_data = NULL;
417 aj->job_stream_data = NULL;
420 aj->buffer_alloc_size = 0;
422 SOUND_DEBUG_AJ("created: 0x%lx\n", (long unsigned int)aj);
427 finish_audio_job_data(audio_job_t aj)
429 SOUND_DEBUG_AJ("finishing: 0x%lx\n", (long unsigned int)aj);
430 SXE_MUTEX_LOCK(&aj->mtx);
431 if (audio_job_device_data(aj)) {
432 SOUND_DEBUG_AJ("audio-job device data still alive. Bug?\n");
433 audio_job_device_data(aj) = NULL;
435 if (audio_job_stream_data(aj)) {
436 SOUND_DEBUG_AJ("audio-job stream data still alive. Bug?\n");
437 audio_job_stream_data(aj) = NULL;
441 SOUND_CRITICAL("strange, buffer is non-NULL: 0x%lx\n",
442 (long unsigned int)aj->buffer);
443 /* xfree(aj->buffer); */
445 aj->buffer_alloc_size = 0;
448 if (audio_job_queue(aj)) {
449 SOUND_DEBUG_AJ("finishing audio job queue\n");
450 free_event_queue(audio_job_queue(aj));
452 audio_job_queue(aj) = (void*)0xB16B00B5;
453 #endif /* EF_USE_ASYNEQ */
459 SXE_MUTEX_UNLOCK(&aj->mtx);
460 SXE_MUTEX_FINI(&aj->mtx);
462 SOUND_DEBUG_AJ("finished: 0x%lx\n", (long unsigned int)aj);
468 sound_DO_NOT_play_stream(audio_job_t mst)
469 __attribute__((unused));
472 sound_DO_NOT_play_stream(audio_job_t mst)
474 /* just a dummy function */
478 DEFUN("play-media-stream-synchronously", Fplay_media_stream_synchronously,
480 Play the media stream STREAM on an audio device synchronously.
481 This function disregards the value of `synchronous-sounds',
482 instead streams will always be played in synchronous mode.
484 Optional second argument DEVICE must be an audio device
485 created by `make-audio-device'.
486 If omitted DEVICE defaults to the value of `default-audio-device'.
488 Optional third argument SENTINEL specifies a lisp function to be
489 called after the stream playback finishes. The function should
490 take one argument (STREAM) where STREAM is bound to the
491 media stream which finished. See `set-media-thread-sentinel'.
493 Optional fourth argument VOLUME specifies an intial value for
496 (stream, device, sentinel, volume))
501 CHECK_MEDIA_STREAM(stream);
504 device = Vdefault_audio_device;
506 CHECK_AUDIO_DEVICE(device);
508 /* hm, it's useful to stop here if default-audio-device is nil,
509 * i merely spit out a warning and return nil, that should suffice
514 GETTEXT("play-media-stream: "
515 "no device specified, "
516 "consider setting `default-audio-device'."));
521 CHECK_NUMBER(volume);
522 volume = Fcoerce_number(volume, Qint, Qnil);
524 if (vol < MEDIA_SAMPLE_VOLUME_MIN)
526 else if (vol > MEDIA_SAMPLE_VOLUME_MAX)
527 vol = MEDIA_SAMPLE_VOLUME_MAX;
529 vol = MEDIA_SAMPLE_VOLUME_NORM;
532 aj = make_audio_job(stream, device, Qnil);
533 if (aj == Qnull_pointer) {
534 SOUND_DEBUG_AJ("audio job is void ... cancelling play\n");
539 aj->play_state = MTPSTATE_RUN;
541 #if defined EF_USE_ASYNEQ
545 SOUND_DEBUG_AJ("calling play meth\n");
546 XAUDIO_DEVICE(device)->meths->play(aj);
548 if (!NILP(sentinel)) {
550 (void*)Qnil, stream, intern("finished"), sentinel);
553 finish_audio_job_data(aj);
560 struct audio_job_event_s pause_event = {aj_change_state, {aj_pause}, 0};
561 struct audio_job_event_s resume_event = {aj_change_state, {aj_resume}, 0};
562 struct audio_job_event_s start_event = {aj_change_state, {aj_start}, 0};
563 struct audio_job_event_s stop_event = {aj_change_state, {aj_stop}, 0};
564 struct audio_job_event_s volnorm_event = {
565 aj_change_volume, {MEDIA_SAMPLE_VOLUME_NORM}, 0};
566 struct audio_job_event_s volmute_event = {
567 aj_change_volume, {MEDIA_SAMPLE_VOLUME_MIN}, 0};
569 DEFUN("pause-audio-job", Fpause_audio_job, 1, 1, 0, /*
570 Pause the audio job JOB.
571 Optionally JOB can be 'all in which case all running
572 media threads are paused.
576 if (!EQ(job, Qall)) {
577 CHECK_AUDIO_JOB(job);
578 /* connect to job's queue and place a PAUSE event there */
579 if (XAUDIO_JOB_QUEUE(job)) {
580 eq_noseeum_enqueue(XAUDIO_JOB_QUEUE(job), &pause_event);
586 DEFUN("resume-audio-job", Fresume_audio_job, 1, 1, 0, /*
587 Resume a paused audio job JOB.
588 Optionally JOB can be 'all in which case all paused
589 media threads are resumed.
593 if (!EQ(job, Qall)) {
594 CHECK_AUDIO_JOB(job);
595 /* connect to job's queue and place a RESUME event there */
596 if (XAUDIO_JOB_QUEUE(job)) {
597 eq_noseeum_enqueue(XAUDIO_JOB_QUEUE(job),
604 DEFUN("stop-audio-job", Fstop_audio_job, 1, 1, 0, /*
605 Stop a audio job JOB.
606 Optionally JOB can be 'all in which case all media threads
611 if (!EQ(job, Qall)) {
612 CHECK_AUDIO_JOB(job);
613 /* connect to job's queue and place a STOP event there */
614 if (XAUDIO_JOB_QUEUE(job)) {
615 eq_noseeum_enqueue(XAUDIO_JOB_QUEUE(job), &stop_event);
621 DEFUN("set-audio-job-volume", Fset_audio_job_volume, 1, 2, 0, /*
622 Set the volume of the audio job JOB to VOLUME.
624 JOB is assumed to be a media thread object with an audio substream.
625 Optionally JOB can be 'all in which case the volume change
626 applies to all (currently handled) media threads.
628 VOLUME is either a comparable number (see `comparablep') or
629 a vector of comparable numbers.
630 In the former case VOLUME sets the master volume of all channels.
631 In the latter case VOLUME sets the volumes channelwise.
633 Any volume value is coerced to an integer.
634 A volume of 128 is the norm.
635 A volume of 0 is muting the respective channels.
636 Volumes greater than 128 cause an amplification of the stream,
637 255 is the maximal volume value. Note that clipping may occur.
642 Lisp_Object tmpv = Qnil;
644 CHECK_AUDIO_JOB(job);
646 if (XAUDIO_JOB_QUEUE(job)) {
648 XAUDIO_JOB_QUEUE(job), &volnorm_event);
650 return make_int(MEDIA_SAMPLE_VOLUME_NORM);
651 } else if (volume == Qnil) {
652 if (XAUDIO_JOB_QUEUE(job)) {
654 XAUDIO_JOB_QUEUE(job), &volmute_event);
656 return make_int(MEDIA_SAMPLE_VOLUME_NORM);
657 } else if (COMPARABLEP(volume)) {
658 volume = Fcoerce_number(volume, Qint, Qnil);
662 vol = MEDIA_SAMPLE_VOLUME_MIN;
663 else if (vol > MEDIA_SAMPLE_VOLUME_MAX)
664 vol = MEDIA_SAMPLE_VOLUME_MAX;
665 } else if (VECTORP(volume)) {
666 tmpv = XVECTOR_DATA(volume)[0];
667 tmpv = Fcoerce_number(tmpv, Qint, Qnil);
671 vol = MEDIA_SAMPLE_VOLUME_MIN;
672 else if (vol > MEDIA_SAMPLE_VOLUME_MAX)
673 vol = MEDIA_SAMPLE_VOLUME_MAX;
675 return wrong_type_argument(Qnumberp, volume);
678 /* place an VOLCHANGE event in job's queue */
679 if (XAUDIO_JOB_QUEUE(job)) {
680 audio_job_event_t aje = make_audio_job_event(aj_change_volume);
681 audio_job_event_args(aje).volume_args = vol;
682 eq_noseeum_enqueue(XAUDIO_JOB_QUEUE(job), aje);
687 DEFUN("audio-job-volume", Faudio_job_volume, 1, 1, 0, /*
688 Return the current volume of audio job JOB.
692 CHECK_AUDIO_JOB(job);
694 return make_int(XAUDIO_JOB(job)->volume);
697 DEFUN("set-audio-job-rate", Fset_audio_job_rate, 1, 2, 0, /*
698 Set the rate of audio job JOB to RATE.
700 If RATE is `t' or `nil', reset the rate to 1.0.
706 CHECK_AUDIO_JOB(job);
707 if (rate == Qt || rate == Qnil) {
709 } else if (COMPARABLEP(rate)) {
710 rate = Fcoerce_number(rate, Qfloat, Qnil);
711 ratetrafo = XFLOAT_DATA(rate);
713 if (ratetrafo <= 0.5)
715 else if (ratetrafo > 2.0)
718 return wrong_type_argument(Qnumberp, rate);
721 /* place a rate change event in job's queue */
722 if (XAUDIO_JOB_QUEUE(job)) {
723 audio_job_event_t aje = make_audio_job_event(aj_change_rate);
724 audio_job_event_args(aje).rate_args = ratetrafo;
725 eq_noseeum_enqueue(XAUDIO_JOB_QUEUE(job), aje);
730 DEFUN("audio-job-rate", Faudio_job_rate, 1, 1, 0, /*
731 Return the current rate of audio job JOB.
735 CHECK_AUDIO_JOB(job);
737 return make_float(XAUDIO_JOB(job)->ratetrafo);
739 #endif /* EF_USE_ASYNEQ */
742 DEFUN("ding", Fding, 0, 3, 0, /*
743 Beep, or flash the frame.
744 Also, unless an argument is given,
745 terminate any keyboard macro currently executing.
746 When called from lisp, the second argument is what sound to make, and
747 the third argument is the device to make it in (defaults to the selected
748 device), but may also be an audio device created by `make-audio-device'.
750 (arg, sound, device))
752 static time_t last_bell_time;
753 static struct device *last_bell_device;
755 struct device *d = decode_device(device);
756 struct gcpro gcpro1, gcpro2, gcpro3;
758 GCPRO3(arg, sound, device);
760 /* XSETDEVICE(device, d); */
763 if (NILP(arg) && !NILP(Vexecuting_macro))
764 /* Stop executing a keyboard macro. */
766 ("Keyboard macro terminated by a command ringing the bell");
768 if (d == last_bell_device && now - last_bell_time < bell_inhibit_time) {
770 } else if (!NILP(Vvisible_bell) && DEVMETH(d, flash, (d))) {
772 } else if (NILP(sound)) {
773 DEVMETH(d, ring_bell, (d, bell_volume, -1, -1));
774 } else if (!NILP(Ffboundp(Qplay_sound))) {
775 call3(Qplay_sound, sound, Qnil, device);
778 last_bell_time = now;
779 last_bell_device = d;
780 RETURN_UNGCPRO(Qnil);
785 DEFUN("device-sound-enabled-p", Fdevice_sound_enabled_p, 0, 1, 0, /*
786 Return t if DEVICE is able to play sound. Defaults to selected device.
790 if (DEVICEP(device)) {
791 #ifdef HAVE_NAS_SOUND
792 if (DEVICE_CONNECTED_TO_NAS_P(decode_device(device)))
795 #ifdef HAVE_OSS_SOUND
796 if (DEVICE_ON_CONSOLE_P(decode_device(device)))
802 device = Vdefault_audio_device;
805 AUDIO_DEVICEP(device) &&
806 XAUDIO_DEVICE_STATE(device) != ASTATE_DEAD)
813 DEFUN("wait-for-sounds", Fwait_for_sounds, 0, 1, 0, /*
814 Wait for all sounds to finish playing on DEVICE.
822 DEFUN("connected-to-nas-p", Fconnected_to_nas_p, 0, 1, 0, /*
823 Return t if connected to NAS server for sounds on DEVICE.
827 #ifdef HAVE_NAS_SOUND
828 return DEVICE_CONNECTED_TO_NAS_P(decode_device(device)) ? Qt : Qnil;
835 /*****************************************************************/
836 /* audio device hack */
837 /*****************************************************************/
838 /* Indeed the console->device->frame->window structure is not what I'd call
839 * applicable to audio devices. That is why this seamless fake here exists :)
843 audio_device_mark(Lisp_Object obj)
845 if (XAUDIO_DEVICE_METH(obj, mark))
846 return XAUDIO_DEVICE_METH(obj, mark)(
847 XAUDIO_DEVICE_DATA(obj));
853 audio_device_finalise(void *header, int for_disksave)
855 Lisp_Audio_Device *ad = (Lisp_Audio_Device*)header;
857 SOUND_DEBUG_DEV("GCor asked me to finalise: 0x%lx\n",
858 (long unsigned int)ad);
860 if (audio_device_data(ad) &&
861 audio_device_meth(ad, finish))
862 audio_device_meth(ad, finish)(audio_device_data(ad));
864 if (audio_device_data(ad))
865 xfree(audio_device_data(ad));
866 audio_device_data(ad) = NULL;
868 /* avoid some warning */
869 if (for_disksave || ad == NULL);
873 audio_device_print(Lisp_Object obj, Lisp_Object printcharfun, int escapeflag)
875 write_c_string("#<audio-device :type ", printcharfun);
878 switch (XAUDIO_DEVICE_DRIVER(obj)) {
880 write_c_string("oss", printcharfun);
884 write_c_string("arts", printcharfun);
888 write_c_string("nas", printcharfun);
892 write_c_string("esd", printcharfun);
896 write_c_string("polyp", printcharfun);
900 write_c_string("pulse", printcharfun);
904 write_c_string("ao", printcharfun);
908 write_c_string("jack", printcharfun);
912 write_c_string("alsa", printcharfun);
915 case NUMBER_OF_AUDIO_DRIVERS:
916 case ADRIVER_UNKNOWN:
918 write_c_string("unknown", printcharfun);
922 if (XAUDIO_DEVICE_METH(obj, print)) {
923 XAUDIO_DEVICE_METH(obj, print)(obj, printcharfun, escapeflag);
926 /* info about the general state */
927 write_c_string(" :device-state ", printcharfun);
928 switch (XAUDIO_DEVICE_STATE(obj)) {
930 case ASTATE_SUSPENDED:
931 write_c_string("#dead", printcharfun);
934 write_c_string("#ready", printcharfun);
937 case NUMBER_OF_AUDIO_STATES:
940 write_c_string("#unknown", printcharfun);
944 write_c_string(">", printcharfun);
948 audio_device_equal(Lisp_Object obj1, Lisp_Object obj2, int depth)
953 if (depth || obj1 || obj2);
957 audio_device_hash (Lisp_Object obj, int SXE_UNUSED(depth))
959 return (unsigned long)obj;
960 /* audio_device_hashcode(XAUDIO_DEVICE_DATA(obj)); */
963 static const struct lrecord_description audio_device_description[] = {
964 { XD_INT, offsetof(Lisp_Audio_Device, driver) },
965 { XD_INT, offsetof(Lisp_Audio_Device, state) },
966 { XD_OPAQUE_PTR, offsetof(Lisp_Audio_Device, device_data) },
970 DEFINE_LRECORD_IMPLEMENTATION("audio_device", audio_device,
971 audio_device_mark, audio_device_print,
972 audio_device_finalise,
973 audio_device_equal, audio_device_hash,
974 audio_device_description,
977 static Lisp_Audio_Device *
978 audio_device_allocate(void)
980 Lisp_Audio_Device *ad;
982 ad = alloc_lcrecord_type(Lisp_Audio_Device, &lrecord_audio_device);
986 audio_driver decode_audio_type(Lisp_Object type)
988 audio_driver ad = ADRIVER_UNKNOWN;
991 #ifdef HAVE_OSS_SOUND
992 else if (EQ(type, Qoss))
995 #ifdef HAVE_NAS_SOUND
996 else if (EQ(type, Qnas))
999 #ifdef HAVE_ESD_SOUND
1000 else if (EQ(type, Qesd))
1003 #ifdef HAVE_POLYP_SOUND
1004 else if (EQ(type, Qpolyp))
1007 #ifdef HAVE_PULSE_SOUND
1008 else if (EQ(type, Qpulse))
1011 #ifdef HAVE_AO_SOUND
1012 else if (EQ(type, Qao))
1015 #ifdef HAVE_ARTS_SOUND
1016 else if (EQ(type, Qarts))
1019 #ifdef HAVE_JACK_SOUND
1020 else if (EQ(type, Qjack))
1023 #ifdef HAVE_ALSA_SOUND
1024 else if (EQ(type, Qalsa))
1031 audio_driver decode_audio_device(Lisp_Object device)
1033 struct device *d = NULL;
1034 audio_driver ad = ADRIVER_UNKNOWN;
1036 if (NILP(device) && !NILP(Vdefault_audio_device))
1037 device = Vdefault_audio_device;
1039 if (AUDIO_DEVICEP(device)) {
1040 ad = XAUDIO_DEVICE_DRIVER(device);
1042 } else if (DEVICEP(device) || NILP(device)) {
1043 d = decode_device(device);
1046 #ifdef HAVE_NAS_SOUND
1047 else if (DEVICE_CONNECTED_TO_NAS_P(d))
1050 #ifdef HAVE_AO_SOUND
1051 else if (DEVICE_CONNECTED_TO_AO_P(d))
1054 #ifdef HAVE_PULSE_SOUND
1055 else if (DEVICE_CONNECTED_TO_PULSE_P(d))
1058 #ifdef HAVE_POLYP_SOUND
1059 else if (DEVICE_CONNECTED_TO_POLYP_P(d))
1062 #ifdef HAVE_ESD_SOUND
1063 else if (DEVICE_CONNECTED_TO_ESD_P(d))
1066 #ifdef HAVE_ARTS_SOUND
1067 else if (DEVICE_CONNECTED_TO_ARTS_P(d))
1070 #ifdef HAVE_ALSA_SOUND
1071 else if (DEVICE_CONNECTED_TO_ALSA_P(d))
1074 #ifdef HAVE_OSS_SOUND
1075 else if (NILP(Vnative_sound_only_on_console) ||
1076 DEVICE_ON_CONSOLE_P(d))
1084 void *get_audio_device_data(Lisp_Object device)
1086 if (AUDIO_DEVICEP(device))
1087 return XAUDIO_DEVICE_DATA(device);
1092 Lisp_Audio_Device *get_audio_device(Lisp_Object device)
1094 if (AUDIO_DEVICEP(device))
1095 return XAUDIO_DEVICE(device);
1102 make_audio_device(Lisp_Object type)
1104 Lisp_Audio_Device *ad;
1109 ad = audio_device_allocate();
1110 audio_device_driver(ad) = decode_audio_type(type);
1111 audio_device_data(ad) = NULL;
1112 XSETAUDIO_DEVICE(lad, ad);
1113 XAUDIO_DEVICE_STATE(lad) = ASTATE_UNKNOWN;
1118 DEFUN("make-audio-device", Fmake_audio_device, 1, MANY, 0, /*
1119 DRIVER &rest DEVICE-OPTIONS
1121 Create a new device to output audio via DRIVER.
1122 DRIVER should be a symbol out of 'oss, 'nas, 'esd, 'pulse,
1123 'jack, 'alsa, 'arts or 'ao.
1125 The rest arguments may be used to pass options to the selected
1126 output driver. These should be `:keyword value' pairs.
1128 Valid keywords for ALSA are:
1129 :device - the name of the hardware interface (default: "default"),
1130 you may want to try "plughw:0,0" first
1131 :keep-open - whether to exclusively reserve the device.
1132 Note this may prevent other applications from using the device.
1134 Valid keywords for (deprecated) OSS are:
1135 :device - the name of the hardware interface (default: "/dev/dsp")
1136 :keep-open - whether to exclusively reserve the device.
1137 Note this may prevent other applications from using the device.
1139 Valid keywords for ESD are:
1140 :server - to use a distant ESD daemon (e.g. "my.machine.box:16001")
1141 The default for ESD output is to use a locally running daemon and
1142 to connect to it via unix domain sockets.
1144 Valid keywords for Pulse are:
1145 :server - the host name to connect to (default: "localhost")
1146 :sink - the name of the sink to connect to (e.g. "output")
1147 :source - the name of the source to record from (e.g. "mic_in")
1148 :client - how to call the client on the server (default "SXEmacs")
1149 :stream - how to call the stream on the server (e.g. "fancy-sound")
1150 :immediate - connect to sink immediately and keep the connection
1151 alive as long as the audio device exists (default `t')
1152 :threaded - initiate a threaded mainloop (default `t')
1153 :force - if non-nil the device object is created even though the
1154 pulse mainloop could not be started; if `nil' any mainloop failure
1155 results in an error. This can be useful if you want to have an
1156 audio device object although the server is not (yet) up or not
1157 (yet) accepting connections from you. (default `nil')
1159 Valid keywords for Jack are:
1160 :server - the jack server to connect to (default "default")
1161 :client - how to call the client on the server (default "SXEmacs")
1163 Valid keywords for AO are:
1164 :driver - the name of the output driver (e.g. "alsa", "esd", etc.)
1165 :options - a list of AO suboptions (see AO documentation)
1166 The default for AO output is to pass nothing and entirely use the
1167 system and user configuration files.
1169 Valid keywords for NAS are:
1170 :server - the NAS server to connect to. This can be either:
1171 - an X display string like "localhost:0.0", the X display string
1172 the current frame is on can be obtained by the function
1174 - or a SXEmacs device name like "localhost-11-0" which can be
1175 obtained by `device-name'
1176 - or a SXEmacs device object, obtainable by `frame-device', like
1177 #<x-device on "localhost:11.0" 0xee4>
1178 If the :server keyword is omitted SXEmacs tries to determine a
1179 sensible default in this order:
1180 - use the frame device of the current frame
1181 - use the frame device of the initial frame
1182 - use the display specified in $AUDIOSERVER
1183 - use the display specified in $DISPLAY
1184 - try "localhost:0.0"
1186 Valid keywords for aRts are:
1190 (int nargs, Lisp_Object *args))
1192 Lisp_Object ad, driver, device_options = Qnil;
1193 audio_driver dev_driver;
1194 ad_device_data *device_data = NULL;
1198 CHECK_SYMBOL(driver);
1199 ad = make_audio_device(driver);
1201 dev_driver = XAUDIO_DEVICE_DRIVER(ad);
1203 switch (dev_driver) {
1205 #ifdef HAVE_NAS_SOUND
1206 XAUDIO_DEVICE_METHS(ad) = sound_nas;
1210 #ifdef HAVE_ARTS_SOUND
1211 XAUDIO_DEVICE_METHS(ad) = sound_arts;
1215 #ifdef HAVE_ALSA_SOUND
1216 XAUDIO_DEVICE_METHS(ad) = sound_alsa;
1220 #ifdef HAVE_OSS_SOUND
1221 XAUDIO_DEVICE_METHS(ad) = sound_oss;
1225 #ifdef HAVE_AO_SOUND
1226 XAUDIO_DEVICE_METHS(ad) = sound_ao;
1231 #ifdef HAVE_PULSE_SOUND
1232 XAUDIO_DEVICE_METHS(ad) = sound_pulse;
1236 #ifdef HAVE_ESD_SOUND
1237 XAUDIO_DEVICE_METHS(ad) = sound_esd;
1241 #ifdef HAVE_JACK_SOUND
1242 XAUDIO_DEVICE_METHS(ad) = sound_jack;
1245 case ADRIVER_UNKNOWN:
1246 case NUMBER_OF_AUDIO_DRIVERS:
1253 Lisp_Object tmp = Flist(nargs, args);
1254 device_options = XCDR(tmp);
1257 if (XAUDIO_DEVICE_METH(ad, create) &&
1258 !(device_data = XAUDIO_DEVICE_METH(ad, create)(device_options))) {
1259 XAUDIO_DEVICE_STATE(ad) = ASTATE_DEAD;
1261 XAUDIO_DEVICE_DATA(ad) = device_data;
1265 DEFUN("audio-device-p", Faudio_device_p, 1, 1, 0, /*
1266 Return non-nil if OBJECT is an audio-device.
1270 if (AUDIO_DEVICEP(object))
1277 DEFUN("delete-audio-device", Fdelete_audio_device, 1, 1, 0, /*
1278 Deinitialise the audio device DEVICE and free its resources.
1282 CHECK_AUDIO_DEVICE(device);
1284 audio_device_finalise(XAUDIO_DEVICE(device), 0);
1290 void syms_of_sound(void)
1292 INIT_LRECORD_IMPLEMENTATION(audio_device);
1294 defkeyword(&Q_volume, ":volume");
1295 defkeyword(&Q_pitch, ":pitch");
1296 defkeyword(&Q_duration, ":duration");
1297 defkeyword(&Q_sound, ":sound");
1299 /* located in sound.el */
1300 defsymbol(&Qplay_sound, "play-sound");
1302 #ifdef HAVE_NAS_SOUND
1303 defsymbol(&Qnas, "nas");
1305 #ifdef HAVE_ESD_SOUND
1306 defsymbol(&Qesd, "esd");
1308 #ifdef HAVE_POLYP_SOUND
1309 defsymbol(&Qpolyp, "polyp");
1311 #ifdef HAVE_PULSE_SOUND
1312 defsymbol(&Qpulse, "pulse");
1314 #ifdef HAVE_AO_SOUND
1315 defsymbol(&Qao, "ao");
1317 #ifdef HAVE_ARTS_SOUND
1318 defsymbol(&Qarts, "arts");
1320 #ifdef HAVE_ALSA_SOUND
1321 defsymbol(&Qalsa, "alsa");
1323 #ifdef HAVE_JACK_SOUND
1324 defsymbol(&Qjack, "jack");
1326 #ifdef HAVE_OSS_SOUND
1327 defsymbol(&Qoss, "oss");
1329 defsymbol(&Qaudio_devicep, "audio-device-p");
1330 defsymbol(&Qaudio_jobp, "audio-job-p");
1332 /* some more symbols */
1333 defsymbol(&Q_device, ":device");
1334 defsymbol(&Q_keep_open, ":keep-open");
1335 defsymbol(&Q_server, ":server");
1336 defsymbol(&Q_client, ":client");
1338 DEFSUBR(Fplay_media_stream_synchronously);
1339 #ifdef EF_USE_ASYNEQ
1340 DEFSUBR(Fplay_media_streamX);
1341 DEFSUBR(Fset_audio_job_sentinel);
1342 DEFSUBR(Fpause_audio_job);
1343 DEFSUBR(Fresume_audio_job);
1344 DEFSUBR(Fstop_audio_job);
1345 DEFSUBR(Fset_audio_job_volume);
1346 DEFSUBR(Faudio_job_volume);
1347 DEFSUBR(Fset_audio_job_rate);
1348 DEFSUBR(Faudio_job_rate);
1352 DEFSUBR(Fwait_for_sounds);
1353 DEFSUBR(Fconnected_to_nas_p);
1354 DEFSUBR(Fdevice_sound_enabled_p);
1356 /* audio device fake */
1357 DEFSUBR(Fmake_audio_device);
1358 DEFSUBR(Faudio_device_p);
1360 DEFSUBR(Fdelete_audio_device); /* too dangerous atm */
1364 void vars_of_sound(void)
1366 #ifdef HAVE_OSS_SOUND
1368 Fprovide(intern("native-sound")); /* for compatibility */
1369 /* transition time is over! */
1371 Fprovide(intern("oss-sound"));
1373 #ifdef HAVE_NAS_SOUND
1374 Fprovide(intern("nas-sound"));
1376 #ifdef HAVE_ESD_SOUND
1377 Fprovide(intern("esd-sound"));
1379 #ifdef HAVE_POLYP_SOUND
1380 Fprovide(intern("polyp-sound"));
1382 #ifdef HAVE_PULSE_SOUND
1383 Fprovide(intern("pulse-sound"));
1385 #ifdef HAVE_AO_SOUND
1386 Fprovide(intern("ao-sound"));
1388 #ifdef HAVE_ARTS_SOUND
1389 Fprovide(intern("arts-sound"));
1391 #ifdef HAVE_ALSA_SOUND
1392 Fprovide(intern("alsa-sound"));
1394 Fprovide(intern("audio"));
1396 DEFVAR_INT("bell-volume", &bell_volume /*
1397 *How loud to be, from 0 to 255, where 127 is the norm (100%).
1398 Values above raise the volume and values below lower it.
1402 DEFVAR_INT("bell-inhibit-time", &bell_inhibit_time /*
1403 *Don't ring the bell on the same device more than once within this many seconds.
1405 bell_inhibit_time = 0;
1407 DEFVAR_LISP("sound-alist", &Vsound_alist /*
1408 An alist associating names with sounds.
1409 When `beep' or `ding' is called with one of the name symbols, the associated
1410 sound will be generated instead of the standard beep.
1412 Each element of `sound-alist' is a list describing a sound.
1413 The first element of the list is the name of the sound being defined.
1414 Subsequent elements of the list are alternating keyword/value pairs:
1418 sound A string of raw sound data (deprecated), or the name of another
1419 sound to play. The symbol `t' here means use the default X beep.
1420 volume An integer from 0-100, defaulting to `bell-volume'
1421 pitch If using the default X beep, the pitch (Hz) to generate.
1422 duration If using the default X beep, the duration (milliseconds).
1423 stream A media stream object containing the sound.
1425 You should probably add things to this list by calling the function
1428 Note: SXEmacs must be built with sound support for your system. Not all
1429 systems support sound.
1430 Note: The pitch, duration, and volume options are available everywhere,
1431 but many X servers ignore the `pitch' option.
1433 The following beep-types are used by SXEmacs itself:
1435 auto-save-error when an auto-save does not succeed
1436 command-error when the emacs command loop catches an error
1437 undefined-key when you type a key that is undefined
1438 undefined-click when you use an undefined mouse-click combination
1439 no-completion during completing-read
1440 y-or-n-p when you type something other than 'y' or 'n'
1441 yes-or-no-p when you type something other than 'yes' or 'no'
1442 default used when nothing else is appropriate.
1444 Other lisp packages may use other beep types, but these are the ones that
1445 the C kernel of Emacs uses.
1447 Vsound_alist = Qnil;
1449 DEFVAR_LISP("synchronous-sounds", &Vsynchronous_sounds /*
1450 Play sounds synchronously, if non-nil.
1451 Only applies if SXEmacs has been compiled with a threading library.
1452 Otherwise, sounds are always played synchronously.
1454 Vsynchronous_sounds = Qt;
1456 DEFVAR_LISP("native-sound-only-on-console", &Vnative_sound_only_on_console /*
1457 Non-nil value means play sounds only if SXEmacs is running
1458 on the system console.
1459 Nil means always play sounds, even if running on a non-console tty
1460 or a secondary X display.
1462 This variable only applies to native sound support.
1464 Vnative_sound_only_on_console = Qt;
1466 DEFVAR_LISP("default-audio-device", &Vdefault_audio_device /*
1467 Default audio device to use.
1469 Vdefault_audio_device = Qnil;
1472 /* sound.c ends here */