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