qemu/audio/coreaudio.c
<<
>>
Prefs
   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
  35struct {
  36    int buffer_frames;
  37    int nbuffers;
  38    int isAtexit;
  39} conf = {
  40    .buffer_frames = 512,
  41    .nbuffers = 4,
  42    .isAtexit = 0
  43};
  44
  45typedef 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
  57static 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
 114static 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
 129static 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
 147static 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
 162static void coreaudio_atexit (void)
 163{
 164    conf.isAtexit = 1;
 165}
 166
 167static 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
 180static 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
 193static 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 */
 220static 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
 285static int coreaudio_write (SWVoiceOut *sw, void *buf, int len)
 286{
 287    return audio_pcm_sw_write (sw, buf, len);
 288}
 289
 290static 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
 440static 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
 471static 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
 502static void *coreaudio_audio_init (void)
 503{
 504    atexit(coreaudio_atexit);
 505    return &coreaudio_audio_init;
 506}
 507
 508static void coreaudio_audio_fini (void *opaque)
 509{
 510    (void) opaque;
 511}
 512
 513static 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
 529static 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
 537struct 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};
 550