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