Loading api/current.txt +4 −0 Original line number Original line Diff line number Diff line Loading @@ -23462,10 +23462,14 @@ package android.media { public final class AudioRecordingConfiguration implements android.os.Parcelable { public final class AudioRecordingConfiguration implements android.os.Parcelable { method public int describeContents(); method public int describeContents(); method public android.media.AudioDeviceInfo getAudioDevice(); method public android.media.AudioDeviceInfo getAudioDevice(); method public int getAudioSource(); method public int getClientAudioSessionId(); method public int getClientAudioSessionId(); method public int getClientAudioSource(); method public int getClientAudioSource(); method public java.util.List<android.media.audiofx.AudioEffect.Descriptor> getClientEffects(); method public android.media.AudioFormat getClientFormat(); method public android.media.AudioFormat getClientFormat(); method public java.util.List<android.media.audiofx.AudioEffect.Descriptor> getEffects(); method public android.media.AudioFormat getFormat(); method public android.media.AudioFormat getFormat(); method public boolean isClientSilenced(); method public void writeToParcel(android.os.Parcel, int); method public void writeToParcel(android.os.Parcel, int); field public static final android.os.Parcelable.Creator<android.media.AudioRecordingConfiguration> CREATOR; field public static final android.os.Parcelable.Creator<android.media.AudioRecordingConfiguration> CREATOR; } } api/test-current.txt +5 −0 Original line number Original line Diff line number Diff line Loading @@ -638,6 +638,11 @@ package android.media { method public static boolean isEncodingLinearPcm(int); method public static boolean isEncodingLinearPcm(int); } } public final class AudioRecordingConfiguration implements android.os.Parcelable { ctor public AudioRecordingConfiguration(int, int, int, android.media.AudioFormat, android.media.AudioFormat, int, java.lang.String, int, boolean, int, android.media.audiofx.AudioEffect.Descriptor[], android.media.audiofx.AudioEffect.Descriptor[]); ctor public AudioRecordingConfiguration(int, int, int, android.media.AudioFormat, android.media.AudioFormat, int, java.lang.String); } public final class BufferingParams implements android.os.Parcelable { public final class BufferingParams implements android.os.Parcelable { method public int describeContents(); method public int describeContents(); method public int getInitialMarkMs(); method public int getInitialMarkMs(); Loading core/jni/android_media_AudioSystem.cpp +23 −7 Original line number Original line Diff line number Diff line Loading @@ -32,6 +32,7 @@ #include <nativehelper/ScopedLocalRef.h> #include <nativehelper/ScopedLocalRef.h> #include <system/audio.h> #include <system/audio.h> #include <system/audio_policy.h> #include <system/audio_policy.h> #include "android_media_AudioEffectDescriptor.h" #include "android_media_AudioFormat.h" #include "android_media_AudioFormat.h" #include "android_media_AudioErrors.h" #include "android_media_AudioErrors.h" #include "android_media_MicrophoneInfo.h" #include "android_media_MicrophoneInfo.h" Loading Loading @@ -427,9 +428,14 @@ android_media_AudioSystem_dyn_policy_callback(int event, String8 regId, int val) } } static void static void android_media_AudioSystem_recording_callback(int event, const record_client_info_t *clientInfo, android_media_AudioSystem_recording_callback(int event, const audio_config_base_t *clientConfig, const audio_config_base_t *deviceConfig, const record_client_info_t *clientInfo, audio_patch_handle_t patchHandle) const audio_config_base_t *clientConfig, std::vector<effect_descriptor_t> clientEffects, const audio_config_base_t *deviceConfig, std::vector<effect_descriptor_t> effects __unused, audio_patch_handle_t patchHandle, audio_source_t source) { { JNIEnv *env = AndroidRuntime::getJNIEnv(); JNIEnv *env = AndroidRuntime::getJNIEnv(); if (env == NULL) { if (env == NULL) { Loading Loading @@ -460,14 +466,24 @@ android_media_AudioSystem_recording_callback(int event, const record_client_info recParamData[6] = (jint) patchHandle; recParamData[6] = (jint) patchHandle; env->SetIntArrayRegion(recParamArray, 0, REC_PARAM_SIZE, recParamData); env->SetIntArrayRegion(recParamArray, 0, REC_PARAM_SIZE, recParamData); jobjectArray jClientEffects; convertAudioEffectDescriptorVectorFromNative(env, &jClientEffects, clientEffects); jobjectArray jEffects; convertAudioEffectDescriptorVectorFromNative(env, &jEffects, effects); // callback into java // callback into java jclass clazz = env->FindClass(kClassPathName); jclass clazz = env->FindClass(kClassPathName); env->CallStaticVoidMethod(clazz, env->CallStaticVoidMethod(clazz, gAudioPolicyEventHandlerMethods.postRecordConfigEventFromNative, gAudioPolicyEventHandlerMethods.postRecordConfigEventFromNative, event, (jint) clientInfo->uid, clientInfo->session, clientInfo->source, recParamArray); event, (jint) clientInfo->uid, clientInfo->session, clientInfo->source, clientInfo->port_id, clientInfo->silenced, recParamArray, jClientEffects, jEffects, source); env->DeleteLocalRef(clazz); env->DeleteLocalRef(clazz); env->DeleteLocalRef(recParamArray); env->DeleteLocalRef(recParamArray); env->DeleteLocalRef(jClientEffects); env->DeleteLocalRef(jEffects); } } static jint static jint Loading Loading @@ -2260,7 +2276,7 @@ int register_android_media_AudioSystem(JNIEnv *env) "dynamicPolicyCallbackFromNative", "(ILjava/lang/String;I)V"); "dynamicPolicyCallbackFromNative", "(ILjava/lang/String;I)V"); gAudioPolicyEventHandlerMethods.postRecordConfigEventFromNative = gAudioPolicyEventHandlerMethods.postRecordConfigEventFromNative = GetStaticMethodIDOrDie(env, env->FindClass(kClassPathName), GetStaticMethodIDOrDie(env, env->FindClass(kClassPathName), "recordingCallbackFromNative", "(IIII[I)V"); "recordingCallbackFromNative", "(IIIIIZ[I[Landroid/media/audiofx/AudioEffect$Descriptor;[Landroid/media/audiofx/AudioEffect$Descriptor;I)V"); jclass audioMixClass = FindClassOrDie(env, "android/media/audiopolicy/AudioMix"); jclass audioMixClass = FindClassOrDie(env, "android/media/audiopolicy/AudioMix"); gAudioMixClass = MakeGlobalRefOrDie(env, audioMixClass); gAudioMixClass = MakeGlobalRefOrDie(env, audioMixClass); Loading media/java/android/media/AudioRecordingConfiguration.java +144 −24 Original line number Original line Diff line number Diff line Loading @@ -18,7 +18,9 @@ package android.media; import android.annotation.IntDef; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.NonNull; import android.annotation.TestApi; import android.annotation.UnsupportedAppUsage; import android.annotation.UnsupportedAppUsage; import android.media.audiofx.AudioEffect; import android.os.Parcel; import android.os.Parcel; import android.os.Parcelable; import android.os.Parcelable; import android.util.Log; import android.util.Log; Loading @@ -27,6 +29,8 @@ import java.io.PrintWriter; import java.lang.annotation.Retention; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Objects; import java.util.Objects; /** /** Loading @@ -48,7 +52,7 @@ import java.util.Objects; public final class AudioRecordingConfiguration implements Parcelable { public final class AudioRecordingConfiguration implements Parcelable { private final static String TAG = new String("AudioRecordingConfiguration"); private final static String TAG = new String("AudioRecordingConfiguration"); private final int mSessionId; private final int mClientSessionId; private final int mClientSource; private final int mClientSource; Loading @@ -60,18 +64,50 @@ public final class AudioRecordingConfiguration implements Parcelable { private final int mPatchHandle; private final int mPatchHandle; private final int mClientPortId; private boolean mClientSilenced; private final int mDeviceSource; private final AudioEffect.Descriptor[] mClientEffects; private final AudioEffect.Descriptor[] mDeviceEffects; /** /** * @hide * @hide */ */ @TestApi public AudioRecordingConfiguration(int uid, int session, int source, AudioFormat clientFormat, public AudioRecordingConfiguration(int uid, int session, int source, AudioFormat clientFormat, AudioFormat devFormat, int patchHandle, String packageName) { AudioFormat devFormat, int patchHandle, String packageName, int clientPortId, boolean clientSilenced, int deviceSource, AudioEffect.Descriptor[] clientEffects, AudioEffect.Descriptor[] deviceEffects) { mClientUid = uid; mClientUid = uid; mSessionId = session; mClientSessionId = session; mClientSource = source; mClientSource = source; mClientFormat = clientFormat; mClientFormat = clientFormat; mDeviceFormat = devFormat; mDeviceFormat = devFormat; mPatchHandle = patchHandle; mPatchHandle = patchHandle; mClientPackageName = packageName; mClientPackageName = packageName; mClientPortId = clientPortId; mClientSilenced = clientSilenced; mDeviceSource = deviceSource; mClientEffects = clientEffects; mDeviceEffects = deviceEffects; } /** * @hide */ @TestApi public AudioRecordingConfiguration(int uid, int session, int source, AudioFormat clientFormat, AudioFormat devFormat, int patchHandle, String packageName) { this(uid, session, source, clientFormat, devFormat, patchHandle, packageName, 0 /*clientPortId*/, false /*clientSilenced*/, MediaRecorder.AudioSource.DEFAULT /*deviceSource*/, new AudioEffect.Descriptor[0] /*clientEffects*/, new AudioEffect.Descriptor[0] /*deviceEffects*/); } } /** /** Loading @@ -87,13 +123,26 @@ public final class AudioRecordingConfiguration implements Parcelable { * @hide * @hide */ */ public static String toLogFriendlyString(AudioRecordingConfiguration arc) { public static String toLogFriendlyString(AudioRecordingConfiguration arc) { return new String("session:" + arc.mSessionId String clientEffects = new String(); + " -- source:" + MediaRecorder.toLogFriendlyAudioSource(arc.mClientSource) for (AudioEffect.Descriptor desc : arc.mClientEffects) { clientEffects += "'" + desc.name + "' "; } String deviceEffects = new String(); for (AudioEffect.Descriptor desc : arc.mDeviceEffects) { deviceEffects += "'" + desc.name + "' "; } return new String("session:" + arc.mClientSessionId + " -- source client=" + MediaRecorder.toLogFriendlyAudioSource(arc.mClientSource) + ", dev=" + arc.mDeviceFormat.toLogFriendlyString() + " -- uid:" + arc.mClientUid + " -- uid:" + arc.mClientUid + " -- patch:" + arc.mPatchHandle + " -- patch:" + arc.mPatchHandle + " -- pack:" + arc.mClientPackageName + " -- pack:" + arc.mClientPackageName + " -- format client=" + arc.mClientFormat.toLogFriendlyString() + " -- format client=" + arc.mClientFormat.toLogFriendlyString() + ", dev=" + arc.mDeviceFormat.toLogFriendlyString()); + ", dev=" + arc.mDeviceFormat.toLogFriendlyString() + " -- silenced:" + arc.mClientSilenced + " -- effects client=" + clientEffects + ", dev=" + deviceEffects); } } // Note that this method is called server side, so no "privileged" information is ever sent // Note that this method is called server side, so no "privileged" information is ever sent Loading @@ -106,8 +155,10 @@ public final class AudioRecordingConfiguration implements Parcelable { */ */ public static AudioRecordingConfiguration anonymizedCopy(AudioRecordingConfiguration in) { public static AudioRecordingConfiguration anonymizedCopy(AudioRecordingConfiguration in) { return new AudioRecordingConfiguration( /*anonymized uid*/ -1, return new AudioRecordingConfiguration( /*anonymized uid*/ -1, in.mSessionId, in.mClientSource, in.mClientFormat, in.mClientSessionId, in.mClientSource, in.mClientFormat, in.mDeviceFormat, in.mPatchHandle, "" /*empty package name*/); in.mDeviceFormat, in.mPatchHandle, "" /*empty package name*/, in.mClientPortId, in.mClientSilenced, in.mDeviceSource, in.mClientEffects, in.mDeviceEffects); } } // matches the sources that return false in MediaRecorder.isSystemOnlyAudioSource(source) // matches the sources that return false in MediaRecorder.isSystemOnlyAudioSource(source) Loading @@ -129,16 +180,8 @@ public final class AudioRecordingConfiguration implements Parcelable { // documented return values match the sources that return false // documented return values match the sources that return false // in MediaRecorder.isSystemOnlyAudioSource(source) // in MediaRecorder.isSystemOnlyAudioSource(source) /** /** * Returns the audio source being used for the recording. * Returns the audio source selected by the client. * @return one of {@link MediaRecorder.AudioSource#DEFAULT}, * @return the audio source selected by the client. * {@link MediaRecorder.AudioSource#MIC}, * {@link MediaRecorder.AudioSource#VOICE_UPLINK}, * {@link MediaRecorder.AudioSource#VOICE_DOWNLINK}, * {@link MediaRecorder.AudioSource#VOICE_CALL}, * {@link MediaRecorder.AudioSource#CAMCORDER}, * {@link MediaRecorder.AudioSource#VOICE_RECOGNITION}, * {@link MediaRecorder.AudioSource#VOICE_COMMUNICATION}, * {@link MediaRecorder.AudioSource#UNPROCESSED}. */ */ public @AudioSource int getClientAudioSource() { return mClientSource; } public @AudioSource int getClientAudioSource() { return mClientSource; } Loading @@ -146,7 +189,9 @@ public final class AudioRecordingConfiguration implements Parcelable { * Returns the session number of the recording, see {@link AudioRecord#getAudioSessionId()}. * Returns the session number of the recording, see {@link AudioRecord#getAudioSessionId()}. * @return the session number. * @return the session number. */ */ public int getClientAudioSessionId() { return mSessionId; } public int getClientAudioSessionId() { return mClientSessionId; } /** /** * Returns the audio format at which audio is recorded on this Android device. * Returns the audio format at which audio is recorded on this Android device. Loading Loading @@ -223,6 +268,54 @@ public final class AudioRecordingConfiguration implements Parcelable { return null; return null; } } /** * Returns the system unique ID assigned for the AudioRecord object corresponding to this * AudioRecordingConfiguration client. * @return the port ID. */ int getClientPortId() { return mClientPortId; } /** * Returns true if the audio returned to the client is currently being silenced by the * audio framework due to concurrent capture policy (e.g the capturing application does not have * an active foreground process or service anymore). * @return true if captured audio is silenced, false otherwise . */ public boolean isClientSilenced() { return mClientSilenced; } /** * Returns the audio source currently used to configure the capture path. It can be different * from the source returned by {@link #getClientAudioSource()} if another capture is active. * @return the audio source active on the capture path. */ public @AudioSource int getAudioSource() { return mDeviceSource; } /** * Returns the list of {@link AudioEffect.Descriptor} for all effects currently enabled on * the audio capture client (e.g. {@link AudioRecord} or {@link MediaRecorder}). * @return List of {@link AudioEffect.Descriptor} containing all effects enabled for the client. */ public @NonNull List<AudioEffect.Descriptor> getClientEffects() { return new ArrayList<AudioEffect.Descriptor>(Arrays.asList(mClientEffects)); } /** * Returns the list of {@link AudioEffect.Descriptor} for all effects currently enabled on * the capture stream. * @return List of {@link AudioEffect.Descriptor} containing all effects enabled on the * capture stream. This can be different from the list returned by {@link #getClientEffects()} * if another capture is active. */ public @NonNull List<AudioEffect.Descriptor> getEffects() { return new ArrayList<AudioEffect.Descriptor>(Arrays.asList(mDeviceEffects)); } public static final Parcelable.Creator<AudioRecordingConfiguration> CREATOR public static final Parcelable.Creator<AudioRecordingConfiguration> CREATOR = new Parcelable.Creator<AudioRecordingConfiguration>() { = new Parcelable.Creator<AudioRecordingConfiguration>() { /** /** Loading @@ -240,7 +333,7 @@ public final class AudioRecordingConfiguration implements Parcelable { @Override @Override public int hashCode() { public int hashCode() { return Objects.hash(mSessionId, mClientSource); return Objects.hash(mClientSessionId, mClientSource); } } @Override @Override Loading @@ -250,23 +343,45 @@ public final class AudioRecordingConfiguration implements Parcelable { @Override @Override public void writeToParcel(Parcel dest, int flags) { public void writeToParcel(Parcel dest, int flags) { dest.writeInt(mSessionId); dest.writeInt(mClientSessionId); dest.writeInt(mClientSource); dest.writeInt(mClientSource); mClientFormat.writeToParcel(dest, 0); mClientFormat.writeToParcel(dest, 0); mDeviceFormat.writeToParcel(dest, 0); mDeviceFormat.writeToParcel(dest, 0); dest.writeInt(mPatchHandle); dest.writeInt(mPatchHandle); dest.writeString(mClientPackageName); dest.writeString(mClientPackageName); dest.writeInt(mClientUid); dest.writeInt(mClientUid); dest.writeInt(mClientPortId); dest.writeBoolean(mClientSilenced); dest.writeInt(mDeviceSource); dest.writeInt(mClientEffects.length); for (int i = 0; i < mClientEffects.length; i++) { mClientEffects[i].writeToParcel(dest, 0); } dest.writeInt(mDeviceEffects.length); for (int i = 0; i < mDeviceEffects.length; i++) { mDeviceEffects[i].writeToParcel(dest, 0); } } } private AudioRecordingConfiguration(Parcel in) { private AudioRecordingConfiguration(Parcel in) { mSessionId = in.readInt(); mClientSessionId = in.readInt(); mClientSource = in.readInt(); mClientSource = in.readInt(); mClientFormat = AudioFormat.CREATOR.createFromParcel(in); mClientFormat = AudioFormat.CREATOR.createFromParcel(in); mDeviceFormat = AudioFormat.CREATOR.createFromParcel(in); mDeviceFormat = AudioFormat.CREATOR.createFromParcel(in); mPatchHandle = in.readInt(); mPatchHandle = in.readInt(); mClientPackageName = in.readString(); mClientPackageName = in.readString(); mClientUid = in.readInt(); mClientUid = in.readInt(); mClientPortId = in.readInt(); mClientSilenced = in.readBoolean(); mDeviceSource = in.readInt(); mClientEffects = AudioEffect.Descriptor.CREATOR.newArray(in.readInt()); for (int i = 0; i < mClientEffects.length; i++) { mClientEffects[i] = AudioEffect.Descriptor.CREATOR.createFromParcel(in); } mDeviceEffects = AudioEffect.Descriptor.CREATOR.newArray(in.readInt()); for (int i = 0; i < mClientEffects.length; i++) { mDeviceEffects[i] = AudioEffect.Descriptor.CREATOR.createFromParcel(in); } } } @Override @Override Loading @@ -277,11 +392,16 @@ public final class AudioRecordingConfiguration implements Parcelable { AudioRecordingConfiguration that = (AudioRecordingConfiguration) o; AudioRecordingConfiguration that = (AudioRecordingConfiguration) o; return ((mClientUid == that.mClientUid) return ((mClientUid == that.mClientUid) && (mSessionId == that.mSessionId) && (mClientSessionId == that.mClientSessionId) && (mClientSource == that.mClientSource) && (mClientSource == that.mClientSource) && (mPatchHandle == that.mPatchHandle) && (mPatchHandle == that.mPatchHandle) && (mClientFormat.equals(that.mClientFormat)) && (mClientFormat.equals(that.mClientFormat)) && (mDeviceFormat.equals(that.mDeviceFormat)) && (mDeviceFormat.equals(that.mDeviceFormat)) && (mClientPackageName.equals(that.mClientPackageName))); && (mClientPackageName.equals(that.mClientPackageName)) && (mClientPortId == that.mClientPortId) && (mClientSilenced == that.mClientSilenced) && (mDeviceSource == that.mDeviceSource) && (mClientEffects.equals(that.mClientEffects)) && (mDeviceEffects.equals(that.mDeviceEffects))); } } } } media/java/android/media/AudioSystem.java +15 −4 Original line number Original line Diff line number Diff line Loading @@ -20,6 +20,7 @@ import android.annotation.NonNull; import android.annotation.UnsupportedAppUsage; import android.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.Context; import android.content.pm.PackageManager; import android.content.pm.PackageManager; import android.media.audiofx.AudioEffect; import android.media.audiopolicy.AudioMix; import android.media.audiopolicy.AudioMix; import android.os.Build; import android.os.Build; import android.util.Log; import android.util.Log; Loading Loading @@ -334,7 +335,9 @@ public class AudioSystem * @param packName package name of the client app performing the recording. NOT SUPPORTED * @param packName package name of the client app performing the recording. NOT SUPPORTED */ */ void onRecordingConfigurationChanged(int event, int uid, int session, int source, void onRecordingConfigurationChanged(int event, int uid, int session, int source, int[] recordingFormat, String packName); int portId, boolean silenced, int[] recordingFormat, AudioEffect.Descriptor[] clienteffects, AudioEffect.Descriptor[] effects, int activeSource, String packName); } } private static AudioRecordingCallback sRecordingCallback; private static AudioRecordingCallback sRecordingCallback; Loading @@ -352,19 +355,27 @@ public class AudioSystem * @param session * @param session * @param source * @param source * @param recordingFormat see * @param recordingFormat see * {@link AudioRecordingCallback#onRecordingConfigurationChanged(int, int, int, int, int[])} * {@link AudioRecordingCallback#onRecordingConfigurationChanged(int, int, int, int, int,\ boolean, int[], AudioEffect.Descriptor[], AudioEffect.Descriptor[], int, String)} * for the description of the record format. * for the description of the record format. */ */ @UnsupportedAppUsage @UnsupportedAppUsage private static void recordingCallbackFromNative(int event, int uid, int session, int source, private static void recordingCallbackFromNative(int event, int uid, int session, int source, int[] recordingFormat) { int portId, boolean silenced, int[] recordingFormat, AudioEffect.Descriptor[] clientEffects, AudioEffect.Descriptor[] effects, int activeSource) { AudioRecordingCallback cb = null; AudioRecordingCallback cb = null; synchronized (AudioSystem.class) { synchronized (AudioSystem.class) { cb = sRecordingCallback; cb = sRecordingCallback; } } String clientEffectName = clientEffects.length == 0 ? "None" : clientEffects[0].name; String effectName = effects.length == 0 ? "None" : effects[0].name; if (cb != null) { if (cb != null) { // TODO receive package name from native // TODO receive package name from native cb.onRecordingConfigurationChanged(event, uid, session, source, recordingFormat, ""); cb.onRecordingConfigurationChanged(event, uid, session, source, portId, silenced, recordingFormat, clientEffects, effects, activeSource, ""); } } } } Loading Loading
api/current.txt +4 −0 Original line number Original line Diff line number Diff line Loading @@ -23462,10 +23462,14 @@ package android.media { public final class AudioRecordingConfiguration implements android.os.Parcelable { public final class AudioRecordingConfiguration implements android.os.Parcelable { method public int describeContents(); method public int describeContents(); method public android.media.AudioDeviceInfo getAudioDevice(); method public android.media.AudioDeviceInfo getAudioDevice(); method public int getAudioSource(); method public int getClientAudioSessionId(); method public int getClientAudioSessionId(); method public int getClientAudioSource(); method public int getClientAudioSource(); method public java.util.List<android.media.audiofx.AudioEffect.Descriptor> getClientEffects(); method public android.media.AudioFormat getClientFormat(); method public android.media.AudioFormat getClientFormat(); method public java.util.List<android.media.audiofx.AudioEffect.Descriptor> getEffects(); method public android.media.AudioFormat getFormat(); method public android.media.AudioFormat getFormat(); method public boolean isClientSilenced(); method public void writeToParcel(android.os.Parcel, int); method public void writeToParcel(android.os.Parcel, int); field public static final android.os.Parcelable.Creator<android.media.AudioRecordingConfiguration> CREATOR; field public static final android.os.Parcelable.Creator<android.media.AudioRecordingConfiguration> CREATOR; } }
api/test-current.txt +5 −0 Original line number Original line Diff line number Diff line Loading @@ -638,6 +638,11 @@ package android.media { method public static boolean isEncodingLinearPcm(int); method public static boolean isEncodingLinearPcm(int); } } public final class AudioRecordingConfiguration implements android.os.Parcelable { ctor public AudioRecordingConfiguration(int, int, int, android.media.AudioFormat, android.media.AudioFormat, int, java.lang.String, int, boolean, int, android.media.audiofx.AudioEffect.Descriptor[], android.media.audiofx.AudioEffect.Descriptor[]); ctor public AudioRecordingConfiguration(int, int, int, android.media.AudioFormat, android.media.AudioFormat, int, java.lang.String); } public final class BufferingParams implements android.os.Parcelable { public final class BufferingParams implements android.os.Parcelable { method public int describeContents(); method public int describeContents(); method public int getInitialMarkMs(); method public int getInitialMarkMs(); Loading
core/jni/android_media_AudioSystem.cpp +23 −7 Original line number Original line Diff line number Diff line Loading @@ -32,6 +32,7 @@ #include <nativehelper/ScopedLocalRef.h> #include <nativehelper/ScopedLocalRef.h> #include <system/audio.h> #include <system/audio.h> #include <system/audio_policy.h> #include <system/audio_policy.h> #include "android_media_AudioEffectDescriptor.h" #include "android_media_AudioFormat.h" #include "android_media_AudioFormat.h" #include "android_media_AudioErrors.h" #include "android_media_AudioErrors.h" #include "android_media_MicrophoneInfo.h" #include "android_media_MicrophoneInfo.h" Loading Loading @@ -427,9 +428,14 @@ android_media_AudioSystem_dyn_policy_callback(int event, String8 regId, int val) } } static void static void android_media_AudioSystem_recording_callback(int event, const record_client_info_t *clientInfo, android_media_AudioSystem_recording_callback(int event, const audio_config_base_t *clientConfig, const audio_config_base_t *deviceConfig, const record_client_info_t *clientInfo, audio_patch_handle_t patchHandle) const audio_config_base_t *clientConfig, std::vector<effect_descriptor_t> clientEffects, const audio_config_base_t *deviceConfig, std::vector<effect_descriptor_t> effects __unused, audio_patch_handle_t patchHandle, audio_source_t source) { { JNIEnv *env = AndroidRuntime::getJNIEnv(); JNIEnv *env = AndroidRuntime::getJNIEnv(); if (env == NULL) { if (env == NULL) { Loading Loading @@ -460,14 +466,24 @@ android_media_AudioSystem_recording_callback(int event, const record_client_info recParamData[6] = (jint) patchHandle; recParamData[6] = (jint) patchHandle; env->SetIntArrayRegion(recParamArray, 0, REC_PARAM_SIZE, recParamData); env->SetIntArrayRegion(recParamArray, 0, REC_PARAM_SIZE, recParamData); jobjectArray jClientEffects; convertAudioEffectDescriptorVectorFromNative(env, &jClientEffects, clientEffects); jobjectArray jEffects; convertAudioEffectDescriptorVectorFromNative(env, &jEffects, effects); // callback into java // callback into java jclass clazz = env->FindClass(kClassPathName); jclass clazz = env->FindClass(kClassPathName); env->CallStaticVoidMethod(clazz, env->CallStaticVoidMethod(clazz, gAudioPolicyEventHandlerMethods.postRecordConfigEventFromNative, gAudioPolicyEventHandlerMethods.postRecordConfigEventFromNative, event, (jint) clientInfo->uid, clientInfo->session, clientInfo->source, recParamArray); event, (jint) clientInfo->uid, clientInfo->session, clientInfo->source, clientInfo->port_id, clientInfo->silenced, recParamArray, jClientEffects, jEffects, source); env->DeleteLocalRef(clazz); env->DeleteLocalRef(clazz); env->DeleteLocalRef(recParamArray); env->DeleteLocalRef(recParamArray); env->DeleteLocalRef(jClientEffects); env->DeleteLocalRef(jEffects); } } static jint static jint Loading Loading @@ -2260,7 +2276,7 @@ int register_android_media_AudioSystem(JNIEnv *env) "dynamicPolicyCallbackFromNative", "(ILjava/lang/String;I)V"); "dynamicPolicyCallbackFromNative", "(ILjava/lang/String;I)V"); gAudioPolicyEventHandlerMethods.postRecordConfigEventFromNative = gAudioPolicyEventHandlerMethods.postRecordConfigEventFromNative = GetStaticMethodIDOrDie(env, env->FindClass(kClassPathName), GetStaticMethodIDOrDie(env, env->FindClass(kClassPathName), "recordingCallbackFromNative", "(IIII[I)V"); "recordingCallbackFromNative", "(IIIIIZ[I[Landroid/media/audiofx/AudioEffect$Descriptor;[Landroid/media/audiofx/AudioEffect$Descriptor;I)V"); jclass audioMixClass = FindClassOrDie(env, "android/media/audiopolicy/AudioMix"); jclass audioMixClass = FindClassOrDie(env, "android/media/audiopolicy/AudioMix"); gAudioMixClass = MakeGlobalRefOrDie(env, audioMixClass); gAudioMixClass = MakeGlobalRefOrDie(env, audioMixClass); Loading
media/java/android/media/AudioRecordingConfiguration.java +144 −24 Original line number Original line Diff line number Diff line Loading @@ -18,7 +18,9 @@ package android.media; import android.annotation.IntDef; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.NonNull; import android.annotation.TestApi; import android.annotation.UnsupportedAppUsage; import android.annotation.UnsupportedAppUsage; import android.media.audiofx.AudioEffect; import android.os.Parcel; import android.os.Parcel; import android.os.Parcelable; import android.os.Parcelable; import android.util.Log; import android.util.Log; Loading @@ -27,6 +29,8 @@ import java.io.PrintWriter; import java.lang.annotation.Retention; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Objects; import java.util.Objects; /** /** Loading @@ -48,7 +52,7 @@ import java.util.Objects; public final class AudioRecordingConfiguration implements Parcelable { public final class AudioRecordingConfiguration implements Parcelable { private final static String TAG = new String("AudioRecordingConfiguration"); private final static String TAG = new String("AudioRecordingConfiguration"); private final int mSessionId; private final int mClientSessionId; private final int mClientSource; private final int mClientSource; Loading @@ -60,18 +64,50 @@ public final class AudioRecordingConfiguration implements Parcelable { private final int mPatchHandle; private final int mPatchHandle; private final int mClientPortId; private boolean mClientSilenced; private final int mDeviceSource; private final AudioEffect.Descriptor[] mClientEffects; private final AudioEffect.Descriptor[] mDeviceEffects; /** /** * @hide * @hide */ */ @TestApi public AudioRecordingConfiguration(int uid, int session, int source, AudioFormat clientFormat, public AudioRecordingConfiguration(int uid, int session, int source, AudioFormat clientFormat, AudioFormat devFormat, int patchHandle, String packageName) { AudioFormat devFormat, int patchHandle, String packageName, int clientPortId, boolean clientSilenced, int deviceSource, AudioEffect.Descriptor[] clientEffects, AudioEffect.Descriptor[] deviceEffects) { mClientUid = uid; mClientUid = uid; mSessionId = session; mClientSessionId = session; mClientSource = source; mClientSource = source; mClientFormat = clientFormat; mClientFormat = clientFormat; mDeviceFormat = devFormat; mDeviceFormat = devFormat; mPatchHandle = patchHandle; mPatchHandle = patchHandle; mClientPackageName = packageName; mClientPackageName = packageName; mClientPortId = clientPortId; mClientSilenced = clientSilenced; mDeviceSource = deviceSource; mClientEffects = clientEffects; mDeviceEffects = deviceEffects; } /** * @hide */ @TestApi public AudioRecordingConfiguration(int uid, int session, int source, AudioFormat clientFormat, AudioFormat devFormat, int patchHandle, String packageName) { this(uid, session, source, clientFormat, devFormat, patchHandle, packageName, 0 /*clientPortId*/, false /*clientSilenced*/, MediaRecorder.AudioSource.DEFAULT /*deviceSource*/, new AudioEffect.Descriptor[0] /*clientEffects*/, new AudioEffect.Descriptor[0] /*deviceEffects*/); } } /** /** Loading @@ -87,13 +123,26 @@ public final class AudioRecordingConfiguration implements Parcelable { * @hide * @hide */ */ public static String toLogFriendlyString(AudioRecordingConfiguration arc) { public static String toLogFriendlyString(AudioRecordingConfiguration arc) { return new String("session:" + arc.mSessionId String clientEffects = new String(); + " -- source:" + MediaRecorder.toLogFriendlyAudioSource(arc.mClientSource) for (AudioEffect.Descriptor desc : arc.mClientEffects) { clientEffects += "'" + desc.name + "' "; } String deviceEffects = new String(); for (AudioEffect.Descriptor desc : arc.mDeviceEffects) { deviceEffects += "'" + desc.name + "' "; } return new String("session:" + arc.mClientSessionId + " -- source client=" + MediaRecorder.toLogFriendlyAudioSource(arc.mClientSource) + ", dev=" + arc.mDeviceFormat.toLogFriendlyString() + " -- uid:" + arc.mClientUid + " -- uid:" + arc.mClientUid + " -- patch:" + arc.mPatchHandle + " -- patch:" + arc.mPatchHandle + " -- pack:" + arc.mClientPackageName + " -- pack:" + arc.mClientPackageName + " -- format client=" + arc.mClientFormat.toLogFriendlyString() + " -- format client=" + arc.mClientFormat.toLogFriendlyString() + ", dev=" + arc.mDeviceFormat.toLogFriendlyString()); + ", dev=" + arc.mDeviceFormat.toLogFriendlyString() + " -- silenced:" + arc.mClientSilenced + " -- effects client=" + clientEffects + ", dev=" + deviceEffects); } } // Note that this method is called server side, so no "privileged" information is ever sent // Note that this method is called server side, so no "privileged" information is ever sent Loading @@ -106,8 +155,10 @@ public final class AudioRecordingConfiguration implements Parcelable { */ */ public static AudioRecordingConfiguration anonymizedCopy(AudioRecordingConfiguration in) { public static AudioRecordingConfiguration anonymizedCopy(AudioRecordingConfiguration in) { return new AudioRecordingConfiguration( /*anonymized uid*/ -1, return new AudioRecordingConfiguration( /*anonymized uid*/ -1, in.mSessionId, in.mClientSource, in.mClientFormat, in.mClientSessionId, in.mClientSource, in.mClientFormat, in.mDeviceFormat, in.mPatchHandle, "" /*empty package name*/); in.mDeviceFormat, in.mPatchHandle, "" /*empty package name*/, in.mClientPortId, in.mClientSilenced, in.mDeviceSource, in.mClientEffects, in.mDeviceEffects); } } // matches the sources that return false in MediaRecorder.isSystemOnlyAudioSource(source) // matches the sources that return false in MediaRecorder.isSystemOnlyAudioSource(source) Loading @@ -129,16 +180,8 @@ public final class AudioRecordingConfiguration implements Parcelable { // documented return values match the sources that return false // documented return values match the sources that return false // in MediaRecorder.isSystemOnlyAudioSource(source) // in MediaRecorder.isSystemOnlyAudioSource(source) /** /** * Returns the audio source being used for the recording. * Returns the audio source selected by the client. * @return one of {@link MediaRecorder.AudioSource#DEFAULT}, * @return the audio source selected by the client. * {@link MediaRecorder.AudioSource#MIC}, * {@link MediaRecorder.AudioSource#VOICE_UPLINK}, * {@link MediaRecorder.AudioSource#VOICE_DOWNLINK}, * {@link MediaRecorder.AudioSource#VOICE_CALL}, * {@link MediaRecorder.AudioSource#CAMCORDER}, * {@link MediaRecorder.AudioSource#VOICE_RECOGNITION}, * {@link MediaRecorder.AudioSource#VOICE_COMMUNICATION}, * {@link MediaRecorder.AudioSource#UNPROCESSED}. */ */ public @AudioSource int getClientAudioSource() { return mClientSource; } public @AudioSource int getClientAudioSource() { return mClientSource; } Loading @@ -146,7 +189,9 @@ public final class AudioRecordingConfiguration implements Parcelable { * Returns the session number of the recording, see {@link AudioRecord#getAudioSessionId()}. * Returns the session number of the recording, see {@link AudioRecord#getAudioSessionId()}. * @return the session number. * @return the session number. */ */ public int getClientAudioSessionId() { return mSessionId; } public int getClientAudioSessionId() { return mClientSessionId; } /** /** * Returns the audio format at which audio is recorded on this Android device. * Returns the audio format at which audio is recorded on this Android device. Loading Loading @@ -223,6 +268,54 @@ public final class AudioRecordingConfiguration implements Parcelable { return null; return null; } } /** * Returns the system unique ID assigned for the AudioRecord object corresponding to this * AudioRecordingConfiguration client. * @return the port ID. */ int getClientPortId() { return mClientPortId; } /** * Returns true if the audio returned to the client is currently being silenced by the * audio framework due to concurrent capture policy (e.g the capturing application does not have * an active foreground process or service anymore). * @return true if captured audio is silenced, false otherwise . */ public boolean isClientSilenced() { return mClientSilenced; } /** * Returns the audio source currently used to configure the capture path. It can be different * from the source returned by {@link #getClientAudioSource()} if another capture is active. * @return the audio source active on the capture path. */ public @AudioSource int getAudioSource() { return mDeviceSource; } /** * Returns the list of {@link AudioEffect.Descriptor} for all effects currently enabled on * the audio capture client (e.g. {@link AudioRecord} or {@link MediaRecorder}). * @return List of {@link AudioEffect.Descriptor} containing all effects enabled for the client. */ public @NonNull List<AudioEffect.Descriptor> getClientEffects() { return new ArrayList<AudioEffect.Descriptor>(Arrays.asList(mClientEffects)); } /** * Returns the list of {@link AudioEffect.Descriptor} for all effects currently enabled on * the capture stream. * @return List of {@link AudioEffect.Descriptor} containing all effects enabled on the * capture stream. This can be different from the list returned by {@link #getClientEffects()} * if another capture is active. */ public @NonNull List<AudioEffect.Descriptor> getEffects() { return new ArrayList<AudioEffect.Descriptor>(Arrays.asList(mDeviceEffects)); } public static final Parcelable.Creator<AudioRecordingConfiguration> CREATOR public static final Parcelable.Creator<AudioRecordingConfiguration> CREATOR = new Parcelable.Creator<AudioRecordingConfiguration>() { = new Parcelable.Creator<AudioRecordingConfiguration>() { /** /** Loading @@ -240,7 +333,7 @@ public final class AudioRecordingConfiguration implements Parcelable { @Override @Override public int hashCode() { public int hashCode() { return Objects.hash(mSessionId, mClientSource); return Objects.hash(mClientSessionId, mClientSource); } } @Override @Override Loading @@ -250,23 +343,45 @@ public final class AudioRecordingConfiguration implements Parcelable { @Override @Override public void writeToParcel(Parcel dest, int flags) { public void writeToParcel(Parcel dest, int flags) { dest.writeInt(mSessionId); dest.writeInt(mClientSessionId); dest.writeInt(mClientSource); dest.writeInt(mClientSource); mClientFormat.writeToParcel(dest, 0); mClientFormat.writeToParcel(dest, 0); mDeviceFormat.writeToParcel(dest, 0); mDeviceFormat.writeToParcel(dest, 0); dest.writeInt(mPatchHandle); dest.writeInt(mPatchHandle); dest.writeString(mClientPackageName); dest.writeString(mClientPackageName); dest.writeInt(mClientUid); dest.writeInt(mClientUid); dest.writeInt(mClientPortId); dest.writeBoolean(mClientSilenced); dest.writeInt(mDeviceSource); dest.writeInt(mClientEffects.length); for (int i = 0; i < mClientEffects.length; i++) { mClientEffects[i].writeToParcel(dest, 0); } dest.writeInt(mDeviceEffects.length); for (int i = 0; i < mDeviceEffects.length; i++) { mDeviceEffects[i].writeToParcel(dest, 0); } } } private AudioRecordingConfiguration(Parcel in) { private AudioRecordingConfiguration(Parcel in) { mSessionId = in.readInt(); mClientSessionId = in.readInt(); mClientSource = in.readInt(); mClientSource = in.readInt(); mClientFormat = AudioFormat.CREATOR.createFromParcel(in); mClientFormat = AudioFormat.CREATOR.createFromParcel(in); mDeviceFormat = AudioFormat.CREATOR.createFromParcel(in); mDeviceFormat = AudioFormat.CREATOR.createFromParcel(in); mPatchHandle = in.readInt(); mPatchHandle = in.readInt(); mClientPackageName = in.readString(); mClientPackageName = in.readString(); mClientUid = in.readInt(); mClientUid = in.readInt(); mClientPortId = in.readInt(); mClientSilenced = in.readBoolean(); mDeviceSource = in.readInt(); mClientEffects = AudioEffect.Descriptor.CREATOR.newArray(in.readInt()); for (int i = 0; i < mClientEffects.length; i++) { mClientEffects[i] = AudioEffect.Descriptor.CREATOR.createFromParcel(in); } mDeviceEffects = AudioEffect.Descriptor.CREATOR.newArray(in.readInt()); for (int i = 0; i < mClientEffects.length; i++) { mDeviceEffects[i] = AudioEffect.Descriptor.CREATOR.createFromParcel(in); } } } @Override @Override Loading @@ -277,11 +392,16 @@ public final class AudioRecordingConfiguration implements Parcelable { AudioRecordingConfiguration that = (AudioRecordingConfiguration) o; AudioRecordingConfiguration that = (AudioRecordingConfiguration) o; return ((mClientUid == that.mClientUid) return ((mClientUid == that.mClientUid) && (mSessionId == that.mSessionId) && (mClientSessionId == that.mClientSessionId) && (mClientSource == that.mClientSource) && (mClientSource == that.mClientSource) && (mPatchHandle == that.mPatchHandle) && (mPatchHandle == that.mPatchHandle) && (mClientFormat.equals(that.mClientFormat)) && (mClientFormat.equals(that.mClientFormat)) && (mDeviceFormat.equals(that.mDeviceFormat)) && (mDeviceFormat.equals(that.mDeviceFormat)) && (mClientPackageName.equals(that.mClientPackageName))); && (mClientPackageName.equals(that.mClientPackageName)) && (mClientPortId == that.mClientPortId) && (mClientSilenced == that.mClientSilenced) && (mDeviceSource == that.mDeviceSource) && (mClientEffects.equals(that.mClientEffects)) && (mDeviceEffects.equals(that.mDeviceEffects))); } } } }
media/java/android/media/AudioSystem.java +15 −4 Original line number Original line Diff line number Diff line Loading @@ -20,6 +20,7 @@ import android.annotation.NonNull; import android.annotation.UnsupportedAppUsage; import android.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.Context; import android.content.pm.PackageManager; import android.content.pm.PackageManager; import android.media.audiofx.AudioEffect; import android.media.audiopolicy.AudioMix; import android.media.audiopolicy.AudioMix; import android.os.Build; import android.os.Build; import android.util.Log; import android.util.Log; Loading Loading @@ -334,7 +335,9 @@ public class AudioSystem * @param packName package name of the client app performing the recording. NOT SUPPORTED * @param packName package name of the client app performing the recording. NOT SUPPORTED */ */ void onRecordingConfigurationChanged(int event, int uid, int session, int source, void onRecordingConfigurationChanged(int event, int uid, int session, int source, int[] recordingFormat, String packName); int portId, boolean silenced, int[] recordingFormat, AudioEffect.Descriptor[] clienteffects, AudioEffect.Descriptor[] effects, int activeSource, String packName); } } private static AudioRecordingCallback sRecordingCallback; private static AudioRecordingCallback sRecordingCallback; Loading @@ -352,19 +355,27 @@ public class AudioSystem * @param session * @param session * @param source * @param source * @param recordingFormat see * @param recordingFormat see * {@link AudioRecordingCallback#onRecordingConfigurationChanged(int, int, int, int, int[])} * {@link AudioRecordingCallback#onRecordingConfigurationChanged(int, int, int, int, int,\ boolean, int[], AudioEffect.Descriptor[], AudioEffect.Descriptor[], int, String)} * for the description of the record format. * for the description of the record format. */ */ @UnsupportedAppUsage @UnsupportedAppUsage private static void recordingCallbackFromNative(int event, int uid, int session, int source, private static void recordingCallbackFromNative(int event, int uid, int session, int source, int[] recordingFormat) { int portId, boolean silenced, int[] recordingFormat, AudioEffect.Descriptor[] clientEffects, AudioEffect.Descriptor[] effects, int activeSource) { AudioRecordingCallback cb = null; AudioRecordingCallback cb = null; synchronized (AudioSystem.class) { synchronized (AudioSystem.class) { cb = sRecordingCallback; cb = sRecordingCallback; } } String clientEffectName = clientEffects.length == 0 ? "None" : clientEffects[0].name; String effectName = effects.length == 0 ? "None" : effects[0].name; if (cb != null) { if (cb != null) { // TODO receive package name from native // TODO receive package name from native cb.onRecordingConfigurationChanged(event, uid, session, source, recordingFormat, ""); cb.onRecordingConfigurationChanged(event, uid, session, source, portId, silenced, recordingFormat, clientEffects, effects, activeSource, ""); } } } } Loading