Bug 839415 - [Audio] Add support of SLAndroidConfigurationItf into backend of Cubeb + OpenSLES. r=kinetik
authorMarco Chen <mchen@mozilla.com>
Tue, 12 Mar 2013 11:46:32 +0800
changeset 124487 c69ac844a778
parent 124486 fc1e85affa7f
child 124488 ea8197d7d588
push id24420
push userryanvm@gmail.com
push date2013-03-12 19:35 +0000
treeherdermozilla-central@79b8e0a0bdb7 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskinetik
bugs839415
milestone22.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 839415 - [Audio] Add support of SLAndroidConfigurationItf into backend of Cubeb + OpenSLES. r=kinetik
content/media/AudioStream.cpp
media/libcubeb/README_MOZILLA
media/libcubeb/include/cubeb.h
media/libcubeb/src/cubeb_opensl.c
--- a/content/media/AudioStream.cpp
+++ b/content/media/AudioStream.cpp
@@ -173,16 +173,41 @@ static sa_stream_type_t ConvertChannelTo
     case dom::AUDIO_CHANNEL_PUBLICNOTIFICATION:
       return SA_STREAM_TYPE_ENFORCED_AUDIBLE;
     default:
       NS_ERROR("The value of AudioChannelType is invalid");
       return SA_STREAM_TYPE_MAX;
   }
 }
 
+#if defined(MOZ_CUBEB) && (__ANDROID__)
+static cubeb_stream_type ConvertChannelToCubebType(dom::AudioChannelType aType)
+{
+  switch(aType) {
+    case dom::AUDIO_CHANNEL_NORMAL:
+      return CUBEB_STREAM_TYPE_SYSTEM;
+    case dom::AUDIO_CHANNEL_CONTENT:
+      return CUBEB_STREAM_TYPE_MUSIC;
+    case dom::AUDIO_CHANNEL_NOTIFICATION:
+      return CUBEB_STREAM_TYPE_NOTIFICATION;
+    case dom::AUDIO_CHANNEL_ALARM:
+      return CUBEB_STREAM_TYPE_ALARM;
+    case dom::AUDIO_CHANNEL_TELEPHONY:
+      return CUBEB_STREAM_TYPE_VOICE_CALL;
+    case dom::AUDIO_CHANNEL_RINGER:
+      return CUBEB_STREAM_TYPE_RING;
+    // Currently Android openSLES library doesn't support FORCE_AUDIBLE yet.
+    case dom::AUDIO_CHANNEL_PUBLICNOTIFICATION:
+    default:
+      NS_ERROR("The value of AudioChannelType is invalid");
+      return CUBEB_STREAM_TYPE_MAX;
+  }
+}
+#endif
+
 AudioStream::AudioStream()
 : mInRate(0),
   mOutRate(0),
   mChannels(0),
   mWritten(0),
   mAudioClock(this)
 {}
 
@@ -755,16 +780,23 @@ BufferedAudioStream::Init(int32_t aNumCh
   }
 
   mInRate = mOutRate = aRate;
   mChannels = aNumChannels;
 
   cubeb_stream_params params;
   params.rate = aRate;
   params.channels = aNumChannels;
+#if defined(__ANDROID__)
+  params.stream_type = ConvertChannelToCubebType(aAudioChannelType);
+
+  if (params.stream_type == CUBEB_STREAM_TYPE_MAX) {
+    return NS_ERROR_INVALID_ARG;
+  }
+#endif
   if (AUDIO_OUTPUT_FORMAT == AUDIO_FORMAT_S16) {
     params.format = CUBEB_SAMPLE_S16NE;
   } else {
     params.format = CUBEB_SAMPLE_FLOAT32NE;
   }
   mBytesPerFrame = sizeof(AudioDataValue) * aNumChannels;
 
   mAudioClock.Init();
--- a/media/libcubeb/README_MOZILLA
+++ b/media/libcubeb/README_MOZILLA
@@ -1,8 +1,8 @@
 The source from this directory was copied from the cubeb 
 git repository using the update.sh script.  The only changes
 made were those applied by update.sh and the addition of
 Makefile.in build files for the Mozilla build system.
 
 The cubeb git repository is: git://github.com/kinetiknz/cubeb.git
 
-The git commit ID used was b56cf57ceb0bf4c9f675fe977b457b54d1a8e08b.
+The git commit ID used was f2d524c34b6f75d85053034c3075c2ff08383769.
--- a/media/libcubeb/include/cubeb.h
+++ b/media/libcubeb/include/cubeb.h
@@ -96,22 +96,43 @@ typedef enum {
 #else
   /**< Native endian 16-bit signed PCM. */
   CUBEB_SAMPLE_S16NE = CUBEB_SAMPLE_S16LE,
   /**< Native endian 32-bit IEEE floating point PCM. */
   CUBEB_SAMPLE_FLOAT32NE = CUBEB_SAMPLE_FLOAT32LE
 #endif
 } cubeb_sample_format;
 
+#if defined(__ANDROID__)
+typedef enum {
+    CUBEB_STREAM_TYPE_VOICE_CALL = 0,
+    CUBEB_STREAM_TYPE_SYSTEM = 1,
+    CUBEB_STREAM_TYPE_RING = 2,
+    CUBEB_STREAM_TYPE_MUSIC = 3,
+    CUBEB_STREAM_TYPE_ALARM = 4,
+    CUBEB_STREAM_TYPE_NOTIFICATION = 5,
+    CUBEB_STREAM_TYPE_BLUETOOTH_SCO = 6,
+    CUBEB_STREAM_TYPE_ENFORCED_AUDIBLE = 7,
+    CUBEB_STREAM_TYPE_DTMF = 8,
+    CUBEB_STREAM_TYPE_TTS = 9,
+    CUBEB_STREAM_TYPE_FM = 10,
+
+    CUBEB_STREAM_TYPE_MAX
+} cubeb_stream_type;
+#endif
+
 /** Stream format initialization parameters. */
 typedef struct {
   cubeb_sample_format format; /**< Requested sample format.  One of
                                    #cubeb_sample_format. */
   unsigned int rate;          /**< Requested sample rate.  Valid range is [1, 192000]. */
   unsigned int channels;      /**< Requested channel count.  Valid range is [1, 32]. */
+#if defined(__ANDROID__)
+  cubeb_stream_type stream_type; /**< Used to map Android audio stream types */
+#endif
 } cubeb_stream_params;
 
 /** Stream states signaled via state_callback. */
 typedef enum {
   CUBEB_STATE_STARTED, /**< Stream started. */
   CUBEB_STATE_STOPPED, /**< Stream stopped. */
   CUBEB_STATE_DRAINED, /**< Stream drained. */
   CUBEB_STATE_ERROR    /**< Stream disabled due to error. */
--- a/media/libcubeb/src/cubeb_opensl.c
+++ b/media/libcubeb/src/cubeb_opensl.c
@@ -4,31 +4,38 @@
  * This program is made available under an ISC-style license.  See the
  * accompanying file LICENSE for details.
  */
 #undef NDEBUG
 #include <assert.h>
 #include <dlfcn.h>
 #include <stdlib.h>
 #include <SLES/OpenSLES.h>
+#if defined(__ANDROID__)
+#include <SLES/OpenSLES_Android.h>
+#endif
 #include "cubeb/cubeb.h"
 #include "cubeb-internal.h"
 
 static struct cubeb_ops const opensl_ops;
 
 struct cubeb {
   struct cubeb_ops const * ops;
   void * lib;
   SLInterfaceID SL_IID_BUFFERQUEUE;
   SLInterfaceID SL_IID_PLAY;
+#if defined(__ANDROID__)
+  SLInterfaceID SL_IID_ANDROIDCONFIGURATION;
+#endif
   SLObjectItf engObj;
   SLEngineItf eng;
   SLObjectItf outmixObj;
 };
 
+#define NELEMS(A) (sizeof(A) / sizeof A[0])
 #define NBUFS 4
 
 struct cubeb_stream {
   struct cubeb * context;
   SLObjectItf playerObj;
   SLPlayItf play;
   SLBufferQueueItf bufq;
   void *queuebuf[NBUFS];
@@ -75,16 +82,40 @@ bufferqueue_callback(SLBufferQueueItf ca
 
     if ((written * stm->framesize) < stm->queuebuf_len) {
       stm->draining = 1;
       return;
     }
   }
 }
 
+#if defined(__ANDROID__)
+static SLuint32
+convert_stream_type_to_sl_stream(cubeb_stream_type stream_type)
+{
+  switch(stream_type) {
+    case CUBEB_STREAM_TYPE_SYSTEM:
+      return SL_ANDROID_STREAM_SYSTEM;
+    case CUBEB_STREAM_TYPE_MUSIC:
+      return SL_ANDROID_STREAM_MEDIA;
+    case CUBEB_STREAM_TYPE_NOTIFICATION:
+      return SL_ANDROID_STREAM_NOTIFICATION;
+    case CUBEB_STREAM_TYPE_ALARM:
+      return SL_ANDROID_STREAM_ALARM;
+    case CUBEB_STREAM_TYPE_VOICE_CALL:
+      return SL_ANDROID_STREAM_VOICE;
+    case CUBEB_STREAM_TYPE_RING:
+      return SL_ANDROID_STREAM_RING;
+    case CUBEB_STREAM_TYPE_ENFORCED_AUDIBLE:
+    default:
+      return 0xFFFFFFFF;
+  }
+}
+#endif
+
 static void opensl_destroy(cubeb * ctx);
 
 /*static*/ int
 opensl_init(cubeb ** context, char const * context_name)
 {
   cubeb * ctx;
 
   *context = NULL;
@@ -104,21 +135,27 @@ opensl_init(cubeb ** context, char const
                                        SLuint32,
                                        const SLInterfaceID *,
                                        const SLboolean *);
   slCreateEngine_t f_slCreateEngine =
     (slCreateEngine_t)dlsym(ctx->lib, "slCreateEngine");
   SLInterfaceID SL_IID_ENGINE = *(SLInterfaceID *)dlsym(ctx->lib, "SL_IID_ENGINE");
   SLInterfaceID SL_IID_OUTPUTMIX = *(SLInterfaceID *)dlsym(ctx->lib, "SL_IID_OUTPUTMIX");
   ctx->SL_IID_BUFFERQUEUE = *(SLInterfaceID *)dlsym(ctx->lib, "SL_IID_BUFFERQUEUE");
+#if defined(__ANDROID__)
+  ctx->SL_IID_ANDROIDCONFIGURATION = *(SLInterfaceID *)dlsym(ctx->lib, "SL_IID_ANDROIDCONFIGURATION");
+#endif
   ctx->SL_IID_PLAY = *(SLInterfaceID *)dlsym(ctx->lib, "SL_IID_PLAY");
   if (!f_slCreateEngine ||
       !SL_IID_ENGINE ||
       !SL_IID_OUTPUTMIX ||
       !ctx->SL_IID_BUFFERQUEUE ||
+#if defined(__ANDROID__)
+      !ctx->SL_IID_ANDROIDCONFIGURATION ||
+#endif
       !ctx->SL_IID_PLAY) {
     opensl_destroy(ctx);
     return CUBEB_ERROR;
   }
 
 
   const SLEngineOption opt[] = {{SL_ENGINEOPTION_THREADSAFE, SL_BOOLEAN_TRUE}};
 
@@ -247,25 +284,46 @@ opensl_stream_init(cubeb * ctx, cubeb_st
 
   SLDataLocator_OutputMix loc_outmix;
   loc_outmix.locatorType = SL_DATALOCATOR_OUTPUTMIX;
   loc_outmix.outputMix = ctx->outmixObj;
   SLDataSink sink;
   sink.pLocator = &loc_outmix;
   sink.pFormat = NULL;
 
+#if defined(__ANDROID__)
+  const SLInterfaceID ids[] = {ctx->SL_IID_BUFFERQUEUE, ctx->SL_IID_ANDROIDCONFIGURATION};
+  const SLboolean req[] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE};
+#else
   const SLInterfaceID ids[] = {ctx->SL_IID_BUFFERQUEUE};
   const SLboolean req[] = {SL_BOOLEAN_TRUE};
+#endif
+  assert(NELEMS(ids) == NELEMS(req));
   SLresult res = (*ctx->eng)->CreateAudioPlayer(ctx->eng, &stm->playerObj,
-                                                &source, &sink, 1, ids, req);
+                                                &source, &sink, NELEMS(ids), ids, req);
   if (res != SL_RESULT_SUCCESS) {
     opensl_stream_destroy(stm);
     return CUBEB_ERROR;
   }
 
+#if defined(__ANDROID__)
+  SLuint32 stream_type = convert_stream_type_to_sl_stream(stream_params.stream_type);
+  if (stream_type != 0xFFFFFFFF) {
+    SLAndroidConfigurationItf playerConfig;
+    res = (*stm->playerObj)->GetInterface(stm->playerObj,
+          ctx->SL_IID_ANDROIDCONFIGURATION, &playerConfig);
+    res = (*playerConfig)->SetConfiguration(playerConfig,
+          SL_ANDROID_KEY_STREAM_TYPE, &stream_type, sizeof(SLint32));
+    if (res != SL_RESULT_SUCCESS) {
+      opensl_stream_destroy(stm);
+      return CUBEB_ERROR;
+    }
+  }
+#endif
+
   res = (*stm->playerObj)->Realize(stm->playerObj, SL_BOOLEAN_FALSE);
   if (res != SL_RESULT_SUCCESS) {
     opensl_stream_destroy(stm);
     return CUBEB_ERROR;
   }
 
   res = (*stm->playerObj)->GetInterface(stm->playerObj, ctx->SL_IID_PLAY, &stm->play);
   if (res != SL_RESULT_SUCCESS) {