From: Andre Noll Date: Sun, 25 Nov 2012 13:00:08 +0000 (+0100) Subject: Merge branch 't/osx_writer_improvements' X-Git-Tag: v0.4.12~8 X-Git-Url: http://git.tuebingen.mpg.de/?p=paraslash.git;a=commitdiff_plain;h=107d4619b3a6a8bdc1a85c8021cb1951244e7626;hp=00583bed658c70aacf2a94532904fd403c5ee7f1 Merge branch 't/osx_writer_improvements' Cooking since 2012-10-30. 9eaa22 osx_write: Check return value of AudioOutputUnitStart(). 831db3 osx_write: Be careful when dereferencing the private_data pointer. 97902a osx: Treat writer node as an internal buffer tree node. 1c6fa9 osx_write: Add big fat comment on callback btr node. --- diff --git a/NEWS b/NEWS index 2c05b8f9..69372cc4 100644 --- a/NEWS +++ b/NEWS @@ -8,6 +8,7 @@ - Overhaul of the build system: All generated files are now written to the "build" directory. - The modular mixer API and the alsa mixer. + - Minor fixes for the osx writer. -------------------------------------- 0.4.11 (2012-07-20) "mutual diversity" diff --git a/osx_write.c b/osx_write.c index 8dcfb4cd..2894f11e 100644 --- a/osx_write.c +++ b/osx_write.c @@ -43,9 +43,28 @@ struct private_osx_write_data { unsigned sample_format; /** Number of channels of the current audio stream. */ unsigned channels; - /** Serializes access to buffer tree nodes. */ + /** + * Serializes access to buffer tree nodes between the writer and + * the callback which runs in a different thread. + */ int mutex; - /** The btr node of the callback. */ + /** + * The btr node of the callback. + * + * Although access to the btr node is serialized between the writer and + * the callback via the above mutex, this does not stop other buffer + * tree nodes, for example the decoder, to race against the osx + * callback. + * + * However, since all operations on buffer tree nodes are local in the + * sense that they only affect one level in the buffer tree (i.e. + * parent or child nodes, but not the grandparent or the + * grandchildren), we may work around this problem by using another + * buffer tree node for the callback. + * + * The writer grabs the mutex in its post_select method and pushes down + * the buffers to the callback node. + */ struct btr_node *callback_btrn; }; @@ -59,10 +78,14 @@ static OSStatus osx_callback(void *cb_arg, __a_unused AudioUnitRenderActionFlags { int i; struct writer_node *wn = cb_arg; - struct private_osx_write_data *powd = wn->private_data; + struct private_osx_write_data *powd; size_t samples_have, samples_want = 0; + powd = wn->private_data; mutex_lock(powd->mutex); + powd = wn->private_data; + if (!powd || !wn->btrn) + goto out; /* * We fill with zeros if no data was yet written and we do not have * enough to fill all buffers. @@ -266,7 +289,7 @@ static void osx_write_pre_select(struct sched *s, struct task *t) } mutex_lock(powd->mutex); - ret = btr_node_status(wn->btrn, wn->min_iqs, BTR_NT_LEAF); + ret = btr_node_status(wn->btrn, wn->min_iqs, BTR_NT_INTERNAL); if (ret < 0) drain_delay_nec = need_drain_delay(powd); mutex_unlock(powd->mutex); @@ -295,25 +318,32 @@ static void osx_write_post_select(__a_unused struct sched *s, struct task *t) if (ret < 0) goto remove_btrn; powd = wn->private_data; - AudioOutputUnitStart(powd->audio_unit); + ret = -E_UNIT_START; + if (AudioOutputUnitStart(powd->audio_unit) != noErr) { + AudioUnitUninitialize(powd->audio_unit); + CloseComponent(powd->audio_unit); + btr_remove_node(&powd->callback_btrn); + goto remove_btrn; + } } mutex_lock(powd->mutex); - btr_pushdown(btrn); - ret = btr_node_status(btrn, wn->min_iqs, BTR_NT_LEAF); + ret = btr_node_status(btrn, wn->min_iqs, BTR_NT_INTERNAL); + if (ret > 0) + btr_pushdown(btrn); if (ret < 0 && need_drain_delay(powd)) ret = 0; - mutex_unlock(powd->mutex); - - if (ret >= 0) - goto out; + if (ret >= 0) { + mutex_unlock(powd->mutex); + return; + } AudioOutputUnitStop(powd->audio_unit); AudioUnitUninitialize(powd->audio_unit); CloseComponent(powd->audio_unit); btr_remove_node(&powd->callback_btrn); + mutex_unlock(powd->mutex); remove_btrn: btr_remove_node(&wn->btrn); PARA_NOTICE_LOG("%s\n", para_strerror(-ret)); -out: t->error = ret; }