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 sprintf(buf3, "wanted %s, got %s", buf1, buf2);
121 if (volume < 0 || volume > 100) {
123 sprintf(buf, "volume must be between 0 and 100 (not %d)",
129 /* set the volume; scale it to 0.0 - 1.0 */
130 double V = (volume / 100.0);
131 audio_get_play_gain(audio_fd, &old_volume);
133 audio_set_play_gain(audio_fd, &V);
140 static void reset_device(int wait_p)
143 audio_drain(audio_fd, 1);
145 audio_flush_play(audio_fd);
147 audio_set_play_config(audio_fd, &dev_hdr);
149 audio_set_play_gain(audio_fd, &old_volume);
152 void play_sound_file(char *sound_file, int volume)
155 unsigned char buf[255];
158 audio_fd = audio_open();
161 perror("open /dev/audio");
165 /* where to find the proto for signal()... */
166 sighup_handler = (SIGTYPE(*)(int))signal(SIGHUP, sighandler);
167 sigint_handler = (SIGTYPE(*)(int))signal(SIGINT, sighandler);
169 file_fd = open(sound_file, O_RDONLY, 0);
175 if (init_device(volume, (unsigned char *)0, file_fd, (unsigned int *)0))
179 rrtn = read(file_fd, (char *)buf, sizeof(buf));
188 wrtn = write(audio_fd, (char *)buf, rrtn);
196 if (AUDIO_ERR_INTERRUPTED == audio_drain(audio_fd, 1))
201 sprintf(warn_buf, "play: rrtn = %d, wrtn = %d", rrtn,
218 signal(SIGHUP, sighup_handler);
219 signal(SIGINT, sigint_handler);
222 int play_sound_data(unsigned char *data, int length, int volume)
233 /* this is just to get a better error message */
234 if (strncmp(".snd\0", (char *)data, 4)) {
235 warn("Not valid audio data (bad magic number)");
238 if (length <= sizeof(Audio_hdr)) {
239 warn("Not valid audio data (too short)");
243 audio_fd = audio_open();
247 /* where to find the proto for signal()... */
248 sighup_handler = (SIGTYPE(*)(int))signal(SIGHUP, sighandler);
249 sigint_handler = (SIGTYPE(*)(int))signal(SIGINT, sighandler);
251 if (init_device(volume, data, 0, &ilen))
255 length -= (ilen << 2);
260 wrtn = write(audio_fd, (char *)(data + start), length - start);
269 if (AUDIO_ERR_INTERRUPTED == audio_drain(audio_fd, 1))
272 if (wrtn != length) {
274 sprintf(buf, "play: rrtn = %d, wrtn = %d", length, wrtn);
288 signal(SIGHUP, sighup_handler);
289 signal(SIGINT, sigint_handler);
296 /* #### sigcontext doesn't exist in Solaris. This should be updated
297 to be correct for Solaris. */
298 static SIGTYPE sighandler(int sig)
304 if (sig == SIGHUP && sighup_handler)
306 else if (sig == SIGINT && sigint_handler)
315 sound_native_audio_init(int audio_fd)
325 if (AUDIO_SUCCESS != audio_get_play_config(audio_fd, &dev_hdr)) {
326 perror("Not a valid audio device");
331 if (AUDIO_SUCCESS != (data
332 ? audio_decode_filehdr(data, &file_hdr,
334 : audio_read_filehdr(fd, &file_hdr, 0, 0))) {
336 perror("invalid audio data");
338 perror("invalid audio file");
343 audio_flush_play(audio_fd);
346 if (!initialized_device_p || (0 != audio_cmp_hdr(&dev_hdr, &file_hdr))) {
350 initialized_device_p = 1;
351 if (AUDIO_SUCCESS != audio_set_play_config(audio_fd, &new_hdr)) {
352 char buf1[100], buf2[100], buf3[250];
353 audio_enc_to_str(&file_hdr, buf1);
354 audio_enc_to_str(&new_hdr, buf2);
355 sprintf(buf3, "wanted %s, got %s", buf1, buf2);
363 if (volume < 0 || volume > 100) {
365 sprintf(buf, "volume must be between 0 and 100 (not %d)",
372 /* set the volume; scale it to 0.0 - 1.0 */
373 double V = 1.0; /* (volume / 100.0); */
374 audio_get_play_gain(audio_fd, &old_volume);
376 audio_set_play_gain(audio_fd, &V);
383 int sound_native_play_stream(Lisp_Object mt)
386 mtype_audio_properties *mtap;
387 Lisp_Media_Stream *ms;
390 Lisp_Audio_Device *lad = NULL;
391 sound_native_data *saod = NULL;
405 /* unpack the media thread */
406 device = XMEDIA_THREAD(mt)->device;
407 ms = XMEDIA_STREAM(XMEDIA_THREAD(mt)->stream);
410 lad = get_audio_device(device);
411 saod = get_audio_device_data(device);
413 /* cannot use AO on incomplete or corrupt audio devices */
415 XAUDIO_DEVICE_DRIVER(device) != MYSELF)
418 /* refuse to play non-audio */
419 if (media_stream_type(ms) != MTYPE_AUDIO)
421 mtap = media_stream_type_properties(ms).aprops;
424 audio_fd = audio_open();
429 /* where to find the proto for signal()... */
430 sighup_handler = (SIGTYPE(*)(int))signal(SIGHUP, sighandler);
431 sigint_handler = (SIGTYPE(*)(int))signal(SIGINT, sighandler);
434 if (!sound_native_audio_init(audio_fd))
437 /* rewind the stream */
438 media_stream_srewind(ms)(ms);
440 /* play chunks of the stream */
441 buffer = xmalloc_atomic(SOUND_MAX_AUDIO_FRAME_SIZE+1);
442 while ((len = media_stream_sread(ms)(
443 ms, buffer, mtap->samplerate)) > 0) {
445 natlen = len * mtap->framesize;
449 if ((written = write(audio_fd, bptr, natlen)) < 0) {
450 perror("error in write");
452 } else if (written) {
456 if (AUDIO_ERR_INTERRUPTED == audio_drain(audio_fd, 1))
469 signal(SIGHUP, sighup_handler);
470 signal(SIGINT, sigint_handler);