/** \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;
};
powd->to->next = NULL;
while (ptr) {
ptr2 = ptr->next;
- if (ptr->buffer)
- free(ptr->buffer);
+ free(ptr->buffer);
free(ptr);
ptr = ptr2;
}
(*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;
}
b->size = size;
}
dest = b->buffer;
- while (size--)
+ while (size--) {
+ char *tmp = (char *)source;
+ char c = *tmp;
+ *tmp = *(tmp + 1);
+ *(tmp + 1) = c;
/* *dest++ = ((*source++) + 32768) / 65536.0; */
*dest++ = (*source++) / 32768.0;
+ }
b->ptr = b->buffer;
b->remaining = b->size;
}
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,
kAudioUnitScope_Input, 0, &inputCallback,
sizeof(inputCallback)) < 0)
goto e3;
- return 0;
+ return 1;
e3:
destroy_buffers(powd);
e2:
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)
+ if (!need_new_buffer(wn))
return 1;
- if (powd->to->remaining) /* Non empty buffer, must still be playing */
- 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;
+ return -E_UNIT_START;
powd->play = 1;
}
return 1;
}
-static int osx_write_pre_select(struct sched *s, struct writer_node *wn)
+static int osx_write_pre_select(struct sched *s, __a_unused struct writer_node *wn)
{
- struct writer_node_group *wng = wn->wng;
- struct private_osx_writer_data *powd = wn->private_data;
-
-// if (!*wng->loaded)
-// return 1;
-// if (powd->to->remaining) /* Non empty buffer, must still be playing */
-// return 1;
s->timeout.tv_sec = 0;
s->timeout.tv_usec = 20;
return 1;