]> git.neil.brown.name Git - plato.git/commitdiff
sound: assorted fixes.
authorNeilBrown <neilb@suse.de>
Fri, 13 Dec 2013 10:27:46 +0000 (21:27 +1100)
committerNeilBrown <neilb@suse.de>
Fri, 13 Dec 2013 10:27:46 +0000 (21:27 +1100)
Trying to make it play the full sound, or stop promptly when requested.

sound/sound.c

index 664510e6906603fdbfe3766a6845a11841fb614b..5e36c3c634ac70ab1d5092fbb32b8ff68590c959 100644 (file)
@@ -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;