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_POLYP_SOUND
56 #include "sound-polyp.h"
58 #ifdef HAVE_PULSE_SOUND
59 #include "sound-pulse.h"
62 #include "sound-esd.h"
65 #include "sound-nas.h"
67 #ifdef HAVE_JACK_SOUND
68 #include "sound-jack.h"
70 #ifdef HAVE_ALSA_SOUND
71 #include "sound-alsa.h"
75 #include "sound-oss.h"
78 /* for CHECK_NUMBER and COMPARABLEP */
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);
863 if (audio_device_data(ad) &&
864 audio_device_meth(ad, finish))
865 audio_device_meth(ad, finish)(audio_device_data(ad));
867 if (audio_device_data(ad))
868 xfree(audio_device_data(ad));
869 audio_device_data(ad) = NULL;
871 /* avoid some warning */
876 audio_device_print(Lisp_Object obj, Lisp_Object printcharfun, int escapeflag)
878 write_c_string("#<audio-device :type ", printcharfun);
881 switch (XAUDIO_DEVICE_DRIVER(obj)) {
883 write_c_string("oss", printcharfun);
887 write_c_string("nas", printcharfun);
891 write_c_string("esd", printcharfun);
895 write_c_string("polyp", printcharfun);
899 write_c_string("pulse", printcharfun);
903 write_c_string("ao", printcharfun);
907 write_c_string("jack", printcharfun);
911 write_c_string("alsa", printcharfun);
914 case NUMBER_OF_AUDIO_DRIVERS:
915 case ADRIVER_UNKNOWN:
917 write_c_string("unknown", printcharfun);
921 if (XAUDIO_DEVICE_METH(obj, print)) {
922 XAUDIO_DEVICE_METH(obj, print)(obj, printcharfun, escapeflag);
925 /* info about the general state */
926 write_c_string(" :device-state ", printcharfun);
927 switch (XAUDIO_DEVICE_STATE(obj)) {
929 case ASTATE_SUSPENDED:
930 write_c_string("#dead", printcharfun);
933 write_c_string("#ready", printcharfun);
936 case NUMBER_OF_AUDIO_STATES:
939 write_c_string("#unknown", printcharfun);
943 write_c_string(">", printcharfun);
947 audio_device_equal(Lisp_Object obj1, Lisp_Object obj2, int depth)
952 if (depth || obj1 || obj2);
956 audio_device_hash (Lisp_Object obj, int SXE_UNUSED(depth))
958 return (unsigned long)obj;
959 /* audio_device_hashcode(XAUDIO_DEVICE_DATA(obj)); */
962 static const struct lrecord_description audio_device_description[] = {
963 { XD_INT, offsetof(Lisp_Audio_Device, driver) },
964 { XD_INT, offsetof(Lisp_Audio_Device, state) },
965 { XD_OPAQUE_PTR, offsetof(Lisp_Audio_Device, device_data) },
969 DEFINE_LRECORD_IMPLEMENTATION("audio_device", audio_device,
970 audio_device_mark, audio_device_print,
971 audio_device_finalise,
972 audio_device_equal, audio_device_hash,
973 audio_device_description,
976 static Lisp_Audio_Device *
977 audio_device_allocate(void)
979 Lisp_Audio_Device *ad;
981 ad = alloc_lcrecord_type(Lisp_Audio_Device, &lrecord_audio_device);
985 audio_driver decode_audio_type(Lisp_Object type)
987 audio_driver ad = ADRIVER_UNKNOWN;
990 #ifdef HAVE_OSS_SOUND
991 else if (EQ(type, Qoss))
994 #ifdef HAVE_NAS_SOUND
995 else if (EQ(type, Qnas))
998 #ifdef HAVE_ESD_SOUND
999 else if (EQ(type, Qesd))
1002 #ifdef HAVE_POLYP_SOUND
1003 else if (EQ(type, Qpolyp))
1006 #ifdef HAVE_PULSE_SOUND
1007 else if (EQ(type, Qpulse))
1010 #ifdef HAVE_AO_SOUND
1011 else if (EQ(type, Qao))
1014 #ifdef HAVE_JACK_SOUND
1015 else if (EQ(type, Qjack))
1018 #ifdef HAVE_ALSA_SOUND
1019 else if (EQ(type, Qalsa))
1026 audio_driver decode_audio_device(Lisp_Object device)
1028 struct device *d = NULL;
1029 audio_driver ad = ADRIVER_UNKNOWN;
1031 if (NILP(device) && !NILP(Vdefault_audio_device))
1032 device = Vdefault_audio_device;
1034 if (AUDIO_DEVICEP(device)) {
1035 ad = XAUDIO_DEVICE_DRIVER(device);
1037 } else if (DEVICEP(device) || NILP(device)) {
1038 d = decode_device(device);
1041 #ifdef HAVE_NAS_SOUND
1042 else if (DEVICE_CONNECTED_TO_NAS_P(d))
1045 #ifdef HAVE_AO_SOUND
1046 else if (DEVICE_CONNECTED_TO_AO_P(d))
1049 #ifdef HAVE_PULSE_SOUND
1050 else if (DEVICE_CONNECTED_TO_PULSE_P(d))
1053 #ifdef HAVE_POLYP_SOUND
1054 else if (DEVICE_CONNECTED_TO_POLYP_P(d))
1057 #ifdef HAVE_ESD_SOUND
1058 else if (DEVICE_CONNECTED_TO_ESD_P(d))
1061 #ifdef HAVE_ALSA_SOUND
1062 else if (DEVICE_CONNECTED_TO_ALSA_P(d))
1065 #ifdef HAVE_OSS_SOUND
1066 else if (NILP(Vnative_sound_only_on_console) ||
1067 DEVICE_ON_CONSOLE_P(d))
1075 void *get_audio_device_data(Lisp_Object device)
1077 if (AUDIO_DEVICEP(device))
1078 return XAUDIO_DEVICE_DATA(device);
1083 Lisp_Audio_Device *get_audio_device(Lisp_Object device)
1085 if (AUDIO_DEVICEP(device))
1086 return XAUDIO_DEVICE(device);
1093 make_audio_device(Lisp_Object type)
1095 Lisp_Audio_Device *ad;
1100 ad = audio_device_allocate();
1101 audio_device_driver(ad) = decode_audio_type(type);
1102 audio_device_data(ad) = NULL;
1103 XSETAUDIO_DEVICE(lad, ad);
1104 XAUDIO_DEVICE_STATE(lad) = ASTATE_UNKNOWN;
1109 DEFUN("make-audio-device", Fmake_audio_device, 1, MANY, 0, /*
1110 DRIVER &rest DEVICE-OPTIONS
1112 Create a new device to output audio via DRIVER.
1113 DRIVER should be a symbol out of 'oss, 'nas, 'esd, 'pulse,
1114 'jack, 'alsa, or 'ao.
1116 The rest arguments may be used to pass options to the selected
1117 output driver. These should be `:keyword value' pairs.
1119 Valid keywords for ALSA are:
1120 :device - the name of the hardware interface (default: "default"),
1121 you may want to try "plughw:0,0" first
1122 :keep-open - whether to exclusively reserve the device.
1123 Note this may prevent other applications from using the device.
1125 Valid keywords for (deprecated) OSS are:
1126 :device - the name of the hardware interface (default: "/dev/dsp")
1127 :keep-open - whether to exclusively reserve the device.
1128 Note this may prevent other applications from using the device.
1130 Valid keywords for ESD are:
1131 :server - to use a distant ESD daemon (e.g. "my.machine.box:16001")
1132 The default for ESD output is to use a locally running daemon and
1133 to connect to it via unix domain sockets.
1135 Valid keywords for Pulse are:
1136 :server - the host name to connect to (default: "localhost")
1137 :sink - the name of the sink to connect to (e.g. "output")
1138 :source - the name of the source to record from (e.g. "mic_in")
1139 :client - how to call the client on the server (default "SXEmacs")
1140 :stream - how to call the stream on the server (e.g. "fancy-sound")
1141 :immediate - connect to sink immediately and keep the connection
1142 alive as long as the audio device exists (default `t')
1143 :threaded - initiate a threaded mainloop (default `t')
1144 :force - if non-nil the device object is created even though the
1145 pulse mainloop could not be started; if `nil' any mainloop failure
1146 results in an error. This can be useful if you want to have an
1147 audio device object although the server is not (yet) up or not
1148 (yet) accepting connections from you. (default `nil')
1150 Valid keywords for Jack are:
1151 :server - the jack server to connect to (default "default")
1152 :client - how to call the client on the server (default "SXEmacs")
1154 Valid keywords for AO are:
1155 :driver - the name of the output driver (e.g. "alsa", "esd", etc.)
1156 :options - a list of AO suboptions (see AO documentation)
1157 The default for AO output is to pass nothing and entirely use the
1158 system and user configuration files.
1160 Valid keywords for NAS are:
1161 :server - the NAS server to connect to. This can be either:
1162 - an X display string like "localhost:0.0", the X display string
1163 the current frame is on can be obtained by the function
1165 - or a SXEmacs device name like "localhost-11-0" which can be
1166 obtained by `device-name'
1167 - or a SXEmacs device object, obtainable by `frame-device', like
1168 #<x-device on "localhost:11.0" 0xee4>
1169 If the :server keyword is omitted SXEmacs tries to determine a
1170 sensible default in this order:
1171 - use the frame device of the current frame
1172 - use the frame device of the initial frame
1173 - use the display specified in $AUDIOSERVER
1174 - use the display specified in $DISPLAY
1175 - try "localhost:0.0"
1178 (int nargs, Lisp_Object *args))
1180 Lisp_Object ad, driver, device_options = Qnil;
1181 audio_driver dev_driver;
1182 ad_device_data *device_data = NULL;
1186 CHECK_SYMBOL(driver);
1187 ad = make_audio_device(driver);
1189 dev_driver = XAUDIO_DEVICE_DRIVER(ad);
1191 switch (dev_driver) {
1193 #ifdef HAVE_NAS_SOUND
1194 XAUDIO_DEVICE_METHS(ad) = sound_nas;
1198 #ifdef HAVE_ALSA_SOUND
1199 XAUDIO_DEVICE_METHS(ad) = sound_alsa;
1203 #ifdef HAVE_OSS_SOUND
1204 XAUDIO_DEVICE_METHS(ad) = sound_oss;
1208 #ifdef HAVE_AO_SOUND
1209 XAUDIO_DEVICE_METHS(ad) = sound_ao;
1214 #ifdef HAVE_PULSE_SOUND
1215 XAUDIO_DEVICE_METHS(ad) = sound_pulse;
1219 #ifdef HAVE_ESD_SOUND
1220 XAUDIO_DEVICE_METHS(ad) = sound_esd;
1224 #ifdef HAVE_JACK_SOUND
1225 XAUDIO_DEVICE_METHS(ad) = sound_jack;
1228 case ADRIVER_UNKNOWN:
1229 case NUMBER_OF_AUDIO_DRIVERS:
1236 Lisp_Object tmp = Flist(nargs, args);
1237 device_options = XCDR(tmp);
1240 if (XAUDIO_DEVICE_METH(ad, create) &&
1241 !(device_data = XAUDIO_DEVICE_METH(ad, create)(device_options))) {
1242 XAUDIO_DEVICE_STATE(ad) = ASTATE_DEAD;
1244 XAUDIO_DEVICE_DATA(ad) = device_data;
1248 DEFUN("audio-device-p", Faudio_device_p, 1, 1, 0, /*
1249 Return non-nil if OBJECT is an audio-device.
1253 if (AUDIO_DEVICEP(object))
1260 DEFUN("delete-audio-device", Fdelete_audio_device, 1, 1, 0, /*
1261 Deinitialise the audio device DEVICE and free its resources.
1265 CHECK_AUDIO_DEVICE(device);
1267 audio_device_finalise(XAUDIO_DEVICE(device), 0);
1273 void syms_of_sound(void)
1275 INIT_LRECORD_IMPLEMENTATION(audio_device);
1277 defkeyword(&Q_volume, ":volume");
1278 defkeyword(&Q_pitch, ":pitch");
1279 defkeyword(&Q_duration, ":duration");
1280 defkeyword(&Q_sound, ":sound");
1282 /* located in sound.el */
1283 defsymbol(&Qplay_sound, "play-sound");
1285 #ifdef HAVE_NAS_SOUND
1286 defsymbol(&Qnas, "nas");
1288 #ifdef HAVE_ESD_SOUND
1289 defsymbol(&Qesd, "esd");
1291 #ifdef HAVE_POLYP_SOUND
1292 defsymbol(&Qpolyp, "polyp");
1294 #ifdef HAVE_PULSE_SOUND
1295 defsymbol(&Qpulse, "pulse");
1297 #ifdef HAVE_AO_SOUND
1298 defsymbol(&Qao, "ao");
1300 #ifdef HAVE_ALSA_SOUND
1301 defsymbol(&Qalsa, "alsa");
1303 #ifdef HAVE_JACK_SOUND
1304 defsymbol(&Qjack, "jack");
1306 #ifdef HAVE_OSS_SOUND
1307 defsymbol(&Qoss, "oss");
1309 defsymbol(&Qaudio_devicep, "audio-device-p");
1310 defsymbol(&Qaudio_jobp, "audio-job-p");
1312 /* some more symbols */
1313 defsymbol(&Q_device, ":device");
1314 defsymbol(&Q_keep_open, ":keep-open");
1315 defsymbol(&Q_server, ":server");
1316 defsymbol(&Q_client, ":client");
1318 DEFSUBR(Fplay_media_stream_synchronously);
1319 #ifdef EF_USE_ASYNEQ
1320 DEFSUBR(Fplay_media_streamX);
1321 DEFSUBR(Fset_audio_job_sentinel);
1322 DEFSUBR(Fpause_audio_job);
1323 DEFSUBR(Fresume_audio_job);
1324 DEFSUBR(Fstop_audio_job);
1325 DEFSUBR(Fset_audio_job_volume);
1326 DEFSUBR(Faudio_job_volume);
1327 DEFSUBR(Fset_audio_job_rate);
1328 DEFSUBR(Faudio_job_rate);
1332 DEFSUBR(Fwait_for_sounds);
1333 DEFSUBR(Fconnected_to_nas_p);
1334 DEFSUBR(Fdevice_sound_enabled_p);
1336 /* audio device fake */
1337 DEFSUBR(Fmake_audio_device);
1338 DEFSUBR(Faudio_device_p);
1340 DEFSUBR(Fdelete_audio_device); /* too dangerous atm */
1344 void vars_of_sound(void)
1346 #ifdef HAVE_OSS_SOUND
1348 Fprovide(intern("native-sound")); /* for compatibility */
1349 /* transition time is over! */
1351 Fprovide(intern("oss-sound"));
1353 #ifdef HAVE_NAS_SOUND
1354 Fprovide(intern("nas-sound"));
1356 #ifdef HAVE_ESD_SOUND
1357 Fprovide(intern("esd-sound"));
1359 #ifdef HAVE_POLYP_SOUND
1360 Fprovide(intern("polyp-sound"));
1362 #ifdef HAVE_PULSE_SOUND
1363 Fprovide(intern("pulse-sound"));
1365 #ifdef HAVE_AO_SOUND
1366 Fprovide(intern("ao-sound"));
1368 #ifdef HAVE_ALSA_SOUND
1369 Fprovide(intern("alsa-sound"));
1371 Fprovide(intern("audio"));
1373 DEFVAR_INT("bell-volume", &bell_volume /*
1374 *How loud to be, from 0 to 255, where 127 is the norm (100%).
1375 Values above raise the volume and values below lower it.
1379 DEFVAR_INT("bell-inhibit-time", &bell_inhibit_time /*
1380 *Don't ring the bell on the same device more than once within this many seconds.
1382 bell_inhibit_time = 0;
1384 DEFVAR_LISP("sound-alist", &Vsound_alist /*
1385 An alist associating names with sounds.
1386 When `beep' or `ding' is called with one of the name symbols, the associated
1387 sound will be generated instead of the standard beep.
1389 Each element of `sound-alist' is a list describing a sound.
1390 The first element of the list is the name of the sound being defined.
1391 Subsequent elements of the list are alternating keyword/value pairs:
1395 sound A string of raw sound data (deprecated), or the name of another
1396 sound to play. The symbol `t' here means use the default X beep.
1397 volume An integer from 0-100, defaulting to `bell-volume'
1398 pitch If using the default X beep, the pitch (Hz) to generate.
1399 duration If using the default X beep, the duration (milliseconds).
1400 stream A media stream object containing the sound.
1402 You should probably add things to this list by calling the function
1405 Note: SXEmacs must be built with sound support for your system. Not all
1406 systems support sound.
1407 Note: The pitch, duration, and volume options are available everywhere,
1408 but many X servers ignore the `pitch' option.
1410 The following beep-types are used by SXEmacs itself:
1412 auto-save-error when an auto-save does not succeed
1413 command-error when the emacs command loop catches an error
1414 undefined-key when you type a key that is undefined
1415 undefined-click when you use an undefined mouse-click combination
1416 no-completion during completing-read
1417 y-or-n-p when you type something other than 'y' or 'n'
1418 yes-or-no-p when you type something other than 'yes' or 'no'
1419 default used when nothing else is appropriate.
1421 Other lisp packages may use other beep types, but these are the ones that
1422 the C kernel of Emacs uses.
1424 Vsound_alist = Qnil;
1426 DEFVAR_LISP("synchronous-sounds", &Vsynchronous_sounds /*
1427 Play sounds synchronously, if non-nil.
1428 Only applies if SXEmacs has been compiled with a threading library.
1429 Otherwise, sounds are always played synchronously.
1431 Vsynchronous_sounds = Qt;
1433 DEFVAR_LISP("native-sound-only-on-console", &Vnative_sound_only_on_console /*
1434 Non-nil value means play sounds only if SXEmacs is running
1435 on the system console.
1436 Nil means always play sounds, even if running on a non-console tty
1437 or a secondary X display.
1439 This variable only applies to native sound support.
1441 Vnative_sound_only_on_console = Qt;
1443 DEFVAR_LISP("default-audio-device", &Vdefault_audio_device /*
1444 Default audio device to use.
1446 Vdefault_audio_device = Qnil;
1449 /* sound.c ends here */