]> git.tuebingen.mpg.de Git - paraslash.git/commitdiff
Merge branch 't/crypto'
authorAndre Noll <maan@systemlinux.org>
Sun, 7 Aug 2011 11:13:43 +0000 (13:13 +0200)
committerAndre Noll <maan@systemlinux.org>
Sun, 7 Aug 2011 11:35:21 +0000 (13:35 +0200)
13 files changed:
Makefile.in
NEWS
aft.c
alsa_write.c
audiod.c
audiod_command.c
client_common.c
command.c
configure.ac
fecdec_filter.c
net.c
osx_write.c
web/manual.m4

index 7e6287e0d0ff72e1e6842535d8f665db70068e0b..5016b065b85d9c36dccff605b4d8e8519a745610 100644 (file)
@@ -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 57ef197ba3e9dbba332ec208c43d90f48cfd5040..7d330ce48c5528a43156fd7b12833859218e9f1e 100644 (file)
--- 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 a27e67eeb7b438546573c254d76c4ed15cdf3750..f4080233855009be5423b3bc9325b861d5f20b0c 100644 (file)
--- 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;
 }
 
index 1c168e7b4b037f8e8853681e02254879f0912640..6850221a83d861e04cfcd8254d3114f837013a2e 100644 (file)
@@ -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:
index 03218e249ec3b69b8863c245628514a5ae32a225..c7998cdb7d02259b4e4da84353a2fdade8ec5584 100644 (file)
--- 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();
index 05059ac06d2ff7f23a9648e14e54c71c904bfa9d..1c22f58b3eea76d91d89af50196c0fbed7c8ab31 100644 (file)
@@ -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)
index 865a1797bd81bbd7e6308278c08249890c1bf241..eb9f9e1fcda2a49ba960582ba67be9c882897a20 100644 (file)
@@ -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;
        }
index d82bd5d71ca3ed6bf2fa40777c5a5b1231fd897f..69bbbb74dd2831791e0f24378d7a4c4451bb6524 100644 (file)
--- 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(&current_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);
index 019fca0b4a67c4fbd0d12ca8c561f3fe85aed171..79aaee63b3f159e20941f137b4b8d279823f7bf0 100644 (file)
@@ -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"
index fb2dba025d37806b2b70bd8f8002cae09e3e4db8..09a2fabd7bb418d7e94f8bea2cac4fb5d9826bfa 100644 (file)
@@ -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 2f720b10477aee8214cac5a5223ca4378b29bd5f..ae596e5a7007260dd3a2954932f3927e88ea3bdd 100644 (file)
--- 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;
index 50f22be9a4939121f1573462ffdfd31037257aa0..429c713945dc799011efeaeb68a9670408067430 100644 (file)
 #include "write.h"
 #include "write_common.h"
 #include "osx_write.cmdline.h"
+#include "ipc.h"
 #include "error.h"
 
 #include <CoreServices/CoreServices.h>
 #include <AudioUnit/AudioUnit.h>
 #include <AudioToolbox/AudioToolbox.h>
 
-/** 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;
index 3193a2f0ca6ef3901c8cb4c08e897d3e50c65dd3..f7071167a62067a9dfbf0c4d594ed49d59a33f0e 100644 (file)
@@ -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