1 /* play.c - play a sound file on the speaker
3 ** Copyright (C) 1989 by Jef Poskanzer.
5 ** Modified 24-May-91 by Jamie Zawinski (for Lucid Emacs).
6 ** Modified 17-Dec-92 by Jamie Zawinski (largely rewritten for SunOS 4.1.3).
8 ** Permission to use, copy, modify, and distribute this software and its
9 ** documentation for any purpose and without fee is hereby granted, provided
10 ** that the above copyright notice appear in all copies and that both that
11 ** copyright notice and this permission notice appear in supporting
12 ** documentation. This software is provided "as is" without express or
16 /* Synched up with: Not in FSF. */
22 #if __STDC__ || defined(STDC_HEADERS)
25 #include <fcntl.h> /* for open() */
30 #include <sys/fcntl.h>
33 #include <multimedia/libaudio.h>
34 #include <multimedia/audio_device.h>
40 #include "syssignal.h"
41 # define perror(string) \
42 message("audio: %s, %s ", string, strerror (errno))
43 # define warn(str) message ("audio: %s ", GETTEXT (str))
45 #include "nativesound.h"
46 #include "media-native.h"
47 #include "sound-sunplay.h"
49 Lisp_Object Qsunplay; /* cannot be Qnative */
51 #define MYSELF ADRIVER_NATIVE
54 static SIGTYPE(*sighup_handler) (int sig);
55 static SIGTYPE(*sigint_handler) (int sig);
56 static SIGTYPE sighandler(int sig);
63 #define audio_open() open ("/dev/audio", (O_WRONLY | O_NONBLOCK), 0)
65 static int initialized_device_p;
66 static int reset_volume_p, reset_device_p;
67 static double old_volume;
68 static Audio_hdr dev_hdr;
72 init_device(int volume, unsigned char *data, int fd,
73 unsigned int *header_length)
86 abort(); /* one or the other */
88 if (AUDIO_SUCCESS != audio_get_play_config(audio_fd, &dev_hdr)) {
89 perror("Not a valid audio device");
93 if (AUDIO_SUCCESS != (data
94 ? audio_decode_filehdr(data, &file_hdr,
96 : audio_read_filehdr(fd, &file_hdr, 0, 0))) {
98 perror("invalid audio data");
100 perror("invalid audio file");
104 audio_flush_play(audio_fd);
106 if (!initialized_device_p || (0 != audio_cmp_hdr(&dev_hdr, &file_hdr))) {
110 initialized_device_p = 1;
111 if (AUDIO_SUCCESS != audio_set_play_config(audio_fd, &new_hdr)) {
112 char buf1[100], buf2[100], buf3[250];
113 audio_enc_to_str(&file_hdr, buf1);
114 audio_enc_to_str(&new_hdr, buf2);
115 (void)snprintf(buf3, sizeof(buf3), "wanted %s, got %s", buf1, buf2);
121 if (volume < 0 || volume > 100) {
123 int sz = sprintf(buf, sizeof(buf), "volume must be between 0 and 100 (not %d)",
125 assert(sz>=0 && sz<sizeof(buf));
130 /* set the volume; scale it to 0.0 - 1.0 */
131 double V = (volume / 100.0);
132 audio_get_play_gain(audio_fd, &old_volume);
134 audio_set_play_gain(audio_fd, &V);
141 static void reset_device(int wait_p)
144 audio_drain(audio_fd, 1);
146 audio_flush_play(audio_fd);
148 audio_set_play_config(audio_fd, &dev_hdr);
150 audio_set_play_gain(audio_fd, &old_volume);
153 void play_sound_file(char *sound_file, int volume)
156 unsigned char buf[255];
159 audio_fd = audio_open();
162 perror("open /dev/audio");
166 /* where to find the proto for signal()... */
167 sighup_handler = (SIGTYPE(*)(int))signal(SIGHUP, sighandler);
168 sigint_handler = (SIGTYPE(*)(int))signal(SIGINT, sighandler);
170 file_fd = open(sound_file, O_RDONLY, 0);
176 if (init_device(volume, (unsigned char *)0, file_fd, (unsigned int *)0))
180 rrtn = read(file_fd, (char *)buf, sizeof(buf));
189 wrtn = write(audio_fd, (char *)buf, rrtn);
197 if (AUDIO_ERR_INTERRUPTED == audio_drain(audio_fd, 1))
202 int sz = sprintf(warn_buf, sizeof(warn_buf), "play: rrtn = %d, wrtn = %d", rrtn,
204 assert(warn_buf>=0 && warn_buf<sizeof(warn_buf));
220 signal(SIGHUP, sighup_handler);
221 signal(SIGINT, sigint_handler);
224 int play_sound_data(unsigned char *data, int length, int volume)
235 /* this is just to get a better error message */
236 if (strncmp(".snd\0", (char *)data, 4)) {
237 warn("Not valid audio data (bad magic number)");
240 if (length <= sizeof(Audio_hdr)) {
241 warn("Not valid audio data (too short)");
245 audio_fd = audio_open();
249 /* where to find the proto for signal()... */
250 sighup_handler = (SIGTYPE(*)(int))signal(SIGHUP, sighandler);
251 sigint_handler = (SIGTYPE(*)(int))signal(SIGINT, sighandler);
253 if (init_device(volume, data, 0, &ilen))
257 length -= (ilen << 2);
262 wrtn = write(audio_fd, (char *)(data + start), length - start);
271 if (AUDIO_ERR_INTERRUPTED == audio_drain(audio_fd, 1))
274 if (wrtn != length) {
276 int sz = snprintf(buf, sizeof(buf),
277 "play: rrtn = %d, wrtn = %d", length, wrtn);
278 assert(sz>=0 && sz < sizeof(buf));
292 signal(SIGHUP, sighup_handler);
293 signal(SIGINT, sigint_handler);
300 /* #### sigcontext doesn't exist in Solaris. This should be updated
301 to be correct for Solaris. */
302 static SIGTYPE sighandler(int sig)
308 if (sig == SIGHUP && sighup_handler)
310 else if (sig == SIGINT && sigint_handler)
319 sound_native_audio_init(int audio_fd)
329 if (AUDIO_SUCCESS != audio_get_play_config(audio_fd, &dev_hdr)) {
330 perror("Not a valid audio device");
335 if (AUDIO_SUCCESS != (data
336 ? audio_decode_filehdr(data, &file_hdr,
338 : audio_read_filehdr(fd, &file_hdr, 0, 0))) {
340 perror("invalid audio data");
342 perror("invalid audio file");
347 audio_flush_play(audio_fd);
350 if (!initialized_device_p || (0 != audio_cmp_hdr(&dev_hdr, &file_hdr))) {
354 initialized_device_p = 1;
355 if (AUDIO_SUCCESS != audio_set_play_config(audio_fd, &new_hdr)) {
356 char buf1[100], buf2[100], buf3[250];
357 audio_enc_to_str(&file_hdr, buf1);
358 audio_enc_to_str(&new_hdr, buf2);
359 (void)snprintf(buf3, sizeof(buf3), "wanted %s, got %s", buf1, buf2);
367 if (volume < 0 || volume > 100) {
369 int sz = snprintf(buf, sizeof(buf),
370 "volume must be between 0 and 100 (not %d)",
372 assert(sz>=0 && sz<sizeof(buf));
378 /* set the volume; scale it to 0.0 - 1.0 */
379 double V = 1.0; /* (volume / 100.0); */
380 audio_get_play_gain(audio_fd, &old_volume);
382 audio_set_play_gain(audio_fd, &V);
389 int sound_native_play_stream(Lisp_Object mt)
392 mtype_audio_properties *mtap;
393 Lisp_Media_Stream *ms;
396 Lisp_Audio_Device *lad = NULL;
397 sound_native_data *saod = NULL;
411 /* unpack the media thread */
412 device = XMEDIA_THREAD(mt)->device;
413 ms = XMEDIA_STREAM(XMEDIA_THREAD(mt)->stream);
416 lad = get_audio_device(device);
417 saod = get_audio_device_data(device);
419 /* cannot use AO on incomplete or corrupt audio devices */
421 XAUDIO_DEVICE_DRIVER(device) != MYSELF)
424 /* refuse to play non-audio */
425 if (media_stream_type(ms) != MTYPE_AUDIO)
427 mtap = media_stream_type_properties(ms).aprops;
430 audio_fd = audio_open();
435 /* where to find the proto for signal()... */
436 sighup_handler = (SIGTYPE(*)(int))signal(SIGHUP, sighandler);
437 sigint_handler = (SIGTYPE(*)(int))signal(SIGINT, sighandler);
440 if (!sound_native_audio_init(audio_fd))
443 /* rewind the stream */
444 media_stream_srewind(ms)(ms);
446 /* play chunks of the stream */
447 buffer = xmalloc_atomic(SOUND_MAX_AUDIO_FRAME_SIZE+1);
448 while ((len = media_stream_sread(ms)(
449 ms, buffer, mtap->samplerate)) > 0) {
451 natlen = len * mtap->framesize;
455 if ((written = write(audio_fd, bptr, natlen)) < 0) {
456 perror("error in write");
458 } else if (written) {
462 if (AUDIO_ERR_INTERRUPTED == audio_drain(audio_fd, 1))
475 signal(SIGHUP, sighup_handler);
476 signal(SIGINT, sigint_handler);