1/*** 2 This file is part of PulseAudio. 3 4 Copyright 2009,2010 Daniel Mack <daniel@caiaq.de> 5 6 PulseAudio is free software; you can redistribute it and/or modify 7 it under the terms of the GNU Lesser General Public License as published 8 by the Free Software Foundation; either version 2.1 of the License, 9 or (at your option) any later version. 10 11 PulseAudio is distributed in the hope that it will be useful, but 12 WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 General Public License for more details. 15 16 You should have received a copy of the GNU Lesser General Public License 17 along with PulseAudio; if not, see <http://www.gnu.org/licenses/>. 18***/ 19 20/* TODO: 21 - implement hardware volume controls 22 - handle audio device stream format changes (will require changes to the core) 23 - add an "off" mode that removes all sinks and sources 24*/ 25 26#ifdef HAVE_CONFIG_H 27#include <config.h> 28#endif 29 30#include <pulse/util.h> 31#include <pulse/xmalloc.h> 32 33#include <pulsecore/sink.h> 34#include <pulsecore/source.h> 35#include <pulsecore/module.h> 36#include <pulsecore/sample-util.h> 37#include <pulsecore/core-util.h> 38#include <pulsecore/modargs.h> 39#include <pulsecore/log.h> 40#include <pulsecore/macro.h> 41#include <pulsecore/llist.h> 42#include <pulsecore/card.h> 43#include <pulsecore/strbuf.h> 44#include <pulsecore/thread.h> 45#include <pulsecore/thread-mq.h> 46#include <pulsecore/i18n.h> 47 48#include <CoreAudio/CoreAudio.h> 49#include <CoreAudio/CoreAudioTypes.h> 50#include <CoreAudio/AudioHardware.h> 51 52#define DEFAULT_FRAMES_PER_IOPROC 512 53 54PA_MODULE_AUTHOR("Daniel Mack"); 55PA_MODULE_DESCRIPTION("CoreAudio device"); 56PA_MODULE_VERSION(PACKAGE_VERSION); 57PA_MODULE_LOAD_ONCE(false); 58PA_MODULE_USAGE("object_id=<the CoreAudio device id> " 59 "ioproc_frames=<audio frames per IOProc call> " 60 "record=<enable source?> " 61 "playback=<enable sink?> "); 62 63static const char* const valid_modargs[] = { 64 "object_id", 65 "ioproc_frames", 66 "record", 67 "playback", 68 NULL 69}; 70 71enum { 72 CA_MESSAGE_RENDER = PA_SINK_MESSAGE_MAX, 73}; 74 75typedef struct coreaudio_sink coreaudio_sink; 76typedef struct coreaudio_source coreaudio_source; 77 78struct userdata { 79 AudioObjectID object_id; 80 AudioDeviceIOProcID proc_id; 81 82 pa_thread_mq thread_mq; 83 pa_asyncmsgq *async_msgq; 84 85 pa_rtpoll *rtpoll; 86 pa_thread *thread; 87 88 pa_module *module; 89 pa_card *card; 90 bool running; 91 92 char *device_name, *vendor_name; 93 94 const AudioBufferList *render_input_data; 95 AudioBufferList *render_output_data; 96 97 AudioStreamBasicDescription stream_description; 98 99 PA_LLIST_HEAD(coreaudio_sink, sinks); 100 PA_LLIST_HEAD(coreaudio_source, sources); 101}; 102 103struct coreaudio_sink { 104 pa_sink *pa_sink; 105 struct userdata *userdata; 106 107 char *name; 108 unsigned int channel_idx; 109 bool active; 110 111 pa_channel_map map; 112 pa_sample_spec ss; 113 114 PA_LLIST_FIELDS(coreaudio_sink); 115}; 116 117struct coreaudio_source { 118 pa_source *pa_source; 119 struct userdata *userdata; 120 121 char *name; 122 unsigned int channel_idx; 123 bool active; 124 125 pa_channel_map map; 126 pa_sample_spec ss; 127 128 PA_LLIST_FIELDS(coreaudio_source); 129}; 130 131static int card_set_profile(pa_card *c, pa_card_profile *new_profile) { 132 return 0; 133} 134 135static OSStatus io_render_proc (AudioDeviceID device, 136 const AudioTimeStamp *now, 137 const AudioBufferList *inputData, 138 const AudioTimeStamp *inputTime, 139 AudioBufferList *outputData, 140 const AudioTimeStamp *outputTime, 141 void *clientData) { 142 struct userdata *u = clientData; 143 144 pa_assert(u); 145 pa_assert(device == u->object_id); 146 147 u->render_input_data = inputData; 148 u->render_output_data = outputData; 149 150 if (u->sinks) 151 pa_assert_se(pa_asyncmsgq_send(u->async_msgq, PA_MSGOBJECT(u->sinks->pa_sink), 152 CA_MESSAGE_RENDER, NULL, 0, NULL) == 0); 153 154 if (u->sources) 155 pa_assert_se(pa_asyncmsgq_send(u->async_msgq, PA_MSGOBJECT(u->sources->pa_source), 156 CA_MESSAGE_RENDER, NULL, 0, NULL) == 0); 157 158 return 0; 159} 160 161static OSStatus ca_stream_format_changed(AudioObjectID objectID, 162 UInt32 numberAddresses, 163 const AudioObjectPropertyAddress addresses[], 164 void *clientData) { 165 struct userdata *u = clientData; 166 UInt32 i; 167 168 pa_assert(u); 169 170 /* REVISIT: PA can't currently handle external format change requests. 171 * Hence, we set the original format back in this callback to avoid horrible audio artefacts. 172 * The device settings will appear to be 'locked' for any application as long as the PA daemon is running. 173 * Once we're able to propagate such events up in the core, this needs to be changed. */ 174 175 for (i = 0; i < numberAddresses; i++) 176 AudioObjectSetPropertyData(objectID, addresses + i, 0, NULL, sizeof(u->stream_description), &u->stream_description); 177 178 return 0; 179} 180 181static pa_usec_t get_latency_us(pa_object *o) { 182 struct userdata *u; 183 pa_sample_spec *ss; 184 bool is_source; 185 UInt32 v = 0, total = 0; 186 OSStatus err; 187 UInt32 size = sizeof(v); 188 AudioObjectPropertyAddress property_address; 189 AudioObjectID stream_id; 190 191 if (pa_sink_isinstance(o)) { 192 coreaudio_sink *sink = PA_SINK(o)->userdata; 193 194 u = sink->userdata; 195 ss = &sink->ss; 196 is_source = false; 197 } else if (pa_source_isinstance(o)) { 198 coreaudio_source *source = PA_SOURCE(o)->userdata; 199 200 u = source->userdata; 201 ss = &source->ss; 202 is_source = true; 203 } else 204 pa_assert_not_reached(); 205 206 pa_assert(u); 207 208 property_address.mScope = is_source ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput; 209 property_address.mElement = kAudioObjectPropertyElementMaster; 210 211 /* get the device latency */ 212 property_address.mSelector = kAudioDevicePropertyLatency; 213 size = sizeof(v); 214 err = AudioObjectGetPropertyData(u->object_id, &property_address, 0, NULL, &size, &v); 215 if (!err) 216 total += v; 217 else 218 pa_log_warn("Failed to get device latency: %d", err); 219 220 /* the IOProc buffer size */ 221 property_address.mSelector = kAudioDevicePropertyBufferFrameSize; 222 size = sizeof(v); 223 err = AudioObjectGetPropertyData(u->object_id, &property_address, 0, NULL, &size, &v); 224 if (!err) 225 total += v; 226 else 227 pa_log_warn("Failed to get buffer frame size: %d", err); 228 229 /* IOProc safety offset - this value is the same for both directions, hence we divide it by 2 */ 230 property_address.mSelector = kAudioDevicePropertySafetyOffset; 231 size = sizeof(v); 232 err = AudioObjectGetPropertyData(u->object_id, &property_address, 0, NULL, &size, &v); 233 if (!err) 234 total += v / 2; 235 else 236 pa_log_warn("Failed to get safety offset: %d", err); 237 238 /* get the stream latency. 239 * FIXME: this assumes the stream latency is the same for all streams */ 240 property_address.mSelector = kAudioDevicePropertyStreams; 241 size = sizeof(stream_id); 242 err = AudioObjectGetPropertyData(u->object_id, &property_address, 0, NULL, &size, &stream_id); 243 if (!err) { 244 property_address.mSelector = kAudioStreamPropertyLatency; 245 property_address.mScope = kAudioObjectPropertyScopeGlobal; 246 size = sizeof(v); 247 err = AudioObjectGetPropertyData(stream_id, &property_address, 0, NULL, &size, &v); 248 if (!err) 249 total += v; 250 else 251 pa_log_warn("Failed to get stream latency: %d", err); 252 } else 253 pa_log_warn("Failed to get streams: %d", err); 254 255 return pa_bytes_to_usec(total * pa_frame_size(ss), ss); 256} 257 258static void ca_device_check_device_state(struct userdata *u) { 259 coreaudio_sink *ca_sink; 260 coreaudio_source *ca_source; 261 bool active = false; 262 263 pa_assert(u); 264 265 for (ca_sink = u->sinks; ca_sink; ca_sink = ca_sink->next) 266 if (ca_sink->active) 267 active = true; 268 269 for (ca_source = u->sources; ca_source; ca_source = ca_source->next) 270 if (ca_source->active) 271 active = true; 272 273 if (active && !u->running) 274 AudioDeviceStart(u->object_id, u->proc_id); 275 else if (!active && u->running) 276 AudioDeviceStop(u->object_id, u->proc_id); 277 278 u->running = active; 279} 280 281static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) { 282 coreaudio_sink *sink = PA_SINK(o)->userdata; 283 struct userdata *u = sink->userdata; 284 unsigned int i; 285 pa_memchunk audio_chunk; 286 287 switch (code) { 288 case CA_MESSAGE_RENDER: { 289 /* audio out */ 290 for (i = 0; i < u->render_output_data->mNumberBuffers; i++) { 291 AudioBuffer *buf = u->render_output_data->mBuffers + i; 292 293 pa_assert(sink); 294 295 if (PA_SINK_IS_OPENED(sink->pa_sink->thread_info.state)) { 296 audio_chunk.memblock = pa_memblock_new_fixed(u->module->core->mempool, buf->mData, buf->mDataByteSize, false); 297 audio_chunk.length = buf->mDataByteSize; 298 audio_chunk.index = 0; 299 300 pa_sink_render_into_full(sink->pa_sink, &audio_chunk); 301 pa_memblock_unref_fixed(audio_chunk.memblock); 302 } 303 304 sink = sink->next; 305 } 306 307 return 0; 308 } 309 310 case PA_SINK_MESSAGE_GET_LATENCY: { 311 *((int64_t *) data) = get_latency_us(PA_OBJECT(o)); 312 return 0; 313 } 314 } 315 316 return pa_sink_process_msg(o, code, data, offset, chunk); 317} 318 319static int source_process_msg(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) { 320 coreaudio_source *source = PA_SOURCE(o)->userdata; 321 struct userdata *u = source->userdata; 322 unsigned int i; 323 pa_memchunk audio_chunk; 324 325 switch (code) { 326 case CA_MESSAGE_RENDER: { 327 /* audio in */ 328 for (i = 0; i < u->render_input_data->mNumberBuffers; i++) { 329 const AudioBuffer *buf = u->render_input_data->mBuffers + i; 330 331 pa_assert(source); 332 333 if (PA_SOURCE_IS_OPENED(source->pa_source->thread_info.state)) { 334 audio_chunk.memblock = pa_memblock_new_fixed(u->module->core->mempool, buf->mData, buf->mDataByteSize, true); 335 audio_chunk.length = buf->mDataByteSize; 336 audio_chunk.index = 0; 337 338 pa_source_post(source->pa_source, &audio_chunk); 339 pa_memblock_unref_fixed(audio_chunk.memblock); 340 } 341 342 source = source->next; 343 } 344 345 return 0; 346 } 347 348 case PA_SOURCE_MESSAGE_GET_LATENCY: { 349 *((int64_t *) data) = get_latency_us(PA_OBJECT(o)); 350 return 0; 351 } 352 } 353 354 return pa_source_process_msg(o, code, data, offset, chunk);; 355} 356 357static int ca_sink_set_state_in_main_thread(pa_sink *s, pa_sink_state_t state, pa_suspend_cause_t suspend_cause) { 358 coreaudio_sink *sink = s->userdata; 359 360 switch (state) { 361 case PA_SINK_SUSPENDED: 362 case PA_SINK_IDLE: 363 sink->active = false; 364 break; 365 366 case PA_SINK_RUNNING: 367 sink->active = true; 368 break; 369 370 case PA_SINK_UNLINKED: 371 case PA_SINK_INIT: 372 case PA_SINK_INVALID_STATE: 373 ; 374 } 375 376 ca_device_check_device_state(sink->userdata); 377 378 return 0; 379} 380 381/* Caveat: The caller is responsible to get rid of the CFString(Ref). */ 382static char * CFString_to_cstr(CFStringRef cfstr) { 383 char *ret = NULL; 384 385 if (cfstr != NULL) { 386 const char *tmp = CFStringGetCStringPtr(cfstr, kCFStringEncodingUTF8); 387 CFIndex n = CFStringGetLength(cfstr) + 1 /* for the terminating NULL */; 388 389 ret = pa_xmalloc(n); 390 391 if (tmp == NULL) { 392 if (!CFStringGetCString(cfstr, ret, n, kCFStringEncodingUTF8)) { 393 pa_xfree(ret); 394 ret = NULL; 395 } 396 } else { 397 strncpy(ret, tmp, n - 1); 398 ret[n - 1] = '\0'; 399 } 400 } 401 402 return ret; 403} 404 405static int ca_device_create_sink(pa_module *m, AudioBuffer *buf, int channel_idx) { 406 OSStatus err; 407 UInt32 size; 408 struct userdata *u = m->userdata; 409 pa_sink_new_data new_data; 410 pa_sink_flags_t flags = PA_SINK_LATENCY | PA_SINK_HARDWARE; 411 coreaudio_sink *ca_sink; 412 pa_sink *sink; 413 unsigned int i; 414 char *tmp = NULL; 415 pa_strbuf *strbuf; 416 AudioObjectPropertyAddress property_address; 417 CFStringRef tmp_cfstr = NULL; 418 419 if (buf->mNumberChannels > PA_CHANNELS_MAX) { 420 pa_log("Skipping device with more channels than we support (%u)", (unsigned int) buf->mNumberChannels); 421 return -1; 422 } 423 424 ca_sink = pa_xnew0(coreaudio_sink, 1); 425 ca_sink->map.channels = buf->mNumberChannels; 426 ca_sink->ss.channels = buf->mNumberChannels; 427 ca_sink->channel_idx = channel_idx; 428 429 /* build a name for this stream */ 430 strbuf = pa_strbuf_new(); 431 432 for (i = 0; i < buf->mNumberChannels; i++) { 433 property_address.mSelector = kAudioObjectPropertyElementName; 434 property_address.mScope = kAudioDevicePropertyScopeOutput; 435 property_address.mElement = channel_idx + i + 1; 436 size = sizeof(tmp_cfstr); 437 err = AudioObjectGetPropertyData(u->object_id, &property_address, 0, NULL, &size, &tmp_cfstr); 438 if (err == 0) { 439 tmp = CFString_to_cstr(tmp_cfstr); 440 441 if (tmp_cfstr) 442 CFRelease(tmp_cfstr); 443 } 444 445 if (i > 0) 446 pa_strbuf_puts(strbuf, ", "); 447 448 if (err || !tmp || !strlen(tmp)) 449 pa_strbuf_printf(strbuf, "Channel %d", (int) property_address.mElement); 450 else 451 pa_strbuf_puts(strbuf, tmp); 452 453 pa_xfree(tmp); 454 tmp = NULL; 455 } 456 457 ca_sink->name = pa_strbuf_to_string_free(strbuf); 458 459 pa_log_debug("Stream name is >%s<", ca_sink->name); 460 461 /* default to mono streams */ 462 for (i = 0; i < ca_sink->map.channels; i++) 463 ca_sink->map.map[i] = PA_CHANNEL_POSITION_MONO; 464 465 if (buf->mNumberChannels == 2) { 466 ca_sink->map.map[0] = PA_CHANNEL_POSITION_LEFT; 467 ca_sink->map.map[1] = PA_CHANNEL_POSITION_RIGHT; 468 } 469 470 ca_sink->ss.rate = u->stream_description.mSampleRate; 471 ca_sink->ss.format = PA_SAMPLE_FLOAT32LE; 472 473 pa_sink_new_data_init(&new_data); 474 new_data.card = u->card; 475 new_data.driver = __FILE__; 476 new_data.module = u->module; 477 new_data.namereg_fail = false; 478 pa_sink_new_data_set_name(&new_data, ca_sink->name); 479 pa_sink_new_data_set_channel_map(&new_data, &ca_sink->map); 480 pa_sink_new_data_set_sample_spec(&new_data, &ca_sink->ss); 481 pa_proplist_sets(new_data.proplist, PA_PROP_DEVICE_STRING, u->device_name); 482 pa_proplist_sets(new_data.proplist, PA_PROP_DEVICE_PRODUCT_NAME, u->device_name); 483 pa_proplist_sets(new_data.proplist, PA_PROP_DEVICE_DESCRIPTION, u->device_name); 484 pa_proplist_sets(new_data.proplist, PA_PROP_DEVICE_ACCESS_MODE, "mmap"); 485 pa_proplist_sets(new_data.proplist, PA_PROP_DEVICE_CLASS, "sound"); 486 pa_proplist_sets(new_data.proplist, PA_PROP_DEVICE_API, "CoreAudio"); 487 pa_proplist_setf(new_data.proplist, PA_PROP_DEVICE_BUFFERING_BUFFER_SIZE, "%lu", (unsigned long) buf->mDataByteSize); 488 489 if (u->vendor_name) 490 pa_proplist_sets(new_data.proplist, PA_PROP_DEVICE_VENDOR_NAME, u->vendor_name); 491 492 sink = pa_sink_new(m->core, &new_data, flags); 493 pa_sink_new_data_done(&new_data); 494 495 if (!sink) { 496 pa_log("unable to create sink."); 497 return -1; 498 } 499 500 sink->parent.process_msg = sink_process_msg; 501 sink->userdata = ca_sink; 502 sink->set_state_in_main_thread = ca_sink_set_state_in_main_thread; 503 504 pa_sink_set_asyncmsgq(sink, u->thread_mq.inq); 505 pa_sink_set_rtpoll(sink, u->rtpoll); 506 507 ca_sink->pa_sink = sink; 508 ca_sink->userdata = u; 509 510 PA_LLIST_PREPEND(coreaudio_sink, u->sinks, ca_sink); 511 512 return 0; 513} 514 515static int ca_source_set_state_in_main_thread(pa_source *s, pa_source_state_t state, pa_suspend_cause_t suspend_cause) { 516 coreaudio_source *source = s->userdata; 517 518 switch (state) { 519 case PA_SOURCE_SUSPENDED: 520 case PA_SOURCE_IDLE: 521 source->active = false; 522 break; 523 524 case PA_SOURCE_RUNNING: 525 source->active = true; 526 break; 527 528 case PA_SOURCE_UNLINKED: 529 case PA_SOURCE_INIT: 530 case PA_SOURCE_INVALID_STATE: 531 ; 532 } 533 534 ca_device_check_device_state(source->userdata); 535 536 return 0; 537} 538 539static int ca_device_create_source(pa_module *m, AudioBuffer *buf, int channel_idx) { 540 OSStatus err; 541 UInt32 size; 542 struct userdata *u = m->userdata; 543 pa_source_new_data new_data; 544 pa_source_flags_t flags = PA_SOURCE_LATENCY | PA_SOURCE_HARDWARE; 545 coreaudio_source *ca_source; 546 pa_source *source; 547 unsigned int i; 548 char *tmp = NULL; 549 pa_strbuf *strbuf; 550 AudioObjectPropertyAddress property_address; 551 CFStringRef tmp_cfstr = NULL; 552 553 if (buf->mNumberChannels > PA_CHANNELS_MAX) { 554 pa_log("Skipping device with more channels than we support (%u)", (unsigned int) buf->mNumberChannels); 555 return -1; 556 } 557 558 ca_source = pa_xnew0(coreaudio_source, 1); 559 ca_source->map.channels = buf->mNumberChannels; 560 ca_source->ss.channels = buf->mNumberChannels; 561 ca_source->channel_idx = channel_idx; 562 563 /* build a name for this stream */ 564 strbuf = pa_strbuf_new(); 565 566 for (i = 0; i < buf->mNumberChannels; i++) { 567 property_address.mSelector = kAudioObjectPropertyElementName; 568 property_address.mScope = kAudioDevicePropertyScopeInput; 569 property_address.mElement = channel_idx + i + 1; 570 size = sizeof(tmp_cfstr); 571 err = AudioObjectGetPropertyData(u->object_id, &property_address, 0, NULL, &size, &tmp_cfstr); 572 if (err == 0) { 573 tmp = CFString_to_cstr(tmp_cfstr); 574 575 if (tmp_cfstr) 576 CFRelease(tmp_cfstr); 577 } 578 579 if (i > 0) 580 pa_strbuf_puts(strbuf, ", "); 581 582 if (err || !tmp || !strlen(tmp)) 583 pa_strbuf_printf(strbuf, "Channel %d", (int) property_address.mElement); 584 else 585 pa_strbuf_puts(strbuf, tmp); 586 587 pa_xfree(tmp); 588 tmp = NULL; 589 } 590 591 ca_source->name = pa_strbuf_to_string_free(strbuf); 592 593 pa_log_debug("Stream name is >%s<", ca_source->name); 594 595 /* default to mono streams */ 596 for (i = 0; i < ca_source->map.channels; i++) 597 ca_source->map.map[i] = PA_CHANNEL_POSITION_MONO; 598 599 if (buf->mNumberChannels == 2) { 600 ca_source->map.map[0] = PA_CHANNEL_POSITION_LEFT; 601 ca_source->map.map[1] = PA_CHANNEL_POSITION_RIGHT; 602 } 603 604 ca_source->ss.rate = u->stream_description.mSampleRate; 605 ca_source->ss.format = PA_SAMPLE_FLOAT32LE; 606 607 pa_source_new_data_init(&new_data); 608 new_data.card = u->card; 609 new_data.driver = __FILE__; 610 new_data.module = u->module; 611 new_data.namereg_fail = false; 612 pa_source_new_data_set_name(&new_data, ca_source->name); 613 pa_source_new_data_set_channel_map(&new_data, &ca_source->map); 614 pa_source_new_data_set_sample_spec(&new_data, &ca_source->ss); 615 pa_proplist_sets(new_data.proplist, PA_PROP_DEVICE_STRING, u->device_name); 616 pa_proplist_sets(new_data.proplist, PA_PROP_DEVICE_PRODUCT_NAME, u->device_name); 617 pa_proplist_sets(new_data.proplist, PA_PROP_DEVICE_DESCRIPTION, u->device_name); 618 pa_proplist_sets(new_data.proplist, PA_PROP_DEVICE_ACCESS_MODE, "mmap"); 619 pa_proplist_sets(new_data.proplist, PA_PROP_DEVICE_CLASS, "sound"); 620 pa_proplist_sets(new_data.proplist, PA_PROP_DEVICE_API, "CoreAudio"); 621 pa_proplist_setf(new_data.proplist, PA_PROP_DEVICE_BUFFERING_BUFFER_SIZE, "%lu", (unsigned long) buf->mDataByteSize); 622 623 if (u->vendor_name) 624 pa_proplist_sets(new_data.proplist, PA_PROP_DEVICE_VENDOR_NAME, u->vendor_name); 625 626 source = pa_source_new(m->core, &new_data, flags); 627 pa_source_new_data_done(&new_data); 628 629 if (!source) { 630 pa_log("unable to create source."); 631 return -1; 632 } 633 634 source->parent.process_msg = source_process_msg; 635 source->userdata = ca_source; 636 source->set_state_in_main_thread = ca_source_set_state_in_main_thread; 637 638 pa_source_set_asyncmsgq(source, u->thread_mq.inq); 639 pa_source_set_rtpoll(source, u->rtpoll); 640 641 ca_source->pa_source = source; 642 ca_source->userdata = u; 643 644 PA_LLIST_PREPEND(coreaudio_source, u->sources, ca_source); 645 646 return 0; 647} 648 649static int ca_device_create_streams(pa_module *m, bool direction_in) { 650 OSStatus err; 651 UInt32 size, i, channel_idx; 652 struct userdata *u = m->userdata; 653 AudioBufferList *buffer_list; 654 AudioObjectPropertyAddress property_address; 655 656 property_address.mScope = direction_in ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput; 657 property_address.mElement = kAudioObjectPropertyElementMaster; 658 659 /* get current stream format */ 660 size = sizeof(AudioStreamBasicDescription); 661 property_address.mSelector = kAudioDevicePropertyStreamFormat; 662 err = AudioObjectGetPropertyData(u->object_id, &property_address, 0, NULL, &size, &u->stream_description); 663 if (err) { 664 /* no appropriate streams found - silently bail. */ 665 return -1; 666 } 667 668 if (u->stream_description.mFormatID != kAudioFormatLinearPCM) { 669 pa_log("Unsupported audio format '%c%c%c%c'", 670 (char) (u->stream_description.mFormatID >> 24), 671 (char) (u->stream_description.mFormatID >> 16) & 0xff, 672 (char) (u->stream_description.mFormatID >> 8) & 0xff, 673 (char) (u->stream_description.mFormatID & 0xff)); 674 return -1; 675 } 676 677 /* get stream configuration */ 678 size = 0; 679 property_address.mSelector = kAudioDevicePropertyStreamConfiguration; 680 err = AudioObjectGetPropertyDataSize(u->object_id, &property_address, 0, NULL, &size); 681 if (err) { 682 pa_log("Failed to get kAudioDevicePropertyStreamConfiguration (%s).", direction_in ? "input" : "output"); 683 return -1; 684 } 685 686 if (!size) 687 return 0; 688 689 buffer_list = (AudioBufferList *) pa_xmalloc(size); 690 err = AudioObjectGetPropertyData(u->object_id, &property_address, 0, NULL, &size, buffer_list); 691 692 if (!err) { 693 pa_log_debug("Sample rate: %f", u->stream_description.mSampleRate); 694 pa_log_debug("%d bytes per packet", (unsigned int) u->stream_description.mBytesPerPacket); 695 pa_log_debug("%d frames per packet", (unsigned int) u->stream_description.mFramesPerPacket); 696 pa_log_debug("%d bytes per frame", (unsigned int) u->stream_description.mBytesPerFrame); 697 pa_log_debug("%d channels per frame", (unsigned int) u->stream_description.mChannelsPerFrame); 698 pa_log_debug("%d bits per channel", (unsigned int) u->stream_description.mBitsPerChannel); 699 700 for (channel_idx = 0, i = 0; i < buffer_list->mNumberBuffers; i++) { 701 AudioBuffer *buf = buffer_list->mBuffers + i; 702 703 if (direction_in) 704 ca_device_create_source(m, buf, channel_idx); 705 else 706 ca_device_create_sink(m, buf, channel_idx); 707 708 channel_idx += buf->mNumberChannels; 709 } 710 } 711 712 pa_xfree(buffer_list); 713 return 0; 714} 715 716static void thread_func(void *userdata) { 717 struct userdata *u = userdata; 718 719 pa_assert(u); 720 pa_assert(u->module); 721 pa_assert(u->module->core); 722 723 pa_log_debug("Thread starting up"); 724 725 if (u->module->core->realtime_scheduling) 726 pa_thread_make_realtime(u->module->core->realtime_priority); 727 728 pa_thread_mq_install(&u->thread_mq); 729 730 for (;;) { 731 coreaudio_sink *ca_sink; 732 int ret; 733 734 PA_LLIST_FOREACH(ca_sink, u->sinks) { 735 if (PA_UNLIKELY(ca_sink->pa_sink->thread_info.rewind_requested)) 736 pa_sink_process_rewind(ca_sink->pa_sink, 0); 737 } 738 739 ret = pa_rtpoll_run(u->rtpoll); 740 741 if (ret < 0) 742 goto fail; 743 744 if (ret == 0) 745 goto finish; 746 } 747 748fail: 749 /* If this was no regular exit from the loop we have to continue 750 * processing messages until we received PA_MESSAGE_SHUTDOWN */ 751 pa_asyncmsgq_post(u->thread_mq.outq, PA_MSGOBJECT(u->module->core), PA_CORE_MESSAGE_UNLOAD_MODULE, u->module, 0, NULL, NULL); 752 pa_asyncmsgq_wait_for(u->thread_mq.inq, PA_MESSAGE_SHUTDOWN); 753 754finish: 755 pa_log_debug("Thread shutting down"); 756} 757 758int pa__init(pa_module *m) { 759 OSStatus err; 760 UInt32 size, frames; 761 struct userdata *u = NULL; 762 pa_modargs *ma = NULL; 763 bool record = true, playback = true; 764 char tmp[64]; 765 pa_card_new_data card_new_data; 766 pa_card_profile *p; 767 coreaudio_sink *ca_sink; 768 coreaudio_source *ca_source; 769 AudioObjectPropertyAddress property_address; 770 771 pa_assert(m); 772 773 if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { 774 pa_log("Failed to parse module arguments."); 775 goto fail; 776 } 777 778 if (pa_modargs_get_value_boolean(ma, "record", &record) < 0 || pa_modargs_get_value_boolean(ma, "playback", &playback) < 0) { 779 pa_log("record= and playback= expect boolean argument."); 780 goto fail; 781 } 782 783 if (!playback && !record) { 784 pa_log("neither playback nor record enabled for device."); 785 goto fail; 786 } 787 788 u = pa_xnew0(struct userdata, 1); 789 u->module = m; 790 m->userdata = u; 791 792 if (pa_modargs_get_value_u32(ma, "object_id", (unsigned int *) &u->object_id) != 0) { 793 pa_log("Failed to parse object_id argument."); 794 goto fail; 795 } 796 797 property_address.mScope = kAudioObjectPropertyScopeGlobal; 798 property_address.mElement = kAudioObjectPropertyElementMaster; 799 800 /* get device product name */ 801 property_address.mSelector = kAudioDevicePropertyDeviceName; 802 size = sizeof(tmp); 803 err = AudioObjectGetPropertyData(u->object_id, &property_address, 0, NULL, &size, tmp); 804 if (err) { 805 pa_log("Failed to get kAudioDevicePropertyDeviceName (err = %08x).", (int) err); 806 goto fail; 807 } 808 809 u->device_name = pa_xstrdup(tmp); 810 811 pa_card_new_data_init(&card_new_data); 812 pa_proplist_sets(card_new_data.proplist, PA_PROP_DEVICE_STRING, tmp); 813 card_new_data.driver = __FILE__; 814 pa_card_new_data_set_name(&card_new_data, tmp); 815 pa_log_info("Initializing module for CoreAudio device '%s' (id %d)", tmp, (unsigned int) u->object_id); 816 817 /* get device vendor name (may fail) */ 818 property_address.mSelector = kAudioDevicePropertyDeviceManufacturer; 819 size = sizeof(tmp); 820 err = AudioObjectGetPropertyData(u->object_id, &property_address, 0, NULL, &size, tmp); 821 if (!err) 822 u->vendor_name = pa_xstrdup(tmp); 823 824 /* add on profile */ 825 p = pa_card_profile_new("on", _("On"), 0); 826 pa_hashmap_put(card_new_data.profiles, p->name, p); 827 828 /* create the card object */ 829 u->card = pa_card_new(m->core, &card_new_data); 830 if (!u->card) { 831 pa_log("Unable to create card.\n"); 832 goto fail; 833 } 834 835 pa_card_new_data_done(&card_new_data); 836 u->card->userdata = u; 837 u->card->set_profile = card_set_profile; 838 pa_card_choose_initial_profile(u->card); 839 pa_card_put(u->card); 840 841 u->rtpoll = pa_rtpoll_new(); 842 843 if (pa_thread_mq_init(&u->thread_mq, m->core->mainloop, u->rtpoll) < 0) { 844 pa_log("pa_thread_mq_init() failed."); 845 goto fail; 846 } 847 848 u->async_msgq = pa_asyncmsgq_new(0); 849 if (!u->async_msgq) { 850 pa_log("pa_asyncmsgq_new() failed."); 851 goto fail; 852 } 853 854 pa_rtpoll_item_new_asyncmsgq_read(u->rtpoll, PA_RTPOLL_EARLY-1, u->async_msgq); 855 856 PA_LLIST_HEAD_INIT(coreaudio_sink, u->sinks); 857 858 /* create sinks */ 859 if (playback) 860 ca_device_create_streams(m, false); 861 862 /* create sources */ 863 if (record) 864 ca_device_create_streams(m, true); 865 866 /* create the message thread */ 867 if (!(u->thread = pa_thread_new(u->device_name, thread_func, u))) { 868 pa_log("Failed to create thread."); 869 goto fail; 870 } 871 872 /* register notification callback for stream format changes */ 873 property_address.mSelector = kAudioDevicePropertyStreamFormat; 874 property_address.mScope = kAudioObjectPropertyScopeGlobal; 875 property_address.mElement = kAudioObjectPropertyElementMaster; 876 877 AudioObjectAddPropertyListener(u->object_id, &property_address, ca_stream_format_changed, u); 878 879 /* set number of frames in IOProc */ 880 frames = DEFAULT_FRAMES_PER_IOPROC; 881 pa_modargs_get_value_u32(ma, "ioproc_frames", (unsigned int *) &frames); 882 883 property_address.mSelector = kAudioDevicePropertyBufferFrameSize; 884 AudioObjectSetPropertyData(u->object_id, &property_address, 0, NULL, sizeof(frames), &frames); 885 pa_log_debug("%u frames per IOProc\n", (unsigned int) frames); 886 887 /* create one ioproc for both directions */ 888 err = AudioDeviceCreateIOProcID(u->object_id, io_render_proc, u, &u->proc_id); 889 if (err) { 890 pa_log("AudioDeviceCreateIOProcID() failed (err = %08x\n).", (int) err); 891 goto fail; 892 } 893 894 for (ca_sink = u->sinks; ca_sink; ca_sink = ca_sink->next) 895 pa_sink_put(ca_sink->pa_sink); 896 897 for (ca_source = u->sources; ca_source; ca_source = ca_source->next) 898 pa_source_put(ca_source->pa_source); 899 900 pa_modargs_free(ma); 901 902 return 0; 903 904fail: 905 if (u) 906 pa__done(m); 907 908 if (ma) 909 pa_modargs_free(ma); 910 911 return -1; 912} 913 914void pa__done(pa_module *m) { 915 struct userdata *u; 916 coreaudio_sink *ca_sink; 917 coreaudio_source *ca_source; 918 AudioObjectPropertyAddress property_address; 919 920 pa_assert(m); 921 922 u = m->userdata; 923 pa_assert(u); 924 925 /* unlink sinks */ 926 for (ca_sink = u->sinks; ca_sink; ca_sink = ca_sink->next) 927 if (ca_sink->pa_sink) 928 pa_sink_unlink(ca_sink->pa_sink); 929 930 /* unlink sources */ 931 for (ca_source = u->sources; ca_source; ca_source = ca_source->next) 932 if (ca_source->pa_source) 933 pa_source_unlink(ca_source->pa_source); 934 935 if (u->thread) { 936 pa_asyncmsgq_send(u->thread_mq.inq, NULL, PA_MESSAGE_SHUTDOWN, NULL, 0, NULL); 937 pa_thread_free(u->thread); 938 pa_thread_mq_done(&u->thread_mq); 939 } 940 941 if (u->async_msgq) 942 pa_asyncmsgq_unref(u->async_msgq); 943 944 /* free sinks */ 945 for (ca_sink = u->sinks; ca_sink;) { 946 coreaudio_sink *next = ca_sink->next; 947 948 if (ca_sink->pa_sink) 949 pa_sink_unref(ca_sink->pa_sink); 950 951 pa_xfree(ca_sink->name); 952 pa_xfree(ca_sink); 953 ca_sink = next; 954 } 955 956 /* free sources */ 957 for (ca_source = u->sources; ca_source;) { 958 coreaudio_source *next = ca_source->next; 959 960 if (ca_source->pa_source) 961 pa_source_unref(ca_source->pa_source); 962 963 pa_xfree(ca_source->name); 964 pa_xfree(ca_source); 965 ca_source = next; 966 } 967 968 if (u->proc_id) { 969 AudioDeviceStop(u->object_id, u->proc_id); 970 AudioDeviceDestroyIOProcID(u->object_id, u->proc_id); 971 } 972 973 property_address.mSelector = kAudioDevicePropertyStreamFormat; 974 property_address.mScope = kAudioObjectPropertyScopeGlobal; 975 property_address.mElement = kAudioObjectPropertyElementMaster; 976 977 AudioObjectRemovePropertyListener(kAudioObjectSystemObject, &property_address, ca_stream_format_changed, u); 978 979 pa_xfree(u->device_name); 980 pa_xfree(u->vendor_name); 981 pa_rtpoll_free(u->rtpoll); 982 pa_card_free(u->card); 983 984 pa_xfree(u); 985} 986