| /* |
| * Copyright (C) 2024 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.bluetooth; |
| |
| import static android.Manifest.permission.BLUETOOTH_CONNECT; |
| import static android.Manifest.permission.BLUETOOTH_PRIVILEGED; |
| import static android.bluetooth.BluetoothUtils.callService; |
| import static android.bluetooth.BluetoothUtils.logRemoteException; |
| |
| import static java.util.Objects.requireNonNull; |
| |
| import android.annotation.CallbackExecutor; |
| import android.annotation.FlaggedApi; |
| import android.annotation.IntDef; |
| import android.annotation.IntRange; |
| import android.annotation.NonNull; |
| import android.annotation.RequiresNoPermission; |
| import android.annotation.RequiresPermission; |
| import android.annotation.SystemApi; |
| import android.bluetooth.annotations.RequiresBluetoothConnectPermission; |
| import android.content.AttributionSource; |
| import android.os.RemoteException; |
| |
| import com.android.bluetooth.flags.Flags; |
| |
| import java.lang.annotation.Retention; |
| import java.lang.annotation.RetentionPolicy; |
| import java.util.List; |
| import java.util.concurrent.Executor; |
| import java.util.stream.Collectors; |
| import java.util.stream.IntStream; |
| |
| /** |
| * This class provides APIs to control a remote AICS (Audio Input Control Service) |
| * |
| * <p>Each {@link AudioInputControl} object represents an instance of the Audio Input Control |
| * Service (AICS) on the remote device. A device may have multiple instances of the AICS, as |
| * described in the <a href="https://www.bluetooth.com/specifications/specs/aics-1-0/">Audio Input |
| * Control Service Specification (AICS 1.0)</a>. |
| * |
| * @see BluetoothVolumeControl#getAudioInputControlServices |
| * @hide |
| */ |
| @FlaggedApi(Flags.FLAG_AICS_API) |
| @SystemApi |
| public class AudioInputControl { |
| private static final String TAG = AudioInputControl.class.getSimpleName(); |
| |
| /** Unspecified Input */ |
| public static final int AUDIO_INPUT_TYPE_UNSPECIFIED = |
| bluetooth.constants.AudioInputType.UNSPECIFIED; |
| |
| /** Bluetooth Audio Stream */ |
| public static final int AUDIO_INPUT_TYPE_BLUETOOTH = |
| bluetooth.constants.AudioInputType.BLUETOOTH; |
| |
| /** Microphone */ |
| public static final int AUDIO_INPUT_TYPE_MICROPHONE = |
| bluetooth.constants.AudioInputType.MICROPHONE; |
| |
| /** Analog Interface */ |
| public static final int AUDIO_INPUT_TYPE_ANALOG = bluetooth.constants.AudioInputType.ANALOG; |
| |
| /** Digital Interface */ |
| public static final int AUDIO_INPUT_TYPE_DIGITAL = bluetooth.constants.AudioInputType.DIGITAL; |
| |
| /** AM/FM/XM/etc. */ |
| public static final int AUDIO_INPUT_TYPE_RADIO = bluetooth.constants.AudioInputType.RADIO; |
| |
| /** Streaming Audio Source */ |
| public static final int AUDIO_INPUT_TYPE_STREAMING = |
| bluetooth.constants.AudioInputType.STREAMING; |
| |
| /** Transparency/Pass-through */ |
| public static final int AUDIO_INPUT_TYPE_AMBIENT = bluetooth.constants.AudioInputType.AMBIENT; |
| |
| /** @hide */ |
| @Retention(RetentionPolicy.SOURCE) |
| @IntDef( |
| prefix = {"AUDIO_INPUT_TYPE_"}, |
| value = { |
| AUDIO_INPUT_TYPE_UNSPECIFIED, |
| AUDIO_INPUT_TYPE_BLUETOOTH, |
| AUDIO_INPUT_TYPE_MICROPHONE, |
| AUDIO_INPUT_TYPE_ANALOG, |
| AUDIO_INPUT_TYPE_DIGITAL, |
| AUDIO_INPUT_TYPE_RADIO, |
| AUDIO_INPUT_TYPE_STREAMING, |
| AUDIO_INPUT_TYPE_AMBIENT, |
| }) |
| public @interface AudioInputType {} |
| |
| /** Inactive */ |
| public static final int AUDIO_INPUT_STATUS_INACTIVE = |
| bluetooth.constants.aics.AudioInputStatus.INACTIVE; |
| |
| /** Active */ |
| public static final int AUDIO_INPUT_STATUS_ACTIVE = |
| bluetooth.constants.aics.AudioInputStatus.ACTIVE; |
| |
| /** |
| * Status is none of {@link #AUDIO_INPUT_STATUS_ACTIVE}, {@link #AUDIO_INPUT_STATUS_INACTIVE}. |
| * This fallback value will be used for forward compatibility, if the 3.4. Audio Input Status |
| * field extend its definition. |
| */ |
| public static final int AUDIO_INPUT_STATUS_UNKNOWN = -1; |
| |
| /** @hide */ |
| @Retention(RetentionPolicy.SOURCE) |
| @IntDef( |
| prefix = {"AUDIO_INPUT_STATUS_"}, |
| value = { |
| AUDIO_INPUT_STATUS_INACTIVE, |
| AUDIO_INPUT_STATUS_ACTIVE, |
| AUDIO_INPUT_STATUS_UNKNOWN, |
| }) |
| public @interface AudioInputStatus {} |
| |
| /** Not Muted */ |
| public static final int MUTE_NOT_MUTED = bluetooth.constants.aics.Mute.NOT_MUTED; |
| |
| /** Muted */ |
| public static final int MUTE_MUTED = bluetooth.constants.aics.Mute.MUTED; |
| |
| /** |
| * Disabled |
| * |
| * <p>Mute command are disabled by the server. For example with a local privacy switch. |
| */ |
| public static final int MUTE_DISABLED = bluetooth.constants.aics.Mute.DISABLED; |
| |
| /** @hide */ |
| @Retention(RetentionPolicy.SOURCE) |
| @IntDef( |
| prefix = {"MUTE_"}, |
| value = { |
| MUTE_NOT_MUTED, |
| MUTE_MUTED, |
| MUTE_DISABLED, |
| }) |
| public @interface Mute {} |
| |
| /** @hide */ |
| @Retention(RetentionPolicy.SOURCE) |
| @IntDef( |
| prefix = {"MUTE_"}, |
| value = { |
| MUTE_NOT_MUTED, |
| MUTE_MUTED, |
| }) |
| public @interface MuteSettable {} |
| |
| /** |
| * Manual Only |
| * |
| * <p>Gain adjustments are made manually through {@link #setGainSetting}. |
| * |
| * <p>The server cannot be switched to automatic gain. |
| */ |
| public static final int GAIN_MODE_MANUAL_ONLY = bluetooth.constants.aics.GainMode.MANUAL_ONLY; |
| |
| /** |
| * Automatic Only |
| * |
| * <p>Gain adjustments are automatic and calls to {@link #setGainSetting} are ignored. |
| * |
| * <p>The server cannot be switched to manual gain. |
| */ |
| public static final int GAIN_MODE_AUTOMATIC_ONLY = |
| bluetooth.constants.aics.GainMode.AUTOMATIC_ONLY; |
| |
| /** |
| * Manual |
| * |
| * <p>Gain adjustments are made manually through {@link #setGainSetting}. |
| * |
| * <p>The server supports switching between manual and automatic gain mode. |
| */ |
| public static final int GAIN_MODE_MANUAL = bluetooth.constants.aics.GainMode.MANUAL; |
| |
| /** |
| * Automatic |
| * |
| * <p>Gain adjustments are automatic and calls to {@link #setGainSetting} are ignored. |
| * |
| * <p>The server supports switching between manual and automatic gain mode. |
| */ |
| public static final int GAIN_MODE_AUTOMATIC = bluetooth.constants.aics.GainMode.AUTOMATIC; |
| |
| /** @hide */ |
| @Retention(RetentionPolicy.SOURCE) |
| @IntDef( |
| prefix = {"GAIN_MODE_"}, |
| value = { |
| GAIN_MODE_MANUAL_ONLY, |
| GAIN_MODE_AUTOMATIC_ONLY, |
| GAIN_MODE_MANUAL, |
| GAIN_MODE_AUTOMATIC, |
| }) |
| public @interface GainMode {} |
| |
| /** @hide */ |
| @Retention(RetentionPolicy.SOURCE) |
| @IntDef( |
| prefix = {"GAIN_MODE_"}, |
| value = { |
| GAIN_MODE_MANUAL, |
| GAIN_MODE_AUTOMATIC, |
| }) |
| public @interface GainModeSettable {} |
| |
| /** Local identifier of the AICS */ |
| private final int mInstanceId; |
| |
| private final IBluetoothVolumeControl mService; |
| private final BluetoothDevice mDevice; |
| private final AttributionSource mAttributionSource; |
| private final CallbackWrapper<AudioInputCallback, IBluetoothVolumeControl> mCallbackWrapper; |
| |
| AudioInputControl( |
| @NonNull BluetoothDevice device, |
| int id, |
| @NonNull IBluetoothVolumeControl service, |
| @NonNull AttributionSource source) { |
| mDevice = requireNonNull(device); |
| mInstanceId = id; |
| mService = requireNonNull(service); |
| mAttributionSource = requireNonNull(source); |
| mCallbackWrapper = |
| new CallbackWrapper<AudioInputCallback, IBluetoothVolumeControl>( |
| this::registerCallbackFn, this::unregisterCallbackFn); |
| } |
| |
| @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED}) |
| private void registerCallbackFn(IBluetoothVolumeControl vcs) { |
| try { |
| vcs.registerAudioInputControlCallback( |
| mAttributionSource, mDevice, mInstanceId, mCallback); |
| } catch (RemoteException e) { |
| logRemoteException(TAG, e); |
| } |
| } |
| |
| @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED}) |
| private void unregisterCallbackFn(IBluetoothVolumeControl vcs) { |
| try { |
| vcs.unregisterAudioInputControlCallback( |
| mAttributionSource, mDevice, mInstanceId, mCallback); |
| } catch (RemoteException e) { |
| logRemoteException(TAG, e); |
| } |
| } |
| |
| private final IAudioInputCallback mCallback = |
| new IAudioInputCallback.Stub() { |
| @Override |
| @RequiresNoPermission |
| public void onDescriptionChanged(String description) { |
| mCallbackWrapper.forEach(cb -> cb.onDescriptionChanged(description)); |
| } |
| |
| @Override |
| @RequiresNoPermission |
| public void onStatusChanged(int status) { |
| mCallbackWrapper.forEach(cb -> cb.onAudioInputStatusChanged(status)); |
| } |
| |
| @Override |
| @RequiresNoPermission |
| public void onStateChanged(int gainSetting, int mute, int gainMode) { |
| mCallbackWrapper.forEach(cb -> cb.onGainSettingChanged(gainSetting)); |
| mCallbackWrapper.forEach(cb -> cb.onMuteChanged(mute)); |
| mCallbackWrapper.forEach(cb -> cb.onGainModeChanged(gainMode)); |
| } |
| |
| @Override |
| @RequiresNoPermission |
| public void onSetGainSettingFailed() { |
| mCallbackWrapper.forEach(cb -> cb.onSetGainSettingFailed()); |
| } |
| |
| @Override |
| @RequiresNoPermission |
| public void onSetGainModeFailed() { |
| mCallbackWrapper.forEach(cb -> cb.onSetGainModeFailed()); |
| } |
| |
| @Override |
| @RequiresNoPermission |
| public void onSetMuteFailed() { |
| mCallbackWrapper.forEach(cb -> cb.onSetMuteFailed()); |
| } |
| }; |
| |
| @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED}) |
| static List<AudioInputControl> getAudioInputControlServices( |
| @NonNull IBluetoothVolumeControl service, |
| @NonNull AttributionSource source, |
| @NonNull BluetoothDevice device) { |
| requireNonNull(service); |
| requireNonNull(source); |
| requireNonNull(device); |
| int numberOfAics = 0; |
| try { |
| numberOfAics = service.getNumberOfAudioInputControlServices(source, device); |
| } catch (RemoteException e) { |
| logRemoteException(TAG, e); |
| } |
| return IntStream.range(0, numberOfAics) |
| .mapToObj(i -> new AudioInputControl(device, i, service, source)) |
| .collect(Collectors.toList()); |
| } |
| |
| /** |
| * This callback is invoked when the remote AICS notifies a local client of a value changed. It |
| * can also be invoked when a locally initiated operation failed. |
| */ |
| public interface AudioInputCallback { |
| /** see {@link #setDescription(String)} */ |
| default void onDescriptionChanged(@NonNull String description) {} |
| |
| /** see {@link #getStatus()} */ |
| default void onAudioInputStatusChanged(@AudioInputStatus int status) {} |
| |
| /** see {@link #setGainSetting(int)} */ |
| default void onGainSettingChanged(int gainSetting) {} |
| |
| /** see {@link #setGainSetting(int)} */ |
| default void onSetGainSettingFailed() {} |
| |
| /** see {@link #setMute(int)} */ |
| default void onMuteChanged(@Mute int mute) {} |
| |
| /** see {@link #setMute(int)} */ |
| default void onSetMuteFailed() {} |
| |
| /** see {@link #setGainMode(int)} */ |
| default void onGainModeChanged(@GainMode int gainMode) {} |
| |
| /** see {@link #setGainMode(int)} */ |
| default void onSetGainModeFailed() {} |
| } |
| |
| /** |
| * Register an {@link AudioInputCallback} to receive callbacks when the state of the AICS on the |
| * remote device changes. |
| * |
| * <p>Repeated registration of the same callback object will have no effect after the first call |
| * to this method, even when the executor is different. API caller must call {@link |
| * #unregisterCallback(AudioInputCallback)} with the same callback object before registering it |
| * again. |
| * |
| * <p>Callbacks are automatically unregistered when the application process goes away. |
| * |
| * @param executor an {@link Executor} to execute given callback |
| * @param callback user implementation of the {@link AudioInputCallback} |
| * @throws IllegalArgumentException if callback is already registered |
| */ |
| @RequiresBluetoothConnectPermission |
| @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED}) |
| public void registerCallback( |
| @NonNull @CallbackExecutor Executor executor, @NonNull AudioInputCallback callback) { |
| mCallbackWrapper.registerCallback(mService, callback, executor); |
| } |
| |
| /** |
| * Unregister the {@link AudioInputCallback}. |
| * |
| * <p>The same {@link AudioInputCallback} object used when calling {@link |
| * #registerCallback(Executor, AudioInputCallback)} must be used. |
| * |
| * <p>Callbacks are automatically unregistered when the application process goes away. |
| * |
| * @param callback user implementation of the {@link AudioInputCallback} |
| * @throws IllegalArgumentException when no callback is registered |
| */ |
| @RequiresBluetoothConnectPermission |
| @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED}) |
| public void unregisterCallback(@NonNull AudioInputCallback callback) { |
| mCallbackWrapper.unregisterCallback(mService, callback); |
| } |
| |
| /** |
| * Gets the Audio Input Type. |
| * |
| * <p>This reflects the source of audio for the audio input described by this AICS. The |
| * description may optionally further describe the Audio Input Type with values such as |
| * Microphone, HDMI, etc… |
| * |
| * @return The Audio Input Type as defined in AICS 1.0 - 3.3. |
| */ |
| @RequiresBluetoothConnectPermission |
| @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED}) |
| public @AudioInputType int getAudioInputType() { |
| return callService( |
| mService, |
| s -> s.getAudioInputType(mAttributionSource, mDevice, mInstanceId), |
| bluetooth.constants.AudioInputType.UNSPECIFIED); |
| } |
| |
| /** |
| * Gets the unit of the gain setting. |
| * |
| * <p>It reflects the size of a single increment or decrement of {@link #setGainSetting} in 0.1 |
| * decibel units. |
| * |
| * @return The Gain Setting Units as defined in AICS 1.0 - 3.2.1. |
| */ |
| @RequiresBluetoothConnectPermission |
| @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED}) |
| public @IntRange(from = 0, to = 0xFF) int getGainSettingUnit() { |
| return callService( |
| mService, |
| s -> s.getAudioInputGainSettingUnit(mAttributionSource, mDevice, mInstanceId), |
| 0); |
| } |
| |
| /** |
| * Gets the minimum value for the gain setting. |
| * |
| * <p>The value return is relative to {@link #getGainSettingUnit} in 0.1 decibel units. |
| * |
| * @return The minimum Gain Setting as defined in AICS 1.0 - 3.2.2. |
| */ |
| @RequiresBluetoothConnectPermission |
| @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED}) |
| public @IntRange(from = -128, to = 127) int getGainSettingMin() { |
| return callService( |
| mService, |
| s -> s.getAudioInputGainSettingMin(mAttributionSource, mDevice, mInstanceId), |
| 0); |
| } |
| |
| /** |
| * Gets the maximum value for the gain setting. |
| * |
| * <p>The value return is relative to {@link #getGainSettingUnit} in 0.1 decibel units. |
| * |
| * @return The maximum Gain Setting as defined in AICS 1.0 - 3.2.3. |
| */ |
| @RequiresBluetoothConnectPermission |
| @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED}) |
| public @IntRange(from = -128, to = 127) int getGainSettingMax() { |
| return callService( |
| mService, |
| s -> s.getAudioInputGainSettingMax(mAttributionSource, mDevice, mInstanceId), |
| 0); |
| } |
| |
| /** |
| * Gets the description. |
| * |
| * <p>Register an {@link AudioInputCallback} to be notified via {@link |
| * AudioInputCallback#onDescriptionChanged} when the description changes. |
| * |
| * <p>This describes the AICS. For example, if a device instantiated a service for both |
| * “Bluetooth” and “Line In” audio inputs, then the description value would be set to |
| * “Bluetooth” on one service and “Line In” on the other service. If multiple Bluetooth audio |
| * inputs are represented, the server may set the Audio Input Description to the remote source’s |
| * name, a string representing the content type, the content control server name, etc. The value |
| * is a UTF-8 string of zero or more characters. |
| * |
| * @return The description as defined in AICS 1.0 - 3.6. |
| */ |
| @RequiresBluetoothConnectPermission |
| @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED}) |
| public @NonNull String getDescription() { |
| return callService( |
| mService, |
| s -> s.getAudioInputDescription(mAttributionSource, mDevice, mInstanceId), |
| ""); |
| } |
| |
| /** |
| * Checks whether the description is writable as defined in AICS 1.0 - 3.6. |
| * |
| * @return true if the description can be written to, false otherwise. |
| */ |
| @RequiresBluetoothConnectPermission |
| @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED}) |
| public boolean isDescriptionWritable() { |
| return callService( |
| mService, |
| s -> s.isAudioInputDescriptionWritable(mAttributionSource, mDevice, mInstanceId), |
| false); |
| } |
| |
| /** |
| * Sets the description as defined in AICS 1.0 - 3.6. |
| * |
| * <p>The operation will fail if the description is not writable. This can be verified with |
| * {@link #isDescriptionWritable} |
| * |
| * <p>Register an {@link AudioInputCallback} to be notified via {@link |
| * AudioInputCallback#onDescriptionChanged} when the description change is applied on remote |
| * device. |
| * |
| * @param description The description of the AICS. |
| * @return true if the operation is successfully initiated, false otherwise. |
| * @throws IllegalStateException if the description is not writable |
| */ |
| @RequiresBluetoothConnectPermission |
| @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED}) |
| public boolean setDescription(@NonNull String description) { |
| requireNonNull(description); |
| return callService( |
| mService, |
| s -> |
| s.setAudioInputDescription( |
| mAttributionSource, mDevice, mInstanceId, description), |
| false); |
| } |
| |
| /** |
| * Gets the Audio Input Status. |
| * |
| * <p>Register an {@link AudioInputCallback} to be notified via {@link |
| * AudioInputCallback#onAudioInputStatusChanged} when the status changes. |
| * |
| * @return The Audio Input Status as defined in AICS 1.0 - 3.4. |
| */ |
| @RequiresBluetoothConnectPermission |
| @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED}) |
| public @AudioInputStatus int getAudioInputStatus() { |
| return callService( |
| mService, |
| s -> s.getAudioInputStatus(mAttributionSource, mDevice, mInstanceId), |
| (int) bluetooth.constants.aics.AudioInputStatus.INACTIVE); |
| } |
| |
| /** |
| * Gets the gain setting. |
| * |
| * <p>Register an {@link AudioInputCallback} to be notified via {@link |
| * AudioInputCallback#onGainSettingChanged} when the gain setting changes. |
| * |
| * <p>The value return is relative to {@link #getGainSettingUnit} in 0.1 decibel units. |
| * |
| * @return The current gain setting as defined in AICS 1.0 - 2.2.1.1. |
| */ |
| @RequiresBluetoothConnectPermission |
| @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED}) |
| public @IntRange(from = -128, to = 127) int getGainSetting() { |
| return callService( |
| mService, |
| s -> s.getAudioInputGainSetting(mAttributionSource, mDevice, mInstanceId), |
| 0); |
| } |
| |
| /** |
| * Sets the gain setting as defined in AICS 1.0 - 3.5.2.1. |
| * |
| * <p>The operation will fail if the current gain mode is {@link #AUTOMATIC} or {@link |
| * #AUTOMATIC_ONLY}. |
| * |
| * <p>Register an {@link AudioInputControl.AudioInputCallback} to be notified via |
| * |
| * <ul> |
| * <li>{@link AudioInputCallback#onGainSettingChanged()} when the gain setting is changed by |
| * the remote device. |
| * <li>{@link AudioInputCallback#onSetGainSettingFailed} if the gain setting cannot be set. |
| * </ul> |
| * |
| * The gain setting is a signed value for which a single increment or decrement should result in |
| * a corresponding increase or decrease of the input amplitude by the value of the gain setting |
| * unit (see {@link #getGainSettingUnit()}). A gain setting value of 0 should result in no |
| * change to the input’s original amplitude. |
| * |
| * @param gainSetting The desired gain setting value. Refer to {@link #getGainSettingMin()} and |
| * {@link #getGainSettingMax()} for the allowed range. Refer to {@link |
| * #getGainSettingUnit()} to knows how much decibel this represents. |
| * @return true if the operation is successfully initiated, false otherwise. The callback {@link |
| * AudioInputCallback#onSetGainSettingFailed()} will not be call if false is returned |
| * @throws IllegalStateException if the gain mode is {@link #AUTOMATIC} or {@link |
| * #AUTOMATIC_ONLY} |
| * @throws IllegalArgumentException if the gain setting is not in range |
| */ |
| @RequiresBluetoothConnectPermission |
| @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED}) |
| public boolean setGainSetting(@IntRange(from = -128, to = 127) int gainSetting) { |
| return callService( |
| mService, |
| s -> |
| s.setAudioInputGainSetting( |
| mAttributionSource, mDevice, mInstanceId, gainSetting), |
| false); |
| } |
| |
| /** |
| * Gets the gain mode. |
| * |
| * <p>Register an {@link AudioInputCallback} to be notified via {@link |
| * AudioInputCallback#onGainModeChanged} when the gain mode changes. |
| * |
| * @return The current gain mode as defined in AICS 1.0 - 2.2.1.3. |
| */ |
| @RequiresBluetoothConnectPermission |
| @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED}) |
| public @GainMode int getGainMode() { |
| return callService( |
| mService, |
| s -> s.getAudioInputGainMode(mAttributionSource, mDevice, mInstanceId), |
| (int) bluetooth.constants.aics.GainMode.AUTOMATIC_ONLY); |
| } |
| |
| /** |
| * Sets the gain mode as defined in AICS 1.0 - 3.5.2.4/5. |
| * |
| * <p>The operation will fail if the current gain mode is {@link #MANUAL_ONLY} or {@link |
| * #AUTOMATIC_ONLY}. |
| * |
| * <p>Register an {@link AudioInputControl.AudioInputCallback} to be notified via |
| * |
| * <ul> |
| * <li>{@link AudioInputCallback#onGainModeChanged()} when the gain setting is changed by the |
| * remote device. |
| * <li>{@link AudioInputCallback#onSetGainModeFailed} if the gain mode cannot be set. |
| * </ul> |
| * |
| * @param gainMode The desired gain mode |
| * @return true if the operation is successfully initiated, false otherwise. The callback {@link |
| * AudioInputCallback#onSetGainModeFailed()} will not be call if false is returned |
| * @throws IllegalStateException if the gain mode is {@link #MANUAL_ONLY} or {@link |
| * #AUTOMATIC_ONLY} |
| * @throws IllegalArgumentException if the gain mode value is invalid. |
| */ |
| @RequiresBluetoothConnectPermission |
| @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED}) |
| public boolean setGainMode(@GainModeSettable int gainMode) { |
| if (gainMode != GAIN_MODE_MANUAL && gainMode != GAIN_MODE_AUTOMATIC) { |
| throw new IllegalArgumentException("Illegal GainMode value: " + gainMode); |
| } |
| return callService( |
| mService, |
| s -> s.setAudioInputGainMode(mAttributionSource, mDevice, mInstanceId, gainMode), |
| false); |
| } |
| |
| /** |
| * Gets the mute state. |
| * |
| * <p>Register an {@link AudioInputCallback} to be notified via {@link |
| * AudioInputCallback#onMuteChanged} when the mute state changes. |
| * |
| * @return The current mute state as defined in AICS 1.0 - 2.2.1.2. |
| */ |
| @RequiresBluetoothConnectPermission |
| @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED}) |
| public @Mute int getMute() { |
| return callService( |
| mService, |
| s -> s.getAudioInputMute(mAttributionSource, mDevice, mInstanceId), |
| (int) bluetooth.constants.aics.Mute.DISABLED); |
| } |
| |
| /** |
| * Sets the mute state as defined in AICS 1.0 - 3.5.2.2/3. |
| * |
| * <p>The operation will fail if the current mute state is {@link #MUTE_DISABLED}. |
| * |
| * <p>Register an {@link AudioInputControl.AudioInputCallback} to be notified via |
| * |
| * <ul> |
| * <li>{@link AudioInputCallback#onMuteChanged()} when the mute state is changed by the remote |
| * device. |
| * <li>{@link AudioInputCallback#onSetMuteFailed} if the mute state cannot be set. |
| * </ul> |
| * |
| * @param mute the new mute state. |
| * @return true on success, false otherwise. |
| * @throws IllegalStateException if the mute state is {@link #MUTE_DISABLED} |
| * @throws IllegalArgumentException if the provided {@code mute} is not valid |
| */ |
| @RequiresBluetoothConnectPermission |
| @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED}) |
| public boolean setMute(@MuteSettable int mute) { |
| if (mute != MUTE_NOT_MUTED && mute != MUTE_MUTED) { |
| throw new IllegalArgumentException("Illegal mute value: " + mute); |
| } |
| return callService( |
| mService, |
| s -> s.setAudioInputMute(mAttributionSource, mDevice, mInstanceId, mute), |
| false); |
| } |
| } |