diff options
author | Eric Laurent <elaurent@google.com> | 2011-07-25 14:43:05 -0700 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2011-07-25 14:43:05 -0700 |
commit | 234cef81299688db75edb6572e37374a67f79bbc (patch) | |
tree | 3fa3964aa740ef9c81204f995fd780dcfe6244e6 | |
parent | fb526513056eb275a8ad7ff7998e2e56be8fd467 (diff) | |
parent | 0f7f4ece1b6b73caf608d533d833a8cdc11c8131 (diff) | |
download | frameworks_base-234cef81299688db75edb6572e37374a67f79bbc.zip frameworks_base-234cef81299688db75edb6572e37374a67f79bbc.tar.gz frameworks_base-234cef81299688db75edb6572e37374a67f79bbc.tar.bz2 |
Merge "Added APIs for audio preprocessing"
-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, |