]> Git Repo - qemu.git/blob - audio/coreaudio.c
Merge remote-tracking branch 'riku/linux-user-for-upstream' 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 <CoreAudio/CoreAudio.h>
26 #include <string.h>             /* strerror */
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 struct {
36     int buffer_frames;
37     int nbuffers;
38     int isAtexit;
39 } conf = {
40     .buffer_frames = 512,
41     .nbuffers = 4,
42     .isAtexit = 0
43 };
44
45 typedef struct coreaudioVoiceOut {
46     HWVoiceOut hw;
47     pthread_mutex_t mutex;
48     int isAtexit;
49     AudioDeviceID outputDeviceID;
50     UInt32 audioDevicePropertyBufferFrameSize;
51     AudioStreamBasicDescription outputStreamBasicDescription;
52     int live;
53     int decr;
54     int rpos;
55 } coreaudioVoiceOut;
56
57 static void coreaudio_logstatus (OSStatus status)
58 {
59     const char *str = "BUG";
60
61     switch(status) {
62     case kAudioHardwareNoError:
63         str = "kAudioHardwareNoError";
64         break;
65
66     case kAudioHardwareNotRunningError:
67         str = "kAudioHardwareNotRunningError";
68         break;
69
70     case kAudioHardwareUnspecifiedError:
71         str = "kAudioHardwareUnspecifiedError";
72         break;
73
74     case kAudioHardwareUnknownPropertyError:
75         str = "kAudioHardwareUnknownPropertyError";
76         break;
77
78     case kAudioHardwareBadPropertySizeError:
79         str = "kAudioHardwareBadPropertySizeError";
80         break;
81
82     case kAudioHardwareIllegalOperationError:
83         str = "kAudioHardwareIllegalOperationError";
84         break;
85
86     case kAudioHardwareBadDeviceError:
87         str = "kAudioHardwareBadDeviceError";
88         break;
89
90     case kAudioHardwareBadStreamError:
91         str = "kAudioHardwareBadStreamError";
92         break;
93
94     case kAudioHardwareUnsupportedOperationError:
95         str = "kAudioHardwareUnsupportedOperationError";
96         break;
97
98     case kAudioDeviceUnsupportedFormatError:
99         str = "kAudioDeviceUnsupportedFormatError";
100         break;
101
102     case kAudioDevicePermissionsError:
103         str = "kAudioDevicePermissionsError";
104         break;
105
106     default:
107         AUD_log (AUDIO_CAP, "Reason: status code %" PRId32 "\n", (int32_t)status);
108         return;
109     }
110
111     AUD_log (AUDIO_CAP, "Reason: %s\n", str);
112 }
113
114 static void GCC_FMT_ATTR (2, 3) coreaudio_logerr (
115     OSStatus status,
116     const char *fmt,
117     ...
118     )
119 {
120     va_list ap;
121
122     va_start (ap, fmt);
123     AUD_log (AUDIO_CAP, fmt, ap);
124     va_end (ap);
125
126     coreaudio_logstatus (status);
127 }
128
129 static void GCC_FMT_ATTR (3, 4) coreaudio_logerr2 (
130     OSStatus status,
131     const char *typ,
132     const char *fmt,
133     ...
134     )
135 {
136     va_list ap;
137
138     AUD_log (AUDIO_CAP, "Could not initialize %s\n", typ);
139
140     va_start (ap, fmt);
141     AUD_vlog (AUDIO_CAP, fmt, ap);
142     va_end (ap);
143
144     coreaudio_logstatus (status);
145 }
146
147 static inline UInt32 isPlaying (AudioDeviceID outputDeviceID)
148 {
149     OSStatus status;
150     UInt32 result = 0;
151     UInt32 propertySize = sizeof(outputDeviceID);
152     status = AudioDeviceGetProperty(
153         outputDeviceID, 0, 0,
154         kAudioDevicePropertyDeviceIsRunning, &propertySize, &result);
155     if (status != kAudioHardwareNoError) {
156         coreaudio_logerr(status,
157                          "Could not determine whether Device is playing\n");
158     }
159     return result;
160 }
161
162 static void coreaudio_atexit (void)
163 {
164     conf.isAtexit = 1;
165 }
166
167 static int coreaudio_lock (coreaudioVoiceOut *core, const char *fn_name)
168 {
169     int err;
170
171     err = pthread_mutex_lock (&core->mutex);
172     if (err) {
173         dolog ("Could not lock voice for %s\nReason: %s\n",
174                fn_name, strerror (err));
175         return -1;
176     }
177     return 0;
178 }
179
180 static int coreaudio_unlock (coreaudioVoiceOut *core, const char *fn_name)
181 {
182     int err;
183
184     err = pthread_mutex_unlock (&core->mutex);
185     if (err) {
186         dolog ("Could not unlock voice for %s\nReason: %s\n",
187                fn_name, strerror (err));
188         return -1;
189     }
190     return 0;
191 }
192
193 static int coreaudio_run_out (HWVoiceOut *hw, int live)
194 {
195     int decr;
196     coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
197
198     if (coreaudio_lock (core, "coreaudio_run_out")) {
199         return 0;
200     }
201
202     if (core->decr > live) {
203         ldebug ("core->decr %d live %d core->live %d\n",
204                 core->decr,
205                 live,
206                 core->live);
207     }
208
209     decr = audio_MIN (core->decr, live);
210     core->decr -= decr;
211
212     core->live = live - decr;
213     hw->rpos = core->rpos;
214
215     coreaudio_unlock (core, "coreaudio_run_out");
216     return decr;
217 }
218
219 /* callback to feed audiooutput buffer */
220 static OSStatus audioDeviceIOProc(
221     AudioDeviceID inDevice,
222     const AudioTimeStamp* inNow,
223     const AudioBufferList* inInputData,
224     const AudioTimeStamp* inInputTime,
225     AudioBufferList* outOutputData,
226     const AudioTimeStamp* inOutputTime,
227     void* hwptr)
228 {
229     UInt32 frame, frameCount;
230     float *out = outOutputData->mBuffers[0].mData;
231     HWVoiceOut *hw = hwptr;
232     coreaudioVoiceOut *core = (coreaudioVoiceOut *) hwptr;
233     int rpos, live;
234     struct st_sample *src;
235 #ifndef FLOAT_MIXENG
236 #ifdef RECIPROCAL
237     const float scale = 1.f / UINT_MAX;
238 #else
239     const float scale = UINT_MAX;
240 #endif
241 #endif
242
243     if (coreaudio_lock (core, "audioDeviceIOProc")) {
244         inInputTime = 0;
245         return 0;
246     }
247
248     frameCount = core->audioDevicePropertyBufferFrameSize;
249     live = core->live;
250
251     /* if there are not enough samples, set signal and return */
252     if (live < frameCount) {
253         inInputTime = 0;
254         coreaudio_unlock (core, "audioDeviceIOProc(empty)");
255         return 0;
256     }
257
258     rpos = core->rpos;
259     src = hw->mix_buf + rpos;
260
261     /* fill buffer */
262     for (frame = 0; frame < frameCount; frame++) {
263 #ifdef FLOAT_MIXENG
264         *out++ = src[frame].l; /* left channel */
265         *out++ = src[frame].r; /* right channel */
266 #else
267 #ifdef RECIPROCAL
268         *out++ = src[frame].l * scale; /* left channel */
269         *out++ = src[frame].r * scale; /* right channel */
270 #else
271         *out++ = src[frame].l / scale; /* left channel */
272         *out++ = src[frame].r / scale; /* right channel */
273 #endif
274 #endif
275     }
276
277     rpos = (rpos + frameCount) % hw->samples;
278     core->decr += frameCount;
279     core->rpos = rpos;
280
281     coreaudio_unlock (core, "audioDeviceIOProc");
282     return 0;
283 }
284
285 static int coreaudio_write (SWVoiceOut *sw, void *buf, int len)
286 {
287     return audio_pcm_sw_write (sw, buf, len);
288 }
289
290 static int coreaudio_init_out (HWVoiceOut *hw, struct audsettings *as)
291 {
292     OSStatus status;
293     coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
294     UInt32 propertySize;
295     int err;
296     const char *typ = "playback";
297     AudioValueRange frameRange;
298
299     /* create mutex */
300     err = pthread_mutex_init(&core->mutex, NULL);
301     if (err) {
302         dolog("Could not create mutex\nReason: %s\n", strerror (err));
303         return -1;
304     }
305
306     audio_pcm_init_info (&hw->info, as);
307
308     /* open default output device */
309     propertySize = sizeof(core->outputDeviceID);
310     status = AudioHardwareGetProperty(
311         kAudioHardwarePropertyDefaultOutputDevice,
312         &propertySize,
313         &core->outputDeviceID);
314     if (status != kAudioHardwareNoError) {
315         coreaudio_logerr2 (status, typ,
316                            "Could not get default output Device\n");
317         return -1;
318     }
319     if (core->outputDeviceID == kAudioDeviceUnknown) {
320         dolog ("Could not initialize %s - Unknown Audiodevice\n", typ);
321         return -1;
322     }
323
324     /* get minimum and maximum buffer frame sizes */
325     propertySize = sizeof(frameRange);
326     status = AudioDeviceGetProperty(
327         core->outputDeviceID,
328         0,
329         0,
330         kAudioDevicePropertyBufferFrameSizeRange,
331         &propertySize,
332         &frameRange);
333     if (status != kAudioHardwareNoError) {
334         coreaudio_logerr2 (status, typ,
335                            "Could not get device buffer frame range\n");
336         return -1;
337     }
338
339     if (frameRange.mMinimum > conf.buffer_frames) {
340         core->audioDevicePropertyBufferFrameSize = (UInt32) frameRange.mMinimum;
341         dolog ("warning: Upsizing Buffer Frames to %f\n", frameRange.mMinimum);
342     }
343     else if (frameRange.mMaximum < conf.buffer_frames) {
344         core->audioDevicePropertyBufferFrameSize = (UInt32) frameRange.mMaximum;
345         dolog ("warning: Downsizing Buffer Frames to %f\n", frameRange.mMaximum);
346     }
347     else {
348         core->audioDevicePropertyBufferFrameSize = conf.buffer_frames;
349     }
350
351     /* set Buffer Frame Size */
352     propertySize = sizeof(core->audioDevicePropertyBufferFrameSize);
353     status = AudioDeviceSetProperty(
354         core->outputDeviceID,
355         NULL,
356         0,
357         false,
358         kAudioDevicePropertyBufferFrameSize,
359         propertySize,
360         &core->audioDevicePropertyBufferFrameSize);
361     if (status != kAudioHardwareNoError) {
362         coreaudio_logerr2 (status, typ,
363                            "Could not set device buffer frame size %" PRIu32 "\n",
364                            (uint32_t)core->audioDevicePropertyBufferFrameSize);
365         return -1;
366     }
367
368     /* get Buffer Frame Size */
369     propertySize = sizeof(core->audioDevicePropertyBufferFrameSize);
370     status = AudioDeviceGetProperty(
371         core->outputDeviceID,
372         0,
373         false,
374         kAudioDevicePropertyBufferFrameSize,
375         &propertySize,
376         &core->audioDevicePropertyBufferFrameSize);
377     if (status != kAudioHardwareNoError) {
378         coreaudio_logerr2 (status, typ,
379                            "Could not get device buffer frame size\n");
380         return -1;
381     }
382     hw->samples = conf.nbuffers * core->audioDevicePropertyBufferFrameSize;
383
384     /* get StreamFormat */
385     propertySize = sizeof(core->outputStreamBasicDescription);
386     status = AudioDeviceGetProperty(
387         core->outputDeviceID,
388         0,
389         false,
390         kAudioDevicePropertyStreamFormat,
391         &propertySize,
392         &core->outputStreamBasicDescription);
393     if (status != kAudioHardwareNoError) {
394         coreaudio_logerr2 (status, typ,
395                            "Could not get Device Stream properties\n");
396         core->outputDeviceID = kAudioDeviceUnknown;
397         return -1;
398     }
399
400     /* set Samplerate */
401     core->outputStreamBasicDescription.mSampleRate = (Float64) as->freq;
402     propertySize = sizeof(core->outputStreamBasicDescription);
403     status = AudioDeviceSetProperty(
404         core->outputDeviceID,
405         0,
406         0,
407         0,
408         kAudioDevicePropertyStreamFormat,
409         propertySize,
410         &core->outputStreamBasicDescription);
411     if (status != kAudioHardwareNoError) {
412         coreaudio_logerr2 (status, typ, "Could not set samplerate %d\n",
413                            as->freq);
414         core->outputDeviceID = kAudioDeviceUnknown;
415         return -1;
416     }
417
418     /* set Callback */
419     status = AudioDeviceAddIOProc(core->outputDeviceID, audioDeviceIOProc, hw);
420     if (status != kAudioHardwareNoError) {
421         coreaudio_logerr2 (status, typ, "Could not set IOProc\n");
422         core->outputDeviceID = kAudioDeviceUnknown;
423         return -1;
424     }
425
426     /* start Playback */
427     if (!isPlaying(core->outputDeviceID)) {
428         status = AudioDeviceStart(core->outputDeviceID, audioDeviceIOProc);
429         if (status != kAudioHardwareNoError) {
430             coreaudio_logerr2 (status, typ, "Could not start playback\n");
431             AudioDeviceRemoveIOProc(core->outputDeviceID, audioDeviceIOProc);
432             core->outputDeviceID = kAudioDeviceUnknown;
433             return -1;
434         }
435     }
436
437     return 0;
438 }
439
440 static void coreaudio_fini_out (HWVoiceOut *hw)
441 {
442     OSStatus status;
443     int err;
444     coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
445
446     if (!conf.isAtexit) {
447         /* stop playback */
448         if (isPlaying(core->outputDeviceID)) {
449             status = AudioDeviceStop(core->outputDeviceID, audioDeviceIOProc);
450             if (status != kAudioHardwareNoError) {
451                 coreaudio_logerr (status, "Could not stop playback\n");
452             }
453         }
454
455         /* remove callback */
456         status = AudioDeviceRemoveIOProc(core->outputDeviceID,
457                                          audioDeviceIOProc);
458         if (status != kAudioHardwareNoError) {
459             coreaudio_logerr (status, "Could not remove IOProc\n");
460         }
461     }
462     core->outputDeviceID = kAudioDeviceUnknown;
463
464     /* destroy mutex */
465     err = pthread_mutex_destroy(&core->mutex);
466     if (err) {
467         dolog("Could not destroy mutex\nReason: %s\n", strerror (err));
468     }
469 }
470
471 static int coreaudio_ctl_out (HWVoiceOut *hw, int cmd, ...)
472 {
473     OSStatus status;
474     coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
475
476     switch (cmd) {
477     case VOICE_ENABLE:
478         /* start playback */
479         if (!isPlaying(core->outputDeviceID)) {
480             status = AudioDeviceStart(core->outputDeviceID, audioDeviceIOProc);
481             if (status != kAudioHardwareNoError) {
482                 coreaudio_logerr (status, "Could not resume playback\n");
483             }
484         }
485         break;
486
487     case VOICE_DISABLE:
488         /* stop playback */
489         if (!conf.isAtexit) {
490             if (isPlaying(core->outputDeviceID)) {
491                 status = AudioDeviceStop(core->outputDeviceID, audioDeviceIOProc);
492                 if (status != kAudioHardwareNoError) {
493                     coreaudio_logerr (status, "Could not pause playback\n");
494                 }
495             }
496         }
497         break;
498     }
499     return 0;
500 }
501
502 static void *coreaudio_audio_init (void)
503 {
504     atexit(coreaudio_atexit);
505     return &coreaudio_audio_init;
506 }
507
508 static void coreaudio_audio_fini (void *opaque)
509 {
510     (void) opaque;
511 }
512
513 static struct audio_option coreaudio_options[] = {
514     {
515         .name  = "BUFFER_SIZE",
516         .tag   = AUD_OPT_INT,
517         .valp  = &conf.buffer_frames,
518         .descr = "Size of the buffer in frames"
519     },
520     {
521         .name  = "BUFFER_COUNT",
522         .tag   = AUD_OPT_INT,
523         .valp  = &conf.nbuffers,
524         .descr = "Number of buffers"
525     },
526     { /* End of list */ }
527 };
528
529 static struct audio_pcm_ops coreaudio_pcm_ops = {
530     .init_out = coreaudio_init_out,
531     .fini_out = coreaudio_fini_out,
532     .run_out  = coreaudio_run_out,
533     .write    = coreaudio_write,
534     .ctl_out  = coreaudio_ctl_out
535 };
536
537 struct audio_driver coreaudio_audio_driver = {
538     .name           = "coreaudio",
539     .descr          = "CoreAudio http://developer.apple.com/audio/coreaudio.html",
540     .options        = coreaudio_options,
541     .init           = coreaudio_audio_init,
542     .fini           = coreaudio_audio_fini,
543     .pcm_ops        = &coreaudio_pcm_ops,
544     .can_be_default = 1,
545     .max_voices_out = 1,
546     .max_voices_in  = 0,
547     .voice_size_out = sizeof (coreaudioVoiceOut),
548     .voice_size_in  = 0
549 };
This page took 0.05045 seconds and 4 git commands to generate.