From 3af6411b482ed8db2243f3e11bb06cf3adba6936 Mon Sep 17 00:00:00 2001 From: Andre Noll Date: Mon, 18 Jul 2016 20:50:41 +0200 Subject: [PATCH] Drop support for Mac OS. This software hasn't been tested on Mac OS for years, so Mac OS support is most likely already broken. This commit removes the osx writer and the autoconf tests for core audio, and adjusts the documentation to not mention Mac OS anymore. It also effectively reverts commit be1074b4 which introduced an ugly workaround in interactive.c that was only needed on Mac OS. --- Makefile.in | 1 - Makefile.real | 2 +- configure.ac | 32 ---- error.h | 6 - interactive.c | 21 +-- m4/gengetopt/osx_write.m4 | 17 -- osx_write.c | 371 -------------------------------------- web/about.in.html | 2 +- web/manual.md | 9 +- write.c | 4 +- 10 files changed, 7 insertions(+), 458 deletions(-) delete mode 100644 m4/gengetopt/osx_write.m4 delete mode 100644 osx_write.c diff --git a/Makefile.in b/Makefile.in index ec55c8e3..d6830ded 100644 --- a/Makefile.in +++ b/Makefile.in @@ -69,7 +69,6 @@ readline_ldflags := @readline_ldflags@ samplerate_ldflags := @samplerate_ldflags@ osl_ldflags := @osl_ldflags@ curses_ldflags := @curses_ldflags@ -core_audio_ldflags := @core_audio_ldflags@ crypto_ldflags := @crypto_ldflags@ iconv_ldflags := @iconv_ldflags@ mp4v2_ldflags := @mp4v2_ldflags@ diff --git a/Makefile.real b/Makefile.real index 8ededf6a..ad83809c 100644 --- a/Makefile.real +++ b/Makefile.real @@ -282,7 +282,7 @@ $(dep_dir)/%.d: %.c | $(dep_dir) para_recv para_afh para_play para_server: LDFLAGS += $(id3tag_ldflags) para_write para_play para_audiod \ -: LDFLAGS += $(ao_ldflags) $(pthread_ldflags) $(core_audio_ldflags) +: LDFLAGS += $(ao_ldflags) $(pthread_ldflags) para_client para_audioc para_play : LDFLAGS += $(readline_ldflags) para_server: LDFLAGS += $(osl_ldflags) para_gui: LDFLAGS += $(curses_ldflags) diff --git a/configure.ac b/configure.ac index 0b00cc2a..ec8cbac2 100644 --- a/configure.ac +++ b/configure.ac @@ -213,24 +213,6 @@ AC_MSG_RESULT($have_ip_mreqn) if test ${have_ip_mreqn} = yes; then AC_DEFINE(HAVE_IP_MREQN, 1, define to 1 you have struct ip_mreqn) fi -########################################################################### osx - -AC_MSG_CHECKING(for CoreAudio (MacOs)) -AC_LINK_IFELSE([AC_LANG_PROGRAM([[ - #include -]], [[ - AudioDeviceID id; -]])],[have_core_audio=yes],[have_core_audio=no]) -AC_MSG_RESULT($have_core_audio) -if test ${have_core_audio} = yes; then - f1="-framework CoreAudio" - f2="-framework AudioToolbox" - f3="-framework AudioUnit" - f4="-framework CoreServices" - core_audio_ldflags="$f1 $f2 $f3 $f4" - AC_SUBST(core_audio_ldflags) - AC_DEFINE(HAVE_CORE_AUDIO, 1, define to 1 on Mac Os X) -fi ########################################################################### ogg STASH_FLAGS LIB_ARG_WITH([ogg], [-logg]) @@ -544,10 +526,6 @@ if test -n "$CRYPTOLIB"; then else audiod_errlist_objs="$audiod_errlist_objs gcrypt" fi - if test "$have_core_audio" = "yes"; then - audiod_errlist_objs="$audiod_errlist_objs osx_write ipc" - audiod_cmdline_objs="$audiod_cmdline_objs osx_write" - fi NEED_VORBIS_OBJECTS && { audiod_errlist_objs="$audiod_errlist_objs oggdec_filter" audiod_audio_formats="$audiod_audio_formats ogg" @@ -880,10 +858,6 @@ play_cmdline_objs=" play sync_filter " -if test "$have_core_audio" = "yes"; then - play_errlist_objs="$play_errlist_objs osx_write ipc" - play_cmdline_objs="$play_cmdline_objs osx_write" -fi NEED_OGG_OBJECTS && play_errlist_objs="$play_errlist_objs ogg_afh_common" NEED_VORBIS_OBJECTS && { play_errlist_objs="$play_errlist_objs oggdec_filter ogg_afh" @@ -957,12 +931,6 @@ write_errlist_objs=" writers="file" default_writer="FILE_WRITE" -if test "$have_core_audio" = "yes"; then - write_errlist_objs="$write_errlist_objs osx_write ipc" - write_cmdline_objs="$write_cmdline_objs osx_write" - writers="$writers osx" - default_writer="OSX_WRITE" -fi NEED_AO_OBJECTS && { write_errlist_objs="$write_errlist_objs ao_write" write_cmdline_objs="$write_cmdline_objs ao_write" diff --git a/error.h b/error.h index 899c574b..dde0122a 100644 --- a/error.h +++ b/error.h @@ -12,7 +12,6 @@ PARA_ERROR(AACDEC_INIT, "failed to init aac decoder"), \ PARA_ERROR(AAC_DECODE, "aac decode error"), \ PARA_ERROR(ACL_PERM, "access denied by acl"), \ - PARA_ERROR(ADD_CALLBACK, "can not add callback"), \ PARA_ERROR(ADDRESS_LOOKUP, "can not resolve requested address"),\ PARA_ERROR(AFH_RECV_BAD_FILENAME, "no file name given"), \ PARA_ERROR(AFS_SHORT_READ, "short read from afs socket"), \ @@ -88,7 +87,6 @@ PARA_ERROR(CREATE_OPUS_DECODER, "could not create opus decoder"), \ PARA_ERROR(DCCP_OVERRUN, "dccp output buffer buffer overrun"), \ PARA_ERROR(DECRYPT, "decrypt error"), \ - PARA_ERROR(DEFAULT_COMP, "can not find default audio output component"), \ PARA_ERROR(DUMMY_ROW, "attempted to access blob dummy object"), \ PARA_ERROR(DUP_PIPE, "exec error: can not create pipe"), \ PARA_ERROR(EMPTY, "file is empty"), \ @@ -177,7 +175,6 @@ PARA_ERROR(OGG_PACKET_IN, "ogg_stream_packetin() failed"), \ PARA_ERROR(OGG_STREAM_FLUSH, "ogg_stream_flush() failed"), \ PARA_ERROR(OGG_SYNC, "internal ogg storage overflow"), \ - PARA_ERROR(OPEN_COMP, "OpenAComponent() error"), \ PARA_ERROR(OPUS_COMMENT, "invalid or corrupted opus comment"), \ PARA_ERROR(OPUS_DECODE, "opus decode error"), \ PARA_ERROR(OPUS_HEADER, "invalid opus header"), \ @@ -227,7 +224,6 @@ PARA_ERROR(STAT_ITEM_PARSE, "failed to parse status item"), \ PARA_ERROR(STATUS_TIMEOUT, "status item timeout"), \ PARA_ERROR(STCO, "did not find stco atom"), \ - PARA_ERROR(STREAM_FORMAT, "could not set stream format"), \ PARA_ERROR(STREAM_PACKETIN, "ogg stream packet-in error"), \ PARA_ERROR(STREAM_PACKETOUT, "ogg stream packet-out error"), \ PARA_ERROR(STREAM_PAGEIN, "ogg stream page-in error"), \ @@ -243,8 +239,6 @@ PARA_ERROR(TOO_MANY_CLIENTS, "maximal number of stat clients exceeded"), \ PARA_ERROR(UCRED_PERM, "permission denied"), \ PARA_ERROR(UDP_OVERRUN, "output buffer overrun"), \ - PARA_ERROR(UNIT_INIT, "AudioUnitInitialize() error"), \ - PARA_ERROR(UNIT_START, "AudioUnitStart() error"), \ PARA_ERROR(UNKNOWN_STAT_ITEM, "status item not recognized"), \ PARA_ERROR(UNSUPPORTED_AUDIO_FORMAT, "given audio format not supported"), \ PARA_ERROR(UNSUPPORTED_FILTER, "given filter not supported"), \ diff --git a/interactive.c b/interactive.c index b72148cc..bda5a0b8 100644 --- a/interactive.c +++ b/interactive.c @@ -205,26 +205,7 @@ void i9e_attach_to_stdout(struct btr_node *producer) static void wipe_bottom_line(void) { - char x[] = " "; - int n = i9ep->num_columns; - - /* - * For reasons beyond my understanding, writing more than 68 characters - * here causes MacOS to mess up the terminal. Writing a line of spaces - * in smaller chunks works fine though. Weird. - */ - fprintf(i9ep->stderr_stream, "\r"); - while (n > 0) { - if (n >= sizeof(x)) { - fprintf(i9ep->stderr_stream, "%s", x); - n -= sizeof(x); - continue; - } - x[n] = '\0'; - fprintf(i9ep->stderr_stream, "%s", x); - break; - } - fprintf(i9ep->stderr_stream, "\r"); + fprintf(i9ep->stderr_stream, "\r%s\r", i9ep->empty_line); } #ifndef RL_FREE_KEYMAP_DECLARED diff --git a/m4/gengetopt/osx_write.m4 b/m4/gengetopt/osx_write.m4 deleted file mode 100644 index 83ed737c..00000000 --- a/m4/gengetopt/osx_write.m4 +++ /dev/null @@ -1,17 +0,0 @@ -args "--no-version --no-help" - -purpose "Output plugin for Mac OS coreaudio" - -section "osx options" -##################### - -option "numbuffers" n -#~~~~~~~~~~~~~~~~~~~~~ - -"number of audio buffers to allocate (increase if -you get buffer underruns)" - - int typestr="num" - default="20" - optional - details = "" diff --git a/osx_write.c b/osx_write.c deleted file mode 100644 index 18a2c084..00000000 --- a/osx_write.c +++ /dev/null @@ -1,371 +0,0 @@ -/* - * Copyright (C) 2006 Andre Noll - * - * Licensed under the GPL v2. For licencing details see COPYING. - */ - -/** \file osx_write.c paraslash's output plugin for MacOs */ - -/* - * based on mosx-mpg123, by Guillaume Outters and Steven A. Kortze - * - */ - -#include -#include - -#include "para.h" -#include "fd.h" -#include "string.h" -#include "list.h" -#include "sched.h" -#include "ggo.h" -#include "buffer_tree.h" -#include "write.h" -#include "write_common.h" -#include "osx_write.cmdline.h" -#include "ipc.h" -#include "error.h" - -#include -#include -#include - -/** Data specific to the osx writer. */ -struct private_osx_write_data { - /** The main CoreAudio handle. */ - AudioUnit audio_unit; - /** 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. */ - unsigned channels; - /** - * 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. - * - * 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; -}; - -/* 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) -{ - int i; - struct writer_node *wn = cb_arg; - 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. - */ - 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; - } - powd->playing = true; - } - - for (i = 0; i < abl->mNumberBuffers; i++) { - /* what we have to fill */ - 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; - } -out: - mutex_unlock(powd->mutex); - return noErr; -} - -static int core_audio_init(struct writer_node *wn) -{ - struct private_osx_write_data *powd = para_calloc(sizeof(*powd)); - Component comp; - int ret; - 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; - - PARA_INFO_LOG("wn: %p\n", wn); - ret = -E_DEFAULT_COMP; - comp = FindNextComponent(NULL, &desc); - if (!comp) - goto e0; - ret = -E_OPEN_COMP; - if (OpenAComponent(comp, &powd->audio_unit)) - goto e0; - ret = -E_UNIT_INIT; - if (AudioUnitInitialize(powd->audio_unit)) - goto e1; - get_btr_sample_rate(btrn, &val); - powd->sample_rate = val; - get_btr_channels(btrn, &val); - powd->channels = val; - get_btr_sample_format(btrn, &val); - powd->sample_format = val; - /* - * Choose PCM format. We tell the Output Unit what format we're going - * to supply data to it. This is necessary if you're providing data - * through an input callback AND you want the DefaultOutputUnit to do - * any format conversions necessary from your format to the device's - * format. - */ - - format.mSampleRate = powd->sample_rate; - 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.mBytesPerFrame = format.mBytesPerPacket; - - 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(format))) - goto e2; - ret = -E_ADD_CALLBACK; - if (AudioUnitSetProperty(powd->audio_unit, kAudioUnitProperty_SetRenderCallback, - 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; -e2: - AudioUnitUninitialize(powd->audio_unit); -e1: - CloseComponent(powd->audio_unit); -e0: - free(powd); - wn->private_data = NULL; - return ret; -} - -__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_write_cmdline_parser(argc, argv, conf); - return conf; -} - -static void osx_free_config(void *conf) -{ - osx_write_cmdline_parser_free(conf); -} - -static void osx_write_close(struct writer_node *wn) -{ - struct private_osx_write_data *powd = wn->private_data; - - if (!powd) - return; - PARA_INFO_LOG("closing writer node %p\n", wn); - mutex_destroy(powd->mutex); - free(powd); - wn->private_data = NULL; -} - -/* 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, void *context) -{ - struct writer_node *wn = context; - struct private_osx_write_data *powd = wn->private_data; - int ret; - bool drain_delay_nec = false; - - if (!powd) { - ret = btr_node_status(wn->btrn, wn->min_iqs, BTR_NT_LEAF); - if (ret != 0) - sched_min_delay(s); - return; - } - - mutex_lock(powd->mutex); - 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); - - 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 int osx_write_post_select(__a_unused struct sched *s, void *context) -{ - struct writer_node *wn = context; - struct private_osx_write_data *powd = wn->private_data; - struct btr_node *btrn = wn->btrn; - int ret; - - ret = task_get_notification(wn->task); - if (ret < 0) - goto fail; - if (!powd) { - ret = btr_node_status(btrn, wn->min_iqs, BTR_NT_LEAF); - if (ret == 0) - return 0; - if (ret < 0) - goto fail; - ret = core_audio_init(wn); - if (ret < 0) - goto fail; - powd = wn->private_data; - 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); - 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) - 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)); - return ret; -} - -/** - * 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; - - 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)DEFINE_GGO_HELP(osx_write); - osx_write_cmdline_parser_free(&dummy); -} diff --git a/web/about.in.html b/web/about.in.html index 2c72f281..d91a2ad4 100644 --- a/web/about.in.html +++ b/web/about.in.html @@ -5,7 +5,7 @@ Paraslash is a collection of network audio streaming tools for Unix systems. It is written in C and released under the GPLv2.
    -
  • Runs on Linux, Mac OS, FreeBSD, NetBSD
  • +
  • Runs on Linux, FreeBSD, NetBSD
  • Mp3, ogg/vorbis, ogg/speex, aac (m4a), wma, flac and ogg/opus support
  • http, dccp and udp network streaming
  • Stand-alone decoder, player, tagger
  • diff --git a/web/manual.md b/web/manual.md index 12454ee2..e7bb4afc 100644 --- a/web/manual.md +++ b/web/manual.md @@ -152,9 +152,8 @@ an array of offsets within the audio file. ### para_write ### A modular audio stream writer. It supports a simple file writer -output plug-in and optional WAV/raw players for ALSA (Linux) and for -coreaudio (Mac OS). para_write can also be used as a stand-alone WAV -or raw audio player. +output plug-in and optional WAV/raw players for ALSA (Linux) and OSS. +para_write can also be used as a stand-alone WAV or raw audio player. ### para_play ### @@ -1700,10 +1699,6 @@ emulation for backwards compatibility. This API is rather simple but also limited. For example only one application can open the device at any time. The OSS writer is activated by default on BSD Systems. -- *OSX*. Mac OS X has yet another API called CoreAudio. The OSX writer -for this API is only compiled in on such systems and is of course -the default there. - - *FILE*. The file writer allows to capture the audio stream and write the PCM data to a file on the file system rather than playing it through a sound device. It is supported on all platforms and is diff --git a/write.c b/write.c index 62caf097..9ff3bc84 100644 --- a/write.c +++ b/write.c @@ -52,8 +52,8 @@ __noreturn static void print_help_and_die(void) * \param wn The writer node. * * If arg is \p NULL, the OS-dependent default writer is used with no - * arguments. The default writers are alsa for Linux, osx for OS X, oss for - * *BSD, and the file writer if the default writer is not supported. + * arguments. The default writers are alsa for Linux and oss for *BSD, and the + * file writer if neither is supported. * * Once the writer configuration has been retrieved from the ->parse_config * callback a writer node is created, its buffer tree node is added to the -- 2.39.5