Hi List, as oss got obsolete in kernel 2.16 I hacked together alsa support for gtkpbbuttons. I guess it still needs some more cleanup / better error handling but I am using it since a week in everyday usage without trouble.
As it is using the 'default' device I can now finally play many audio sources simultaneously without gtkpbbuttons blocking it. To make it work, just download gtkpbbuttons 0.6.8 and replace audio.{c,h} with the ones in this file. Finally link with -lasound linken ... thats all. Soeren. -- Sometimes, there's a moment as you're waking, when you become aware of the real world around you, but you're still dreaming.
/* ---------------------------------------------------------------------------- * audio.c * funtions for play audio samples * * Copyright 2002 Matthias Grimm * * 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. * ----------------------------------------------------------------------------*/ #ifdef HAVE_CONFIG_H # include <config.h> #endif #ifdef HAVE_SOUND #include <pthread.h> #include <unistd.h> #include <fcntl.h> #include <sys/ioctl.h> #include <malloc.h> #include <linux/soundcard.h> #include <alsa/asoundlib.h> #include <audiofile.h> #include <time.h> #include "audio.h" struct sample* load_sample (char *samplename) { AFfilehandle affd; /* filehandle for soundfile from libaudiofile */ AFframecount framecount; int dummy, channels, byteorder, framesize, precision, err = 0; struct sample *sample; if ((sample = (struct sample *) malloc(sizeof(struct sample))) == NULL) return NULL; if ((affd = afOpenFile(samplename, "r", 0))) { afGetSampleFormat(affd, AF_DEFAULT_TRACK, &dummy, &precision); channels = afGetChannels(affd, AF_DEFAULT_TRACK); byteorder = afGetVirtualByteOrder(affd, AF_DEFAULT_TRACK); framesize = (int) afGetFrameSize(affd, AF_DEFAULT_TRACK, 0); framecount = afGetFrameCount(affd, AF_DEFAULT_TRACK); sample->speed = (int) afGetRate(affd, AF_DEFAULT_TRACK); if (channels <= 2) sample->channels = channels; else err = -1; if (precision == 8) sample->format = SND_PCM_FORMAT_S8; else if (precision == 16) { if (byteorder == AF_BYTEORDER_LITTLEENDIAN) sample->format = SND_PCM_FORMAT_S16_LE; else sample->format = SND_PCM_FORMAT_S16_BE; } else err = -1; if (err == 0) { sample->framesize=framesize; sample->framecount=framecount; sample->audiodatalen = framecount * framesize; if ((sample->audiodata = (char *) malloc(sample->audiodatalen))) { if ((afReadFrames(affd, AF_DEFAULT_TRACK, sample->audiodata, framecount)) != framecount) { free(sample->audiodata); err = -1; } } } afCloseFile(affd); } if (err == -1) { free(sample); return NULL; } sample->periods=sample->framesize; sample->buffersize=(sample->periods*8192)>>2; return sample; } void cleanup_audio(struct dspdata *dsp) { if (dsp->active) { pthread_mutex_destroy(&dsp->mutex); pthread_cond_destroy(&dsp->cond); } } /* This function ist the sound playing thread. */ void play_sample (void *arg) { struct dspdata *dsp = (struct dspdata *) arg; dsp->playbeep = 0; for (;;) { if (dsp->playbeep == 0) { pthread_mutex_lock(&dsp->mutex); pthread_cond_wait(&dsp->cond, &dsp->mutex); pthread_mutex_unlock(&dsp->mutex); } dsp->playbeep = 0; snd_pcm_t *pcm_handle; snd_pcm_hw_params_t *hwparams; char *pcm_name="default"; struct sample* s=dsp->sample; snd_pcm_hw_params_alloca(&hwparams); if (snd_pcm_open(&pcm_handle, pcm_name, SND_PCM_STREAM_PLAYBACK, 0) < 0) { fprintf(stderr, "Error opening PCM device %s\n", pcm_name); return; } if (snd_pcm_hw_params_any(pcm_handle, hwparams) < 0) { fprintf(stderr, "Can not configure this PCM device.\n"); return; } if (snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED) < 0) { fprintf(stderr, "Error setting access.\n"); return; } if (snd_pcm_hw_params_set_format(pcm_handle, hwparams, s->format) < 0) { fprintf(stderr, "Error setting format.\n"); return; } if (snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, &s->speed, 0) < 0) { fprintf(stderr, "Error setting rate.\n"); return; } /* Set number of channels */ if (snd_pcm_hw_params_set_channels_near(pcm_handle, hwparams, &s->channels) < 0) { fprintf(stderr, "Error setting channels.\n"); return; } /* Set number of periods. Periods used to be called fragments. */ if (snd_pcm_hw_params_set_periods_near(pcm_handle, hwparams, &s->periods, 0) < 0) { fprintf(stderr, "Error setting periods.\n"); return; } /* Set buffer size (in frames). The resulting latency is given by */ /* latency = periodsize * periods / (rate * bytes_per_frame) */ if (snd_pcm_hw_params_set_buffer_size_near(pcm_handle, hwparams, &s->buffersize) < 0) { fprintf(stderr, "Error setting buffersize.\n"); return; } /* Apply HW parameter settings to */ /* PCM device and prepare device */ if (snd_pcm_hw_params(pcm_handle, hwparams) < 0) { fprintf(stderr, "Error setting HW params.\n"); return; } int pcmreturn; /* Write num_frames frames from buffer data to */ /* the PCM device pointed to by pcm_handle. */ /* Returns the number of frames actually written. */ while ((pcmreturn = snd_pcm_writei(pcm_handle, s->audiodata, s->framecount)) < 0) { snd_pcm_prepare(pcm_handle); fprintf(stderr, "<<<<<<<<<<<<<<< Buffer Underrun >>>>>>>>>>>>>>>\n"); } /* Stop PCM device and drop pending frames */ snd_pcm_drop(pcm_handle); /* Stop PCM device after pending frames have been played */ if (snd_pcm_close(pcm_handle) < 0) { fprintf(stderr, "snd_pcm_close error\n"); return; } } pthread_exit(NULL); } /* This function wakes the sound playing thread to do * a beep. If the audio subsystem is disabled * (dsp->active = 0) it does nothing. */ void trigger_beep(struct dspdata *dsp, struct sample *sample) { if (dsp->active) /* audio subsystem active and valid? */ if ((dsp->sample = sample)) { /* is there a sample to play? */ pthread_mutex_lock(&dsp->mutex); /* ok, give me one ping */ dsp->playbeep = 1; pthread_cond_signal(&dsp->cond); pthread_mutex_unlock(&dsp->mutex); } } /* This function sets up the sound playing thread. * It starts the thread or if an error occur cleans * up all the audio stuff */ int init_sound_thread(struct dspdata *dsp) { pthread_attr_t attr; int rc = 0; dsp->maxblocksize = 0; dsp->thread = 0; pthread_mutex_init(&dsp->mutex, NULL); pthread_cond_init (&dsp->cond, NULL); pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); if ((pthread_create(&dsp->thread, &attr, play_sample, (void *) dsp)) != 0) { cleanup_audio(dsp); rc = -1; } pthread_attr_destroy(&attr); return rc; } #endif
#ifndef INCLUDE_AUDIO_H #define INCLUDE_AUDIO_H /* ---------------------------------------------------------------------------- * audio.h * prototypes and definitions for audio.c. * * Copyright 2002 Matthias Grimm * * 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. * ----------------------------------------------------------------------------*/ #ifdef HAVE_CONFIG_H # include <config.h> #endif #include <audiofile.h> #include <alsa/asoundlib.h> #define DEFAULT_AUDIO "/dev/dsp" struct dspdata { int active; /* =1, if sound system is active */ char *audiodev; int maxblocksize; int playbeep; pthread_mutex_t mutex; pthread_cond_t cond; pthread_t thread; struct sample *sample; /* sound to play */ }; struct sample { char *audiodata; int audiodatalen; int format; unsigned int channels; unsigned int speed; unsigned int framesize; int framecount; unsigned int periods; snd_pcm_uframes_t buffersize; }; /* prototypes */ struct sample* load_sample (char *samplename); void cleanup_audio(struct dspdata *dsp); void play_sample (void *arg); void trigger_beep(struct dspdata *dsp, struct sample *sample); int init_sound_thread(struct dspdata *dsp); #endif /* INCLUDE_AUDIO_H */