]> code.delx.au - pulseaudio/blob - src/modules/coreaudio/module-coreaudio-device.c
CoreAudio: add audio device module
[pulseaudio] / src / modules / coreaudio / module-coreaudio-device.c
1 /***
2 This file is part of PulseAudio.
3
4 Copyright 2009 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, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
19 USA.
20 ***/
21
22 /* TODO:
23 - implement hardware volume controls
24 - handle audio device stream format changes (will require changes to the core)
25 */
26
27 #ifdef HAVE_CONFIG_H
28 #include <config.h>
29 #endif
30
31 #include <pulse/xmalloc.h>
32 #include <pulse/util.h>
33
34 #include <pulsecore/core-error.h>
35 #include <pulsecore/sink.h>
36 #include <pulsecore/source.h>
37 #include <pulsecore/module.h>
38 #include <pulsecore/sample-util.h>
39 #include <pulsecore/core-util.h>
40 #include <pulsecore/modargs.h>
41 #include <pulsecore/log.h>
42 #include <pulsecore/macro.h>
43 #include <pulsecore/llist.h>
44 #include <pulsecore/card.h>
45 #include <pulsecore/strbuf.h>
46 #include <pulsecore/thread.h>
47 #include <pulsecore/thread-mq.h>
48
49 #include <CoreAudio/CoreAudio.h>
50 #include <CoreAudio/CoreAudioTypes.h>
51 #include <CoreAudio/AudioHardware.h>
52
53 #include "module-coreaudio-device-symdef.h"
54
55 #define DEFAULT_FRAMES_PER_IOPROC 512
56
57 PA_MODULE_AUTHOR("Daniel Mack");
58 PA_MODULE_DESCRIPTION("CoreAudio device");
59 PA_MODULE_VERSION(PACKAGE_VERSION);
60 PA_MODULE_LOAD_ONCE(FALSE);
61 PA_MODULE_USAGE("device_id=<the CoreAudio device id> "
62 "ioproc_frames=<audio frames per IOProc call> ");
63
64 static const char* const valid_modargs[] = {
65 "device_id",
66 "ioproc_frames",
67 NULL
68 };
69
70 enum {
71 CA_MESSAGE_RENDER = PA_SINK_MESSAGE_MAX,
72 };
73
74 typedef struct coreaudio_sink coreaudio_sink;
75 typedef struct coreaudio_source coreaudio_source;
76
77 struct userdata {
78 AudioDeviceID device_id;
79 AudioDeviceIOProcID proc_id;
80
81 pa_thread_mq thread_mq;
82 pa_asyncmsgq *async_msgq;
83
84 pa_rtpoll *rtpoll;
85 pa_thread *thread;
86
87 pa_module *module;
88 pa_card *card;
89 pa_bool_t running;
90
91 char *device_name, *vendor_name;
92
93 const AudioBufferList *render_input_data;
94 AudioBufferList *render_output_data;
95
96 AudioStreamBasicDescription stream_description;
97
98 PA_LLIST_HEAD(coreaudio_sink, sinks);
99 PA_LLIST_HEAD(coreaudio_source, sources);
100 };
101
102 struct coreaudio_sink {
103 pa_sink *pa_sink;
104 struct userdata *userdata;
105
106 char *name;
107 unsigned int channel_idx;
108 pa_bool_t active;
109
110 pa_channel_map map;
111 pa_sample_spec ss;
112
113 PA_LLIST_FIELDS(coreaudio_sink);
114 };
115
116 struct coreaudio_source {
117 pa_source *pa_source;
118 struct userdata *userdata;
119
120 char *name;
121 unsigned int channel_idx;
122 pa_bool_t active;
123
124 pa_channel_map map;
125 pa_sample_spec ss;
126
127 PA_LLIST_FIELDS(coreaudio_source);
128 };
129
130 static OSStatus io_render_proc (AudioDeviceID device,
131 const AudioTimeStamp *now,
132 const AudioBufferList *inputData,
133 const AudioTimeStamp *inputTime,
134 AudioBufferList *outputData,
135 const AudioTimeStamp *outputTime,
136 void *clientData)
137 {
138 struct userdata *u = clientData;
139
140 pa_assert(u);
141 pa_assert(device == u->device_id);
142
143 u->render_input_data = inputData;
144 u->render_output_data = outputData;
145
146 if (u->sinks)
147 pa_assert_se(pa_asyncmsgq_send(u->async_msgq, PA_MSGOBJECT(u->sinks->pa_sink),
148 CA_MESSAGE_RENDER, NULL, 0, NULL) == 0);
149
150 if (u->sources)
151 pa_assert_se(pa_asyncmsgq_send(u->async_msgq, PA_MSGOBJECT(u->sources->pa_source),
152 CA_MESSAGE_RENDER, NULL, 0, NULL) == 0);
153
154 return 0;
155 }
156
157 static OSStatus ca_stream_format_changed(AudioDeviceID inDevice,
158 UInt32 inChannel,
159 Boolean isInput,
160 AudioDevicePropertyID inPropertyID,
161 void *inClientData)
162 {
163 struct userdata *u = inClientData;
164
165 pa_assert(u);
166
167 /* REVISIT: PA can't currently handle external format change requests.
168 * Hence, we set the original format back in this callback to avoid horrible audio artefacts.
169 * The device settings will appear to be 'locked' for any application as long as the PA daemon is running.
170 * Once we're able to propagate such events up in the core, this needs to be changed. */
171
172 return AudioDeviceSetProperty(inDevice, NULL, inChannel, isInput,
173 kAudioDevicePropertyStreamFormat, sizeof(u->stream_description), &u->stream_description);
174 }
175
176 static pa_usec_t get_latency_us(pa_object *o) {
177 struct userdata *u;
178 pa_sample_spec *ss;
179 bool is_source;
180 UInt32 v, total = 0;
181 UInt32 err, size = sizeof(v);
182
183 if (pa_sink_isinstance(o)) {
184 coreaudio_sink *sink = PA_SINK(o)->userdata;
185
186 u = sink->userdata;
187 ss = &sink->ss;
188 is_source = FALSE;
189 } else if (pa_source_isinstance(o)) {
190 coreaudio_source *source = PA_SOURCE(o)->userdata;
191
192 u = source->userdata;
193 ss = &source->ss;
194 is_source = TRUE;
195 } else
196 pa_assert_not_reached();
197
198 pa_assert(u);
199
200 /* get the device latency */
201 size = sizeof(total);
202 AudioDeviceGetProperty(u->device_id, 0, is_source, kAudioDevicePropertyLatency, &size, &v);
203 total += v;
204
205 /* the the IOProc buffer size */
206 size = sizeof(v);
207 AudioDeviceGetProperty(u->device_id, 0, is_source, kAudioDevicePropertyBufferFrameSize, &size, &v);
208 total += v;
209
210 /* IOProc safety offset - this value is the same for both directions, hence we divide it by 2 */
211 size = sizeof(v);
212 AudioDeviceGetProperty(u->device_id, 0, is_source, kAudioDevicePropertySafetyOffset, &size, &v);
213 total += v / 2;
214
215 /* get the stream latency.
216 * FIXME: this assumes the stream latency is the same for all streams */
217 err = AudioStreamGetProperty(0, is_source, kAudioStreamPropertyLatency, &size, &v);
218 if (!err)
219 total += v;
220
221 return pa_bytes_to_usec(total * pa_frame_size(ss), ss);
222 }
223
224 static void ca_device_check_device_state(struct userdata *u) {
225 coreaudio_sink *ca_sink;
226 coreaudio_source *ca_source;
227 pa_bool_t active = FALSE;
228
229 pa_assert(u);
230
231 for (ca_sink = u->sinks; ca_sink; ca_sink = ca_sink->next)
232 if (ca_sink->active)
233 active = TRUE;
234
235 for (ca_source = u->sources; ca_source; ca_source = ca_source->next)
236 if (ca_source->active)
237 active = TRUE;
238
239 if (active && !u->running)
240 AudioDeviceStart(u->device_id, u->proc_id);
241 else if (!active && u->running)
242 AudioDeviceStop(u->device_id, u->proc_id);
243
244 u->running = active;
245 }
246
247 static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) {
248 coreaudio_sink *sink = PA_SINK(o)->userdata;
249 struct userdata *u = sink->userdata;
250 unsigned int i;
251 pa_memchunk audio_chunk;
252
253 switch (code) {
254 case CA_MESSAGE_RENDER: {
255 /* audio out */
256 for (i = 0; i < u->render_output_data->mNumberBuffers; i++) {
257 AudioBuffer *buf = u->render_output_data->mBuffers + i;
258
259 pa_assert(sink);
260
261 if (PA_SINK_IS_OPENED(sink->pa_sink->thread_info.state)) {
262 if (sink->pa_sink->thread_info.rewind_requested)
263 pa_sink_process_rewind(sink->pa_sink, 0);
264
265 audio_chunk.memblock = pa_memblock_new_fixed(u->module->core->mempool, buf->mData, buf->mDataByteSize, FALSE);
266 audio_chunk.length = buf->mDataByteSize;
267 audio_chunk.index = 0;
268
269 pa_sink_render_into_full(sink->pa_sink, &audio_chunk);
270 pa_memblock_unref_fixed(audio_chunk.memblock);
271 }
272
273 sink = sink->next;
274 }
275
276 return 0;
277 }
278
279 case PA_SINK_MESSAGE_GET_LATENCY: {
280 *((pa_usec_t *) data) = get_latency_us(PA_OBJECT(o));
281 return 0;
282 }
283
284 case PA_SINK_MESSAGE_SET_STATE:
285 switch ((pa_sink_state_t) PA_PTR_TO_UINT(data)) {
286 case PA_SINK_SUSPENDED:
287 case PA_SINK_IDLE:
288 sink->active = FALSE;
289 break;
290
291 case PA_SINK_RUNNING:
292 sink->active = TRUE;
293 break;
294
295 case PA_SINK_UNLINKED:
296 case PA_SINK_INIT:
297 case PA_SINK_INVALID_STATE:
298 ;
299 }
300
301 ca_device_check_device_state(sink->userdata);
302 break;
303 }
304
305 return pa_sink_process_msg(o, code, data, offset, chunk);
306 }
307
308 static int source_process_msg(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) {
309 coreaudio_source *source = PA_SOURCE(o)->userdata;
310 struct userdata *u = source->userdata;
311 unsigned int i;
312 pa_memchunk audio_chunk;
313
314 switch (code) {
315 case CA_MESSAGE_RENDER: {
316 /* audio in */
317 for (i = 0; i < u->render_input_data->mNumberBuffers; i++) {
318 const AudioBuffer *buf = u->render_input_data->mBuffers + i;
319
320 pa_assert(source);
321
322 if (PA_SOURCE_IS_OPENED(source->pa_source->thread_info.state)) {
323 audio_chunk.memblock = pa_memblock_new_fixed(u->module->core->mempool, buf->mData, buf->mDataByteSize, TRUE);
324 audio_chunk.length = buf->mDataByteSize;
325 audio_chunk.index = 0;
326
327 pa_source_post(source->pa_source, &audio_chunk);
328 pa_memblock_unref_fixed(audio_chunk.memblock);
329 }
330
331 source = source->next;
332 }
333
334 return 0;
335 }
336
337 case PA_SOURCE_MESSAGE_GET_LATENCY: {
338 *((pa_usec_t *) data) = get_latency_us(PA_OBJECT(o));
339 return 0;
340 }
341
342 case PA_SOURCE_MESSAGE_SET_STATE:
343 switch ((pa_source_state_t) PA_PTR_TO_UINT(data)) {
344 case PA_SOURCE_SUSPENDED:
345 case PA_SOURCE_IDLE:
346 source->active = FALSE;
347 break;
348
349 case PA_SOURCE_RUNNING:
350 source->active = TRUE;
351 break;
352
353 case PA_SOURCE_UNLINKED:
354 case PA_SOURCE_INIT:
355 case PA_SOURCE_INVALID_STATE:
356 ;
357 }
358
359 ca_device_check_device_state(source->userdata);
360 break;
361 }
362
363 return pa_source_process_msg(o, code, data, offset, chunk);
364 }
365
366 static int ca_device_create_sink(pa_module *m, AudioBuffer *buf, int channel_idx) {
367 OSStatus err;
368 UInt32 size;
369 struct userdata *u = m->userdata;
370 pa_sink_new_data new_data;
371 pa_sink_flags_t flags = PA_SINK_LATENCY | PA_SINK_HARDWARE;
372 coreaudio_sink *ca_sink;
373 pa_sink *sink;
374 unsigned int i;
375 char tmp[255];
376 pa_strbuf *strbuf;
377
378 ca_sink = pa_xnew0(coreaudio_sink, 1);
379 ca_sink->map.channels = buf->mNumberChannels;
380 ca_sink->ss.channels = buf->mNumberChannels;
381 ca_sink->channel_idx = channel_idx;
382
383 /* build a name for this stream */
384 strbuf = pa_strbuf_new();
385
386 for (i = 0; i < buf->mNumberChannels; i++) {
387 size = sizeof(tmp);
388 err = AudioDeviceGetProperty(u->device_id, channel_idx + i + 1, 0, kAudioObjectPropertyElementName, &size, tmp);
389 if (err || !strlen(tmp))
390 snprintf(tmp, sizeof(tmp), "Channel %d", channel_idx + i + 1);
391
392 if (i > 0)
393 pa_strbuf_puts(strbuf, ", ");
394
395 pa_strbuf_puts(strbuf, tmp);
396 }
397
398 ca_sink->name = pa_strbuf_tostring_free(strbuf);
399
400 pa_log_debug("Stream name is >%s<", ca_sink->name);
401
402 /* default to mono streams */
403 for (i = 0; i < ca_sink->map.channels; i++)
404 ca_sink->map.map[i] = PA_CHANNEL_POSITION_MONO;
405
406 if (buf->mNumberChannels == 2) {
407 ca_sink->map.map[0] = PA_CHANNEL_POSITION_LEFT;
408 ca_sink->map.map[1] = PA_CHANNEL_POSITION_RIGHT;
409 }
410
411 ca_sink->ss.rate = u->stream_description.mSampleRate;
412 ca_sink->ss.format = PA_SAMPLE_FLOAT32LE;
413
414 pa_sink_new_data_init(&new_data);
415 new_data.card = u->card;
416 new_data.driver = __FILE__;
417 new_data.module = u->module;
418 new_data.namereg_fail = FALSE;
419 pa_sink_new_data_set_name(&new_data, ca_sink->name);
420 pa_sink_new_data_set_channel_map(&new_data, &ca_sink->map);
421 pa_sink_new_data_set_sample_spec(&new_data, &ca_sink->ss);
422 pa_proplist_sets(new_data.proplist, PA_PROP_DEVICE_STRING, u->device_name);
423 pa_proplist_sets(new_data.proplist, PA_PROP_DEVICE_PRODUCT_NAME, u->device_name);
424 pa_proplist_sets(new_data.proplist, PA_PROP_DEVICE_DESCRIPTION, u->device_name);
425 pa_proplist_sets(new_data.proplist, PA_PROP_DEVICE_ACCESS_MODE, "mmap");
426 pa_proplist_sets(new_data.proplist, PA_PROP_DEVICE_CLASS, "sound");
427 pa_proplist_sets(new_data.proplist, PA_PROP_DEVICE_API, "CoreAudio");
428 pa_proplist_setf(new_data.proplist, PA_PROP_DEVICE_BUFFERING_BUFFER_SIZE, "%lu", (unsigned long) buf->mDataByteSize);
429
430 if (u->vendor_name)
431 pa_proplist_sets(new_data.proplist, PA_PROP_DEVICE_VENDOR_NAME, u->vendor_name);
432
433 sink = pa_sink_new(m->core, &new_data, flags);
434 pa_sink_new_data_done(&new_data);
435
436 if (!sink) {
437 pa_log("unable to create sink.");
438 return -1;
439 }
440
441 sink->parent.process_msg = sink_process_msg;
442 sink->userdata = ca_sink;
443
444 pa_sink_set_asyncmsgq(sink, u->thread_mq.inq);
445 pa_sink_set_rtpoll(sink, u->rtpoll);
446
447 ca_sink->pa_sink = sink;
448 ca_sink->userdata = u;
449
450 PA_LLIST_PREPEND(coreaudio_sink, u->sinks, ca_sink);
451
452 return 0;
453 }
454
455 static int ca_device_create_source(pa_module *m, AudioBuffer *buf, int channel_idx) {
456 OSStatus err;
457 UInt32 size;
458 struct userdata *u = m->userdata;
459 pa_source_new_data new_data;
460 pa_source_flags_t flags = PA_SOURCE_LATENCY | PA_SOURCE_HARDWARE;
461 coreaudio_source *ca_source;
462 pa_source *source;
463 unsigned int i;
464 char tmp[255];
465 pa_strbuf *strbuf;
466
467 ca_source = pa_xnew0(coreaudio_source, 1);
468 ca_source->map.channels = buf->mNumberChannels;
469 ca_source->ss.channels = buf->mNumberChannels;
470 ca_source->channel_idx = channel_idx;
471
472 /* build a name for this stream */
473 strbuf = pa_strbuf_new();
474
475 for (i = 0; i < buf->mNumberChannels; i++) {
476 size = sizeof(tmp);
477 err = AudioDeviceGetProperty(u->device_id, channel_idx + i + 1, 0, kAudioObjectPropertyElementName, &size, tmp);
478 if (err || !strlen(tmp))
479 snprintf(tmp, sizeof(tmp), "Channel %d", channel_idx + i + 1);
480
481 if (i > 0)
482 pa_strbuf_puts(strbuf, ", ");
483
484 pa_strbuf_puts(strbuf, tmp);
485 }
486
487 ca_source->name = pa_strbuf_tostring_free(strbuf);
488
489 pa_log_debug("Stream name is >%s<", ca_source->name);
490
491 /* default to mono streams */
492 for (i = 0; i < ca_source->map.channels; i++)
493 ca_source->map.map[i] = PA_CHANNEL_POSITION_MONO;
494
495 if (buf->mNumberChannels == 2) {
496 ca_source->map.map[0] = PA_CHANNEL_POSITION_LEFT;
497 ca_source->map.map[1] = PA_CHANNEL_POSITION_RIGHT;
498 }
499
500 ca_source->ss.rate = u->stream_description.mSampleRate;
501 ca_source->ss.format = PA_SAMPLE_FLOAT32LE;
502
503 pa_source_new_data_init(&new_data);
504 new_data.card = u->card;
505 new_data.driver = __FILE__;
506 new_data.module = u->module;
507 new_data.namereg_fail = FALSE;
508 pa_source_new_data_set_name(&new_data, ca_source->name);
509 pa_source_new_data_set_channel_map(&new_data, &ca_source->map);
510 pa_source_new_data_set_sample_spec(&new_data, &ca_source->ss);
511 pa_proplist_sets(new_data.proplist, PA_PROP_DEVICE_STRING, u->device_name);
512 pa_proplist_sets(new_data.proplist, PA_PROP_DEVICE_PRODUCT_NAME, u->device_name);
513 pa_proplist_sets(new_data.proplist, PA_PROP_DEVICE_DESCRIPTION, u->device_name);
514 pa_proplist_sets(new_data.proplist, PA_PROP_DEVICE_ACCESS_MODE, "mmap");
515 pa_proplist_sets(new_data.proplist, PA_PROP_DEVICE_CLASS, "sound");
516 pa_proplist_sets(new_data.proplist, PA_PROP_DEVICE_API, "CoreAudio");
517 pa_proplist_setf(new_data.proplist, PA_PROP_DEVICE_BUFFERING_BUFFER_SIZE, "%lu", (unsigned long) buf->mDataByteSize);
518
519 if (u->vendor_name)
520 pa_proplist_sets(new_data.proplist, PA_PROP_DEVICE_VENDOR_NAME, u->vendor_name);
521
522 source = pa_source_new(m->core, &new_data, flags);
523 pa_source_new_data_done(&new_data);
524
525 if (!source) {
526 pa_log("unable to create source.");
527 return -1;
528 }
529
530 source->parent.process_msg = source_process_msg;
531 source->userdata = ca_source;
532
533 pa_source_set_asyncmsgq(source, u->thread_mq.inq);
534 pa_source_set_rtpoll(source, u->rtpoll);
535
536 ca_source->pa_source = source;
537 ca_source->userdata = u;
538
539 PA_LLIST_PREPEND(coreaudio_source, u->sources, ca_source);
540
541 return 0;
542 }
543
544 static int ca_device_create_streams(pa_module *m, bool direction_in) {
545 OSStatus err;
546 UInt32 size, i, channel_idx;
547 struct userdata *u = m->userdata;
548 int section = direction_in ? 1 : 0;
549 AudioBufferList *buffer_list;
550
551 /* get current stream format */
552 size = sizeof(AudioStreamBasicDescription);
553 err = AudioDeviceGetProperty(u->device_id, 0, section, kAudioDevicePropertyStreamFormat, &size, &u->stream_description);
554 if (err) {
555 /* no appropriate streams found - silently bail. */
556 return -1;
557 }
558
559 if (u->stream_description.mFormatID != kAudioFormatLinearPCM) {
560 pa_log("Unsupported audio format '%c%c%c%c'",
561 (char) (u->stream_description.mFormatID >> 24),
562 (char) (u->stream_description.mFormatID >> 16) & 0xff,
563 (char) (u->stream_description.mFormatID >> 8) & 0xff,
564 (char) (u->stream_description.mFormatID & 0xff));
565 return -1;
566 }
567
568 /* get stream configuration */
569 size = 0;
570 err = AudioDeviceGetPropertyInfo(u->device_id, 0, section, kAudioDevicePropertyStreamConfiguration, &size, NULL);
571 if (err) {
572 pa_log("Failed to get kAudioDevicePropertyStreamConfiguration (%s).", direction_in ? "input" : "output");
573 return -1;
574 }
575
576 if (!size)
577 return 0;
578
579 buffer_list = (AudioBufferList *) pa_xmalloc(size);
580 err = AudioDeviceGetProperty(u->device_id, 0, section, kAudioDevicePropertyStreamConfiguration, &size, buffer_list);
581
582 if (!err) {
583 pa_log_debug("Sample rate: %f", u->stream_description.mSampleRate);
584 pa_log_debug("%d bytes per packet", (unsigned int) u->stream_description.mBytesPerPacket);
585 pa_log_debug("%d frames per packet", (unsigned int) u->stream_description.mFramesPerPacket);
586 pa_log_debug("%d bytes per frame", (unsigned int) u->stream_description.mBytesPerFrame);
587 pa_log_debug("%d channels per frame", (unsigned int) u->stream_description.mChannelsPerFrame);
588 pa_log_debug("%d bits per channel", (unsigned int) u->stream_description.mBitsPerChannel);
589
590 for (channel_idx = 0, i = 0; i < buffer_list->mNumberBuffers; i++) {
591 AudioBuffer *buf = buffer_list->mBuffers + i;
592
593 if (direction_in)
594 ca_device_create_source(m, buf, channel_idx);
595 else
596 ca_device_create_sink(m, buf, channel_idx);
597
598 channel_idx += buf->mNumberChannels;
599 }
600 }
601
602 pa_xfree(buffer_list);
603 return 0;
604 }
605
606 static void thread_func(void *userdata) {
607 struct userdata *u = userdata;
608
609 pa_assert(u);
610 pa_assert(u->module);
611 pa_assert(u->module->core);
612
613 pa_log_debug("Thread starting up");
614
615 if (u->module->core->realtime_scheduling)
616 pa_make_realtime(u->module->core->realtime_priority);
617
618 pa_thread_mq_install(&u->thread_mq);
619
620 for (;;) {
621 int ret;
622
623 ret = pa_rtpoll_run(u->rtpoll, TRUE);
624
625 if (ret < 0)
626 goto fail;
627
628 if (ret == 0)
629 goto finish;
630 }
631
632 fail:
633 /* If this was no regular exit from the loop we have to continue
634 * processing messages until we received PA_MESSAGE_SHUTDOWN */
635 pa_asyncmsgq_post(u->thread_mq.outq, PA_MSGOBJECT(u->module->core), PA_CORE_MESSAGE_UNLOAD_MODULE, u->module, 0, NULL, NULL);
636 pa_asyncmsgq_wait_for(u->thread_mq.inq, PA_MESSAGE_SHUTDOWN);
637
638 finish:
639 pa_log_debug("Thread shutting down");
640 }
641
642 int pa__init(pa_module *m) {
643 OSStatus err;
644 UInt32 size, frames;
645 struct userdata *u = NULL;
646 pa_modargs *ma = NULL;
647 char tmp[64];
648 pa_card_new_data card_new_data;
649 coreaudio_sink *ca_sink;
650 coreaudio_source *ca_source;
651
652 pa_assert(m);
653
654 if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
655 pa_log("Failed to parse module arguments.");
656 goto fail;
657 }
658
659 u = pa_xnew0(struct userdata, 1);
660 u->module = m;
661 m->userdata = u;
662
663 if (pa_modargs_get_value_u32(ma, "device_id", (unsigned int *) &u->device_id) != 0) {
664 pa_log("Failed to parse device_id argument.");
665 goto fail;
666 }
667
668 /* get device product name */
669 size = sizeof(tmp);
670 err = AudioDeviceGetProperty(u->device_id, 0, 0, kAudioDevicePropertyDeviceName, &size, &tmp);
671 if (err) {
672 pa_log("Failed to get kAudioDevicePropertyDeviceName (err = %08x).", (int) err);
673 goto fail;
674 }
675
676 u->device_name = pa_xstrdup(tmp);
677
678 pa_card_new_data_init(&card_new_data);
679 pa_proplist_sets(card_new_data.proplist, PA_PROP_DEVICE_STRING, tmp);
680 card_new_data.driver = __FILE__;
681 pa_card_new_data_set_name(&card_new_data, tmp);
682 pa_log_info("Initializing module for CoreAudio device '%s' (id %d)", tmp, (unsigned int) u->device_id);
683
684 /* get device vendor name (may fail) */
685 size = sizeof(tmp);
686 err = AudioDeviceGetProperty(u->device_id, 0, 0, kAudioDevicePropertyDeviceManufacturer, &size, &tmp);
687 if (!err)
688 u->vendor_name = pa_xstrdup(tmp);
689
690 /* create the card object */
691 u->card = pa_card_new(m->core, &card_new_data);
692 if (!u->card) {
693 pa_log("Unable to create card.\n");
694 goto fail;
695 }
696
697 pa_card_new_data_done(&card_new_data);
698 u->card->userdata = u;
699
700 u->rtpoll = pa_rtpoll_new();
701 pa_thread_mq_init(&u->thread_mq, m->core->mainloop, u->rtpoll);
702 u->async_msgq = pa_asyncmsgq_new(0);
703 pa_rtpoll_item_new_asyncmsgq_read(u->rtpoll, PA_RTPOLL_EARLY-1, u->async_msgq);
704
705 PA_LLIST_HEAD_INIT(coreaudio_sink, u->sinks);
706
707 /* create sinks */
708 ca_device_create_streams(m, FALSE);
709
710 /* create sources */
711 ca_device_create_streams(m, TRUE);
712
713 /* create the message thread */
714 if (!(u->thread = pa_thread_new(thread_func, u))) {
715 pa_log("Failed to create thread.");
716 goto fail;
717 }
718
719 /* register notification callback for stream format changes */
720 AudioDeviceAddPropertyListener(u->device_id, 0, 0, kAudioDevicePropertyStreamFormat, ca_stream_format_changed, u);
721
722 /* set number of frames in IOProc */
723 frames = DEFAULT_FRAMES_PER_IOPROC;
724 pa_modargs_get_value_u32(ma, "ioproc_frames", (unsigned int *) &frames);
725
726 AudioDeviceSetProperty(u->device_id, NULL, 0, 0, kAudioDevicePropertyBufferFrameSize, sizeof(frames), &frames);
727 pa_log_debug("%u frames per IOProc\n", (unsigned int) frames);
728
729 /* create one ioproc for both directions */
730 err = AudioDeviceCreateIOProcID(u->device_id, io_render_proc, u, &u->proc_id);
731 if (err) {
732 pa_log("AudioDeviceCreateIOProcID() failed (err = %08x\n).", (int) err);
733 goto fail;
734 }
735
736 for (ca_sink = u->sinks; ca_sink; ca_sink = ca_sink->next)
737 pa_sink_put(ca_sink->pa_sink);
738
739 for (ca_source = u->sources; ca_source; ca_source = ca_source->next)
740 pa_source_put(ca_source->pa_source);
741
742 pa_modargs_free(ma);
743
744 return 0;
745
746 fail:
747 if (u)
748 pa__done(m);
749
750 if (ma)
751 pa_modargs_free(ma);
752
753 return -1;
754 }
755
756 void pa__done(pa_module *m) {
757 struct userdata *u;
758 coreaudio_sink *ca_sink;
759 coreaudio_source *ca_source;
760
761 pa_assert(m);
762
763 u = m->userdata;
764 pa_assert(u);
765
766 /* unlink sinks */
767 for (ca_sink = u->sinks; ca_sink; ca_sink = ca_sink->next)
768 if (ca_sink->pa_sink)
769 pa_sink_unlink(ca_sink->pa_sink);
770
771 /* unlink sources */
772 for (ca_source = u->sources; ca_source; ca_source = ca_source->next)
773 if (ca_source->pa_source)
774 pa_source_unlink(ca_source->pa_source);
775
776 if (u->thread) {
777 pa_asyncmsgq_send(u->thread_mq.inq, NULL, PA_MESSAGE_SHUTDOWN, NULL, 0, NULL);
778 pa_thread_free(u->thread);
779 pa_thread_mq_done(&u->thread_mq);
780 pa_asyncmsgq_unref(u->async_msgq);
781 }
782
783 /* free sinks */
784 for (ca_sink = u->sinks; ca_sink;) {
785 coreaudio_sink *next = ca_sink->next;
786
787 if (ca_sink->pa_sink)
788 pa_sink_unref(ca_sink->pa_sink);
789
790 pa_xfree(ca_sink->name);
791 pa_xfree(ca_sink);
792 ca_sink = next;
793 }
794
795 /* free sources */
796 for (ca_source = u->sources; ca_source;) {
797 coreaudio_source *next = ca_source->next;
798
799 if (ca_source->pa_source)
800 pa_source_unref(ca_source->pa_source);
801
802 pa_xfree(ca_source->name);
803 pa_xfree(ca_source);
804 ca_source = next;
805 }
806
807 if (u->proc_id) {
808 AudioDeviceStop(u->device_id, u->proc_id);
809 AudioDeviceDestroyIOProcID(u->device_id, u->proc_id);
810 }
811
812 AudioDeviceRemovePropertyListener(u->device_id, 0, 0, kAudioDevicePropertyStreamFormat, ca_stream_format_changed);
813
814 pa_xfree(u->device_name);
815 pa_xfree(u->vendor_name);
816 pa_rtpoll_free(u->rtpoll);
817 pa_card_free(u->card);
818
819 pa_xfree(u);
820 }