]> git.proxmox.com Git - qemu.git/blobdiff - audio/coreaudio.c
Wrap recv to avoid warnings
[qemu.git] / audio / coreaudio.c
index eee12386ce2b30098469d39cceb78bf24710a4a5..5964c62eafc6d8b7a5325d467faeb66448eb178d 100644 (file)
 #include <string.h>             /* strerror */
 #include <pthread.h>            /* pthread_X */
 
-#include "vl.h"
+#include "qemu-common.h"
+#include "audio.h"
 
 #define AUDIO_CAP "coreaudio"
 #include "audio_int.h"
 
-#define DEVICE_BUFFER_FRAMES  (512)
-
 struct {
     int buffer_frames;
+    int nbuffers;
+    int isAtexit;
 } conf = {
-    .buffer_frames = 512
+    .buffer_frames = 512,
+    .nbuffers = 4,
+    .isAtexit = 0
 };
 
 typedef struct coreaudioVoiceOut {
     HWVoiceOut hw;
     pthread_mutex_t mutex;
+    int isAtexit;
     AudioDeviceID outputDeviceID;
-    UInt32 audioDevicePropertyBufferSize;
+    UInt32 audioDevicePropertyBufferFrameSize;
     AudioStreamBasicDescription outputStreamBasicDescription;
-    int isPlaying;
     int live;
     int decr;
     int rpos;
@@ -53,7 +56,7 @@ typedef struct coreaudioVoiceOut {
 
 static void coreaudio_logstatus (OSStatus status)
 {
-    char *str = "BUG";
+    const char *str = "BUG";
 
     switch(status) {
     case kAudioHardwareNoError:
@@ -101,7 +104,7 @@ static void coreaudio_logstatus (OSStatus status)
         break;
 
     default:
-        AUD_log (AUDIO_CAP, "Reason: status code %ld\n", status);
+        AUD_log (AUDIO_CAP, "Reason: status code %" PRId32 "\n", (int32_t)status);
         return;
     }
 
@@ -132,7 +135,7 @@ static void GCC_FMT_ATTR (3, 4) coreaudio_logerr2 (
 {
     va_list ap;
 
-    AUD_log (AUDIO_CAP, "Can not initialize %s\n", typ);
+    AUD_log (AUDIO_CAP, "Could not initialize %s\n", typ);
 
     va_start (ap, fmt);
     AUD_vlog (AUDIO_CAP, fmt, ap);
@@ -141,13 +144,33 @@ static void GCC_FMT_ATTR (3, 4) coreaudio_logerr2 (
     coreaudio_logstatus (status);
 }
 
+static inline UInt32 isPlaying (AudioDeviceID outputDeviceID)
+{
+    OSStatus status;
+    UInt32 result = 0;
+    UInt32 propertySize = sizeof(outputDeviceID);
+    status = AudioDeviceGetProperty(
+        outputDeviceID, 0, 0,
+        kAudioDevicePropertyDeviceIsRunning, &propertySize, &result);
+    if (status != kAudioHardwareNoError) {
+        coreaudio_logerr(status,
+                         "Could not determine whether Device is playing\n");
+    }
+    return result;
+}
+
+static void coreaudio_atexit (void)
+{
+    conf.isAtexit = 1;
+}
+
 static int coreaudio_lock (coreaudioVoiceOut *core, const char *fn_name)
 {
     int err;
 
     err = pthread_mutex_lock (&core->mutex);
     if (err) {
-        dolog ("Can not lock voice for %s\nReason: %s\n",
+        dolog ("Could not lock voice for %s\nReason: %s\n",
                fn_name, strerror (err));
         return -1;
     }
@@ -160,24 +183,22 @@ static int coreaudio_unlock (coreaudioVoiceOut *core, const char *fn_name)
 
     err = pthread_mutex_unlock (&core->mutex);
     if (err) {
-        dolog ("Can not unlock voice for %s\nReason: %s\n",
+        dolog ("Could not unlock voice for %s\nReason: %s\n",
                fn_name, strerror (err));
         return -1;
     }
     return 0;
 }
 
-static int coreaudio_run_out (HWVoiceOut *hw)
+static int coreaudio_run_out (HWVoiceOut *hw, int live)
 {
-    int live, decr;
+    int decr;
     coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
 
     if (coreaudio_lock (core, "coreaudio_run_out")) {
         return 0;
     }
 
-    live = audio_pcm_hw_get_live_out (hw);
-
     if (core->decr > live) {
         ldebug ("core->decr %d live %d core->live %d\n",
                 core->decr,
@@ -205,12 +226,12 @@ static OSStatus audioDeviceIOProc(
     const AudioTimeStamp* inOutputTime,
     void* hwptr)
 {
-    unsigned int frame, frameCount;
+    UInt32 frame, frameCount;
     float *out = outOutputData->mBuffers[0].mData;
     HWVoiceOut *hw = hwptr;
     coreaudioVoiceOut *core = (coreaudioVoiceOut *) hwptr;
     int rpos, live;
-    st_sample_t *src;
+    struct st_sample *src;
 #ifndef FLOAT_MIXENG
 #ifdef RECIPROCAL
     const float scale = 1.f / UINT_MAX;
@@ -224,7 +245,7 @@ static OSStatus audioDeviceIOProc(
         return 0;
     }
 
-    frameCount = conf.buffer_frames;
+    frameCount = core->audioDevicePropertyBufferFrameSize;
     live = core->live;
 
     /* if there are not enough samples, set signal and return */
@@ -253,10 +274,8 @@ static OSStatus audioDeviceIOProc(
 #endif
     }
 
-    /* cleanup */
-    mixeng_clear (src, frameCount);
     rpos = (rpos + frameCount) % hw->samples;
-    core->decr = frameCount;
+    core->decr += frameCount;
     core->rpos = rpos;
 
     coreaudio_unlock (core, "audioDeviceIOProc");
@@ -268,39 +287,23 @@ static int coreaudio_write (SWVoiceOut *sw, void *buf, int len)
     return audio_pcm_sw_write (sw, buf, len);
 }
 
-static int coreaudio_init_out (HWVoiceOut *hw, int freq,
-                               int nchannels, audfmt_e fmt)
+static int coreaudio_init_out (HWVoiceOut *hw, struct audsettings *as)
 {
     OSStatus status;
     coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
     UInt32 propertySize;
     int err;
-    int bits = 8;
-    int endianess = 0;
-    const char *typ = "DAC";
+    const char *typ = "playback";
+    AudioValueRange frameRange;
 
     /* create mutex */
     err = pthread_mutex_init(&core->mutex, NULL);
     if (err) {
-        dolog("Can not create mutex\nReason: %s\n", strerror (err));
+        dolog("Could not create mutex\nReason: %s\n", strerror (err));
         return -1;
     }
 
-    if (fmt == AUD_FMT_S16 || fmt == AUD_FMT_U16) {
-        bits = 16;
-        endianess = 1;
-    }
-
-    audio_pcm_init_info (
-        &hw->info,
-        freq,
-        nchannels,
-        fmt,
-        /* Following is irrelevant actually since we do not use
-           mixengs clipping routines */
-        audio_need_to_swap_endian (endianess)
-        );
-    hw->bufsize = 4 * conf.buffer_frames * nchannels * bits;
+    audio_pcm_init_info (&hw->info, as);
 
     /* open default output device */
     propertySize = sizeof(core->outputDeviceID);
@@ -310,46 +313,73 @@ static int coreaudio_init_out (HWVoiceOut *hw, int freq,
         &core->outputDeviceID);
     if (status != kAudioHardwareNoError) {
         coreaudio_logerr2 (status, typ,
-                           "Can not get default output Device\n");
+                           "Could not get default output Device\n");
         return -1;
     }
     if (core->outputDeviceID == kAudioDeviceUnknown) {
-        dolog ("Can not initialize %s - Unknown Audiodevice\n", typ);
+        dolog ("Could not initialize %s - Unknown Audiodevice\n", typ);
         return -1;
     }
 
-    /* set Buffersize to conf.buffer_frames frames */
-    propertySize = sizeof(core->audioDevicePropertyBufferSize);
-    core->audioDevicePropertyBufferSize =
-        conf.buffer_frames * sizeof(float) * 2;
+    /* get minimum and maximum buffer frame sizes */
+    propertySize = sizeof(frameRange);
+    status = AudioDeviceGetProperty(
+        core->outputDeviceID,
+        0,
+        0,
+        kAudioDevicePropertyBufferFrameSizeRange,
+        &propertySize,
+        &frameRange);
+    if (status != kAudioHardwareNoError) {
+        coreaudio_logerr2 (status, typ,
+                           "Could not get device buffer frame range\n");
+        return -1;
+    }
+
+    if (frameRange.mMinimum > conf.buffer_frames) {
+        core->audioDevicePropertyBufferFrameSize = (UInt32) frameRange.mMinimum;
+        dolog ("warning: Upsizing Buffer Frames to %f\n", frameRange.mMinimum);
+    }
+    else if (frameRange.mMaximum < conf.buffer_frames) {
+        core->audioDevicePropertyBufferFrameSize = (UInt32) frameRange.mMaximum;
+        dolog ("warning: Downsizing Buffer Frames to %f\n", frameRange.mMaximum);
+    }
+    else {
+        core->audioDevicePropertyBufferFrameSize = conf.buffer_frames;
+    }
+
+    /* set Buffer Frame Size */
+    propertySize = sizeof(core->audioDevicePropertyBufferFrameSize);
     status = AudioDeviceSetProperty(
         core->outputDeviceID,
         NULL,
         0,
         false,
-        kAudioDevicePropertyBufferSize,
+        kAudioDevicePropertyBufferFrameSize,
         propertySize,
-        &core->audioDevicePropertyBufferSize);
+        &core->audioDevicePropertyBufferFrameSize);
     if (status != kAudioHardwareNoError) {
         coreaudio_logerr2 (status, typ,
-                           "Can not set device buffer size %d\n",
-                           kAudioDevicePropertyBufferSize);
+                           "Could not set device buffer frame size %" PRIu32 "\n",
+                           (uint32_t)core->audioDevicePropertyBufferFrameSize);
         return -1;
     }
 
-    /* get Buffersize */
-    propertySize = sizeof(core->audioDevicePropertyBufferSize);
+    /* get Buffer Frame Size */
+    propertySize = sizeof(core->audioDevicePropertyBufferFrameSize);
     status = AudioDeviceGetProperty(
         core->outputDeviceID,
         0,
         false,
-        kAudioDevicePropertyBufferSize,
+        kAudioDevicePropertyBufferFrameSize,
         &propertySize,
-        &core->audioDevicePropertyBufferSize);
+        &core->audioDevicePropertyBufferFrameSize);
     if (status != kAudioHardwareNoError) {
-        coreaudio_logerr2 (status, typ, "Can not get device buffer size\n");
+        coreaudio_logerr2 (status, typ,
+                           "Could not get device buffer frame size\n");
         return -1;
     }
+    hw->samples = conf.nbuffers * core->audioDevicePropertyBufferFrameSize;
 
     /* get StreamFormat */
     propertySize = sizeof(core->outputStreamBasicDescription);
@@ -362,13 +392,13 @@ static int coreaudio_init_out (HWVoiceOut *hw, int freq,
         &core->outputStreamBasicDescription);
     if (status != kAudioHardwareNoError) {
         coreaudio_logerr2 (status, typ,
-                           "Can not get Device Stream properties\n");
+                           "Could not get Device Stream properties\n");
         core->outputDeviceID = kAudioDeviceUnknown;
         return -1;
     }
 
     /* set Samplerate */
-    core->outputStreamBasicDescription.mSampleRate = (Float64)freq;
+    core->outputStreamBasicDescription.mSampleRate = (Float64) as->freq;
     propertySize = sizeof(core->outputStreamBasicDescription);
     status = AudioDeviceSetProperty(
         core->outputDeviceID,
@@ -379,7 +409,8 @@ static int coreaudio_init_out (HWVoiceOut *hw, int freq,
         propertySize,
         &core->outputStreamBasicDescription);
     if (status != kAudioHardwareNoError) {
-        coreaudio_logerr2 (status, typ, "Can not set samplerate %d\n", freq);
+        coreaudio_logerr2 (status, typ, "Could not set samplerate %d\n",
+                           as->freq);
         core->outputDeviceID = kAudioDeviceUnknown;
         return -1;
     }
@@ -387,21 +418,20 @@ static int coreaudio_init_out (HWVoiceOut *hw, int freq,
     /* set Callback */
     status = AudioDeviceAddIOProc(core->outputDeviceID, audioDeviceIOProc, hw);
     if (status != kAudioHardwareNoError) {
-        coreaudio_logerr2 (status, typ, "Can not set IOProc\n");
+        coreaudio_logerr2 (status, typ, "Could not set IOProc\n");
         core->outputDeviceID = kAudioDeviceUnknown;
         return -1;
     }
 
     /* start Playback */
-    if (!core->isPlaying) {
+    if (!isPlaying(core->outputDeviceID)) {
         status = AudioDeviceStart(core->outputDeviceID, audioDeviceIOProc);
         if (status != kAudioHardwareNoError) {
-            coreaudio_logerr2 (status, typ, "Can not start playback\n");
+            coreaudio_logerr2 (status, typ, "Could not start playback\n");
             AudioDeviceRemoveIOProc(core->outputDeviceID, audioDeviceIOProc);
             core->outputDeviceID = kAudioDeviceUnknown;
             return -1;
         }
-        core->isPlaying = 1;
     }
 
     return 0;
@@ -413,26 +443,28 @@ static void coreaudio_fini_out (HWVoiceOut *hw)
     int err;
     coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
 
-    /* stop playback */
-    if (core->isPlaying) {
-        status = AudioDeviceStop(core->outputDeviceID, audioDeviceIOProc);
-        if (status != kAudioHardwareNoError) {
-            coreaudio_logerr (status, "Can not stop playback\n");
+    if (!conf.isAtexit) {
+        /* stop playback */
+        if (isPlaying(core->outputDeviceID)) {
+            status = AudioDeviceStop(core->outputDeviceID, audioDeviceIOProc);
+            if (status != kAudioHardwareNoError) {
+                coreaudio_logerr (status, "Could not stop playback\n");
+            }
         }
-        core->isPlaying = 0;
-    }
 
-    /* remove callback */
-    status = AudioDeviceRemoveIOProc(core->outputDeviceID, audioDeviceIOProc);
-    if (status != kAudioHardwareNoError) {
-        coreaudio_logerr (status, "Can not remove IOProc\n");
+        /* remove callback */
+        status = AudioDeviceRemoveIOProc(core->outputDeviceID,
+                                         audioDeviceIOProc);
+        if (status != kAudioHardwareNoError) {
+            coreaudio_logerr (status, "Could not remove IOProc\n");
+        }
     }
     core->outputDeviceID = kAudioDeviceUnknown;
 
     /* destroy mutex */
     err = pthread_mutex_destroy(&core->mutex);
     if (err) {
-        dolog("Can not destroy mutex\nReason: %s\n", strerror (err));
+        dolog("Could not destroy mutex\nReason: %s\n", strerror (err));
     }
 }
 
@@ -444,23 +476,23 @@ static int coreaudio_ctl_out (HWVoiceOut *hw, int cmd, ...)
     switch (cmd) {
     case VOICE_ENABLE:
         /* start playback */
-        if (!core->isPlaying) {
+        if (!isPlaying(core->outputDeviceID)) {
             status = AudioDeviceStart(core->outputDeviceID, audioDeviceIOProc);
             if (status != kAudioHardwareNoError) {
-                coreaudio_logerr (status, "Can not unpause playback\n");
+                coreaudio_logerr (status, "Could not resume playback\n");
             }
-            core->isPlaying = 1;
         }
         break;
 
     case VOICE_DISABLE:
         /* stop playback */
-        if (core->isPlaying) {
-            status = AudioDeviceStop(core->outputDeviceID, audioDeviceIOProc);
-            if (status != kAudioHardwareNoError) {
-                coreaudio_logerr (status, "Can not pause playback\n");
+        if (!conf.isAtexit) {
+            if (isPlaying(core->outputDeviceID)) {
+                status = AudioDeviceStop(core->outputDeviceID, audioDeviceIOProc);
+                if (status != kAudioHardwareNoError) {
+                    coreaudio_logerr (status, "Could not pause playback\n");
+                }
             }
-            core->isPlaying = 0;
         }
         break;
     }
@@ -469,6 +501,7 @@ static int coreaudio_ctl_out (HWVoiceOut *hw, int cmd, ...)
 
 static void *coreaudio_audio_init (void)
 {
+    atexit(coreaudio_atexit);
     return &coreaudio_audio_init;
 }
 
@@ -478,36 +511,39 @@ static void coreaudio_audio_fini (void *opaque)
 }
 
 static struct audio_option coreaudio_options[] = {
-    {"BUFFER_SIZE", AUD_OPT_INT, &conf.buffer_frames,
-     "Size of the buffer in frames", NULL, 0},
-    {NULL, 0, NULL, NULL, NULL, 0}
+    {
+        .name  = "BUFFER_SIZE",
+        .tag   = AUD_OPT_INT,
+        .valp  = &conf.buffer_frames,
+        .descr = "Size of the buffer in frames"
+    },
+    {
+        .name  = "BUFFER_COUNT",
+        .tag   = AUD_OPT_INT,
+        .valp  = &conf.nbuffers,
+        .descr = "Number of buffers"
+    },
+    { /* End of list */ }
 };
 
 static struct audio_pcm_ops coreaudio_pcm_ops = {
-    coreaudio_init_out,
-    coreaudio_fini_out,
-    coreaudio_run_out,
-    coreaudio_write,
-    coreaudio_ctl_out,
-
-    NULL,
-    NULL,
-    NULL,
-    NULL,
-    NULL
+    .init_out = coreaudio_init_out,
+    .fini_out = coreaudio_fini_out,
+    .run_out  = coreaudio_run_out,
+    .write    = coreaudio_write,
+    .ctl_out  = coreaudio_ctl_out
 };
 
 struct audio_driver coreaudio_audio_driver = {
-    INIT_FIELD (name           = ) "coreaudio",
-    INIT_FIELD (descr          = )
-    "CoreAudio http://developer.apple.com/audio/coreaudio.html",
-    INIT_FIELD (options        = ) coreaudio_options,
-    INIT_FIELD (init           = ) coreaudio_audio_init,
-    INIT_FIELD (fini           = ) coreaudio_audio_fini,
-    INIT_FIELD (pcm_ops        = ) &coreaudio_pcm_ops,
-    INIT_FIELD (can_be_default = ) 1,
-    INIT_FIELD (max_voices_out = ) 1,
-    INIT_FIELD (max_voices_in  = ) 0,
-    INIT_FIELD (voice_size_out = ) sizeof (coreaudioVoiceOut),
-    INIT_FIELD (voice_size_in  = ) 0
+    .name           = "coreaudio",
+    .descr          = "CoreAudio http://developer.apple.com/audio/coreaudio.html",
+    .options        = coreaudio_options,
+    .init           = coreaudio_audio_init,
+    .fini           = coreaudio_audio_fini,
+    .pcm_ops        = &coreaudio_pcm_ops,
+    .can_be_default = 1,
+    .max_voices_out = 1,
+    .max_voices_in  = 0,
+    .voice_size_out = sizeof (coreaudioVoiceOut),
+    .voice_size_in  = 0
 };