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; p = xmalloc (sizeof (*p)); p->handle = NULL; p->hwparams = NULL; p->swparams = NULL; sd->fd = -1; sd->data = p; err = snd_pcm_open (&p->handle, file, SND_PCM_STREAM_PLAYBACK, 0); if (err < 0) alsa_sound_perror (file, err); }
static void alsa_write (struct sound_device *sd, const char *buffer, int 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; int err; while (nwritten < nbytes) { snd_pcm_uframes_t frames = (nbytes - nwritten)/fact; if (frames == 0) break; err = snd_pcm_writei (p->handle, buffer + nwritten, frames); if (err < 0) { if (err == -EPIPE) { /* under-run */ err = snd_pcm_prepare (p->handle); if (err < 0) alsa_sound_perror ("Can't recover from underrun, prepare failed", err); } else if (err == -ESTRPIPE) { while ((err = snd_pcm_resume (p->handle)) == -EAGAIN) sleep(1); /* wait until the suspend flag is released */ if (err < 0) { err = snd_pcm_prepare (p->handle); if (err < 0) alsa_sound_perror ("Can't recover from suspend, " "prepare failed", err); } } else alsa_sound_perror ("Error writing to sound device", err); } else nwritten += err * fact; } }
static void alsa_open (struct sound_device *sd) { /* Open the sound device. Default is "default". */ struct alsa_params *p = xmalloc (sizeof *p); char const *file = string_default (sd->file, DEFAULT_ALSA_SOUND_DEVICE); int err; p->handle = NULL; p->hwparams = NULL; p->swparams = NULL; sd->fd = -1; sd->data = p; err = snd_pcm_open (&p->handle, file, SND_PCM_STREAM_PLAYBACK, 0); if (err < 0) alsa_sound_perror (file, err); }
static void 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); err = snd_pcm_hw_params_malloc (&p->hwparams); if (err < 0) alsa_sound_perror ("Could not allocate hardware parameter structure", err); err = snd_pcm_sw_params_malloc (&p->swparams); if (err < 0) alsa_sound_perror ("Could not allocate software parameter structure", err); err = snd_pcm_hw_params_any (p->handle, p->hwparams); if (err < 0) alsa_sound_perror ("Could not initialize hardware parameter structure", err); 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; err = snd_pcm_hw_params_set_format (p->handle, p->hwparams, val); if (err < 0) alsa_sound_perror ("Could not set sound format", err); 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; 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) alsa_sound_perror ("Unable to get period size for playback", err); 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); err = snd_pcm_sw_params_current (p->handle, p->swparams); if (err < 0) alsa_sound_perror ("Unable to determine current swparams for playback", err); /* Start the transfer when the buffer is almost full */ err = snd_pcm_sw_params_set_start_threshold (p->handle, p->swparams, (buffer_size / p->period_size) * p->period_size); if (err < 0) alsa_sound_perror ("Unable to set start threshold mode for playback", err); /* Allow the transfer when at least period_size samples can be processed */ err = snd_pcm_sw_params_set_avail_min (p->handle, p->swparams, p->period_size); if (err < 0) alsa_sound_perror ("Unable to set avail min for playback", err); err = snd_pcm_sw_params (p->handle, p->swparams); if (err < 0) alsa_sound_perror ("Unable to set sw params for playback\n", err); snd_pcm_hw_params_free (p->hwparams); p->hwparams = NULL; snd_pcm_sw_params_free (p->swparams); p->swparams = NULL; 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; 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) { if (snd_mixer_attach (handle, file) >= 0 && snd_mixer_load (handle) >= 0 && snd_mixer_selem_register (handle, NULL, NULL) >= 0) for (e = snd_mixer_first_elem (handle); e; e = snd_mixer_elem_next (e)) { if (snd_mixer_selem_has_playback_volume (e)) { long pmin, pmax, vol; snd_mixer_selem_get_playback_volume_range (e, &pmin, &pmax); 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_mixer_close(handle); } } }