[PATCH] gtkpbbuttons alsa support
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 */
Reply to: