Loading core/java/android/companion/virtual/audio/AudioInjection.java +10 −3 Original line number Diff line number Diff line Loading @@ -43,13 +43,20 @@ public final class AudioInjection { private static final String TAG = "AudioInjection"; private final Object mLock = new Object(); @GuardedBy("mLock") @Nullable private AudioTrack mAudioTrack; @GuardedBy("mLock") private int mPlayState = PLAYSTATE_STOPPED; @GuardedBy("mLock") private boolean mIsSilent; /** Sets if the injected microphone sound is silent. */ void setSilent(boolean isSilent) { synchronized (mLock) { mIsSilent = isSilent; } } /** * Sets the {@link AudioTrack} to handle audio injection. Loading Loading @@ -86,7 +93,7 @@ public final class AudioInjection { public int write(@NonNull ByteBuffer audioBuffer, int sizeInBytes, int writeMode) { final int sizeWrite; synchronized (mLock) { if (mAudioTrack != null) { if (mAudioTrack != null && !mIsSilent) { sizeWrite = mAudioTrack.write(audioBuffer, sizeInBytes, writeMode); } else { sizeWrite = 0; Loading core/java/android/companion/virtual/audio/UserRestrictionsDetector.java 0 → 100644 +96 −0 Original line number Diff line number Diff line /* * Copyright (C) 2022 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.companion.virtual.audio; import android.annotation.NonNull; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.os.Bundle; import android.os.UserManager; import com.android.internal.annotations.GuardedBy; /** * Class to detect the user restrictions change for microphone usage. */ final class UserRestrictionsDetector extends BroadcastReceiver { private static final String TAG = "UserRestrictionsDetector"; /** Interface for listening user restrictions change. */ interface UserRestrictionsCallback { /** Notifies when value of {@link UserManager#DISALLOW_UNMUTE_MICROPHONE} is changed. */ void onMicrophoneRestrictionChanged(boolean isUnmuteMicDisallowed); } private final Context mContext; private final UserManager mUserManager; private final Object mLock = new Object(); @GuardedBy("mLock") private boolean mIsUnmuteMicDisallowed; private UserRestrictionsCallback mUserRestrictionsCallback; UserRestrictionsDetector(Context context) { mContext = context; mUserManager = context.getSystemService(UserManager.class); } /** Returns value of {@link UserManager#DISALLOW_UNMUTE_MICROPHONE}. */ boolean isUnmuteMicrophoneDisallowed() { Bundle bundle = mUserManager.getUserRestrictions(); return bundle.getBoolean(UserManager.DISALLOW_UNMUTE_MICROPHONE); } /** 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); synchronized (mLock) { // Gets initial value. mIsUnmuteMicDisallowed = isUnmuteMicrophoneDisallowed(); } } /** Unregisters user restrictions change. */ void unregister() { mUserRestrictionsCallback = null; mContext.unregisterReceiver(/* receiver= */ this); } @Override public void onReceive(Context context, Intent intent) { final String action = intent.getAction(); if (UserManager.ACTION_USER_RESTRICTIONS_CHANGED.equals(action)) { boolean isUnmuteMicDisallowed = isUnmuteMicrophoneDisallowed(); synchronized (mLock) { if (isUnmuteMicDisallowed == mIsUnmuteMicDisallowed) { return; } mIsUnmuteMicDisallowed = isUnmuteMicDisallowed; } if (mUserRestrictionsCallback != null) { mUserRestrictionsCallback.onMicrophoneRestrictionChanged(isUnmuteMicDisallowed); } } } } core/java/android/companion/virtual/audio/VirtualAudioSession.java +16 −2 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ package android.companion.virtual.audio; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.companion.virtual.audio.UserRestrictionsDetector.UserRestrictionsCallback; import android.companion.virtual.audio.VirtualAudioDevice.AudioConfigurationChangeCallback; import android.content.Context; import android.media.AudioFormat; Loading Loading @@ -50,10 +51,11 @@ import java.util.concurrent.Executor; */ @VisibleForTesting public final class VirtualAudioSession extends IAudioSessionCallback.Stub implements Closeable { UserRestrictionsCallback, Closeable { private static final String TAG = "VirtualAudioSession"; private final Context mContext; private final UserRestrictionsDetector mUserRestrictionsDetector; /** The {@link Executor} for sending {@link AudioConfigurationChangeCallback} to the caller */ private final Executor mExecutor; @Nullable Loading Loading @@ -81,6 +83,7 @@ public final class VirtualAudioSession extends IAudioSessionCallback.Stub implem public VirtualAudioSession(Context context, @Nullable AudioConfigurationChangeCallback callback, @Nullable Executor executor) { mContext = context; mUserRestrictionsDetector = new UserRestrictionsDetector(context); mCallback = callback; mExecutor = executor != null ? executor : context.getMainExecutor(); } Loading Loading @@ -117,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( Loading @@ -127,6 +130,7 @@ public final class VirtualAudioSession extends IAudioSessionCallback.Stub implem mInjectionFormat = injectionFormat; mAudioInjection = new AudioInjection(); mAudioInjection.play(); mAudioInjection.setSilent(mUserRestrictionsDetector.isUnmuteMicrophoneDisallowed()); return mAudioInjection; } } Loading Loading @@ -170,6 +174,7 @@ public final class VirtualAudioSession extends IAudioSessionCallback.Stub implem @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) @Override public void close() { mUserRestrictionsDetector.unregister(); releaseAudioStreams(); synchronized (mLock) { mAudioCapture = null; Loading @@ -179,6 +184,15 @@ public final class VirtualAudioSession extends IAudioSessionCallback.Stub implem } } @Override public void onMicrophoneRestrictionChanged(boolean isUnmuteMicDisallowed) { synchronized (mLock) { if (mAudioInjection != null) { mAudioInjection.setSilent(isUnmuteMicDisallowed); } } } @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) private void createAudioStreams(int[] appUids) { synchronized (mLock) { Loading Loading
core/java/android/companion/virtual/audio/AudioInjection.java +10 −3 Original line number Diff line number Diff line Loading @@ -43,13 +43,20 @@ public final class AudioInjection { private static final String TAG = "AudioInjection"; private final Object mLock = new Object(); @GuardedBy("mLock") @Nullable private AudioTrack mAudioTrack; @GuardedBy("mLock") private int mPlayState = PLAYSTATE_STOPPED; @GuardedBy("mLock") private boolean mIsSilent; /** Sets if the injected microphone sound is silent. */ void setSilent(boolean isSilent) { synchronized (mLock) { mIsSilent = isSilent; } } /** * Sets the {@link AudioTrack} to handle audio injection. Loading Loading @@ -86,7 +93,7 @@ public final class AudioInjection { public int write(@NonNull ByteBuffer audioBuffer, int sizeInBytes, int writeMode) { final int sizeWrite; synchronized (mLock) { if (mAudioTrack != null) { if (mAudioTrack != null && !mIsSilent) { sizeWrite = mAudioTrack.write(audioBuffer, sizeInBytes, writeMode); } else { sizeWrite = 0; Loading
core/java/android/companion/virtual/audio/UserRestrictionsDetector.java 0 → 100644 +96 −0 Original line number Diff line number Diff line /* * Copyright (C) 2022 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.companion.virtual.audio; import android.annotation.NonNull; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.os.Bundle; import android.os.UserManager; import com.android.internal.annotations.GuardedBy; /** * Class to detect the user restrictions change for microphone usage. */ final class UserRestrictionsDetector extends BroadcastReceiver { private static final String TAG = "UserRestrictionsDetector"; /** Interface for listening user restrictions change. */ interface UserRestrictionsCallback { /** Notifies when value of {@link UserManager#DISALLOW_UNMUTE_MICROPHONE} is changed. */ void onMicrophoneRestrictionChanged(boolean isUnmuteMicDisallowed); } private final Context mContext; private final UserManager mUserManager; private final Object mLock = new Object(); @GuardedBy("mLock") private boolean mIsUnmuteMicDisallowed; private UserRestrictionsCallback mUserRestrictionsCallback; UserRestrictionsDetector(Context context) { mContext = context; mUserManager = context.getSystemService(UserManager.class); } /** Returns value of {@link UserManager#DISALLOW_UNMUTE_MICROPHONE}. */ boolean isUnmuteMicrophoneDisallowed() { Bundle bundle = mUserManager.getUserRestrictions(); return bundle.getBoolean(UserManager.DISALLOW_UNMUTE_MICROPHONE); } /** 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); synchronized (mLock) { // Gets initial value. mIsUnmuteMicDisallowed = isUnmuteMicrophoneDisallowed(); } } /** Unregisters user restrictions change. */ void unregister() { mUserRestrictionsCallback = null; mContext.unregisterReceiver(/* receiver= */ this); } @Override public void onReceive(Context context, Intent intent) { final String action = intent.getAction(); if (UserManager.ACTION_USER_RESTRICTIONS_CHANGED.equals(action)) { boolean isUnmuteMicDisallowed = isUnmuteMicrophoneDisallowed(); synchronized (mLock) { if (isUnmuteMicDisallowed == mIsUnmuteMicDisallowed) { return; } mIsUnmuteMicDisallowed = isUnmuteMicDisallowed; } if (mUserRestrictionsCallback != null) { mUserRestrictionsCallback.onMicrophoneRestrictionChanged(isUnmuteMicDisallowed); } } } }
core/java/android/companion/virtual/audio/VirtualAudioSession.java +16 −2 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ package android.companion.virtual.audio; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.companion.virtual.audio.UserRestrictionsDetector.UserRestrictionsCallback; import android.companion.virtual.audio.VirtualAudioDevice.AudioConfigurationChangeCallback; import android.content.Context; import android.media.AudioFormat; Loading Loading @@ -50,10 +51,11 @@ import java.util.concurrent.Executor; */ @VisibleForTesting public final class VirtualAudioSession extends IAudioSessionCallback.Stub implements Closeable { UserRestrictionsCallback, Closeable { private static final String TAG = "VirtualAudioSession"; private final Context mContext; private final UserRestrictionsDetector mUserRestrictionsDetector; /** The {@link Executor} for sending {@link AudioConfigurationChangeCallback} to the caller */ private final Executor mExecutor; @Nullable Loading Loading @@ -81,6 +83,7 @@ public final class VirtualAudioSession extends IAudioSessionCallback.Stub implem public VirtualAudioSession(Context context, @Nullable AudioConfigurationChangeCallback callback, @Nullable Executor executor) { mContext = context; mUserRestrictionsDetector = new UserRestrictionsDetector(context); mCallback = callback; mExecutor = executor != null ? executor : context.getMainExecutor(); } Loading Loading @@ -117,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( Loading @@ -127,6 +130,7 @@ public final class VirtualAudioSession extends IAudioSessionCallback.Stub implem mInjectionFormat = injectionFormat; mAudioInjection = new AudioInjection(); mAudioInjection.play(); mAudioInjection.setSilent(mUserRestrictionsDetector.isUnmuteMicrophoneDisallowed()); return mAudioInjection; } } Loading Loading @@ -170,6 +174,7 @@ public final class VirtualAudioSession extends IAudioSessionCallback.Stub implem @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) @Override public void close() { mUserRestrictionsDetector.unregister(); releaseAudioStreams(); synchronized (mLock) { mAudioCapture = null; Loading @@ -179,6 +184,15 @@ public final class VirtualAudioSession extends IAudioSessionCallback.Stub implem } } @Override public void onMicrophoneRestrictionChanged(boolean isUnmuteMicDisallowed) { synchronized (mLock) { if (mAudioInjection != null) { mAudioInjection.setSilent(isUnmuteMicDisallowed); } } } @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) private void createAudioStreams(int[] appUids) { synchronized (mLock) { Loading