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