/* ALSA test program based on pcsx-r ALSA plugin. */ /*************************************************************************** * * * This program 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 of the License, or * * (at your option) any later version. See also the license.txt file for * * additional informations. * * * ***************************************************************************/ #define ALSA_PCM_NEW_HW_PARAMS_API #define ALSA_PCM_NEW_SW_PARAMS_API #include #include static snd_pcm_t *handle = NULL; static snd_pcm_uframes_t buffer_size; // SETUP SOUND void SetupSound (void) { snd_pcm_hw_params_t *hwparams; snd_pcm_status_t *status; unsigned int pspeed; int pchannels = 2; int format; int err; pspeed = 44100; format = SND_PCM_FORMAT_S16; if ((err = snd_pcm_open (&handle, "default", SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK)) < 0) { printf ("Audio open error: %s\n", snd_strerror (err)); return; } if ((err = snd_pcm_nonblock (handle, 0)) < 0) { printf ("Can't set blocking moded: %s\n", snd_strerror (err)); return; } snd_pcm_hw_params_alloca (&hwparams); if ((err = snd_pcm_hw_params_any (handle, hwparams)) < 0) { printf ("Broken configuration for this PCM: %s\n", snd_strerror (err)); return; } if ((err = snd_pcm_hw_params_set_access (handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) { printf ("Access type not available: %s\n", snd_strerror (err)); return; } if ((err = snd_pcm_hw_params_set_format (handle, hwparams, format)) < 0) { printf ("Sample format not available: %s\n", snd_strerror (err)); return; } if ((err = snd_pcm_hw_params_set_channels (handle, hwparams, pchannels)) < 0) { printf ("Channels count not available: %s\n", snd_strerror (err)); return; } if ((err = snd_pcm_hw_params_set_rate_near (handle, hwparams, &pspeed, 0)) < 0) { printf ("Rate not available: %s\n", snd_strerror (err)); return; } if ((err = snd_pcm_hw_params (handle, hwparams)) < 0) { printf ("Unable to install hw params: %s\n", snd_strerror (err)); return; } snd_pcm_status_alloca (&status); if ((err = snd_pcm_status (handle, status)) < 0) { printf ("Unable to get status: %s\n", snd_strerror (err)); return; } buffer_size = snd_pcm_status_get_avail (status); printf ("ALSA buffer size: %d\n", buffer_size); } // REMOVE SOUND void RemoveSound (void) { if (handle != NULL) { snd_pcm_drop (handle); snd_pcm_close (handle); handle = NULL; } } unsigned long SoundGetFreeBuffers (void) { signed long l; if (handle == NULL) // failed to open? return 0; l = snd_pcm_avail_update (handle); if (l < 0) { if (snd_pcm_state (handle) == SND_PCM_STATE_XRUN) { snd_pcm_prepare (handle); //snd_pcm_recover (handle, -EPIPE, 0); return 0; } else { printf ("some other unrelated error happened, that we don't care about\n"); exit (0); } } return l; } // FEED SOUND DATA void SoundFeedStreamData (unsigned char *pSound, long samples) { if (handle == NULL) return; if (snd_pcm_state (handle) == SND_PCM_STATE_XRUN) { snd_pcm_prepare (handle); //snd_pcm_recover (handle, -EPIPE, 0); } snd_pcm_writei (handle, pSound, samples); } int main (int argc, char *argv[]) { #define BUFLEN 100 signed short data[BUFLEN]; int i; for (i = 0; i < BUFLEN; i++) data[i] = 64.0 * 256.0 * sin ((3.14159 * 2.0 * i) / 441); SetupSound (); while (1) { if ((i = SoundGetFreeBuffers ()) > (BUFLEN/2)) { // buffer has enough room for another block of samples SoundFeedStreamData ((unsigned char *) data, BUFLEN/2); } else { //printf ("buffer has only %d free buffers\n", i); } usleep (5000); // sleep 5000 microsecond // this loop should run 200 times per second // delivering up to (200*BUFLEN/2) samples per second // rate is 44100. buffer length is 33791 // (200*BUFLEN/2) = 10000 // Therefore it causes a buffer underrun approx 200 // times per second } RemoveSound (); }