diff options
| -rw-r--r-- | api/system-current.txt | 1 | ||||
| -rw-r--r-- | media/java/android/media/AudioManager.java | 22 | ||||
| -rw-r--r-- | media/java/android/media/IAudioService.aidl | 2 | ||||
| -rw-r--r-- | media/java/android/media/audiopolicy/AudioPolicy.java | 60 | ||||
| -rw-r--r-- | services/core/java/com/android/server/audio/AudioService.java | 23 |
5 files changed, 107 insertions, 1 deletions
diff --git a/api/system-current.txt b/api/system-current.txt index 681147a536c2..03a3a55c50c8 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -3487,6 +3487,7 @@ package android.media { method public void setAudioServerStateCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.AudioManager.AudioServerStateCallback); method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void setFocusRequestResult(@NonNull android.media.AudioFocusInfo, int, @NonNull android.media.audiopolicy.AudioPolicy); method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void setVolumeIndexForAttributes(@NonNull android.media.AudioAttributes, int, int); + method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void unregisterAudioPolicy(@NonNull android.media.audiopolicy.AudioPolicy); method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void unregisterAudioPolicyAsync(@NonNull android.media.audiopolicy.AudioPolicy); method public void unregisterVolumeGroupCallback(@NonNull android.media.AudioManager.VolumeGroupCallback); field public static final int AUDIOFOCUS_FLAG_DELAY_OK = 1; // 0x1 diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java index 7783a4d6c869..c11f44600be4 100644 --- a/media/java/android/media/AudioManager.java +++ b/media/java/android/media/AudioManager.java @@ -3308,6 +3308,7 @@ public class AudioManager { /** * @hide + * Unregisters an {@link AudioPolicy} asynchronously. * @param policy the non-null {@link AudioPolicy} to unregister. */ @SystemApi @@ -3329,6 +3330,27 @@ public class AudioManager { } } + /** + * @hide + * Unregisters an {@link AudioPolicy} synchronously. + * This method also invalidates all {@link AudioRecord} and {@link AudioTrack} objects + * associated with mixes of this policy. + * @param policy the non-null {@link AudioPolicy} to unregister. + */ + @SystemApi + @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) + public void unregisterAudioPolicy(@NonNull AudioPolicy policy) { + Preconditions.checkNotNull(policy, "Illegal null AudioPolicy argument"); + final IAudioService service = getService(); + try { + policy.invalidateCaptorsAndInjectors(); + service.unregisterAudioPolicy(policy.cb()); + policy.setRegistration(null); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + //==================================================================== // Notification of playback activity & playback configuration /** diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl index 02856678879e..95d89bb75b34 100644 --- a/media/java/android/media/IAudioService.aidl +++ b/media/java/android/media/IAudioService.aidl @@ -199,6 +199,8 @@ interface IAudioService { oneway void unregisterAudioPolicyAsync(in IAudioPolicyCallback pcb); + void unregisterAudioPolicy(in IAudioPolicyCallback pcb); + int addMixForPolicy(in AudioPolicyConfig policyConfig, in IAudioPolicyCallback pcb); int removeMixForPolicy(in AudioPolicyConfig policyConfig, in IAudioPolicyCallback pcb); diff --git a/media/java/android/media/audiopolicy/AudioPolicy.java b/media/java/android/media/audiopolicy/AudioPolicy.java index 5f65d586b730..978583e99971 100644 --- a/media/java/android/media/audiopolicy/AudioPolicy.java +++ b/media/java/android/media/audiopolicy/AudioPolicy.java @@ -43,8 +43,11 @@ import android.os.ServiceManager; import android.util.Log; import android.util.Slog; +import com.android.internal.annotations.GuardedBy; + import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.List; @@ -74,6 +77,19 @@ public class AudioPolicy { private boolean mIsFocusPolicy; /** + * The list of AudioTrack instances created to inject audio into the associated mixes + * Lazy initialization in {@link #createAudioTrackSource(AudioMix)} + */ + @GuardedBy("mLock") + @Nullable private ArrayList<WeakReference<AudioTrack>> mInjectors; + /** + * The list AudioRecord instances created to capture audio from the associated mixes + * Lazy initialization in {@link #createAudioRecordSink(AudioMix)} + */ + @GuardedBy("mLock") + @Nullable private ArrayList<WeakReference<AudioRecord>> mCaptors; + + /** * The behavior of a policy with regards to audio focus where it relies on the application * to do the ducking, the is the legacy and default behavior. */ @@ -606,6 +622,12 @@ public class AudioPolicy { AudioFormat.CHANNEL_IN_STEREO, mix.getFormat().getEncoding()), AudioManager.AUDIO_SESSION_ID_GENERATE ); + synchronized (mLock) { + if (mCaptors == null) { + mCaptors = new ArrayList<>(1); + } + mCaptors.add(new WeakReference<AudioRecord>(ar)); + } return ar; } @@ -638,9 +660,47 @@ public class AudioPolicy { AudioTrack.MODE_STREAM, AudioManager.AUDIO_SESSION_ID_GENERATE ); + synchronized (mLock) { + if (mInjectors == null) { + mInjectors = new ArrayList<>(1); + } + mInjectors.add(new WeakReference<AudioTrack>(at)); + } return at; } + /** + * @hide + */ + public void invalidateCaptorsAndInjectors() { + if (!policyReadyToUse()) { + return; + } + synchronized (mLock) { + if (mInjectors != null) { + for (final WeakReference<AudioTrack> weakTrack : mInjectors) { + final AudioTrack track = weakTrack.get(); + if (track == null) { + break; + } + // TODO: add synchronous versions + track.stop(); + track.flush(); + } + } + if (mCaptors != null) { + for (final WeakReference<AudioRecord> weakRecord : mCaptors) { + final AudioRecord record = weakRecord.get(); + if (record == null) { + break; + } + // TODO: if needed: implement an invalidate method + record.stop(); + } + } + } + } + public int getStatus() { return mStatus; } diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index 91d19def1766..100113cbb5a5 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -6387,7 +6387,28 @@ public class AudioService extends IAudioService.Stub return mProjectionService; } - public void unregisterAudioPolicyAsync(IAudioPolicyCallback pcb) { + /** + * See {@link AudioManager#unregisterAudioPolicyAsync(AudioPolicy)} + * Declared oneway + * @param pcb nullable because on service interface + */ + public void unregisterAudioPolicyAsync(@Nullable IAudioPolicyCallback pcb) { + unregisterAudioPolicy(pcb); + } + + /** + * See {@link AudioManager#unregisterAudioPolicy(AudioPolicy)} + * @param pcb nullable because on service interface + */ + public void unregisterAudioPolicy(@Nullable IAudioPolicyCallback pcb) { + if (pcb == null) { + return; + } + unregisterAudioPolicyInt(pcb); + } + + + private void unregisterAudioPolicyInt(@NonNull IAudioPolicyCallback pcb) { mDynPolicyLogger.log((new AudioEventLogger.StringEvent("unregisterAudioPolicyAsync for " + pcb.asBinder()).printLog(TAG))); synchronized (mAudioPolicies) { |