From: Andre Noll Date: Sun, 7 Aug 2011 11:13:43 +0000 (+0200) Subject: Merge branch 't/crypto' X-Git-Tag: v0.4.8~21 X-Git-Url: http://git.tuebingen.mpg.de/?p=paraslash.git;a=commitdiff_plain;h=7bf235513ca87b608bdddf6220e284213965e130;hp=c13f9045d75565f517a4e73cade098da7cc46fcc Merge branch 't/crypto' --- diff --git a/Makefile.in b/Makefile.in index 7e6287e0..5016b065 100644 --- a/Makefile.in +++ b/Makefile.in @@ -19,9 +19,9 @@ codename := nested assignment GIT_VERSION := $(shell ./GIT-VERSION-GEN git-version.h) -DEBUG_CPPFLAGS += -Wno-sign-compare -g -Wunused -Wundef -W +DEBUG_CPPFLAGS += -g -Wunused -Wundef -W DEBUG_CPPFLAGS += -Wredundant-decls -DEBUG_CPPFLAGS += -Wall +DEBUG_CPPFLAGS += -Wall -Wno-sign-compare -Wno-unknown-pragmas DEBUG_CPPFLAGS += -Wformat-security DEBUG_CPPFLAGS += -Wmissing-format-attribute # produces false positives diff --git a/NEWS b/NEWS index 57ef197b..7d330ce4 100644 --- a/NEWS +++ b/NEWS @@ -2,10 +2,21 @@ 0.4.8 (to be announced) "nested assignment" ------------------------------------------- +Gcrypt support, the overhauled osx writer and regex format specifiers +are the highlights of this release. + + - support for libgcrypt as a drop-in replacement for openssl. + Run configure --enable-cryptolib=gcrypt to link against + libgcrypt. The two crypto implementations are compatible to + each other, i.e. a para_client executable linked against + gcrypt can connect to para_server linked against libssl + and vice versa. + - Rewrite of the osx writer (output plugin for Mac OS). - audiod: The format specifier for receivers, filters and writers is now treated as a regular expression. This allows to replace 5 lines in the config file (one for each audio format) by one single line. See the manual for details. + - Compiles cleanly also with llvm/clang. -------------------------------------- 0.4.7 (2011-06-01) "infinite rollback" diff --git a/aft.c b/aft.c index a27e67ee..f4080233 100644 --- a/aft.c +++ b/aft.c @@ -1823,7 +1823,7 @@ static void hash_sister_callback(int fd, const struct osl_object *query) static int get_row_pointer_from_result(struct osl_object *result, void *private) { struct osl_row **row = private; - *row = result->data; + *row = *(struct osl_row **)(result->data); return 1; } diff --git a/alsa_write.c b/alsa_write.c index 1c168e7b..6850221a 100644 --- a/alsa_write.c +++ b/alsa_write.c @@ -253,7 +253,9 @@ again: } frames = bytes / pad->bytes_per_frame; frames = snd_pcm_writei(pad->handle, data, frames); - if (frames >= 0) { + if (frames == 0 || frames == -EAGAIN) + return; + if (frames > 0) { btr_consume(btrn, frames * pad->bytes_per_frame); goto again; } @@ -262,8 +264,6 @@ again: snd_pcm_prepare(pad->handle); return; } - if (frames == -EAGAIN) - return; PARA_WARNING_LOG("%s\n", snd_strerror(-frames)); ret = -E_ALSA_WRITE; err: diff --git a/audiod.c b/audiod.c index 03218e24..c7998cdb 100644 --- a/audiod.c +++ b/audiod.c @@ -289,7 +289,7 @@ out: length / 60, length % 60 ); - PARA_DEBUG_LOG("slot %d: %s\n", slot_num, msg); + //PARA_DEBUG_LOG("slot %d: %s\n", slot_num, msg); return msg; empty: return para_strdup(NULL); @@ -1048,7 +1048,6 @@ static void close_stat_pipe(void) { if (!stat_task->ct) return; - btr_free_node(stat_task->ct->btrn); client_close(stat_task->ct); stat_task->ct = NULL; clear_and_dump_items(); diff --git a/audiod_command.c b/audiod_command.c index 05059ac0..1c22f58b 100644 --- a/audiod_command.c +++ b/audiod_command.c @@ -120,24 +120,22 @@ void stat_client_write_item(int item_num) struct para_buffer pb = {.flags = 0}; struct para_buffer pfpb = {.flags = PBF_SIZE_PREFIX}; const uint64_t one = 1; + char *msg = stat_item_values[item_num]; + struct para_buffer *b; list_for_each_entry_safe(sc, tmp, &client_list, node) { int fd = sc->fd, ret; if (!((one << item_num) & sc->item_mask)) continue; - if (write_ok(fd) > 0) { - struct para_buffer *b = - (sc->flags & SCF_PARSER_FRIENDLY)? &pfpb : &pb; - char *msg = stat_item_values[item_num]; - if (!b->buf) - WRITE_STATUS_ITEM(b, item_num, "%s\n", - msg? msg : ""); - ret = write(fd, b->buf, b->offset); - if (ret == b->offset) - continue; - } - /* write error or fd not ready for writing */ + b = (sc->flags & SCF_PARSER_FRIENDLY)? &pfpb : &pb; + if (!b->buf) + (void)WRITE_STATUS_ITEM(b, item_num, "%s\n", + msg? msg : ""); + ret = write(fd, b->buf, b->offset); + if (ret == b->offset) + continue; + /* write error or short write */ close(fd); num_clients--; PARA_INFO_LOG("deleting client on fd %d\n", fd); @@ -147,8 +145,6 @@ void stat_client_write_item(int item_num) } free(pb.buf); free(pfpb.buf); -// if (num_clients) -// PARA_DEBUG_LOG("%d client(s)\n", num_clients); } /** @@ -198,7 +194,7 @@ static int get_play_time_slot_num(void) FOR_EACH_SLOT(i) { struct slot_info *s = &slot[i]; struct timeval wstime; - if (!s->wns) + if (!s->wns || !s->wns[0].btrn) continue; btr_get_node_start(s->wns[0].btrn, &wstime); if (oldest_slot >= 0 && tv_diff(&wstime, &oldest_wstime, NULL) > 0) @@ -307,6 +303,9 @@ int com_stat(int fd, int argc, char **argv) const uint64_t one = 1; struct para_buffer b = {.flags = 0}; + ret = mark_fd_nonblocking(fd); + if (ret < 0) + return ret; for (i = 1; i < argc; i++) { const char *arg = argv[i]; if (arg[0] != '-') @@ -334,7 +333,7 @@ int com_stat(int fd, int argc, char **argv) char *item = stat_item_values[i]; if (!((one << i) & mask)) continue; - WRITE_STATUS_ITEM(&b, i, "%s\n", item? item : ""); + (void)WRITE_STATUS_ITEM(&b, i, "%s\n", item? item : ""); } ret = client_write(fd, b.buf); if (ret >= 0) diff --git a/client_common.c b/client_common.c index 865a1797..eb9f9e1f 100644 --- a/client_common.c +++ b/client_common.c @@ -44,6 +44,7 @@ void client_close(struct client_task *ct) free(ct->user); free(ct->config_file); free(ct->key_file); + btr_free_node(ct->btrn); client_cmdline_parser_free(&ct->conf); free(ct); } @@ -418,7 +419,6 @@ out: if (ret < 0) { PARA_ERROR_LOG("%s\n", para_strerror(-ret)); btr_remove_node(ct->btrn); - btr_free_node(ct->btrn); client_close(ct); *ct_ptr = NULL; } diff --git a/command.c b/command.c index d82bd5d7..69bbbb74 100644 --- a/command.c +++ b/command.c @@ -122,16 +122,22 @@ static char *get_status(struct misc_meta_data *nmmd, int parser_friendly) strftime(mtime, 29, "%b %d %Y", &mtime_tm); } gettimeofday(¤t_time, NULL); - WRITE_STATUS_ITEM(&b, SI_FILE_SIZE, "%zu\n", nmmd->size / 1024); - WRITE_STATUS_ITEM(&b, SI_MTIME, "%s\n", mtime); - WRITE_STATUS_ITEM(&b, SI_STATUS, "%s\n", status); - WRITE_STATUS_ITEM(&b, SI_STATUS_FLAGS, "%s\n", flags); - WRITE_STATUS_ITEM(&b, SI_OFFSET, "%li\n", offset); - WRITE_STATUS_ITEM(&b, SI_AFS_MODE, "%s\n", mmd->afs_mode_string); - WRITE_STATUS_ITEM(&b, SI_STREAM_START, "%lu.%lu\n", + /* + * The calls to WRITE_STATUS_ITEM() below never fail because + * b->max_size is zero (unlimited), see para_printf(). However, clang + * is not smart enough to prove this and complains nevertheless. + * Casting the return value to void silences solves this. + */ + (void)WRITE_STATUS_ITEM(&b, SI_FILE_SIZE, "%zu\n", nmmd->size / 1024); + (void)WRITE_STATUS_ITEM(&b, SI_MTIME, "%s\n", mtime); + (void)WRITE_STATUS_ITEM(&b, SI_STATUS, "%s\n", status); + (void)WRITE_STATUS_ITEM(&b, SI_STATUS_FLAGS, "%s\n", flags); + (void)WRITE_STATUS_ITEM(&b, SI_OFFSET, "%li\n", offset); + (void)WRITE_STATUS_ITEM(&b, SI_AFS_MODE, "%s\n", mmd->afs_mode_string); + (void)WRITE_STATUS_ITEM(&b, SI_STREAM_START, "%lu.%lu\n", (long unsigned)nmmd->stream_start.tv_sec, (long unsigned)nmmd->stream_start.tv_usec); - WRITE_STATUS_ITEM(&b, SI_CURRENT_TIME, "%lu.%lu\n", + (void)WRITE_STATUS_ITEM(&b, SI_CURRENT_TIME, "%lu.%lu\n", (long unsigned)current_time.tv_sec, (long unsigned)current_time.tv_usec); free(flags); diff --git a/configure.ac b/configure.ac index 019fca0b..79aaee63 100644 --- a/configure.ac +++ b/configure.ac @@ -493,11 +493,11 @@ if test ${have_core_audio} = yes; then f="$f1 $f2 $f3 $f4" all_errlist_objs="$all_errlist_objs osx_write" - audiod_errlist_objs="$audiod_errlist_objs osx_write" + audiod_errlist_objs="$audiod_errlist_objs osx_write ipc" audiod_cmdline_objs="$audiod_cmdline_objs osx_write.cmdline" audiod_ldflags="$audiod_ldflags $f" - write_errlist_objs="$write_errlist_objs osx_write" + write_errlist_objs="$write_errlist_objs osx_write ipc" write_cmdline_objs="$write_cmdline_objs osx_write.cmdline" write_ldflags="$write_ldflags $f" writers="$writers osx" diff --git a/fecdec_filter.c b/fecdec_filter.c index fb2dba02..09a2fabd 100644 --- a/fecdec_filter.c +++ b/fecdec_filter.c @@ -291,7 +291,7 @@ static int decode_group(struct fecdec_group *fg, struct filter_node *fn) size_t written, need; struct private_fecdec_data *pfd = fn->private_data; enum fec_group_usability u = group_is_usable(fg, pfd); - char *buf = NULL, *p; + char *buf = NULL; if (u == FEC_GROUP_UNUSABLE) { PARA_INFO_LOG("dropping unusable group %d\n", fg->h.group_num); @@ -315,7 +315,6 @@ static int decode_group(struct fecdec_group *fg, struct filter_node *fn) if (need > btr_pool_unused(pfd->btrp)) return -E_FECDEC_OVERRUN; btr_pool_get_buffer(pfd->btrp, &buf); - p = buf; if (u == FEC_GROUP_USABLE_WITH_HEADER) { PARA_INFO_LOG("writing audio file header\n"); written = 0; @@ -328,7 +327,6 @@ static int decode_group(struct fecdec_group *fg, struct filter_node *fn) btr_copy(fg->data[i], n, pfd->btrp, fn->btrn); written += n; } - p += written; } written = 0; for (; i < fg->h.data_slices_per_group; i++) { @@ -338,7 +336,6 @@ static int decode_group(struct fecdec_group *fg, struct filter_node *fn) btr_copy(fg->data[i], n, pfd->btrp, fn->btrn); written += n; } - p += written; return 0; } diff --git a/net.c b/net.c index 2f720b10..ae596e5a 100644 --- a/net.c +++ b/net.c @@ -607,8 +607,7 @@ int generic_max_transport_msg_size(int sockfd) * \sa getsockname(2), getpeername(2), parse_url(), getnameinfo(3), * services(5), nsswitch.conf(5). */ -static char *__get_sock_name(int fd, int (*getname)(int, struct sockaddr*, - socklen_t *)) +static char *__get_sock_name(int fd, typeof(getsockname) getname) { struct sockaddr_storage ss; const struct sockaddr *sa; diff --git a/osx_write.c b/osx_write.c index 50f22be9..429c7139 100644 --- a/osx_write.c +++ b/osx_write.c @@ -25,187 +25,119 @@ #include "write.h" #include "write_common.h" #include "osx_write.cmdline.h" +#include "ipc.h" #include "error.h" #include #include #include -/** describes one input buffer for the osx writer */ -struct osx_buffer { - /** pointer to the beginning of the buffer */ - float *buffer; - /** the size of this buffer */ - long size; - /** current position in the buffer */ - float *ptr; - /** number of floats not yet consuned */ - long remaining; - /** pointer to the next audio buffer */ - struct osx_buffer *next; -}; - -/** data specific to the osx writer */ +/** Data specific to the osx writer. */ struct private_osx_write_data { - /** the main control structure for audio data manipulation */ + /** The main CoreAudio handle. */ AudioUnit audio_unit; - /** non-zero if playback has started */ - char play; - /** callback reads audio data from this buffer */ - struct osx_buffer *from; - /** the post_select writes audio data here */ - struct osx_buffer *to; - /** sample rate of the current audio stream */ + /** True if we wrote some audio data. */ + bool playing; + /** Sample rate of the current audio stream. */ unsigned sample_rate; /** Sample format of the current audio stream */ unsigned sample_format; - /** number of channels of the current audio stream */ + /** Number of channels of the current audio stream. */ unsigned channels; + /** Serializes access to buffer tree nodes. */ + int mutex; + /** The btr node of the callback. */ + struct btr_node *callback_btrn; }; -static void destroy_buffers(struct private_osx_write_data *powd) -{ - struct osx_buffer *ptr; - struct osx_buffer *ptr2; - ptr = powd->to->next; - powd->to->next = NULL; - while (ptr) { - ptr2 = ptr->next; - free(ptr->buffer); - free(ptr); - ptr = ptr2; - } -} - -static void init_buffers(struct writer_node *wn) +/* This function writes the address and the number of bytes to one end of the socket. + * The post_select() function then fills the buffer and notifies the callback also + * through the socket. + */ +static OSStatus osx_callback(void *cb_arg, __a_unused AudioUnitRenderActionFlags *af, + __a_unused const AudioTimeStamp *ts, __a_unused UInt32 bus_number, + __a_unused UInt32 num_frames, AudioBufferList *abl) { - struct private_osx_write_data *powd = wn->private_data; - struct osx_write_args_info *conf = wn->conf; - struct osx_buffer **ptrptr; int i; + struct writer_node *wn = cb_arg; + struct private_osx_write_data *powd = wn->private_data; + size_t samples_have, samples_want = 0; - ptrptr = &powd->to; - for (i = 0; i < conf->numbuffers_arg; i++) { - *ptrptr = para_malloc(sizeof(struct osx_buffer)); - (*ptrptr)->size = 0; - (*ptrptr)->remaining = 0; - (*ptrptr)->buffer = NULL; - ptrptr = &(*ptrptr)->next; - } - *ptrptr = powd->from = powd->to; -} - -static void fill_buffer(struct private_osx_write_data *powd, char *data, long bytes) -{ - struct osx_buffer *b = powd->to; - float *dest; - long samples; - enum sample_format sf = powd->sample_format; - - samples = (sf == SF_S8 || sf == SF_U8)? bytes : bytes / 2; - assert(b->remaining == 0 || samples > 0); - if (b->size != samples) { - b->buffer = para_realloc(b->buffer, samples * sizeof(float)); - b->size = samples; - } - dest = b->buffer; - switch (powd->sample_format) { - case SF_U8: { - uint8_t *src = (uint8_t *)data; - while (samples--) { - *dest++ = (*src++) / 256.0; + mutex_lock(powd->mutex); + /* + * We fill with zeros if no data was yet written and we do not have + * enough to fill all buffers. + */ + if (!powd->playing) { + size_t want = 0, have = + btr_get_input_queue_size(powd->callback_btrn); + for (i = 0; i < abl->mNumberBuffers; i++) + want += abl->mBuffers[i].mDataByteSize; + if (have < want) { + PARA_DEBUG_LOG("deferring playback (have = %zu < %zu = want)\n", + have, want); + for (i = 0; i < abl->mNumberBuffers; i++) + memset(abl->mBuffers[i].mData, 0, + abl->mBuffers[i].mDataByteSize); + goto out; } - break; + powd->playing = true; } - case SF_S8: { - int8_t *src = (int8_t *)data; - while (samples--) { - *dest++ = ((*src++) + 128) / 256.0; - } - break; - } - default: { - short *src = (short *)data; - while (samples--) - *dest++ = (*src++) / 32768.0; - } - } - b->ptr = b->buffer; - b->remaining = b->size; -} - -static OSStatus osx_callback(void * inClientData, - __a_unused AudioUnitRenderActionFlags *inActionFlags, - __a_unused const AudioTimeStamp *inTimeStamp, - __a_unused UInt32 inBusNumber, - __a_unused UInt32 inNumFrames, - AudioBufferList *outOutputData) -{ - long m, n; - float *dest; - int i; - struct private_osx_write_data *powd = inClientData; -// PARA_INFO_LOG("%p\n", powd); - for (i = 0; i < outOutputData->mNumberBuffers; ++i) { + for (i = 0; i < abl->mNumberBuffers; i++) { /* what we have to fill */ - m = outOutputData->mBuffers[i].mDataByteSize / sizeof(float); - dest = outOutputData->mBuffers[i].mData; - while (m > 0) { - n = powd->from->remaining; - if (n <= 0) { - n = powd->from->next->remaining; - if (n <= 0) { - PARA_INFO_LOG("buffer underrun\n"); - return 0; - } - powd->from = powd->from->next; - } -// PARA_INFO_LOG("buf %p: n = %ld, m= %ld\n", powd->from->buffer, n, m); - /* - * we dump what we can. In fact, just the necessary - * should be sufficient - */ - if (n > m) - n = m; - memcpy(dest, powd->from->ptr, n * sizeof(float)); - dest += n; - /* remember all done work */ - m -= n; - powd->from->ptr += n; - if ((powd->from->remaining -= n) <= 0) - powd->from = powd->from->next; + void *dest = abl->mBuffers[i].mData; + size_t sz = abl->mBuffers[i].mDataByteSize, samples, bytes; + + samples_want = sz / wn->min_iqs; + while (samples_want > 0) { + char *buf; + btr_merge(powd->callback_btrn, wn->min_iqs); + samples_have = btr_next_buffer(powd->callback_btrn, &buf) / wn->min_iqs; + //PARA_INFO_LOG("i: %d want %zu samples to addr %p, have: %zu\n", i, samples_want, + // dest, samples_have); + samples = PARA_MIN(samples_have, samples_want); + if (samples == 0) + break; + bytes = samples * wn->min_iqs; + memcpy(dest, buf, bytes); + btr_consume(powd->callback_btrn, bytes); + samples_want -= samples; + dest += bytes; } + if (samples_want == 0) + continue; + if (btr_node_status(wn->btrn, wn->min_iqs, BTR_NT_LEAF) >= 0) + PARA_INFO_LOG("zero-padding (%zu samples)\n", + samples_want); + memset(dest, 0, samples_want * wn->min_iqs); + break; } - return 0; +out: + mutex_unlock(powd->mutex); + return noErr; } -#ifdef WORDS_BIGENDIAN /* ppc */ -#define ENDIAN_FLAGS kLinearPCMFormatFlagIsBigEndian -#else -#define ENDIAN_FLAGS 0 -#endif - static int core_audio_init(struct writer_node *wn) { struct private_osx_write_data *powd = para_calloc(sizeof(*powd)); - ComponentDescription desc; Component comp; - AURenderCallbackStruct inputCallback = {osx_callback, powd}; - AudioStreamBasicDescription format; int ret; - struct btr_node *btrn = wn->btrn; int32_t val; + AURenderCallbackStruct input_callback; + ComponentDescription desc = { + .componentType = kAudioUnitType_Output, + .componentSubType = kAudioUnitSubType_DefaultOutput, + .componentManufacturer = kAudioUnitManufacturer_Apple, + }; + AudioStreamBasicDescription format = { + .mFormatID = kAudioFormatLinearPCM, + .mFramesPerPacket = 1, + }; + struct btr_node *btrn = wn->btrn; + struct btr_node_description bnd; - wn->private_data = powd; - init_buffers(wn); - /* where did that default audio output go? */ - desc.componentType = kAudioUnitType_Output; - desc.componentSubType = kAudioUnitSubType_DefaultOutput; - /* NOTE: and if default output isn't Apple? */ - desc.componentManufacturer = kAudioUnitManufacturer_Apple; - desc.componentFlags = 0; - desc.componentFlagsMask = 0; + PARA_INFO_LOG("wn: %p\n", wn); ret = -E_DEFAULT_COMP; comp = FindNextComponent(NULL, &desc); if (!comp) @@ -216,7 +148,6 @@ static int core_audio_init(struct writer_node *wn) ret = -E_UNIT_INIT; if (AudioUnitInitialize(powd->audio_unit)) goto e1; - powd->play = 0; get_btr_sample_rate(btrn, &val); powd->sample_rate = val; get_btr_channels(btrn, &val); @@ -230,39 +161,53 @@ static int core_audio_init(struct writer_node *wn) * any format conversions necessary from your format to the device's * format. */ - format.mFormatID = kAudioFormatLinearPCM; - format.mFramesPerPacket = 1; + format.mSampleRate = powd->sample_rate; - /* flags specific to each format */ - format.mFormatFlags = kLinearPCMFormatFlagIsFloat - | kLinearPCMFormatFlagIsPacked - | ENDIAN_FLAGS; + format.mChannelsPerFrame = powd->channels; + switch (powd->sample_format) { case SF_S8: case SF_U8: wn->min_iqs = powd->channels; + format.mBitsPerChannel = 8; + format.mBytesPerPacket = powd->channels; + format.mFormatFlags |= kLinearPCMFormatFlagIsPacked; break; default: wn->min_iqs = powd->channels * 2; + format.mBytesPerPacket = powd->channels * 2; + format.mBitsPerChannel = 16; + format.mFormatFlags |= kLinearPCMFormatFlagIsSignedInteger; } - format.mBitsPerChannel = 8 * sizeof(float); - format.mBytesPerPacket = powd->channels * sizeof(float); format.mBytesPerFrame = format.mBytesPerPacket; - format.mChannelsPerFrame = powd->channels; + if (powd->sample_format == SF_S16_BE || powd->sample_format == SF_U16_BE) + format.mFormatFlags |= kLinearPCMFormatFlagIsBigEndian; + + input_callback = (AURenderCallbackStruct){osx_callback, wn}; ret = -E_STREAM_FORMAT; if (AudioUnitSetProperty(powd->audio_unit, kAudioUnitProperty_StreamFormat, - kAudioUnitScope_Input, 0, &format, - sizeof(AudioStreamBasicDescription))) + kAudioUnitScope_Input, 0, &format, sizeof(format))) goto e2; ret = -E_ADD_CALLBACK; if (AudioUnitSetProperty(powd->audio_unit, kAudioUnitProperty_SetRenderCallback, - kAudioUnitScope_Input, 0, &inputCallback, - sizeof(inputCallback)) < 0) - goto e3; + kAudioUnitScope_Input, 0, &input_callback, + sizeof(input_callback)) < 0) + goto e2; + + ret = mutex_new(); + if (ret < 0) + goto e2; + powd->mutex = ret; + /* set up callback btr node */ + bnd.name = "cb_node"; + bnd.parent = btrn; + bnd.child = NULL; + bnd.handler = NULL; + bnd.context = powd; + powd->callback_btrn = btr_new_node(&bnd); + wn->private_data = powd; return 1; -e3: - destroy_buffers(powd); e2: AudioUnitUninitialize(powd->audio_unit); e1: @@ -294,73 +239,91 @@ static void osx_write_close(struct writer_node *wn) if (!powd) return; PARA_INFO_LOG("closing writer node %p\n", wn); - AudioOutputUnitStop(powd->audio_unit); - AudioUnitUninitialize(powd->audio_unit); - CloseComponent(powd->audio_unit); - destroy_buffers(powd); + mutex_destroy(powd->mutex); free(powd); + wn->private_data = NULL; } -static void osx_write_post_select(__a_unused struct sched *s, struct task *t) +/* must be called with the mutex held */ +static inline bool need_drain_delay(struct private_osx_write_data *powd) +{ + if (!powd->playing) + return false; + return btr_get_input_queue_size(powd->callback_btrn) != 0; +} + +static void osx_write_pre_select(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; - char *data; - size_t bytes; - int ret = 0; + int ret; + bool drain_delay_nec = false; - while (!powd || powd->to->remaining <= 0) { + if (!powd) { ret = btr_node_status(wn->btrn, wn->min_iqs, BTR_NT_LEAF); - if (ret <= 0) - break; - if (!powd) { - ret = core_audio_init(wn); - if (ret < 0) - break; - powd = wn->private_data; - } - btr_merge(btrn, 8192); - bytes = btr_next_buffer(btrn, &data); - //PARA_CRIT_LOG("have: %zu\n", bytes); - fill_buffer(powd, data, bytes); - btr_consume(btrn, bytes); - if (!powd->play) { - ret = -E_UNIT_START; - if (AudioOutputUnitStart(powd->audio_unit)) - break; - powd->play = 1; - } - powd->to = powd->to->next; - } - if (ret < 0 && (!powd || powd->from->remaining <= 0)) { - btr_remove_node(btrn); - t->error = ret; + if (ret != 0) + sched_min_delay(s); + return; } + + mutex_lock(powd->mutex); + ret = btr_node_status(wn->btrn, wn->min_iqs, BTR_NT_LEAF); + if (ret < 0) + drain_delay_nec = need_drain_delay(powd); + mutex_unlock(powd->mutex); + + if (drain_delay_nec) + return sched_request_timeout_ms(50, s); + if (ret != 0) + return sched_min_delay(s); + sched_request_timeout_ms(50, s); } -static void osx_write_pre_select(struct sched *s, struct task *t) +static void 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 timeval tmp = {.tv_sec = 1, .tv_usec = 0}, delay = tmp; - unsigned long factor; - size_t numbytes; - int ret = btr_node_status(wn->btrn, wn->min_iqs, BTR_NT_LEAF); + struct btr_node *btrn = wn->btrn; + int ret; - if (ret == 0) - return; - if (ret < 0 || !powd) - return sched_min_delay(s); - assert(powd->sample_rate > 0); - assert(wn->min_iqs > 0); - numbytes = powd->to->remaining * sizeof(short); - factor = numbytes / powd->sample_rate / wn->min_iqs; - tv_scale(factor, &tmp, &delay); - sched_request_timeout(&delay, s); + if (!powd) { + ret = btr_node_status(btrn, wn->min_iqs, BTR_NT_LEAF); + if (ret == 0) + return; + if (ret < 0) + goto remove_btrn; + ret = core_audio_init(wn); + if (ret < 0) + goto remove_btrn; + powd = wn->private_data; + AudioOutputUnitStart(powd->audio_unit); + } + mutex_lock(powd->mutex); + btr_pushdown(btrn); + ret = btr_node_status(btrn, wn->min_iqs, BTR_NT_LEAF); + 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); + PARA_NOTICE_LOG("%s\n", para_strerror(-ret)); +out: + t->error = ret; } -/** the init function of the osx writer */ +/** + * The init function of the osx writer. + * + * \param w Filled in by the function. + */ void osx_write_init(struct writer *w) { struct osx_write_args_info dummy; diff --git a/web/manual.m4 b/web/manual.m4 index 3193a2f0..f7071167 100644 --- a/web/manual.m4 +++ b/web/manual.m4 @@ -202,9 +202,10 @@ In any case you'll need git clone git://git.tuebingen.mpg.de/osl - - XREFERENCE(ftp://ftp.gnu.org/pub/gnu/gcc, gcc). The - EMPH(gnu compiler collection) is usually shipped with the - distro. gcc-3.3 or newer is required. + - XREFERENCE(ftp://ftp.gnu.org/pub/gnu/gcc, gcc) or + XREFERENCE(http://clang.llvm.org, clang). All gcc versions + >= 3.3 are currently supported. Clang version 1.1 or newer + should work as well. - XREFERENCE(ftp://ftp.gnu.org/pub/gnu/make, gnu make) is also shipped with the disto. On BSD systems the gnu make