*/
/*
- *
+ *
* This is a daemon that waits for sound files to appear in a particular
* directory, and when they do, it plays them.
* Files can be WAV or OGG VORBIS
u_int length; /* samplecount */
} WaveChunkHeader;
-
#ifndef LLONG_MAX
#define LLONG_MAX 9223372036854775807LL
#endif
#define DEFAULT_FORMAT SND_PCM_FORMAT_U8
-#define DEFAULT_SPEED 8000
+#define DEFAULT_SPEED 8000
#define FORMAT_DEFAULT -1
#define FORMAT_RAW 0
#define FORMAT_UNKNOWN 9999
/* global data */
-
struct sound {
int fd;
int empty;
dir_changed = 1;
}
+static void nlog(char *m)
+{
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ printf("%d.%06d %s\n", tv.tv_sec, tv.tv_usec, m);
+ fflush(stdout);
+}
+
static void *raw_read(struct sound *s, int bytes)
{
/* Return pointer to next 'bytes' bytes in the buffer.
lseek(s->fd, bytes, SEEK_CUR);
}
-
int parse_wave(struct sound *s)
{
WaveHeader *h;
WaveChunkHeader *h;
int bytes = ((long long)msec * s->rate / 1000) * s->sample_bytes;
int len;
-
+
while (bytes) {
while (s->chunk_bytes == 0) {
h = raw_read(s, sizeof(*h));
{
}
-
snd_pcm_t *open_dev(void)
{
snd_pcm_t *handle;
int rc;
+// nlog("open device");
rc = snd_pcm_open(&handle, "default", SND_PCM_STREAM_PLAYBACK, 0/*SND_PCM_NONBLOCK*/);
if (rc < 0)
return NULL;
return handle;
}
-void dev_close(struct dev *dev);
+void dev_close(struct dev *dev, int flush);
void set_scenario(struct dev *dev, char *scenario)
{
char path[100];
return;
if (strcmp(dev->scenario, scenario) == 0)
return;
- dev_close(dev);
+ dev_close(dev, 0);
strcpy(dev->scenario, scenario);
snprintf(path, 100, "alsactl -f /data/scenarios/%s restore", scenario);
system(path);
+// nlog(path);
}
void set_params(struct dev *dev, struct sound *sound)
{
snd_pcm_hw_params_t *hwp;
+ sigset_t blocked;
if (sound->format == FORMAT_UNKNOWN)
return;
dev->rate == sound->rate)
return;
+ sigemptyset(&blocked);
+ sigaddset(&blocked, SIGIO);
+ sigprocmask(SIG_BLOCK, &blocked, NULL);
+
if (dev->pcm_format)
snd_pcm_drop(dev->handle);
snd_pcm_hw_params_set_access(dev->handle, hwp, SND_PCM_ACCESS_RW_INTERLEAVED);
snd_pcm_hw_params_set_format(dev->handle, hwp, sound->pcm_format);
snd_pcm_hw_params_set_channels(dev->handle, hwp, sound->channels);
+
snd_pcm_hw_params_set_rate(dev->handle, hwp, sound->rate, 0);
snd_pcm_hw_params_set_period_size(dev->handle, hwp,
sound->period_bytes/sound->sample_bytes, 0);
snd_pcm_hw_params_set_buffer_size(dev->handle, hwp,
- sound->period_bytes*4/sound->sample_bytes);
+ sound->period_bytes*2/sound->sample_bytes);
snd_pcm_hw_params(dev->handle, hwp);
dev->pcm_format = sound->pcm_format;
dev->channels = sound->channels;
dev->period_buf = malloc(dev->period_bytes);
dev->buf_size = dev->period_bytes;
}
+ sigprocmask(SIG_UNBLOCK, &blocked, NULL);
}
void load_some(struct dev *dev, struct sound *sound)
/* 44100, 2 seconds, 4 bytes would be 160K !!
* Doesn't work yet.
*/
- s->period_bytes = 8192;
+ s->period_bytes = 2048;
}
if (s->posn)
free(sound);
}
-
struct sound *find_match(struct list_head *list,
char *name, int ino,
int *matched)
void play_buf(struct dev *dev)
{
if (dev->present == dev->period_bytes) {
+ sigset_t blocked;
+ sigemptyset(&blocked);
+ sigaddset(&blocked, SIGIO);
+ sigprocmask(SIG_BLOCK, &blocked, NULL);
if (dev->attenuate)
scale_buf(dev);
alarm(8);
+ if(0){char b[100];sprintf(b, "write %d/%d=%d",
+ dev->period_bytes,dev->sample_bytes,
+ dev->period_bytes/dev->sample_bytes);
+
+ nlog(b);
+ }
snd_pcm_writei(dev->handle,
dev->period_buf,
dev->period_bytes / dev->sample_bytes);
alarm(0);
dev->present = 0;
+ sigprocmask(SIG_UNBLOCK, &blocked, NULL);
}
}
-void dev_close(struct dev *dev)
+void dev_close(struct dev *dev, int flush)
{
+ sigset_t blocked;
+
if (!dev->handle)
return;
+
+ sigemptyset(&blocked);
+ sigaddset(&blocked, SIGIO);
+ sigprocmask(SIG_BLOCK, &blocked, NULL);
+ if (flush) {
+// nlog("purge");
+ snd_pcm_drop(dev->handle);
+ dev->present = 0;
+ }
if (dev->present) {
memset(dev->period_buf + dev->present, 0,
dev->period_bytes - dev->present);
if (dev->attenuate)
scale_buf(dev);
+// nlog("flush last");
snd_pcm_writei(dev->handle,
dev->period_buf,
dev->period_bytes / dev->sample_bytes);
dev->present = 0;
+
+ sigprocmask(SIG_UNBLOCK, &blocked, NULL);
}
+// nlog("close");
snd_pcm_drain(dev->handle);
snd_pcm_close(dev->handle);
+// nlog("closed");
dev->handle = NULL;
+ sigprocmask(SIG_UNBLOCK, &blocked, NULL);
}
char *dir = "/var/run/sound";
scan_dir(dir, soundqueue);
if (list_empty(soundqueue)) {
- dev_close(&dev);
+ event_del(&work_ev);
+ dev_close(&dev, 1);
set_scenario(&dev, "off");
suspend_allow(suspend_handle);
last = NULL;
next = list_entry(soundqueue->next,
struct sound, list);
if (next->empty) {
- dev_close(&dev);
+ dev_close(&dev, 1);
set_scenario(&dev, next->scenario);
suspend_allow(suspend_handle);
last = next;
set_params(&dev, next);
last = next;
}
- load_some(&dev, next);
- play_buf(&dev);
if (next->eof) {
char buf[1000];
sprintf(buf, "%s/%s", dir, next->name);
+ if (dev.present) {
+ memset(dev.period_buf + dev.present, 0,
+ dev.period_bytes - dev.present);
+ dev.present = dev.period_bytes;
+ play_buf(&dev);
+ }
+ snd_pcm_drain(dev.handle);
unlink(buf);
list_del(&next->list);
close_sound(next);
do_scan(fd, ev, vp);
} else {
struct timeval tv = {0, 0};
+ load_some(&dev, next);
+ play_buf(&dev);
event_add(&work_ev, &tv);
}
}
return 1;
}
-
int main(int argc, char *argv[])
{
struct list_head soundqueue;