/* sound.c -- sound support.
Copyright (C) 1998, 1999, 2001, 2002, 2003, 2004,
- 2005, 2006 Free Software Foundation, Inc.
+ 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
This file is part of GNU Emacs.
GNU Emacs is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
+the Free Software Foundation; either version 3, or (at your option)
any later version.
GNU Emacs is distributed in the hope that it will be useful,
#include <soundcard.h>
#endif
#ifdef HAVE_ALSA
+#ifdef ALSA_SUBDIR_INCLUDE
+#include <alsa/asoundlib.h>
+#else
#include <asoundlib.h>
-#endif
+#endif /* ALSA_SUBDIR_INCLUDE */
+#endif /* HAVE_ALSA */
/* END: Non Windows Includes */
SOUND_ATTR_SENTINEL
};
-static void sound_perror P_ ((char *));
+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 *));
char *buffer;
int nbytes;
int blksize = sd->period_size ? sd->period_size (sd) : 2048;
+ int data_left = header->data_length;
buffer = (char *) alloca (blksize);
lseek (s->fd, sizeof *header, SEEK_SET);
-
- while ((nbytes = emacs_read (s->fd, buffer, blksize)) > 0)
- sd->write (sd, buffer, nbytes);
+ while (data_left > 0
+ && (nbytes = emacs_read (s->fd, buffer, blksize)) > 0)
+ {
+ /* Don't play possible garbage at the end of file */
+ if (data_left < nbytes) nbytes = data_left;
+ data_left -= nbytes;
+ sd->write (sd, buffer, nbytes);
+ }
if (nbytes < 0)
sound_perror ("Error reading sound file");
sd->data = p;
- if ((err = snd_pcm_open (&p->handle, file, SND_PCM_STREAM_PLAYBACK, 0)) < 0)
+ err = snd_pcm_open (&p->handle, file, SND_PCM_STREAM_PLAYBACK, 0);
+ if (err < 0)
alsa_sound_perror (file, err);
}
struct sound_device *sd;
{
struct alsa_params *p = (struct alsa_params *) sd->data;
- return p->period_size;
+ int fact = snd_pcm_format_size (sd->format, 1) * sd->channels;
+ return p->period_size * (fact > 0 ? fact : 1);
}
static void
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);
- if ((err = snd_pcm_hw_params_malloc (&p->hwparams)) < 0)
+ err = snd_pcm_hw_params_malloc (&p->hwparams);
+ if (err < 0)
alsa_sound_perror ("Could not allocate hardware parameter structure", err);
- if ((err = snd_pcm_sw_params_malloc (&p->swparams)) < 0)
+ err = snd_pcm_sw_params_malloc (&p->swparams);
+ if (err < 0)
alsa_sound_perror ("Could not allocate software parameter structure", err);
- if ((err = snd_pcm_hw_params_any (p->handle, p->hwparams)) < 0)
+ err = snd_pcm_hw_params_any (p->handle, p->hwparams);
+ if (err < 0)
alsa_sound_perror ("Could not initialize hardware parameter structure", err);
- if ((err = snd_pcm_hw_params_set_access (p->handle, p->hwparams,
- SND_PCM_ACCESS_RW_INTERLEAVED)) < 0)
+ err = snd_pcm_hw_params_set_access (p->handle, p->hwparams,
+ SND_PCM_ACCESS_RW_INTERLEAVED);
+ if (err < 0)
alsa_sound_perror ("Could not set access type", err);
val = sd->format;
- if ((err = snd_pcm_hw_params_set_format (p->handle, p->hwparams, val)) < 0)
+ err = snd_pcm_hw_params_set_format (p->handle, p->hwparams, val);
+ if (err < 0)
alsa_sound_perror ("Could not set sound format", err);
- val = sd->sample_rate;
- if ((err = snd_pcm_hw_params_set_rate_near (p->handle, p->hwparams, &val, 0))
- < 0)
+ uval = sd->sample_rate;
+ err = snd_pcm_hw_params_set_rate_near (p->handle, p->hwparams, &uval, 0);
+ if (err < 0)
alsa_sound_perror ("Could not set sample rate", err);
-
+
val = sd->channels;
- if ((err = snd_pcm_hw_params_set_channels (p->handle, p->hwparams, val)) < 0)
+ err = snd_pcm_hw_params_set_channels (p->handle, p->hwparams, val);
+ if (err < 0)
alsa_sound_perror ("Could not set channel count", err);
+ err = snd_pcm_hw_params (p->handle, p->hwparams);
+ if (err < 0)
+ alsa_sound_perror ("Could not set parameters", err);
+
err = snd_pcm_hw_params_get_period_size (p->hwparams, &p->period_size, &dir);
if (err < 0)
if (err < 0)
alsa_sound_perror("Unable to get buffer size for playback", err);
- if ((err = snd_pcm_hw_params (p->handle, p->hwparams)) < 0)
- alsa_sound_perror ("Could not set parameters", err);
-
err = snd_pcm_sw_params_current (p->handle, p->swparams);
if (err < 0)
alsa_sound_perror ("Unable to determine current swparams for playback",
p->hwparams = NULL;
snd_pcm_sw_params_free (p->swparams);
p->swparams = NULL;
-
- if ((err = snd_pcm_prepare (p->handle)) < 0)
+
+ err = snd_pcm_prepare (p->handle);
+ if (err < 0)
alsa_sound_perror ("Could not prepare audio interface for use", err);
-
+
if (sd->volume > 0)
{
int chn;
long pmin, pmax;
snd_mixer_selem_get_playback_volume_range (e, &pmin, &pmax);
long vol = pmin + (sd->volume * (pmax - pmin)) / 100;
-
+
for (chn = 0; chn <= SND_MIXER_SCHN_LAST; chn++)
snd_mixer_selem_set_playback_volume (e, chn, vol);
}
snd_pcm_sw_params_free (p->swparams);
if (p->handle)
{
- snd_pcm_drain(p->handle);
+ snd_pcm_drain (p->handle);
snd_pcm_close (p->handle);
}
free (p);
while (nwritten < nbytes)
{
- if ((err = snd_pcm_writei (p->handle,
- buffer + nwritten,
- (nbytes - nwritten)/fact)) < 0)
+ snd_pcm_uframes_t frames = (nbytes - nwritten)/fact;
+ if (frames == 0) break;
+
+ err = snd_pcm_writei (p->handle, buffer + nwritten, frames);
+ if (err < 0)
{
- fprintf(stderr, "Err %d/%s\n", err, snd_strerror(err));
if (err == -EPIPE)
{ /* under-run */
err = snd_pcm_prepare (p->handle);
err);
}
}
- else
+ else
alsa_sound_perror ("Error writing to sound device", err);
-
+
}
else
nwritten += err * fact;
err = snd_pcm_open (&handle, file, SND_PCM_STREAM_PLAYBACK, 0);
snd_lib_error_set_handler (NULL);
if (err < 0)
- return 0;
+ return 0;
+ snd_pcm_close (handle);
sd->fd = -1;
sd->open = alsa_open;
DEFUN ("play-sound-internal", Fplay_sound_internal, Splay_sound_internal, 1, 1, 0,
doc: /* Play sound SOUND.
-Internal use only, use `play-sound' instead.\n */)
+Internal use only, use `play-sound' instead. */)
(sound)
Lisp_Object sound;
{