(linenum→info "unix/slp.c:2238")

qemu/0.9.1/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:     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 %ld\n", 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)
  194: {
  195:     int live, decr;
  196:     coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
  197: 
  198:     if (coreaudio_lock (core, "coreaudio_run_out")) {
  199:         return 0;
  200:     }
  201: 
  202:     live = audio_pcm_hw_get_live_out (hw);
  203: 
  204:     if (core->decr > live) {
  205:         ldebug ("core->decr %d live %d core->live %d\n",
  206:                 core->decr,
  207:                 live,
  208:                 core->live);
  209:     }
  210: 
  211:     decr = audio_MIN (core->decr, live);
  212:     core->decr -= decr;
  213: 
  214:     core->live = live - decr;
  215:     hw->rpos = core->rpos;
  216: 
  217:     coreaudio_unlock (core, "coreaudio_run_out");
  218:     return decr;
  219: }
  220: 
  221: /* callback to feed audiooutput buffer */
  222: static OSStatus audioDeviceIOProc(
  223:     AudioDeviceID inDevice,
  224:     const AudioTimeStamp* inNow,
  225:     const AudioBufferList* inInputData,
  226:     const AudioTimeStamp* inInputTime,
  227:     AudioBufferList* outOutputData,
  228:     const AudioTimeStamp* inOutputTime,
  229:     void* hwptr)
  230: {
  231:     UInt32 frame, frameCount;
  232:     float *out = outOutputData->mBuffers[0].mData;
  233:     HWVoiceOut *hw = hwptr;
  234:     coreaudioVoiceOut *core = (coreaudioVoiceOut *) hwptr;
  235:     int rpos, live;
  236:     st_sample_t *src;
  237: #ifndef FLOAT_MIXENG
  238: #ifdef RECIPROCAL
  239:     const float scale = 1.f / UINT_MAX;
  240: #else
  241:     const float scale = UINT_MAX;
  242: #endif
  243: #endif
  244: 
  245:     if (coreaudio_lock (core, "audioDeviceIOProc")) {
  246:         inInputTime = 0;
  247:         return 0;
  248:     }
  249: 
  250:     frameCount = core->audioDevicePropertyBufferFrameSize;
  251:     live = core->live;
  252: 
  253:     /* if there are not enough samples, set signal and return */
  254:     if (live < frameCount) {
  255:         inInputTime = 0;
  256:         coreaudio_unlock (core, "audioDeviceIOProc(empty)");
  257:         return 0;
  258:     }
  259: 
  260:     rpos = core->rpos;
  261:     src = hw->mix_buf + rpos;
  262: 
  263:     /* fill buffer */
  264:     for (frame = 0; frame < frameCount; frame++) {
  265: #ifdef FLOAT_MIXENG
  266:         *out++ = src[frame].l; /* left channel */
  267:         *out++ = src[frame].r; /* right channel */
  268: #else
  269: #ifdef RECIPROCAL
  270:         *out++ = src[frame].l * scale; /* left channel */
  271:         *out++ = src[frame].r * scale; /* right channel */
  272: #else
  273:         *out++ = src[frame].l / scale; /* left channel */
  274:         *out++ = src[frame].r / scale; /* right channel */
  275: #endif
  276: #endif
  277:     }
  278: 
  279:     rpos = (rpos + frameCount) % hw->samples;
  280:     core->decr += frameCount;
  281:     core->rpos = rpos;
  282: 
  283:     coreaudio_unlock (core, "audioDeviceIOProc");
  284:     return 0;
  285: }
  286: 
  287: static int coreaudio_write (SWVoiceOut *sw, void *buf, int len)
  288: {
  289:     return audio_pcm_sw_write (sw, buf, len);
  290: }
  291: 
  292: static int coreaudio_init_out (HWVoiceOut *hw, audsettings_t *as)
  293: {
  294:     OSStatus status;
  295:     coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
  296:     UInt32 propertySize;
  297:     int err;
  298:     const char *typ = "playback";
  299:     AudioValueRange frameRange;
  300: 
  301:     /* create mutex */
  302:     err = pthread_mutex_init(&core->mutex, NULL);
  303:     if (err) {
  304:         dolog("Could not create mutex\nReason: %s\n", strerror (err));
  305:         return -1;
  306:     }
  307: 
  308:     audio_pcm_init_info (&hw->info, as);
  309: 
  310:     /* open default output device */
  311:     propertySize = sizeof(core->outputDeviceID);
  312:     status = AudioHardwareGetProperty(
  313:         kAudioHardwarePropertyDefaultOutputDevice,
  314:         &propertySize,
  315:         &core->outputDeviceID);
  316:     if (status != kAudioHardwareNoError) {
  317:         coreaudio_logerr2 (status, typ,
  318:                            "Could not get default output Device\n");
  319:         return -1;
  320:     }
  321:     if (core->outputDeviceID == kAudioDeviceUnknown) {
  322:         dolog ("Could not initialize %s - Unknown Audiodevice\n", typ);
  323:         return -1;
  324:     }
  325: 
  326:     /* get minimum and maximum buffer frame sizes */
  327:     propertySize = sizeof(frameRange);
  328:     status = AudioDeviceGetProperty(
  329:         core->outputDeviceID,
  330:         0,
  331:         0,
  332:         kAudioDevicePropertyBufferFrameSizeRange,
  333:         &propertySize,
  334:         &frameRange);
  335:     if (status != kAudioHardwareNoError) {
  336:         coreaudio_logerr2 (status, typ,
  337:                            "Could not get device buffer frame range\n");
  338:         return -1;
  339:     }
  340: 
  341:     if (frameRange.mMinimum > conf.buffer_frames) {
  342:         core->audioDevicePropertyBufferFrameSize = (UInt32) frameRange.mMinimum;
  343:         dolog ("warning: Upsizing Buffer Frames to %f\n", frameRange.mMinimum);
  344:     }
  345:     else if (frameRange.mMaximum < conf.buffer_frames) {
  346:         core->audioDevicePropertyBufferFrameSize = (UInt32) frameRange.mMaximum;
  347:         dolog ("warning: Downsizing Buffer Frames to %f\n", frameRange.mMaximum);
  348:     }
  349:     else {
  350:         core->audioDevicePropertyBufferFrameSize = conf.buffer_frames;
  351:     }
  352: 
  353:     /* set Buffer Frame Size */
  354:     propertySize = sizeof(core->audioDevicePropertyBufferFrameSize);
  355:     status = AudioDeviceSetProperty(
  356:         core->outputDeviceID,
  357:         NULL,
  358:         0,
  359:         false,
  360:         kAudioDevicePropertyBufferFrameSize,
  361:         propertySize,
  362:         &core->audioDevicePropertyBufferFrameSize);
  363:     if (status != kAudioHardwareNoError) {
  364:         coreaudio_logerr2 (status, typ,
  365:                            "Could not set device buffer frame size %ld\n",
  366:                            core->audioDevicePropertyBufferFrameSize);
  367:         return -1;
  368:     }
  369: 
  370:     /* get Buffer Frame Size */
  371:     propertySize = sizeof(core->audioDevicePropertyBufferFrameSize);
  372:     status = AudioDeviceGetProperty(
  373:         core->outputDeviceID,
  374:         0,
  375:         false,
  376:         kAudioDevicePropertyBufferFrameSize,
  377:         &propertySize,
  378:         &core->audioDevicePropertyBufferFrameSize);
  379:     if (status != kAudioHardwareNoError) {
  380:         coreaudio_logerr2 (status, typ,
  381:                            "Could not get device buffer frame size\n");
  382:         return -1;
  383:     }
  384:     hw->samples = conf.nbuffers * core->audioDevicePropertyBufferFrameSize;
  385: 
  386:     /* get StreamFormat */
  387:     propertySize = sizeof(core->outputStreamBasicDescription);
  388:     status = AudioDeviceGetProperty(
  389:         core->outputDeviceID,
  390:         0,
  391:         false,
  392:         kAudioDevicePropertyStreamFormat,
  393:         &propertySize,
  394:         &core->outputStreamBasicDescription);
  395:     if (status != kAudioHardwareNoError) {
  396:         coreaudio_logerr2 (status, typ,
  397:                            "Could not get Device Stream properties\n");
  398:         core->outputDeviceID = kAudioDeviceUnknown;
  399:         return -1;
  400:     }
  401: 
  402:     /* set Samplerate */
  403:     core->outputStreamBasicDescription.mSampleRate = (Float64) as->freq;
  404:     propertySize = sizeof(core->outputStreamBasicDescription);
  405:     status = AudioDeviceSetProperty(
  406:         core->outputDeviceID,
  407:         0,
  408:         0,
  409:         0,
  410:         kAudioDevicePropertyStreamFormat,
  411:         propertySize,
  412:         &core->outputStreamBasicDescription);
  413:     if (status != kAudioHardwareNoError) {
  414:         coreaudio_logerr2 (status, typ, "Could not set samplerate %d\n",
  415:                            as->freq);
  416:         core->outputDeviceID = kAudioDeviceUnknown;
  417:         return -1;
  418:     }
  419: 
  420:     /* set Callback */
  421:     status = AudioDeviceAddIOProc(core->outputDeviceID, audioDeviceIOProc, hw);
  422:     if (status != kAudioHardwareNoError) {
  423:         coreaudio_logerr2 (status, typ, "Could not set IOProc\n");
  424:         core->outputDeviceID = kAudioDeviceUnknown;
  425:         return -1;
  426:     }
  427: 
  428:     /* start Playback */
  429:     if (!isPlaying(core->outputDeviceID)) {
  430:         status = AudioDeviceStart(core->outputDeviceID, audioDeviceIOProc);
  431:         if (status != kAudioHardwareNoError) {
  432:             coreaudio_logerr2 (status, typ, "Could not start playback\n");
  433:             AudioDeviceRemoveIOProc(core->outputDeviceID, audioDeviceIOProc);
  434:             core->outputDeviceID = kAudioDeviceUnknown;
  435:             return -1;
  436:         }
  437:     }
  438: 
  439:     return 0;
  440: }
  441: 
  442: static void coreaudio_fini_out (HWVoiceOut *hw)
  443: {
  444:     OSStatus status;
  445:     int err;
  446:     coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
  447: 
  448:     if (!conf.isAtexit) {
  449:         /* stop playback */
  450:         if (isPlaying(core->outputDeviceID)) {
  451:             status = AudioDeviceStop(core->outputDeviceID, audioDeviceIOProc);
  452:             if (status != kAudioHardwareNoError) {
  453:                 coreaudio_logerr (status, "Could not stop playback\n");
  454:             }
  455:         }
  456: 
  457:         /* remove callback */
  458:         status = AudioDeviceRemoveIOProc(core->outputDeviceID,
  459:                                          audioDeviceIOProc);
  460:         if (status != kAudioHardwareNoError) {
  461:             coreaudio_logerr (status, "Could not remove IOProc\n");
  462:         }
  463:     }
  464:     core->outputDeviceID = kAudioDeviceUnknown;
  465: 
  466:     /* destroy mutex */
  467:     err = pthread_mutex_destroy(&core->mutex);
  468:     if (err) {
  469:         dolog("Could not destroy mutex\nReason: %s\n", strerror (err));
  470:     }
  471: }
  472: 
  473: static int coreaudio_ctl_out (HWVoiceOut *hw, int cmd, ...)
  474: {
  475:     OSStatus status;
  476:     coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
  477: 
  478:     switch (cmd) {
  479:     case VOICE_ENABLE:
  480:         /* start playback */
  481:         if (!isPlaying(core->outputDeviceID)) {
  482:             status = AudioDeviceStart(core->outputDeviceID, audioDeviceIOProc);
  483:             if (status != kAudioHardwareNoError) {
  484:                 coreaudio_logerr (status, "Could not resume playback\n");
  485:             }
  486:         }
  487:         break;
  488: 
  489:     case VOICE_DISABLE:
  490:         /* stop playback */
  491:         if (!conf.isAtexit) {
  492:             if (isPlaying(core->outputDeviceID)) {
  493:                 status = AudioDeviceStop(core->outputDeviceID, audioDeviceIOProc);
  494:                 if (status != kAudioHardwareNoError) {
  495:                     coreaudio_logerr (status, "Could not pause playback\n");
  496:                 }
  497:             }
  498:         }
  499:         break;
  500:     }
  501:     return 0;
  502: }
  503: 
  504: static void *coreaudio_audio_init (void)
  505: {
  506:     atexit(coreaudio_atexit);
  507:     return &coreaudio_audio_init;
  508: }
  509: 
  510: static void coreaudio_audio_fini (void *opaque)
  511: {
  512:     (void) opaque;
  513: }
  514: 
  515: static struct audio_option coreaudio_options[] = {
  516:     {"BUFFER_SIZE", AUD_OPT_INT, &conf.buffer_frames,
  517:      "Size of the buffer in frames", NULL, 0},
  518:     {"BUFFER_COUNT", AUD_OPT_INT, &conf.nbuffers,
  519:      "Number of buffers", NULL, 0},
  520:     {NULL, 0, NULL, NULL, NULL, 0}
  521: };
  522: 
  523: static struct audio_pcm_ops coreaudio_pcm_ops = {
  524:     coreaudio_init_out,
  525:     coreaudio_fini_out,
  526:     coreaudio_run_out,
  527:     coreaudio_write,
  528:     coreaudio_ctl_out,
  529: 
  530:     NULL,
  531:     NULL,
  532:     NULL,
  533:     NULL,
  534:     NULL
  535: };
  536: 
  537: struct audio_driver coreaudio_audio_driver = {
  538:     INIT_FIELD (name           = ) "coreaudio",
  539:     INIT_FIELD (descr          = )
  540:     "CoreAudio http://developer.apple.com/audio/coreaudio.html",
  541:     INIT_FIELD (options        = ) coreaudio_options,
  542:     INIT_FIELD (init           = ) coreaudio_audio_init,
  543:     INIT_FIELD (fini           = ) coreaudio_audio_fini,
  544:     INIT_FIELD (pcm_ops        = ) &coreaudio_pcm_ops,
  545:     INIT_FIELD (can_be_default = ) 1,
  546:     INIT_FIELD (max_voices_out = ) 1,
  547:     INIT_FIELD (max_voices_in  = ) 0,
  548:     INIT_FIELD (voice_size_out = ) sizeof (coreaudioVoiceOut),
  549:     INIT_FIELD (voice_size_in  = ) 0
  550: };
1
Syntax (Markdown)