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;
411 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 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);
429 finish_audio_job_data(audio_job_t aj)
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;
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;
443 SOUND_CRITICAL("strange, buffer is non-NULL: 0x%lx\n",
444 (long unsigned int)aj->buffer);
445 /* xfree(aj->buffer); */
447 aj->buffer_alloc_size = 0;
450 if (audio_job_queue(aj)) {
451 SOUND_DEBUG_AJ("finishing audio job queue\n");
452 free_event_queue(audio_job_queue(aj));
454 audio_job_queue(aj) = (void*)0xB16B00B5;
455 #endif /* EF_USE_ASYNEQ */
461 SXE_MUTEX_UNLOCK(&aj->mtx);
462 SXE_MUTEX_FINI(&aj->mtx);
464 SOUND_DEBUG_AJ("finished: 0x%lx\n", (long unsigned int)aj);
470 sound_DO_NOT_play_stream(audio_job_t mst)
471 __attribute__((unused));
474 sound_DO_NOT_play_stream(audio_job_t mst)
476 /* just a dummy function */
480 DEFUN("play-media-stream-synchronously", Fplay_media_stream_synchronously,
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.
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'.
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'.
495 Optional fourth argument VOLUME specifies an intial value for
498 (stream, device, sentinel, volume))
503 CHECK_MEDIA_STREAM(stream);
506 device = Vdefault_audio_device;
508 CHECK_AUDIO_DEVICE(device);
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
516 GETTEXT("play-media-stream: "
517 "no device specified, "
518 "consider setting `default-audio-device'."));
523 CHECK_NUMBER(volume);
524 volume = Fcoerce_number(volume, Qint, Qnil);
526 if (vol < MEDIA_SAMPLE_VOLUME_MIN)
528 else if (vol > MEDIA_SAMPLE_VOLUME_MAX)
529 vol = MEDIA_SAMPLE_VOLUME_MAX;
531 vol = MEDIA_SAMPLE_VOLUME_NORM;
534 aj = make_audio_job(stream, device, Qnil);
535 if (aj == Qnull_pointer) {
536 SOUND_DEBUG_AJ("audio job is void ... cancelling play\n");
541 aj->play_state = MTPSTATE_RUN;
543 #if defined EF_USE_ASYNEQ
547 SOUND_DEBUG_AJ("sync calling play meth\n");
548 XAUDIO_DEVICE(device)->meths->play(aj);
550 if (!NILP(sentinel)) {
552 (void*)Qnil, stream, intern("finished"), sentinel);
555 finish_audio_job_data(aj);
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};
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.
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);
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.
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),
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
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);
623 DEFUN("set-audio-job-volume", Fset_audio_job_volume, 1, 2, 0, /*
624 Set the volume of the audio job JOB to VOLUME.
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.
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.
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.
644 Lisp_Object tmpv = Qnil;
646 CHECK_AUDIO_JOB(job);
648 if (XAUDIO_JOB_QUEUE(job)) {
650 XAUDIO_JOB_QUEUE(job), &volnorm_event);
652 return make_int(MEDIA_SAMPLE_VOLUME_NORM);
653 } else if (volume == Qnil) {
654 if (XAUDIO_JOB_QUEUE(job)) {
656 XAUDIO_JOB_QUEUE(job), &volmute_event);
658 return make_int(MEDIA_SAMPLE_VOLUME_NORM);
659 } else if (COMPARABLEP(volume)) {
660 volume = Fcoerce_number(volume, Qint, Qnil);
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);
673 vol = MEDIA_SAMPLE_VOLUME_MIN;
674 else if (vol > MEDIA_SAMPLE_VOLUME_MAX)
675 vol = MEDIA_SAMPLE_VOLUME_MAX;
677 return wrong_type_argument(Qnumberp, volume);
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);
689 DEFUN("audio-job-volume", Faudio_job_volume, 1, 1, 0, /*
690 Return the current volume of audio job JOB.
694 CHECK_AUDIO_JOB(job);
696 return make_int(XAUDIO_JOB(job)->volume);
699 DEFUN("set-audio-job-rate", Fset_audio_job_rate, 1, 2, 0, /*
700 Set the rate of audio job JOB to RATE.
702 If RATE is `t' or `nil', reset the rate to 1.0.
708 CHECK_AUDIO_JOB(job);
709 if (rate == Qt || rate == Qnil) {
711 } else if (COMPARABLEP(rate)) {
712 rate = Fcoerce_number(rate, Qfloat, Qnil);
713 ratetrafo = XFLOAT_DATA(rate);
715 if (ratetrafo <= 0.5)
717 else if (ratetrafo > 2.0)
720 return wrong_type_argument(Qnumberp, rate);
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);
732 DEFUN("audio-job-rate", Faudio_job_rate, 1, 1, 0, /*
733 Return the current rate of audio job JOB.
737 CHECK_AUDIO_JOB(job);
739 return make_float(XAUDIO_JOB(job)->ratetrafo);
741 #endif /* EF_USE_ASYNEQ */
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'.
752 (arg, sound, device))
754 static time_t last_bell_time;
755 static struct device *last_bell_device;
757 struct device *d = decode_device(device);
758 struct gcpro gcpro1, gcpro2, gcpro3;
760 GCPRO3(arg, sound, device);
762 /* XSETDEVICE(device, d); */
765 if (NILP(arg) && !NILP(Vexecuting_macro))
766 /* Stop executing a keyboard macro. */
768 ("Keyboard macro terminated by a command ringing the bell");
770 if (d == last_bell_device && now - last_bell_time < bell_inhibit_time) {
772 } else if (!NILP(Vvisible_bell) && DEVMETH(d, flash, (d))) {
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);
780 last_bell_time = now;
781 last_bell_device = d;
782 RETURN_UNGCPRO(Qnil);
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.
792 if (DEVICEP(device)) {
793 #ifdef HAVE_NAS_SOUND
794 if (DEVICE_CONNECTED_TO_NAS_P(decode_device(device)))
797 #ifdef HAVE_OSS_SOUND
798 if (DEVICE_ON_CONSOLE_P(decode_device(device)))
804 device = Vdefault_audio_device;
807 AUDIO_DEVICEP(device) &&
808 XAUDIO_DEVICE_STATE(device) != ASTATE_DEAD)
815 DEFUN("wait-for-sounds", Fwait_for_sounds, 0, 1, 0, /*
816 Wait for all sounds to finish playing on DEVICE.
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.
829 #ifdef HAVE_NAS_SOUND
830 return DEVICE_CONNECTED_TO_NAS_P(decode_device(device)) ? Qt : Qnil;
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 :)
845 audio_device_mark(Lisp_Object obj)
847 if (XAUDIO_DEVICE_METH(obj, mark))
848 return XAUDIO_DEVICE_METH(obj, mark)(
849 XAUDIO_DEVICE_DATA(obj));
855 audio_device_finalise(void *header, int for_disksave)
857 Lisp_Audio_Device *ad = (Lisp_Audio_Device*)header;
859 SOUND_DEBUG_DEV("GCor asked me to finalise: 0x%lx\n",
860 (long unsigned int)ad);
865 if (audio_device_data(ad) &&
866 audio_device_meth(ad, finish))
867 audio_device_meth(ad, finish)(audio_device_data(ad));
869 if (audio_device_data(ad))
870 xfree(audio_device_data(ad));
871 audio_device_data(ad) = NULL;
873 /* avoid some warning */
878 audio_device_print(Lisp_Object obj, Lisp_Object printcharfun, int escapeflag)
880 write_c_string("#<audio-device :type ", printcharfun);
883 switch (XAUDIO_DEVICE_DRIVER(obj)) {
885 write_c_string("oss", printcharfun);
889 write_c_string("nas", printcharfun);
893 write_c_string("esd", printcharfun);
897 write_c_string("polyp", printcharfun);
901 write_c_string("pulse", printcharfun);
905 write_c_string("ao", printcharfun);
909 write_c_string("jack", printcharfun);
913 write_c_string("alsa", printcharfun);
916 case NUMBER_OF_AUDIO_DRIVERS:
917 case ADRIVER_UNKNOWN:
919 write_c_string("unknown", printcharfun);
923 if (XAUDIO_DEVICE_METH(obj, print)) {
924 XAUDIO_DEVICE_METH(obj, print)(obj, printcharfun, escapeflag);
927 /* info about the general state */
928 write_c_string(" :device-state ", printcharfun);
929 switch (XAUDIO_DEVICE_STATE(obj)) {
931 case ASTATE_SUSPENDED:
932 write_c_string("#dead", printcharfun);
935 write_c_string("#ready", printcharfun);
938 case NUMBER_OF_AUDIO_STATES:
941 write_c_string("#unknown", printcharfun);
945 write_c_string(">", printcharfun);
949 audio_device_equal(Lisp_Object obj1, Lisp_Object obj2, int depth)
954 if (depth || obj1 || obj2);
958 audio_device_hash (Lisp_Object obj, int SXE_UNUSED(depth))
960 return (unsigned long)obj;
961 /* audio_device_hashcode(XAUDIO_DEVICE_DATA(obj)); */
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) },
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,
978 static Lisp_Audio_Device *
979 audio_device_allocate(void)
981 Lisp_Audio_Device *ad;
983 ad = alloc_lcrecord_type(Lisp_Audio_Device, &lrecord_audio_device);
987 audio_driver decode_audio_type(Lisp_Object type)
989 audio_driver ad = ADRIVER_UNKNOWN;
992 #ifdef HAVE_OSS_SOUND
993 else if (EQ(type, Qoss))
996 #ifdef HAVE_NAS_SOUND
997 else if (EQ(type, Qnas))
1000 #ifdef HAVE_ESD_SOUND
1001 else if (EQ(type, Qesd))
1004 #ifdef HAVE_POLYP_SOUND
1005 else if (EQ(type, Qpolyp))
1008 #ifdef HAVE_PULSE_SOUND
1009 else if (EQ(type, Qpulse))
1012 #ifdef HAVE_AO_SOUND
1013 else if (EQ(type, Qao))
1016 #ifdef HAVE_JACK_SOUND
1017 else if (EQ(type, Qjack))
1020 #ifdef HAVE_ALSA_SOUND
1021 else if (EQ(type, Qalsa))
1028 audio_driver decode_audio_device(Lisp_Object device)
1030 struct device *d = NULL;
1031 audio_driver ad = ADRIVER_UNKNOWN;
1033 if (NILP(device) && !NILP(Vdefault_audio_device))
1034 device = Vdefault_audio_device;
1036 if (AUDIO_DEVICEP(device)) {
1037 ad = XAUDIO_DEVICE_DRIVER(device);
1039 } else if (DEVICEP(device) || NILP(device)) {
1040 d = decode_device(device);
1043 #ifdef HAVE_NAS_SOUND
1044 else if (DEVICE_CONNECTED_TO_NAS_P(d))
1047 #ifdef HAVE_AO_SOUND
1048 else if (DEVICE_CONNECTED_TO_AO_P(d))
1051 #ifdef HAVE_PULSE_SOUND
1052 else if (DEVICE_CONNECTED_TO_PULSE_P(d))
1055 #ifdef HAVE_POLYP_SOUND
1056 else if (DEVICE_CONNECTED_TO_POLYP_P(d))
1059 #ifdef HAVE_ESD_SOUND
1060 else if (DEVICE_CONNECTED_TO_ESD_P(d))
1063 #ifdef HAVE_ALSA_SOUND
1064 else if (DEVICE_CONNECTED_TO_ALSA_P(d))
1067 #ifdef HAVE_OSS_SOUND
1068 else if (NILP(Vnative_sound_only_on_console) ||
1069 DEVICE_ON_CONSOLE_P(d))
1077 void *get_audio_device_data(Lisp_Object device)
1079 if (AUDIO_DEVICEP(device))
1080 return XAUDIO_DEVICE_DATA(device);
1085 Lisp_Audio_Device *get_audio_device(Lisp_Object device)
1087 if (AUDIO_DEVICEP(device))
1088 return XAUDIO_DEVICE(device);
1095 make_audio_device(Lisp_Object type)
1097 Lisp_Audio_Device *ad;
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;
1111 DEFUN("make-audio-device", Fmake_audio_device, 1, MANY, 0, /*
1112 DRIVER &rest DEVICE-OPTIONS
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.
1118 The rest arguments may be used to pass options to the selected
1119 output driver. These should be `:keyword value' pairs.
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.
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.
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.
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')
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")
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.
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
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"
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_ALSA_SOUND
1211 XAUDIO_DEVICE_METHS(ad) = sound_alsa;
1215 #ifdef HAVE_OSS_SOUND
1216 XAUDIO_DEVICE_METHS(ad) = sound_oss;
1220 #ifdef HAVE_AO_SOUND
1221 XAUDIO_DEVICE_METHS(ad) = sound_ao;
1226 #ifdef HAVE_PULSE_SOUND
1227 XAUDIO_DEVICE_METHS(ad) = sound_pulse;
1231 #ifdef HAVE_ESD_SOUND
1232 XAUDIO_DEVICE_METHS(ad) = sound_esd;
1236 #ifdef HAVE_JACK_SOUND
1237 XAUDIO_DEVICE_METHS(ad) = sound_jack;
1240 case ADRIVER_UNKNOWN:
1241 case NUMBER_OF_AUDIO_DRIVERS:
1248 Lisp_Object tmp = Flist(nargs, args);
1249 device_options = XCDR(tmp);
1252 if (XAUDIO_DEVICE_METH(ad, create) &&
1253 !(device_data = XAUDIO_DEVICE_METH(ad, create)(device_options))) {
1254 XAUDIO_DEVICE_STATE(ad) = ASTATE_DEAD;
1256 XAUDIO_DEVICE_DATA(ad) = device_data;
1260 DEFUN("audio-device-p", Faudio_device_p, 1, 1, 0, /*
1261 Return non-nil if OBJECT is an audio-device.
1265 if (AUDIO_DEVICEP(object))
1272 DEFUN("delete-audio-device", Fdelete_audio_device, 1, 1, 0, /*
1273 Deinitialise the audio device DEVICE and free its resources.
1277 CHECK_AUDIO_DEVICE(device);
1279 audio_device_finalise(XAUDIO_DEVICE(device), 0);
1285 void syms_of_sound(void)
1287 INIT_LRECORD_IMPLEMENTATION(audio_device);
1289 defkeyword(&Q_volume, ":volume");
1290 defkeyword(&Q_pitch, ":pitch");
1291 defkeyword(&Q_duration, ":duration");
1292 defkeyword(&Q_sound, ":sound");
1294 /* located in sound.el */
1295 defsymbol(&Qplay_sound, "play-sound");
1297 #ifdef HAVE_NAS_SOUND
1298 defsymbol(&Qnas, "nas");
1300 #ifdef HAVE_ESD_SOUND
1301 defsymbol(&Qesd, "esd");
1303 #ifdef HAVE_POLYP_SOUND
1304 defsymbol(&Qpolyp, "polyp");
1306 #ifdef HAVE_PULSE_SOUND
1307 defsymbol(&Qpulse, "pulse");
1309 #ifdef HAVE_AO_SOUND
1310 defsymbol(&Qao, "ao");
1312 #ifdef HAVE_ALSA_SOUND
1313 defsymbol(&Qalsa, "alsa");
1315 #ifdef HAVE_JACK_SOUND
1316 defsymbol(&Qjack, "jack");
1318 #ifdef HAVE_OSS_SOUND
1319 defsymbol(&Qoss, "oss");
1321 defsymbol(&Qaudio_devicep, "audio-device-p");
1322 defsymbol(&Qaudio_jobp, "audio-job-p");
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");
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);
1344 DEFSUBR(Fwait_for_sounds);
1345 DEFSUBR(Fconnected_to_nas_p);
1346 DEFSUBR(Fdevice_sound_enabled_p);
1348 /* audio device fake */
1349 DEFSUBR(Fmake_audio_device);
1350 DEFSUBR(Faudio_device_p);
1352 DEFSUBR(Fdelete_audio_device); /* too dangerous atm */
1356 void vars_of_sound(void)
1358 #ifdef HAVE_OSS_SOUND
1360 Fprovide(intern("native-sound")); /* for compatibility */
1361 /* transition time is over! */
1363 Fprovide(intern("oss-sound"));
1365 #ifdef HAVE_NAS_SOUND
1366 Fprovide(intern("nas-sound"));
1368 #ifdef HAVE_ESD_SOUND
1369 Fprovide(intern("esd-sound"));
1371 #ifdef HAVE_POLYP_SOUND
1372 Fprovide(intern("polyp-sound"));
1374 #ifdef HAVE_PULSE_SOUND
1375 Fprovide(intern("pulse-sound"));
1377 #ifdef HAVE_AO_SOUND
1378 Fprovide(intern("ao-sound"));
1380 #ifdef HAVE_ALSA_SOUND
1381 Fprovide(intern("alsa-sound"));
1383 Fprovide(intern("audio"));
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.
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.
1394 bell_inhibit_time = 0;
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.
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:
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.
1414 You should probably add things to this list by calling the function
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.
1422 The following beep-types are used by SXEmacs itself:
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.
1433 Other lisp packages may use other beep types, but these are the ones that
1434 the C kernel of Emacs uses.
1436 Vsound_alist = Qnil;
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.
1443 Vsynchronous_sounds = Qt;
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.
1451 This variable only applies to native sound support.
1453 Vnative_sound_only_on_console = Qt;
1455 DEFVAR_LISP("default-audio-device", &Vdefault_audio_device /*
1456 Default audio device to use.
1458 Vdefault_audio_device = Qnil;
1461 /* sound.c ends here */