33 |
|
|
34 |
struct { |
struct { |
35 |
int buffer_frames; |
int buffer_frames; |
36 |
|
int isAtexit; |
37 |
} conf = { |
} conf = { |
38 |
.buffer_frames = 512 |
.buffer_frames = 512, |
39 |
|
.isAtexit = 0 |
40 |
}; |
}; |
41 |
|
|
42 |
typedef struct coreaudioVoiceOut { |
typedef struct coreaudioVoiceOut { |
43 |
HWVoiceOut hw; |
HWVoiceOut hw; |
44 |
pthread_mutex_t mutex; |
pthread_mutex_t mutex; |
45 |
|
int isAtexit; |
46 |
AudioDeviceID outputDeviceID; |
AudioDeviceID outputDeviceID; |
47 |
UInt32 audioDevicePropertyBufferSize; |
UInt32 audioDevicePropertyBufferFrameSize; |
48 |
AudioStreamBasicDescription outputStreamBasicDescription; |
AudioStreamBasicDescription outputStreamBasicDescription; |
|
int isPlaying; |
|
49 |
int live; |
int live; |
50 |
int decr; |
int decr; |
51 |
int rpos; |
int rpos; |
141 |
coreaudio_logstatus (status); |
coreaudio_logstatus (status); |
142 |
} |
} |
143 |
|
|
144 |
|
static inline UInt32 isPlaying (AudioDeviceID outputDeviceID) |
145 |
|
{ |
146 |
|
OSStatus status; |
147 |
|
UInt32 result = 0; |
148 |
|
UInt32 propertySize = sizeof(outputDeviceID); |
149 |
|
status = AudioDeviceGetProperty( |
150 |
|
outputDeviceID, 0, 0, |
151 |
|
kAudioDevicePropertyDeviceIsRunning, &propertySize, &result); |
152 |
|
if (status != kAudioHardwareNoError) { |
153 |
|
coreaudio_logerr(status, |
154 |
|
"Could not determine whether Device is playing\n"); |
155 |
|
} |
156 |
|
return result; |
157 |
|
} |
158 |
|
|
159 |
|
static void coreaudio_atexit (void) |
160 |
|
{ |
161 |
|
conf.isAtexit = 1; |
162 |
|
} |
163 |
|
|
164 |
static int coreaudio_lock (coreaudioVoiceOut *core, const char *fn_name) |
static int coreaudio_lock (coreaudioVoiceOut *core, const char *fn_name) |
165 |
{ |
{ |
166 |
int err; |
int err; |
225 |
const AudioTimeStamp* inOutputTime, |
const AudioTimeStamp* inOutputTime, |
226 |
void* hwptr) |
void* hwptr) |
227 |
{ |
{ |
228 |
unsigned int frame, frameCount; |
UInt32 frame, frameCount; |
229 |
float *out = outOutputData->mBuffers[0].mData; |
float *out = outOutputData->mBuffers[0].mData; |
230 |
HWVoiceOut *hw = hwptr; |
HWVoiceOut *hw = hwptr; |
231 |
coreaudioVoiceOut *core = (coreaudioVoiceOut *) hwptr; |
coreaudioVoiceOut *core = (coreaudioVoiceOut *) hwptr; |
244 |
return 0; |
return 0; |
245 |
} |
} |
246 |
|
|
247 |
frameCount = conf.buffer_frames; |
frameCount = core->audioDevicePropertyBufferFrameSize; |
248 |
live = core->live; |
live = core->live; |
249 |
|
|
250 |
/* if there are not enough samples, set signal and return */ |
/* if there are not enough samples, set signal and return */ |
276 |
/* cleanup */ |
/* cleanup */ |
277 |
mixeng_clear (src, frameCount); |
mixeng_clear (src, frameCount); |
278 |
rpos = (rpos + frameCount) % hw->samples; |
rpos = (rpos + frameCount) % hw->samples; |
279 |
core->decr = frameCount; |
core->decr += frameCount; |
280 |
core->rpos = rpos; |
core->rpos = rpos; |
281 |
|
|
282 |
coreaudio_unlock (core, "audioDeviceIOProc"); |
coreaudio_unlock (core, "audioDeviceIOProc"); |
296 |
int err; |
int err; |
297 |
int bits = 8; |
int bits = 8; |
298 |
int endianess = 0; |
int endianess = 0; |
299 |
const char *typ = "DAC"; |
const char *typ = "playback"; |
300 |
|
AudioValueRange frameRange; |
301 |
|
|
302 |
/* create mutex */ |
/* create mutex */ |
303 |
err = pthread_mutex_init(&core->mutex, NULL); |
err = pthread_mutex_init(&core->mutex, NULL); |
335 |
return -1; |
return -1; |
336 |
} |
} |
337 |
|
|
338 |
/* set Buffersize to conf.buffer_frames frames */ |
/* get minimum and maximum buffer frame sizes */ |
339 |
propertySize = sizeof(core->audioDevicePropertyBufferSize); |
propertySize = sizeof(frameRange); |
340 |
core->audioDevicePropertyBufferSize = |
status = AudioDeviceGetProperty( |
341 |
conf.buffer_frames * sizeof(float) << (as->nchannels == 2); |
core->outputDeviceID, |
342 |
|
0, |
343 |
|
0, |
344 |
|
kAudioDevicePropertyBufferFrameSizeRange, |
345 |
|
&propertySize, |
346 |
|
&frameRange); |
347 |
|
if (status != kAudioHardwareNoError) { |
348 |
|
coreaudio_logerr2 (status, typ, |
349 |
|
"Could not get device buffer frame range\n"); |
350 |
|
return -1; |
351 |
|
} |
352 |
|
|
353 |
|
if (frameRange.mMinimum > conf.buffer_frames) { |
354 |
|
core->audioDevicePropertyBufferFrameSize = (UInt32) frameRange.mMinimum; |
355 |
|
dolog ("warning: Upsizing Buffer Frames to %f\n", frameRange.mMinimum); |
356 |
|
} |
357 |
|
else if (frameRange.mMaximum < conf.buffer_frames) { |
358 |
|
core->audioDevicePropertyBufferFrameSize = (UInt32) frameRange.mMaximum; |
359 |
|
dolog ("warning: Downsizing Buffer Frames to %f\n", frameRange.mMaximum); |
360 |
|
} |
361 |
|
else { |
362 |
|
core->audioDevicePropertyBufferFrameSize = conf.buffer_frames; |
363 |
|
} |
364 |
|
|
365 |
|
/* set Buffer Frame Size */ |
366 |
|
propertySize = sizeof(core->audioDevicePropertyBufferFrameSize); |
367 |
status = AudioDeviceSetProperty( |
status = AudioDeviceSetProperty( |
368 |
core->outputDeviceID, |
core->outputDeviceID, |
369 |
NULL, |
NULL, |
370 |
0, |
0, |
371 |
false, |
false, |
372 |
kAudioDevicePropertyBufferSize, |
kAudioDevicePropertyBufferFrameSize, |
373 |
propertySize, |
propertySize, |
374 |
&core->audioDevicePropertyBufferSize); |
&core->audioDevicePropertyBufferFrameSize); |
375 |
if (status != kAudioHardwareNoError) { |
if (status != kAudioHardwareNoError) { |
376 |
coreaudio_logerr2 (status, typ, |
coreaudio_logerr2 (status, typ, |
377 |
"Could not set device buffer size %d\n", |
"Could not set device buffer frame size %ld\n", |
378 |
kAudioDevicePropertyBufferSize); |
core->audioDevicePropertyBufferFrameSize); |
379 |
return -1; |
return -1; |
380 |
} |
} |
381 |
|
|
382 |
/* get Buffersize */ |
/* get Buffer Frame Size */ |
383 |
propertySize = sizeof(core->audioDevicePropertyBufferSize); |
propertySize = sizeof(core->audioDevicePropertyBufferFrameSize); |
384 |
status = AudioDeviceGetProperty( |
status = AudioDeviceGetProperty( |
385 |
core->outputDeviceID, |
core->outputDeviceID, |
386 |
0, |
0, |
387 |
false, |
false, |
388 |
kAudioDevicePropertyBufferSize, |
kAudioDevicePropertyBufferFrameSize, |
389 |
&propertySize, |
&propertySize, |
390 |
&core->audioDevicePropertyBufferSize); |
&core->audioDevicePropertyBufferFrameSize); |
391 |
if (status != kAudioHardwareNoError) { |
if (status != kAudioHardwareNoError) { |
392 |
coreaudio_logerr2 (status, typ, "Could not get device buffer size\n"); |
coreaudio_logerr2 (status, typ, |
393 |
|
"Could not get device buffer frame size\n"); |
394 |
return -1; |
return -1; |
395 |
} |
} |
396 |
hw->samples = (core->audioDevicePropertyBufferSize / sizeof (float)) |
hw->samples = 4 * core->audioDevicePropertyBufferFrameSize; |
|
>> (as->nchannels == 2); |
|
397 |
|
|
398 |
/* get StreamFormat */ |
/* get StreamFormat */ |
399 |
propertySize = sizeof(core->outputStreamBasicDescription); |
propertySize = sizeof(core->outputStreamBasicDescription); |
412 |
} |
} |
413 |
|
|
414 |
/* set Samplerate */ |
/* set Samplerate */ |
415 |
core->outputStreamBasicDescription.mSampleRate = (Float64)as->freq; |
core->outputStreamBasicDescription.mSampleRate = (Float64) as->freq; |
416 |
propertySize = sizeof(core->outputStreamBasicDescription); |
propertySize = sizeof(core->outputStreamBasicDescription); |
417 |
status = AudioDeviceSetProperty( |
status = AudioDeviceSetProperty( |
418 |
core->outputDeviceID, |
core->outputDeviceID, |
438 |
} |
} |
439 |
|
|
440 |
/* start Playback */ |
/* start Playback */ |
441 |
if (!core->isPlaying) { |
if (!isPlaying(core->outputDeviceID)) { |
442 |
status = AudioDeviceStart(core->outputDeviceID, audioDeviceIOProc); |
status = AudioDeviceStart(core->outputDeviceID, audioDeviceIOProc); |
443 |
if (status != kAudioHardwareNoError) { |
if (status != kAudioHardwareNoError) { |
444 |
coreaudio_logerr2 (status, typ, "Could not start playback\n"); |
coreaudio_logerr2 (status, typ, "Could not start playback\n"); |
446 |
core->outputDeviceID = kAudioDeviceUnknown; |
core->outputDeviceID = kAudioDeviceUnknown; |
447 |
return -1; |
return -1; |
448 |
} |
} |
|
core->isPlaying = 1; |
|
449 |
} |
} |
450 |
|
|
451 |
return 0; |
return 0; |
457 |
int err; |
int err; |
458 |
coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw; |
coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw; |
459 |
|
|
460 |
/* stop playback */ |
if (!conf.isAtexit) { |
461 |
if (core->isPlaying) { |
/* stop playback */ |
462 |
status = AudioDeviceStop(core->outputDeviceID, audioDeviceIOProc); |
if (isPlaying(core->outputDeviceID)) { |
463 |
if (status != kAudioHardwareNoError) { |
status = AudioDeviceStop(core->outputDeviceID, audioDeviceIOProc); |
464 |
coreaudio_logerr (status, "Could not stop playback\n"); |
if (status != kAudioHardwareNoError) { |
465 |
|
coreaudio_logerr (status, "Could not stop playback\n"); |
466 |
|
} |
467 |
} |
} |
|
core->isPlaying = 0; |
|
|
} |
|
468 |
|
|
469 |
/* remove callback */ |
/* remove callback */ |
470 |
status = AudioDeviceRemoveIOProc(core->outputDeviceID, audioDeviceIOProc); |
status = AudioDeviceRemoveIOProc(core->outputDeviceID, |
471 |
if (status != kAudioHardwareNoError) { |
audioDeviceIOProc); |
472 |
coreaudio_logerr (status, "Could not remove IOProc\n"); |
if (status != kAudioHardwareNoError) { |
473 |
|
coreaudio_logerr (status, "Could not remove IOProc\n"); |
474 |
|
} |
475 |
} |
} |
476 |
core->outputDeviceID = kAudioDeviceUnknown; |
core->outputDeviceID = kAudioDeviceUnknown; |
477 |
|
|
490 |
switch (cmd) { |
switch (cmd) { |
491 |
case VOICE_ENABLE: |
case VOICE_ENABLE: |
492 |
/* start playback */ |
/* start playback */ |
493 |
if (!core->isPlaying) { |
if (!isPlaying(core->outputDeviceID)) { |
494 |
status = AudioDeviceStart(core->outputDeviceID, audioDeviceIOProc); |
status = AudioDeviceStart(core->outputDeviceID, audioDeviceIOProc); |
495 |
if (status != kAudioHardwareNoError) { |
if (status != kAudioHardwareNoError) { |
496 |
coreaudio_logerr (status, "Could not unpause playback\n"); |
coreaudio_logerr (status, "Could not resume playback\n"); |
497 |
} |
} |
|
core->isPlaying = 1; |
|
498 |
} |
} |
499 |
break; |
break; |
500 |
|
|
501 |
case VOICE_DISABLE: |
case VOICE_DISABLE: |
502 |
/* stop playback */ |
/* stop playback */ |
503 |
if (core->isPlaying) { |
if (!conf.isAtexit) { |
504 |
status = AudioDeviceStop(core->outputDeviceID, audioDeviceIOProc); |
if (isPlaying(core->outputDeviceID)) { |
505 |
if (status != kAudioHardwareNoError) { |
status = AudioDeviceStop(core->outputDeviceID, audioDeviceIOProc); |
506 |
coreaudio_logerr (status, "Could not pause playback\n"); |
if (status != kAudioHardwareNoError) { |
507 |
|
coreaudio_logerr (status, "Could not pause playback\n"); |
508 |
|
} |
509 |
} |
} |
|
core->isPlaying = 0; |
|
510 |
} |
} |
511 |
break; |
break; |
512 |
} |
} |
515 |
|
|
516 |
static void *coreaudio_audio_init (void) |
static void *coreaudio_audio_init (void) |
517 |
{ |
{ |
518 |
|
atexit(coreaudio_atexit); |
519 |
return &coreaudio_audio_init; |
return &coreaudio_audio_init; |
520 |
} |
} |
521 |
|
|