]> Git Repo - qemu.git/blob - audio/coreaudio.c
Merge remote-tracking branch 'remotes/jnsnow/tags/bitmaps-pull-request' into staging
[qemu.git] / audio / coreaudio.c
1 /*
2  * QEMU OS X CoreAudio audio driver
3  *
4  * Copyright (c) 2005 Mike Kronenberg
5  *
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:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
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
22  * THE SOFTWARE.
23  */
24
25 #include "qemu/osdep.h"
26 #include <CoreAudio/CoreAudio.h>
27 #include <pthread.h>            /* pthread_X */
28
29 #include "qemu-common.h"
30 #include "audio.h"
31
32 #define AUDIO_CAP "coreaudio"
33 #include "audio_int.h"
34
35 #ifndef MAC_OS_X_VERSION_10_6
36 #define MAC_OS_X_VERSION_10_6 1060
37 #endif
38
39 typedef struct coreaudioVoiceOut {
40     HWVoiceOut hw;
41     pthread_mutex_t mutex;
42     AudioDeviceID outputDeviceID;
43     UInt32 audioDevicePropertyBufferFrameSize;
44     AudioStreamBasicDescription outputStreamBasicDescription;
45     AudioDeviceIOProcID ioprocid;
46     int live;
47     int decr;
48     int rpos;
49 } coreaudioVoiceOut;
50
51 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
52 /* The APIs used here only become available from 10.6 */
53
54 static OSStatus coreaudio_get_voice(AudioDeviceID *id)
55 {
56     UInt32 size = sizeof(*id);
57     AudioObjectPropertyAddress addr = {
58         kAudioHardwarePropertyDefaultOutputDevice,
59         kAudioObjectPropertyScopeGlobal,
60         kAudioObjectPropertyElementMaster
61     };
62
63     return AudioObjectGetPropertyData(kAudioObjectSystemObject,
64                                       &addr,
65                                       0,
66                                       NULL,
67                                       &size,
68                                       id);
69 }
70
71 static OSStatus coreaudio_get_framesizerange(AudioDeviceID id,
72                                              AudioValueRange *framerange)
73 {
74     UInt32 size = sizeof(*framerange);
75     AudioObjectPropertyAddress addr = {
76         kAudioDevicePropertyBufferFrameSizeRange,
77         kAudioDevicePropertyScopeOutput,
78         kAudioObjectPropertyElementMaster
79     };
80
81     return AudioObjectGetPropertyData(id,
82                                       &addr,
83                                       0,
84                                       NULL,
85                                       &size,
86                                       framerange);
87 }
88
89 static OSStatus coreaudio_get_framesize(AudioDeviceID id, UInt32 *framesize)
90 {
91     UInt32 size = sizeof(*framesize);
92     AudioObjectPropertyAddress addr = {
93         kAudioDevicePropertyBufferFrameSize,
94         kAudioDevicePropertyScopeOutput,
95         kAudioObjectPropertyElementMaster
96     };
97
98     return AudioObjectGetPropertyData(id,
99                                       &addr,
100                                       0,
101                                       NULL,
102                                       &size,
103                                       framesize);
104 }
105
106 static OSStatus coreaudio_set_framesize(AudioDeviceID id, UInt32 *framesize)
107 {
108     UInt32 size = sizeof(*framesize);
109     AudioObjectPropertyAddress addr = {
110         kAudioDevicePropertyBufferFrameSize,
111         kAudioDevicePropertyScopeOutput,
112         kAudioObjectPropertyElementMaster
113     };
114
115     return AudioObjectSetPropertyData(id,
116                                       &addr,
117                                       0,
118                                       NULL,
119                                       size,
120                                       framesize);
121 }
122
123 static OSStatus coreaudio_get_streamformat(AudioDeviceID id,
124                                            AudioStreamBasicDescription *d)
125 {
126     UInt32 size = sizeof(*d);
127     AudioObjectPropertyAddress addr = {
128         kAudioDevicePropertyStreamFormat,
129         kAudioDevicePropertyScopeOutput,
130         kAudioObjectPropertyElementMaster
131     };
132
133     return AudioObjectGetPropertyData(id,
134                                       &addr,
135                                       0,
136                                       NULL,
137                                       &size,
138                                       d);
139 }
140
141 static OSStatus coreaudio_set_streamformat(AudioDeviceID id,
142                                            AudioStreamBasicDescription *d)
143 {
144     UInt32 size = sizeof(*d);
145     AudioObjectPropertyAddress addr = {
146         kAudioDevicePropertyStreamFormat,
147         kAudioDevicePropertyScopeOutput,
148         kAudioObjectPropertyElementMaster
149     };
150
151     return AudioObjectSetPropertyData(id,
152                                       &addr,
153                                       0,
154                                       NULL,
155                                       size,
156                                       d);
157 }
158
159 static OSStatus coreaudio_get_isrunning(AudioDeviceID id, UInt32 *result)
160 {
161     UInt32 size = sizeof(*result);
162     AudioObjectPropertyAddress addr = {
163         kAudioDevicePropertyDeviceIsRunning,
164         kAudioDevicePropertyScopeOutput,
165         kAudioObjectPropertyElementMaster
166     };
167
168     return AudioObjectGetPropertyData(id,
169                                       &addr,
170                                       0,
171                                       NULL,
172                                       &size,
173                                       result);
174 }
175 #else
176 /* Legacy versions of functions using deprecated APIs */
177
178 static OSStatus coreaudio_get_voice(AudioDeviceID *id)
179 {
180     UInt32 size = sizeof(*id);
181
182     return AudioHardwareGetProperty(
183         kAudioHardwarePropertyDefaultOutputDevice,
184         &size,
185         id);
186 }
187
188 static OSStatus coreaudio_get_framesizerange(AudioDeviceID id,
189                                              AudioValueRange *framerange)
190 {
191     UInt32 size = sizeof(*framerange);
192
193     return AudioDeviceGetProperty(
194         id,
195         0,
196         0,
197         kAudioDevicePropertyBufferFrameSizeRange,
198         &size,
199         framerange);
200 }
201
202 static OSStatus coreaudio_get_framesize(AudioDeviceID id, UInt32 *framesize)
203 {
204     UInt32 size = sizeof(*framesize);
205
206     return AudioDeviceGetProperty(
207         id,
208         0,
209         false,
210         kAudioDevicePropertyBufferFrameSize,
211         &size,
212         framesize);
213 }
214
215 static OSStatus coreaudio_set_framesize(AudioDeviceID id, UInt32 *framesize)
216 {
217     UInt32 size = sizeof(*framesize);
218
219     return AudioDeviceSetProperty(
220         id,
221         NULL,
222         0,
223         false,
224         kAudioDevicePropertyBufferFrameSize,
225         size,
226         framesize);
227 }
228
229 static OSStatus coreaudio_get_streamformat(AudioDeviceID id,
230                                            AudioStreamBasicDescription *d)
231 {
232     UInt32 size = sizeof(*d);
233
234     return AudioDeviceGetProperty(
235         id,
236         0,
237         false,
238         kAudioDevicePropertyStreamFormat,
239         &size,
240         d);
241 }
242
243 static OSStatus coreaudio_set_streamformat(AudioDeviceID id,
244                                            AudioStreamBasicDescription *d)
245 {
246     UInt32 size = sizeof(*d);
247
248     return AudioDeviceSetProperty(
249         id,
250         0,
251         0,
252         0,
253         kAudioDevicePropertyStreamFormat,
254         size,
255         d);
256 }
257
258 static OSStatus coreaudio_get_isrunning(AudioDeviceID id, UInt32 *result)
259 {
260     UInt32 size = sizeof(*result);
261
262     return AudioDeviceGetProperty(
263         id,
264         0,
265         0,
266         kAudioDevicePropertyDeviceIsRunning,
267         &size,
268         result);
269 }
270 #endif
271
272 static void coreaudio_logstatus (OSStatus status)
273 {
274     const char *str = "BUG";
275
276     switch(status) {
277     case kAudioHardwareNoError:
278         str = "kAudioHardwareNoError";
279         break;
280
281     case kAudioHardwareNotRunningError:
282         str = "kAudioHardwareNotRunningError";
283         break;
284
285     case kAudioHardwareUnspecifiedError:
286         str = "kAudioHardwareUnspecifiedError";
287         break;
288
289     case kAudioHardwareUnknownPropertyError:
290         str = "kAudioHardwareUnknownPropertyError";
291         break;
292
293     case kAudioHardwareBadPropertySizeError:
294         str = "kAudioHardwareBadPropertySizeError";
295         break;
296
297     case kAudioHardwareIllegalOperationError:
298         str = "kAudioHardwareIllegalOperationError";
299         break;
300
301     case kAudioHardwareBadDeviceError:
302         str = "kAudioHardwareBadDeviceError";
303         break;
304
305     case kAudioHardwareBadStreamError:
306         str = "kAudioHardwareBadStreamError";
307         break;
308
309     case kAudioHardwareUnsupportedOperationError:
310         str = "kAudioHardwareUnsupportedOperationError";
311         break;
312
313     case kAudioDeviceUnsupportedFormatError:
314         str = "kAudioDeviceUnsupportedFormatError";
315         break;
316
317     case kAudioDevicePermissionsError:
318         str = "kAudioDevicePermissionsError";
319         break;
320
321     default:
322         AUD_log (AUDIO_CAP, "Reason: status code %" PRId32 "\n", (int32_t)status);
323         return;
324     }
325
326     AUD_log (AUDIO_CAP, "Reason: %s\n", str);
327 }
328
329 static void GCC_FMT_ATTR (2, 3) coreaudio_logerr (
330     OSStatus status,
331     const char *fmt,
332     ...
333     )
334 {
335     va_list ap;
336
337     va_start (ap, fmt);
338     AUD_log (AUDIO_CAP, fmt, ap);
339     va_end (ap);
340
341     coreaudio_logstatus (status);
342 }
343
344 static void GCC_FMT_ATTR (3, 4) coreaudio_logerr2 (
345     OSStatus status,
346     const char *typ,
347     const char *fmt,
348     ...
349     )
350 {
351     va_list ap;
352
353     AUD_log (AUDIO_CAP, "Could not initialize %s\n", typ);
354
355     va_start (ap, fmt);
356     AUD_vlog (AUDIO_CAP, fmt, ap);
357     va_end (ap);
358
359     coreaudio_logstatus (status);
360 }
361
362 static inline UInt32 isPlaying (AudioDeviceID outputDeviceID)
363 {
364     OSStatus status;
365     UInt32 result = 0;
366     status = coreaudio_get_isrunning(outputDeviceID, &result);
367     if (status != kAudioHardwareNoError) {
368         coreaudio_logerr(status,
369                          "Could not determine whether Device is playing\n");
370     }
371     return result;
372 }
373
374 static int coreaudio_lock (coreaudioVoiceOut *core, const char *fn_name)
375 {
376     int err;
377
378     err = pthread_mutex_lock (&core->mutex);
379     if (err) {
380         dolog ("Could not lock voice for %s\nReason: %s\n",
381                fn_name, strerror (err));
382         return -1;
383     }
384     return 0;
385 }
386
387 static int coreaudio_unlock (coreaudioVoiceOut *core, const char *fn_name)
388 {
389     int err;
390
391     err = pthread_mutex_unlock (&core->mutex);
392     if (err) {
393         dolog ("Could not unlock voice for %s\nReason: %s\n",
394                fn_name, strerror (err));
395         return -1;
396     }
397     return 0;
398 }
399
400 static int coreaudio_run_out (HWVoiceOut *hw, int live)
401 {
402     int decr;
403     coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
404
405     if (coreaudio_lock (core, "coreaudio_run_out")) {
406         return 0;
407     }
408
409     if (core->decr > live) {
410         ldebug ("core->decr %d live %d core->live %d\n",
411                 core->decr,
412                 live,
413                 core->live);
414     }
415
416     decr = audio_MIN (core->decr, live);
417     core->decr -= decr;
418
419     core->live = live - decr;
420     hw->rpos = core->rpos;
421
422     coreaudio_unlock (core, "coreaudio_run_out");
423     return decr;
424 }
425
426 /* callback to feed audiooutput buffer */
427 static OSStatus audioDeviceIOProc(
428     AudioDeviceID inDevice,
429     const AudioTimeStamp* inNow,
430     const AudioBufferList* inInputData,
431     const AudioTimeStamp* inInputTime,
432     AudioBufferList* outOutputData,
433     const AudioTimeStamp* inOutputTime,
434     void* hwptr)
435 {
436     UInt32 frame, frameCount;
437     float *out = outOutputData->mBuffers[0].mData;
438     HWVoiceOut *hw = hwptr;
439     coreaudioVoiceOut *core = (coreaudioVoiceOut *) hwptr;
440     int rpos, live;
441     struct st_sample *src;
442 #ifndef FLOAT_MIXENG
443 #ifdef RECIPROCAL
444     const float scale = 1.f / UINT_MAX;
445 #else
446     const float scale = UINT_MAX;
447 #endif
448 #endif
449
450     if (coreaudio_lock (core, "audioDeviceIOProc")) {
451         inInputTime = 0;
452         return 0;
453     }
454
455     frameCount = core->audioDevicePropertyBufferFrameSize;
456     live = core->live;
457
458     /* if there are not enough samples, set signal and return */
459     if (live < frameCount) {
460         inInputTime = 0;
461         coreaudio_unlock (core, "audioDeviceIOProc(empty)");
462         return 0;
463     }
464
465     rpos = core->rpos;
466     src = hw->mix_buf + rpos;
467
468     /* fill buffer */
469     for (frame = 0; frame < frameCount; frame++) {
470 #ifdef FLOAT_MIXENG
471         *out++ = src[frame].l; /* left channel */
472         *out++ = src[frame].r; /* right channel */
473 #else
474 #ifdef RECIPROCAL
475         *out++ = src[frame].l * scale; /* left channel */
476         *out++ = src[frame].r * scale; /* right channel */
477 #else
478         *out++ = src[frame].l / scale; /* left channel */
479         *out++ = src[frame].r / scale; /* right channel */
480 #endif
481 #endif
482     }
483
484     rpos = (rpos + frameCount) % hw->samples;
485     core->decr += frameCount;
486     core->rpos = rpos;
487
488     coreaudio_unlock (core, "audioDeviceIOProc");
489     return 0;
490 }
491
492 static int coreaudio_write (SWVoiceOut *sw, void *buf, int len)
493 {
494     return audio_pcm_sw_write (sw, buf, len);
495 }
496
497 static int coreaudio_init_out(HWVoiceOut *hw, struct audsettings *as,
498                               void *drv_opaque)
499 {
500     OSStatus status;
501     coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
502     int err;
503     const char *typ = "playback";
504     AudioValueRange frameRange;
505     Audiodev *dev = drv_opaque;
506     AudiodevCoreaudioPerDirectionOptions *cpdo = dev->u.coreaudio.out;
507     int frames;
508
509     /* create mutex */
510     err = pthread_mutex_init(&core->mutex, NULL);
511     if (err) {
512         dolog("Could not create mutex\nReason: %s\n", strerror (err));
513         return -1;
514     }
515
516     audio_pcm_init_info (&hw->info, as);
517
518     status = coreaudio_get_voice(&core->outputDeviceID);
519     if (status != kAudioHardwareNoError) {
520         coreaudio_logerr2 (status, typ,
521                            "Could not get default output Device\n");
522         return -1;
523     }
524     if (core->outputDeviceID == kAudioDeviceUnknown) {
525         dolog ("Could not initialize %s - Unknown Audiodevice\n", typ);
526         return -1;
527     }
528
529     /* get minimum and maximum buffer frame sizes */
530     status = coreaudio_get_framesizerange(core->outputDeviceID,
531                                           &frameRange);
532     if (status != kAudioHardwareNoError) {
533         coreaudio_logerr2 (status, typ,
534                            "Could not get device buffer frame range\n");
535         return -1;
536     }
537
538     frames = audio_buffer_frames(
539         qapi_AudiodevCoreaudioPerDirectionOptions_base(cpdo), as, 11610);
540     if (frameRange.mMinimum > frames) {
541         core->audioDevicePropertyBufferFrameSize = (UInt32) frameRange.mMinimum;
542         dolog ("warning: Upsizing Buffer Frames to %f\n", frameRange.mMinimum);
543     } else if (frameRange.mMaximum < frames) {
544         core->audioDevicePropertyBufferFrameSize = (UInt32) frameRange.mMaximum;
545         dolog ("warning: Downsizing Buffer Frames to %f\n", frameRange.mMaximum);
546     }
547     else {
548         core->audioDevicePropertyBufferFrameSize = frames;
549     }
550
551     /* set Buffer Frame Size */
552     status = coreaudio_set_framesize(core->outputDeviceID,
553                                      &core->audioDevicePropertyBufferFrameSize);
554     if (status != kAudioHardwareNoError) {
555         coreaudio_logerr2 (status, typ,
556                            "Could not set device buffer frame size %" PRIu32 "\n",
557                            (uint32_t)core->audioDevicePropertyBufferFrameSize);
558         return -1;
559     }
560
561     /* get Buffer Frame Size */
562     status = coreaudio_get_framesize(core->outputDeviceID,
563                                      &core->audioDevicePropertyBufferFrameSize);
564     if (status != kAudioHardwareNoError) {
565         coreaudio_logerr2 (status, typ,
566                            "Could not get device buffer frame size\n");
567         return -1;
568     }
569     hw->samples = (cpdo->has_buffer_count ? cpdo->buffer_count : 4) *
570         core->audioDevicePropertyBufferFrameSize;
571
572     /* get StreamFormat */
573     status = coreaudio_get_streamformat(core->outputDeviceID,
574                                         &core->outputStreamBasicDescription);
575     if (status != kAudioHardwareNoError) {
576         coreaudio_logerr2 (status, typ,
577                            "Could not get Device Stream properties\n");
578         core->outputDeviceID = kAudioDeviceUnknown;
579         return -1;
580     }
581
582     /* set Samplerate */
583     core->outputStreamBasicDescription.mSampleRate = (Float64) as->freq;
584     status = coreaudio_set_streamformat(core->outputDeviceID,
585                                         &core->outputStreamBasicDescription);
586     if (status != kAudioHardwareNoError) {
587         coreaudio_logerr2 (status, typ, "Could not set samplerate %d\n",
588                            as->freq);
589         core->outputDeviceID = kAudioDeviceUnknown;
590         return -1;
591     }
592
593     /* set Callback */
594     core->ioprocid = NULL;
595     status = AudioDeviceCreateIOProcID(core->outputDeviceID,
596                                        audioDeviceIOProc,
597                                        hw,
598                                        &core->ioprocid);
599     if (status != kAudioHardwareNoError || core->ioprocid == NULL) {
600         coreaudio_logerr2 (status, typ, "Could not set IOProc\n");
601         core->outputDeviceID = kAudioDeviceUnknown;
602         return -1;
603     }
604
605     /* start Playback */
606     if (!isPlaying(core->outputDeviceID)) {
607         status = AudioDeviceStart(core->outputDeviceID, core->ioprocid);
608         if (status != kAudioHardwareNoError) {
609             coreaudio_logerr2 (status, typ, "Could not start playback\n");
610             AudioDeviceDestroyIOProcID(core->outputDeviceID, core->ioprocid);
611             core->outputDeviceID = kAudioDeviceUnknown;
612             return -1;
613         }
614     }
615
616     return 0;
617 }
618
619 static void coreaudio_fini_out (HWVoiceOut *hw)
620 {
621     OSStatus status;
622     int err;
623     coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
624
625     if (!audio_is_cleaning_up()) {
626         /* stop playback */
627         if (isPlaying(core->outputDeviceID)) {
628             status = AudioDeviceStop(core->outputDeviceID, core->ioprocid);
629             if (status != kAudioHardwareNoError) {
630                 coreaudio_logerr (status, "Could not stop playback\n");
631             }
632         }
633
634         /* remove callback */
635         status = AudioDeviceDestroyIOProcID(core->outputDeviceID,
636                                             core->ioprocid);
637         if (status != kAudioHardwareNoError) {
638             coreaudio_logerr (status, "Could not remove IOProc\n");
639         }
640     }
641     core->outputDeviceID = kAudioDeviceUnknown;
642
643     /* destroy mutex */
644     err = pthread_mutex_destroy(&core->mutex);
645     if (err) {
646         dolog("Could not destroy mutex\nReason: %s\n", strerror (err));
647     }
648 }
649
650 static int coreaudio_ctl_out (HWVoiceOut *hw, int cmd, ...)
651 {
652     OSStatus status;
653     coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
654
655     switch (cmd) {
656     case VOICE_ENABLE:
657         /* start playback */
658         if (!isPlaying(core->outputDeviceID)) {
659             status = AudioDeviceStart(core->outputDeviceID, core->ioprocid);
660             if (status != kAudioHardwareNoError) {
661                 coreaudio_logerr (status, "Could not resume playback\n");
662             }
663         }
664         break;
665
666     case VOICE_DISABLE:
667         /* stop playback */
668         if (!audio_is_cleaning_up()) {
669             if (isPlaying(core->outputDeviceID)) {
670                 status = AudioDeviceStop(core->outputDeviceID,
671                                          core->ioprocid);
672                 if (status != kAudioHardwareNoError) {
673                     coreaudio_logerr (status, "Could not pause playback\n");
674                 }
675             }
676         }
677         break;
678     }
679     return 0;
680 }
681
682 static void *coreaudio_audio_init(Audiodev *dev)
683 {
684     return dev;
685 }
686
687 static void coreaudio_audio_fini (void *opaque)
688 {
689 }
690
691 static struct audio_pcm_ops coreaudio_pcm_ops = {
692     .init_out = coreaudio_init_out,
693     .fini_out = coreaudio_fini_out,
694     .run_out  = coreaudio_run_out,
695     .write    = coreaudio_write,
696     .ctl_out  = coreaudio_ctl_out
697 };
698
699 static struct audio_driver coreaudio_audio_driver = {
700     .name           = "coreaudio",
701     .descr          = "CoreAudio http://developer.apple.com/audio/coreaudio.html",
702     .init           = coreaudio_audio_init,
703     .fini           = coreaudio_audio_fini,
704     .pcm_ops        = &coreaudio_pcm_ops,
705     .can_be_default = 1,
706     .max_voices_out = 1,
707     .max_voices_in  = 0,
708     .voice_size_out = sizeof (coreaudioVoiceOut),
709     .voice_size_in  = 0
710 };
711
712 static void register_audio_coreaudio(void)
713 {
714     audio_driver_register(&coreaudio_audio_driver);
715 }
716 type_init(register_audio_coreaudio);
This page took 0.065936 seconds and 4 git commands to generate.