symbian-qemu-0.9.1-12/qemu-symbian-svp/audio/coreaudio.c
changeset 1 2fb8b9db1c86
equal deleted inserted replaced
0:ffa851df0825 1:2fb8b9db1c86
       
     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     struct st_sample *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, struct audsettings *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 };