/** \file osx_writer.c paraslash's output plugin for MacOs */
+/*
+ * based on mosx-mpg123, by Guillaume Outters and Steven A. Kortze
+ * <skortze@sourceforge.net>
+ */
+
#include <CoreAudio/CoreAudio.h>
#include "para.h"
#include "fd.h"
#include <CoreAudio/CoreAudio.h>
#include <AudioUnit/AudioUnit.h>
#include <AudioToolbox/DefaultAudioOutput.h>
-#include <semaphore.h>
struct osx_buffer {
float *buffer;
long size;
short *ptr;
AudioUnit output;
char play;
- sem_t *semaphore;
osx_buffer *from; /* Current buffers */
osx_buffer *to;
+ unsigned samplerate;
+ unsigned channels;
};
(*ptrptr)->buffer = NULL;
ptrptr = &(*ptrptr)->next;
/* This buffer is ready for filling (of course, it is empty!) */
- sem_post(powd->semaphore);
}
*ptrptr = powd->from = powd->to;
}
dest = outOutputData->mBuffers[i].mData;
while (m > 0) {
if ((n = powd->from->remaining) <= 0) {
+ PARA_INFO_LOG("%s", "buffer underrun\n");
/* no more bytes in the current read buffer! */
while ((n = powd->from->remaining) <= 0)
/* wait for the results */
/* remember all done work */
m -= n;
powd->from->ptr += n;
- if ((powd->from->remaining -= n) <= 0) {
- /* tell that there's a buffer to fill */
- sem_post(powd->semaphore);
+ if ((powd->from->remaining -= n) <= 0)
powd->from = powd->from->next;
- }
}
}
return 0;
Component comp;
AURenderCallbackStruct inputCallback = {osx_callback, powd};
AudioStreamBasicDescription format;
- char s[10];
- int m, ret;
+ int ret;
+ struct writer_node_group *wng = wn->wng;
+ struct osx_write_args_info *conf = wn->conf;
wn->private_data = powd;
/* where did that default audio output go? */
* AND you want the DefaultOutputUnit to do any format conversions
* necessary from your format to the device's format.
*/
- format.mSampleRate = 44100.0; /* The sample rate of the audio stream */
+ if (!conf->samplerate_given && wng->samplerate)
+ powd->samplerate = *wng->samplerate;
+ else
+ powd->samplerate = conf->samplerate_arg;
+ format.mSampleRate = powd->samplerate;
/* The specific encoding type of audio stream*/
format.mFormatID = kAudioFormatLinearPCM;
/* flags specific to each format */
format.mFormatFlags = kLinearPCMFormatFlagIsFloat
| kLinearPCMFormatFlagIsPacked
| kLinearPCMFormatFlagIsBigEndian;
- /*
- * We produce 2-channel audio. Now if we have a mega-super-hyper card for our
- * audio, it is its problem to convert it to 8-, 16-, 32- or 1024-channel data.
- */
- format.mBytesPerFrame = (format.mFramesPerPacket = 1)
- * (format.mBytesPerPacket = (format.mChannelsPerFrame = 2) * sizeof(float));
+ if (!conf->channels_given && wng->channels)
+ powd->channels = *wng->channels;
+ else
+ powd->channels = conf->channels_arg;
+ format.mChannelsPerFrame = powd->channels;
+ format.mFramesPerPacket = 1;
+ format.mBytesPerPacket = format.mChannelsPerFrame * sizeof(float);
+ format.mBytesPerFrame = format.mFramesPerPacket * format.mBytesPerPacket;
/* one of the most constant constants of the whole computer history */
format.mBitsPerChannel = sizeof(float) * 8;
ret = -E_STREAM_FORMAT;
kAudioUnitScope_Input, 0, &format,
sizeof(AudioStreamBasicDescription)))
goto e2;
- /* init the semaphore */
- strcpy(s, "/mpg123-0000");
- do {
- for (m = 10;; m--)
- if( (s[m]++) <= '9')
- break;
- else
- s[m] = '0';
- } while ((powd->semaphore = sem_open(s, O_CREAT | O_EXCL, 0644, 0))
- == (sem_t *)SEM_FAILED);
init_buffers(powd);
ret = -E_ADD_CALLBACK;
if (AudioUnitSetProperty(powd->output, kAudioUnitProperty_SetRenderCallback,
AudioUnitUninitialize(powd->output);
CloseComponent(powd->output);
destroy_buffers(powd);
- sem_close(powd->semaphore);
free(powd);
}
+static int need_new_buffer(struct writer_node *wn)
+{
+ struct writer_node_group *wng = wn->wng;
+ struct private_osx_writer_data *powd = wn->private_data;
+
+ if (*wng->loaded < sizeof(short))
+ return 0;
+ if (powd->to->remaining) /* Non empty buffer, must still be playing */
+ return 0;
+ return 1;
+}
+
static int osx_write_post_select(__a_unused struct sched *s,
struct writer_node *wn)
{
struct private_osx_writer_data *powd = wn->private_data;
struct writer_node_group *wng = wn->wng;
- short *data = (short*)wng->buf + wn->written;
+ short *data = (short*)wng->buf;
- if (*wng->loaded <= wn->written)
- return 1;
- if (powd->to->remaining) /* Non empty buffer, must still be playing */
+ if (!need_new_buffer(wn))
return 1;
- fill_buffer(powd->to, data, (*wng->loaded - wn->written) / sizeof(short));
+ fill_buffer(powd->to, data, *wng->loaded / sizeof(short));
powd->to = powd->to->next;
- wn->written += (*wng->loaded - wn->written);
+ wn->written = *wng->loaded;
if (!powd->play) {
if (AudioOutputUnitStart(powd->output))
return -1;