]> code.delx.au - gnu-emacs/blobdiff - src/sound.c
Avoid crashing due to closing of font whose driver pointer is NULL.
[gnu-emacs] / src / sound.c
index 6b8af3893f3d6ac4b02d087db1b6ac718bfcd1d7..f8c6b483056270996d38f5ee38232835da3f8db3 100644 (file)
@@ -1,6 +1,6 @@
 /* sound.c -- sound support.
-   Copyright (C) 1998, 1999, 2001, 2002, 2003, 2004,
-                 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc.
+
+Copyright (C) 1998-1999, 2001-2013 Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
@@ -31,7 +31,7 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
   cause an error to be generated.
 
   The Windows implementation of play-sound is implemented via the
-  Win32 API functions mciSendString, waveOutGetVolume, and
+  Windows API functions mciSendString, waveOutGetVolume, and
   waveOutSetVolume which are exported by Winmm.dll.
 */
 
@@ -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,9 +55,9 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 /* BEGIN: Non Windows Includes */
 #ifndef WINDOWSNT
 
-#ifndef MSDOS
+#include <byteswap.h>
+
 #include <sys/ioctl.h>
-#endif
 
 /* FreeBSD has machine/soundcard.h.  Voxware sound driver docs mention
    sys/soundcard.h.  So, let's try whatever's there.  */
@@ -86,8 +85,6 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 
 /* BEGIN: Windows Specific Includes */
 #include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
 #include <limits.h>
 #include <windows.h>
 #include <mmsystem.h>
@@ -99,10 +96,9 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 
 /* Symbols.  */
 
-extern Lisp_Object QCfile, QCdata;
-Lisp_Object QCvolume, QCdevice;
-Lisp_Object Qsound;
-Lisp_Object Qplay_sound_functions;
+static Lisp_Object QCvolume, QCdevice;
+static Lisp_Object Qsound;
+static Lisp_Object Qplay_sound_functions;
 
 /* Indices of attributes in a sound attributes vector.  */
 
@@ -115,24 +111,11 @@ enum sound_attr
   SOUND_ATTR_SENTINEL
 };
 
-static void alsa_sound_perror P_ ((char *, int)) NO_RETURN;
-static void sound_perror P_ ((char *)) NO_RETURN;
-static void sound_warning P_ ((char *));
-static int parse_sound P_ ((Lisp_Object, Lisp_Object *));
-
 /* END: Common Definitions */
 
 /* BEGIN: Non Windows Definitions */
 #ifndef WINDOWSNT
 
-#ifndef DEFAULT_SOUND_DEVICE
-#define DEFAULT_SOUND_DEVICE "/dev/dsp"
-#endif
-#ifndef DEFAULT_ALSA_SOUND_DEVICE
-#define DEFAULT_ALSA_SOUND_DEVICE "default"
-#endif
-
-
 /* Structure forward declarations.  */
 
 struct sound;
@@ -200,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;
@@ -225,25 +208,25 @@ struct sound_device
   int channels;
 
   /* Open device SD.  */
-  void (* open) P_ ((struct sound_device *sd));
+  void (* open) (struct sound_device *sd);
 
   /* Close device SD.  */
-  void (* close) P_ ((struct sound_device *sd));
+  void (* close) (struct sound_device *sd);
 
-  /* Configure SD accoring to device-dependent parameters.  */
-  void (* configure) P_ ((struct sound_device *device));
+  /* Configure SD according to device-dependent parameters.  */
+  void (* configure) (struct sound_device *device);
 
   /* Choose a device-dependent format for outputting sound S.  */
-  void (* choose_format) P_ ((struct sound_device *sd,
-                             struct sound *s));
+  void (* choose_format) (struct sound_device *sd,
+                          struct sound *s);
 
   /* Return a preferred data size in bytes to be sent to write (below)
      each time.  2048 is used if this is NULL.  */
-  int (* period_size) P_ ((struct sound_device *sd));
+  ptrdiff_t (* period_size) (struct sound_device *sd);
 
   /* Write NYBTES bytes from BUFFER to device SD.  */
-  void (* write) P_ ((struct sound_device *sd, const char *buffer,
-                     int nbytes));
+  void (* write) (struct sound_device *sd, const char *buffer,
+                  ptrdiff_t nbytes);
 
   /* A place for devices to store additional data.  */
   void *data;
@@ -271,7 +254,7 @@ struct sound
      read from the start of a sound file.  */
   char *header;
 
-  /* Number of bytes raed from sound file.  This is always <=
+  /* Number of bytes read from sound file.  This is always <=
      MAX_SOUND_HEADER_BYTES.  */
   int header_size;
 
@@ -279,41 +262,28 @@ struct sound
   Lisp_Object data;
 
   /* Play sound file S on device SD.  */
-  void (* play) P_ ((struct sound *s, struct sound_device *sd));
+  void (* play) (struct sound *s, struct sound_device *sd);
 };
 
 /* These are set during `play-sound-internal' so that sound_cleanup has
    access to them.  */
 
-struct sound_device *current_sound_device;
-struct sound *current_sound;
+static struct sound_device *current_sound_device;
+static struct sound *current_sound;
 
 /* Function prototypes.  */
 
-static void vox_open P_ ((struct sound_device *));
-static void vox_configure P_ ((struct sound_device *));
-static void vox_close P_ ((struct sound_device *sd));
-static void vox_choose_format P_ ((struct sound_device *, struct sound *));
-static int vox_init P_ ((struct sound_device *));
-static void vox_write P_ ((struct sound_device *, const char *, int));
-static void find_sound_type P_ ((struct sound *));
-static u_int32_t le2hl P_ ((u_int32_t));
-static u_int16_t le2hs P_ ((u_int16_t));
-static u_int32_t be2hl P_ ((u_int32_t));
-static int wav_init P_ ((struct sound *));
-static void wav_play P_ ((struct sound *, struct sound_device *));
-static int au_init P_ ((struct sound *));
-static void au_play P_ ((struct sound *, struct sound_device *));
-
-#if 0 /* Currently not used.  */
-static u_int16_t be2hs P_ ((u_int16_t));
-#endif
+static void vox_write (struct sound_device *, const char *, ptrdiff_t);
+static bool wav_init (struct sound *);
+static void wav_play (struct sound *, struct sound_device *);
+static bool au_init (struct sound *);
+static void au_play (struct sound *, struct sound_device *);
 
 /* END: Non Windows Definitions */
 #else /* WINDOWSNT */
 
 /* BEGIN: Windows Specific Definitions */
-static int do_play_sound P_ ((const char *, unsigned long));
+static int do_play_sound (const char *, unsigned long);
 /*
   END: Windows Specific Definitions */
 #endif /* WINDOWSNT */
@@ -327,15 +297,19 @@ static int do_play_sound P_ ((const char *, unsigned long));
 
 /* Like perror, but signals an error.  */
 
-static void
-sound_perror (msg)
-     char *msg;
+static _Noreturn void
+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));
@@ -347,10 +321,9 @@ sound_perror (msg)
 /* Display a warning message.  */
 
 static void
-sound_warning (msg)
-     char *msg;
+sound_warning (const char *msg)
 {
-  message (msg);
+  message1 (msg);
 }
 
 
@@ -380,10 +353,8 @@ sound_warning (msg)
    VOL must be an integer in the range [0, 100], or a float in the
    range [0, 1].  */
 
-static int
-parse_sound (sound, attrs)
-     Lisp_Object sound;
-     Lisp_Object *attrs;
+static bool
+parse_sound (Lisp_Object sound, Lisp_Object *attrs)
 {
   /* SOUND must be a list starting with the symbol `sound'.  */
   if (!CONSP (sound) || !EQ (XCAR (sound), Qsound))
@@ -448,32 +419,37 @@ parse_sound (sound, 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.  */
 
 static void
-find_sound_type (s)
-     struct sound *s;
+find_sound_type (struct sound *s)
 {
   if (!wav_init (s) && !au_init (s))
     error ("Unknown sound format");
 }
 
 
-/* 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 (arg)
-     Lisp_Object arg;
+static void
+sound_cleanup (void)
 {
   if (current_sound_device->close)
     current_sound_device->close (current_sound_device);
   if (current_sound->fd > 0)
     emacs_close (current_sound->fd);
-  free (current_sound_device);
-  free (current_sound);
-
-  return Qnil;
+  xfree (current_sound_device);
+  xfree (current_sound);
 }
 
 /***********************************************************************
@@ -484,12 +460,10 @@ sound_cleanup (arg)
    to host byte-order.  */
 
 static u_int32_t
-le2hl (value)
-     u_int32_t value;
+le2hl (u_int32_t value)
 {
-#ifdef WORDS_BIG_ENDIAN
-  unsigned char *p = (unsigned char *) &value;
-  value = p[0] + (p[1] << 8) + (p[2] << 16) + (p[3] << 24);
+#ifdef WORDS_BIGENDIAN
+  value = bswap_32 (value);
 #endif
   return value;
 }
@@ -499,12 +473,10 @@ le2hl (value)
    to host byte-order.  */
 
 static u_int16_t
-le2hs (value)
-     u_int16_t value;
+le2hs (u_int16_t value)
 {
-#ifdef WORDS_BIG_ENDIAN
-  unsigned char *p = (unsigned char *) &value;
-  value = p[0] + (p[1] << 8);
+#ifdef WORDS_BIGENDIAN
+  value = bswap_16 (value);
 #endif
   return value;
 }
@@ -514,35 +486,14 @@ le2hs (value)
    to host byte-order.  */
 
 static u_int32_t
-be2hl (value)
-     u_int32_t value;
-{
-#ifndef WORDS_BIG_ENDIAN
-  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 (value)
-     u_int16_t value;
+be2hl (u_int32_t value)
 {
-#ifndef WORDS_BIG_ENDIAN
-  unsigned char *p = (unsigned char *) &value;
-  value = p[1] + (p[0] << 8);
+#ifndef WORDS_BIGENDIAN
+  value = bswap_32 (value);
 #endif
   return value;
 }
 
-#endif /* 0 */
-
 /***********************************************************************
                          RIFF-WAVE (*.wav)
  ***********************************************************************/
@@ -551,16 +502,15 @@ be2hs (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
-wav_init (s)
-     struct sound *s;
+static bool
+wav_init (struct sound *s)
 {
   struct wav_header *header = (struct wav_header *) s->header;
 
   if (s->header_size < sizeof *header
-      || bcmp (s->header, "RIFF", 4) != 0)
+      || memcmp (s->header, "RIFF", 4) != 0)
     return 0;
 
   /* WAV files are in little-endian order.  Convert the header
@@ -590,9 +540,7 @@ wav_init (s)
 /* Play RIFF-WAVE audio file S on sound device SD.  */
 
 static void
-wav_play (s, sd)
-     struct sound *s;
-     struct sound_device *sd;
+wav_play (struct sound *s, struct sound_device *sd)
 {
   struct wav_header *header = (struct wav_header *) s->header;
 
@@ -612,16 +560,16 @@ wav_play (s, sd)
      files I found so far.  If someone feels inclined to implement the
      whole RIFF-WAVE spec, please do.  */
   if (STRINGP (s->data))
-    sd->write (sd, SDATA (s->data) + sizeof *header,
+    sd->write (sd, SSDATA (s->data) + sizeof *header,
               SBYTES (s->data) - sizeof *header);
   else
     {
       char *buffer;
-      int nbytes;
-      int blksize = sd->period_size ? sd->period_size (sd) : 2048;
-      int data_left = header->data_length;
+      ptrdiff_t nbytes = 0;
+      ptrdiff_t blksize = sd->period_size ? sd->period_size (sd) : 2048;
+      ptrdiff_t data_left = header->data_length;
 
-      buffer = (char *) alloca (blksize);
+      buffer = alloca (blksize);
       lseek (s->fd, sizeof *header, SEEK_SET);
       while (data_left > 0
              && (nbytes = emacs_read (s->fd, buffer, blksize)) > 0)
@@ -662,16 +610,15 @@ 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
-au_init (s)
-     struct sound *s;
+static bool
+au_init (struct sound *s)
 {
   struct au_header *header = (struct au_header *) s->header;
 
   if (s->header_size < sizeof *header
-      || bcmp (s->header, ".snd", 4) != 0)
+      || memcmp (s->header, ".snd", 4) != 0)
     return 0;
 
   header->magic_number = be2hl (header->magic_number);
@@ -692,9 +639,7 @@ au_init (s)
 /* Play Sun audio file S on sound device SD.  */
 
 static void
-au_play (s, sd)
-     struct sound *s;
-     struct sound_device *sd;
+au_play (struct sound *s, struct sound_device *sd)
 {
   struct au_header *header = (struct au_header *) s->header;
 
@@ -706,19 +651,19 @@ au_play (s, sd)
   sd->configure (sd);
 
   if (STRINGP (s->data))
-    sd->write (sd, SDATA (s->data) + header->data_offset,
+    sd->write (sd, SSDATA (s->data) + header->data_offset,
               SBYTES (s->data) - header->data_offset);
   else
     {
-      int blksize = sd->period_size ? sd->period_size (sd) : 2048;
+      ptrdiff_t blksize = sd->period_size ? sd->period_size (sd) : 2048;
       char *buffer;
-      int nbytes;
+      ptrdiff_t nbytes;
 
       /* Seek */
       lseek (s->fd, header->data_offset, SEEK_SET);
 
       /* Copy sound data to the device.  */
-      buffer = (char *) alloca (blksize);
+      buffer = alloca (blksize);
       while ((nbytes = emacs_read (s->fd, buffer, blksize)) > 0)
        sd->write (sd, buffer, nbytes);
 
@@ -736,21 +681,14 @@ au_play (s, 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 (sd)
-     struct sound_device *sd;
+vox_open (struct sound_device *sd)
 {
-  char *file;
-
-  /* Open the sound device.  Default is /dev/dsp.  */
-  if (sd->file)
-    file = sd->file;
-  else
-    file = DEFAULT_SOUND_DEVICE;
-
+  /* Open the sound device (eg /dev/dsp).  */
+  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);
@@ -760,19 +698,23 @@ vox_open (sd)
 /* Configure device SD from parameters in it.  */
 
 static void
-vox_configure (sd)
-     struct sound_device *sd;
+vox_configure (struct sound_device *sd)
 {
   int val;
+#ifdef USABLE_SIGIO
+  sigset_t blocked;
+#endif
 
-  xassert (sd->fd >= 0);
+  eassert (sd->fd >= 0);
 
   /* 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.  */
   turn_on_atimers (0);
-#ifdef SIGIO
-  sigblock (sigmask (SIGIO));
+#ifdef USABLE_SIGIO
+  sigemptyset (&blocked);
+  sigaddset (&blocked, SIGIO);
+  pthread_sigmask (SIG_BLOCK, &blocked, 0);
 #endif
 
   val = sd->format;
@@ -805,8 +747,8 @@ vox_configure (sd)
     }
 
   turn_on_atimers (1);
-#ifdef SIGIO
-  sigunblock (sigmask (SIGIO));
+#ifdef USABLE_SIGIO
+  pthread_sigmask (SIG_UNBLOCK, &blocked, 0);
 #endif
 }
 
@@ -814,16 +756,18 @@ vox_configure (sd)
 /* Close device SD if it is open.  */
 
 static void
-vox_close (sd)
-     struct sound_device *sd;
+vox_close (struct sound_device *sd)
 {
   if (sd->fd >= 0)
     {
       /* 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;
+      sigemptyset (&blocked);
+      sigaddset (&blocked, SIGIO);
+      pthread_sigmask (SIG_BLOCK, &blocked, 0);
 #endif
       turn_on_atimers (0);
 
@@ -831,8 +775,8 @@ vox_close (sd)
       ioctl (sd->fd, SNDCTL_DSP_SYNC, NULL);
 
       turn_on_atimers (1);
-#ifdef SIGIO
-      sigunblock (sigmask (SIGIO));
+#ifdef USABLE_SIGIO
+      pthread_sigmask (SIG_UNBLOCK, &blocked, 0);
 #endif
 
       /* Close the device.  */
@@ -845,9 +789,7 @@ vox_close (sd)
 /* Choose device-dependent format for device SD from sound file S.  */
 
 static void
-vox_choose_format (sd, s)
-     struct sound_device *sd;
-     struct sound *s;
+vox_choose_format (struct sound_device *sd, struct sound *s)
 {
   if (s->type == RIFF)
     {
@@ -882,26 +824,19 @@ vox_choose_format (sd, s)
        }
     }
   else
-    abort ();
+    emacs_abort ();
 }
 
 
 /* Initialize device SD.  Set up the interface functions in the device
    structure.  */
 
-static int
-vox_init (sd)
-     struct sound_device *sd;
+static bool
+vox_init (struct sound_device *sd)
 {
-  char *file;
-  int fd;
-
-  /* Open the sound device.  Default is /dev/dsp.  */
-  if (sd->file)
-    file = sd->file;
-  else
-    file = DEFAULT_SOUND_DEVICE;
-  fd = emacs_open (file, O_WRONLY, 0);
+  /* Open the sound device (eg /dev/dsp).  */
+  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
@@ -921,13 +856,9 @@ vox_init (sd)
 /* Write NBYTES bytes from BUFFER to device SD.  */
 
 static void
-vox_write (sd, buffer, nbytes)
-     struct sound_device *sd;
-     const char *buffer;
-     int nbytes;
+vox_write (struct sound_device *sd, const char *buffer, ptrdiff_t nbytes)
 {
-  int nwritten = emacs_write (sd->fd, buffer, nbytes);
-  if (nwritten < 0)
+  if (emacs_write_sig (sd->fd, buffer, nbytes) != nbytes)
     sound_perror ("Error writing to sound device");
 }
 
@@ -938,10 +869,12 @@ vox_write (sd, buffer, nbytes)
 
 /* This driver is available on GNU/Linux. */
 
-static void
-alsa_sound_perror (msg, err)
-     char *msg;
-     int err;
+#ifndef DEFAULT_ALSA_SOUND_DEVICE
+#define DEFAULT_ALSA_SOUND_DEVICE "default"
+#endif
+
+static _Noreturn void
+alsa_sound_perror (const char *msg, int err)
 {
   error ("%s: %s", msg, snd_strerror (err));
 }
@@ -954,24 +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 (sd)
-     struct sound_device *sd;
+alsa_open (struct sound_device *sd)
 {
-  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;
@@ -985,9 +911,8 @@ alsa_open (sd)
     alsa_sound_perror (file, err);
 }
 
-static int
-alsa_period_size (sd)
-       struct sound_device *sd;
+static ptrdiff_t
+alsa_period_size (struct sound_device *sd)
 {
   struct alsa_params *p = (struct alsa_params *) sd->data;
   int fact = snd_pcm_format_size (sd->format, 1) * sd->channels;
@@ -995,15 +920,14 @@ alsa_period_size (sd)
 }
 
 static void
-alsa_configure (sd)
-     struct sound_device *sd;
+alsa_configure (struct sound_device *sd)
 {
   int val, err, dir;
   unsigned uval;
   struct alsa_params *p = (struct alsa_params *) sd->data;
   snd_pcm_uframes_t buffer_size;
 
-  xassert (p->handle != 0);
+  eassert (p->handle != 0);
 
   err = snd_pcm_hw_params_malloc (&p->hwparams);
   if (err < 0)
@@ -1048,7 +972,7 @@ alsa_configure (sd)
 
   err = snd_pcm_hw_params_get_buffer_size (p->hwparams, &buffer_size);
   if (err < 0)
-    alsa_sound_perror("Unable to get buffer size for playback", err);
+    alsa_sound_perror ("Unable to get buffer size for playback", err);
 
   err = snd_pcm_sw_params_current (p->handle, p->swparams);
   if (err < 0)
@@ -1085,10 +1009,10 @@ alsa_configure (sd)
       int chn;
       snd_mixer_t *handle;
       snd_mixer_elem_t *e;
-      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)
@@ -1106,7 +1030,7 @@ alsa_configure (sd)
                       snd_mixer_selem_set_playback_volume (e, chn, vol);
                   }
               }
-          snd_mixer_close(handle);
+          snd_mixer_close (handle);
         }
     }
 }
@@ -1115,8 +1039,7 @@ alsa_configure (sd)
 /* Close device SD if it is open.  */
 
 static void
-alsa_close (sd)
-     struct sound_device *sd;
+alsa_close (struct sound_device *sd)
 {
   struct alsa_params *p = (struct alsa_params *) sd->data;
   if (p)
@@ -1130,18 +1053,15 @@ alsa_close (sd)
           snd_pcm_drain (p->handle);
           snd_pcm_close (p->handle);
         }
-      free (p);
+      xfree (p);
     }
 }
 
 /* Choose device-dependent format for device SD from sound file S.  */
 
 static void
-alsa_choose_format (sd, s)
-     struct sound_device *sd;
-     struct sound *s;
+alsa_choose_format (struct sound_device *sd, struct sound *s)
 {
-  struct alsa_params *p = (struct alsa_params *) sd->data;
   if (s->type == RIFF)
     {
       struct wav_header *h = (struct wav_header *) s->header;
@@ -1187,23 +1107,20 @@ alsa_choose_format (sd, s)
        }
     }
   else
-    abort ();
+    emacs_abort ();
 }
 
 
 /* Write NBYTES bytes from BUFFER to device SD.  */
 
 static void
-alsa_write (sd, buffer, nbytes)
-     struct sound_device *sd;
-     const char *buffer;
-     int nbytes;
+alsa_write (struct sound_device *sd, const char *buffer, ptrdiff_t nbytes)
 {
   struct alsa_params *p = (struct alsa_params *) sd->data;
 
   /* The the third parameter to snd_pcm_writei is frames, not bytes. */
   int fact = snd_pcm_format_size (sd->format, 1) * sd->channels;
-  int nwritten = 0;
+  ptrdiff_t nwritten = 0;
   int err;
 
   while (nwritten < nbytes)
@@ -1224,7 +1141,7 @@ alsa_write (sd, buffer, nbytes)
           else if (err == -ESTRPIPE)
             {
               while ((err = snd_pcm_resume (p->handle)) == -EAGAIN)
-                sleep(1);      /* wait until the suspend flag is released */
+                sleep (1);     /* wait until the suspend flag is released */
               if (err < 0)
                 {
                   err = snd_pcm_prepare (p->handle);
@@ -1244,32 +1161,22 @@ alsa_write (sd, buffer, nbytes)
 }
 
 static void
-snd_error_quiet (file, line, function, err, fmt)
-     const char *file;
-     int line;
-     const char *function;
-     int err;
-     const char *fmt;
+snd_error_quiet (const char *file, int line, const char *function, int err,
+                const char *fmt)
 {
 }
 
 /* Initialize device SD.  Set up the interface functions in the device
    structure.  */
 
-static int
-alsa_init (sd)
-     struct sound_device *sd;
+static bool
+alsa_init (struct sound_device *sd)
 {
-  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);
@@ -1307,9 +1214,7 @@ alsa_init (sd)
   }
 
 static int
-do_play_sound (psz_file, ui_volume)
-     const char *psz_file;
-     unsigned long ui_volume;
+do_play_sound (const char *psz_file, unsigned long ui_volume)
 {
   int i_result = 0;
   MCIERROR mci_error = 0;
@@ -1394,11 +1299,10 @@ DEFUN ("play-sound-internal", Fplay_sound_internal, Splay_sound_internal, 1, 1,
        doc: /* Play sound SOUND.
 
 Internal use only, use `play-sound' instead.  */)
-     (sound)
-     Lisp_Object sound;
+  (Lisp_Object sound)
 {
   Lisp_Object attrs[SOUND_ATTR_SENTINEL];
-  int count = SPECPDL_INDEX ();
+  ptrdiff_t count = SPECPDL_INDEX ();
 
 #ifndef WINDOWSNT
   Lisp_Object file;
@@ -1410,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.  */
@@ -1420,17 +1323,15 @@ Internal use only, use `play-sound' instead.  */)
 #ifndef WINDOWSNT
   file = Qnil;
   GCPRO2 (sound, file);
-  current_sound_device = (struct sound_device *) xmalloc (sizeof (struct sound_device));
-  bzero (current_sound_device, sizeof (struct sound_device));
-  current_sound = (struct sound *) xmalloc (sizeof (struct sound));
-  bzero (current_sound, sizeof (struct sound));
-  record_unwind_protect (sound_cleanup, Qnil);
-  current_sound->header = (char *) alloca (MAX_SOUND_HEADER_BYTES);
+  current_sound_device = xzalloc (sizeof *current_sound_device);
+  current_sound = xzalloc (sizeof *current_sound);
+  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),
+      current_sound->fd = openp (list1 (Vdata_directory),
                                 attrs[SOUND_FILE], Qnil, &file, Qnil);
       if (current_sound->fd < 0)
        sound_perror ("Could not open sound file");
@@ -1446,19 +1347,15 @@ Internal use only, use `play-sound' instead.  */)
     {
       current_sound->data = attrs[SOUND_DATA];
       current_sound->header_size = min (MAX_SOUND_HEADER_BYTES, SBYTES (current_sound->data));
-      bcopy (SDATA (current_sound->data), current_sound->header, current_sound->header_size);
+      memcpy (current_sound->header, SDATA (current_sound->data),
+             current_sound->header_size);
     }
 
   /* Find out the type of sound.  Give up if we can't tell.  */
   find_sound_type (current_sound);
 
   /* Set up a device.  */
-  if (STRINGP (attrs[SOUND_DEVICE]))
-    {
-      int len = SCHARS (attrs[SOUND_DEVICE]);
-      current_sound_device->file = (char *) alloca (len + 1);
-      strcpy (current_sound_device->file, SDATA (attrs[SOUND_DEVICE]));
-    }
+  current_sound_device->file = attrs[SOUND_DEVICE];
 
   if (INTEGERP (attrs[SOUND_VOLUME]))
     current_sound_device->volume = XFASTINT (attrs[SOUND_VOLUME]);
@@ -1488,7 +1385,7 @@ Internal use only, use `play-sound' instead.  */)
 
   lo_file = Fexpand_file_name (attrs[SOUND_FILE], Qnil);
   len = XSTRING (lo_file)->size;
-  psz_file = (char *) alloca (len + 1);
+  psz_file = alloca (len + 1);
   strcpy (psz_file, XSTRING (lo_file)->data);
   if (INTEGERP (attrs[SOUND_VOLUME]))
     {
@@ -1496,7 +1393,7 @@ Internal use only, use `play-sound' instead.  */)
     }
   else if (FLOATP (attrs[SOUND_VOLUME]))
     {
-      ui_volume_tmp = (unsigned long) XFLOAT_DATA (attrs[SOUND_VOLUME]) * 100;
+      ui_volume_tmp = XFLOAT_DATA (attrs[SOUND_VOLUME]) * 100;
     }
   /*
     Based on some experiments I have conducted, a value of 100 or less
@@ -1511,7 +1408,7 @@ 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 */
 
@@ -1524,27 +1421,14 @@ Internal use only, use `play-sound' instead.  */)
  ***********************************************************************/
 
 void
-syms_of_sound ()
+syms_of_sound (void)
 {
-  QCdevice = intern_c_string(":device");
-  staticpro (&QCdevice);
-  QCvolume = intern_c_string (":volume");
-  staticpro (&QCvolume);
-  Qsound = intern_c_string ("sound");
-  staticpro (&Qsound);
-  Qplay_sound_functions = intern_c_string ("play-sound-functions");
-  staticpro (&Qplay_sound_functions);
+  DEFSYM (QCdevice, ":device");
+  DEFSYM (QCvolume, ":volume");
+  DEFSYM (Qsound, "sound");
+  DEFSYM (Qplay_sound_functions, "play-sound-functions");
 
   defsubr (&Splay_sound_internal);
 }
 
-
-void
-init_sound ()
-{
-}
-
 #endif /* HAVE_SOUND */
-
-/* arch-tag: dd850ad8-0433-4e2c-9cba-b7aeeccc0dbd
-   (do not change this comment) */