Merge branch 't/sound_device_lock'
authorAndre Noll <maan@tuebingen.mpg.de>
Sun, 23 Nov 2014 16:06:04 +0000 (17:06 +0100)
committerAndre Noll <maan@tuebingen.mpg.de>
Sun, 23 Nov 2014 16:07:21 +0000 (17:07 +0100)
Cooking since 2014-09-22.

* t/sound_device_lock:
  oss: Avoid sound artefacts on some setups.
  oss: Introduce sound device lock.
  audiod: Invalidate current audio format on close.

NEWS
audiod.c
oss_write.c

diff --git a/NEWS b/NEWS
index 305d9147b2f0be1a3f02697be4a769fed2024449..82e0f0d5b495b1eb4badfd19407cb30a5d35a18b 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -11,6 +11,7 @@ NEWS
        - New sender subcommand: status.
        - Improved help text for server and afs commands.
        - audiod memory leak fixes.
+       - oss_writer improvements.
 
 Download: ./releases/paraslash-git.tar.bz2
 
index d9df3847b61c1ff93f7fcf8389ccb90baadff17e..f8eeccee395a0a01a0fdd512e0449433c5b0da93 100644 (file)
--- a/audiod.c
+++ b/audiod.c
@@ -390,6 +390,7 @@ static void close_receiver(int slot_num)
        task_reap(&s->receiver_node->task);
        free(s->receiver_node);
        s->receiver_node = NULL;
+       stat_task->current_audio_format_num = -1;
        tv_add(now, &(struct timeval)EMBRACE(0, 200 * 1000),
                &a->restart_barrier);
 }
index d4bfd446ab845ef1b381201bccf091fadfae96c0..35f7b6280115ec53bf88d5f2e303e34f8cc45d98 100644 (file)
@@ -31,6 +31,29 @@ struct private_oss_write_data {
        int bytes_per_frame;
 };
 
+/*
+ * We keep one bit of static storage to make sure only one instance of the oss
+ * writer is running at any given time.
+ */
+static bool sound_device_busy;
+
+static bool sound_device_is_busy(void)
+{
+       return sound_device_busy;
+}
+
+static void set_sound_device_busy(void)
+{
+       assert(!sound_device_busy);
+       sound_device_busy = true;
+}
+
+static void set_sound_device_idle(void)
+{
+       assert(sound_device_busy);
+       sound_device_busy = false;
+}
+
 static int get_oss_format(enum sample_format sf)
 {
        switch (sf) {
@@ -50,7 +73,7 @@ static void oss_pre_select(struct sched *s, void *context)
        struct private_oss_write_data *powd = wn->private_data;
        int ret = btr_node_status(wn->btrn, wn->min_iqs, BTR_NT_LEAF);
 
-       if (ret == 0)
+       if (ret == 0 || (sound_device_is_busy() && !powd))
                return;
        if (ret < 0 || !powd)
                return sched_min_delay(s);
@@ -65,6 +88,7 @@ static void oss_close(struct writer_node *wn)
                return;
        close(powd->fd);
        free(powd);
+       set_sound_device_idle();
 }
 
 /*
@@ -165,6 +189,7 @@ static int oss_post_select(__a_unused struct sched *s, void *context)
        size_t frames, bytes;
        int ret;
        char *data;
+       audio_buf_info abi;
 
        ret = task_get_notification(wn->task);
        if (ret < 0)
@@ -174,12 +199,16 @@ static int oss_post_select(__a_unused struct sched *s, void *context)
                goto out;
        if (!powd) {
                int32_t rate, ch, format;
+
+               if (sound_device_is_busy())
+                       return 0;
                get_btr_sample_rate(btrn, &rate);
                get_btr_channels(btrn, &ch);
                get_btr_sample_format(btrn, &format);
                ret = oss_init(wn, rate, ch, format);
                if (ret < 0)
                        goto out;
+               set_sound_device_busy();
                return 0;
        }
        btr_merge(btrn, wn->min_iqs);
@@ -192,6 +221,15 @@ static int oss_post_select(__a_unused struct sched *s, void *context)
        ret = 0;
        if (!FD_ISSET(powd->fd, &s->wfds))
                goto out;
+       /* get maximal number of bytes that can be written */
+       ret = ioctl(powd->fd, SNDCTL_DSP_GETOSPACE, &abi);
+       if (ret >= 0) {
+               size_t max_frames = abi.bytes / powd->bytes_per_frame;
+               if (max_frames == 0)
+                       goto out;
+               /* cap number of frames to avoid sound artefacts */
+               frames = PARA_MIN(frames, max_frames);
+       }
        ret = xwrite(powd->fd, data, frames * powd->bytes_per_frame);
        if (ret < 0)
                goto out;