OSDN Git Service

Implement SLAndroidConfigurationItf on AudioRecorder.
authorJean-Michel Trivi <jmtrivi@google.com>
Tue, 14 Sep 2010 01:24:59 +0000 (18:24 -0700)
committerJean-Michel Trivi <jmtrivi@google.com>
Tue, 14 Sep 2010 22:05:33 +0000 (15:05 -0700)
Enable the use of the configuration interface before the
 AudioRecorder object is realized to set the recording
 preset. Recording presets map to the Android
 AudioRecord input source.

Change-Id: I804095a0b39e4676862f6bc8e7fbaa0ba63b9336

opensles/include/SLES/OpenSLES_AndroidConfiguration.h [new file with mode: 0644]
opensles/libopensles/IAndroidConfiguration.c
opensles/libopensles/IObject.c
opensles/libopensles/android_AudioRecorder.cpp
opensles/libopensles/android_AudioRecorder.h
opensles/libopensles/sles_allinclusive.h
opensles/tests/examples/Android.mk_
opensles/tests/examples/slesTestRecBuffQueue.cpp

diff --git a/opensles/include/SLES/OpenSLES_AndroidConfiguration.h b/opensles/include/SLES/OpenSLES_AndroidConfiguration.h
new file mode 100644 (file)
index 0000000..f761441
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef OPENSL_ES_ANDROIDCONFIGURATION_H_
+#define OPENSL_ES_ANDROIDCONFIGURATION_H_
+
+#ifdef __cplusplus
+extern "C" {
+
+/*---------------------------------------------------------------------------*/
+/* Android AudioRecorder configuration                                       */
+/*---------------------------------------------------------------------------*/
+
+/** Audio recording preset */
+/** Audio recording preset key */
+#define SL_ANDROID_KEY_RECORDING_PRESET ((const SLchar*) "androidRecordingPreset")
+/** Audio recording preset values */
+/**   preset "none" cannot be set, it is used to indicate the current settings
+ *     do not match any of the presets. */
+#define SL_ANDROID_RECORDING_PRESET_NONE              ((SLuint32) 0x00000000)
+/**   default recording configuration on the platform */
+#define SL_ANDROID_RECORDING_PRESET_DEFAULT           ((SLuint32) 0x00000001)
+/**   uses the microphone audio source with the same orientation as the camera
+ *     if available, the main device microphone otherwise */
+#define SL_ANDROID_RECORDING_PRESET_CAMCORDER         ((SLuint32) 0x00000002)
+/**   uses the main microphone tuned for voice recognition */
+#define SL_ANDROID_RECORDING_PRESET_VOICE_RECOGNITION ((SLuint32) 0x00000003)
+
+/*---------------------------------------------------------------------------*/
+/* Android AudioPlayer configuration                                         */
+/*---------------------------------------------------------------------------*/
+
+/** Audio playback stream type */
+/** Audio playback stream type key */
+#define SL_ANDROID_KEY_STREAM_TYPE ((const SLchar*) "androidPlaybackStreamType")
+
+/** Audio playback stream type  values */
+// FIXME remove comments in front of #define below once the SLAndroidStreamTypeItf interface is gone
+/*      same as android.media.AudioManager.STREAM_VOICE_CALL */
+//#define SL_ANDROID_STREAM_VOICE        ((SLint32) 0x00000000)
+/*      same as android.media.AudioManager.STREAM_SYSTEM */
+//#define SL_ANDROID_STREAM_SYSTEM       ((SLint32) 0x00000001)
+/*      same as android.media.AudioManager.STREAM_RING */
+//#define SL_ANDROID_STREAM_RING         ((SLint32) 0x00000002)
+/*      same as android.media.AudioManager.STREAM_MUSIC */
+//#define SL_ANDROID_STREAM_MEDIA        ((SLint32) 0x00000003)
+/*      same as android.media.AudioManager.STREAM_ALARM */
+//#define SL_ANDROID_STREAM_ALARM        ((SLint32) 0x00000004)
+/*      same as android.media.AudioManager.STREAM_NOTIFICATION */
+//#define SL_ANDROID_STREAM_NOTIFICATION ((SLint32) 0x00000005)
+
+
+
+}
+#endif /* __cplusplus */
+
+#endif /* OPENSL_ES_ANDROIDCONFIGURATION_H_ */
index c191f8d..45006ab 100644 (file)
@@ -27,16 +27,25 @@ static SLresult IAndroidConfiguration_SetConfiguration(SLAndroidConfigurationItf
     SL_ENTER_INTERFACE
 
     IAndroidConfiguration *this = (IAndroidConfiguration *) self;
+
     interface_lock_exclusive(this);
 
-    // route key configuration to the appropriate object
-    // FIXME implement
-#if 0
-    // is SLAndroidConfigurationItf on an AudioPlayer?
-    CAudioPlayer *ap = (SL_OBJECTID_AUDIOPLAYER == InterfaceToObjectID(this)) ?
-            (CAudioPlayer *) this->mThis : NULL;
-#endif
+#ifndef ANDROID
     result = SL_RESULT_SUCCESS;
+#else
+    // route configuration to the appropriate object
+    if (SL_OBJECTID_AUDIORECORDER == IObjectToObjectID((this)->mThis)) {
+        SL_LOGV("SetConfiguration issued for AudioRecorder");
+        result = android_audioRecorder_setConfig((CAudioRecorder *) this->mThis, configKey,
+                pConfigValue, valueSize);
+    } else if (SL_OBJECTID_AUDIOPLAYER == IObjectToObjectID((this)->mThis)) {
+        SL_LOGV("SetConfiguration issued for AudioPlayer");
+        result = SL_RESULT_PARAMETER_INVALID;
+    } else if (SL_OBJECTID_OUTPUTMIX == IObjectToObjectID((this)->mThis)) {
+        SL_LOGV("SetConfiguration issued for OutputMix");
+        result = SL_RESULT_PARAMETER_INVALID;
+    }
+#endif
 
     interface_unlock_exclusive(this);
 
@@ -51,17 +60,29 @@ static SLresult IAndroidConfiguration_GetConfiguration(SLAndroidConfigurationItf
 {
     SL_ENTER_INTERFACE
 
-    if (NULL == configKey) {
+#ifndef ANDROID
+    result = SL_RESULT_SUCCESS;
+#else
+    if ((NULL == pValueSize) || (NULL == pConfigValue)) {
         result = SL_RESULT_PARAMETER_INVALID;
     } else {
         IAndroidConfiguration *this = (IAndroidConfiguration *) self;
-        interface_lock_shared(this);
-        // route key configuration to the appropriate object
-        // FIXME implement
-        result = SL_RESULT_SUCCESS;
 
-        interface_unlock_shared(this);
+        interface_lock_exclusive(this);
+
+        // route configuration request to the appropriate object
+        if (SL_OBJECTID_AUDIORECORDER == IObjectToObjectID((this)->mThis)) {
+            result = android_audioRecorder_getConfig((CAudioRecorder *) this->mThis, configKey,
+                    pValueSize, pConfigValue);
+        } else if (SL_OBJECTID_AUDIOPLAYER == IObjectToObjectID((this)->mThis)) {
+            result = SL_RESULT_PARAMETER_INVALID;
+        } else if (SL_OBJECTID_OUTPUTMIX == IObjectToObjectID((this)->mThis)) {
+            result = SL_RESULT_PARAMETER_INVALID;
+        }
+
+        interface_unlock_exclusive(this);
     }
+#endif
 
     SL_LEAVE_INTERFACE
 }
index 8abc745..7e7fc07 100644 (file)
@@ -328,9 +328,24 @@ static SLresult IObject_GetInterface(SLObjectItf self, const SLInterfaceID iid,
             } else {
                 unsigned mask = 1 << index;
                 object_lock_exclusive(this);
-                // Can't get interface on a suspended/suspending/resuming object
                 if (SL_OBJECT_STATE_REALIZED != this->mState) {
+                    // Can't get interface on a suspended/suspending/resuming object
                     result = SL_RESULT_PRECONDITIONS_VIOLATED;
+
+                    // unless this is an explicit + configuration interface,
+                    // which will be checked here:
+
+                    // FIXME: temporary hack to allow an interface to be called before it's
+                    //        object is realized
+                    if (this->mInterfaceStates[index] == INTERFACE_EXPOSED) {
+                        interface = (char *) this + class__->mInterfaces[index].mOffset;
+                        if (!(this->mGottenMask & mask)) {
+                            this->mGottenMask |= mask;
+                            ((size_t *) interface)[0] ^= ~0;
+                        }
+                        result = SL_RESULT_SUCCESS;
+                    }
+
                 } else {
                     switch (this->mInterfaceStates[index]) {
                     case INTERFACE_EXPOSED:
index 370265f..8821006 100644 (file)
@@ -35,6 +35,80 @@ static FILE* gMonitorFp = NULL;
         "Cannot create AudioRecorder: data source device type must be SL_IODEVICE_AUDIOINPUT"
 #define ERROR_INPUT_ID_MUST_BE_DEFAULT \
         "Cannot create AudioRecorder: data source device ID must be SL_DEFAULTDEVICEID_AUDIOINPUT"
+#define ERROR_UNKNOWN_KEY \
+        "Cannot set recording configuration: unknown key"
+#define ERROR_SET_UNKNOWN_PRESET \
+        "Cannot set recording preset: unknown preset"
+#define ERROR_VALUESIZE_TOO_LOW \
+        "Configuration error: value size too low to store valid value"
+#define ERROR_INVALID_SOURCE_FOR_VOICE_RECO \
+        "Cannot set recording preset to voice recognition: incompatible recording source"
+#define ERROR_AEC_UNSUPPORTED \
+        "Cannot change AEC setting: unsupported feature on this platform"
+#define ERROR_AGC_UNSUPPORTED \
+        "Cannot change AGC setting: unsupported feature on this platform"
+#define ERROR_NULL_PARAM \
+        "Configuration error: invalid NULL parameter"
+
+#define KEY_RECORDING_SOURCE_PARAMSIZE  sizeof(SLuint32)
+#define KEY_RECORDING_PRESET_PARAMSIZE  sizeof(SLuint32)
+
+//-----------------------------------------------------------------------------
+// Internal utility functions
+//----------------------------
+
+SLresult audioRecorder_setPreset(CAudioRecorder* ar, SLuint32 recordPreset) {
+    SLresult result = SL_RESULT_SUCCESS;
+
+    switch (recordPreset) {
+    case SL_ANDROID_RECORDING_PRESET_DEFAULT:
+        ar->mRecordSource = android::AUDIO_SOURCE_DEFAULT;
+        break;
+    case SL_ANDROID_RECORDING_PRESET_CAMCORDER:
+        ar->mRecordSource = android::AUDIO_SOURCE_CAMCORDER;
+        break;
+    case SL_ANDROID_RECORDING_PRESET_VOICE_RECOGNITION:
+        ar->mRecordSource = android::AUDIO_SOURCE_VOICE_RECOGNITION;
+        break;
+    case SL_ANDROID_RECORDING_PRESET_NONE:
+        // it is an error to set preset "none"
+    default:
+        SL_LOGE(ERROR_SET_UNKNOWN_PRESET);
+        result = SL_RESULT_PARAMETER_INVALID;
+    }
+
+    return result;
+}
+
+
+SLresult audioRecorder_getPreset(CAudioRecorder* ar, SLuint32* pPreset) {
+    SLresult result = SL_RESULT_SUCCESS;
+
+    switch (ar->mRecordSource) {
+    case android::AUDIO_SOURCE_DEFAULT:
+    case android::AUDIO_SOURCE_MIC:
+        *pPreset = SL_ANDROID_RECORDING_PRESET_DEFAULT;
+        break;
+    case android::AUDIO_SOURCE_VOICE_UPLINK:
+    case android::AUDIO_SOURCE_VOICE_DOWNLINK:
+    case android::AUDIO_SOURCE_VOICE_CALL:
+        *pPreset = SL_ANDROID_RECORDING_PRESET_NONE;
+        break;
+    case android::AUDIO_SOURCE_VOICE_RECOGNITION:
+        *pPreset = SL_ANDROID_RECORDING_PRESET_VOICE_RECOGNITION;
+        break;
+    case android::AUDIO_SOURCE_CAMCORDER:
+        *pPreset = SL_ANDROID_RECORDING_PRESET_CAMCORDER;
+        break;
+    default:
+        *pPreset = SL_ANDROID_RECORDING_PRESET_NONE;
+        result = SL_RESULT_INTERNAL_ERROR;
+        break;
+    }
+
+    return result;
+}
+
 
 //-----------------------------------------------------------------------------
 SLresult android_audioRecorder_checkSourceSinkSupport(CAudioRecorder* ar) {
@@ -177,6 +251,70 @@ SLresult android_audioRecorder_create(CAudioRecorder* ar) {
     SLresult result = SL_RESULT_SUCCESS;
 
     ar->mAudioRecord = NULL;
+    ar->mRecordSource = android::AUDIO_SOURCE_DEFAULT;
+
+    return result;
+}
+
+
+//-----------------------------------------------------------------------------
+SLresult android_audioRecorder_setConfig(CAudioRecorder* ar, const SLchar *configKey,
+        const void *pConfigValue, SLuint32 valueSize) {
+
+    SLresult result = SL_RESULT_SUCCESS;
+
+    if (NULL == ar) {
+        result = SL_RESULT_INTERNAL_ERROR;
+    } else if (NULL == pConfigValue) {
+        SL_LOGE(ERROR_NULL_PARAM);
+        result = SL_RESULT_PARAMETER_INVALID;
+
+    } else if(strcmp((const char*)configKey, (const char*)SL_ANDROID_KEY_RECORDING_PRESET) == 0) {
+
+        // recording preset
+        if (KEY_RECORDING_PRESET_PARAMSIZE > valueSize) {
+            SL_LOGE(ERROR_VALUESIZE_TOO_LOW);
+            result = SL_RESULT_PARAMETER_INVALID;
+        } else {
+            result = audioRecorder_setPreset(ar, *(SLuint32*)pConfigValue);
+        }
+
+    } else {
+        SL_LOGE(ERROR_UNKNOWN_KEY);
+        result = SL_RESULT_PARAMETER_INVALID;
+    }
+
+    return result;
+}
+
+
+//-----------------------------------------------------------------------------
+SLresult android_audioRecorder_getConfig(CAudioRecorder* ar, const SLchar *configKey,
+        SLuint32* pValueSize, void *pConfigValue) {
+
+    SLresult result = SL_RESULT_SUCCESS;
+
+    if (NULL == ar) {
+        return SL_RESULT_INTERNAL_ERROR;
+    } else if ((NULL == pValueSize) || (NULL == pConfigValue)) {
+        SL_LOGE(ERROR_NULL_PARAM);
+        result = SL_RESULT_PARAMETER_INVALID;
+
+    } else if(strcmp((const char*)configKey, (const char*)SL_ANDROID_KEY_RECORDING_PRESET) == 0) {
+
+        // recording preset
+        if (KEY_RECORDING_PRESET_PARAMSIZE > *pValueSize) {
+            SL_LOGE(ERROR_VALUESIZE_TOO_LOW);
+            result = SL_RESULT_PARAMETER_INVALID;
+        } else {
+            *pValueSize = KEY_RECORDING_PRESET_PARAMSIZE;
+            result = audioRecorder_getPreset(ar, (SLuint32*)pConfigValue);
+        }
+
+    } else {
+        SL_LOGE(ERROR_UNKNOWN_KEY);
+        result = SL_RESULT_PARAMETER_INVALID;
+    }
 
     return result;
 }
@@ -201,7 +339,7 @@ SLresult android_audioRecorder_realize(CAudioRecorder* ar, SLboolean async) {
 
     // initialize platform-specific CAudioRecorder fields
     ar->mAudioRecord = new android::AudioRecord();
-    ar->mAudioRecord->set(android::AUDIO_SOURCE_DEFAULT, // source
+    ar->mAudioRecord->set(ar->mRecordSource, // source
             sles_to_android_sampleRate(ar->mSampleRateMilliHz), // sample rate in Hertz
             android::AudioSystem::PCM_16_BIT,   //FIXME use format from buffer queue sink
             sles_to_android_channelMask(ar->mNumChannels, 0 /*no channel mask*/), // channel config
index dfa1adb..3165a27 100644 (file)
@@ -18,6 +18,12 @@ extern SLresult android_audioRecorder_checkSourceSinkSupport(CAudioRecorder* ar)
 
 extern SLresult android_audioRecorder_create(CAudioRecorder* ar);
 
+extern SLresult android_audioRecorder_setConfig(CAudioRecorder* ar, const SLchar *configKey,
+        const void *pConfigValue, SLuint32 valueSize);
+
+extern SLresult android_audioRecorder_getConfig(CAudioRecorder* ar, const SLchar *configKey,
+        SLuint32* pValueSize, void *pConfigValue);
+
 extern SLresult android_audioRecorder_realize(CAudioRecorder* ar, SLboolean async);
 
 extern void android_audioRecorder_destroy(CAudioRecorder* ar);
index 7b5f0fb..6bb4623 100644 (file)
@@ -60,6 +60,7 @@ typedef struct COutputMix_struct COutputMix;
 #include <utils/Log.h>
 #include <utils/KeyedVector.h>
 #include "SLES/OpenSLES_Android.h"
+#include "SLES/OpenSLES_AndroidConfiguration.h"
 #include "media/AudioSystem.h"
 #include "media/mediarecorder.h"
 #include "media/AudioRecord.h"
@@ -167,6 +168,7 @@ typedef bool (*BoolHook)(void *self);
 #define INTERFACE_ADDING_1A    11  ///< /part 1 of asynchronous AddInterface, aborted
 #define INTERFACE_RESUMING_1A  12  ///< /part 1 of asynchronous ResumeInterface, aborted
 
+
 // Maps an interface ID to its offset within the class that exposes it
 
 struct iid_vtable {
@@ -1026,6 +1028,7 @@ enum AndroidObject_state {
     // implementation-specific data for this instance
 #ifdef ANDROID
     android::AudioRecord *mAudioRecord;
+    int mRecordSource;
 #endif
 } /*CAudioRecorder*/;
 
index 430bc33..0b9ba37 100644 (file)
@@ -7,7 +7,7 @@ include $(CLEAR_VARS)
 LOCAL_MODULE_TAGS := tests
 
 LOCAL_C_INCLUDES:= \
-       system/media/opensles/include
+       system/media/opensles/include/SLES/
 
 LOCAL_SRC_FILES:= \
        slesTestRecBuffQueue.cpp
index 68e272b..06e15df 100644 (file)
 
 #include "OpenSLES.h"
 #include "OpenSLES_Android.h"
+#include "OpenSLES_AndroidConfiguration.h"
 
-/* Explicitly requesting SL_IID_BUFFERQUEUE on the AudioRecorder object */
-#define NUM_EXPLICIT_INTERFACES_FOR_RECORDER 1
+/* Explicitly requesting SL_IID_BUFFERQUEUE and SL_IID_ANDROIDCONFIGURATION
+ * on the AudioRecorder object */
+#define NUM_EXPLICIT_INTERFACES_FOR_RECORDER 2
 
 /* Size of the recording buffer queue */
 #define NB_BUFFERS_IN_QUEUE 1
@@ -108,8 +110,9 @@ void TestRecToBuffQueue( SLObjectItf sl, const char* path, SLAint64 durationInSe
     SLObjectItf  recorder;
 
     /* Interfaces for the audio recorder */
-    SLBufferQueueItf       recBuffQueueItf;
-    SLRecordItf            recordItf;
+    SLBufferQueueItf          recBuffQueueItf;
+    SLRecordItf               recordItf;
+    SLAndroidConfigurationItf configItf;
 
     /* Source of audio data for the recording */
     SLDataSource           recSource;
@@ -137,9 +140,11 @@ void TestRecToBuffQueue( SLObjectItf sl, const char* path, SLAint64 durationInSe
     /* ------------------------------------------------------ */
     /* Configuration of the recorder  */
 
-    /* Request the BufferQueue interface */
+    /* Request the BufferQueue and AndroidConfiguration interfaces */
     required[0] = SL_BOOLEAN_TRUE;
     iidArray[0] = SL_IID_BUFFERQUEUE;
+    required[1] = SL_BOOLEAN_TRUE;
+    iidArray[1] = SL_IID_ANDROIDCONFIGURATION;
 
     /* Setup the data source */
     ioDevice.locatorType = SL_DATALOCATOR_IODEVICE;
@@ -164,11 +169,32 @@ void TestRecToBuffQueue( SLObjectItf sl, const char* path, SLAint64 durationInSe
     recDest.pFormat = (void * ) &pcm;
 
     /* Create the audio recorder */
-    result = (*EngineItf)->CreateAudioRecorder(EngineItf, &recorder, &recSource, &recDest, 1,
-            iidArray, required);
+    result = (*EngineItf)->CreateAudioRecorder(EngineItf, &recorder, &recSource, &recDest,
+            NUM_EXPLICIT_INTERFACES_FOR_RECORDER, iidArray, required);
     ExitOnError(result);
     fprintf(stdout, "Recorder created\n");
 
+    /* Get the Android configuration interface which is explicit */
+    result = (*recorder)->GetInterface(recorder, SL_IID_ANDROIDCONFIGURATION, (void*)&configItf);
+    ExitOnError(result);
+
+    /* Use the configuration interface to configure the recorder before it's realized */
+    SLuint32 presetValue = SL_ANDROID_RECORDING_PRESET_CAMCORDER;
+    result = (*configItf)->SetConfiguration(configItf, SL_ANDROID_KEY_RECORDING_PRESET,
+            &presetValue, sizeof(SLuint32));
+    ExitOnError(result);
+    fprintf(stdout, "Recorder parametrized\n");
+
+    presetValue = SL_ANDROID_RECORDING_PRESET_NONE;
+    SLuint32 presetSize = 2*sizeof(SLuint32); // intentionally too big
+    result = (*configItf)->GetConfiguration(configItf, SL_ANDROID_KEY_RECORDING_PRESET,
+            &presetSize, (void*)&presetValue);
+    ExitOnError(result);
+    if (presetValue != SL_ANDROID_RECORDING_PRESET_CAMCORDER) {
+        fprintf(stderr, "Error retrieved recording preset\n");
+        ExitOnError(SL_RESULT_INTERNAL_ERROR);
+    }
+
     /* Realize the recorder in synchronous mode. */
     result = (*recorder)->Realize(recorder, SL_BOOLEAN_FALSE);
     ExitOnError(result);