Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 60e26f7a authored by Yuanjia Hsu's avatar Yuanjia Hsu Committed by Android (Google) Code Review
Browse files

Merge "Clean up audio resources when VirtualDevice is closed"

parents 9f8dd75e 5536865e
Loading
Loading
Loading
Loading
+17 −5
Original line number Diff line number Diff line
@@ -148,6 +148,8 @@ public final class VirtualDeviceManager {
                        }
                    }
                };
        @Nullable
        private VirtualAudioDevice mVirtualAudioDevice;

        private VirtualDevice(
                IVirtualDeviceManager service,
@@ -255,8 +257,8 @@ public final class VirtualDeviceManager {
        }

        /**
         * Closes the virtual device, stopping and tearing down any virtual displays,
         * audio policies, and event injection that's currently in progress.
         * Closes the virtual device, stopping and tearing down any virtual displays, associated
         * virtual audio device, and event injection that's currently in progress.
         */
        @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
        public void close() {
@@ -265,6 +267,10 @@ public final class VirtualDeviceManager {
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
            }
            if (mVirtualAudioDevice != null) {
                mVirtualAudioDevice.close();
                mVirtualAudioDevice = null;
            }
        }

        /**
@@ -351,8 +357,10 @@ public final class VirtualDeviceManager {
         * Creates a VirtualAudioDevice, capable of recording audio emanating from this device,
         * or injecting audio from another device.
         *
         * <p>Note: This object does not support capturing privileged playback, such as voice call
         * audio.
         * <p>Note: One {@link VirtualDevice} can only create one {@link VirtualAudioDevice}, so
         * calling this method multiple times will return the same instance. When
         * {@link VirtualDevice#close()} is called, the associated {@link VirtualAudioDevice} will
         * also be closed automatically.
         *
         * @param display The target virtual display to capture from and inject into.
         * @param executor The {@link Executor} object for the thread on which to execute
@@ -368,7 +376,11 @@ public final class VirtualDeviceManager {
                @NonNull VirtualDisplay display,
                @Nullable Executor executor,
                @Nullable AudioConfigurationChangeCallback callback) {
            return new VirtualAudioDevice(mContext, mVirtualDevice, display, executor, callback);
            if (mVirtualAudioDevice == null) {
                mVirtualAudioDevice = new VirtualAudioDevice(
                        mContext, mVirtualDevice, display, executor, callback);
            }
            return mVirtualAudioDevice;
        }

        /**
+4 −3
Original line number Diff line number Diff line
@@ -60,7 +60,6 @@ final class UserRestrictionsDetector extends BroadcastReceiver {
    /** Registers user restrictions change. */
    void register(@NonNull UserRestrictionsCallback callback) {
        mUserRestrictionsCallback = callback;

        IntentFilter filter = new IntentFilter();
        filter.addAction(UserManager.ACTION_USER_RESTRICTIONS_CHANGED);
        mContext.registerReceiver(/* receiver= */ this, filter);
@@ -73,9 +72,11 @@ final class UserRestrictionsDetector extends BroadcastReceiver {

    /** Unregisters user restrictions change. */
    void unregister() {
        if (mUserRestrictionsCallback != null) {
            mUserRestrictionsCallback = null;
            mContext.unregisterReceiver(/* receiver= */ this);
        }
    }

    @Override
    public void onReceive(Context context, Intent intent) {
+6 −1
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@ import android.companion.virtual.IVirtualDevice;
import android.content.Context;
import android.hardware.display.VirtualDisplay;
import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioPlaybackConfiguration;
import android.media.AudioRecordingConfiguration;
import android.os.RemoteException;
@@ -96,7 +97,7 @@ public final class VirtualAudioDevice implements Closeable {

        if (mOngoingSession != null && mOngoingSession.getAudioInjection() != null) {
            throw new IllegalStateException("Cannot start an audio injection while a session is "
                    + "ongoing. Call close() on this device first to end the previous injection.");
                    + "ongoing. Call close() on this device first to end the previous session.");
        }
        if (mOngoingSession == null) {
            mOngoingSession = new VirtualAudioSession(mContext, mCallback, mExecutor);
@@ -114,6 +115,9 @@ public final class VirtualAudioDevice implements Closeable {
    /**
     * Begins recording audio emanating from this device.
     *
     * <p>Note: This method does not support capturing privileged playback, which means the
     * application can opt out of capturing by {@link AudioManager#setAllowedCapturePolicy(int)}.
     *
     * @return An {@link AudioCapture} containing the recorded audio.
     */
    @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
@@ -150,6 +154,7 @@ public final class VirtualAudioDevice implements Closeable {
        return mOngoingSession != null ? mOngoingSession.getAudioInjection() : null;
    }

    /** Stops audio capture and injection then releases all the resources */
    @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
    @Override
    public void close() {
+3 −1
Original line number Diff line number Diff line
@@ -120,7 +120,7 @@ public final class VirtualAudioSession extends IAudioSessionCallback.Stub implem
    @NonNull
    public AudioInjection startAudioInjection(@NonNull AudioFormat injectionFormat) {
        Objects.requireNonNull(injectionFormat, "injectionFormat must not be null");
        mUserRestrictionsDetector.register(/* callback= */ this);

        synchronized (mLock) {
            if (mAudioInjection != null) {
                throw new IllegalStateException(
@@ -130,6 +130,8 @@ public final class VirtualAudioSession extends IAudioSessionCallback.Stub implem
            mInjectionFormat = injectionFormat;
            mAudioInjection = new AudioInjection();
            mAudioInjection.play();

            mUserRestrictionsDetector.register(/* callback= */ this);
            mAudioInjection.setSilent(mUserRestrictionsDetector.isUnmuteMicrophoneDisallowed());
            return mAudioInjection;
        }
+4 −0
Original line number Diff line number Diff line
@@ -235,6 +235,10 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
                });
                mPerDisplayWakelocks.clear();
            }
            if (mVirtualAudioController != null) {
                mVirtualAudioController.stopListening();
                mVirtualAudioController = null;
            }
        }
        mListener.onClose(mAssociationInfo.getId());
        mAppToken.unlinkToDeath(this, 0);
Loading