X-Git-Url: http://git.tuebingen.mpg.de/?p=paraslash.git;a=blobdiff_plain;f=osx_write.c;h=889854c22a711a167e5bbfa61ac35241c60f8a95;hp=0f9d9605926a81fa5be0c4643ca6565fbe0391c2;hb=d1e6b28f66e243516d01916f9125baee75dd98d6;hpb=49ae9b0afbaa8b1ac05c7956f325c4f7a710b59a diff --git a/osx_write.c b/osx_write.c index 0f9d9605..889854c2 100644 --- a/osx_write.c +++ b/osx_write.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006-2012 Andre Noll + * Copyright (C) 2006-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ @@ -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. @@ -217,18 +240,18 @@ e0: return ret; } -__malloc static void *osx_write_parse_config_or_die(const char *options) +__malloc static void *osx_write_parse_config_or_die(int argc, char **argv) { struct osx_write_args_info *conf = para_calloc(sizeof(*conf)); /* exits on errors */ - osx_cmdline_parser_string(options, conf, "osx_write"); + osx_write_cmdline_parser(argc, argv, conf); return conf; } static void osx_free_config(void *conf) { - osx_cmdline_parser_free(conf); + osx_write_cmdline_parser_free(conf); } static void osx_write_close(struct writer_node *wn) @@ -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); @@ -278,44 +301,54 @@ static void osx_write_pre_select(struct sched *s, struct task *t) sched_request_timeout_ms(50, s); } -static void osx_write_post_select(__a_unused struct sched *s, struct task *t) +static int osx_write_post_select(__a_unused struct sched *s, struct task *t) { struct writer_node *wn = container_of(t, struct writer_node, task); struct private_osx_write_data *powd = wn->private_data; struct btr_node *btrn = wn->btrn; int ret; + ret = task_get_notification(t); + if (ret < 0) + goto fail; if (!powd) { ret = btr_node_status(btrn, wn->min_iqs, BTR_NT_LEAF); if (ret == 0) - return; + return 0; if (ret < 0) - goto remove_btrn; + goto fail; ret = core_audio_init(wn); if (ret < 0) - goto remove_btrn; + goto fail; 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 fail; + } } 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; - AudioOutputUnitStop(powd->audio_unit); - AudioUnitUninitialize(powd->audio_unit); - CloseComponent(powd->audio_unit); - btr_remove_node(powd->callback_btrn); - btr_free_node(powd->callback_btrn); -remove_btrn: - btr_remove_node(btrn); + return 0; +fail: + assert(ret < 0); + if (powd && powd->callback_btrn) { + AudioOutputUnitStop(powd->audio_unit); + AudioUnitUninitialize(powd->audio_unit); + CloseComponent(powd->audio_unit); + btr_remove_node(&powd->callback_btrn); + } + btr_remove_node(&wn->btrn); PARA_NOTICE_LOG("%s\n", para_strerror(-ret)); -out: - t->error = ret; + return ret; } /** @@ -327,15 +360,12 @@ void osx_write_init(struct writer *w) { struct osx_write_args_info dummy; - osx_cmdline_parser_init(&dummy); + osx_write_cmdline_parser_init(&dummy); w->close = osx_write_close; w->pre_select = osx_write_pre_select; w->post_select = osx_write_post_select; w->parse_config_or_die = osx_write_parse_config_or_die; w->free_config = osx_free_config; - w->help = (struct ggo_help) { - .short_help = osx_write_args_info_help, - .detailed_help = osx_write_args_info_detailed_help - }; - osx_cmdline_parser_free(&dummy); + w->help = (struct ggo_help)DEFINE_GGO_HELP(osx_write); + osx_write_cmdline_parser_free(&dummy); }