Loading api/current.txt +1 −1 Original line number Diff line number Diff line Loading @@ -23385,7 +23385,7 @@ package android.media { } public static final class AudioPlaybackCaptureConfiguration.Builder { ctor public AudioPlaybackCaptureConfiguration.Builder(); ctor public AudioPlaybackCaptureConfiguration.Builder(@NonNull android.media.projection.MediaProjection); method public android.media.AudioPlaybackCaptureConfiguration.Builder addMatchingUid(int); method public android.media.AudioPlaybackCaptureConfiguration.Builder addMatchingUsage(@NonNull android.media.AudioAttributes); method public android.media.AudioPlaybackCaptureConfiguration build(); media/java/android/media/AudioManager.java +4 −1 Original line number Diff line number Diff line Loading @@ -36,6 +36,7 @@ import android.content.Context; import android.content.Intent; import android.media.audiopolicy.AudioPolicy; import android.media.audiopolicy.AudioPolicy.AudioPolicyFocusListener; import android.media.projection.MediaProjection; import android.media.session.MediaController; import android.media.session.MediaSession; import android.media.session.MediaSessionLegacyHelper; Loading Loading @@ -3197,8 +3198,10 @@ public class AudioManager { } final IAudioService service = getService(); try { MediaProjection projection = policy.getMediaProjection(); String regId = service.registerAudioPolicy(policy.getConfig(), policy.cb(), policy.hasFocusListener(), policy.isFocusPolicy(), policy.isVolumeController()); policy.hasFocusListener(), policy.isFocusPolicy(), policy.isVolumeController(), projection == null ? null : projection.getProjection()); if (regId == null) { return ERROR; } else { Loading media/java/android/media/AudioPlaybackCaptureConfiguration.java +42 −6 Original line number Diff line number Diff line Loading @@ -19,34 +19,52 @@ package android.media; import android.annotation.NonNull; import android.media.audiopolicy.AudioMix; import android.media.audiopolicy.AudioMixingRule; import android.media.projection.MediaProjection; import android.os.RemoteException; import com.android.internal.util.Preconditions; /** * Configuration for capturing audio played by other apps. * * For privacy and copyright reason, only the following audio can be captured: * - usage MUST be UNKNOWN or GAME or MEDIA. All other usages CAN NOT be capturable. * - audio attributes MUST NOT have the FLAG_NO_CAPTURE * - played by apps that MUST be in the same user profile as the capturing app * (eg work profile can not capture user profile apps and vice-versa). * - played by apps that MUST NOT have in their manifest.xml the application * attribute android:allowPlaybackCapture="false" * - played by apps that MUST have a targetSdkVersion higher or equal to 29 (Q). * * <p>An example for creating a capture configuration for capturing all media playback: * * <pre> * MediaProjection mediaProjection; * // Retrieve a audio capable projection from the MediaProjectionManager * AudioAttributes mediaAttr = new AudioAttributes.Builder() * .setUsage(AudioAttributes.USAGE_MEDIA) * .build(); * AudioPlaybackCaptureConfiguration config = new AudioPlaybackCaptureConfiguration.Builder() * AudioPlaybackCaptureConfiguration config = * new AudioPlaybackCaptureConfiguration.Builder(mediaProjection) * .addMatchingUsage(mediaAttr) * .build(); * AudioRecord record = new AudioRecord.Builder() * .setPlaybackCaptureConfig(config) * .setAudioPlaybackCaptureConfig(config) * .build(); * </pre> * * @see AudioRecord.Builder#setPlaybackCaptureConfig(AudioPlaybackCaptureConfiguration) * @see MediaProjectionManager#getMediaProjection(int, Intent) * @see AudioRecord.Builder#setAudioPlaybackCaptureConfig(AudioPlaybackCaptureConfiguration) */ public final class AudioPlaybackCaptureConfiguration { private final AudioMixingRule mAudioMixingRule; private final MediaProjection mProjection; private AudioPlaybackCaptureConfiguration(AudioMixingRule audioMixingRule) { private AudioPlaybackCaptureConfiguration(AudioMixingRule audioMixingRule, MediaProjection projection) { mAudioMixingRule = audioMixingRule; mProjection = projection; } /** Loading @@ -60,6 +78,9 @@ public final class AudioPlaybackCaptureConfiguration { .setRouteFlags(AudioMix.ROUTE_FLAG_LOOP_BACK | AudioMix.ROUTE_FLAG_RENDER) .build(); } MediaProjection getMediaProjection() { return mProjection; } /** Builder for creating {@link AudioPlaybackCaptureConfiguration} instances. */ public static final class Builder { Loading @@ -70,12 +91,26 @@ public final class AudioPlaybackCaptureConfiguration { private static final String ERROR_MESSAGE_MISMATCHED_RULES = "Inclusive and exclusive usage rules cannot be combined"; private static final String ERROR_MESSAGE_START_ACTIVITY_FAILED = "startActivityForResult failed"; private static final String ERROR_MESSAGE_NON_AUDIO_PROJECTION = "MediaProjection can not project audio"; private final AudioMixingRule.Builder mAudioMixingRuleBuilder; private final MediaProjection mProjection; private int mUsageMatchType = MATCH_TYPE_UNSPECIFIED; private int mUidMatchType = MATCH_TYPE_UNSPECIFIED; public Builder() { /** @param projection A MediaProjection that supports audio projection. */ public Builder(@NonNull MediaProjection projection) { Preconditions.checkNotNull(projection); try { Preconditions.checkArgument(projection.getProjection().canProjectAudio(), ERROR_MESSAGE_NON_AUDIO_PROJECTION); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } mProjection = projection; mAudioMixingRuleBuilder = new AudioMixingRule.Builder(); } Loading Loading @@ -155,7 +190,8 @@ public final class AudioPlaybackCaptureConfiguration { * @throws UnsupportedOperationException if the parameters set are incompatible. */ public AudioPlaybackCaptureConfiguration build() { return new AudioPlaybackCaptureConfiguration(mAudioMixingRuleBuilder.build()); return new AudioPlaybackCaptureConfiguration(mAudioMixingRuleBuilder.build(), mProjection); } } } media/java/android/media/AudioRecord.java +3 −0 Original line number Diff line number Diff line Loading @@ -26,6 +26,7 @@ import android.annotation.UnsupportedAppUsage; import android.app.ActivityThread; import android.media.audiopolicy.AudioMix; import android.media.audiopolicy.AudioPolicy; import android.media.projection.MediaProjection; import android.os.Binder; import android.os.Handler; import android.os.IBinder; Loading Loading @@ -648,7 +649,9 @@ public class AudioRecord implements AudioRouting, MicrophoneDirection, private AudioRecord buildAudioPlaybackCaptureRecord() { AudioMix audioMix = mAudioPlaybackCaptureConfiguration.createAudioMix(mFormat); MediaProjection projection = mAudioPlaybackCaptureConfiguration.getMediaProjection(); AudioPolicy audioPolicy = new AudioPolicy.Builder(/*context=*/ null) .setMediaProjection(projection) .addMix(audioMix).build(); AudioRecord record = audioPolicy.createAudioRecordSink(audioMix); record.unregisterAudioPolicyOnRelease(audioPolicy); Loading media/java/android/media/IAudioService.aidl +2 −1 Original line number Diff line number Diff line Loading @@ -34,6 +34,7 @@ import android.media.PlayerBase; import android.media.VolumePolicy; import android.media.audiopolicy.AudioPolicyConfig; import android.media.audiopolicy.IAudioPolicyCallback; import android.media.projection.IMediaProjection; /** * {@hide} Loading Loading @@ -176,7 +177,7 @@ interface IAudioService { String registerAudioPolicy(in AudioPolicyConfig policyConfig, in IAudioPolicyCallback pcb, boolean hasFocusListener, boolean isFocusPolicy, boolean isVolumeController); boolean isVolumeController, in IMediaProjection projection); oneway void unregisterAudioPolicyAsync(in IAudioPolicyCallback pcb); Loading Loading
api/current.txt +1 −1 Original line number Diff line number Diff line Loading @@ -23385,7 +23385,7 @@ package android.media { } public static final class AudioPlaybackCaptureConfiguration.Builder { ctor public AudioPlaybackCaptureConfiguration.Builder(); ctor public AudioPlaybackCaptureConfiguration.Builder(@NonNull android.media.projection.MediaProjection); method public android.media.AudioPlaybackCaptureConfiguration.Builder addMatchingUid(int); method public android.media.AudioPlaybackCaptureConfiguration.Builder addMatchingUsage(@NonNull android.media.AudioAttributes); method public android.media.AudioPlaybackCaptureConfiguration build();
media/java/android/media/AudioManager.java +4 −1 Original line number Diff line number Diff line Loading @@ -36,6 +36,7 @@ import android.content.Context; import android.content.Intent; import android.media.audiopolicy.AudioPolicy; import android.media.audiopolicy.AudioPolicy.AudioPolicyFocusListener; import android.media.projection.MediaProjection; import android.media.session.MediaController; import android.media.session.MediaSession; import android.media.session.MediaSessionLegacyHelper; Loading Loading @@ -3197,8 +3198,10 @@ public class AudioManager { } final IAudioService service = getService(); try { MediaProjection projection = policy.getMediaProjection(); String regId = service.registerAudioPolicy(policy.getConfig(), policy.cb(), policy.hasFocusListener(), policy.isFocusPolicy(), policy.isVolumeController()); policy.hasFocusListener(), policy.isFocusPolicy(), policy.isVolumeController(), projection == null ? null : projection.getProjection()); if (regId == null) { return ERROR; } else { Loading
media/java/android/media/AudioPlaybackCaptureConfiguration.java +42 −6 Original line number Diff line number Diff line Loading @@ -19,34 +19,52 @@ package android.media; import android.annotation.NonNull; import android.media.audiopolicy.AudioMix; import android.media.audiopolicy.AudioMixingRule; import android.media.projection.MediaProjection; import android.os.RemoteException; import com.android.internal.util.Preconditions; /** * Configuration for capturing audio played by other apps. * * For privacy and copyright reason, only the following audio can be captured: * - usage MUST be UNKNOWN or GAME or MEDIA. All other usages CAN NOT be capturable. * - audio attributes MUST NOT have the FLAG_NO_CAPTURE * - played by apps that MUST be in the same user profile as the capturing app * (eg work profile can not capture user profile apps and vice-versa). * - played by apps that MUST NOT have in their manifest.xml the application * attribute android:allowPlaybackCapture="false" * - played by apps that MUST have a targetSdkVersion higher or equal to 29 (Q). * * <p>An example for creating a capture configuration for capturing all media playback: * * <pre> * MediaProjection mediaProjection; * // Retrieve a audio capable projection from the MediaProjectionManager * AudioAttributes mediaAttr = new AudioAttributes.Builder() * .setUsage(AudioAttributes.USAGE_MEDIA) * .build(); * AudioPlaybackCaptureConfiguration config = new AudioPlaybackCaptureConfiguration.Builder() * AudioPlaybackCaptureConfiguration config = * new AudioPlaybackCaptureConfiguration.Builder(mediaProjection) * .addMatchingUsage(mediaAttr) * .build(); * AudioRecord record = new AudioRecord.Builder() * .setPlaybackCaptureConfig(config) * .setAudioPlaybackCaptureConfig(config) * .build(); * </pre> * * @see AudioRecord.Builder#setPlaybackCaptureConfig(AudioPlaybackCaptureConfiguration) * @see MediaProjectionManager#getMediaProjection(int, Intent) * @see AudioRecord.Builder#setAudioPlaybackCaptureConfig(AudioPlaybackCaptureConfiguration) */ public final class AudioPlaybackCaptureConfiguration { private final AudioMixingRule mAudioMixingRule; private final MediaProjection mProjection; private AudioPlaybackCaptureConfiguration(AudioMixingRule audioMixingRule) { private AudioPlaybackCaptureConfiguration(AudioMixingRule audioMixingRule, MediaProjection projection) { mAudioMixingRule = audioMixingRule; mProjection = projection; } /** Loading @@ -60,6 +78,9 @@ public final class AudioPlaybackCaptureConfiguration { .setRouteFlags(AudioMix.ROUTE_FLAG_LOOP_BACK | AudioMix.ROUTE_FLAG_RENDER) .build(); } MediaProjection getMediaProjection() { return mProjection; } /** Builder for creating {@link AudioPlaybackCaptureConfiguration} instances. */ public static final class Builder { Loading @@ -70,12 +91,26 @@ public final class AudioPlaybackCaptureConfiguration { private static final String ERROR_MESSAGE_MISMATCHED_RULES = "Inclusive and exclusive usage rules cannot be combined"; private static final String ERROR_MESSAGE_START_ACTIVITY_FAILED = "startActivityForResult failed"; private static final String ERROR_MESSAGE_NON_AUDIO_PROJECTION = "MediaProjection can not project audio"; private final AudioMixingRule.Builder mAudioMixingRuleBuilder; private final MediaProjection mProjection; private int mUsageMatchType = MATCH_TYPE_UNSPECIFIED; private int mUidMatchType = MATCH_TYPE_UNSPECIFIED; public Builder() { /** @param projection A MediaProjection that supports audio projection. */ public Builder(@NonNull MediaProjection projection) { Preconditions.checkNotNull(projection); try { Preconditions.checkArgument(projection.getProjection().canProjectAudio(), ERROR_MESSAGE_NON_AUDIO_PROJECTION); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } mProjection = projection; mAudioMixingRuleBuilder = new AudioMixingRule.Builder(); } Loading Loading @@ -155,7 +190,8 @@ public final class AudioPlaybackCaptureConfiguration { * @throws UnsupportedOperationException if the parameters set are incompatible. */ public AudioPlaybackCaptureConfiguration build() { return new AudioPlaybackCaptureConfiguration(mAudioMixingRuleBuilder.build()); return new AudioPlaybackCaptureConfiguration(mAudioMixingRuleBuilder.build(), mProjection); } } }
media/java/android/media/AudioRecord.java +3 −0 Original line number Diff line number Diff line Loading @@ -26,6 +26,7 @@ import android.annotation.UnsupportedAppUsage; import android.app.ActivityThread; import android.media.audiopolicy.AudioMix; import android.media.audiopolicy.AudioPolicy; import android.media.projection.MediaProjection; import android.os.Binder; import android.os.Handler; import android.os.IBinder; Loading Loading @@ -648,7 +649,9 @@ public class AudioRecord implements AudioRouting, MicrophoneDirection, private AudioRecord buildAudioPlaybackCaptureRecord() { AudioMix audioMix = mAudioPlaybackCaptureConfiguration.createAudioMix(mFormat); MediaProjection projection = mAudioPlaybackCaptureConfiguration.getMediaProjection(); AudioPolicy audioPolicy = new AudioPolicy.Builder(/*context=*/ null) .setMediaProjection(projection) .addMix(audioMix).build(); AudioRecord record = audioPolicy.createAudioRecordSink(audioMix); record.unregisterAudioPolicyOnRelease(audioPolicy); Loading
media/java/android/media/IAudioService.aidl +2 −1 Original line number Diff line number Diff line Loading @@ -34,6 +34,7 @@ import android.media.PlayerBase; import android.media.VolumePolicy; import android.media.audiopolicy.AudioPolicyConfig; import android.media.audiopolicy.IAudioPolicyCallback; import android.media.projection.IMediaProjection; /** * {@hide} Loading Loading @@ -176,7 +177,7 @@ interface IAudioService { String registerAudioPolicy(in AudioPolicyConfig policyConfig, in IAudioPolicyCallback pcb, boolean hasFocusListener, boolean isFocusPolicy, boolean isVolumeController); boolean isVolumeController, in IMediaProjection projection); oneway void unregisterAudioPolicyAsync(in IAudioPolicyCallback pcb); Loading