Merge "Add explicit private audio recording request"
This commit is contained in:
@@ -23794,6 +23794,7 @@ package android.media {
|
||||
method public int getSampleRate();
|
||||
method public int getState();
|
||||
method public int getTimestamp(@NonNull android.media.AudioTimestamp, int);
|
||||
method public boolean isPrivacySensitive();
|
||||
method public int read(@NonNull byte[], int, int);
|
||||
method public int read(@NonNull byte[], int, int, int);
|
||||
method public int read(@NonNull short[], int, int);
|
||||
@@ -23836,6 +23837,7 @@ package android.media {
|
||||
method @NonNull public android.media.AudioRecord.Builder setAudioPlaybackCaptureConfig(@NonNull android.media.AudioPlaybackCaptureConfiguration);
|
||||
method public android.media.AudioRecord.Builder setAudioSource(int) throws java.lang.IllegalArgumentException;
|
||||
method public android.media.AudioRecord.Builder setBufferSizeInBytes(int) throws java.lang.IllegalArgumentException;
|
||||
method @NonNull public android.media.AudioRecord.Builder setPrivacySensitive(boolean);
|
||||
}
|
||||
|
||||
public static final class AudioRecord.MetricsConstants {
|
||||
@@ -25899,6 +25901,7 @@ package android.media {
|
||||
method public android.media.AudioDeviceInfo getPreferredDevice();
|
||||
method public android.media.AudioDeviceInfo getRoutedDevice();
|
||||
method public android.view.Surface getSurface();
|
||||
method public boolean isPrivacySensitive();
|
||||
method public void pause() throws java.lang.IllegalStateException;
|
||||
method public void prepare() throws java.io.IOException, java.lang.IllegalStateException;
|
||||
method public void registerAudioRecordingCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.AudioManager.AudioRecordingCallback);
|
||||
@@ -25930,6 +25933,7 @@ package android.media {
|
||||
method public boolean setPreferredMicrophoneDirection(int);
|
||||
method public boolean setPreferredMicrophoneFieldDimension(@FloatRange(from=-1.0, to=1.0) float);
|
||||
method public void setPreviewDisplay(android.view.Surface);
|
||||
method public void setPrivacySensitive(boolean);
|
||||
method public void setProfile(android.media.CamcorderProfile);
|
||||
method public void setVideoEncoder(int) throws java.lang.IllegalStateException;
|
||||
method public void setVideoEncodingBitRate(int);
|
||||
|
||||
@@ -388,12 +388,21 @@ public final class AudioAttributes implements Parcelable {
|
||||
*/
|
||||
public static final int FLAG_NO_SYSTEM_CAPTURE = 0x1 << 12;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
* Flag requesting private audio capture. When set in audio attributes passed to an
|
||||
* AudioRecord, this prevents a privileged Assistant from capturing audio while this
|
||||
* AudioRecord is active.
|
||||
*/
|
||||
public static final int FLAG_CAPTURE_PRIVATE = 0x1 << 13;
|
||||
|
||||
|
||||
// Note that even though FLAG_MUTE_HAPTIC is stored as a flag bit, it is not here since
|
||||
// it is known as a boolean value outside of AudioAttributes.
|
||||
private static final int FLAG_ALL = FLAG_AUDIBILITY_ENFORCED | FLAG_SECURE | FLAG_SCO
|
||||
| FLAG_BEACON | FLAG_HW_AV_SYNC | FLAG_HW_HOTWORD | FLAG_BYPASS_INTERRUPTION_POLICY
|
||||
| FLAG_BYPASS_MUTE | FLAG_LOW_LATENCY | FLAG_DEEP_BUFFER | FLAG_NO_MEDIA_PROJECTION
|
||||
| FLAG_NO_SYSTEM_CAPTURE;
|
||||
| FLAG_NO_SYSTEM_CAPTURE | FLAG_CAPTURE_PRIVATE;
|
||||
private final static int FLAG_ALL_PUBLIC = FLAG_AUDIBILITY_ENFORCED |
|
||||
FLAG_HW_AV_SYNC | FLAG_LOW_LATENCY;
|
||||
|
||||
@@ -620,6 +629,12 @@ public final class AudioAttributes implements Parcelable {
|
||||
if (mMuteHapticChannels) {
|
||||
aa.mFlags |= FLAG_MUTE_HAPTIC;
|
||||
}
|
||||
// capturing for camcorder of communication is private by default to
|
||||
// reflect legacy behavior
|
||||
if (aa.mSource == MediaRecorder.AudioSource.VOICE_COMMUNICATION
|
||||
|| aa.mSource == MediaRecorder.AudioSource.CAMCORDER) {
|
||||
aa.mFlags |= FLAG_CAPTURE_PRIVATE;
|
||||
}
|
||||
aa.mTags = (HashSet<String>) mTags.clone();
|
||||
aa.mFormattedTags = TextUtils.join(";", mTags);
|
||||
if (mBundle != null) {
|
||||
|
||||
@@ -527,6 +527,11 @@ public class AudioRecord implements AudioRouting, MicrophoneDirection,
|
||||
private AudioFormat mFormat;
|
||||
private int mBufferSizeInBytes;
|
||||
private int mSessionId = AudioManager.AUDIO_SESSION_ID_GENERATE;
|
||||
private int mPrivacySensitive = PRIVACY_SENSITIVE_DEFAULT;
|
||||
|
||||
private static final int PRIVACY_SENSITIVE_DEFAULT = -1;
|
||||
private static final int PRIVACY_SENSITIVE_DISABLED = 0;
|
||||
private static final int PRIVACY_SENSITIVE_ENABLED = 1;
|
||||
|
||||
/**
|
||||
* Constructs a new Builder with the default values as described above.
|
||||
@@ -631,6 +636,36 @@ public class AudioRecord implements AudioRouting, MicrophoneDirection,
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates that this capture request is privacy sensitive and that
|
||||
* any concurrent capture is not permitted.
|
||||
* <p>
|
||||
* The default is not privacy sensitive except when the audio source set with
|
||||
* {@link #setAudioSource(int)} is {@link MediaRecorder.AudioSource#VOICE_COMMUNICATION} or
|
||||
* {@link MediaRecorder.AudioSource#CAMCORDER}.
|
||||
* <p>
|
||||
* Always takes precedence over default from audio source when set explicitly.
|
||||
* <p>
|
||||
* Using this API is only permitted when the audio source is one of:
|
||||
* <ul>
|
||||
* <li>{@link MediaRecorder.AudioSource#MIC}</li>
|
||||
* <li>{@link MediaRecorder.AudioSource#CAMCORDER}</li>
|
||||
* <li>{@link MediaRecorder.AudioSource#VOICE_RECOGNITION}</li>
|
||||
* <li>{@link MediaRecorder.AudioSource#VOICE_COMMUNICATION}</li>
|
||||
* <li>{@link MediaRecorder.AudioSource#UNPROCESSED}</li>
|
||||
* <li>{@link MediaRecorder.AudioSource#VOICE_PERFORMANCE}</li>
|
||||
* </ul>
|
||||
* Invoking {@link #build()} will throw an UnsupportedOperationException if this
|
||||
* condition is not met.
|
||||
* @param privacySensitive True if capture from this AudioRecord must be marked as privacy
|
||||
* sensitive, false otherwise.
|
||||
*/
|
||||
public @NonNull Builder setPrivacySensitive(boolean privacySensitive) {
|
||||
mPrivacySensitive =
|
||||
privacySensitive ? PRIVACY_SENSITIVE_ENABLED : PRIVACY_SENSITIVE_DISABLED;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
* To be only used by system components.
|
||||
@@ -704,6 +739,34 @@ public class AudioRecord implements AudioRouting, MicrophoneDirection,
|
||||
.setInternalCapturePreset(MediaRecorder.AudioSource.DEFAULT)
|
||||
.build();
|
||||
}
|
||||
|
||||
// If mPrivacySensitive is default, the privacy flag is already set
|
||||
// according to audio source in audio attributes.
|
||||
if (mPrivacySensitive != PRIVACY_SENSITIVE_DEFAULT) {
|
||||
int source = mAttributes.getCapturePreset();
|
||||
if (source == MediaRecorder.AudioSource.REMOTE_SUBMIX
|
||||
|| source == MediaRecorder.AudioSource.RADIO_TUNER
|
||||
|| source == MediaRecorder.AudioSource.VOICE_DOWNLINK
|
||||
|| source == MediaRecorder.AudioSource.VOICE_UPLINK
|
||||
|| source == MediaRecorder.AudioSource.VOICE_CALL
|
||||
|| source == MediaRecorder.AudioSource.ECHO_REFERENCE) {
|
||||
throw new UnsupportedOperationException(
|
||||
"Cannot request private capture with source: " + source);
|
||||
}
|
||||
|
||||
int flags = mAttributes.getAllFlags();
|
||||
if (mPrivacySensitive == PRIVACY_SENSITIVE_DISABLED) {
|
||||
flags &= ~AudioAttributes.FLAG_CAPTURE_PRIVATE;
|
||||
} else if (mPrivacySensitive == PRIVACY_SENSITIVE_ENABLED) {
|
||||
flags |= AudioAttributes.FLAG_CAPTURE_PRIVATE;
|
||||
}
|
||||
if (flags != mAttributes.getAllFlags()) {
|
||||
mAttributes = new AudioAttributes.Builder(mAttributes)
|
||||
.replaceFlags(flags)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
// If the buffer size is not specified,
|
||||
// use a single frame for the buffer size and let the
|
||||
@@ -1062,6 +1125,17 @@ public class AudioRecord implements AudioRouting, MicrophoneDirection,
|
||||
return mSessionId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this AudioRecord is marked as privacy sensitive or not.
|
||||
* <p>
|
||||
* See {@link Builder#setPrivacySensitive(boolean)}
|
||||
* <p>
|
||||
* @return true if privacy sensitive, false otherwise
|
||||
*/
|
||||
public boolean isPrivacySensitive() {
|
||||
return (mAudioAttributes.getAllFlags() & AudioAttributes.FLAG_CAPTURE_PRIVATE) != 0;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------
|
||||
// Transport control methods
|
||||
//--------------------
|
||||
|
||||
@@ -586,6 +586,46 @@ public class MediaRecorder implements AudioRouting,
|
||||
return AudioSource.VOICE_PERFORMANCE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates that this capture request is privacy sensitive and that
|
||||
* any concurrent capture is not permitted.
|
||||
* <p>
|
||||
* The default is not privacy sensitive except when the audio source set with
|
||||
* {@link #setAudioSource(int)} is {@link AudioSource#VOICE_COMMUNICATION} or
|
||||
* {@link AudioSource#CAMCORDER}.
|
||||
* <p>
|
||||
* Always takes precedence over default from audio source when set explicitly.
|
||||
* <p>
|
||||
* Using this API is only permitted when the audio source is one of:
|
||||
* <ul>
|
||||
* <li>{@link AudioSource#MIC}</li>
|
||||
* <li>{@link AudioSource#CAMCORDER}</li>
|
||||
* <li>{@link AudioSource#VOICE_RECOGNITION}</li>
|
||||
* <li>{@link AudioSource#VOICE_COMMUNICATION}</li>
|
||||
* <li>{@link AudioSource#UNPROCESSED}</li>
|
||||
* <li>{@link AudioSource#VOICE_PERFORMANCE}</li>
|
||||
* </ul>
|
||||
* Invoking {@link #prepare()} will throw an IOException if this
|
||||
* condition is not met.
|
||||
* <p>
|
||||
* Must be called after {@link #setAudioSource(int)} and before {@link #setOutputFormat(int)}.
|
||||
* @param privacySensitive True if capture from this MediaRecorder must be marked as privacy
|
||||
* sensitive, false otherwise.
|
||||
* @throws IllegalStateException if called before {@link #setAudioSource(int)}
|
||||
* or after {@link #setOutputFormat(int)}
|
||||
*/
|
||||
public native void setPrivacySensitive(boolean privacySensitive);
|
||||
|
||||
/**
|
||||
* Returns whether this MediaRecorder is marked as privacy sensitive or not with
|
||||
* regard to audio capture.
|
||||
* <p>
|
||||
* See {@link #setPrivacySensitive(boolean)}
|
||||
* <p>
|
||||
* @return true if privacy sensitive, false otherwise
|
||||
*/
|
||||
public native boolean isPrivacySensitive();
|
||||
|
||||
/**
|
||||
* Sets the video source to be used for recording. If this method is not
|
||||
* called, the output file will not contain an video track. The source needs
|
||||
|
||||
@@ -226,6 +226,36 @@ android_media_MediaRecorder_setAudioSource(JNIEnv *env, jobject thiz, jint as)
|
||||
process_media_recorder_call(env, mr->setAudioSource(as), "java/lang/RuntimeException", "setAudioSource failed.");
|
||||
}
|
||||
|
||||
static void
|
||||
android_media_MediaRecorder_setPrivacySensitive(JNIEnv *env, jobject thiz, jboolean privacySensitive)
|
||||
{
|
||||
ALOGV("%s(%s)", __func__, privacySensitive ? "true" : "false");
|
||||
|
||||
sp<MediaRecorder> mr = getMediaRecorder(env, thiz);
|
||||
if (mr == NULL) {
|
||||
jniThrowException(env, "java/lang/IllegalStateException", NULL);
|
||||
return;
|
||||
}
|
||||
process_media_recorder_call(env, mr->setPrivacySensitive(privacySensitive),
|
||||
"java/lang/RuntimeException", "setPrivacySensitive failed.");
|
||||
}
|
||||
|
||||
static jboolean
|
||||
android_media_MediaRecorder_isPrivacySensitive(JNIEnv *env, jobject thiz)
|
||||
{
|
||||
sp<MediaRecorder> mr = getMediaRecorder(env, thiz);
|
||||
if (mr == NULL) {
|
||||
jniThrowException(env, "java/lang/IllegalStateException", NULL);
|
||||
return false;
|
||||
}
|
||||
bool privacySensitive;
|
||||
process_media_recorder_call(env, mr->isPrivacySensitive(&privacySensitive),
|
||||
"java/lang/RuntimeException", "isPrivacySensitive failed.");
|
||||
|
||||
ALOGV("%s() -> %s", __func__, privacySensitive ? "true" : "false");
|
||||
return privacySensitive;
|
||||
}
|
||||
|
||||
static void
|
||||
android_media_MediaRecorder_setOutputFormat(JNIEnv *env, jobject thiz, jint of)
|
||||
{
|
||||
@@ -817,6 +847,8 @@ static const JNINativeMethod gMethods[] = {
|
||||
{"setCamera", "(Landroid/hardware/Camera;)V", (void *)android_media_MediaRecorder_setCamera},
|
||||
{"setVideoSource", "(I)V", (void *)android_media_MediaRecorder_setVideoSource},
|
||||
{"setAudioSource", "(I)V", (void *)android_media_MediaRecorder_setAudioSource},
|
||||
{"setPrivacySensitive", "(Z)V", (void *)android_media_MediaRecorder_setPrivacySensitive},
|
||||
{"isPrivacySensitive", "()Z", (void *)android_media_MediaRecorder_isPrivacySensitive},
|
||||
{"setOutputFormat", "(I)V", (void *)android_media_MediaRecorder_setOutputFormat},
|
||||
{"setVideoEncoder", "(I)V", (void *)android_media_MediaRecorder_setVideoEncoder},
|
||||
{"setAudioEncoder", "(I)V", (void *)android_media_MediaRecorder_setAudioEncoder},
|
||||
|
||||
Reference in New Issue
Block a user