From 5414dfd4356e63634f1a4e94382d14e200759d18 Mon Sep 17 00:00:00 2001 From: Andre Noll Date: Tue, 15 Apr 2014 13:18:45 +0000 Subject: [PATCH] oss: Introduce sound device lock. Unlike ALSA with dmix, the OSS driver allows only a single opener of the sound device at any given time. With para_audiod it may happen that the writer of the buffer tree for the next audio file tries to open the device while the old writer is still active. If this happens, the second writer fails to open the device which causes the whole buffer tree to be aborted. This patch serializes access to the OSS sound device by adding a locking mechanism to oss_write.c. Since audiod is single threaded this is rather simple: The lock is taken in oss_post_select() when the device is opened. It is released in oss_close() after the file descriptor has been closed. --- oss_write.c | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/oss_write.c b/oss_write.c index d4bfd446..5b910742 100644 --- a/oss_write.c +++ b/oss_write.c @@ -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(); } /* @@ -174,12 +198,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); -- 2.39.2