#define AUDIO_CAP "coreaudio"
#include "audio_int.h"
-#define DEVICE_BUFFER_FRAMES (512)
-
struct {
int buffer_frames;
+ int nbuffers;
+ int isAtexit;
} conf = {
- .buffer_frames = 512
+ .buffer_frames = 512,
+ .nbuffers = 4,
+ .isAtexit = 0
};
typedef struct coreaudioVoiceOut {
HWVoiceOut hw;
pthread_mutex_t mutex;
+ int isAtexit;
AudioDeviceID outputDeviceID;
- UInt32 audioDevicePropertyBufferSize;
+ UInt32 audioDevicePropertyBufferFrameSize;
AudioStreamBasicDescription outputStreamBasicDescription;
- int isPlaying;
int live;
int decr;
int rpos;
{
va_list ap;
- AUD_log (AUDIO_CAP, "Can not initialize %s\n", typ);
+ AUD_log (AUDIO_CAP, "Could not initialize %s\n", typ);
va_start (ap, fmt);
AUD_vlog (AUDIO_CAP, fmt, ap);
coreaudio_logstatus (status);
}
+static inline UInt32 isPlaying (AudioDeviceID outputDeviceID)
+{
+ OSStatus status;
+ UInt32 result = 0;
+ UInt32 propertySize = sizeof(outputDeviceID);
+ status = AudioDeviceGetProperty(
+ outputDeviceID, 0, 0,
+ kAudioDevicePropertyDeviceIsRunning, &propertySize, &result);
+ if (status != kAudioHardwareNoError) {
+ coreaudio_logerr(status,
+ "Could not determine whether Device is playing\n");
+ }
+ return result;
+}
+
+static void coreaudio_atexit (void)
+{
+ conf.isAtexit = 1;
+}
+
static int coreaudio_lock (coreaudioVoiceOut *core, const char *fn_name)
{
int err;
err = pthread_mutex_lock (&core->mutex);
if (err) {
- dolog ("Can not lock voice for %s\nReason: %s\n",
+ dolog ("Could not lock voice for %s\nReason: %s\n",
fn_name, strerror (err));
return -1;
}
err = pthread_mutex_unlock (&core->mutex);
if (err) {
- dolog ("Can not unlock voice for %s\nReason: %s\n",
+ dolog ("Could not unlock voice for %s\nReason: %s\n",
fn_name, strerror (err));
return -1;
}
const AudioTimeStamp* inOutputTime,
void* hwptr)
{
- unsigned int frame, frameCount;
+ UInt32 frame, frameCount;
float *out = outOutputData->mBuffers[0].mData;
HWVoiceOut *hw = hwptr;
coreaudioVoiceOut *core = (coreaudioVoiceOut *) hwptr;
return 0;
}
- frameCount = conf.buffer_frames;
+ frameCount = core->audioDevicePropertyBufferFrameSize;
live = core->live;
/* if there are not enough samples, set signal and return */
#endif
}
- /* cleanup */
- mixeng_clear (src, frameCount);
rpos = (rpos + frameCount) % hw->samples;
- core->decr = frameCount;
+ core->decr += frameCount;
core->rpos = rpos;
coreaudio_unlock (core, "audioDeviceIOProc");
return audio_pcm_sw_write (sw, buf, len);
}
-static int coreaudio_init_out (HWVoiceOut *hw, int freq,
- int nchannels, audfmt_e fmt)
+static int coreaudio_init_out (HWVoiceOut *hw, audsettings_t *as)
{
OSStatus status;
coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
UInt32 propertySize;
int err;
- int bits = 8;
- int endianess = 0;
- const char *typ = "DAC";
+ const char *typ = "playback";
+ AudioValueRange frameRange;
/* create mutex */
err = pthread_mutex_init(&core->mutex, NULL);
if (err) {
- dolog("Can not create mutex\nReason: %s\n", strerror (err));
+ dolog("Could not create mutex\nReason: %s\n", strerror (err));
return -1;
}
- if (fmt == AUD_FMT_S16 || fmt == AUD_FMT_U16) {
- bits = 16;
- endianess = 1;
- }
-
- audio_pcm_init_info (
- &hw->info,
- freq,
- nchannels,
- fmt,
- /* Following is irrelevant actually since we do not use
- mixengs clipping routines */
- audio_need_to_swap_endian (endianess)
- );
- hw->bufsize = 4 * conf.buffer_frames * nchannels * bits;
+ audio_pcm_init_info (&hw->info, as);
/* open default output device */
propertySize = sizeof(core->outputDeviceID);
&core->outputDeviceID);
if (status != kAudioHardwareNoError) {
coreaudio_logerr2 (status, typ,
- "Can not get default output Device\n");
+ "Could not get default output Device\n");
return -1;
}
if (core->outputDeviceID == kAudioDeviceUnknown) {
- dolog ("Can not initialize %s - Unknown Audiodevice\n", typ);
+ dolog ("Could not initialize %s - Unknown Audiodevice\n", typ);
return -1;
}
- /* set Buffersize to conf.buffer_frames frames */
- propertySize = sizeof(core->audioDevicePropertyBufferSize);
- core->audioDevicePropertyBufferSize =
- conf.buffer_frames * sizeof(float) * 2;
+ /* get minimum and maximum buffer frame sizes */
+ propertySize = sizeof(frameRange);
+ status = AudioDeviceGetProperty(
+ core->outputDeviceID,
+ 0,
+ 0,
+ kAudioDevicePropertyBufferFrameSizeRange,
+ &propertySize,
+ &frameRange);
+ if (status != kAudioHardwareNoError) {
+ coreaudio_logerr2 (status, typ,
+ "Could not get device buffer frame range\n");
+ return -1;
+ }
+
+ if (frameRange.mMinimum > conf.buffer_frames) {
+ core->audioDevicePropertyBufferFrameSize = (UInt32) frameRange.mMinimum;
+ dolog ("warning: Upsizing Buffer Frames to %f\n", frameRange.mMinimum);
+ }
+ else if (frameRange.mMaximum < conf.buffer_frames) {
+ core->audioDevicePropertyBufferFrameSize = (UInt32) frameRange.mMaximum;
+ dolog ("warning: Downsizing Buffer Frames to %f\n", frameRange.mMaximum);
+ }
+ else {
+ core->audioDevicePropertyBufferFrameSize = conf.buffer_frames;
+ }
+
+ /* set Buffer Frame Size */
+ propertySize = sizeof(core->audioDevicePropertyBufferFrameSize);
status = AudioDeviceSetProperty(
core->outputDeviceID,
NULL,
0,
false,
- kAudioDevicePropertyBufferSize,
+ kAudioDevicePropertyBufferFrameSize,
propertySize,
- &core->audioDevicePropertyBufferSize);
+ &core->audioDevicePropertyBufferFrameSize);
if (status != kAudioHardwareNoError) {
coreaudio_logerr2 (status, typ,
- "Can not set device buffer size %d\n",
- kAudioDevicePropertyBufferSize);
+ "Could not set device buffer frame size %ld\n",
+ core->audioDevicePropertyBufferFrameSize);
return -1;
}
- /* get Buffersize */
- propertySize = sizeof(core->audioDevicePropertyBufferSize);
+ /* get Buffer Frame Size */
+ propertySize = sizeof(core->audioDevicePropertyBufferFrameSize);
status = AudioDeviceGetProperty(
core->outputDeviceID,
0,
false,
- kAudioDevicePropertyBufferSize,
+ kAudioDevicePropertyBufferFrameSize,
&propertySize,
- &core->audioDevicePropertyBufferSize);
+ &core->audioDevicePropertyBufferFrameSize);
if (status != kAudioHardwareNoError) {
- coreaudio_logerr2 (status, typ, "Can not get device buffer size\n");
+ coreaudio_logerr2 (status, typ,
+ "Could not get device buffer frame size\n");
return -1;
}
+ hw->samples = conf.nbuffers * core->audioDevicePropertyBufferFrameSize;
/* get StreamFormat */
propertySize = sizeof(core->outputStreamBasicDescription);
&core->outputStreamBasicDescription);
if (status != kAudioHardwareNoError) {
coreaudio_logerr2 (status, typ,
- "Can not get Device Stream properties\n");
+ "Could not get Device Stream properties\n");
core->outputDeviceID = kAudioDeviceUnknown;
return -1;
}
/* set Samplerate */
- core->outputStreamBasicDescription.mSampleRate = (Float64)freq;
+ core->outputStreamBasicDescription.mSampleRate = (Float64) as->freq;
propertySize = sizeof(core->outputStreamBasicDescription);
status = AudioDeviceSetProperty(
core->outputDeviceID,
propertySize,
&core->outputStreamBasicDescription);
if (status != kAudioHardwareNoError) {
- coreaudio_logerr2 (status, typ, "Can not set samplerate %d\n", freq);
+ coreaudio_logerr2 (status, typ, "Could not set samplerate %d\n",
+ as->freq);
core->outputDeviceID = kAudioDeviceUnknown;
return -1;
}
/* set Callback */
status = AudioDeviceAddIOProc(core->outputDeviceID, audioDeviceIOProc, hw);
if (status != kAudioHardwareNoError) {
- coreaudio_logerr2 (status, typ, "Can not set IOProc\n");
+ coreaudio_logerr2 (status, typ, "Could not set IOProc\n");
core->outputDeviceID = kAudioDeviceUnknown;
return -1;
}
/* start Playback */
- if (!core->isPlaying) {
+ if (!isPlaying(core->outputDeviceID)) {
status = AudioDeviceStart(core->outputDeviceID, audioDeviceIOProc);
if (status != kAudioHardwareNoError) {
- coreaudio_logerr2 (status, typ, "Can not start playback\n");
+ coreaudio_logerr2 (status, typ, "Could not start playback\n");
AudioDeviceRemoveIOProc(core->outputDeviceID, audioDeviceIOProc);
core->outputDeviceID = kAudioDeviceUnknown;
return -1;
}
- core->isPlaying = 1;
}
return 0;
int err;
coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
- /* stop playback */
- if (core->isPlaying) {
- status = AudioDeviceStop(core->outputDeviceID, audioDeviceIOProc);
- if (status != kAudioHardwareNoError) {
- coreaudio_logerr (status, "Can not stop playback\n");
+ if (!conf.isAtexit) {
+ /* stop playback */
+ if (isPlaying(core->outputDeviceID)) {
+ status = AudioDeviceStop(core->outputDeviceID, audioDeviceIOProc);
+ if (status != kAudioHardwareNoError) {
+ coreaudio_logerr (status, "Could not stop playback\n");
+ }
}
- core->isPlaying = 0;
- }
- /* remove callback */
- status = AudioDeviceRemoveIOProc(core->outputDeviceID, audioDeviceIOProc);
- if (status != kAudioHardwareNoError) {
- coreaudio_logerr (status, "Can not remove IOProc\n");
+ /* remove callback */
+ status = AudioDeviceRemoveIOProc(core->outputDeviceID,
+ audioDeviceIOProc);
+ if (status != kAudioHardwareNoError) {
+ coreaudio_logerr (status, "Could not remove IOProc\n");
+ }
}
core->outputDeviceID = kAudioDeviceUnknown;
/* destroy mutex */
err = pthread_mutex_destroy(&core->mutex);
if (err) {
- dolog("Can not destroy mutex\nReason: %s\n", strerror (err));
+ dolog("Could not destroy mutex\nReason: %s\n", strerror (err));
}
}
switch (cmd) {
case VOICE_ENABLE:
/* start playback */
- if (!core->isPlaying) {
+ if (!isPlaying(core->outputDeviceID)) {
status = AudioDeviceStart(core->outputDeviceID, audioDeviceIOProc);
if (status != kAudioHardwareNoError) {
- coreaudio_logerr (status, "Can not unpause playback\n");
+ coreaudio_logerr (status, "Could not resume playback\n");
}
- core->isPlaying = 1;
}
break;
case VOICE_DISABLE:
/* stop playback */
- if (core->isPlaying) {
- status = AudioDeviceStop(core->outputDeviceID, audioDeviceIOProc);
- if (status != kAudioHardwareNoError) {
- coreaudio_logerr (status, "Can not pause playback\n");
+ if (!conf.isAtexit) {
+ if (isPlaying(core->outputDeviceID)) {
+ status = AudioDeviceStop(core->outputDeviceID, audioDeviceIOProc);
+ if (status != kAudioHardwareNoError) {
+ coreaudio_logerr (status, "Could not pause playback\n");
+ }
}
- core->isPlaying = 0;
}
break;
}
static void *coreaudio_audio_init (void)
{
+ atexit(coreaudio_atexit);
return &coreaudio_audio_init;
}
static struct audio_option coreaudio_options[] = {
{"BUFFER_SIZE", AUD_OPT_INT, &conf.buffer_frames,
"Size of the buffer in frames", NULL, 0},
+ {"BUFFER_COUNT", AUD_OPT_INT, &conf.nbuffers,
+ "Number of buffers", NULL, 0},
{NULL, 0, NULL, NULL, NULL, 0}
};