chiark / gitweb /
Merge scratch fixes branch
[disorder] / lib / uaudio-coreaudio.c
index 129a66e793a4fcf2d9b5b35be3c28e2633ba4f84..73cc287d48f4a93309540b6a04f35257009862ff 100644 (file)
@@ -26,6 +26,7 @@
 #include "mem.h"
 #include "log.h"
 #include "syscalls.h"
+#include "configuration.h"
 
 /** @brief Callback to request sample data */
 static uaudio_callback *coreaudio_callback;
@@ -68,18 +69,44 @@ static OSStatus coreaudio_adioproc
 
     while(nsamples > 0) {
       /* Integer-format input buffer */
-      int16_t input[1024], *ptr = input;
+      unsigned char input[1024];
+      const size_t maxsamples = sizeof input / uaudio_sample_size;
       /* How many samples we'll ask for */
-      const int ask = nsamples > 1024 ? 1024 : (int)nsamples;
+      const size_t ask = nsamples > maxsamples ? maxsamples : nsamples;
       /* How many we get */
       int got;
 
       got = coreaudio_callback(input, ask, coreaudio_userdata);
       /* Convert the samples and store in the output buffer */
       nsamples -= got;
-      while(got > 0) {
-        --got;
-        *samples++ = *ptr++ * (0.5 / 32767);
+      if(uaudio_signed) {
+        if(uaudio_bits == 16) {
+          const int16_t *ptr = (int16_t *)input;
+          while(got > 0) {
+            --got;
+            *samples++ = *ptr++ * (0.5 / 32767);
+          }
+        } else {
+          const int8_t *ptr = (int8_t *)input;
+          while(got > 0) {
+            --got;
+            *samples++ = *ptr++ * (0.5 / 127);
+          }
+        }
+      } else {
+        if(uaudio_bits == 16) {
+          const uint16_t *ptr = (uint16_t *)input;
+          while(got > 0) {
+            --got;
+            *samples++ = ((int)*ptr++ - 32768) * (0.5 / 32767);
+          }
+        } else {
+          const uint8_t *ptr = (uint8_t *)input;
+          while(got > 0) {
+            --got;
+            *samples++ = ((int)*ptr++ - 128) * (0.5 / 127);
+          }
+        }
       }
     }
     /* Move on to the next buffer */
@@ -96,10 +123,14 @@ static void coreaudio_start(uaudio_callback *callback,
   AudioStreamBasicDescription asbd;
   const char *device;
 
+  if(uaudio_bits != 8 && uaudio_bits != 16)
+    disorder_fatal(0, "asked for %d bits/channel but only support 8 and 16",
+                   uaudio_bits);
   coreaudio_callback = callback;
   coreaudio_userdata = userdata;
-  device = uaudio_get("device");
+  device = uaudio_get("device", "default");
   coreaudio_adid = coreaudio_getdevice(device);
+  /* Get the device properties */
   propertySize = sizeof asbd;
   status = AudioDeviceGetProperty(coreaudio_adid, 0, false,
                                  kAudioDevicePropertyStreamFormat,
@@ -107,16 +138,27 @@ static void coreaudio_start(uaudio_callback *callback,
   if(status)
     coreaudio_fatal(status, "AudioHardwareGetProperty");
   D(("mSampleRate       %f", asbd.mSampleRate));
-  D(("mFormatID         %08lx", asbd.mFormatID));
-  D(("mFormatFlags      %08lx", asbd.mFormatFlags));
-  D(("mBytesPerPacket   %08lx", asbd.mBytesPerPacket));
-  D(("mFramesPerPacket  %08lx", asbd.mFramesPerPacket));
-  D(("mBytesPerFrame    %08lx", asbd.mBytesPerFrame));
-  D(("mChannelsPerFrame %08lx", asbd.mChannelsPerFrame));
-  D(("mBitsPerChannel   %08lx", asbd.mBitsPerChannel));
-  D(("mReserved         %08lx", asbd.mReserved));
+  D(("mFormatID         %08"PRIx32, (uint32_t)asbd.mFormatID));
+  D(("mFormatFlags      %08"PRIx32, (uint32_t)asbd.mFormatFlags));
+  D(("mBytesPerPacket   %08"PRIx32, (uint32_t)asbd.mBytesPerPacket));
+  D(("mFramesPerPacket  %08"PRIx32, (uint32_t)asbd.mFramesPerPacket));
+  D(("mBytesPerFrame    %08"PRIx32, (uint32_t)asbd.mBytesPerFrame));
+  D(("mChannelsPerFrame %08"PRIx32, (uint32_t)asbd.mChannelsPerFrame));
+  D(("mBitsPerChannel   %08"PRIx32, (uint32_t)asbd.mBitsPerChannel));
+  D(("mReserved         %08"PRIx32, (uint32_t)asbd.mReserved));
+  /* Check that everything adds up */
   if(asbd.mFormatID != kAudioFormatLinearPCM)
     disorder_fatal(0, "audio device does not support kAudioFormatLinearPCM");
+  if(asbd.mSampleRate != uaudio_rate
+     || asbd.mChannelsPerFrame != (unsigned)uaudio_channels) {
+    disorder_fatal(0, "want %dHz %d channels "
+                      "but got %gHz %"PRIu32" channels",
+                   uaudio_rate,
+                   uaudio_channels,
+                   (double)asbd.mSampleRate,
+                   (uint32_t)asbd.mChannelsPerFrame);
+  }
+  /* Add a collector callback */
   status = AudioDeviceAddIOProc(coreaudio_adid, coreaudio_adioproc, 0);
   if(status)
     coreaudio_fatal(status, "AudioDeviceAddIOProc");
@@ -141,13 +183,18 @@ static void coreaudio_deactivate(void) {
     coreaudio_fatal(status, "AudioDeviceStop");
 }
 
+static void coreaudio_configure(void) {
+  uaudio_set("device", config->device);
+}
+
 const struct uaudio uaudio_coreaudio = {
   .name = "coreaudio",
   .options = coreaudio_options,
   .start = coreaudio_start,
   .stop = coreaudio_stop,
   .activate = coreaudio_activate,
-  .deactivate = coreaudio_deactivate
+  .deactivate = coreaudio_deactivate,
+  .configure = coreaudio_configure,
 };
 
 #endif