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 Lisp_Object Qaudio_devicep;
79 Lisp_Object Qaudio_jobp;
80 Lisp_Object Vdefault_audio_device;
82 static audio_job_t make_audio_job(Lisp_Object, Lisp_Object, Lisp_Object);
83 static Lisp_Object make_audio_asyneq_job(audio_job_t);
84 static inline void finish_audio_job_data(audio_job_t);
86 exec_sentinel(void *job, Lisp_Object, Lisp_Object, Lisp_Object);
89 #include "events/worker-asyneq.h"
91 /*****************************************************************/
93 /*****************************************************************/
94 /* sound-mst handler */
97 mark_audio_job(worker_job_t job)
106 SOUND_DEBUG_AJ("Marking audio job 0x%lx (job 0x%lx)\n",
107 (long unsigned int)aj,
108 (long unsigned int)job);
109 SXE_MUTEX_LOCK(&aj->mtx);
110 mark_object(aj->stream);
111 mark_object(aj->device);
112 mark_object(aj->result);
113 mark_object(aj->sentinel);
114 SXE_MUTEX_UNLOCK(&aj->mtx);
119 print_audio_job(worker_job_t job, Lisp_Object pcf)
121 audio_job_t aj = audio_job(job);
122 SXE_MUTEX_LOCK(&aj->mtx);
123 write_fmt_string(pcf, " carrying #<audio-job 0x%lx>", (long unsigned int)aj);
124 SXE_MUTEX_UNLOCK(&aj->mtx);
129 finish_audio_job(worker_job_t job)
133 lock_worker_job(job);
136 SOUND_DEBUG_AJ("Finishing audio job 0x%lx (job 0x%lx)\n",
137 (long unsigned int)aj,
138 (long unsigned int)job);
140 finish_audio_job_data(aj);
142 worker_job_data(job) = NULL;
143 unlock_worker_job(job);
148 audio_job_handle(worker_job_t job)
151 /* usually called from aux threads */
154 #if !defined HAVE_BDWGC || !defined EF_USE_BDWGC
155 Lisp_Object ljob = (Lisp_Object)job;
157 int(*playfun)(audio_job_t);
161 lock_worker_job(job);
163 SXE_MUTEX_LOCK(&aj->mtx);
164 SOUND_DEBUG_AJ("inherit scratch buffer 0x%lx (sz=%ld)\n",
165 (long unsigned int)worker_job_buffer(job),
166 (long int)worker_job_buffer_alloc_size(job));
167 aj->buffer = worker_job_buffer(job);
168 aj->buffer_alloc_size = worker_job_buffer_alloc_size(job);
169 device = audio_job_device(job);
170 SOUND_DEBUG_MT("starting thread 0x%lx@0x%lx\n",
171 (long unsigned int)aj,
172 (long unsigned int)job);
173 aj->play_state = MTPSTATE_RUN;
175 SOUND_DEBUG_AJ("fetching play function\n");
176 playfun = XAUDIO_DEVICE(device)->meths->play;
177 SOUND_DEBUG_AJ("fetched 0x%lx\n", (long unsigned int)playfun);
179 SXE_MUTEX_UNLOCK(&aj->mtx);
180 SOUND_DEBUG_AJ("calling play function\n");
182 SOUND_DEBUG_AJ("play function finished\n");
183 unlock_worker_job(job);
189 audio_job_started(worker_job_t job)
191 if (NILP(audio_job_sentinel(job) /* sentinel */)) {
194 /* called from main thread */
195 exec_sentinel(job, audio_job_stream(job), intern("started"),
196 audio_job_sentinel(job));
201 audio_job_finished(worker_job_t job)
203 if (NILP(audio_job_sentinel(job) /* sentinel */)) {
206 /* called from main thread */
207 exec_sentinel(job, audio_job_stream(job), intern("finished"),
208 audio_job_sentinel(job));
212 static struct work_handler_s audio_job_handler = {
213 mark_audio_job, print_audio_job, finish_audio_job,
214 audio_job_handle, audio_job_started, audio_job_finished
218 make_audio_asyneq_job(audio_job_t aj)
220 /* create a job digestible by the asyneq */
221 Lisp_Object job = Qnil;
226 j = make_worker_job(&audio_job_handler);
227 job = wrap_object(j);
228 XWORKER_JOB_DATA(job) = aj;
229 /* the scratch buffer thingie */
230 SXE_MUTEX_LOCK(&aj->mtx);
231 aj->buffer = XWORKER_JOB_BUFFER(job);
232 aj->buffer_alloc_size = XWORKER_JOB_BUFFER_ALLOC_SIZE(job);
233 /* generate an event queue for job control */
234 audio_job_queue(aj) = make_noseeum_event_queue();
235 SXE_MUTEX_UNLOCK(&aj->mtx);
241 DEFUN("set-audio-job-sentinel", Fset_audio_job_sentinel, 2, 2, 0, /*
242 Give JOB the sentinel SENTINEL; `nil' for none.
243 The sentinel is called as a function whenever the stream state changes.
245 The function should take three (optional four) arguments
246 (JOB STREAM STATE &optional OLD-STATE)
248 - JOB is the worker job object currently coping with the stream,
249 - STREAM is bound to the stream object, and
250 - STATE is one of 'unknown, 'started, 'paused, 'stopped, 'finished
251 and indicates the current state of the job
252 - OLD-STATE is again one of the above state symbols but indicates
253 the previous state of the job.
257 CHECK_AUDIO_JOB(job);
258 XAUDIO_JOB_SENTINEL(job) = sentinel;
262 DEFUN("play-media-stream&", Fplay_media_streamX,
264 Play the media stream STREAM on an audio device DEVICE.
266 Optional second argument DEVICE must be an audio device
267 created by `make-audio-device'.
268 If omitted DEVICE defaults to the value of `default-audio-device'.
270 Optional third argument SENTINEL specifies a lisp function to be
271 called whenever the stream state changes. The function should
272 take three (optional four) arguments
273 (JOB STREAM STATE &optional OLD-STATE)
275 - JOB is the worker job object currently coping with the stream,
276 - STREAM is bound to the stream object, and
277 - STATE is one of 'unknown, 'started, 'paused, 'stopped and indicates
278 the current state of the job
279 - OLD-STATE is again one of the above state symbols but indicates
280 the previous state of the job.
282 See also `set-media-thread-sentinel'.
284 Optional fourth argument VOLUME specifies an intial value for
287 (stream, device, sentinel, volume))
290 Lisp_Object job = Qnil;
292 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
294 CHECK_MEDIA_STREAM(stream);
297 device = Vdefault_audio_device;
299 CHECK_AUDIO_DEVICE(device);
301 /* hm, it's useful to stop here if default-audio-device is nil,
302 * i merely spit out a warning and return nil, that should suffice
307 GETTEXT("play-media-stream: "
308 "no device specified, "
309 "consider setting `default-audio-device'."));
314 CHECK_NUMBER(volume);
315 volume = Fcoerce_number(volume, Qint, Qnil);
317 if (vol < MEDIA_SAMPLE_VOLUME_MIN)
319 else if (vol > MEDIA_SAMPLE_VOLUME_MAX)
320 vol = MEDIA_SAMPLE_VOLUME_MAX;
322 vol = MEDIA_SAMPLE_VOLUME_NORM;
324 GCPRO4(job, device, stream, sentinel);
325 /* create the job data object */
326 aj = make_audio_job(stream, device, sentinel);
327 if (aj == Qnull_pointer) {
333 /* now prepare the job to dispatch */
334 job = make_audio_asyneq_job(aj);
336 /* ... and dispatch it */
337 eq_enqueue(delegate_eq, job);
338 /* brag about new jobs in the queue */
339 eq_queue_trigger_all(delegate_eq);
343 #endif /* EF_USE_ASYNEQ */
346 /* media thread sentinels */
348 exec_sentinel_unwind(Lisp_Object SXE_UNUSED(datum))
354 exec_sentinel(void *job, Lisp_Object stream,
355 Lisp_Object state, Lisp_Object sentinel)
357 /* This function can GC */
358 /* called from main thread */
359 Lisp_Object funcell[4] = {sentinel, (Lisp_Object)job, stream, state};
360 int speccount = specpdl_depth();
363 GCPROn(funcell, countof(funcell));
365 record_unwind_protect(exec_sentinel_unwind, Qnil);
366 /* call the funcell */
367 Ffuncall(countof(funcell), funcell);
368 /* reset to previous state */
369 restore_match_data();
371 unbind_to(speccount, Qnil);
375 static inline audio_job_t
376 allocate_audio_job(void)
378 audio_job_t aj = xnew(struct audio_job_s);
379 SOUND_DEBUG_AJ("allocated: 0x%lx\n", (long unsigned int)aj);
384 make_audio_job(Lisp_Object stream, Lisp_Object device, Lisp_Object sentinel)
386 audio_job_t aj = NULL;
387 media_substream *mss;
389 /* traverse the substreams, try to find the first audio stream */
390 for (mss = XMEDIA_STREAM_FIRST(stream);
391 mss && media_substream_type(mss) != MTYPE_AUDIO;
392 mss = media_substream_next(mss));
396 return Qnull_pointer;
399 aj = allocate_audio_job();
404 aj->sentinel = sentinel;
406 aj->state = MTSTATE_UNKNOWN;
407 aj->play_state = MTPSTATE_UNKNOWN;
409 SXE_MUTEX_INIT(&aj->mtx);
410 audio_job_queue(aj) = NULL;
413 aj->job_device_data = NULL;
414 aj->job_stream_data = NULL;
417 aj->buffer_alloc_size = 0;
419 SOUND_DEBUG_AJ("created: 0x%lx\n", (long unsigned int)aj);
424 finish_audio_job_data(audio_job_t aj)
426 SOUND_DEBUG_AJ("finishing: 0x%lx\n", (long unsigned int)aj);
427 SXE_MUTEX_LOCK(&aj->mtx);
428 if (audio_job_device_data(aj)) {
429 SOUND_DEBUG_AJ("audio-job device data still alive. Bug?\n");
430 audio_job_device_data(aj) = NULL;
432 if (audio_job_stream_data(aj)) {
433 SOUND_DEBUG_AJ("audio-job stream data still alive. Bug?\n");
434 audio_job_stream_data(aj) = NULL;
438 SOUND_CRITICAL("strange, buffer is non-NULL: 0x%lx\n",
439 (long unsigned int)aj->buffer);
440 /* xfree(aj->buffer); */
442 aj->buffer_alloc_size = 0;
445 if (audio_job_queue(aj)) {
446 SOUND_DEBUG_AJ("finishing audio job queue\n");
447 free_event_queue(audio_job_queue(aj));
449 audio_job_queue(aj) = (void*)0xB16B00B5;
450 #endif /* EF_USE_ASYNEQ */
456 SXE_MUTEX_UNLOCK(&aj->mtx);
457 SXE_MUTEX_FINI(&aj->mtx);
459 SOUND_DEBUG_AJ("finished: 0x%lx\n", (long unsigned int)aj);
465 sound_DO_NOT_play_stream(audio_job_t mst)
466 __attribute__((unused));
469 sound_DO_NOT_play_stream(audio_job_t mst)
471 /* just a dummy function */
475 DEFUN("play-media-stream-synchronously", Fplay_media_stream_synchronously,
477 Play the media stream STREAM on an audio device synchronously.
478 This function disregards the value of `synchronous-sounds',
479 instead streams will always be played in synchronous mode.
481 Optional second argument DEVICE must be an audio device
482 created by `make-audio-device'.
483 If omitted DEVICE defaults to the value of `default-audio-device'.
485 Optional third argument SENTINEL specifies a lisp function to be
486 called after the stream playback finishes. The function should
487 take one argument (STREAM) where STREAM is bound to the
488 media stream which finished. See `set-media-thread-sentinel'.
490 Optional fourth argument VOLUME specifies an intial value for
493 (stream, device, sentinel, volume))
498 CHECK_MEDIA_STREAM(stream);
501 device = Vdefault_audio_device;
503 CHECK_AUDIO_DEVICE(device);
505 /* hm, it's useful to stop here if default-audio-device is nil,
506 * i merely spit out a warning and return nil, that should suffice
511 GETTEXT("play-media-stream: "
512 "no device specified, "
513 "consider setting `default-audio-device'."));
518 CHECK_NUMBER(volume);
519 volume = Fcoerce_number(volume, Qint, Qnil);
521 if (vol < MEDIA_SAMPLE_VOLUME_MIN)
523 else if (vol > MEDIA_SAMPLE_VOLUME_MAX)
524 vol = MEDIA_SAMPLE_VOLUME_MAX;
526 vol = MEDIA_SAMPLE_VOLUME_NORM;
529 aj = make_audio_job(stream, device, Qnil);
530 if (aj == Qnull_pointer) {
531 SOUND_DEBUG_AJ("audio job is void ... cancelling play\n");
536 aj->play_state = MTPSTATE_RUN;
538 #if defined EF_USE_ASYNEQ
542 SOUND_DEBUG_AJ("calling play meth\n");
543 XAUDIO_DEVICE(device)->meths->play(aj);
545 if (!NILP(sentinel)) {
547 (void*)Qnil, stream, intern("finished"), sentinel);
550 finish_audio_job_data(aj);
557 struct audio_job_event_s pause_event = {aj_change_state, {aj_pause}, 0};
558 struct audio_job_event_s resume_event = {aj_change_state, {aj_resume}, 0};
559 struct audio_job_event_s start_event = {aj_change_state, {aj_start}, 0};
560 struct audio_job_event_s stop_event = {aj_change_state, {aj_stop}, 0};
561 struct audio_job_event_s volnorm_event = {
562 aj_change_volume, {MEDIA_SAMPLE_VOLUME_NORM}, 0};
563 struct audio_job_event_s volmute_event = {
564 aj_change_volume, {MEDIA_SAMPLE_VOLUME_MIN}, 0};
566 DEFUN("pause-audio-job", Fpause_audio_job, 1, 1, 0, /*
567 Pause the audio job JOB.
568 Optionally JOB can be 'all in which case all running
569 media threads are paused.
573 if (!EQ(job, Qall)) {
574 CHECK_AUDIO_JOB(job);
575 /* connect to job's queue and place a PAUSE event there */
576 if (XAUDIO_JOB_QUEUE(job)) {
577 eq_noseeum_enqueue(XAUDIO_JOB_QUEUE(job), &pause_event);
583 DEFUN("resume-audio-job", Fresume_audio_job, 1, 1, 0, /*
584 Resume a paused audio job JOB.
585 Optionally JOB can be 'all in which case all paused
586 media threads are resumed.
590 if (!EQ(job, Qall)) {
591 CHECK_AUDIO_JOB(job);
592 /* connect to job's queue and place a RESUME event there */
593 if (XAUDIO_JOB_QUEUE(job)) {
594 eq_noseeum_enqueue(XAUDIO_JOB_QUEUE(job),
601 DEFUN("stop-audio-job", Fstop_audio_job, 1, 1, 0, /*
602 Stop a audio job JOB.
603 Optionally JOB can be 'all in which case all media threads
608 if (!EQ(job, Qall)) {
609 CHECK_AUDIO_JOB(job);
610 /* connect to job's queue and place a STOP event there */
611 if (XAUDIO_JOB_QUEUE(job)) {
612 eq_noseeum_enqueue(XAUDIO_JOB_QUEUE(job), &stop_event);
618 DEFUN("set-audio-job-volume", Fset_audio_job_volume, 1, 2, 0, /*
619 Set the volume of the audio job JOB to VOLUME.
621 JOB is assumed to be a media thread object with an audio substream.
622 Optionally JOB can be 'all in which case the volume change
623 applies to all (currently handled) media threads.
625 VOLUME is either a comparable number (see `comparablep') or
626 a vector of comparable numbers.
627 In the former case VOLUME sets the master volume of all channels.
628 In the latter case VOLUME sets the volumes channelwise.
630 Any volume value is coerced to an integer.
631 A volume of 128 is the norm.
632 A volume of 0 is muting the respective channels.
633 Volumes greater than 128 cause an amplification of the stream,
634 255 is the maximal volume value. Note that clipping may occur.
639 Lisp_Object tmpv = Qnil;
641 CHECK_AUDIO_JOB(job);
643 if (XAUDIO_JOB_QUEUE(job)) {
645 XAUDIO_JOB_QUEUE(job), &volnorm_event);
647 return make_int(MEDIA_SAMPLE_VOLUME_NORM);
648 } else if (volume == Qnil) {
649 if (XAUDIO_JOB_QUEUE(job)) {
651 XAUDIO_JOB_QUEUE(job), &volmute_event);
653 return make_int(MEDIA_SAMPLE_VOLUME_NORM);
654 } else if (COMPARABLEP(volume)) {
655 volume = Fcoerce_number(volume, Qint, Qnil);
659 vol = MEDIA_SAMPLE_VOLUME_MIN;
660 else if (vol > MEDIA_SAMPLE_VOLUME_MAX)
661 vol = MEDIA_SAMPLE_VOLUME_MAX;
662 } else if (VECTORP(volume)) {
663 tmpv = XVECTOR_DATA(volume)[0];
664 tmpv = Fcoerce_number(tmpv, Qint, Qnil);
668 vol = MEDIA_SAMPLE_VOLUME_MIN;
669 else if (vol > MEDIA_SAMPLE_VOLUME_MAX)
670 vol = MEDIA_SAMPLE_VOLUME_MAX;
672 return wrong_type_argument(Qnumberp, volume);
675 /* place an VOLCHANGE event in job's queue */
676 if (XAUDIO_JOB_QUEUE(job)) {
677 audio_job_event_t aje = make_audio_job_event(aj_change_volume);
678 audio_job_event_args(aje).volume_args = vol;
679 eq_noseeum_enqueue(XAUDIO_JOB_QUEUE(job), aje);
684 DEFUN("audio-job-volume", Faudio_job_volume, 1, 1, 0, /*
685 Return the current volume of audio job JOB.
689 CHECK_AUDIO_JOB(job);
691 return make_int(XAUDIO_JOB(job)->volume);
694 DEFUN("set-audio-job-rate", Fset_audio_job_rate, 1, 2, 0, /*
695 Set the rate of audio job JOB to RATE.
697 If RATE is `t' or `nil', reset the rate to 1.0.
703 CHECK_AUDIO_JOB(job);
704 if (rate == Qt || rate == Qnil) {
706 } else if (COMPARABLEP(rate)) {
707 rate = Fcoerce_number(rate, Qfloat, Qnil);
708 ratetrafo = XFLOAT_DATA(rate);
710 if (ratetrafo <= 0.5)
712 else if (ratetrafo > 2.0)
715 return wrong_type_argument(Qnumberp, rate);
718 /* place a rate change event in job's queue */
719 if (XAUDIO_JOB_QUEUE(job)) {
720 audio_job_event_t aje = make_audio_job_event(aj_change_rate);
721 audio_job_event_args(aje).rate_args = ratetrafo;
722 eq_noseeum_enqueue(XAUDIO_JOB_QUEUE(job), aje);
727 DEFUN("audio-job-rate", Faudio_job_rate, 1, 1, 0, /*
728 Return the current rate of audio job JOB.
732 CHECK_AUDIO_JOB(job);
734 return make_float(XAUDIO_JOB(job)->ratetrafo);
736 #endif /* EF_USE_ASYNEQ */
739 DEFUN("ding", Fding, 0, 3, 0, /*
740 Beep, or flash the frame.
741 Also, unless an argument is given,
742 terminate any keyboard macro currently executing.
743 When called from lisp, the second argument is what sound to make, and
744 the third argument is the device to make it in (defaults to the selected
745 device), but may also be an audio device created by `make-audio-device'.
747 (arg, sound, device))
749 static time_t last_bell_time;
750 static struct device *last_bell_device;
752 struct device *d = decode_device(device);
753 struct gcpro gcpro1, gcpro2, gcpro3;
755 GCPRO3(arg, sound, device);
757 /* XSETDEVICE(device, d); */
760 if (NILP(arg) && !NILP(Vexecuting_macro))
761 /* Stop executing a keyboard macro. */
763 ("Keyboard macro terminated by a command ringing the bell");
765 if (d == last_bell_device && now - last_bell_time < bell_inhibit_time) {
767 } else if (!NILP(Vvisible_bell) && DEVMETH(d, flash, (d))) {
769 } else if (NILP(sound)) {
770 DEVMETH(d, ring_bell, (d, bell_volume, -1, -1));
771 } else if (!NILP(Ffboundp(Qplay_sound))) {
772 call3(Qplay_sound, sound, Qnil, device);
775 last_bell_time = now;
776 last_bell_device = d;
777 RETURN_UNGCPRO(Qnil);
782 DEFUN("device-sound-enabled-p", Fdevice_sound_enabled_p, 0, 1, 0, /*
783 Return t if DEVICE is able to play sound. Defaults to selected device.
787 if (DEVICEP(device)) {
788 #ifdef HAVE_NAS_SOUND
789 if (DEVICE_CONNECTED_TO_NAS_P(decode_device(device)))
792 #ifdef HAVE_OSS_SOUND
793 if (DEVICE_ON_CONSOLE_P(decode_device(device)))
799 device = Vdefault_audio_device;
802 AUDIO_DEVICEP(device) &&
803 XAUDIO_DEVICE_STATE(device) != ASTATE_DEAD)
810 DEFUN("wait-for-sounds", Fwait_for_sounds, 0, 1, 0, /*
811 Wait for all sounds to finish playing on DEVICE.
819 DEFUN("connected-to-nas-p", Fconnected_to_nas_p, 0, 1, 0, /*
820 Return t if connected to NAS server for sounds on DEVICE.
824 #ifdef HAVE_NAS_SOUND
825 return DEVICE_CONNECTED_TO_NAS_P(decode_device(device)) ? Qt : Qnil;
832 /*****************************************************************/
833 /* audio device hack */
834 /*****************************************************************/
835 /* Indeed the console->device->frame->window structure is not what I'd call
836 * applicable to audio devices. That is why this seamless fake here exists :)
840 audio_device_mark(Lisp_Object obj)
842 if (XAUDIO_DEVICE_METH(obj, mark))
843 return XAUDIO_DEVICE_METH(obj, mark)(
844 XAUDIO_DEVICE_DATA(obj));
850 audio_device_finalise(void *header, int for_disksave)
852 Lisp_Audio_Device *ad = (Lisp_Audio_Device*)header;
854 SOUND_DEBUG_DEV("GCor asked me to finalise: 0x%lx\n",
855 (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 */
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("nas", printcharfun);
888 write_c_string("esd", printcharfun);
892 write_c_string("polyp", printcharfun);
896 write_c_string("pulse", printcharfun);
900 write_c_string("ao", printcharfun);
904 write_c_string("jack", printcharfun);
908 write_c_string("alsa", printcharfun);
911 case NUMBER_OF_AUDIO_DRIVERS:
912 case ADRIVER_UNKNOWN:
914 write_c_string("unknown", printcharfun);
918 if (XAUDIO_DEVICE_METH(obj, print)) {
919 XAUDIO_DEVICE_METH(obj, print)(obj, printcharfun, escapeflag);
922 /* info about the general state */
923 write_c_string(" :device-state ", printcharfun);
924 switch (XAUDIO_DEVICE_STATE(obj)) {
926 case ASTATE_SUSPENDED:
927 write_c_string("#dead", printcharfun);
930 write_c_string("#ready", printcharfun);
933 case NUMBER_OF_AUDIO_STATES:
936 write_c_string("#unknown", printcharfun);
940 write_c_string(">", printcharfun);
944 audio_device_equal(Lisp_Object obj1, Lisp_Object obj2, int depth)
949 if (depth || obj1 || obj2);
953 audio_device_hash (Lisp_Object obj, int SXE_UNUSED(depth))
955 return (unsigned long)obj;
956 /* audio_device_hashcode(XAUDIO_DEVICE_DATA(obj)); */
959 static const struct lrecord_description audio_device_description[] = {
960 { XD_INT, offsetof(Lisp_Audio_Device, driver) },
961 { XD_INT, offsetof(Lisp_Audio_Device, state) },
962 { XD_OPAQUE_PTR, offsetof(Lisp_Audio_Device, device_data) },
966 DEFINE_LRECORD_IMPLEMENTATION("audio_device", audio_device,
967 audio_device_mark, audio_device_print,
968 audio_device_finalise,
969 audio_device_equal, audio_device_hash,
970 audio_device_description,
973 static Lisp_Audio_Device *
974 audio_device_allocate(void)
976 Lisp_Audio_Device *ad;
978 ad = alloc_lcrecord_type(Lisp_Audio_Device, &lrecord_audio_device);
982 audio_driver decode_audio_type(Lisp_Object type)
984 audio_driver ad = ADRIVER_UNKNOWN;
987 #ifdef HAVE_OSS_SOUND
988 else if (EQ(type, Qoss))
991 #ifdef HAVE_NAS_SOUND
992 else if (EQ(type, Qnas))
995 #ifdef HAVE_ESD_SOUND
996 else if (EQ(type, Qesd))
999 #ifdef HAVE_POLYP_SOUND
1000 else if (EQ(type, Qpolyp))
1003 #ifdef HAVE_PULSE_SOUND
1004 else if (EQ(type, Qpulse))
1007 #ifdef HAVE_AO_SOUND
1008 else if (EQ(type, Qao))
1011 #ifdef HAVE_JACK_SOUND
1012 else if (EQ(type, Qjack))
1015 #ifdef HAVE_ALSA_SOUND
1016 else if (EQ(type, Qalsa))
1023 audio_driver decode_audio_device(Lisp_Object device)
1025 struct device *d = NULL;
1026 audio_driver ad = ADRIVER_UNKNOWN;
1028 if (NILP(device) && !NILP(Vdefault_audio_device))
1029 device = Vdefault_audio_device;
1031 if (AUDIO_DEVICEP(device)) {
1032 ad = XAUDIO_DEVICE_DRIVER(device);
1034 } else if (DEVICEP(device) || NILP(device)) {
1035 d = decode_device(device);
1038 #ifdef HAVE_NAS_SOUND
1039 else if (DEVICE_CONNECTED_TO_NAS_P(d))
1042 #ifdef HAVE_AO_SOUND
1043 else if (DEVICE_CONNECTED_TO_AO_P(d))
1046 #ifdef HAVE_PULSE_SOUND
1047 else if (DEVICE_CONNECTED_TO_PULSE_P(d))
1050 #ifdef HAVE_POLYP_SOUND
1051 else if (DEVICE_CONNECTED_TO_POLYP_P(d))
1054 #ifdef HAVE_ESD_SOUND
1055 else if (DEVICE_CONNECTED_TO_ESD_P(d))
1058 #ifdef HAVE_ALSA_SOUND
1059 else if (DEVICE_CONNECTED_TO_ALSA_P(d))
1062 #ifdef HAVE_OSS_SOUND
1063 else if (NILP(Vnative_sound_only_on_console) ||
1064 DEVICE_ON_CONSOLE_P(d))
1072 void *get_audio_device_data(Lisp_Object device)
1074 if (AUDIO_DEVICEP(device))
1075 return XAUDIO_DEVICE_DATA(device);
1080 Lisp_Audio_Device *get_audio_device(Lisp_Object device)
1082 if (AUDIO_DEVICEP(device))
1083 return XAUDIO_DEVICE(device);
1090 make_audio_device(Lisp_Object type)
1092 Lisp_Audio_Device *ad;
1097 ad = audio_device_allocate();
1098 audio_device_driver(ad) = decode_audio_type(type);
1099 audio_device_data(ad) = NULL;
1100 XSETAUDIO_DEVICE(lad, ad);
1101 XAUDIO_DEVICE_STATE(lad) = ASTATE_UNKNOWN;
1106 DEFUN("make-audio-device", Fmake_audio_device, 1, MANY, 0, /*
1107 DRIVER &rest DEVICE-OPTIONS
1109 Create a new device to output audio via DRIVER.
1110 DRIVER should be a symbol out of 'oss, 'nas, 'esd, 'pulse,
1111 'jack, 'alsa, or 'ao.
1113 The rest arguments may be used to pass options to the selected
1114 output driver. These should be `:keyword value' pairs.
1116 Valid keywords for ALSA are:
1117 :device - the name of the hardware interface (default: "default"),
1118 you may want to try "plughw:0,0" first
1119 :keep-open - whether to exclusively reserve the device.
1120 Note this may prevent other applications from using the device.
1122 Valid keywords for (deprecated) OSS are:
1123 :device - the name of the hardware interface (default: "/dev/dsp")
1124 :keep-open - whether to exclusively reserve the device.
1125 Note this may prevent other applications from using the device.
1127 Valid keywords for ESD are:
1128 :server - to use a distant ESD daemon (e.g. "my.machine.box:16001")
1129 The default for ESD output is to use a locally running daemon and
1130 to connect to it via unix domain sockets.
1132 Valid keywords for Pulse are:
1133 :server - the host name to connect to (default: "localhost")
1134 :sink - the name of the sink to connect to (e.g. "output")
1135 :source - the name of the source to record from (e.g. "mic_in")
1136 :client - how to call the client on the server (default "SXEmacs")
1137 :stream - how to call the stream on the server (e.g. "fancy-sound")
1138 :immediate - connect to sink immediately and keep the connection
1139 alive as long as the audio device exists (default `t')
1140 :threaded - initiate a threaded mainloop (default `t')
1141 :force - if non-nil the device object is created even though the
1142 pulse mainloop could not be started; if `nil' any mainloop failure
1143 results in an error. This can be useful if you want to have an
1144 audio device object although the server is not (yet) up or not
1145 (yet) accepting connections from you. (default `nil')
1147 Valid keywords for Jack are:
1148 :server - the jack server to connect to (default "default")
1149 :client - how to call the client on the server (default "SXEmacs")
1151 Valid keywords for AO are:
1152 :driver - the name of the output driver (e.g. "alsa", "esd", etc.)
1153 :options - a list of AO suboptions (see AO documentation)
1154 The default for AO output is to pass nothing and entirely use the
1155 system and user configuration files.
1157 Valid keywords for NAS are:
1158 :server - the NAS server to connect to. This can be either:
1159 - an X display string like "localhost:0.0", the X display string
1160 the current frame is on can be obtained by the function
1162 - or a SXEmacs device name like "localhost-11-0" which can be
1163 obtained by `device-name'
1164 - or a SXEmacs device object, obtainable by `frame-device', like
1165 #<x-device on "localhost:11.0" 0xee4>
1166 If the :server keyword is omitted SXEmacs tries to determine a
1167 sensible default in this order:
1168 - use the frame device of the current frame
1169 - use the frame device of the initial frame
1170 - use the display specified in $AUDIOSERVER
1171 - use the display specified in $DISPLAY
1172 - try "localhost:0.0"
1175 (int nargs, Lisp_Object *args))
1177 Lisp_Object ad, driver, device_options = Qnil;
1178 audio_driver dev_driver;
1179 ad_device_data *device_data = NULL;
1183 CHECK_SYMBOL(driver);
1184 ad = make_audio_device(driver);
1186 dev_driver = XAUDIO_DEVICE_DRIVER(ad);
1188 switch (dev_driver) {
1190 #ifdef HAVE_NAS_SOUND
1191 XAUDIO_DEVICE_METHS(ad) = sound_nas;
1195 #ifdef HAVE_ALSA_SOUND
1196 XAUDIO_DEVICE_METHS(ad) = sound_alsa;
1200 #ifdef HAVE_OSS_SOUND
1201 XAUDIO_DEVICE_METHS(ad) = sound_oss;
1205 #ifdef HAVE_AO_SOUND
1206 XAUDIO_DEVICE_METHS(ad) = sound_ao;
1211 #ifdef HAVE_PULSE_SOUND
1212 XAUDIO_DEVICE_METHS(ad) = sound_pulse;
1216 #ifdef HAVE_ESD_SOUND
1217 XAUDIO_DEVICE_METHS(ad) = sound_esd;
1221 #ifdef HAVE_JACK_SOUND
1222 XAUDIO_DEVICE_METHS(ad) = sound_jack;
1225 case ADRIVER_UNKNOWN:
1226 case NUMBER_OF_AUDIO_DRIVERS:
1233 Lisp_Object tmp = Flist(nargs, args);
1234 device_options = XCDR(tmp);
1237 if (XAUDIO_DEVICE_METH(ad, create) &&
1238 !(device_data = XAUDIO_DEVICE_METH(ad, create)(device_options))) {
1239 XAUDIO_DEVICE_STATE(ad) = ASTATE_DEAD;
1241 XAUDIO_DEVICE_DATA(ad) = device_data;
1245 DEFUN("audio-device-p", Faudio_device_p, 1, 1, 0, /*
1246 Return non-nil if OBJECT is an audio-device.
1250 if (AUDIO_DEVICEP(object))
1257 DEFUN("delete-audio-device", Fdelete_audio_device, 1, 1, 0, /*
1258 Deinitialise the audio device DEVICE and free its resources.
1262 CHECK_AUDIO_DEVICE(device);
1264 audio_device_finalise(XAUDIO_DEVICE(device), 0);
1270 void syms_of_sound(void)
1272 INIT_LRECORD_IMPLEMENTATION(audio_device);
1274 defkeyword(&Q_volume, ":volume");
1275 defkeyword(&Q_pitch, ":pitch");
1276 defkeyword(&Q_duration, ":duration");
1277 defkeyword(&Q_sound, ":sound");
1279 /* located in sound.el */
1280 defsymbol(&Qplay_sound, "play-sound");
1282 #ifdef HAVE_NAS_SOUND
1283 defsymbol(&Qnas, "nas");
1285 #ifdef HAVE_ESD_SOUND
1286 defsymbol(&Qesd, "esd");
1288 #ifdef HAVE_POLYP_SOUND
1289 defsymbol(&Qpolyp, "polyp");
1291 #ifdef HAVE_PULSE_SOUND
1292 defsymbol(&Qpulse, "pulse");
1294 #ifdef HAVE_AO_SOUND
1295 defsymbol(&Qao, "ao");
1297 #ifdef HAVE_ALSA_SOUND
1298 defsymbol(&Qalsa, "alsa");
1300 #ifdef HAVE_JACK_SOUND
1301 defsymbol(&Qjack, "jack");
1303 #ifdef HAVE_OSS_SOUND
1304 defsymbol(&Qoss, "oss");
1306 defsymbol(&Qaudio_devicep, "audio-device-p");
1307 defsymbol(&Qaudio_jobp, "audio-job-p");
1309 /* some more symbols */
1310 defsymbol(&Q_device, ":device");
1311 defsymbol(&Q_keep_open, ":keep-open");
1312 defsymbol(&Q_server, ":server");
1313 defsymbol(&Q_client, ":client");
1315 DEFSUBR(Fplay_media_stream_synchronously);
1316 #ifdef EF_USE_ASYNEQ
1317 DEFSUBR(Fplay_media_streamX);
1318 DEFSUBR(Fset_audio_job_sentinel);
1319 DEFSUBR(Fpause_audio_job);
1320 DEFSUBR(Fresume_audio_job);
1321 DEFSUBR(Fstop_audio_job);
1322 DEFSUBR(Fset_audio_job_volume);
1323 DEFSUBR(Faudio_job_volume);
1324 DEFSUBR(Fset_audio_job_rate);
1325 DEFSUBR(Faudio_job_rate);
1329 DEFSUBR(Fwait_for_sounds);
1330 DEFSUBR(Fconnected_to_nas_p);
1331 DEFSUBR(Fdevice_sound_enabled_p);
1333 /* audio device fake */
1334 DEFSUBR(Fmake_audio_device);
1335 DEFSUBR(Faudio_device_p);
1337 DEFSUBR(Fdelete_audio_device); /* too dangerous atm */
1341 void vars_of_sound(void)
1343 #ifdef HAVE_OSS_SOUND
1345 Fprovide(intern("native-sound")); /* for compatibility */
1346 /* transition time is over! */
1348 Fprovide(intern("oss-sound"));
1350 #ifdef HAVE_NAS_SOUND
1351 Fprovide(intern("nas-sound"));
1353 #ifdef HAVE_ESD_SOUND
1354 Fprovide(intern("esd-sound"));
1356 #ifdef HAVE_POLYP_SOUND
1357 Fprovide(intern("polyp-sound"));
1359 #ifdef HAVE_PULSE_SOUND
1360 Fprovide(intern("pulse-sound"));
1362 #ifdef HAVE_AO_SOUND
1363 Fprovide(intern("ao-sound"));
1365 #ifdef HAVE_ALSA_SOUND
1366 Fprovide(intern("alsa-sound"));
1368 Fprovide(intern("audio"));
1370 DEFVAR_INT("bell-volume", &bell_volume /*
1371 *How loud to be, from 0 to 255, where 127 is the norm (100%).
1372 Values above raise the volume and values below lower it.
1376 DEFVAR_INT("bell-inhibit-time", &bell_inhibit_time /*
1377 *Don't ring the bell on the same device more than once within this many seconds.
1379 bell_inhibit_time = 0;
1381 DEFVAR_LISP("sound-alist", &Vsound_alist /*
1382 An alist associating names with sounds.
1383 When `beep' or `ding' is called with one of the name symbols, the associated
1384 sound will be generated instead of the standard beep.
1386 Each element of `sound-alist' is a list describing a sound.
1387 The first element of the list is the name of the sound being defined.
1388 Subsequent elements of the list are alternating keyword/value pairs:
1392 sound A string of raw sound data (deprecated), or the name of another
1393 sound to play. The symbol `t' here means use the default X beep.
1394 volume An integer from 0-100, defaulting to `bell-volume'
1395 pitch If using the default X beep, the pitch (Hz) to generate.
1396 duration If using the default X beep, the duration (milliseconds).
1397 stream A media stream object containing the sound.
1399 You should probably add things to this list by calling the function
1402 Note: SXEmacs must be built with sound support for your system. Not all
1403 systems support sound.
1404 Note: The pitch, duration, and volume options are available everywhere,
1405 but many X servers ignore the `pitch' option.
1407 The following beep-types are used by SXEmacs itself:
1409 auto-save-error when an auto-save does not succeed
1410 command-error when the emacs command loop catches an error
1411 undefined-key when you type a key that is undefined
1412 undefined-click when you use an undefined mouse-click combination
1413 no-completion during completing-read
1414 y-or-n-p when you type something other than 'y' or 'n'
1415 yes-or-no-p when you type something other than 'yes' or 'no'
1416 default used when nothing else is appropriate.
1418 Other lisp packages may use other beep types, but these are the ones that
1419 the C kernel of Emacs uses.
1421 Vsound_alist = Qnil;
1423 DEFVAR_LISP("synchronous-sounds", &Vsynchronous_sounds /*
1424 Play sounds synchronously, if non-nil.
1425 Only applies if SXEmacs has been compiled with a threading library.
1426 Otherwise, sounds are always played synchronously.
1428 Vsynchronous_sounds = Qt;
1430 DEFVAR_LISP("native-sound-only-on-console", &Vnative_sound_only_on_console /*
1431 Non-nil value means play sounds only if SXEmacs is running
1432 on the system console.
1433 Nil means always play sounds, even if running on a non-console tty
1434 or a secondary X display.
1436 This variable only applies to native sound support.
1438 Vnative_sound_only_on_console = Qt;
1440 DEFVAR_LISP("default-audio-device", &Vdefault_audio_device /*
1441 Default audio device to use.
1443 Vdefault_audio_device = Qnil;
1446 /* sound.c ends here */