use dynwind_begin and dynwind_end
[bpt/emacs.git] / src / sound.c
index d20fa5e..ad51c73 100644 (file)
@@ -1,6 +1,6 @@
 /* sound.c -- sound support.
 
-Copyright (C) 1998-1999, 2001-2012 Free Software Foundation, Inc.
+Copyright (C) 1998-1999, 2001-2014 Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
@@ -44,11 +44,10 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #include <unistd.h>
 #include <sys/types.h>
 #include <errno.h>
-#include <setjmp.h>
+
 #include "lisp.h"
 #include "dispextern.h"
 #include "atimer.h"
-#include <signal.h>
 #include "syssignal.h"
 /* END: Common Includes */
 
@@ -56,6 +55,8 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 /* BEGIN: Non Windows Includes */
 #ifndef WINDOWSNT
 
+#include <byteswap.h>
+
 #include <sys/ioctl.h>
 
 /* FreeBSD has machine/soundcard.h.  Voxware sound driver docs mention
@@ -182,8 +183,8 @@ struct au_header
 
 struct sound_device
 {
-  /* The name of the device or null meaning use a default device name.  */
-  char *file;
+  /* If a string, the name of the device; otherwise use a default.  */
+  Lisp_Object file;
 
   /* File descriptor of the device.  */
   int fd;
@@ -272,25 +273,12 @@ static struct sound *current_sound;
 
 /* Function prototypes.  */
 
-static void vox_open (struct sound_device *);
-static void vox_configure (struct sound_device *);
-static void vox_close (struct sound_device *sd);
-static void vox_choose_format (struct sound_device *, struct sound *);
-static int vox_init (struct sound_device *);
 static void vox_write (struct sound_device *, const char *, ptrdiff_t);
-static void find_sound_type (struct sound *);
-static u_int32_t le2hl (u_int32_t);
-static u_int16_t le2hs (u_int16_t);
-static u_int32_t be2hl (u_int32_t);
-static int wav_init (struct sound *);
+static bool wav_init (struct sound *);
 static void wav_play (struct sound *, struct sound_device *);
-static int au_init (struct sound *);
+static bool au_init (struct sound *);
 static void au_play (struct sound *, struct sound_device *);
 
-#if 0 /* Currently not used.  */
-static u_int16_t be2hs (u_int16_t);
-#endif
-
 /* END: Non Windows Definitions */
 #else /* WINDOWSNT */
 
@@ -315,8 +303,13 @@ sound_perror (const char *msg)
   int saved_errno = errno;
 
   turn_on_atimers (1);
-#ifdef SIGIO
-  sigunblock (sigmask (SIGIO));
+#ifdef USABLE_SIGIO
+  {
+    sigset_t unblocked;
+    sigemptyset (&unblocked);
+    sigaddset (&unblocked, SIGIO);
+    pthread_sigmask (SIG_UNBLOCK, &unblocked, 0);
+  }
 #endif
   if (saved_errno != 0)
     error ("%s: %s", msg, strerror (saved_errno));
@@ -330,7 +323,7 @@ sound_perror (const char *msg)
 static void
 sound_warning (const char *msg)
 {
-  message ("%s", msg);
+  message1 (msg);
 }
 
 
@@ -360,7 +353,7 @@ sound_warning (const char *msg)
    VOL must be an integer in the range [0, 100], or a float in the
    range [0, 1].  */
 
-static int
+static bool
 parse_sound (Lisp_Object sound, Lisp_Object *attrs)
 {
   /* SOUND must be a list starting with the symbol `sound'.  */
@@ -426,6 +419,15 @@ parse_sound (Lisp_Object sound, Lisp_Object *attrs)
 /* BEGIN: Non Windows functions */
 #ifndef WINDOWSNT
 
+/* Return S's value as a string if S is a string, otherwise DEFAULT_VALUE.  */
+
+static char const *
+string_default (Lisp_Object s, char const *default_value)
+{
+  return STRINGP (s) ? SSDATA (s) : default_value;
+}
+
+
 /* Find out the type of the sound file whose file descriptor is FD.
    S is the sound file structure to fill in.  */
 
@@ -437,10 +439,10 @@ find_sound_type (struct sound *s)
 }
 
 
-/* Function installed by play-sound-internal with record_unwind_protect.  */
+/* Function installed by play-sound-internal with record_unwind_protect_void.  */
 
-static Lisp_Object
-sound_cleanup (Lisp_Object arg)
+static void
+sound_cleanup (void)
 {
   if (current_sound_device->close)
     current_sound_device->close (current_sound_device);
@@ -448,8 +450,6 @@ sound_cleanup (Lisp_Object arg)
     emacs_close (current_sound->fd);
   xfree (current_sound_device);
   xfree (current_sound);
-
-  return Qnil;
 }
 
 /***********************************************************************
@@ -463,8 +463,7 @@ static u_int32_t
 le2hl (u_int32_t value)
 {
 #ifdef WORDS_BIGENDIAN
-  unsigned char *p = (unsigned char *) &value;
-  value = p[0] + (p[1] << 8) + (p[2] << 16) + (p[3] << 24);
+  value = bswap_32 (value);
 #endif
   return value;
 }
@@ -477,8 +476,7 @@ static u_int16_t
 le2hs (u_int16_t value)
 {
 #ifdef WORDS_BIGENDIAN
-  unsigned char *p = (unsigned char *) &value;
-  value = p[0] + (p[1] << 8);
+  value = bswap_16 (value);
 #endif
   return value;
 }
@@ -491,30 +489,11 @@ static u_int32_t
 be2hl (u_int32_t value)
 {
 #ifndef WORDS_BIGENDIAN
-  unsigned char *p = (unsigned char *) &value;
-  value = p[3] + (p[2] << 8) + (p[1] << 16) + (p[0] << 24);
-#endif
-  return value;
-}
-
-
-#if 0 /* Currently not used.  */
-
-/* Convert 16-bit value VALUE which is in big-endian byte-order
-   to host byte-order.  */
-
-static u_int16_t
-be2hs (u_int16_t value)
-{
-#ifndef WORDS_BIGENDIAN
-  unsigned char *p = (unsigned char *) &value;
-  value = p[1] + (p[0] << 8);
+  value = bswap_32 (value);
 #endif
   return value;
 }
 
-#endif /* 0 */
-
 /***********************************************************************
                          RIFF-WAVE (*.wav)
  ***********************************************************************/
@@ -523,9 +502,9 @@ be2hs (u_int16_t value)
    contains the first MAX_SOUND_HEADER_BYTES number of bytes from the
    sound file.  If the file is a WAV-format file, set up interface
    functions in S and convert header fields to host byte-order.
-   Value is non-zero if the file is a WAV file.  */
+   Value is true if the file is a WAV file.  */
 
-static int
+static bool
 wav_init (struct sound *s)
 {
   struct wav_header *header = (struct wav_header *) s->header;
@@ -631,9 +610,9 @@ enum au_encoding
    contains the first MAX_SOUND_HEADER_BYTES number of bytes from the
    sound file.  If the file is a AU-format file, set up interface
    functions in S and convert header fields to host byte-order.
-   Value is non-zero if the file is an AU file.  */
+   Value is true if the file is an AU file.  */
 
-static int
+static bool
 au_init (struct sound *s)
 {
   struct au_header *header = (struct au_header *) s->header;
@@ -702,20 +681,14 @@ au_play (struct sound *s, struct sound_device *sd)
    has a compatible own driver aka Luigi's driver.  */
 
 
-/* Open device SD.  If SD->file is non-null, open that device,
+/* Open device SD.  If SD->file is a string, open that device,
    otherwise use a default device name.  */
 
 static void
 vox_open (struct sound_device *sd)
 {
-  const char *file;
-
   /* Open the sound device (eg /dev/dsp).  */
-  if (sd->file)
-    file = sd->file;
-  else
-    file = DEFAULT_SOUND_DEVICE;
-
+  char const *file = string_default (sd->file, DEFAULT_SOUND_DEVICE);
   sd->fd = emacs_open (file, O_WRONLY, 0);
   if (sd->fd < 0)
     sound_perror (file);
@@ -728,6 +701,9 @@ static void
 vox_configure (struct sound_device *sd)
 {
   int val;
+#ifdef USABLE_SIGIO
+  sigset_t oldset, blocked;
+#endif
 
   eassert (sd->fd >= 0);
 
@@ -735,8 +711,10 @@ vox_configure (struct sound_device *sd)
      interrupted by a signal.  Block the ones we know to cause
      troubles.  */
   turn_on_atimers (0);
-#ifdef SIGIO
-  sigblock (sigmask (SIGIO));
+#ifdef USABLE_SIGIO
+  sigemptyset (&blocked);
+  sigaddset (&blocked, SIGIO);
+  pthread_sigmask (SIG_BLOCK, &blocked, &oldset);
 #endif
 
   val = sd->format;
@@ -769,8 +747,8 @@ vox_configure (struct sound_device *sd)
     }
 
   turn_on_atimers (1);
-#ifdef SIGIO
-  sigunblock (sigmask (SIGIO));
+#ifdef USABLE_SIGIO
+  pthread_sigmask (SIG_SETMASK, &oldset, 0);
 #endif
 }
 
@@ -785,8 +763,11 @@ vox_close (struct sound_device *sd)
       /* On GNU/Linux, it seems that the device driver doesn't like to
         be interrupted by a signal.  Block the ones we know to cause
         troubles.  */
-#ifdef SIGIO
-      sigblock (sigmask (SIGIO));
+#ifdef USABLE_SIGIO
+      sigset_t blocked, oldset;
+      sigemptyset (&blocked);
+      sigaddset (&blocked, SIGIO);
+      pthread_sigmask (SIG_BLOCK, &blocked, &oldset);
 #endif
       turn_on_atimers (0);
 
@@ -794,8 +775,8 @@ vox_close (struct sound_device *sd)
       ioctl (sd->fd, SNDCTL_DSP_SYNC, NULL);
 
       turn_on_atimers (1);
-#ifdef SIGIO
-      sigunblock (sigmask (SIGIO));
+#ifdef USABLE_SIGIO
+      pthread_sigmask (SIG_SETMASK, &oldset, 0);
 #endif
 
       /* Close the device.  */
@@ -850,18 +831,12 @@ vox_choose_format (struct sound_device *sd, struct sound *s)
 /* Initialize device SD.  Set up the interface functions in the device
    structure.  */
 
-static int
+static bool
 vox_init (struct sound_device *sd)
 {
-  const char *file;
-  int fd;
-
   /* Open the sound device (eg /dev/dsp).  */
-  if (sd->file)
-    file = sd->file;
-  else
-    file = DEFAULT_SOUND_DEVICE;
-  fd = emacs_open (file, O_WRONLY, 0);
+  char const *file = string_default (sd->file, DEFAULT_SOUND_DEVICE);
+  int fd = emacs_open (file, O_WRONLY, 0);
   if (fd >= 0)
     emacs_close (fd);
   else
@@ -883,7 +858,7 @@ vox_init (struct sound_device *sd)
 static void
 vox_write (struct sound_device *sd, const char *buffer, ptrdiff_t nbytes)
 {
-  if (emacs_write (sd->fd, buffer, nbytes) != nbytes)
+  if (emacs_write_sig (sd->fd, buffer, nbytes) != nbytes)
     sound_perror ("Error writing to sound device");
 }
 
@@ -912,23 +887,17 @@ struct alsa_params
   snd_pcm_uframes_t period_size;
 };
 
-/* Open device SD.  If SD->file is non-null, open that device,
+/* Open device SD.  If SD->file is a string, open that device,
    otherwise use a default device name.  */
 
 static void
 alsa_open (struct sound_device *sd)
 {
-  const char *file;
-  struct alsa_params *p;
-  int err;
-
   /* Open the sound device.  Default is "default".  */
-  if (sd->file)
-    file = sd->file;
-  else
-    file = DEFAULT_ALSA_SOUND_DEVICE;
+  struct alsa_params *p = xmalloc (sizeof *p);
+  char const *file = string_default (sd->file, DEFAULT_ALSA_SOUND_DEVICE);
+  int err;
 
-  p = xmalloc (sizeof *p);
   p->handle = NULL;
   p->hwparams = NULL;
   p->swparams = NULL;
@@ -1040,10 +1009,10 @@ alsa_configure (struct sound_device *sd)
       int chn;
       snd_mixer_t *handle;
       snd_mixer_elem_t *e;
-      const char *file = sd->file ? sd->file : DEFAULT_ALSA_SOUND_DEVICE;
-
       if (snd_mixer_open (&handle, 0) >= 0)
         {
+         char const *file = string_default (sd->file,
+                                            DEFAULT_ALSA_SOUND_DEVICE);
           if (snd_mixer_attach (handle, file) >= 0
               && snd_mixer_load (handle) >= 0
               && snd_mixer_selem_register (handle, NULL, NULL) >= 0)
@@ -1200,19 +1169,14 @@ snd_error_quiet (const char *file, int line, const char *function, int err,
 /* Initialize device SD.  Set up the interface functions in the device
    structure.  */
 
-static int
+static bool
 alsa_init (struct sound_device *sd)
 {
-  const char *file;
+  /* Open the sound device.  Default is "default".  */
+  char const *file = string_default (sd->file, DEFAULT_ALSA_SOUND_DEVICE);
   snd_pcm_t *handle;
   int err;
 
-  /* Open the sound device.  Default is "default".  */
-  if (sd->file)
-    file = sd->file;
-  else
-    file = DEFAULT_ALSA_SOUND_DEVICE;
-
   snd_lib_error_set_handler ((snd_lib_error_handler_t) snd_error_quiet);
   err = snd_pcm_open (&handle, file, SND_PCM_STREAM_PLAYBACK, 0);
   snd_lib_error_set_handler (NULL);
@@ -1338,7 +1302,7 @@ Internal use only, use `play-sound' instead.  */)
   (Lisp_Object sound)
 {
   Lisp_Object attrs[SOUND_ATTR_SENTINEL];
-  ptrdiff_t count = SPECPDL_INDEX ();
+  dynwind_begin ();
 
 #ifndef WINDOWSNT
   Lisp_Object file;
@@ -1350,7 +1314,6 @@ Internal use only, use `play-sound' instead.  */)
   char * psz_file = NULL;
   unsigned long ui_volume_tmp = UINT_MAX;
   unsigned long ui_volume = UINT_MAX;
-  int i_result = 0;
 #endif /* WINDOWSNT */
 
   /* Parse the sound specification.  Give up if it is invalid.  */
@@ -1362,14 +1325,14 @@ Internal use only, use `play-sound' instead.  */)
   GCPRO2 (sound, file);
   current_sound_device = xzalloc (sizeof *current_sound_device);
   current_sound = xzalloc (sizeof *current_sound);
-  record_unwind_protect (sound_cleanup, Qnil);
+  record_unwind_protect_void (sound_cleanup);
   current_sound->header = alloca (MAX_SOUND_HEADER_BYTES);
 
   if (STRINGP (attrs[SOUND_FILE]))
     {
       /* Open the sound file.  */
-      current_sound->fd = openp (Fcons (Vdata_directory, Qnil),
-                                attrs[SOUND_FILE], Qnil, &file, Qnil);
+      current_sound->fd = openp (list1 (Vdata_directory),
+                                attrs[SOUND_FILE], Qnil, &file, Qnil, false);
       if (current_sound->fd < 0)
        sound_perror ("Could not open sound file");
 
@@ -1392,12 +1355,7 @@ Internal use only, use `play-sound' instead.  */)
   find_sound_type (current_sound);
 
   /* Set up a device.  */
-  if (STRINGP (attrs[SOUND_DEVICE]))
-    {
-      int len = SCHARS (attrs[SOUND_DEVICE]);
-      current_sound_device->file = alloca (len + 1);
-      strcpy (current_sound_device->file, SSDATA (attrs[SOUND_DEVICE]));
-    }
+  current_sound_device->file = attrs[SOUND_DEVICE];
 
   if (INTEGERP (attrs[SOUND_VOLUME]))
     current_sound_device->volume = XFASTINT (attrs[SOUND_VOLUME]);
@@ -1450,11 +1408,11 @@ Internal use only, use `play-sound' instead.  */)
     {
       ui_volume = ui_volume_tmp * (UINT_MAX / 100);
     }
-  i_result = do_play_sound (psz_file, ui_volume);
+  do_play_sound (psz_file, ui_volume);
 
 #endif /* WINDOWSNT */
 
-  unbind_to (count, Qnil);
+  dynwind_end ();
   return Qnil;
 }
 \f
@@ -1465,12 +1423,12 @@ Internal use only, use `play-sound' instead.  */)
 void
 syms_of_sound (void)
 {
+#include "sound.x"
+
   DEFSYM (QCdevice, ":device");
   DEFSYM (QCvolume, ":volume");
   DEFSYM (Qsound, "sound");
   DEFSYM (Qplay_sound_functions, "play-sound-functions");
-
-  defsubr (&Splay_sound_internal);
 }
 
 #endif /* HAVE_SOUND */