diff options
author | Eric Laurent <elaurent@google.com> | 2011-07-24 13:36:09 -0700 |
---|---|---|
committer | Eric Laurent <elaurent@google.com> | 2011-07-25 14:39:00 -0700 |
commit | 0f7f4ece1b6b73caf608d533d833a8cdc11c8131 (patch) | |
tree | 0f8a57676ec5ac53b22594b5f754a6216c720651 | |
parent | 84e35d995f0b804a322e9e07fd1a0341658763ef (diff) | |
download | frameworks_base-0f7f4ece1b6b73caf608d533d833a8cdc11c8131.zip frameworks_base-0f7f4ece1b6b73caf608d533d833a8cdc11c8131.tar.gz frameworks_base-0f7f4ece1b6b73caf608d533d833a8cdc11c8131.tar.bz2 |
Added APIs for audio preprocessing
Added APIs to control pre processes applied on captured audio.
Those APIs are still hidden until reviewed by API council.
Three types of standard pre processes are supported:
- Automatic Gain Control (AGC) by AutomaticGainControl class
- Acoustic Echo Cancellation (AEC) by AcousticEchoCanceler class
- Noise Suppression (NS) by NoiseSuppressor class
A method is added to AudioEffect class to query audio pre processings
applied by default by the platform on a given AudioRecord session ID.
Change-Id: I0b9fceeb8c704dd06319c3b52b85c96fe871d51d
-rw-r--r-- | include/media/AudioEffect.h | 31 | ||||
-rw-r--r-- | include/media/IAudioPolicyService.h | 3 | ||||
-rw-r--r-- | media/java/android/media/audiofx/AcousticEchoCanceler.java | 67 | ||||
-rw-r--r-- | media/java/android/media/audiofx/AudioEffect.java | 53 | ||||
-rw-r--r-- | media/java/android/media/audiofx/AutomaticGainControl.java | 67 | ||||
-rw-r--r-- | media/java/android/media/audiofx/NoiseSuppressor.java | 68 | ||||
-rw-r--r-- | media/jni/audioeffect/android_media_AudioEffect.cpp | 99 | ||||
-rw-r--r-- | media/libmedia/AudioEffect.cpp | 9 | ||||
-rw-r--r-- | media/libmedia/IAudioPolicyService.cpp | 49 | ||||
-rw-r--r-- | services/audioflinger/AudioPolicyService.cpp | 37 | ||||
-rw-r--r-- | services/audioflinger/AudioPolicyService.h | 3 |
11 files changed, 477 insertions, 9 deletions
diff --git a/include/media/AudioEffect.h b/include/media/AudioEffect.h index 496b23e..1417416 100644 --- a/include/media/AudioEffect.h +++ b/include/media/AudioEffect.h @@ -21,6 +21,7 @@ #include <sys/types.h> #include <media/IAudioFlinger.h> +#include <media/IAudioPolicyService.h> #include <media/IEffect.h> #include <media/IEffectClient.h> #include <hardware/audio_effect.h> @@ -111,6 +112,36 @@ public: /* + * Returns a list of descriptors corresponding to the pre processings enabled by default + * on an AudioRecord with the supplied audio session ID. + * + * Parameters: + * audioSession: audio session ID. + * descriptors: address where the effect descriptors should be returned. + * count: as input, the maximum number of descriptor than should be returned + * as output, the number of descriptor returned if status is NO_ERROR or the actual + * number of enabled pre processings if status is NO_MEMORY + * + * Returned status (from utils/Errors.h) can be: + * NO_ERROR successful operation. + * NO_MEMORY the number of descriptor to return is more than the maximum number + * indicated by count. + * PERMISSION_DENIED could not get AudioFlinger interface + * NO_INIT effect library failed to initialize + * BAD_VALUE invalid audio session or descriptor pointers + * + * Returned value + * *descriptor updated with descriptors of pre processings enabled by default + * *count number of descriptors returned if returned status is N_ERROR. + * total number of pre processing enabled by default if returned status is + * NO_MEMORY. This happens if the count passed as input is less than the number + * of descriptors to return + */ + static status_t queryDefaultPreProcessing(int audioSession, + effect_descriptor_t *descriptors, + uint32_t *count); + + /* * Events used by callback function (effect_callback_t). */ enum event_type { diff --git a/include/media/IAudioPolicyService.h b/include/media/IAudioPolicyService.h index 86b9f85..ed265e1 100644 --- a/include/media/IAudioPolicyService.h +++ b/include/media/IAudioPolicyService.h @@ -85,6 +85,9 @@ public: int id) = 0; virtual status_t unregisterEffect(int id) = 0; virtual bool isStreamActive(int stream, uint32_t inPastMs = 0) const = 0; + virtual status_t queryDefaultPreProcessing(int audioSession, + effect_descriptor_t *descriptors, + uint32_t *count) = 0; }; diff --git a/media/java/android/media/audiofx/AcousticEchoCanceler.java b/media/java/android/media/audiofx/AcousticEchoCanceler.java new file mode 100644 index 0000000..7197dd2 --- /dev/null +++ b/media/java/android/media/audiofx/AcousticEchoCanceler.java @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2011 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. + */ + +package android.media.audiofx; + +/** + * Acoustic Echo Canceler (AEC). + * <p>Acoustic Echo Canceler (AEC) is an audio pre-processing which removes the contribution of the + * signal received from the remote party from the captured audio signal. + * <p>AEC is used by voice communication applications (voice chat, video conferencing, SIP calls) + * where the presence of echo with significant delay in the signal received from the remote party + * is highly disturbing. AEC is often used in conjunction with noise suppression (NS). + * <p>An application creates an AcousticEchoCanceler object to instantiate and control an AEC + * engine in the audio capture path. + * <p>To attach the AcousticEchoCanceler to a particular {@link android.media.AudioRecord}, + * specify the audio session ID of this AudioRecord when constructing the AcousticEchoCanceler. + * The audio session is retrieved by calling + * {@link android.media.AudioRecord#getAudioSessionId()} on the AudioRecord instance. + * <p>On some devices, an AEC can be inserted by default in the capture path by the platform + * according to the {@link android.media.MediaRecorder.AudioSource} used. The application can + * query which pre-processings are currently applied to an AudioRecord instance by calling + * {@link android.media.audiofx.AudioEffect#queryPreProcessings(int)} with the audio session of the + * AudioRecord. + * <p>See {@link android.media.audiofx.AudioEffect} class for more details on + * controlling audio effects. + * @hide + */ + +public class AcousticEchoCanceler extends AudioEffect { + + private final static String TAG = "AcousticEchoCanceler"; + + /** + * Class constructor. + * <p> The application must catch exceptions when creating an AcousticEchoCanceler as the + * constructor is not guarantied to succeed: + * <ul> + * <li>IllegalArgumentException is thrown if the device does not implement an AEC</li> + * <li>UnsupportedOperationException is thrown is the resources allocated to audio + * pre-procesing are currently exceeded.</li> + * </ul> + * + * @param audioSession system wide unique audio session identifier. The AcousticEchoCanceler + * will be applied to the AudioRecord with the same audio session. + * + * @throws java.lang.IllegalArgumentException + * @throws java.lang.UnsupportedOperationException + * @throws java.lang.RuntimeException + */ + public AcousticEchoCanceler(int audioSession) + throws IllegalArgumentException, UnsupportedOperationException, RuntimeException { + super(EFFECT_TYPE_AEC, EFFECT_TYPE_NULL, 0, audioSession); + } +} diff --git a/media/java/android/media/audiofx/AudioEffect.java b/media/java/android/media/audiofx/AudioEffect.java index 39c6d3e..3ac0104 100644 --- a/media/java/android/media/audiofx/AudioEffect.java +++ b/media/java/android/media/audiofx/AudioEffect.java @@ -66,6 +66,8 @@ public class AudioEffect { private final static String TAG = "AudioEffect-JAVA"; + // effect type UUIDs are taken from hardware/libhardware/include/hardware/audio_effect.h + /** * The following UUIDs define effect types corresponding to standard audio * effects whose implementation and interface conform to the OpenSL ES @@ -105,6 +107,27 @@ public class AudioEffect { .fromString("37cc2c00-dddd-11db-8577-0002a5d5c51b"); /** + * UUID for Automatic Gain Control (AGC) audio pre-processing + * @hide + */ + public static final UUID EFFECT_TYPE_AGC = UUID + .fromString("0a8abfe0-654c-11e0-ba26-0002a5d5c51b"); + + /** + * UUID for Acoustic Echo Canceler (AEC) audio pre-processing + * @hide + */ + public static final UUID EFFECT_TYPE_AEC = UUID + .fromString("7b491460-8d4d-11e0-bd61-0002a5d5c51b"); + + /** + * UUID for Noise Suppressor (NS) audio pre-processing + * @hide + */ + public static final UUID EFFECT_TYPE_NS = UUID + .fromString("58b4b260-8e06-11e0-aa8e-0002a5d5c51b"); + + /** * Null effect UUID. Used when the UUID for effect type of * @hide */ @@ -180,7 +203,8 @@ public class AudioEffect { * <ul> * <li>type: UUID corresponding to the OpenSL ES interface implemented by this effect</li> * <li>uuid: UUID for this particular implementation</li> - * <li>connectMode: {@link #EFFECT_INSERT} or {@link #EFFECT_AUXILIARY}</li> + * <li>connectMode: {@link #EFFECT_INSERT}, {@link #EFFECT_AUXILIARY} or + * {at_link #EFFECT_PRE_PROCESSING}</li> * <li>name: human readable effect name</li> * <li>implementor: human readable effect implementor name</li> * </ul> @@ -212,11 +236,13 @@ public class AudioEffect { */ public UUID uuid; /** - * Indicates if the effect is of insert category {@link #EFFECT_INSERT} or auxiliary - * category {@link #EFFECT_AUXILIARY}. Insert effects (Typically an Equalizer) are applied + * Indicates if the effect is of insert category {@link #EFFECT_INSERT}, auxiliary + * category {@link #EFFECT_AUXILIARY} or pre processing category + * {at_link #EFFECT_PRE_PROCESSING}. Insert effects (Typically an Equalizer) are applied * to the entire audio source and usually not shared by several sources. Auxiliary effects * (typically a reverberator) are applied to part of the signal (wet) and the effect output * is added to the original signal (dry). + * Audio pre processing are applied to audio captured on a particular AudioRecord. */ public String connectMode; /** @@ -243,6 +269,12 @@ public class AudioEffect { * attaching it to the MediaPlayer or AudioTrack. */ public static final String EFFECT_AUXILIARY = "Auxiliary"; + /** + * Effect connection mode is pre processing. + * The audio pre processing effects are attached to an audio input (AudioRecord). + * @hide + */ + public static final String EFFECT_PRE_PROCESSING = "Pre Processing"; // -------------------------------------------------------------------------- // Member variables @@ -410,6 +442,19 @@ public class AudioEffect { return (Descriptor[]) native_query_effects(); } + /** + * Query all audio pre processing effects applied to the AudioRecord with the supplied + * audio session ID. Returns an array of {@link android.media.audiofx.AudioEffect.Descriptor} + * objects. + * @param audioSession system wide unique audio session identifier. + * @throws IllegalStateException + * @hide + */ + + static public Descriptor[] queryPreProcessings(int audioSession) { + return (Descriptor[]) native_query_pre_processing(audioSession); + } + // -------------------------------------------------------------------------- // Control methods // -------------------- @@ -1155,6 +1200,8 @@ public class AudioEffect { private static native Object[] native_query_effects(); + private static native Object[] native_query_pre_processing(int audioSession); + // --------------------------------------------------------- // Utility methods // ------------------ diff --git a/media/java/android/media/audiofx/AutomaticGainControl.java b/media/java/android/media/audiofx/AutomaticGainControl.java new file mode 100644 index 0000000..44574f0 --- /dev/null +++ b/media/java/android/media/audiofx/AutomaticGainControl.java @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2011 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. + */ + +package android.media.audiofx; + +/** + * Automatic Gain Control (AGC). + * <p>Automatic Gain Control (AGC) is an audio pre-processing which automatically normalizes the + * output of the captured signal by boosting or lowering input from the microphone to match a preset + * level so that that the output signal level is virtually constant. + * AGC can be used by applications where the input signal dynamic range is not important but where + * a constant strong capture level is desired. + * <p>An application creates a AutomaticGainControl object to instantiate and control an AGC + * engine in the audio framework. + * <p>To attach the AutomaticGainControl to a particular {@link android.media.AudioRecord}, + * specify the audio session ID of this AudioRecord when constructing the AutomaticGainControl. + * The audio session is retrieved by calling + * {@link android.media.AudioRecord#getAudioSessionId()} on the AudioRecord instance. + * <p>On some devices, an AGC can be inserted by default in the capture path by the platform + * according to the {@link android.media.MediaRecorder.AudioSource} used. The application can + * query which pre-processings are currently applied to an AudioRecord instance by calling + * {@link android.media.audiofx.AudioEffect#queryPreProcessings(int)} with the audio session of the + * AudioRecord. + * <p>See {@link android.media.audiofx.AudioEffect} class for more details on + * controlling audio effects. + * @hide + */ + +public class AutomaticGainControl extends AudioEffect { + + private final static String TAG = "AutomaticGainControl"; + + /** + * Class constructor. + * <p> The application must catch exceptions when creating an AutomaticGainControl as the + * constructor is not guarantied to succeed: + * <ul> + * <li>IllegalArgumentException is thrown if the device does not implement an AGC</li> + * <li>UnsupportedOperationException is thrown is the resources allocated to audio + * pre-procesing are currently exceeded.</li> + * </ul> + * + * @param audioSession system wide unique audio session identifier. The AutomaticGainControl + * will be applied to the AudioRecord with the same audio session. + * + * @throws java.lang.IllegalArgumentException + * @throws java.lang.UnsupportedOperationException + * @throws java.lang.RuntimeException + */ + public AutomaticGainControl(int audioSession) + throws IllegalArgumentException, UnsupportedOperationException, RuntimeException { + super(EFFECT_TYPE_AGC, EFFECT_TYPE_NULL, 0, audioSession); + } +} diff --git a/media/java/android/media/audiofx/NoiseSuppressor.java b/media/java/android/media/audiofx/NoiseSuppressor.java new file mode 100644 index 0000000..4e7a8b6 --- /dev/null +++ b/media/java/android/media/audiofx/NoiseSuppressor.java @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2011 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. + */ + +package android.media.audiofx; + +/** + * Noise Suppressor (NS). + * <p>Noise suppression (NS) is an audio pre-processing which removes background noise from the + * captured signal. The component of the signal considered as noise can be either stationary + * (car/airplane engine, AC system) or non-stationary (other peoples conversations, car horn) for + * more advanced implementations. + * <p>NS is mostly used by voice communication applications (voice chat, video conferencing, + * SIP calls). + * <p>An application creates a NoiseSuppressor object to instantiate and control an NS + * engine in the audio framework. + * <p>To attach the NoiseSuppressor to a particular {@link android.media.AudioRecord}, + * specify the audio session ID of this AudioRecord when constructing the NoiseSuppressor. + * The audio session is retrieved by calling + * {@link android.media.AudioRecord#getAudioSessionId()} on the AudioRecord instance. + * <p>On some devices, NS can be inserted by default in the capture path by the platform + * according to the {@link android.media.MediaRecorder.AudioSource} used. The application can + * query which pre-processings are currently applied to an AudioRecord instance by calling + * {@link android.media.audiofx.AudioEffect#queryPreProcessings(int)} with the audio session of the + * AudioRecord. + * <p>See {@link android.media.audiofx.AudioEffect} class for more details on + * controlling audio effects. + * @hide + */ + +public class NoiseSuppressor extends AudioEffect { + + private final static String TAG = "NoiseSuppressor"; + + /** + * Class constructor. + * <p> The application must catch exceptions when creating an NoiseSuppressor as the + * constructor is not guarantied to succeed: + * <ul> + * <li>IllegalArgumentException is thrown if the device does not implement an NS</li> + * <li>UnsupportedOperationException is thrown is the resources allocated to audio + * pre-procesing are currently exceeded.</li> + * </ul> + * + * @param audioSession system wide unique audio session identifier. The NoiseSuppressor + * will be applied to the AudioRecord with the same audio session. + * + * @throws java.lang.IllegalArgumentException + * @throws java.lang.UnsupportedOperationException + * @throws java.lang.RuntimeException + */ + public NoiseSuppressor(int audioSession) + throws IllegalArgumentException, UnsupportedOperationException, RuntimeException { + super(EFFECT_TYPE_NS, EFFECT_TYPE_NULL, 0, audioSession); + } +} diff --git a/media/jni/audioeffect/android_media_AudioEffect.cpp b/media/jni/audioeffect/android_media_AudioEffect.cpp index e71e727..57cabe2 100644 --- a/media/jni/audioeffect/android_media_AudioEffect.cpp +++ b/media/jni/audioeffect/android_media_AudioEffect.cpp @@ -725,18 +725,22 @@ android_media_AudioEffect_native_queryEffects(JNIEnv *env, jclass clazz) goto queryEffects_failure; } + if ((desc.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) { + jdescConnect = env->NewStringUTF("Auxiliary"); + } else if ((desc.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_INSERT) { + jdescConnect = env->NewStringUTF("Insert"); + } else if ((desc.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_PRE_PROC) { + jdescConnect = env->NewStringUTF("Pre Processing"); + } else { + continue; + } + AudioEffect::guidToString(&desc.type, str, EFFECT_STRING_LEN_MAX); jdescType = env->NewStringUTF(str); AudioEffect::guidToString(&desc.uuid, str, EFFECT_STRING_LEN_MAX); jdescUuid = env->NewStringUTF(str); - if ((desc.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) { - jdescConnect = env->NewStringUTF("Auxiliary"); - } else { - jdescConnect = env->NewStringUTF("Insert"); - } - jdescName = env->NewStringUTF(desc.name); jdescImplementor = env->NewStringUTF(desc.implementor); @@ -771,6 +775,87 @@ queryEffects_failure: } + + +static jobjectArray +android_media_AudioEffect_native_queryPreProcessings(JNIEnv *env, jclass clazz, jint audioSession) +{ + // kDefaultNumEffects is a "reasonable" value ensuring that only one query will be enough on + // most devices to get all active audio pre processing on a given session. + static const uint32_t kDefaultNumEffects = 5; + + effect_descriptor_t *descriptors = new effect_descriptor_t[kDefaultNumEffects]; + uint32_t numEffects = kDefaultNumEffects; + + status_t status = AudioEffect::queryDefaultPreProcessing(audioSession, + descriptors, + &numEffects); + if ((status != NO_ERROR && status != NO_MEMORY) || + numEffects == 0) { + delete[] descriptors; + return NULL; + } + if (status == NO_MEMORY) { + delete [] descriptors; + descriptors = new effect_descriptor_t[numEffects]; + status = AudioEffect::queryDefaultPreProcessing(audioSession, + descriptors, + &numEffects); + } + if (status != NO_ERROR || numEffects == 0) { + delete[] descriptors; + return NULL; + } + LOGV("queryDefaultPreProcessing() got %d effects", numEffects); + + jobjectArray ret = env->NewObjectArray(numEffects, fields.clazzDesc, NULL); + if (ret == NULL) { + delete[] descriptors; + return ret; + } + + char str[EFFECT_STRING_LEN_MAX]; + jstring jdescType; + jstring jdescUuid; + jstring jdescConnect; + jstring jdescName; + jstring jdescImplementor; + jobject jdesc; + + for (uint32_t i = 0; i < numEffects; i++) { + + AudioEffect::guidToString(&descriptors[i].type, str, EFFECT_STRING_LEN_MAX); + jdescType = env->NewStringUTF(str); + AudioEffect::guidToString(&descriptors[i].uuid, str, EFFECT_STRING_LEN_MAX); + jdescUuid = env->NewStringUTF(str); + jdescConnect = env->NewStringUTF("Pre Processing"); + jdescName = env->NewStringUTF(descriptors[i].name); + jdescImplementor = env->NewStringUTF(descriptors[i].implementor); + + jdesc = env->NewObject(fields.clazzDesc, + fields.midDescCstor, + jdescType, + jdescUuid, + jdescConnect, + jdescName, + jdescImplementor); + env->DeleteLocalRef(jdescType); + env->DeleteLocalRef(jdescUuid); + env->DeleteLocalRef(jdescConnect); + env->DeleteLocalRef(jdescName); + env->DeleteLocalRef(jdescImplementor); + if (jdesc == NULL) { + LOGE("env->NewObject(fields.clazzDesc, fields.midDescCstor)"); + env->DeleteLocalRef(ret); + return NULL;; + } + + env->SetObjectArrayElement(ret, i, jdesc); + } + + return ret; +} + // ---------------------------------------------------------------------------- // Dalvik VM type signatures @@ -787,6 +872,8 @@ static JNINativeMethod gMethods[] = { {"native_getParameter", "(I[BI[B)I", (void *)android_media_AudioEffect_native_getParameter}, {"native_command", "(II[BI[B)I", (void *)android_media_AudioEffect_native_command}, {"native_query_effects", "()[Ljava/lang/Object;", (void *)android_media_AudioEffect_native_queryEffects}, + {"native_query_pre_processing", "(I)[Ljava/lang/Object;", + (void *)android_media_AudioEffect_native_queryPreProcessings}, }; diff --git a/media/libmedia/AudioEffect.cpp b/media/libmedia/AudioEffect.cpp index 3919551..0633744 100644 --- a/media/libmedia/AudioEffect.cpp +++ b/media/libmedia/AudioEffect.cpp @@ -419,6 +419,15 @@ status_t AudioEffect::getEffectDescriptor(effect_uuid_t *uuid, effect_descriptor return af->getEffectDescriptor(uuid, descriptor); } + +status_t AudioEffect::queryDefaultPreProcessing(int audioSession, + effect_descriptor_t *descriptors, + uint32_t *count) +{ + const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service(); + if (aps == 0) return PERMISSION_DENIED; + return aps->queryDefaultPreProcessing(audioSession, descriptors, count); +} // ------------------------------------------------------------------------- status_t AudioEffect::stringToGuid(const char *str, effect_uuid_t *guid) diff --git a/media/libmedia/IAudioPolicyService.cpp b/media/libmedia/IAudioPolicyService.cpp index 49d410f..15f4be0 100644 --- a/media/libmedia/IAudioPolicyService.cpp +++ b/media/libmedia/IAudioPolicyService.cpp @@ -53,6 +53,7 @@ enum { UNREGISTER_EFFECT, IS_STREAM_ACTIVE, GET_DEVICES_FOR_STREAM, + QUERY_DEFAULT_PRE_PROCESSING }; class BpAudioPolicyService : public BpInterface<IAudioPolicyService> @@ -321,6 +322,31 @@ public: remote()->transact(IS_STREAM_ACTIVE, data, &reply); return reply.readInt32(); } + + virtual status_t queryDefaultPreProcessing(int audioSession, + effect_descriptor_t *descriptors, + uint32_t *count) + { + if (descriptors == NULL || count == NULL) { + return BAD_VALUE; + } + Parcel data, reply; + data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor()); + data.writeInt32(audioSession); + data.writeInt32(*count); + status_t status = remote()->transact(QUERY_DEFAULT_PRE_PROCESSING, data, &reply); + if (status != NO_ERROR) { + return status; + } + status = static_cast <status_t> (reply.readInt32()); + uint32_t retCount = reply.readInt32(); + if (retCount != 0) { + uint32_t numDesc = (retCount < *count) ? retCount : *count; + reply.read(descriptors, sizeof(effect_descriptor_t) * numDesc); + } + *count = retCount; + return status; + } }; IMPLEMENT_META_INTERFACE(AudioPolicyService, "android.media.IAudioPolicyService"); @@ -559,6 +585,29 @@ status_t BnAudioPolicyService::onTransact( return NO_ERROR; } break; + case QUERY_DEFAULT_PRE_PROCESSING: { + CHECK_INTERFACE(IAudioPolicyService, data, reply); + int audioSession = data.readInt32(); + uint32_t count = data.readInt32(); + uint32_t retCount = count; + effect_descriptor_t *descriptors = + (effect_descriptor_t *)new char[count * sizeof(effect_descriptor_t)]; + status_t status = queryDefaultPreProcessing(audioSession, descriptors, &retCount); + reply->writeInt32(status); + if (status != NO_ERROR && status != NO_MEMORY) { + retCount = 0; + } + reply->writeInt32(retCount); + if (retCount) { + if (retCount < count) { + count = retCount; + } + reply->write(descriptors, sizeof(effect_descriptor_t) * count); + } + delete[] descriptors; + return status; + } + default: return BBinder::onTransact(code, data, reply, flags); } diff --git a/services/audioflinger/AudioPolicyService.cpp b/services/audioflinger/AudioPolicyService.cpp index dd1e153..6d06d83 100644 --- a/services/audioflinger/AudioPolicyService.cpp +++ b/services/audioflinger/AudioPolicyService.cpp @@ -497,6 +497,43 @@ bool AudioPolicyService::isStreamActive(int stream, uint32_t inPastMs) const return mpAudioPolicy->is_stream_active(mpAudioPolicy, stream, inPastMs); } +status_t AudioPolicyService::queryDefaultPreProcessing(int audioSession, + effect_descriptor_t *descriptors, + uint32_t *count) +{ + + if (mpAudioPolicy == NULL) { + *count = 0; + return NO_INIT; + } + Mutex::Autolock _l(mLock); + status_t status = NO_ERROR; + + size_t index; + for (index = 0; index < mInputs.size(); index++) { + if (mInputs.valueAt(index)->mSessionId == audioSession) { + break; + } + } + if (index == mInputs.size()) { + *count = 0; + return BAD_VALUE; + } + Vector< sp<AudioEffect> > effects = mInputs.valueAt(index)->mEffects; + + for (size_t i = 0; i < effects.size(); i++) { + effect_descriptor_t desc = effects[i]->descriptor(); + if (i < *count) { + memcpy(descriptors + i, &desc, sizeof(effect_descriptor_t)); + } + } + if (effects.size() > *count) { + status = NO_MEMORY; + } + *count = effects.size(); + return status; +} + void AudioPolicyService::binderDied(const wp<IBinder>& who) { LOGW("binderDied() %p, tid %d, calling tid %d", who.unsafe_get(), gettid(), IPCThreadState::self()->getCallingPid()); diff --git a/services/audioflinger/AudioPolicyService.h b/services/audioflinger/AudioPolicyService.h index 62ad29e..834b794 100644 --- a/services/audioflinger/AudioPolicyService.h +++ b/services/audioflinger/AudioPolicyService.h @@ -104,6 +104,9 @@ public: virtual status_t unregisterEffect(int id); virtual bool isStreamActive(int stream, uint32_t inPastMs = 0) const; + virtual status_t queryDefaultPreProcessing(int audioSession, + effect_descriptor_t *descriptors, + uint32_t *count); virtual status_t onTransact( uint32_t code, const Parcel& data, |