bug 1171072 - make libcubeb build on iOS. r=kinetik
authorTed Mielczarek <ted@mielczarek.org>
Fri, 06 Feb 2015 14:50:40 -0500
changeset 279533 d832a498605feff06b542b2b95f803adb1f5edcc
parent 279532 4d4b31f83c6908849efee5dec0be6afe222d53f5
child 279534 4655a27961146c2667bfa6821415da775e684f3a
push id4932
push userjlund@mozilla.com
push dateMon, 10 Aug 2015 18:23:06 +0000
treeherdermozilla-beta@6dd5a4f5f745 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskinetik
bugs1171072
milestone41.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
bug 1171072 - make libcubeb build on iOS. r=kinetik
media/libcubeb/src/cubeb_audiounit.c
media/libcubeb/src/moz.build
media/libcubeb/tests/moz.build
--- a/media/libcubeb/src/cubeb_audiounit.c
+++ b/media/libcubeb/src/cubeb_audiounit.c
@@ -1,32 +1,46 @@
 /*
  * Copyright © 2011 Mozilla Foundation
  *
  * This program is made available under an ISC-style license.  See the
  * accompanying file LICENSE for details.
  */
 #undef NDEBUG
+
+#include <TargetConditionals.h>
 #include <assert.h>
+#include <mach/mach_time.h>
 #include <pthread.h>
 #include <stdlib.h>
 #include <AudioUnit/AudioUnit.h>
+#if !TARGET_OS_IPHONE
 #include <CoreAudio/AudioHardware.h>
 #include <CoreAudio/HostTime.h>
 #include <CoreFoundation/CoreFoundation.h>
+#else
+#include <CoreAudio/CoreAudioTypes.h>
+#include <AudioToolbox/AudioToolbox.h>
+#endif
 #include "cubeb/cubeb.h"
 #include "cubeb-internal.h"
 #include "cubeb_panner.h"
+#if !TARGET_OS_IPHONE
 #include "cubeb_osx_run_loop.h"
+#endif
 
 #if !defined(kCFCoreFoundationVersionNumber10_7)
 /* From CoreFoundation CFBase.h */
 #define kCFCoreFoundationVersionNumber10_7 635.00
 #endif
 
+#if !TARGET_OS_IPHONE && MAC_OS_X_VERSION_MIN_REQUIRED < 1060
+#define MACOSX_LESS_THAN_106
+#endif
+
 #define CUBEB_STREAM_MAX 8
 #define NBUFS 4
 
 static struct cubeb_ops const audiounit_ops;
 
 struct cubeb {
   struct cubeb_ops const * ops;
   pthread_mutex_t mutex;
@@ -47,16 +61,41 @@ struct cubeb_stream {
   uint64_t frames_queued;
   int shutdown;
   int draining;
   uint64_t current_latency_frames;
   uint64_t hw_latency_frames;
   float panning;
 };
 
+#if TARGET_OS_IPHONE
+typedef UInt32 AudioDeviceID;
+typedef UInt32 AudioObjectID;
+
+#define AudioGetCurrentHostTime mach_absolute_time
+
+uint64_t
+AudioConvertHostTimeToNanos(uint64_t host_time)
+{
+  static struct mach_timebase_info timebase_info;
+  static bool initialized = false;
+  if (!initialized) {
+    mach_timebase_info(&timebase_info);
+    initialized = true;
+  }
+
+  long double answer = host_time;
+  if (timebase_info.numer != timebase_info.denom) {
+    answer *= timebase_info.numer;
+    answer /= timebase_info.denom;
+  }
+  return (uint64_t)answer;
+}
+#endif
+
 static int64_t
 audiotimestamp_to_latency(AudioTimeStamp const * tstamp, cubeb_stream * stream)
 {
   if (!(tstamp->mFlags & kAudioTimeStampHostTimeValid)) {
     return 0;
   }
 
   uint64_t pres = AudioConvertHostTimeToNanos(tstamp->mHostTime);
@@ -140,30 +179,32 @@ audiounit_init(cubeb ** context, char co
   ctx->ops = &audiounit_ops;
 
   r = pthread_mutex_init(&ctx->mutex, NULL);
   assert(r == 0);
 
   ctx->active_streams = 0;
 
   ctx->limit_streams = kCFCoreFoundationVersionNumber < kCFCoreFoundationVersionNumber10_7;
-
+#if !TARGET_OS_IPHONE
   cubeb_set_coreaudio_notification_runloop();
+#endif
 
   *context = ctx;
 
   return CUBEB_OK;
 }
 
 static char const *
 audiounit_get_backend_id(cubeb * ctx)
 {
   return "audiounit";
 }
 
+#if !TARGET_OS_IPHONE
 static int
 audiounit_get_output_device_id(AudioDeviceID * device_id)
 {
   UInt32 size;
   OSStatus r;
   AudioObjectPropertyAddress output_device_address = {
     kAudioHardwarePropertyDefaultOutputDevice,
     kAudioObjectPropertyScopeGlobal,
@@ -352,20 +393,25 @@ audiounit_get_acceptable_latency_range(A
                                  &size,
                                  latency_range);
   if (r != noErr) {
     return CUBEB_ERROR;
   }
 
   return CUBEB_OK;
 }
+#endif /* !TARGET_OS_IPHONE */
 
 int
 audiounit_get_max_channel_count(cubeb * ctx, uint32_t * max_channels)
 {
+#if TARGET_OS_IPHONE
+  //TODO: [[AVAudioSession sharedInstance] maximumOutputNumberOfChannels]
+  *max_channels = 2;
+#else
   UInt32 size;
   OSStatus r;
   AudioDeviceID output_device_id;
   AudioStreamBasicDescription stream_format;
   AudioObjectPropertyAddress stream_format_address = {
     kAudioDevicePropertyStreamFormat,
     kAudioDevicePropertyScopeOutput,
     kAudioObjectPropertyElementMaster
@@ -385,37 +431,45 @@ audiounit_get_max_channel_count(cubeb * 
                                  NULL,
                                  &size,
                                  &stream_format);
   if (r != noErr) {
     return CUBEB_ERROR;
   }
 
   *max_channels = stream_format.mChannelsPerFrame;
-
+#endif
   return CUBEB_OK;
 }
 
 static int
 audiounit_get_min_latency(cubeb * ctx, cubeb_stream_params params, uint32_t * latency_ms)
 {
+#if TARGET_OS_IPHONE
+  //TODO: [[AVAudioSession sharedInstance] inputLatency]
+  return CUBEB_ERROR_NOT_SUPPORTED;
+#else
   AudioValueRange latency_range;
-
   if (audiounit_get_acceptable_latency_range(&latency_range) != CUBEB_OK) {
     return CUBEB_ERROR;
   }
 
   *latency_ms = (latency_range.mMinimum * 1000 + params.rate - 1) / params.rate;
+#endif
 
   return CUBEB_OK;
 }
 
 static int
 audiounit_get_preferred_sample_rate(cubeb * ctx, uint32_t * rate)
 {
+#if TARGET_OS_IPHONE
+  //TODO
+  return CUBEB_ERROR_NOT_SUPPORTED;
+#else
   UInt32 size;
   OSStatus r;
   Float64 fsamplerate;
   AudioDeviceID output_device_id;
   AudioObjectPropertyAddress samplerate_address = {
     kAudioDevicePropertyNominalSampleRate,
     kAudioObjectPropertyScopeGlobal,
     kAudioObjectPropertyElementMaster
@@ -433,17 +487,17 @@ audiounit_get_preferred_sample_rate(cube
                                  &size,
                                  &fsamplerate);
 
   if (r != noErr) {
     return CUBEB_ERROR;
   }
 
   *rate = (uint32_t)fsamplerate;
-
+#endif
   return CUBEB_OK;
 }
 
 static void
 audiounit_destroy(cubeb * ctx)
 {
   int r;
 
@@ -460,17 +514,17 @@ static void audiounit_stream_destroy(cub
 
 static int
 audiounit_stream_init(cubeb * context, cubeb_stream ** stream, char const * stream_name,
                       cubeb_stream_params stream_params, unsigned int latency,
                       cubeb_data_callback data_callback, cubeb_state_callback state_callback,
                       void * user_ptr)
 {
   AudioStreamBasicDescription ss;
-#if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
+#if MACOSX_LESS_THAN_106
   ComponentDescription desc;
   Component comp;
 #else
   AudioComponentDescription desc;
   AudioComponent comp;
 #endif
   cubeb_stream * stm;
   AURenderCallbackStruct input;
@@ -521,21 +575,26 @@ audiounit_stream_init(cubeb * context, c
   if (context->limit_streams && context->active_streams >= CUBEB_STREAM_MAX) {
     pthread_mutex_unlock(&context->mutex);
     return CUBEB_ERROR;
   }
   context->active_streams += 1;
   pthread_mutex_unlock(&context->mutex);
 
   desc.componentType = kAudioUnitType_Output;
-  desc.componentSubType = kAudioUnitSubType_DefaultOutput;
+  desc.componentSubType =
+#if TARGET_OS_IPHONE
+    kAudioUnitSubType_RemoteIO;
+#else
+    kAudioUnitSubType_DefaultOutput;
+#endif
   desc.componentManufacturer = kAudioUnitManufacturer_Apple;
   desc.componentFlags = 0;
   desc.componentFlagsMask = 0;
-#if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
+#if MACOSX_LESS_THAN_106
   comp = FindNextComponent(NULL, &desc);
 #else
   comp = AudioComponentFindNext(NULL, &desc);
 #endif
   assert(comp);
 
   stm = calloc(1, sizeof(*stm));
   assert(stm);
@@ -555,17 +614,17 @@ audiounit_stream_init(cubeb * context, c
   pthread_mutexattr_destroy(&attr);
   assert(r == 0);
 
   stm->frames_played = 0;
   stm->frames_queued = 0;
   stm->current_latency_frames = 0;
   stm->hw_latency_frames = UINT64_MAX;
 
-#if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
+#if MACOSX_LESS_THAN_106
   r = OpenAComponent(comp, &stm->unit);
 #else
   r = AudioComponentInstanceNew(comp, &stm->unit);
 #endif
   if (r != 0) {
     audiounit_stream_destroy(stm);
     return CUBEB_ERROR;
   }
@@ -578,16 +637,17 @@ audiounit_stream_init(cubeb * context, c
     audiounit_stream_destroy(stm);
     return CUBEB_ERROR;
   }
 
   buffer_size = latency / 1000.0 * ss.mSampleRate;
 
   /* Get the range of latency this particular device can work with, and clamp
    * the requested latency to this acceptable range. */
+#if !TARGET_OS_IPHONE
   if (audiounit_get_acceptable_latency_range(&latency_range) != CUBEB_OK) {
     audiounit_stream_destroy(stm);
     return CUBEB_ERROR;
   }
 
   if (buffer_size < (unsigned int) latency_range.mMinimum) {
     buffer_size = (unsigned int) latency_range.mMinimum;
   } else if (buffer_size > (unsigned int) latency_range.mMaximum) {
@@ -601,16 +661,20 @@ audiounit_stream_init(cubeb * context, c
   size = sizeof(default_buffer_size);
   r = AudioUnitGetProperty(stm->unit, kAudioDevicePropertyBufferFrameSize,
                            kAudioUnitScope_Output, 0, &default_buffer_size, &size);
 
   if (r != 0) {
     audiounit_stream_destroy(stm);
     return CUBEB_ERROR;
   }
+#else  // TARGET_OS_IPHONE
+  //TODO: [[AVAudioSession sharedInstance] inputLatency]
+  // http://stackoverflow.com/questions/13157523/kaudiodevicepropertybufferframesize-replacement-for-ios
+#endif
 
   // Setting the latency doesn't work well for USB headsets (eg. plantronics).
   // Keep the default latency for now.
 #if 0
   if (buffer_size < default_buffer_size) {
     /* Set the maximum number of frame that the render callback will ask for,
      * effectively setting the latency of the stream. This is process-wide. */
     r = AudioUnitSetProperty(stm->unit, kAudioDevicePropertyBufferFrameSize,
@@ -632,41 +696,45 @@ audiounit_stream_init(cubeb * context, c
   r = AudioUnitInitialize(stm->unit);
   if (r != 0) {
     audiounit_stream_destroy(stm);
     return CUBEB_ERROR;
   }
 
   *stream = stm;
 
+#if !TARGET_OS_IPHONE
   /* we dont' check the return value here, because we want to be able to play
    * even if we can't detect device changes. */
   audiounit_install_device_changed_callback(stm);
+#endif
 
   return CUBEB_OK;
 }
 
 static void
 audiounit_stream_destroy(cubeb_stream * stm)
 {
   int r;
 
   stm->shutdown = 1;
 
   if (stm->unit) {
     AudioOutputUnitStop(stm->unit);
     AudioUnitUninitialize(stm->unit);
-#if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
+#if MACOSX_LESS_THAN_106
     CloseComponent(stm->unit);
 #else
     AudioComponentInstanceDispose(stm->unit);
 #endif
   }
 
+#if !TARGET_OS_IPHONE
   audiounit_uninstall_device_changed_callback(stm);
+#endif
 
   r = pthread_mutex_destroy(&stm->mutex);
   assert(r == 0);
 
   pthread_mutex_lock(&stm->context->mutex);
   assert(stm->context->active_streams >= 1);
   stm->context->active_streams -= 1;
   pthread_mutex_unlock(&stm->context->mutex);
@@ -701,16 +769,20 @@ audiounit_stream_get_position(cubeb_stre
   *position = stm->frames_played;
   pthread_mutex_unlock(&stm->mutex);
   return CUBEB_OK;
 }
 
 int
 audiounit_stream_get_latency(cubeb_stream * stm, uint32_t * latency)
 {
+#if TARGET_OS_IPHONE
+  //TODO
+  return CUBEB_ERROR_NOT_SUPPORTED;
+#else
   pthread_mutex_lock(&stm->mutex);
   if (stm->hw_latency_frames == UINT64_MAX) {
     UInt32 size;
     uint32_t device_latency_frames, device_safety_offset;
     double unit_latency_sec;
     AudioDeviceID output_device_id;
     OSStatus r;
     AudioObjectPropertyAddress latency_address = {
@@ -773,16 +845,17 @@ audiounit_stream_get_latency(cubeb_strea
       + device_latency_frames
       + device_safety_offset;
   }
 
   *latency = stm->hw_latency_frames + stm->current_latency_frames;
   pthread_mutex_unlock(&stm->mutex);
 
   return CUBEB_OK;
+#endif
 }
 
 int audiounit_stream_set_volume(cubeb_stream * stm, float volume)
 {
   OSStatus r;
 
   r = AudioUnitSetParameter(stm->unit,
                             kHALOutputParam_Volume,
@@ -806,16 +879,20 @@ int audiounit_stream_set_panning(cubeb_s
   pthread_mutex_unlock(&stm->mutex);
 
   return CUBEB_OK;
 }
 
 int audiounit_stream_get_current_device(cubeb_stream * stm,
                                         cubeb_device ** const  device)
 {
+#if TARGET_OS_IPHONE
+  //TODO
+  return CUBEB_ERROR_NOT_SUPPORTED;
+#else
   OSStatus r;
   UInt32 size;
   UInt32 data;
   char strdata[4];
   AudioDeviceID output_device_id;
   AudioDeviceID input_device_id;
 
   AudioObjectPropertyAddress datasource_address = {
@@ -892,16 +969,17 @@ int audiounit_stream_get_current_device(
   strdata[1] = (char)(data >> 16);
   strdata[2] = (char)(data >> 8);
   strdata[3] = (char)(data);
 
   memcpy((*device)->input_name, strdata, size);
   (*device)->input_name[size] = '\0';
 
   return CUBEB_OK;
+#endif
 }
 
 int audiounit_stream_device_destroy(cubeb_stream * stream,
                                     cubeb_device * device)
 {
   free(device->output_name);
   free(device->input_name);
   free(device);
--- a/media/libcubeb/src/moz.build
+++ b/media/libcubeb/src/moz.build
@@ -29,18 +29,21 @@ if CONFIG['OS_ARCH'] == 'OpenBSD':
     SOURCES += [
         'cubeb_sndio.c',
     ]
     DEFINES['USE_SNDIO'] = True
 
 if CONFIG['OS_TARGET'] == 'Darwin':
     SOURCES += [
         'cubeb_audiounit.c',
-        'cubeb_osx_run_loop.c'
     ]
+    if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa':
+        SOURCES += [
+            'cubeb_osx_run_loop.c',
+        ]
     DEFINES['USE_AUDIOUNIT'] = True
 
 if CONFIG['OS_TARGET'] == 'WINNT':
     SOURCES += [
         'cubeb_resampler.cpp',
         'cubeb_wasapi.cpp',
         'cubeb_winmm.c',
     ]
--- a/media/libcubeb/tests/moz.build
+++ b/media/libcubeb/tests/moz.build
@@ -39,20 +39,25 @@ else:
         'cubeb',
     ]
     # Don't link gkmedias for it introduces dependencies on Android.
     if CONFIG['OS_TARGET'] == 'Android':
         USE_LIBS += [
             'speex',
         ]
 
-if CONFIG['OS_TARGET'] == 'Darwin':
+if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa':
     OS_LIBS += [
         '-framework AudioUnit',
         '-framework CoreAudio',
     ]
+elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'uikit':
+    OS_LIBS += [
+      '-framework CoreFoundation',
+      '-framework AudioToolbox',
+    ]
 elif CONFIG['OS_TARGET'] == 'OpenBSD':
     OS_LIBS += [
         'sndio',
     ]
 else:
     OS_LIBS += CONFIG['MOZ_ALSA_LIBS']
     OS_LIBS += CONFIG['MOZ_PULSEAUDIO_LIBS']