From 653a63f1cd3574eb6420532b71cca4c8235dbea9 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Fri, 13 Dec 2013 21:27:46 +1100 Subject: [PATCH] sound: assorted fixes. Trying to make it play the full sound, or stop promptly when requested. --- sound/sound.c | 83 ++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 65 insertions(+), 18 deletions(-) diff --git a/sound/sound.c b/sound/sound.c index 664510e..5e36c3c 100644 --- a/sound/sound.c +++ b/sound/sound.c @@ -7,7 +7,7 @@ */ /* - * + * * 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 @@ -104,13 +104,12 @@ typedef struct { 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 @@ -121,7 +120,6 @@ typedef struct { #define FORMAT_UNKNOWN 9999 /* global data */ - struct sound { int fd; int empty; @@ -171,6 +169,14 @@ void handle_change(int sig) 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. @@ -220,7 +226,6 @@ static void raw_skip(struct sound *s, int bytes) lseek(s->fd, bytes, SEEK_CUR); } - int parse_wave(struct sound *s) { WaveHeader *h; @@ -331,7 +336,7 @@ void seek_wave(struct sound *s, int msec) 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)); @@ -416,12 +421,12 @@ static void seek_vorbis(struct sound *s, int msec) { } - 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; @@ -429,7 +434,7 @@ snd_pcm_t *open_dev(void) 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]; @@ -437,15 +442,17 @@ void set_scenario(struct dev *dev, char *scenario) 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; @@ -461,6 +468,10 @@ void set_params(struct dev *dev, struct sound *sound) dev->rate == sound->rate) return; + sigemptyset(&blocked); + sigaddset(&blocked, SIGIO); + sigprocmask(SIG_BLOCK, &blocked, NULL); + if (dev->pcm_format) snd_pcm_drop(dev->handle); @@ -469,11 +480,12 @@ void set_params(struct dev *dev, struct sound *sound) 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; @@ -486,6 +498,7 @@ void set_params(struct dev *dev, struct sound *sound) 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) @@ -597,7 +610,7 @@ struct sound *open_sound(char *dir, char *name, int ino) /* 44100, 2 seconds, 4 bytes would be 160K !! * Doesn't work yet. */ - s->period_bytes = 8192; + s->period_bytes = 2048; } if (s->posn) @@ -626,7 +639,6 @@ void close_sound(struct sound *sound) free(sound); } - struct sound *find_match(struct list_head *list, char *name, int ino, int *matched) @@ -722,34 +734,62 @@ static void scale_buf(struct dev *dev) 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"; @@ -769,7 +809,8 @@ static void do_scan(int fd, short ev, void *vp) 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; @@ -778,7 +819,7 @@ static void do_scan(int fd, short ev, void *vp) 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; @@ -808,17 +849,24 @@ static void do_work(int fd, short ev, void *vp) 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); } } @@ -833,7 +881,6 @@ static int suspend(void *vp) return 1; } - int main(int argc, char *argv[]) { struct list_head soundqueue; -- 2.39.5