From: Andre Noll Date: Sun, 21 May 2017 21:12:48 +0000 (+0200) Subject: Remove osx_write.c, this time for real. X-Git-Tag: v0.6.1~75 X-Git-Url: http://git.tue.mpg.de/?a=commitdiff_plain;h=7d9e345416f87866bea1e0179641d31091b97ffb;p=paraslash.git Remove osx_write.c, this time for real. This file was removed prior to v0.6.0 in commit 3af6411b (Drop support for Mac OS), but it was brought back by mistake via the lopsub merge 764e71ce. --- diff --git a/osx_write.c b/osx_write.c deleted file mode 100644 index 0517892e..00000000 --- a/osx_write.c +++ /dev/null @@ -1,343 +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 - -#include "write_cmd.lsg.h" -#include "para.h" -#include "fd.h" -#include "string.h" -#include "list.h" -#include "sched.h" -#include "buffer_tree.h" -#include "write.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; -} - -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; -} - -struct writer lsg_write_cmd_com_osx_user_data = { - .close = osx_write_close, - .pre_select = osx_write_pre_select, - .post_select = osx_write_post_select, -};