2 * QEMU OS X CoreAudio audio driver
4 * Copyright (c) 2005 Mike Kronenberg
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 #include <CoreAudio/CoreAudio.h>
26 #include <string.h> /* strerror */
27 #include <pthread.h> /* pthread_X */
31 #define AUDIO_CAP "coreaudio"
32 #include "audio_int.h"
40 typedef struct coreaudioVoiceOut
{
42 pthread_mutex_t mutex
;
43 AudioDeviceID outputDeviceID
;
44 UInt32 audioDevicePropertyBufferSize
;
45 AudioStreamBasicDescription outputStreamBasicDescription
;
52 static void coreaudio_logstatus (OSStatus status
)
57 case kAudioHardwareNoError
:
58 str
= "kAudioHardwareNoError";
61 case kAudioHardwareNotRunningError
:
62 str
= "kAudioHardwareNotRunningError";
65 case kAudioHardwareUnspecifiedError
:
66 str
= "kAudioHardwareUnspecifiedError";
69 case kAudioHardwareUnknownPropertyError
:
70 str
= "kAudioHardwareUnknownPropertyError";
73 case kAudioHardwareBadPropertySizeError
:
74 str
= "kAudioHardwareBadPropertySizeError";
77 case kAudioHardwareIllegalOperationError
:
78 str
= "kAudioHardwareIllegalOperationError";
81 case kAudioHardwareBadDeviceError
:
82 str
= "kAudioHardwareBadDeviceError";
85 case kAudioHardwareBadStreamError
:
86 str
= "kAudioHardwareBadStreamError";
89 case kAudioHardwareUnsupportedOperationError
:
90 str
= "kAudioHardwareUnsupportedOperationError";
93 case kAudioDeviceUnsupportedFormatError
:
94 str
= "kAudioDeviceUnsupportedFormatError";
97 case kAudioDevicePermissionsError
:
98 str
= "kAudioDevicePermissionsError";
102 AUD_log (AUDIO_CAP
, "Reason: status code %ld\n", status
);
106 AUD_log (AUDIO_CAP
, "Reason: %s\n", str
);
109 static void GCC_FMT_ATTR (2, 3) coreaudio_logerr (
118 AUD_log (AUDIO_CAP
, fmt
, ap
);
121 coreaudio_logstatus (status
);
124 static void GCC_FMT_ATTR (3, 4) coreaudio_logerr2 (
133 AUD_log (AUDIO_CAP
, "Could not initialize %s\n", typ
);
136 AUD_vlog (AUDIO_CAP
, fmt
, ap
);
139 coreaudio_logstatus (status
);
142 static int coreaudio_lock (coreaudioVoiceOut
*core
, const char *fn_name
)
146 err
= pthread_mutex_lock (&core
->mutex
);
148 dolog ("Could not lock voice for %s\nReason: %s\n",
149 fn_name
, strerror (err
));
155 static int coreaudio_unlock (coreaudioVoiceOut
*core
, const char *fn_name
)
159 err
= pthread_mutex_unlock (&core
->mutex
);
161 dolog ("Could not unlock voice for %s\nReason: %s\n",
162 fn_name
, strerror (err
));
168 static int coreaudio_run_out (HWVoiceOut
*hw
)
171 coreaudioVoiceOut
*core
= (coreaudioVoiceOut
*) hw
;
173 if (coreaudio_lock (core
, "coreaudio_run_out")) {
177 live
= audio_pcm_hw_get_live_out (hw
);
179 if (core
->decr
> live
) {
180 ldebug ("core->decr %d live %d core->live %d\n",
186 decr
= audio_MIN (core
->decr
, live
);
189 core
->live
= live
- decr
;
190 hw
->rpos
= core
->rpos
;
192 coreaudio_unlock (core
, "coreaudio_run_out");
196 /* callback to feed audiooutput buffer */
197 static OSStatus
audioDeviceIOProc(
198 AudioDeviceID inDevice
,
199 const AudioTimeStamp
* inNow
,
200 const AudioBufferList
* inInputData
,
201 const AudioTimeStamp
* inInputTime
,
202 AudioBufferList
* outOutputData
,
203 const AudioTimeStamp
* inOutputTime
,
206 unsigned int frame
, frameCount
;
207 float *out
= outOutputData
->mBuffers
[0].mData
;
208 HWVoiceOut
*hw
= hwptr
;
209 coreaudioVoiceOut
*core
= (coreaudioVoiceOut
*) hwptr
;
214 const float scale
= 1.f
/ UINT_MAX
;
216 const float scale
= UINT_MAX
;
220 if (coreaudio_lock (core
, "audioDeviceIOProc")) {
225 frameCount
= conf
.buffer_frames
;
228 /* if there are not enough samples, set signal and return */
229 if (live
< frameCount
) {
231 coreaudio_unlock (core
, "audioDeviceIOProc(empty)");
236 src
= hw
->mix_buf
+ rpos
;
239 for (frame
= 0; frame
< frameCount
; frame
++) {
241 *out
++ = src
[frame
].l
; /* left channel */
242 *out
++ = src
[frame
].r
; /* right channel */
245 *out
++ = src
[frame
].l
* scale
; /* left channel */
246 *out
++ = src
[frame
].r
* scale
; /* right channel */
248 *out
++ = src
[frame
].l
/ scale
; /* left channel */
249 *out
++ = src
[frame
].r
/ scale
; /* right channel */
255 mixeng_clear (src
, frameCount
);
256 rpos
= (rpos
+ frameCount
) % hw
->samples
;
257 core
->decr
= frameCount
;
260 coreaudio_unlock (core
, "audioDeviceIOProc");
264 static int coreaudio_write (SWVoiceOut
*sw
, void *buf
, int len
)
266 return audio_pcm_sw_write (sw
, buf
, len
);
269 static int coreaudio_init_out (HWVoiceOut
*hw
, audsettings_t
*as
)
272 coreaudioVoiceOut
*core
= (coreaudioVoiceOut
*) hw
;
277 const char *typ
= "DAC";
280 err
= pthread_mutex_init(&core
->mutex
, NULL
);
282 dolog("Could not create mutex\nReason: %s\n", strerror (err
));
286 if (as
->fmt
== AUD_FMT_S16
|| as
->fmt
== AUD_FMT_U16
) {
291 audio_pcm_init_info (
294 /* Following is irrelevant actually since we do not use
295 mixengs clipping routines */
296 audio_need_to_swap_endian (endianess
)
299 /* open default output device */
300 propertySize
= sizeof(core
->outputDeviceID
);
301 status
= AudioHardwareGetProperty(
302 kAudioHardwarePropertyDefaultOutputDevice
,
304 &core
->outputDeviceID
);
305 if (status
!= kAudioHardwareNoError
) {
306 coreaudio_logerr2 (status
, typ
,
307 "Could not get default output Device\n");
310 if (core
->outputDeviceID
== kAudioDeviceUnknown
) {
311 dolog ("Could not initialize %s - Unknown Audiodevice\n", typ
);
315 /* set Buffersize to conf.buffer_frames frames */
316 propertySize
= sizeof(core
->audioDevicePropertyBufferSize
);
317 core
->audioDevicePropertyBufferSize
=
318 conf
.buffer_frames
* sizeof(float) << (as
->nchannels
== 2);
319 status
= AudioDeviceSetProperty(
320 core
->outputDeviceID
,
324 kAudioDevicePropertyBufferSize
,
326 &core
->audioDevicePropertyBufferSize
);
327 if (status
!= kAudioHardwareNoError
) {
328 coreaudio_logerr2 (status
, typ
,
329 "Could not set device buffer size %d\n",
330 kAudioDevicePropertyBufferSize
);
335 propertySize
= sizeof(core
->audioDevicePropertyBufferSize
);
336 status
= AudioDeviceGetProperty(
337 core
->outputDeviceID
,
340 kAudioDevicePropertyBufferSize
,
342 &core
->audioDevicePropertyBufferSize
);
343 if (status
!= kAudioHardwareNoError
) {
344 coreaudio_logerr2 (status
, typ
, "Could not get device buffer size\n");
347 hw
->samples
= (core
->audioDevicePropertyBufferSize
/ sizeof (float))
348 >> (as
->nchannels
== 2);
350 /* get StreamFormat */
351 propertySize
= sizeof(core
->outputStreamBasicDescription
);
352 status
= AudioDeviceGetProperty(
353 core
->outputDeviceID
,
356 kAudioDevicePropertyStreamFormat
,
358 &core
->outputStreamBasicDescription
);
359 if (status
!= kAudioHardwareNoError
) {
360 coreaudio_logerr2 (status
, typ
,
361 "Could not get Device Stream properties\n");
362 core
->outputDeviceID
= kAudioDeviceUnknown
;
367 core
->outputStreamBasicDescription
.mSampleRate
= (Float64
)as
->freq
;
368 propertySize
= sizeof(core
->outputStreamBasicDescription
);
369 status
= AudioDeviceSetProperty(
370 core
->outputDeviceID
,
374 kAudioDevicePropertyStreamFormat
,
376 &core
->outputStreamBasicDescription
);
377 if (status
!= kAudioHardwareNoError
) {
378 coreaudio_logerr2 (status
, typ
, "Could not set samplerate %d\n", freq
);
379 core
->outputDeviceID
= kAudioDeviceUnknown
;
384 status
= AudioDeviceAddIOProc(core
->outputDeviceID
, audioDeviceIOProc
, hw
);
385 if (status
!= kAudioHardwareNoError
) {
386 coreaudio_logerr2 (status
, typ
, "Could not set IOProc\n");
387 core
->outputDeviceID
= kAudioDeviceUnknown
;
392 if (!core
->isPlaying
) {
393 status
= AudioDeviceStart(core
->outputDeviceID
, audioDeviceIOProc
);
394 if (status
!= kAudioHardwareNoError
) {
395 coreaudio_logerr2 (status
, typ
, "Could not start playback\n");
396 AudioDeviceRemoveIOProc(core
->outputDeviceID
, audioDeviceIOProc
);
397 core
->outputDeviceID
= kAudioDeviceUnknown
;
406 static void coreaudio_fini_out (HWVoiceOut
*hw
)
410 coreaudioVoiceOut
*core
= (coreaudioVoiceOut
*) hw
;
413 if (core
->isPlaying
) {
414 status
= AudioDeviceStop(core
->outputDeviceID
, audioDeviceIOProc
);
415 if (status
!= kAudioHardwareNoError
) {
416 coreaudio_logerr (status
, "Could not stop playback\n");
421 /* remove callback */
422 status
= AudioDeviceRemoveIOProc(core
->outputDeviceID
, audioDeviceIOProc
);
423 if (status
!= kAudioHardwareNoError
) {
424 coreaudio_logerr (status
, "Could not remove IOProc\n");
426 core
->outputDeviceID
= kAudioDeviceUnknown
;
429 err
= pthread_mutex_destroy(&core
->mutex
);
431 dolog("Could not destroy mutex\nReason: %s\n", strerror (err
));
435 static int coreaudio_ctl_out (HWVoiceOut
*hw
, int cmd
, ...)
438 coreaudioVoiceOut
*core
= (coreaudioVoiceOut
*) hw
;
443 if (!core
->isPlaying
) {
444 status
= AudioDeviceStart(core
->outputDeviceID
, audioDeviceIOProc
);
445 if (status
!= kAudioHardwareNoError
) {
446 coreaudio_logerr (status
, "Could not unpause playback\n");
454 if (core
->isPlaying
) {
455 status
= AudioDeviceStop(core
->outputDeviceID
, audioDeviceIOProc
);
456 if (status
!= kAudioHardwareNoError
) {
457 coreaudio_logerr (status
, "Could not pause playback\n");
466 static void *coreaudio_audio_init (void)
468 return &coreaudio_audio_init
;
471 static void coreaudio_audio_fini (void *opaque
)
476 static struct audio_option coreaudio_options
[] = {
477 {"BUFFER_SIZE", AUD_OPT_INT
, &conf
.buffer_frames
,
478 "Size of the buffer in frames", NULL
, 0},
479 {NULL
, 0, NULL
, NULL
, NULL
, 0}
482 static struct audio_pcm_ops coreaudio_pcm_ops
= {
496 struct audio_driver coreaudio_audio_driver
= {
497 INIT_FIELD (name
= ) "coreaudio",
498 INIT_FIELD (descr
= )
499 "CoreAudio http://developer.apple.com/audio/coreaudio.html",
500 INIT_FIELD (options
= ) coreaudio_options
,
501 INIT_FIELD (init
= ) coreaudio_audio_init
,
502 INIT_FIELD (fini
= ) coreaudio_audio_fini
,
503 INIT_FIELD (pcm_ops
= ) &coreaudio_pcm_ops
,
504 INIT_FIELD (can_be_default
= ) 1,
505 INIT_FIELD (max_voices_out
= ) 1,
506 INIT_FIELD (max_voices_in
= ) 0,
507 INIT_FIELD (voice_size_out
= ) sizeof (coreaudioVoiceOut
),
508 INIT_FIELD (voice_size_in
= ) 0