| 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 |
|
|