blob: 25c767a88b17768a8a3c120920ac4fa3cab0c94c [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2007 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.media;
18
Jan Sebechlebskyfb48c022022-12-16 16:26:47 +010019import static android.companion.virtual.VirtualDeviceParams.DEVICE_POLICY_DEFAULT;
20import static android.companion.virtual.VirtualDeviceParams.POLICY_TYPE_AUDIO;
Marco Loaiza7b7d2af2023-01-23 15:21:52 +000021import static android.content.Context.DEVICE_ID_DEFAULT;
Jean-Michel Trivi31323ab2023-11-22 17:44:29 +000022import static android.media.audio.Flags.autoPublicVolumeApiHardening;
Vlad Popae1dae842023-11-28 19:04:03 -080023import static android.media.audio.Flags.automaticBtDeviceType;
Jean-Michel Trivia97cd682023-12-15 08:43:35 -080024import static android.media.audio.Flags.FLAG_FOCUS_EXCLUSIVE_WITH_RECORDING;
Atneya Nair511993782023-10-30 22:03:34 -070025import static android.media.audio.Flags.FLAG_FOCUS_FREEZE_TEST_API;
Paul McLeanb5dd7b52024-01-23 21:29:59 +000026import static android.media.audio.Flags.FLAG_SUPPORTED_DEVICE_TYPES_API;
Raj Goparaju04285802023-12-01 16:57:51 -080027import static android.media.audiopolicy.Flags.FLAG_ENABLE_FADE_MANAGER_CONFIGURATION;
Jean-Michel Trivi68390dc2023-10-02 14:32:07 -070028
Jean-Michel Trivic4557822023-01-23 18:19:52 +000029import android.Manifest;
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -080030import android.annotation.CallbackExecutor;
Jean-Michel Trivid31ca2a2023-10-02 14:32:07 -070031import android.annotation.FlaggedApi;
Jean-Michel Trivi8e7aca32017-11-28 18:12:38 -080032import android.annotation.IntDef;
Hayden Gomes695f8022019-04-11 10:44:18 -070033import android.annotation.IntRange;
Jean-Michel Trivi958876f2014-11-16 15:40:22 -080034import android.annotation.NonNull;
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -070035import android.annotation.Nullable;
Jeff Sharkeyd86b8fe2017-06-02 17:36:26 -060036import android.annotation.RequiresPermission;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080037import android.annotation.SdkConstant;
38import android.annotation.SdkConstant.SdkConstantType;
Jean-Michel Trivi26ae15f2017-08-25 19:20:49 -070039import android.annotation.SuppressLint;
Terry Heoe7d6d972014-09-04 21:05:28 +090040import android.annotation.SystemApi;
Jeff Sharkeyd86b8fe2017-06-02 17:36:26 -060041import android.annotation.SystemService;
Jean-Michel Triviec977322019-04-12 11:20:35 -070042import android.annotation.TestApi;
Julia Reynolds48034f82016-03-09 10:15:16 -050043import android.app.NotificationManager;
Jean-Michel Trivif0cff042011-09-14 18:11:09 -070044import android.app.PendingIntent;
Eric Laurent1c3408f2021-11-09 12:09:54 +010045import android.app.compat.CompatChanges;
Arun Mirpuricb102fa2019-01-11 18:39:21 -080046import android.bluetooth.BluetoothCodecConfig;
Eric Laurentb1fbaac2012-05-29 09:24:28 -070047import android.bluetooth.BluetoothDevice;
Patty46694212021-11-04 21:03:32 +080048import android.bluetooth.BluetoothLeAudioCodecConfig;
Jan Sebechlebskyfb48c022022-12-16 16:26:47 +010049import android.companion.virtual.VirtualDeviceManager;
Eric Laurent1c3408f2021-11-09 12:09:54 +010050import android.compat.annotation.ChangeId;
51import android.compat.annotation.EnabledSince;
Yan Han31b10112023-02-13 17:25:46 +010052import android.compat.annotation.Overridable;
Artur Satayev53fe9662019-12-10 17:47:55 +000053import android.compat.annotation.UnsupportedAppUsage;
Jean-Michel Trivid327f212010-03-16 21:44:33 -070054import android.content.ComponentName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080055import android.content.Context;
Jean-Michel Trivif0cff042011-09-14 18:11:09 -070056import android.content.Intent;
Jean-Michel Trivi31323ab2023-11-22 17:44:29 +000057import android.content.pm.PackageManager;
Hayden Gomes62812aa2019-12-23 11:40:27 -080058import android.media.AudioAttributes.AttributeSystemUsage;
Jean-Michel Trivi91f0baa2021-11-11 16:31:32 -080059import android.media.CallbackUtil.ListenerInfo;
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -070060import android.media.audiopolicy.AudioPolicy;
Jean-Michel Trivie2d8aae2018-01-30 15:09:47 -080061import android.media.audiopolicy.AudioPolicy.AudioPolicyFocusListener;
Hayden Gomes6d69bde2019-04-04 13:10:13 -070062import android.media.audiopolicy.AudioProductStrategy;
Hayden Gomesebd6aaa2019-04-04 13:14:21 -070063import android.media.audiopolicy.AudioVolumeGroup;
François Gaffieadcd00a2018-09-18 17:06:26 +020064import android.media.audiopolicy.AudioVolumeGroupChangeHandler;
Kevin Rocard2fe8b8b2019-02-20 11:25:23 -080065import android.media.projection.MediaProjection;
RoboErikb214efb2014-07-24 13:20:30 -070066import android.media.session.MediaController;
67import android.media.session.MediaSession;
RoboErikf1372422014-04-23 14:38:17 -070068import android.media.session.MediaSessionLegacyHelper;
RoboErikb214efb2014-07-24 13:20:30 -070069import android.media.session.MediaSessionManager;
jiabinad225202019-03-20 15:22:50 -070070import android.net.Uri;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080071import android.os.Binder;
Jean-Michel Trivi461922f2017-04-25 15:23:17 -070072import android.os.Build;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080073import android.os.Handler;
74import android.os.IBinder;
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -080075import android.os.Looper;
76import android.os.Message;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080077import android.os.RemoteException;
78import android.os.ServiceManager;
Beverlye2d9a232017-11-08 18:14:59 -050079import android.os.SystemClock;
Kenny Guy70e0c582015-06-30 19:18:28 +010080import android.os.UserHandle;
Lais Andrade724d0cd2021-11-03 19:46:21 +000081import android.provider.Settings;
jiabinc0f49442018-01-05 10:23:50 -080082import android.text.TextUtils;
Paul McLeane3383cc2015-05-08 11:41:20 -070083import android.util.ArrayMap;
Paul McLeanb5dd7b52024-01-23 21:29:59 +000084import android.util.IntArray;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080085import android.util.Log;
jiabin589a2362018-02-22 16:21:53 -080086import android.util.Pair;
Jean-Michel Trivid327f212010-03-16 21:44:33 -070087import android.view.KeyEvent;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080088
Jean-Michel Trivie2d8aae2018-01-30 15:09:47 -080089import com.android.internal.annotations.GuardedBy;
François Gaffieadcd00a2018-09-18 17:06:26 +020090import com.android.internal.util.Preconditions;
Jean-Michel Trivie2d8aae2018-01-30 15:09:47 -080091
jiabinc0f49442018-01-05 10:23:50 -080092import java.io.IOException;
Jean-Michel Trivi8e7aca32017-11-28 18:12:38 -080093import java.lang.annotation.Retention;
94import java.lang.annotation.RetentionPolicy;
jiabin0f3339c2021-07-09 11:50:07 -070095import java.lang.ref.WeakReference;
Eric Laurenta198a292014-02-18 16:26:17 -080096import java.util.ArrayList;
jiabinf40141d2020-08-07 17:27:48 -070097import java.util.Arrays;
Dorin Drimusdaeb6a92021-12-22 11:46:26 +010098import java.util.Collections;
Jean-Michel Trivie2d8aae2018-01-30 15:09:47 -080099import java.util.HashMap;
jiabind0be5b22018-04-10 14:10:04 -0700100import java.util.HashSet;
Wonsik Kimb561cce2015-01-30 17:48:51 +0900101import java.util.Iterator;
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -0800102import java.util.List;
jiabin39940752018-04-02 18:18:45 -0700103import java.util.Map;
Jean-Michel Trivi21cd5412019-10-30 08:16:51 -0700104import java.util.Objects;
Paul McLeanb5dd7b52024-01-23 21:29:59 +0000105import java.util.Set;
Hyundo Moonca0080d2018-12-26 16:16:55 +0900106import java.util.TreeMap;
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -0700107import java.util.concurrent.ConcurrentHashMap;
Eric Laurent1d3cdce2018-01-20 10:31:21 -0800108import java.util.concurrent.Executor;
Eric Laurent78eef3a2021-11-09 16:10:42 +0100109import java.util.concurrent.Executors;
Jean-Michel Trivi933bf142021-11-19 16:18:52 -0800110import java.util.concurrent.TimeUnit;
Eric Laurent700e7342014-05-02 18:33:15 -0700111
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800112/**
113 * AudioManager provides access to volume and ringer mode control.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800114 */
Jeff Sharkeyd86b8fe2017-06-02 17:36:26 -0600115@SystemService(Context.AUDIO_SERVICE)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800116public class AudioManager {
117
Marco Nelissen29f16932015-04-17 09:50:56 -0700118 private Context mOriginalContext;
119 private Context mApplicationContext;
Ján Sebechlebskýdcc49642023-02-07 10:20:59 +0000120 private int mOriginalContextDeviceId = DEVICE_ID_DEFAULT;
Jan Sebechlebskyfb48c022022-12-16 16:26:47 +0100121 private @Nullable VirtualDeviceManager mVirtualDeviceManager; // Lazy initialized.
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -0800122 private static final String TAG = "AudioManager";
123 private static final boolean DEBUG = false;
Eric Laurentf076db42015-01-14 13:23:27 -0800124 private static final AudioPortEventHandler sAudioPortEventHandler = new AudioPortEventHandler();
François Gaffieadcd00a2018-09-18 17:06:26 +0200125 private static final AudioVolumeGroupChangeHandler sAudioAudioVolumeGroupChangedHandler =
126 new AudioVolumeGroupChangeHandler();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800127
jiabin0f3339c2021-07-09 11:50:07 -0700128 private static WeakReference<Context> sContext;
jiabincfcf1032021-07-01 16:30:50 -0700129
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800130 /**
131 * Broadcast intent, a hint for applications that audio is about to become
132 * 'noisy' due to a change in audio outputs. For example, this intent may
133 * be sent when a wired headset is unplugged, or when an A2DP audio
134 * sink is disconnected, and the audio system is about to automatically
135 * switch audio route to the speaker. Applications that are controlling
136 * audio streams may consider pausing, reducing volume or some other action
137 * on receipt of this intent so as not to surprise the user with audio
138 * from the speaker.
139 */
140 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
141 public static final String ACTION_AUDIO_BECOMING_NOISY = "android.media.AUDIO_BECOMING_NOISY";
142
143 /**
144 * Sticky broadcast intent action indicating that the ringer mode has
145 * changed. Includes the new ringer mode.
146 *
147 * @see #EXTRA_RINGER_MODE
148 */
149 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
150 public static final String RINGER_MODE_CHANGED_ACTION = "android.media.RINGER_MODE_CHANGED";
151
152 /**
John Spurlockbcc10872014-11-28 15:29:21 -0500153 * @hide
154 * Sticky broadcast intent action indicating that the internal ringer mode has
155 * changed. Includes the new ringer mode.
156 *
157 * @see #EXTRA_RINGER_MODE
158 */
159 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
160 public static final String INTERNAL_RINGER_MODE_CHANGED_ACTION =
161 "android.media.INTERNAL_RINGER_MODE_CHANGED_ACTION";
162
163 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800164 * The new ringer mode.
165 *
166 * @see #RINGER_MODE_CHANGED_ACTION
167 * @see #RINGER_MODE_NORMAL
168 * @see #RINGER_MODE_SILENT
169 * @see #RINGER_MODE_VIBRATE
170 */
171 public static final String EXTRA_RINGER_MODE = "android.media.EXTRA_RINGER_MODE";
172
173 /**
174 * Broadcast intent action indicating that the vibrate setting has
175 * changed. Includes the vibrate type and its new setting.
176 *
177 * @see #EXTRA_VIBRATE_TYPE
178 * @see #EXTRA_VIBRATE_SETTING
Eric Laurentcd1cd732012-05-01 11:23:07 -0700179 * @deprecated Applications should maintain their own vibrate policy based on
180 * current ringer mode and listen to {@link #RINGER_MODE_CHANGED_ACTION} instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800181 */
182 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
Mike Lockwood0dc37cc2011-12-01 16:14:19 -0500183 public static final String VIBRATE_SETTING_CHANGED_ACTION =
184 "android.media.VIBRATE_SETTING_CHANGED";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800185
186 /**
187 * @hide Broadcast intent when the volume for a particular stream type changes.
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700188 * Includes the stream, the new volume and previous volumes.
189 * Notes:
190 * - for internal platform use only, do not make public,
191 * - never used for "remote" volume changes
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800192 *
193 * @see #EXTRA_VOLUME_STREAM_TYPE
194 * @see #EXTRA_VOLUME_STREAM_VALUE
Eric Laurent9ce379a2010-02-16 06:00:26 -0800195 * @see #EXTRA_PREV_VOLUME_STREAM_VALUE
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800196 */
197 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
Mathew Inwood31a792a2018-08-17 08:54:26 +0100198 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800199 public static final String VOLUME_CHANGED_ACTION = "android.media.VOLUME_CHANGED_ACTION";
200
201 /**
Roopa Sattirajuf2675c72022-01-27 21:31:35 -0800202 * @hide Broadcast intent when the volume for a particular stream type changes.
203 * Includes the stream, the new volume and previous volumes.
204 * Notes:
205 * - for internal platform use only, do not make public,
206 * - never used for "remote" volume changes
207 *
208 * @see #EXTRA_VOLUME_STREAM_TYPE
209 * @see #EXTRA_VOLUME_STREAM_VALUE
210 * @see #EXTRA_PREV_VOLUME_STREAM_VALUE
211 */
212 @SystemApi
213 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
214 @SuppressLint("ActionValue")
215 public static final String ACTION_VOLUME_CHANGED = "android.media.VOLUME_CHANGED_ACTION";
216
217 /**
John Spurlock8a52c442015-03-26 14:23:58 -0400218 * @hide Broadcast intent when the devices for a particular stream type changes.
219 * Includes the stream, the new devices and previous devices.
220 * Notes:
221 * - for internal platform use only, do not make public,
222 * - never used for "remote" volume changes
223 *
224 * @see #EXTRA_VOLUME_STREAM_TYPE
225 * @see #EXTRA_VOLUME_STREAM_DEVICES
226 * @see #EXTRA_PREV_VOLUME_STREAM_DEVICES
227 * @see #getDevicesForStream
228 */
229 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
230 public static final String STREAM_DEVICES_CHANGED_ACTION =
231 "android.media.STREAM_DEVICES_CHANGED_ACTION";
232
233 /**
RoboErik7c82ced2014-12-04 17:39:08 -0800234 * @hide Broadcast intent when a stream mute state changes.
235 * Includes the stream that changed and the new mute state
236 *
237 * @see #EXTRA_VOLUME_STREAM_TYPE
238 * @see #EXTRA_STREAM_VOLUME_MUTED
239 */
240 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
241 public static final String STREAM_MUTE_CHANGED_ACTION =
242 "android.media.STREAM_MUTE_CHANGED_ACTION";
243
244 /**
Mike Lockwood0dc37cc2011-12-01 16:14:19 -0500245 * @hide Broadcast intent when the master mute state changes.
246 * Includes the the new volume
247 *
248 * @see #EXTRA_MASTER_VOLUME_MUTED
249 */
250 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
251 public static final String MASTER_MUTE_CHANGED_ACTION =
252 "android.media.MASTER_MUTE_CHANGED_ACTION";
253
254 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800255 * The new vibrate setting for a particular type.
256 *
257 * @see #VIBRATE_SETTING_CHANGED_ACTION
258 * @see #EXTRA_VIBRATE_TYPE
259 * @see #VIBRATE_SETTING_ON
260 * @see #VIBRATE_SETTING_OFF
261 * @see #VIBRATE_SETTING_ONLY_SILENT
Eric Laurentcd1cd732012-05-01 11:23:07 -0700262 * @deprecated Applications should maintain their own vibrate policy based on
263 * current ringer mode and listen to {@link #RINGER_MODE_CHANGED_ACTION} instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800264 */
265 public static final String EXTRA_VIBRATE_SETTING = "android.media.EXTRA_VIBRATE_SETTING";
266
267 /**
268 * The vibrate type whose setting has changed.
269 *
270 * @see #VIBRATE_SETTING_CHANGED_ACTION
271 * @see #VIBRATE_TYPE_NOTIFICATION
272 * @see #VIBRATE_TYPE_RINGER
Eric Laurentcd1cd732012-05-01 11:23:07 -0700273 * @deprecated Applications should maintain their own vibrate policy based on
274 * current ringer mode and listen to {@link #RINGER_MODE_CHANGED_ACTION} instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800275 */
276 public static final String EXTRA_VIBRATE_TYPE = "android.media.EXTRA_VIBRATE_TYPE";
277
278 /**
279 * @hide The stream type for the volume changed intent.
280 */
Roopa Sattirajuf2675c72022-01-27 21:31:35 -0800281 @SystemApi
282 @SuppressLint("ActionValue")
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800283 public static final String EXTRA_VOLUME_STREAM_TYPE = "android.media.EXTRA_VOLUME_STREAM_TYPE";
284
285 /**
Jean-Michel Trivi560877d2015-06-25 17:38:35 -0700286 * @hide
287 * The stream type alias for the volume changed intent.
288 * For instance the intent may indicate a change of the {@link #STREAM_NOTIFICATION} stream
289 * type (as indicated by the {@link #EXTRA_VOLUME_STREAM_TYPE} extra), but this is also
290 * reflected by a change of the volume of its alias, {@link #STREAM_RING} on some devices,
291 * {@link #STREAM_MUSIC} on others (e.g. a television).
292 */
293 public static final String EXTRA_VOLUME_STREAM_TYPE_ALIAS =
294 "android.media.EXTRA_VOLUME_STREAM_TYPE_ALIAS";
295
296 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800297 * @hide The volume associated with the stream for the volume changed intent.
298 */
Roopa Sattirajuf2675c72022-01-27 21:31:35 -0800299 @SystemApi
300 @SuppressLint("ActionValue")
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800301 public static final String EXTRA_VOLUME_STREAM_VALUE =
302 "android.media.EXTRA_VOLUME_STREAM_VALUE";
303
Eric Laurent9ce379a2010-02-16 06:00:26 -0800304 /**
305 * @hide The previous volume associated with the stream for the volume changed intent.
306 */
307 public static final String EXTRA_PREV_VOLUME_STREAM_VALUE =
308 "android.media.EXTRA_PREV_VOLUME_STREAM_VALUE";
309
Mike Lockwood0dc37cc2011-12-01 16:14:19 -0500310 /**
John Spurlock8a52c442015-03-26 14:23:58 -0400311 * @hide The devices associated with the stream for the stream devices changed intent.
312 */
313 public static final String EXTRA_VOLUME_STREAM_DEVICES =
314 "android.media.EXTRA_VOLUME_STREAM_DEVICES";
315
316 /**
317 * @hide The previous devices associated with the stream for the stream devices changed intent.
318 */
319 public static final String EXTRA_PREV_VOLUME_STREAM_DEVICES =
320 "android.media.EXTRA_PREV_VOLUME_STREAM_DEVICES";
321
322 /**
Mike Lockwood0dc37cc2011-12-01 16:14:19 -0500323 * @hide The new master volume mute state for the master mute changed intent.
324 * Value is boolean
325 */
326 public static final String EXTRA_MASTER_VOLUME_MUTED =
327 "android.media.EXTRA_MASTER_VOLUME_MUTED";
328
Jean-Michel Trivic5258432014-08-27 15:46:54 -0700329 /**
RoboErik7c82ced2014-12-04 17:39:08 -0800330 * @hide The new stream volume mute state for the stream mute changed intent.
331 * Value is boolean
332 */
333 public static final String EXTRA_STREAM_VOLUME_MUTED =
334 "android.media.EXTRA_STREAM_VOLUME_MUTED";
335
336 /**
Jean-Michel Trivic5258432014-08-27 15:46:54 -0700337 * Broadcast Action: Wired Headset plugged in or unplugged.
338 *
339 * You <em>cannot</em> receive this through components declared
340 * in manifests, only by explicitly registering for it with
341 * {@link Context#registerReceiver(BroadcastReceiver, IntentFilter)
342 * Context.registerReceiver()}.
343 *
344 * <p>The intent will have the following extra values:
345 * <ul>
346 * <li><em>state</em> - 0 for unplugged, 1 for plugged. </li>
347 * <li><em>name</em> - Headset type, human readable string </li>
348 * <li><em>microphone</em> - 1 if headset has a microphone, 0 otherwise </li>
349 * </ul>
350 * </ul>
351 */
352 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
353 public static final String ACTION_HEADSET_PLUG =
354 "android.intent.action.HEADSET_PLUG";
355
356 /**
Eemi Haukkalabc682562015-03-06 23:03:30 +0200357 * Broadcast Action: A sticky broadcast indicating an HDMI cable was plugged or unplugged.
Jean-Michel Trivic5258432014-08-27 15:46:54 -0700358 *
359 * The intent will have the following extra values: {@link #EXTRA_AUDIO_PLUG_STATE},
360 * {@link #EXTRA_MAX_CHANNEL_COUNT}, {@link #EXTRA_ENCODINGS}.
361 * <p>It can only be received by explicitly registering for it with
362 * {@link Context#registerReceiver(BroadcastReceiver, IntentFilter)}.
363 */
364 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
365 public static final String ACTION_HDMI_AUDIO_PLUG =
366 "android.media.action.HDMI_AUDIO_PLUG";
367
368 /**
369 * Extra used in {@link #ACTION_HDMI_AUDIO_PLUG} to communicate whether HDMI is plugged in
370 * or unplugged.
371 * An integer value of 1 indicates a plugged-in state, 0 is unplugged.
372 */
Jean-Michel Trivideddda52014-09-05 14:38:47 -0700373 public static final String EXTRA_AUDIO_PLUG_STATE = "android.media.extra.AUDIO_PLUG_STATE";
Jean-Michel Trivic5258432014-08-27 15:46:54 -0700374
375 /**
376 * Extra used in {@link #ACTION_HDMI_AUDIO_PLUG} to define the maximum number of channels
377 * supported by the HDMI device.
378 * The corresponding integer value is only available when the device is plugged in (as expressed
379 * by {@link #EXTRA_AUDIO_PLUG_STATE}).
380 */
Jean-Michel Trivideddda52014-09-05 14:38:47 -0700381 public static final String EXTRA_MAX_CHANNEL_COUNT = "android.media.extra.MAX_CHANNEL_COUNT";
Jean-Michel Trivic5258432014-08-27 15:46:54 -0700382
383 /**
384 * Extra used in {@link #ACTION_HDMI_AUDIO_PLUG} to define the audio encodings supported by
385 * the connected HDMI device.
386 * The corresponding array of encoding values is only available when the device is plugged in
387 * (as expressed by {@link #EXTRA_AUDIO_PLUG_STATE}). Encoding values are defined in
388 * {@link AudioFormat} (for instance see {@link AudioFormat#ENCODING_PCM_16BIT}). Use
389 * {@link android.content.Intent#getIntArrayExtra(String)} to retrieve the encoding values.
390 */
Jean-Michel Trivideddda52014-09-05 14:38:47 -0700391 public static final String EXTRA_ENCODINGS = "android.media.extra.ENCODINGS";
Jean-Michel Trivic5258432014-08-27 15:46:54 -0700392
Jean-Michel Trivi46d5b822016-10-04 12:37:53 -0700393 /** Used to identify the volume of audio streams for phone calls */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800394 public static final int STREAM_VOICE_CALL = AudioSystem.STREAM_VOICE_CALL;
Jean-Michel Trivi46d5b822016-10-04 12:37:53 -0700395 /** Used to identify the volume of audio streams for system sounds */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800396 public static final int STREAM_SYSTEM = AudioSystem.STREAM_SYSTEM;
Jean-Michel Trivi46d5b822016-10-04 12:37:53 -0700397 /** Used to identify the volume of audio streams for the phone ring */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800398 public static final int STREAM_RING = AudioSystem.STREAM_RING;
Jean-Michel Trivi46d5b822016-10-04 12:37:53 -0700399 /** Used to identify the volume of audio streams for music playback */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800400 public static final int STREAM_MUSIC = AudioSystem.STREAM_MUSIC;
Jean-Michel Trivi46d5b822016-10-04 12:37:53 -0700401 /** Used to identify the volume of audio streams for alarms */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800402 public static final int STREAM_ALARM = AudioSystem.STREAM_ALARM;
Jean-Michel Trivi46d5b822016-10-04 12:37:53 -0700403 /** Used to identify the volume of audio streams for notifications */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800404 public static final int STREAM_NOTIFICATION = AudioSystem.STREAM_NOTIFICATION;
Jean-Michel Trivi46d5b822016-10-04 12:37:53 -0700405 /** @hide Used to identify the volume of audio streams for phone calls when connected
406 * to bluetooth */
Roopa Sattirajuf2675c72022-01-27 21:31:35 -0800407 @SystemApi
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800408 public static final int STREAM_BLUETOOTH_SCO = AudioSystem.STREAM_BLUETOOTH_SCO;
Jean-Michel Trivi46d5b822016-10-04 12:37:53 -0700409 /** @hide Used to identify the volume of audio streams for enforced system sounds
410 * in certain countries (e.g camera in Japan) */
Mathew Inwood31a792a2018-08-17 08:54:26 +0100411 @UnsupportedAppUsage
Eric Laurenta553c252009-07-17 12:17:14 -0700412 public static final int STREAM_SYSTEM_ENFORCED = AudioSystem.STREAM_SYSTEM_ENFORCED;
Jean-Michel Trivi46d5b822016-10-04 12:37:53 -0700413 /** Used to identify the volume of audio streams for DTMF Tones */
Eric Laurenta553c252009-07-17 12:17:14 -0700414 public static final int STREAM_DTMF = AudioSystem.STREAM_DTMF;
Jean-Michel Trivi46d5b822016-10-04 12:37:53 -0700415 /** @hide Used to identify the volume of audio streams exclusively transmitted through the
416 * speaker (TTS) of the device */
Mathew Inwood31a792a2018-08-17 08:54:26 +0100417 @UnsupportedAppUsage
Eric Laurenta553c252009-07-17 12:17:14 -0700418 public static final int STREAM_TTS = AudioSystem.STREAM_TTS;
Jean-Michel Trivi3f0945a2016-11-11 10:05:18 -0800419 /** Used to identify the volume of audio streams for accessibility prompts */
420 public static final int STREAM_ACCESSIBILITY = AudioSystem.STREAM_ACCESSIBILITY;
Kim Baekgyeongb64fac72019-12-09 10:35:58 +0000421 /** @hide Used to identify the volume of audio streams for virtual assistant */
422 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +0000423 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
Kim Baekgyeongb64fac72019-12-09 10:35:58 +0000424 public static final int STREAM_ASSISTANT = AudioSystem.STREAM_ASSISTANT;
Jean-Michel Trivi3f0945a2016-11-11 10:05:18 -0800425
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800426 /** Number of audio streams */
427 /**
Jean-Michel Trivi46d5b822016-10-04 12:37:53 -0700428 * @deprecated Do not iterate on volume stream type values.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800429 */
Eric Laurenta553c252009-07-17 12:17:14 -0700430 @Deprecated public static final int NUM_STREAMS = AudioSystem.NUM_STREAMS;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800431
Paul McLeand6f87c82021-03-31 13:02:41 -0600432 /** @hide */
433 private static final int[] PUBLIC_STREAM_TYPES = { AudioManager.STREAM_VOICE_CALL,
434 AudioManager.STREAM_SYSTEM, AudioManager.STREAM_RING, AudioManager.STREAM_MUSIC,
435 AudioManager.STREAM_ALARM, AudioManager.STREAM_NOTIFICATION,
436 AudioManager.STREAM_DTMF, AudioManager.STREAM_ACCESSIBILITY };
437
438 /** @hide */
439 @TestApi
440 public static final int[] getPublicStreamTypes() {
441 return PUBLIC_STREAM_TYPES;
442 }
443
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800444 /**
445 * Increase the ringer volume.
446 *
447 * @see #adjustVolume(int, int)
448 * @see #adjustStreamVolume(int, int, int)
449 */
450 public static final int ADJUST_RAISE = 1;
451
452 /**
453 * Decrease the ringer volume.
454 *
455 * @see #adjustVolume(int, int)
456 * @see #adjustStreamVolume(int, int, int)
457 */
458 public static final int ADJUST_LOWER = -1;
459
460 /**
461 * Maintain the previous ringer volume. This may be useful when needing to
462 * show the volume toast without actually modifying the volume.
463 *
464 * @see #adjustVolume(int, int)
465 * @see #adjustStreamVolume(int, int, int)
466 */
467 public static final int ADJUST_SAME = 0;
468
RoboErik4197cb62015-01-21 15:45:32 -0800469 /**
470 * Mute the volume. Has no effect if the stream is already muted.
471 *
472 * @see #adjustVolume(int, int)
473 * @see #adjustStreamVolume(int, int, int)
474 */
475 public static final int ADJUST_MUTE = -100;
476
477 /**
478 * Unmute the volume. Has no effect if the stream is not muted.
479 *
480 * @see #adjustVolume(int, int)
481 * @see #adjustStreamVolume(int, int, int)
482 */
483 public static final int ADJUST_UNMUTE = 100;
484
485 /**
486 * Toggle the mute state. If muted the stream will be unmuted. If not muted
487 * the stream will be muted.
488 *
489 * @see #adjustVolume(int, int)
490 * @see #adjustStreamVolume(int, int, int)
491 */
492 public static final int ADJUST_TOGGLE_MUTE = 101;
493
Jean-Michel Trivicf170362017-08-24 17:24:57 -0700494 /** @hide */
Jean-Michel Trivi610aa9b2018-01-27 15:42:42 -0800495 @IntDef(flag = false, prefix = "ADJUST", value = {
496 ADJUST_RAISE,
497 ADJUST_LOWER,
498 ADJUST_SAME,
499 ADJUST_MUTE,
500 ADJUST_UNMUTE,
501 ADJUST_TOGGLE_MUTE }
502 )
503 @Retention(RetentionPolicy.SOURCE)
Jean-Michel Trivi1b926e72018-01-29 16:06:51 -0800504 public @interface VolumeAdjustment {}
Jean-Michel Trivi610aa9b2018-01-27 15:42:42 -0800505
506 /** @hide */
Jean-Michel Trivicf170362017-08-24 17:24:57 -0700507 public static final String adjustToString(int adj) {
508 switch (adj) {
509 case ADJUST_RAISE: return "ADJUST_RAISE";
510 case ADJUST_LOWER: return "ADJUST_LOWER";
511 case ADJUST_SAME: return "ADJUST_SAME";
512 case ADJUST_MUTE: return "ADJUST_MUTE";
513 case ADJUST_UNMUTE: return "ADJUST_UNMUTE";
514 case ADJUST_TOGGLE_MUTE: return "ADJUST_TOGGLE_MUTE";
515 default: return new StringBuilder("unknown adjust mode ").append(adj).toString();
516 }
517 }
518
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800519 // Flags should be powers of 2!
520
521 /**
522 * Show a toast containing the current volume.
523 *
524 * @see #adjustStreamVolume(int, int, int)
525 * @see #adjustVolume(int, int)
526 * @see #setStreamVolume(int, int, int)
527 * @see #setRingerMode(int)
528 */
529 public static final int FLAG_SHOW_UI = 1 << 0;
530
531 /**
532 * Whether to include ringer modes as possible options when changing volume.
533 * For example, if true and volume level is 0 and the volume is adjusted
534 * with {@link #ADJUST_LOWER}, then the ringer mode may switch the silent or
535 * vibrate mode.
536 * <p>
537 * By default this is on for the ring stream. If this flag is included,
538 * this behavior will be present regardless of the stream type being
539 * affected by the ringer mode.
The Android Open Source Project10592532009-03-18 17:39:46 -0700540 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800541 * @see #adjustVolume(int, int)
542 * @see #adjustStreamVolume(int, int, int)
543 */
544 public static final int FLAG_ALLOW_RINGER_MODES = 1 << 1;
545
546 /**
547 * Whether to play a sound when changing the volume.
548 * <p>
549 * If this is given to {@link #adjustVolume(int, int)} or
550 * {@link #adjustSuggestedStreamVolume(int, int, int)}, it may be ignored
551 * in some cases (for example, the decided stream type is not
552 * {@link AudioManager#STREAM_RING}, or the volume is being adjusted
553 * downward).
554 *
555 * @see #adjustStreamVolume(int, int, int)
556 * @see #adjustVolume(int, int)
557 * @see #setStreamVolume(int, int, int)
558 */
559 public static final int FLAG_PLAY_SOUND = 1 << 2;
560
561 /**
562 * Removes any sounds/vibrate that may be in the queue, or are playing (related to
563 * changing volume).
564 */
565 public static final int FLAG_REMOVE_SOUND_AND_VIBRATE = 1 << 3;
566
567 /**
568 * Whether to vibrate if going into the vibrate ringer mode.
569 */
570 public static final int FLAG_VIBRATE = 1 << 4;
571
572 /**
Eric Laurent4bbcc652012-09-24 14:26:30 -0700573 * Indicates to VolumePanel that the volume slider should be disabled as user
574 * cannot change the stream volume
575 * @hide
576 */
577 public static final int FLAG_FIXED_VOLUME = 1 << 5;
578
579 /**
Matthew Xiec9d1d5f2013-09-12 00:32:22 -0700580 * Indicates the volume set/adjust call is for Bluetooth absolute volume
581 * @hide
582 */
Roopa Sattirajufb933242022-01-30 13:27:58 -0800583 @SystemApi
Matthew Xiec9d1d5f2013-09-12 00:32:22 -0700584 public static final int FLAG_BLUETOOTH_ABS_VOLUME = 1 << 6;
585
586 /**
John Spurlocka11b4af2014-06-01 11:52:23 -0400587 * Adjusting the volume was prevented due to silent mode, display a hint in the UI.
588 * @hide
589 */
590 public static final int FLAG_SHOW_SILENT_HINT = 1 << 7;
591
592 /**
Jungshik Jang41d97462014-06-30 22:26:29 +0900593 * Indicates the volume call is for Hdmi Cec system audio volume
594 * @hide
595 */
596 public static final int FLAG_HDMI_SYSTEM_AUDIO_VOLUME = 1 << 8;
597
598 /**
RoboErik3c45c292014-07-08 16:47:31 -0700599 * Indicates that this should only be handled if media is actively playing.
600 * @hide
601 */
602 public static final int FLAG_ACTIVE_MEDIA_ONLY = 1 << 9;
603
604 /**
John Spurlock35134602014-07-24 18:10:48 -0400605 * Like FLAG_SHOW_UI, but only dialog warnings and confirmations, no sliders.
606 * @hide
607 */
608 public static final int FLAG_SHOW_UI_WARNINGS = 1 << 10;
609
610 /**
John Spurlock661f2cf42014-11-17 10:29:10 -0500611 * Adjusting the volume down from vibrated was prevented, display a hint in the UI.
612 * @hide
613 */
614 public static final int FLAG_SHOW_VIBRATE_HINT = 1 << 11;
615
John Spurlockb94f2d62015-03-17 14:11:57 -0400616 /**
617 * Adjusting the volume due to a hardware key press.
Hyundo Moonca0080d2018-12-26 16:16:55 +0900618 * This flag can be used in the places in order to denote (or check) that a volume adjustment
619 * request is from a hardware key press. (e.g. {@link MediaController}).
John Spurlockb94f2d62015-03-17 14:11:57 -0400620 * @hide
621 */
Jin Seok Park4abc23e2020-07-30 22:28:50 +0900622 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
Hyundo Moonc3ce09e2019-03-11 20:00:00 +0900623 public static final int FLAG_FROM_KEY = 1 << 12;
John Spurlockb94f2d62015-03-17 14:11:57 -0400624
Yan Han7d419822022-01-31 19:10:16 +0100625 /**
626 * Indicates that an absolute volume controller is notifying AudioService of a change in the
627 * volume or mute status of an external audio system.
628 * @hide
629 */
630 public static final int FLAG_ABSOLUTE_VOLUME = 1 << 13;
631
Jin Seok Park5ccb6cc2021-02-05 01:47:13 +0900632 /** @hide */
Kriti Dang527e66c2021-03-04 10:37:22 +0100633 @IntDef(prefix = {"ENCODED_SURROUND_OUTPUT_"}, value = {
Kriti Dang98fdb262021-04-01 13:26:00 +0200634 ENCODED_SURROUND_OUTPUT_UNKNOWN,
Kriti Dang527e66c2021-03-04 10:37:22 +0100635 ENCODED_SURROUND_OUTPUT_AUTO,
636 ENCODED_SURROUND_OUTPUT_NEVER,
637 ENCODED_SURROUND_OUTPUT_ALWAYS,
638 ENCODED_SURROUND_OUTPUT_MANUAL
639 })
640 @Retention(RetentionPolicy.SOURCE)
641 public @interface EncodedSurroundOutputMode {}
642
643 /**
Kriti Dang98fdb262021-04-01 13:26:00 +0200644 * The mode for surround sound formats is unknown.
645 */
646 public static final int ENCODED_SURROUND_OUTPUT_UNKNOWN = -1;
647
648 /**
Kriti Dang527e66c2021-03-04 10:37:22 +0100649 * The surround sound formats are available for use if they are detected. This is the default
650 * mode.
651 */
652 public static final int ENCODED_SURROUND_OUTPUT_AUTO = 0;
653
654 /**
655 * The surround sound formats are NEVER available, even if they are detected by the hardware.
656 * Those formats will not be reported.
657 */
658 public static final int ENCODED_SURROUND_OUTPUT_NEVER = 1;
659
660 /**
661 * The surround sound formats are ALWAYS available, even if they are not detected by the
662 * hardware. Those formats will be reported as part of the HDMI output capability.
663 * Applications are then free to use either PCM or encoded output.
664 */
665 public static final int ENCODED_SURROUND_OUTPUT_ALWAYS = 2;
666
667 /**
668 * Surround sound formats are available according to the choice of user, even if they are not
669 * detected by the hardware. Those formats will be reported as part of the HDMI output
670 * capability. Applications are then free to use either PCM or encoded output.
671 */
672 public static final int ENCODED_SURROUND_OUTPUT_MANUAL = 3;
673
Jean-Michel Trivi48f99852023-03-31 18:47:58 -0700674 /**
675 * @hide
676 * This list contains all the flags that can be used in internal APIs for volume
677 * related operations */
Jin Seok Parkfc9db6c2021-02-26 02:37:20 +0900678 @IntDef(flag = true, prefix = "FLAG", value = {
Jin Seok Park5ccb6cc2021-02-05 01:47:13 +0900679 FLAG_SHOW_UI,
680 FLAG_ALLOW_RINGER_MODES,
681 FLAG_PLAY_SOUND,
682 FLAG_REMOVE_SOUND_AND_VIBRATE,
683 FLAG_VIBRATE,
684 FLAG_FIXED_VOLUME,
685 FLAG_BLUETOOTH_ABS_VOLUME,
686 FLAG_SHOW_SILENT_HINT,
687 FLAG_HDMI_SYSTEM_AUDIO_VOLUME,
688 FLAG_ACTIVE_MEDIA_ONLY,
689 FLAG_SHOW_UI_WARNINGS,
690 FLAG_SHOW_VIBRATE_HINT,
691 FLAG_FROM_KEY,
Yan Han7d419822022-01-31 19:10:16 +0100692 FLAG_ABSOLUTE_VOLUME,
Jin Seok Park5ccb6cc2021-02-05 01:47:13 +0900693 })
694 @Retention(RetentionPolicy.SOURCE)
Atneya Nair511993782023-10-30 22:03:34 -0700695 // TODO(308698465) remove due to potential conflict with the new flags class
Jin Seok Park5ccb6cc2021-02-05 01:47:13 +0900696 public @interface Flags {}
697
Jean-Michel Trivi48f99852023-03-31 18:47:58 -0700698 /**
699 * @hide
700 * This list contains all the flags that can be used in SDK-visible methods for volume
701 * related operations.
702 * See for instance {@link #adjustVolume(int, int)},
703 * {@link #adjustStreamVolume(int, int, int)},
704 * {@link #adjustSuggestedStreamVolume(int, int, int)},
705 * {@link #adjustVolumeGroupVolume(int, int, int)},
706 * {@link #setStreamVolume(int, int, int)}
707 * The list contains all volume flags, but the values commented out of the list are there for
708 * maintenance reasons (for when adding flags or changing their visibility),
709 * and to document why some are not in the list (hidden or SystemApi). */
Jean-Michel Trivi23123b62023-02-14 01:22:31 +0000710 @IntDef(flag = true, prefix = "FLAG", value = {
711 FLAG_SHOW_UI,
712 FLAG_ALLOW_RINGER_MODES,
713 FLAG_PLAY_SOUND,
714 FLAG_REMOVE_SOUND_AND_VIBRATE,
715 FLAG_VIBRATE,
Jean-Michel Trivi48f99852023-03-31 18:47:58 -0700716 //FLAG_FIXED_VOLUME, removed due to @hide
717 //FLAG_BLUETOOTH_ABS_VOLUME, removed due to @SystemApi
718 //FLAG_SHOW_SILENT_HINT, removed due to @hide
719 //FLAG_HDMI_SYSTEM_AUDIO_VOLUME, removed due to @hide
720 //FLAG_ACTIVE_MEDIA_ONLY, removed due to @hide
721 //FLAG_SHOW_UI_WARNINGS, removed due to @hide
722 //FLAG_SHOW_VIBRATE_HINT, removed due to @hide
723 //FLAG_FROM_KEY, removed due to @SystemApi
724 //FLAG_ABSOLUTE_VOLUME, removed due to @hide
725 })
726 @Retention(RetentionPolicy.SOURCE)
727 public @interface PublicVolumeFlags {}
728
729 /**
730 * @hide
731 * Like PublicVolumeFlags, but for all the flags that can be used in @SystemApi methods for
732 * volume related operations.
733 * See for instance {@link #setVolumeIndexForAttributes(AudioAttributes, int, int)},
734 * {@link #setVolumeGroupVolumeIndex(int, int, int)},
735 * {@link #setStreamVolumeForUid(int, int, int, String, int, int, int)},
736 * {@link #adjustStreamVolumeForUid(int, int, int, String, int, int, int)},
737 * {@link #adjustSuggestedStreamVolumeForUid(int, int, int, String, int, int, int)}
738 * The list contains all volume flags, but the values commented out of the list are there for
739 * maintenance reasons (for when adding flags or changing their visibility),
740 * and to document which hidden values are not in the list. */
741 @IntDef(flag = true, prefix = "FLAG", value = {
742 FLAG_SHOW_UI,
743 FLAG_ALLOW_RINGER_MODES,
744 FLAG_PLAY_SOUND,
745 FLAG_REMOVE_SOUND_AND_VIBRATE,
746 FLAG_VIBRATE,
747 //FLAG_FIXED_VOLUME, removed due to @hide
Jean-Michel Trivi23123b62023-02-14 01:22:31 +0000748 FLAG_BLUETOOTH_ABS_VOLUME,
Jean-Michel Trivi48f99852023-03-31 18:47:58 -0700749 //FLAG_SHOW_SILENT_HINT, removed due to @hide
750 //FLAG_HDMI_SYSTEM_AUDIO_VOLUME, removed due to @hide
751 //FLAG_ACTIVE_MEDIA_ONLY, removed due to @hide
752 //FLAG_SHOW_UI_WARNINGS, removed due to @hide
753 //FLAG_SHOW_VIBRATE_HINT, removed due to @hide
Jean-Michel Trivi23123b62023-02-14 01:22:31 +0000754 FLAG_FROM_KEY,
Jean-Michel Trivi48f99852023-03-31 18:47:58 -0700755 //FLAG_ABSOLUTE_VOLUME, removed due to @hide
Jean-Michel Trivi23123b62023-02-14 01:22:31 +0000756 })
757 @Retention(RetentionPolicy.SOURCE)
758 public @interface SystemVolumeFlags {}
759
Hyundo Moonca0080d2018-12-26 16:16:55 +0900760 // The iterator of TreeMap#entrySet() returns the entries in ascending key order.
761 private static final TreeMap<Integer, String> FLAG_NAMES = new TreeMap<>();
762
763 static {
764 FLAG_NAMES.put(FLAG_SHOW_UI, "FLAG_SHOW_UI");
765 FLAG_NAMES.put(FLAG_ALLOW_RINGER_MODES, "FLAG_ALLOW_RINGER_MODES");
766 FLAG_NAMES.put(FLAG_PLAY_SOUND, "FLAG_PLAY_SOUND");
767 FLAG_NAMES.put(FLAG_REMOVE_SOUND_AND_VIBRATE, "FLAG_REMOVE_SOUND_AND_VIBRATE");
768 FLAG_NAMES.put(FLAG_VIBRATE, "FLAG_VIBRATE");
769 FLAG_NAMES.put(FLAG_FIXED_VOLUME, "FLAG_FIXED_VOLUME");
770 FLAG_NAMES.put(FLAG_BLUETOOTH_ABS_VOLUME, "FLAG_BLUETOOTH_ABS_VOLUME");
771 FLAG_NAMES.put(FLAG_SHOW_SILENT_HINT, "FLAG_SHOW_SILENT_HINT");
772 FLAG_NAMES.put(FLAG_HDMI_SYSTEM_AUDIO_VOLUME, "FLAG_HDMI_SYSTEM_AUDIO_VOLUME");
773 FLAG_NAMES.put(FLAG_ACTIVE_MEDIA_ONLY, "FLAG_ACTIVE_MEDIA_ONLY");
774 FLAG_NAMES.put(FLAG_SHOW_UI_WARNINGS, "FLAG_SHOW_UI_WARNINGS");
775 FLAG_NAMES.put(FLAG_SHOW_VIBRATE_HINT, "FLAG_SHOW_VIBRATE_HINT");
776 FLAG_NAMES.put(FLAG_FROM_KEY, "FLAG_FROM_KEY");
Yan Han7d419822022-01-31 19:10:16 +0100777 FLAG_NAMES.put(FLAG_ABSOLUTE_VOLUME, "FLAG_ABSOLUTE_VOLUME");
Hyundo Moonca0080d2018-12-26 16:16:55 +0900778 }
John Spurlock661f2cf42014-11-17 10:29:10 -0500779
780 /** @hide */
781 public static String flagsToString(int flags) {
782 final StringBuilder sb = new StringBuilder();
Hyundo Moonca0080d2018-12-26 16:16:55 +0900783 for (Map.Entry<Integer, String> entry : FLAG_NAMES.entrySet()) {
784 final int flag = entry.getKey();
John Spurlock661f2cf42014-11-17 10:29:10 -0500785 if ((flags & flag) != 0) {
786 if (sb.length() > 0) {
787 sb.append(',');
788 }
Hyundo Moonca0080d2018-12-26 16:16:55 +0900789 sb.append(entry.getValue());
John Spurlock661f2cf42014-11-17 10:29:10 -0500790 flags &= ~flag;
791 }
792 }
793 if (flags != 0) {
794 if (sb.length() > 0) {
795 sb.append(',');
796 }
797 sb.append(flags);
798 }
799 return sb.toString();
800 }
801
802 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800803 * Ringer mode that will be silent and will not vibrate. (This overrides the
804 * vibrate setting.)
805 *
806 * @see #setRingerMode(int)
807 * @see #getRingerMode()
808 */
809 public static final int RINGER_MODE_SILENT = 0;
810
811 /**
812 * Ringer mode that will be silent and will vibrate. (This will cause the
813 * phone ringer to always vibrate, but the notification vibrate to only
814 * vibrate if set.)
815 *
816 * @see #setRingerMode(int)
817 * @see #getRingerMode()
818 */
819 public static final int RINGER_MODE_VIBRATE = 1;
820
821 /**
822 * Ringer mode that may be audible and may vibrate. It will be audible if
823 * the volume before changing out of this mode was audible. It will vibrate
824 * if the vibrate setting is on.
825 *
826 * @see #setRingerMode(int)
827 * @see #getRingerMode()
828 */
829 public static final int RINGER_MODE_NORMAL = 2;
830
John Spurlock97559372014-10-24 16:27:36 -0400831 /**
832 * Maximum valid ringer mode value. Values must start from 0 and be contiguous.
833 * @hide
834 */
835 public static final int RINGER_MODE_MAX = RINGER_MODE_NORMAL;
Eric Laurent72668b22011-07-19 16:04:27 -0700836
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800837 /**
838 * Vibrate type that corresponds to the ringer.
839 *
840 * @see #setVibrateSetting(int, int)
841 * @see #getVibrateSetting(int)
842 * @see #shouldVibrate(int)
Eric Laurentcd1cd732012-05-01 11:23:07 -0700843 * @deprecated Applications should maintain their own vibrate policy based on
844 * current ringer mode that can be queried via {@link #getRingerMode()}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800845 */
846 public static final int VIBRATE_TYPE_RINGER = 0;
847
848 /**
849 * Vibrate type that corresponds to notifications.
850 *
851 * @see #setVibrateSetting(int, int)
852 * @see #getVibrateSetting(int)
853 * @see #shouldVibrate(int)
Eric Laurentcd1cd732012-05-01 11:23:07 -0700854 * @deprecated Applications should maintain their own vibrate policy based on
855 * current ringer mode that can be queried via {@link #getRingerMode()}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800856 */
857 public static final int VIBRATE_TYPE_NOTIFICATION = 1;
858
859 /**
860 * Vibrate setting that suggests to never vibrate.
861 *
862 * @see #setVibrateSetting(int, int)
863 * @see #getVibrateSetting(int)
Eric Laurentcd1cd732012-05-01 11:23:07 -0700864 * @deprecated Applications should maintain their own vibrate policy based on
865 * current ringer mode that can be queried via {@link #getRingerMode()}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800866 */
867 public static final int VIBRATE_SETTING_OFF = 0;
868
869 /**
870 * Vibrate setting that suggests to vibrate when possible.
871 *
872 * @see #setVibrateSetting(int, int)
873 * @see #getVibrateSetting(int)
Eric Laurentcd1cd732012-05-01 11:23:07 -0700874 * @deprecated Applications should maintain their own vibrate policy based on
875 * current ringer mode that can be queried via {@link #getRingerMode()}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800876 */
877 public static final int VIBRATE_SETTING_ON = 1;
878
879 /**
880 * Vibrate setting that suggests to only vibrate when in the vibrate ringer
881 * mode.
882 *
883 * @see #setVibrateSetting(int, int)
884 * @see #getVibrateSetting(int)
Eric Laurentcd1cd732012-05-01 11:23:07 -0700885 * @deprecated Applications should maintain their own vibrate policy based on
886 * current ringer mode that can be queried via {@link #getRingerMode()}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800887 */
888 public static final int VIBRATE_SETTING_ONLY_SILENT = 2;
889
890 /**
891 * Suggests using the default stream type. This may not be used in all
892 * places a stream type is needed.
893 */
894 public static final int USE_DEFAULT_STREAM_TYPE = Integer.MIN_VALUE;
895
896 private static IAudioService sService;
897
898 /**
899 * @hide
Jean-Michel Trivi9dc22c22017-01-05 18:06:03 -0800900 * For test purposes only, will throw NPE with some methods that require a Context.
901 */
Mathew Inwood8e742f92020-10-27 11:47:29 +0000902 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
Jean-Michel Trivi9dc22c22017-01-05 18:06:03 -0800903 public AudioManager() {
Jean-Michel Trivi9dc22c22017-01-05 18:06:03 -0800904 }
905
906 /**
907 * @hide
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800908 */
Mathew Inwood31a792a2018-08-17 08:54:26 +0100909 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800910 public AudioManager(Context context) {
Marco Nelissen29f16932015-04-17 09:50:56 -0700911 setContext(context);
Jean-Michel Trivi31323ab2023-11-22 17:44:29 +0000912 initPlatform();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800913 }
914
Marco Nelissen29f16932015-04-17 09:50:56 -0700915 private Context getContext() {
916 if (mApplicationContext == null) {
917 setContext(mOriginalContext);
918 }
919 if (mApplicationContext != null) {
920 return mApplicationContext;
921 }
922 return mOriginalContext;
923 }
924
925 private void setContext(Context context) {
Jean-Michel Trivi31323ab2023-11-22 17:44:29 +0000926 if (context == null) {
927 return;
928 }
Ján Sebechlebskýdcc49642023-02-07 10:20:59 +0000929 mOriginalContextDeviceId = context.getDeviceId();
Marco Nelissen29f16932015-04-17 09:50:56 -0700930 mApplicationContext = context.getApplicationContext();
931 if (mApplicationContext != null) {
932 mOriginalContext = null;
933 } else {
934 mOriginalContext = context;
935 }
jiabin0f3339c2021-07-09 11:50:07 -0700936 sContext = new WeakReference<>(context);
Marco Nelissen29f16932015-04-17 09:50:56 -0700937 }
938
Mathew Inwood31a792a2018-08-17 08:54:26 +0100939 @UnsupportedAppUsage
Jean-Michel Trivie9dd14e2021-07-12 11:10:18 -0700940 static IAudioService getService()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800941 {
942 if (sService != null) {
943 return sService;
944 }
945 IBinder b = ServiceManager.getService(Context.AUDIO_SERVICE);
946 sService = IAudioService.Stub.asInterface(b);
947 return sService;
948 }
949
Jan Sebechlebskyfb48c022022-12-16 16:26:47 +0100950 private VirtualDeviceManager getVirtualDeviceManager() {
951 if (mVirtualDeviceManager != null) {
952 return mVirtualDeviceManager;
953 }
954 mVirtualDeviceManager = getContext().getSystemService(VirtualDeviceManager.class);
955 return mVirtualDeviceManager;
956 }
957
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800958 /**
Santiago Seifert309a61b2023-09-21 13:43:34 +0000959 * Sends a simulated key event for a media button. To simulate a key press, you must first send
960 * a KeyEvent built with a {@link KeyEvent#ACTION_DOWN} action, then another event with the
961 * {@link KeyEvent#ACTION_UP} action.
962 *
Jean-Michel Trivia83487e2013-09-17 21:19:30 -0700963 * <p>The key event will be sent to the current media key event consumer which registered with
964 * {@link AudioManager#registerMediaButtonEventReceiver(PendingIntent)}.
Santiago Seifert309a61b2023-09-21 13:43:34 +0000965 *
966 * @param keyEvent a media session {@link KeyEvent}, as defined by {@link
967 * KeyEvent#isMediaSessionKey}.
Jean-Michel Trivi7ddd2262013-09-01 18:06:45 -0700968 */
Jean-Michel Trivia83487e2013-09-17 21:19:30 -0700969 public void dispatchMediaKeyEvent(KeyEvent keyEvent) {
Marco Nelissen29f16932015-04-17 09:50:56 -0700970 MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(getContext());
RoboErik430fc482014-06-12 15:49:20 -0700971 helper.sendMediaButtonEvent(keyEvent, false);
Jean-Michel Trivi7ddd2262013-09-01 18:06:45 -0700972 }
973
974 /**
975 * @hide
Joe Onorato86f67862010-11-05 18:57:34 -0700976 */
Mike Lockwoodce952c82011-11-14 10:47:42 -0800977 public void preDispatchKeyEvent(KeyEvent event, int stream) {
Joe Onorato86f67862010-11-05 18:57:34 -0700978 /*
979 * If the user hits another key within the play sound delay, then
980 * cancel the sound
981 */
Mike Lockwoodce952c82011-11-14 10:47:42 -0800982 int keyCode = event.getKeyCode();
Joe Onorato86f67862010-11-05 18:57:34 -0700983 if (keyCode != KeyEvent.KEYCODE_VOLUME_DOWN && keyCode != KeyEvent.KEYCODE_VOLUME_UP
984 && keyCode != KeyEvent.KEYCODE_VOLUME_MUTE
Santiago Seifert75969912023-01-18 11:11:30 +0000985 && AudioSystem.PLAY_SOUND_DELAY > SystemClock.uptimeMillis()) {
Joe Onorato86f67862010-11-05 18:57:34 -0700986 /*
987 * The user has hit another key during the delay (e.g., 300ms)
988 * since the last volume key up, so cancel any sounds.
989 */
John Spurlockee5ad722015-03-03 16:17:21 -0500990 adjustSuggestedStreamVolume(ADJUST_SAME,
991 stream, AudioManager.FLAG_REMOVE_SOUND_AND_VIBRATE);
Joe Onorato86f67862010-11-05 18:57:34 -0700992 }
993 }
994
995 /**
Eric Laurentba207e72014-05-15 17:08:16 -0700996 * Indicates if the device implements a fixed volume policy.
997 * <p>Some devices may not have volume control and may operate at a fixed volume,
998 * and may not enable muting or changing the volume of audio streams.
999 * This method will return true on such devices.
1000 * <p>The following APIs have no effect when volume is fixed:
1001 * <ul>
1002 * <li> {@link #adjustVolume(int, int)}
1003 * <li> {@link #adjustSuggestedStreamVolume(int, int, int)}
1004 * <li> {@link #adjustStreamVolume(int, int, int)}
1005 * <li> {@link #setStreamVolume(int, int, int)}
1006 * <li> {@link #setRingerMode(int)}
1007 * <li> {@link #setStreamSolo(int, boolean)}
1008 * <li> {@link #setStreamMute(int, boolean)}
1009 * </ul>
1010 */
1011 public boolean isVolumeFixed() {
Jean-Michel Trivi547d2632021-10-26 15:40:58 -07001012 boolean res = false;
1013 try {
1014 res = getService().isVolumeFixed();
1015 } catch (RemoteException e) {
1016 Log.e(TAG, "Error querying isVolumeFixed", e);
Jean-Michel Trivia0513082020-09-22 18:43:53 -07001017 }
Jean-Michel Trivi547d2632021-10-26 15:40:58 -07001018 return res;
Eric Laurentba207e72014-05-15 17:08:16 -07001019 }
1020
1021 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001022 * Adjusts the volume of a particular stream by one step in a direction.
Jean-Michel Trivifccb25d2009-09-15 16:06:10 -07001023 * <p>
1024 * This method should only be used by applications that replace the platform-wide
1025 * management of audio settings or the main telephony application.
Jean-Michel Trivi59773622018-06-19 17:17:57 -07001026 * <p>This method has no effect if the device implements a fixed volume policy
1027 * as indicated by {@link #isVolumeFixed()}.
1028 * <p>From N onward, ringer mode adjustments that would toggle Do Not Disturb are not allowed
1029 * unless the app has been granted Do Not Disturb Access.
1030 * See {@link NotificationManager#isNotificationPolicyAccessGranted()}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001031 *
1032 * @param streamType The stream type to adjust. One of {@link #STREAM_VOICE_CALL},
Jean-Michel Trivi8e0bc782016-11-25 10:22:23 -08001033 * {@link #STREAM_SYSTEM}, {@link #STREAM_RING}, {@link #STREAM_MUSIC},
1034 * {@link #STREAM_ALARM} or {@link #STREAM_ACCESSIBILITY}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001035 * @param direction The direction to adjust the volume. One of
1036 * {@link #ADJUST_LOWER}, {@link #ADJUST_RAISE}, or
1037 * {@link #ADJUST_SAME}.
Jean-Michel Trivi48f99852023-03-31 18:47:58 -07001038 * @param flags
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001039 * @see #adjustVolume(int, int)
1040 * @see #setStreamVolume(int, int, int)
Jean-Michel Trivi59773622018-06-19 17:17:57 -07001041 * @throws SecurityException if the adjustment triggers a Do Not Disturb change
1042 * and the caller is not granted notification policy access.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001043 */
Jean-Michel Trivi48f99852023-03-31 18:47:58 -07001044 public void adjustStreamVolume(int streamType, int direction, @PublicVolumeFlags int flags) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001045 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001046 try {
John Wu4f7e5102021-06-22 17:29:11 +00001047 service.adjustStreamVolumeWithAttribution(streamType, direction, flags,
1048 getContext().getOpPackageName(), getContext().getAttributionTag());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001049 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001050 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001051 }
1052 }
1053
1054 /**
1055 * Adjusts the volume of the most relevant stream. For example, if a call is
1056 * active, it will have the highest priority regardless of if the in-call
1057 * screen is showing. Another example, if music is playing in the background
1058 * and a call is not active, the music stream will be adjusted.
Jean-Michel Trivifccb25d2009-09-15 16:06:10 -07001059 * <p>
RoboErik4197cb62015-01-21 15:45:32 -08001060 * This method should only be used by applications that replace the
1061 * platform-wide management of audio settings or the main telephony
1062 * application.
1063 * <p>
1064 * This method has no effect if the device implements a fixed volume policy
Eric Laurentba207e72014-05-15 17:08:16 -07001065 * as indicated by {@link #isVolumeFixed()}.
RoboErik4197cb62015-01-21 15:45:32 -08001066 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001067 * @param direction The direction to adjust the volume. One of
RoboErik4197cb62015-01-21 15:45:32 -08001068 * {@link #ADJUST_LOWER}, {@link #ADJUST_RAISE},
1069 * {@link #ADJUST_SAME}, {@link #ADJUST_MUTE},
1070 * {@link #ADJUST_UNMUTE}, or {@link #ADJUST_TOGGLE_MUTE}.
Jean-Michel Trivi48f99852023-03-31 18:47:58 -07001071 * @param flags
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001072 * @see #adjustSuggestedStreamVolume(int, int, int)
1073 * @see #adjustStreamVolume(int, int, int)
1074 * @see #setStreamVolume(int, int, int)
Eric Laurentba207e72014-05-15 17:08:16 -07001075 * @see #isVolumeFixed()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001076 */
Jean-Michel Trivi48f99852023-03-31 18:47:58 -07001077 public void adjustVolume(int direction, @PublicVolumeFlags int flags) {
Jean-Michel Trivi31323ab2023-11-22 17:44:29 +00001078 if (applyAutoHardening()) {
1079 final IAudioService service = getService();
1080 try {
1081 service.adjustVolume(direction, flags);
1082 } catch (RemoteException e) {
1083 throw e.rethrowFromSystemServer();
1084 }
1085 } else {
1086 MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(getContext());
1087 helper.sendAdjustVolumeBy(USE_DEFAULT_STREAM_TYPE, direction, flags);
1088 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001089 }
1090
1091 /**
1092 * Adjusts the volume of the most relevant stream, or the given fallback
1093 * stream.
Jean-Michel Trivifccb25d2009-09-15 16:06:10 -07001094 * <p>
RoboErik4197cb62015-01-21 15:45:32 -08001095 * This method should only be used by applications that replace the
1096 * platform-wide management of audio settings or the main telephony
1097 * application.
1098 * <p>
1099 * This method has no effect if the device implements a fixed volume policy
Eric Laurentba207e72014-05-15 17:08:16 -07001100 * as indicated by {@link #isVolumeFixed()}.
RoboErik4197cb62015-01-21 15:45:32 -08001101 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001102 * @param direction The direction to adjust the volume. One of
RoboErik4197cb62015-01-21 15:45:32 -08001103 * {@link #ADJUST_LOWER}, {@link #ADJUST_RAISE},
1104 * {@link #ADJUST_SAME}, {@link #ADJUST_MUTE},
1105 * {@link #ADJUST_UNMUTE}, or {@link #ADJUST_TOGGLE_MUTE}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001106 * @param suggestedStreamType The stream type that will be used if there
RoboErik4197cb62015-01-21 15:45:32 -08001107 * isn't a relevant stream. {@link #USE_DEFAULT_STREAM_TYPE} is
1108 * valid here.
Jean-Michel Trivi48f99852023-03-31 18:47:58 -07001109 * @param flags
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001110 * @see #adjustVolume(int, int)
1111 * @see #adjustStreamVolume(int, int, int)
1112 * @see #setStreamVolume(int, int, int)
Eric Laurentba207e72014-05-15 17:08:16 -07001113 * @see #isVolumeFixed()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001114 */
Jean-Michel Trivi48f99852023-03-31 18:47:58 -07001115 public void adjustSuggestedStreamVolume(int direction, int suggestedStreamType,
1116 @PublicVolumeFlags int flags) {
Jean-Michel Trivi31323ab2023-11-22 17:44:29 +00001117 if (applyAutoHardening()) {
1118 final IAudioService service = getService();
1119 try {
1120 service.adjustSuggestedStreamVolume(direction, suggestedStreamType, flags);
1121 } catch (RemoteException e) {
1122 throw e.rethrowFromSystemServer();
1123 }
1124 } else {
1125 MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(getContext());
1126 helper.sendAdjustVolumeBy(suggestedStreamType, direction, flags);
1127 }
Mike Lockwoodcbdb49d2011-10-20 12:54:05 -04001128 }
1129
John Spurlockee5ad722015-03-03 16:17:21 -05001130 /** @hide */
Mathew Inwood31a792a2018-08-17 08:54:26 +01001131 @UnsupportedAppUsage
Jean-Michel Trivic4557822023-01-23 18:19:52 +00001132 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
John Spurlockee5ad722015-03-03 16:17:21 -05001133 public void setMasterMute(boolean mute, int flags) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001134 final IAudioService service = getService();
Mike Lockwoodcbdb49d2011-10-20 12:54:05 -04001135 try {
Kenny Guy70e0c582015-06-30 19:18:28 +01001136 service.setMasterMute(mute, flags, getContext().getOpPackageName(),
John Wu4f7e5102021-06-22 17:29:11 +00001137 UserHandle.getCallingUserId(), getContext().getAttributionTag());
Mike Lockwoodcbdb49d2011-10-20 12:54:05 -04001138 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001139 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001140 }
1141 }
1142
1143 /**
1144 * Returns the current ringtone mode.
1145 *
1146 * @return The current ringtone mode, one of {@link #RINGER_MODE_NORMAL},
1147 * {@link #RINGER_MODE_SILENT}, or {@link #RINGER_MODE_VIBRATE}.
1148 * @see #setRingerMode(int)
1149 */
1150 public int getRingerMode() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001151 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001152 try {
John Spurlock661f2cf42014-11-17 10:29:10 -05001153 return service.getRingerModeExternal();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001154 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001155 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001156 }
1157 }
1158
1159 /**
Lais Andrade724d0cd2021-11-03 19:46:21 +00001160 * Returns the current user setting for ramping ringer on incoming phone call ringtone.
1161 *
1162 * @return true if the incoming phone call ringtone is configured to gradually increase its
1163 * volume, false otherwise.
1164 */
1165 public boolean isRampingRingerEnabled() {
1166 return Settings.System.getInt(getContext().getContentResolver(),
1167 Settings.System.APPLY_RAMPING_RINGER, 0) != 0;
1168 }
1169
1170 /**
1171 * Sets the flag for enabling ramping ringer on incoming phone call ringtone.
1172 *
1173 * @see #isRampingRingerEnabled()
1174 * @hide
1175 */
1176 @TestApi
1177 public void setRampingRingerEnabled(boolean enabled) {
1178 Settings.System.putInt(getContext().getContentResolver(),
1179 Settings.System.APPLY_RAMPING_RINGER, enabled ? 1 : 0);
1180 }
1181
1182 /**
Eric Laurent72668b22011-07-19 16:04:27 -07001183 * Checks valid ringer mode values.
1184 *
1185 * @return true if the ringer mode indicated is valid, false otherwise.
1186 *
1187 * @see #setRingerMode(int)
1188 * @hide
1189 */
Mathew Inwood8e742f92020-10-27 11:47:29 +00001190 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
Eric Laurent72668b22011-07-19 16:04:27 -07001191 public static boolean isValidRingerMode(int ringerMode) {
1192 if (ringerMode < 0 || ringerMode > RINGER_MODE_MAX) {
1193 return false;
1194 }
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001195 final IAudioService service = getService();
John Spurlock97559372014-10-24 16:27:36 -04001196 try {
1197 return service.isValidRingerMode(ringerMode);
1198 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001199 throw e.rethrowFromSystemServer();
John Spurlock97559372014-10-24 16:27:36 -04001200 }
Eric Laurent72668b22011-07-19 16:04:27 -07001201 }
1202
1203 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001204 * Returns the maximum volume index for a particular stream.
1205 *
1206 * @param streamType The stream type whose maximum volume index is returned.
1207 * @return The maximum valid volume index for the stream.
1208 * @see #getStreamVolume(int)
1209 */
1210 public int getStreamMaxVolume(int streamType) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001211 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001212 try {
John Spurlockee5ad722015-03-03 16:17:21 -05001213 return service.getStreamMaxVolume(streamType);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001214 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001215 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001216 }
1217 }
1218
1219 /**
John Spurlockb6e19e32015-03-10 21:33:44 -04001220 * Returns the minimum volume index for a particular stream.
Jean-Michel Trivi8e7aca32017-11-28 18:12:38 -08001221 * @param streamType The stream type whose minimum volume index is returned. Must be one of
1222 * {@link #STREAM_VOICE_CALL}, {@link #STREAM_SYSTEM},
1223 * {@link #STREAM_RING}, {@link #STREAM_MUSIC}, {@link #STREAM_ALARM},
1224 * {@link #STREAM_NOTIFICATION}, {@link #STREAM_DTMF} or {@link #STREAM_ACCESSIBILITY}.
1225 * @return The minimum valid volume index for the stream.
1226 * @see #getStreamVolume(int)
1227 */
1228 public int getStreamMinVolume(int streamType) {
1229 if (!isPublicStreamType(streamType)) {
1230 throw new IllegalArgumentException("Invalid stream type " + streamType);
1231 }
1232 return getStreamMinVolumeInt(streamType);
1233 }
1234
1235 /**
1236 * @hide
1237 * Same as {@link #getStreamMinVolume(int)} but without the check on the public stream type.
John Spurlockb6e19e32015-03-10 21:33:44 -04001238 * @param streamType The stream type whose minimum volume index is returned.
1239 * @return The minimum valid volume index for the stream.
1240 * @see #getStreamVolume(int)
John Spurlockb6e19e32015-03-10 21:33:44 -04001241 */
Paul McLeand6f87c82021-03-31 13:02:41 -06001242 @TestApi
Jean-Michel Trivi8e7aca32017-11-28 18:12:38 -08001243 public int getStreamMinVolumeInt(int streamType) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001244 final IAudioService service = getService();
John Spurlockb6e19e32015-03-10 21:33:44 -04001245 try {
1246 return service.getStreamMinVolume(streamType);
1247 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001248 throw e.rethrowFromSystemServer();
John Spurlockb6e19e32015-03-10 21:33:44 -04001249 }
1250 }
1251
1252 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001253 * Returns the current volume index for a particular stream.
1254 *
1255 * @param streamType The stream type whose volume index is returned.
1256 * @return The current volume index for the stream.
1257 * @see #getStreamMaxVolume(int)
1258 * @see #setStreamVolume(int, int, int)
1259 */
1260 public int getStreamVolume(int streamType) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001261 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001262 try {
John Spurlockee5ad722015-03-03 16:17:21 -05001263 return service.getStreamVolume(streamType);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001264 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001265 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001266 }
1267 }
1268
Jean-Michel Trivi8e7aca32017-11-28 18:12:38 -08001269 // keep in sync with frameworks/av/services/audiopolicy/common/include/Volume.h
1270 private static final float VOLUME_MIN_DB = -758.0f;
1271
1272 /** @hide */
1273 @IntDef(flag = false, prefix = "STREAM", value = {
1274 STREAM_VOICE_CALL,
1275 STREAM_SYSTEM,
1276 STREAM_RING,
1277 STREAM_MUSIC,
1278 STREAM_ALARM,
1279 STREAM_NOTIFICATION,
1280 STREAM_DTMF,
1281 STREAM_ACCESSIBILITY }
1282 )
1283 @Retention(RetentionPolicy.SOURCE)
1284 public @interface PublicStreamTypes {}
1285
1286 /**
1287 * Returns the volume in dB (decibel) for the given stream type at the given volume index, on
1288 * the given type of audio output device.
1289 * @param streamType stream type for which the volume is queried.
1290 * @param index the volume index for which the volume is queried. The index value must be
1291 * between the minimum and maximum index values for the given stream type (see
1292 * {@link #getStreamMinVolume(int)} and {@link #getStreamMaxVolume(int)}).
1293 * @param deviceType the type of audio output device for which volume is queried.
1294 * @return a volume expressed in dB.
1295 * A negative value indicates the audio signal is attenuated. A typical maximum value
1296 * at the maximum volume index is 0 dB (no attenuation nor amplification). Muting is
1297 * reflected by a value of {@link Float#NEGATIVE_INFINITY}.
1298 */
1299 public float getStreamVolumeDb(@PublicStreamTypes int streamType, int index,
1300 @AudioDeviceInfo.AudioDeviceTypeOut int deviceType) {
1301 if (!isPublicStreamType(streamType)) {
1302 throw new IllegalArgumentException("Invalid stream type " + streamType);
1303 }
1304 if (index > getStreamMaxVolume(streamType) || index < getStreamMinVolume(streamType)) {
1305 throw new IllegalArgumentException("Invalid stream volume index " + index);
1306 }
1307 if (!AudioDeviceInfo.isValidAudioDeviceTypeOut(deviceType)) {
1308 throw new IllegalArgumentException("Invalid audio output device type " + deviceType);
1309 }
1310 final float gain = AudioSystem.getStreamVolumeDB(streamType, index,
1311 AudioDeviceInfo.convertDeviceTypeToInternalDevice(deviceType));
1312 if (gain <= VOLUME_MIN_DB) {
1313 return Float.NEGATIVE_INFINITY;
1314 } else {
1315 return gain;
1316 }
1317 }
1318
Jean-Michel Trivi283a4c72022-09-28 21:46:51 +00001319 /**
1320 * @hide
1321 * Checks whether a stream type is part of the public SDK
1322 * @param streamType
1323 * @return true if the stream type is available in SDK
1324 */
1325 public static boolean isPublicStreamType(int streamType) {
Jean-Michel Trivi8e7aca32017-11-28 18:12:38 -08001326 switch (streamType) {
1327 case STREAM_VOICE_CALL:
1328 case STREAM_SYSTEM:
1329 case STREAM_RING:
1330 case STREAM_MUSIC:
1331 case STREAM_ALARM:
1332 case STREAM_NOTIFICATION:
1333 case STREAM_DTMF:
1334 case STREAM_ACCESSIBILITY:
1335 return true;
1336 default:
1337 return false;
1338 }
1339 }
1340
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001341 /**
Eric Laurent25101b02011-02-02 09:33:30 -08001342 * Get last audible volume before stream was muted.
1343 *
1344 * @hide
1345 */
wescandee178f8f2021-10-19 20:15:09 +02001346 @SystemApi
1347 @RequiresPermission("android.permission.QUERY_AUDIO_STATE")
Eric Laurent25101b02011-02-02 09:33:30 -08001348 public int getLastAudibleStreamVolume(int streamType) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001349 final IAudioService service = getService();
Eric Laurent25101b02011-02-02 09:33:30 -08001350 try {
John Spurlockee5ad722015-03-03 16:17:21 -05001351 return service.getLastAudibleStreamVolume(streamType);
Eric Laurent25101b02011-02-02 09:33:30 -08001352 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001353 throw e.rethrowFromSystemServer();
Eric Laurent25101b02011-02-02 09:33:30 -08001354 }
1355 }
1356
1357 /**
Eric Laurent6d517662012-04-23 18:42:39 -07001358 * Get the stream type whose volume is driving the UI sounds volume.
1359 * UI sounds are screen lock/unlock, camera shutter, key clicks...
John Spurlock4f0f1202014-08-05 13:28:33 -04001360 * It is assumed that this stream type is also tied to ringer mode changes.
Eric Laurent6d517662012-04-23 18:42:39 -07001361 * @hide
1362 */
John Spurlockee5ad722015-03-03 16:17:21 -05001363 public int getUiSoundsStreamType() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001364 final IAudioService service = getService();
Eric Laurent6d517662012-04-23 18:42:39 -07001365 try {
John Spurlockee5ad722015-03-03 16:17:21 -05001366 return service.getUiSoundsStreamType();
Eric Laurent6d517662012-04-23 18:42:39 -07001367 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001368 throw e.rethrowFromSystemServer();
Eric Laurent6d517662012-04-23 18:42:39 -07001369 }
1370 }
1371
1372 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001373 * Sets the ringer mode.
1374 * <p>
1375 * Silent mode will mute the volume and will not vibrate. Vibrate mode will
1376 * mute the volume and vibrate. Normal mode will be audible and may vibrate
1377 * according to user settings.
Eric Laurentba207e72014-05-15 17:08:16 -07001378 * <p>This method has no effect if the device implements a fixed volume policy
1379 * as indicated by {@link #isVolumeFixed()}.
Julia Reynolds48034f82016-03-09 10:15:16 -05001380 * * <p>From N onward, ringer mode adjustments that would toggle Do Not Disturb are not allowed
1381 * unless the app has been granted Do Not Disturb Access.
1382 * See {@link NotificationManager#isNotificationPolicyAccessGranted()}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001383 * @param ringerMode The ringer mode, one of {@link #RINGER_MODE_NORMAL},
1384 * {@link #RINGER_MODE_SILENT}, or {@link #RINGER_MODE_VIBRATE}.
1385 * @see #getRingerMode()
Eric Laurentba207e72014-05-15 17:08:16 -07001386 * @see #isVolumeFixed()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001387 */
1388 public void setRingerMode(int ringerMode) {
Eric Laurent72668b22011-07-19 16:04:27 -07001389 if (!isValidRingerMode(ringerMode)) {
1390 return;
1391 }
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001392 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001393 try {
Marco Nelissen29f16932015-04-17 09:50:56 -07001394 service.setRingerModeExternal(ringerMode, getContext().getOpPackageName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001395 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001396 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001397 }
1398 }
1399
1400 /**
1401 * Sets the volume index for a particular stream.
Eric Laurentba207e72014-05-15 17:08:16 -07001402 * <p>This method has no effect if the device implements a fixed volume policy
1403 * as indicated by {@link #isVolumeFixed()}.
Julia Reynolds48034f82016-03-09 10:15:16 -05001404 * <p>From N onward, volume adjustments that would toggle Do Not Disturb are not allowed unless
1405 * the app has been granted Do Not Disturb Access.
1406 * See {@link NotificationManager#isNotificationPolicyAccessGranted()}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001407 * @param streamType The stream whose volume index should be set.
1408 * @param index The volume index to set. See
1409 * {@link #getStreamMaxVolume(int)} for the largest valid value.
Jean-Michel Trivi48f99852023-03-31 18:47:58 -07001410 * @param flags
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001411 * @see #getStreamMaxVolume(int)
1412 * @see #getStreamVolume(int)
Eric Laurentba207e72014-05-15 17:08:16 -07001413 * @see #isVolumeFixed()
Jean-Michel Trivi59773622018-06-19 17:17:57 -07001414 * @throws SecurityException if the volume change triggers a Do Not Disturb change
1415 * and the caller is not granted notification policy access.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001416 */
Jean-Michel Trivi48f99852023-03-31 18:47:58 -07001417 public void setStreamVolume(int streamType, int index, @PublicVolumeFlags int flags) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001418 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001419 try {
John Wu4f7e5102021-06-22 17:29:11 +00001420 service.setStreamVolumeWithAttribution(streamType, index, flags,
1421 getContext().getOpPackageName(), getContext().getAttributionTag());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001422 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001423 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001424 }
1425 }
1426
1427 /**
François Gaffie9c362102018-09-21 17:43:52 +02001428 * Sets the volume index for a particular {@link AudioAttributes}.
1429 * @param attr The {@link AudioAttributes} whose volume index should be set.
1430 * @param index The volume index to set. See
1431 * {@link #getMaxVolumeIndexForAttributes(AudioAttributes)} for the largest valid value
1432 * {@link #getMinVolumeIndexForAttributes(AudioAttributes)} for the lowest valid value.
Jean-Michel Trivi48f99852023-03-31 18:47:58 -07001433 * @param flags
François Gaffie9c362102018-09-21 17:43:52 +02001434 * @see #getMaxVolumeIndexForAttributes(AudioAttributes)
1435 * @see #getMinVolumeIndexForAttributes(AudioAttributes)
1436 * @see #isVolumeFixed()
1437 * @hide
1438 */
1439 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00001440 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
Jean-Michel Trivi48f99852023-03-31 18:47:58 -07001441 public void setVolumeIndexForAttributes(@NonNull AudioAttributes attr, int index,
1442 @SystemVolumeFlags int flags) {
François Gaffie9c362102018-09-21 17:43:52 +02001443 Preconditions.checkNotNull(attr, "attr must not be null");
1444 final IAudioService service = getService();
Francois Gaffie32a2b5f2021-11-10 13:45:42 +01001445 int groupId = getVolumeGroupIdForAttributes(attr);
1446 setVolumeGroupVolumeIndex(groupId, index, flags);
François Gaffie9c362102018-09-21 17:43:52 +02001447 }
1448
1449 /**
1450 * Returns the current volume index for a particular {@link AudioAttributes}.
1451 *
1452 * @param attr The {@link AudioAttributes} whose volume index is returned.
1453 * @return The current volume index for the stream.
1454 * @see #getMaxVolumeIndexForAttributes(AudioAttributes)
1455 * @see #getMinVolumeIndexForAttributes(AudioAttributes)
1456 * @see #setVolumeForAttributes(AudioAttributes, int, int)
1457 * @hide
1458 */
1459 @SystemApi
Hayden Gomes695f8022019-04-11 10:44:18 -07001460 @IntRange(from = 0)
Jean-Michel Trivic4557822023-01-23 18:19:52 +00001461 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
François Gaffie9c362102018-09-21 17:43:52 +02001462 public int getVolumeIndexForAttributes(@NonNull AudioAttributes attr) {
1463 Preconditions.checkNotNull(attr, "attr must not be null");
1464 final IAudioService service = getService();
Francois Gaffie32a2b5f2021-11-10 13:45:42 +01001465 int groupId = getVolumeGroupIdForAttributes(attr);
1466 return getVolumeGroupVolumeIndex(groupId);
François Gaffie9c362102018-09-21 17:43:52 +02001467 }
1468
1469 /**
1470 * Returns the maximum volume index for a particular {@link AudioAttributes}.
1471 *
1472 * @param attr The {@link AudioAttributes} whose maximum volume index is returned.
1473 * @return The maximum valid volume index for the {@link AudioAttributes}.
1474 * @see #getVolumeIndexForAttributes(AudioAttributes)
1475 * @hide
1476 */
1477 @SystemApi
Hayden Gomes695f8022019-04-11 10:44:18 -07001478 @IntRange(from = 0)
Jean-Michel Trivic4557822023-01-23 18:19:52 +00001479 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
François Gaffie9c362102018-09-21 17:43:52 +02001480 public int getMaxVolumeIndexForAttributes(@NonNull AudioAttributes attr) {
1481 Preconditions.checkNotNull(attr, "attr must not be null");
1482 final IAudioService service = getService();
Francois Gaffie32a2b5f2021-11-10 13:45:42 +01001483 int groupId = getVolumeGroupIdForAttributes(attr);
1484 return getVolumeGroupMaxVolumeIndex(groupId);
François Gaffie9c362102018-09-21 17:43:52 +02001485 }
1486
1487 /**
1488 * Returns the minimum volume index for a particular {@link AudioAttributes}.
1489 *
1490 * @param attr The {@link AudioAttributes} whose minimum volume index is returned.
1491 * @return The minimum valid volume index for the {@link AudioAttributes}.
1492 * @see #getVolumeIndexForAttributes(AudioAttributes)
1493 * @hide
1494 */
1495 @SystemApi
Hayden Gomes695f8022019-04-11 10:44:18 -07001496 @IntRange(from = 0)
Jean-Michel Trivic4557822023-01-23 18:19:52 +00001497 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
François Gaffie9c362102018-09-21 17:43:52 +02001498 public int getMinVolumeIndexForAttributes(@NonNull AudioAttributes attr) {
1499 Preconditions.checkNotNull(attr, "attr must not be null");
1500 final IAudioService service = getService();
Francois Gaffie32a2b5f2021-11-10 13:45:42 +01001501 int groupId = getVolumeGroupIdForAttributes(attr);
1502 return getVolumeGroupMinVolumeIndex(groupId);
1503 }
1504
1505 /**
1506 * Returns the volume group id associated to the given {@link AudioAttributes}.
1507 *
1508 * @param attributes The {@link AudioAttributes} to consider.
Anton Hansson49bee422023-10-11 15:33:25 +00001509 * @return audio volume group id supporting the given {@link AudioAttributes} if found,
Francois Gaffie32a2b5f2021-11-10 13:45:42 +01001510 * {@code android.media.audiopolicy.AudioVolumeGroup.DEFAULT_VOLUME_GROUP} otherwise.
1511 */
1512 public int getVolumeGroupIdForAttributes(@NonNull AudioAttributes attributes) {
1513 Preconditions.checkNotNull(attributes, "Audio Attributes must not be null");
1514 return AudioProductStrategy.getVolumeGroupIdForAudioAttributes(attributes,
Eric Laurent00c916c2023-02-03 20:50:06 +01001515 /* fallbackOnDefault= */ true);
Francois Gaffie32a2b5f2021-11-10 13:45:42 +01001516 }
1517
1518 /**
1519 * Sets the volume index for a particular group associated to given id.
1520 * <p> Call first in prior {@link #getVolumeGroupIdForAttributes(AudioAttributes)}
1521 * to retrieve the volume group id supporting the given {@link AudioAttributes}.
1522 *
1523 * @param groupId of the {@link android.media.audiopolicy.AudioVolumeGroup} to consider.
1524 * @param index The volume index to set. See
1525 * {@link #getVolumeGroupMaxVolumeIndex(id)} for the largest valid value
1526 * {@link #getVolumeGroupMinVolumeIndex(id)} for the lowest valid value.
Jean-Michel Trivi48f99852023-03-31 18:47:58 -07001527 * @param flags
Francois Gaffie32a2b5f2021-11-10 13:45:42 +01001528 * @hide
1529 */
1530 @SystemApi
1531 @RequiresPermission(anyOf = {
Jean-Michel Trivi10fd2d72023-02-13 18:06:36 +00001532 android.Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED,
Francois Gaffie32a2b5f2021-11-10 13:45:42 +01001533 android.Manifest.permission.MODIFY_AUDIO_ROUTING
1534 })
Jean-Michel Trivi23123b62023-02-14 01:22:31 +00001535 public void setVolumeGroupVolumeIndex(int groupId, int index, @SystemVolumeFlags int flags) {
Francois Gaffie32a2b5f2021-11-10 13:45:42 +01001536 final IAudioService service = getService();
François Gaffie9c362102018-09-21 17:43:52 +02001537 try {
Francois Gaffie32a2b5f2021-11-10 13:45:42 +01001538 service.setVolumeGroupVolumeIndex(groupId, index, flags,
1539 getContext().getOpPackageName(), getContext().getAttributionTag());
1540 } catch (RemoteException e) {
1541 throw e.rethrowFromSystemServer();
1542 }
1543 }
1544
1545 /**
1546 * Returns the current volume index for a particular group associated to given id.
1547 * <p> Call first in prior {@link #getVolumeGroupIdForAttributes(AudioAttributes)}
1548 * to retrieve the volume group id supporting the given {@link AudioAttributes}.
1549 *
1550 * @param groupId of the {@link android.media.audiopolicy.AudioVolumeGroup} to consider.
1551 * @return The current volume index for the stream.
1552 * @hide
1553 */
1554 @SystemApi
1555 @IntRange(from = 0)
1556 @RequiresPermission(anyOf = {
Jean-Michel Trivi10fd2d72023-02-13 18:06:36 +00001557 android.Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED,
Francois Gaffie32a2b5f2021-11-10 13:45:42 +01001558 android.Manifest.permission.MODIFY_AUDIO_ROUTING
1559 })
1560 public int getVolumeGroupVolumeIndex(int groupId) {
1561 final IAudioService service = getService();
1562 try {
1563 return service.getVolumeGroupVolumeIndex(groupId);
1564 } catch (RemoteException e) {
1565 throw e.rethrowFromSystemServer();
1566 }
1567 }
1568
1569 /**
1570 * Returns the maximum volume index for a particular group associated to given id.
1571 * <p> Call first in prior {@link #getVolumeGroupIdForAttributes(AudioAttributes)}
1572 * to retrieve the volume group id supporting the given {@link AudioAttributes}.
1573 *
1574 * @param groupId of the {@link android.media.audiopolicy.AudioVolumeGroup} to consider.
1575 * @return The maximum valid volume index for the {@link AudioAttributes}.
1576 * @hide
1577 */
1578 @SystemApi
1579 @IntRange(from = 0)
1580 @RequiresPermission(anyOf = {
Jean-Michel Trivi10fd2d72023-02-13 18:06:36 +00001581 android.Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED,
Francois Gaffie32a2b5f2021-11-10 13:45:42 +01001582 android.Manifest.permission.MODIFY_AUDIO_ROUTING
1583 })
1584 public int getVolumeGroupMaxVolumeIndex(int groupId) {
1585 final IAudioService service = getService();
1586 try {
1587 return service.getVolumeGroupMaxVolumeIndex(groupId);
1588 } catch (RemoteException e) {
1589 throw e.rethrowFromSystemServer();
1590 }
1591 }
1592
1593 /**
1594 * Returns the minimum volume index for a particular group associated to given id.
1595 * <p> Call first in prior {@link #getVolumeGroupIdForAttributes(AudioAttributes)}
1596 * to retrieve the volume group id supporting the given {@link AudioAttributes}.
1597 *
1598 * @param groupId of the {@link android.media.audiopolicy.AudioVolumeGroup} to consider.
1599 * @return The minimum valid volume index for the {@link AudioAttributes}.
1600 * @hide
1601 */
1602 @SystemApi
1603 @IntRange(from = 0)
1604 @RequiresPermission(anyOf = {
Jean-Michel Trivi10fd2d72023-02-13 18:06:36 +00001605 android.Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED,
Francois Gaffie32a2b5f2021-11-10 13:45:42 +01001606 android.Manifest.permission.MODIFY_AUDIO_ROUTING
1607 })
1608 public int getVolumeGroupMinVolumeIndex(int groupId) {
1609 final IAudioService service = getService();
1610 try {
1611 return service.getVolumeGroupMinVolumeIndex(groupId);
1612 } catch (RemoteException e) {
1613 throw e.rethrowFromSystemServer();
1614 }
1615 }
1616
1617 /**
1618 * Adjusts the volume of a particular group associated to given id by one step in a direction.
1619 * <p> If the volume group is associated to a stream type, it fallbacks on
1620 * {@link #adjustStreamVolume(int, int, int)} for compatibility reason.
1621 * <p> Call first in prior {@link #getVolumeGroupIdForAttributes(AudioAttributes)} to retrieve
1622 * the volume group id supporting the given {@link AudioAttributes}.
1623 *
Anton Hansson49bee422023-10-11 15:33:25 +00001624 * @param groupId of the audio volume group to consider.
Francois Gaffie32a2b5f2021-11-10 13:45:42 +01001625 * @param direction The direction to adjust the volume. One of
1626 * {@link #ADJUST_LOWER}, {@link #ADJUST_RAISE}, or
1627 * {@link #ADJUST_SAME}.
Jean-Michel Trivi48f99852023-03-31 18:47:58 -07001628 * @param flags
Francois Gaffie32a2b5f2021-11-10 13:45:42 +01001629 * @throws SecurityException if the adjustment triggers a Do Not Disturb change and the caller
1630 * is not granted notification policy access.
1631 */
Jean-Michel Trivi48f99852023-03-31 18:47:58 -07001632 public void adjustVolumeGroupVolume(int groupId, int direction, @PublicVolumeFlags int flags) {
Francois Gaffie32a2b5f2021-11-10 13:45:42 +01001633 IAudioService service = getService();
1634 try {
1635 service.adjustVolumeGroupVolume(groupId, direction, flags,
1636 getContext().getOpPackageName());
1637 } catch (RemoteException e) {
1638 throw e.rethrowFromSystemServer();
1639 }
1640 }
1641
1642 /**
1643 * Get last audible volume of the group associated to given id before it was muted.
1644 * <p> Call first in prior {@link #getVolumeGroupIdForAttributes(AudioAttributes)} to retrieve
1645 * the volume group id supporting the given {@link AudioAttributes}.
1646 *
1647 * @param groupId of the {@link android.media.audiopolicy.AudioVolumeGroup} to consider.
1648 * @return current volume if not muted, volume before muted otherwise.
1649 * @hide
1650 */
1651 @SystemApi
1652 @RequiresPermission("android.permission.QUERY_AUDIO_STATE")
1653 @IntRange(from = 0)
Jean-Michel Trivi23123b62023-02-14 01:22:31 +00001654 public int getLastAudibleVolumeForVolumeGroup(int groupId) {
Francois Gaffie32a2b5f2021-11-10 13:45:42 +01001655 IAudioService service = getService();
1656 try {
Jean-Michel Trivi23123b62023-02-14 01:22:31 +00001657 return service.getLastAudibleVolumeForVolumeGroup(groupId);
Francois Gaffie32a2b5f2021-11-10 13:45:42 +01001658 } catch (RemoteException e) {
1659 throw e.rethrowFromSystemServer();
1660 }
1661 }
1662
1663 /**
1664 * Returns the current mute state for a particular volume group associated to the given id.
1665 * <p> Call first in prior {@link #getVolumeGroupIdForAttributes(AudioAttributes)} to retrieve
1666 * the volume group id supporting the given {@link AudioAttributes}.
1667 *
Anton Hansson49bee422023-10-11 15:33:25 +00001668 * @param groupId of the audio volume group to consider.
1669 * @return The mute state for the given audio volume group id.
Francois Gaffie32a2b5f2021-11-10 13:45:42 +01001670 * @see #adjustVolumeGroupVolume(int, int, int)
1671 */
1672 public boolean isVolumeGroupMuted(int groupId) {
1673 IAudioService service = getService();
1674 try {
1675 return service.isVolumeGroupMuted(groupId);
François Gaffie9c362102018-09-21 17:43:52 +02001676 } catch (RemoteException e) {
1677 throw e.rethrowFromSystemServer();
1678 }
1679 }
1680
1681 /**
Hayden Gomes62812aa2019-12-23 11:40:27 -08001682 * Set the system usages to be supported on this device.
1683 * @param systemUsages array of system usages to support {@link AttributeSystemUsage}
1684 * @hide
1685 */
1686 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00001687 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
Hayden Gomes62812aa2019-12-23 11:40:27 -08001688 public void setSupportedSystemUsages(@NonNull @AttributeSystemUsage int[] systemUsages) {
1689 Objects.requireNonNull(systemUsages, "systemUsages must not be null");
1690 final IAudioService service = getService();
1691 try {
1692 service.setSupportedSystemUsages(systemUsages);
1693 } catch (RemoteException e) {
1694 throw e.rethrowFromSystemServer();
1695 }
1696 }
1697
1698 /**
1699 * Get the system usages supported on this device.
1700 * @return array of supported system usages {@link AttributeSystemUsage}
1701 * @hide
1702 */
1703 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00001704 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
Hayden Gomes62812aa2019-12-23 11:40:27 -08001705 public @NonNull @AttributeSystemUsage int[] getSupportedSystemUsages() {
1706 final IAudioService service = getService();
1707 try {
1708 return service.getSupportedSystemUsages();
1709 } catch (RemoteException e) {
1710 throw e.rethrowFromSystemServer();
1711 }
1712 }
1713
1714 /**
RoboErik4197cb62015-01-21 15:45:32 -08001715 * Solo or unsolo a particular stream.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001716 * <p>
RoboErik4197cb62015-01-21 15:45:32 -08001717 * Do not use. This method has been deprecated and is now a no-op.
1718 * {@link #requestAudioFocus} should be used for exclusive audio playback.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001719 *
1720 * @param streamType The stream to be soloed/unsoloed.
RoboErik4197cb62015-01-21 15:45:32 -08001721 * @param state The required solo state: true for solo ON, false for solo
1722 * OFF
Eric Laurentba207e72014-05-15 17:08:16 -07001723 * @see #isVolumeFixed()
RoboErik4197cb62015-01-21 15:45:32 -08001724 * @deprecated Do not use. If you need exclusive audio playback use
1725 * {@link #requestAudioFocus}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001726 */
RoboErik4197cb62015-01-21 15:45:32 -08001727 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001728 public void setStreamSolo(int streamType, boolean state) {
RoboErik4197cb62015-01-21 15:45:32 -08001729 Log.w(TAG, "setStreamSolo has been deprecated. Do not use.");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001730 }
1731
1732 /**
1733 * Mute or unmute an audio stream.
1734 * <p>
RoboErik4197cb62015-01-21 15:45:32 -08001735 * This method should only be used by applications that replace the
1736 * platform-wide management of audio settings or the main telephony
1737 * application.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001738 * <p>
RoboErik4197cb62015-01-21 15:45:32 -08001739 * This method has no effect if the device implements a fixed volume policy
Eric Laurentba207e72014-05-15 17:08:16 -07001740 * as indicated by {@link #isVolumeFixed()}.
RoboErik4197cb62015-01-21 15:45:32 -08001741 * <p>
1742 * This method was deprecated in API level 22. Prior to API level 22 this
1743 * method had significantly different behavior and should be used carefully.
1744 * The following applies only to pre-22 platforms:
1745 * <ul>
1746 * <li>The mute command is protected against client process death: if a
1747 * process with an active mute request on a stream dies, this stream will be
1748 * unmuted automatically.</li>
1749 * <li>The mute requests for a given stream are cumulative: the AudioManager
1750 * can receive several mute requests from one or more clients and the stream
1751 * will be unmuted only when the same number of unmute requests are
1752 * received.</li>
1753 * <li>For a better user experience, applications MUST unmute a muted stream
1754 * in onPause() and mute is again in onResume() if appropriate.</li>
1755 * </ul>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001756 *
1757 * @param streamType The stream to be muted/unmuted.
RoboErik4197cb62015-01-21 15:45:32 -08001758 * @param state The required mute state: true for mute ON, false for mute
1759 * OFF
Eric Laurentba207e72014-05-15 17:08:16 -07001760 * @see #isVolumeFixed()
RoboErik4197cb62015-01-21 15:45:32 -08001761 * @deprecated Use {@link #adjustStreamVolume(int, int, int)} with
1762 * {@link #ADJUST_MUTE} or {@link #ADJUST_UNMUTE} instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001763 */
RoboErik4197cb62015-01-21 15:45:32 -08001764 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001765 public void setStreamMute(int streamType, boolean state) {
RoboErik4197cb62015-01-21 15:45:32 -08001766 Log.w(TAG, "setStreamMute is deprecated. adjustStreamVolume should be used instead.");
1767 int direction = state ? ADJUST_MUTE : ADJUST_UNMUTE;
1768 if (streamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
1769 adjustSuggestedStreamVolume(direction, streamType, 0);
1770 } else {
1771 adjustStreamVolume(streamType, direction, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001772 }
1773 }
1774
1775 /**
RoboErik4197cb62015-01-21 15:45:32 -08001776 * Returns the current mute state for a particular stream.
Eric Laurent25101b02011-02-02 09:33:30 -08001777 *
RoboErik4197cb62015-01-21 15:45:32 -08001778 * @param streamType The stream to get mute state for.
1779 * @return The mute state for the given stream.
1780 * @see #adjustStreamVolume(int, int, int)
Eric Laurent25101b02011-02-02 09:33:30 -08001781 */
1782 public boolean isStreamMute(int streamType) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001783 final IAudioService service = getService();
Eric Laurent25101b02011-02-02 09:33:30 -08001784 try {
John Spurlockee5ad722015-03-03 16:17:21 -05001785 return service.isStreamMute(streamType);
Eric Laurent25101b02011-02-02 09:33:30 -08001786 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001787 throw e.rethrowFromSystemServer();
Eric Laurent25101b02011-02-02 09:33:30 -08001788 }
1789 }
1790
1791 /**
Mike Lockwoodce952c82011-11-14 10:47:42 -08001792 * get master mute state.
1793 *
1794 * @hide
1795 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01001796 @UnsupportedAppUsage
Mike Lockwoodce952c82011-11-14 10:47:42 -08001797 public boolean isMasterMute() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001798 final IAudioService service = getService();
Mike Lockwoodce952c82011-11-14 10:47:42 -08001799 try {
1800 return service.isMasterMute();
1801 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001802 throw e.rethrowFromSystemServer();
Mike Lockwoodce952c82011-11-14 10:47:42 -08001803 }
1804 }
1805
1806 /**
Eric Laurent402f7f22011-02-04 12:30:32 -08001807 * forces the stream controlled by hard volume keys
1808 * specifying streamType == -1 releases control to the
1809 * logic.
1810 *
1811 * @hide
1812 */
Jean-Michel Trivic4557822023-01-23 18:19:52 +00001813 @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
Mathew Inwood31a792a2018-08-17 08:54:26 +01001814 @UnsupportedAppUsage
Eric Laurent402f7f22011-02-04 12:30:32 -08001815 public void forceVolumeControlStream(int streamType) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001816 final IAudioService service = getService();
Eric Laurent45c90ce2012-04-24 18:44:22 -07001817 try {
1818 service.forceVolumeControlStream(streamType, mICallBack);
1819 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001820 throw e.rethrowFromSystemServer();
Eric Laurent45c90ce2012-04-24 18:44:22 -07001821 }
Eric Laurent402f7f22011-02-04 12:30:32 -08001822 }
1823
1824 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001825 * Returns whether a particular type should vibrate according to user
1826 * settings and the current ringer mode.
1827 * <p>
1828 * This shouldn't be needed by most clients that use notifications to
1829 * vibrate. The notification manager will not vibrate if the policy doesn't
1830 * allow it, so the client should always set a vibrate pattern and let the
1831 * notification manager control whether or not to actually vibrate.
1832 *
1833 * @param vibrateType The type of vibrate. One of
1834 * {@link #VIBRATE_TYPE_NOTIFICATION} or
1835 * {@link #VIBRATE_TYPE_RINGER}.
1836 * @return Whether the type should vibrate at the instant this method is
1837 * called.
1838 * @see #setVibrateSetting(int, int)
1839 * @see #getVibrateSetting(int)
Eric Laurentcd1cd732012-05-01 11:23:07 -07001840 * @deprecated Applications should maintain their own vibrate policy based on
1841 * current ringer mode that can be queried via {@link #getRingerMode()}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001842 */
1843 public boolean shouldVibrate(int vibrateType) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001844 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001845 try {
1846 return service.shouldVibrate(vibrateType);
1847 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001848 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001849 }
1850 }
1851
1852 /**
1853 * Returns whether the user's vibrate setting for a vibrate type.
1854 * <p>
1855 * This shouldn't be needed by most clients that want to vibrate, instead
1856 * see {@link #shouldVibrate(int)}.
1857 *
1858 * @param vibrateType The type of vibrate. One of
1859 * {@link #VIBRATE_TYPE_NOTIFICATION} or
1860 * {@link #VIBRATE_TYPE_RINGER}.
1861 * @return The vibrate setting, one of {@link #VIBRATE_SETTING_ON},
1862 * {@link #VIBRATE_SETTING_OFF}, or
1863 * {@link #VIBRATE_SETTING_ONLY_SILENT}.
1864 * @see #setVibrateSetting(int, int)
1865 * @see #shouldVibrate(int)
Eric Laurentcd1cd732012-05-01 11:23:07 -07001866 * @deprecated Applications should maintain their own vibrate policy based on
1867 * current ringer mode that can be queried via {@link #getRingerMode()}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001868 */
1869 public int getVibrateSetting(int vibrateType) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001870 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001871 try {
1872 return service.getVibrateSetting(vibrateType);
1873 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001874 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001875 }
1876 }
1877
1878 /**
1879 * Sets the setting for when the vibrate type should vibrate.
Jean-Michel Trivifccb25d2009-09-15 16:06:10 -07001880 * <p>
1881 * This method should only be used by applications that replace the platform-wide
1882 * management of audio settings or the main telephony application.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001883 *
1884 * @param vibrateType The type of vibrate. One of
1885 * {@link #VIBRATE_TYPE_NOTIFICATION} or
1886 * {@link #VIBRATE_TYPE_RINGER}.
1887 * @param vibrateSetting The vibrate setting, one of
1888 * {@link #VIBRATE_SETTING_ON},
1889 * {@link #VIBRATE_SETTING_OFF}, or
1890 * {@link #VIBRATE_SETTING_ONLY_SILENT}.
1891 * @see #getVibrateSetting(int)
1892 * @see #shouldVibrate(int)
Eric Laurentcd1cd732012-05-01 11:23:07 -07001893 * @deprecated Applications should maintain their own vibrate policy based on
1894 * current ringer mode that can be queried via {@link #getRingerMode()}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001895 */
1896 public void setVibrateSetting(int vibrateType, int vibrateSetting) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001897 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001898 try {
1899 service.setVibrateSetting(vibrateType, vibrateSetting);
1900 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001901 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001902 }
1903 }
1904
1905 /**
1906 * Sets the speakerphone on or off.
Jean-Michel Trivifccb25d2009-09-15 16:06:10 -07001907 * <p>
1908 * This method should only be used by applications that replace the platform-wide
1909 * management of audio settings or the main telephony application.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001910 *
1911 * @param on set <var>true</var> to turn on speakerphone;
1912 * <var>false</var> to turn it off
Eric Laurentf23f1b72022-02-18 10:57:54 +01001913 * @deprecated Use {@link AudioManager#setCommunicationDevice(AudioDeviceInfo)} or
1914 * {@link AudioManager#clearCommunicationDevice()} instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001915 */
Eric Laurentf23f1b72022-02-18 10:57:54 +01001916 @Deprecated public void setSpeakerphoneOn(boolean on) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001917 final IAudioService service = getService();
Eric Laurentc42ac9d2009-07-29 08:53:03 -07001918 try {
Eric Laurent3aad0ad2020-05-14 12:45:18 -07001919 service.setSpeakerphoneOn(mICallBack, on);
Eric Laurentc42ac9d2009-07-29 08:53:03 -07001920 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001921 throw e.rethrowFromSystemServer();
Eric Laurenta553c252009-07-17 12:17:14 -07001922 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001923 }
1924
1925 /**
1926 * Checks whether the speakerphone is on or off.
1927 *
1928 * @return true if speakerphone is on, false if it's off
Eric Laurentf23f1b72022-02-18 10:57:54 +01001929 * @deprecated Use {@link AudioManager#getCommunicationDevice()} instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001930 */
Eric Laurentf23f1b72022-02-18 10:57:54 +01001931 @Deprecated public boolean isSpeakerphoneOn() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001932 final IAudioService service = getService();
Eric Laurentc42ac9d2009-07-29 08:53:03 -07001933 try {
1934 return service.isSpeakerphoneOn();
1935 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001936 throw e.rethrowFromSystemServer();
Eric Laurenta553c252009-07-17 12:17:14 -07001937 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001938 }
1939
Kevin Rocard7919c2a2019-03-21 10:28:01 -07001940 /**
Kevin Rocarddb0ff412019-05-02 17:55:35 -07001941 * Specifies whether the audio played by this app may or may not be captured by other apps or
Kevin Rocard654b3cb2019-04-03 16:51:11 -07001942 * the system.
Kevin Rocard7919c2a2019-03-21 10:28:01 -07001943 *
1944 * The default is {@link AudioAttributes#ALLOW_CAPTURE_BY_ALL}.
1945 *
Kevin Rocard654b3cb2019-04-03 16:51:11 -07001946 * There are multiple ways to set this policy:
Kevin Rocarddb0ff412019-05-02 17:55:35 -07001947 * <ul>
1948 * <li> for each track independently, see
1949 * {@link AudioAttributes.Builder#setAllowedCapturePolicy(int)} </li>
1950 * <li> application-wide at runtime, with this method </li>
1951 * <li> application-wide at build time, see {@code allowAudioPlaybackCapture} in the application
1952 * manifest. </li>
1953 * </ul>
Kevin Rocard654b3cb2019-04-03 16:51:11 -07001954 * The most restrictive policy is always applied.
1955 *
Kevin Rocarddb0ff412019-05-02 17:55:35 -07001956 * See {@link AudioPlaybackCaptureConfiguration} for more details on
Kevin Rocard654b3cb2019-04-03 16:51:11 -07001957 * which audio signals can be captured.
Kevin Rocard7919c2a2019-03-21 10:28:01 -07001958 *
1959 * @param capturePolicy one of
1960 * {@link AudioAttributes#ALLOW_CAPTURE_BY_ALL},
1961 * {@link AudioAttributes#ALLOW_CAPTURE_BY_SYSTEM},
1962 * {@link AudioAttributes#ALLOW_CAPTURE_BY_NONE}.
jiabinb33f3692019-12-23 13:09:58 -08001963 * @throws RuntimeException if the argument is not a valid value.
Kevin Rocard7919c2a2019-03-21 10:28:01 -07001964 */
1965 public void setAllowedCapturePolicy(@AudioAttributes.CapturePolicy int capturePolicy) {
Kevin Rocard7919c2a2019-03-21 10:28:01 -07001966 // TODO: also pass the package in case multiple packages have the same UID
jiabinb33f3692019-12-23 13:09:58 -08001967 final IAudioService service = getService();
1968 try {
1969 int result = service.setAllowedCapturePolicy(capturePolicy);
1970 if (result != AudioSystem.AUDIO_STATUS_OK) {
1971 Log.e(TAG, "Could not setAllowedCapturePolicy: " + result);
1972 return;
1973 }
1974 } catch (RemoteException e) {
1975 throw e.rethrowFromSystemServer();
Kevin Rocard7919c2a2019-03-21 10:28:01 -07001976 }
Kevin Rocard019f60d2019-04-09 16:25:26 -07001977 }
1978
Kevin Rocard019f60d2019-04-09 16:25:26 -07001979 /**
1980 * Return the capture policy.
1981 * @return the capture policy set by {@link #setAllowedCapturePolicy(int)} or
1982 * the default if it was not called.
1983 */
1984 @AudioAttributes.CapturePolicy
1985 public int getAllowedCapturePolicy() {
jiabinb33f3692019-12-23 13:09:58 -08001986 int result = AudioAttributes.ALLOW_CAPTURE_BY_ALL;
1987 try {
1988 result = getService().getAllowedCapturePolicy();
1989 } catch (RemoteException e) {
1990 Log.e(TAG, "Failed to query allowed capture policy: " + e);
1991 }
1992 return result;
Kevin Rocard7919c2a2019-03-21 10:28:01 -07001993 }
1994
Eric Laurent3def1ee2010-03-17 23:26:26 -07001995 //====================================================================
Jean-Michel Trivi21cd5412019-10-30 08:16:51 -07001996 // Audio Product Strategy routing
1997
1998 /**
1999 * @hide
2000 * Set the preferred device for a given strategy, i.e. the audio routing to be used by
2001 * this audio strategy. Note that the device may not be available at the time the preferred
2002 * device is set, but it will be used once made available.
2003 * <p>Use {@link #removePreferredDeviceForStrategy(AudioProductStrategy)} to cancel setting
2004 * this preference for this strategy.</p>
2005 * @param strategy the audio strategy whose routing will be affected
2006 * @param device the audio device to route to when available
2007 * @return true if the operation was successful, false otherwise
2008 */
2009 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00002010 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
Jean-Michel Trivi21cd5412019-10-30 08:16:51 -07002011 public boolean setPreferredDeviceForStrategy(@NonNull AudioProductStrategy strategy,
Jean-Michel Trivi0e87bca2020-02-18 14:30:29 -08002012 @NonNull AudioDeviceAttributes device) {
jiabinf40141d2020-08-07 17:27:48 -07002013 return setPreferredDevicesForStrategy(strategy, Arrays.asList(device));
Jean-Michel Trivi21cd5412019-10-30 08:16:51 -07002014 }
2015
2016 /**
2017 * @hide
jiabinf40141d2020-08-07 17:27:48 -07002018 * Removes the preferred audio device(s) previously set with
2019 * {@link #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAttributes)} or
2020 * {@link #setPreferredDevicesForStrategy(AudioProductStrategy, List<AudioDeviceAttributes>)}.
Jean-Michel Trivi21cd5412019-10-30 08:16:51 -07002021 * @param strategy the audio strategy whose routing will be affected
2022 * @return true if the operation was successful, false otherwise (invalid strategy, or no
2023 * device set for example)
2024 */
2025 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00002026 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
Jean-Michel Trivi21cd5412019-10-30 08:16:51 -07002027 public boolean removePreferredDeviceForStrategy(@NonNull AudioProductStrategy strategy) {
2028 Objects.requireNonNull(strategy);
2029 try {
2030 final int status =
jiabinf40141d2020-08-07 17:27:48 -07002031 getService().removePreferredDevicesForStrategy(strategy.getId());
Jean-Michel Trivi21cd5412019-10-30 08:16:51 -07002032 return status == AudioSystem.SUCCESS;
2033 } catch (RemoteException e) {
2034 throw e.rethrowFromSystemServer();
2035 }
2036 }
2037
2038 /**
2039 * @hide
2040 * Return the preferred device for an audio strategy, previously set with
jiabinf40141d2020-08-07 17:27:48 -07002041 * {@link #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAttributes)} or
2042 * {@link #setPreferredDevicesForStrategy(AudioProductStrategy, List<AudioDeviceAttributes>)}
2043 * @param strategy the strategy to query
2044 * @return the preferred device for that strategy, if multiple devices are set as preferred
2045 * devices, the first one in the list will be returned. Null will be returned if none was
2046 * ever set or if the strategy is invalid
2047 */
2048 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00002049 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
jiabinf40141d2020-08-07 17:27:48 -07002050 @Nullable
2051 public AudioDeviceAttributes getPreferredDeviceForStrategy(
2052 @NonNull AudioProductStrategy strategy) {
2053 List<AudioDeviceAttributes> devices = getPreferredDevicesForStrategy(strategy);
2054 return devices.isEmpty() ? null : devices.get(0);
2055 }
2056
2057 /**
2058 * @hide
2059 * Set the preferred devices for a given strategy, i.e. the audio routing to be used by
2060 * this audio strategy. Note that the devices may not be available at the time the preferred
2061 * devices is set, but it will be used once made available.
2062 * <p>Use {@link #removePreferredDeviceForStrategy(AudioProductStrategy)} to cancel setting
2063 * this preference for this strategy.</p>
2064 * Note that the list of devices is not a list ranked by preference, but a list of one or more
2065 * devices used simultaneously to output the same audio signal.
2066 * @param strategy the audio strategy whose routing will be affected
2067 * @param devices a non-empty list of the audio devices to route to when available
2068 * @return true if the operation was successful, false otherwise
2069 */
2070 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00002071 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
jiabinf40141d2020-08-07 17:27:48 -07002072 public boolean setPreferredDevicesForStrategy(@NonNull AudioProductStrategy strategy,
2073 @NonNull List<AudioDeviceAttributes> devices) {
2074 Objects.requireNonNull(strategy);
2075 Objects.requireNonNull(devices);
2076 if (devices.isEmpty()) {
2077 throw new IllegalArgumentException(
2078 "Tried to set preferred devices for strategy with a empty list");
2079 }
2080 for (AudioDeviceAttributes device : devices) {
2081 Objects.requireNonNull(device);
2082 }
2083 try {
2084 final int status =
2085 getService().setPreferredDevicesForStrategy(strategy.getId(), devices);
2086 return status == AudioSystem.SUCCESS;
2087 } catch (RemoteException e) {
2088 throw e.rethrowFromSystemServer();
2089 }
2090 }
2091
2092 /**
2093 * @hide
2094 * Return the preferred devices for an audio strategy, previously set with
Jean-Michel Trivi0e87bca2020-02-18 14:30:29 -08002095 * {@link #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAttributes)}
jiabinf40141d2020-08-07 17:27:48 -07002096 * {@link #setPreferredDevicesForStrategy(AudioProductStrategy, List<AudioDeviceAttributes>)}
Jean-Michel Trivi21cd5412019-10-30 08:16:51 -07002097 * @param strategy the strategy to query
Paul Wang8ee29602022-12-22 03:40:19 +00002098 * @return list of the preferred devices for that strategy
Jean-Michel Trivi21cd5412019-10-30 08:16:51 -07002099 */
2100 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00002101 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
jiabinf40141d2020-08-07 17:27:48 -07002102 @NonNull
2103 public List<AudioDeviceAttributes> getPreferredDevicesForStrategy(
Jean-Michel Trivi21cd5412019-10-30 08:16:51 -07002104 @NonNull AudioProductStrategy strategy) {
2105 Objects.requireNonNull(strategy);
2106 try {
jiabinf40141d2020-08-07 17:27:48 -07002107 return getService().getPreferredDevicesForStrategy(strategy.getId());
Jean-Michel Trivi21cd5412019-10-30 08:16:51 -07002108 } catch (RemoteException e) {
2109 throw e.rethrowFromSystemServer();
2110 }
2111 }
2112
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08002113 /**
2114 * @hide
Paul Wangee4774a2022-08-23 09:41:03 +00002115 * Set a device as non-default for a given strategy, i.e. the audio routing to be avoided by
2116 * this audio strategy.
2117 * <p>Use
2118 * {@link #removeDeviceAsNonDefaultForStrategy(AudioProductStrategy, AudioDeviceAttributes)}
2119 * to cancel setting this preference for this strategy.</p>
2120 * @param strategy the audio strategy whose routing will be affected
2121 * @param device the audio device to not route to when available
2122 * @return true if the operation was successful, false otherwise
2123 */
2124 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00002125 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
Paul Wangee4774a2022-08-23 09:41:03 +00002126 public boolean setDeviceAsNonDefaultForStrategy(@NonNull AudioProductStrategy strategy,
2127 @NonNull AudioDeviceAttributes device) {
2128 Objects.requireNonNull(strategy);
2129 Objects.requireNonNull(device);
2130 try {
2131 final int status =
2132 getService().setDeviceAsNonDefaultForStrategy(strategy.getId(), device);
2133 return status == AudioSystem.SUCCESS;
2134 } catch (RemoteException e) {
2135 throw e.rethrowFromSystemServer();
2136 }
2137 }
2138
2139 /**
2140 * @hide
2141 * Removes the audio device(s) from the non-default device list previously set with
2142 * {@link #setDeviceAsNonDefaultForStrategy(AudioProductStrategy, AudioDeviceAttributes)}
2143 * @param strategy the audio strategy whose routing will be affected
2144 * @param device the audio device to remove from the non-default device list
2145 * @return true if the operation was successful, false otherwise (invalid strategy, or no
2146 * device set for example)
2147 */
2148 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00002149 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
Paul Wangee4774a2022-08-23 09:41:03 +00002150 public boolean removeDeviceAsNonDefaultForStrategy(@NonNull AudioProductStrategy strategy,
2151 @NonNull AudioDeviceAttributes device) {
2152 Objects.requireNonNull(strategy);
2153 Objects.requireNonNull(device);
2154 try {
2155 final int status =
2156 getService().removeDeviceAsNonDefaultForStrategy(strategy.getId(), device);
2157 return status == AudioSystem.SUCCESS;
2158 } catch (RemoteException e) {
2159 throw e.rethrowFromSystemServer();
2160 }
2161 }
2162
2163 /**
2164 * @hide
2165 * Gets the audio device(s) from the non-default device list previously set with
2166 * {@link #setDeviceAsNonDefaultForStrategy(AudioProductStrategy, AudioDeviceAttributes)}
2167 * @param strategy the audio strategy to query
2168 * @return list of non-default devices for the strategy
2169 */
2170 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00002171 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
Paul Wangee4774a2022-08-23 09:41:03 +00002172 @NonNull
2173 public List<AudioDeviceAttributes> getNonDefaultDevicesForStrategy(
2174 @NonNull AudioProductStrategy strategy) {
2175 Objects.requireNonNull(strategy);
2176 try {
2177 return getService().getNonDefaultDevicesForStrategy(strategy.getId());
2178 } catch (RemoteException e) {
2179 throw e.rethrowFromSystemServer();
2180 }
2181 }
2182
2183 /**
2184 * @hide
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08002185 * Interface to be notified of changes in the preferred audio device set for a given audio
2186 * strategy.
Jean-Michel Trivicf9c5d32020-02-20 10:45:35 -08002187 * <p>Note that this listener will only be invoked whenever
2188 * {@link #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAttributes)} or
jiabinf40141d2020-08-07 17:27:48 -07002189 * {@link #setPreferredDevicesForStrategy(AudioProductStrategy, List<AudioDeviceAttributes>)}
Jean-Michel Trivicf9c5d32020-02-20 10:45:35 -08002190 * {@link #removePreferredDeviceForStrategy(AudioProductStrategy)} causes a change in
2191 * preferred device. It will not be invoked directly after registration with
2192 * {@link #addOnPreferredDeviceForStrategyChangedListener(Executor, OnPreferredDeviceForStrategyChangedListener)}
2193 * to indicate which strategies had preferred devices at the time of registration.</p>
Jean-Michel Trivi0e87bca2020-02-18 14:30:29 -08002194 * @see #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAttributes)
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08002195 * @see #removePreferredDeviceForStrategy(AudioProductStrategy)
2196 * @see #getPreferredDeviceForStrategy(AudioProductStrategy)
jiabinf40141d2020-08-07 17:27:48 -07002197 * @deprecated use #OnPreferredDevicesForStrategyChangedListener
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08002198 */
2199 @SystemApi
jiabinf40141d2020-08-07 17:27:48 -07002200 @Deprecated
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08002201 public interface OnPreferredDeviceForStrategyChangedListener {
2202 /**
2203 * Called on the listener to indicate that the preferred audio device for the given
2204 * strategy has changed.
2205 * @param strategy the {@link AudioProductStrategy} whose preferred device changed
2206 * @param device <code>null</code> if the preferred device was removed, or the newly set
2207 * preferred audio device
2208 */
2209 void onPreferredDeviceForStrategyChanged(@NonNull AudioProductStrategy strategy,
Jean-Michel Trivi0e87bca2020-02-18 14:30:29 -08002210 @Nullable AudioDeviceAttributes device);
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08002211 }
2212
2213 /**
2214 * @hide
jiabinf40141d2020-08-07 17:27:48 -07002215 * Interface to be notified of changes in the preferred audio devices set for a given audio
2216 * strategy.
2217 * <p>Note that this listener will only be invoked whenever
Paul Wangee4774a2022-08-23 09:41:03 +00002218 * {@link #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAttributes)},
2219 * {@link #setPreferredDevicesForStrategy(AudioProductStrategy, List<AudioDeviceAttributes>)},
2220 * {@link #setDeviceAsNonDefaultForStrategy(AudioProductStrategy, AudioDeviceAttributes)},
2221 * {@link #removeDeviceAsNonDefaultForStrategy(AudioProductStrategy, AudioDeviceAttributes)}
2222 * or {@link #removePreferredDeviceForStrategy(AudioProductStrategy)} causes a change in
jiabinf40141d2020-08-07 17:27:48 -07002223 * preferred device(s). It will not be invoked directly after registration with
2224 * {@link #addOnPreferredDevicesForStrategyChangedListener(
2225 * Executor, OnPreferredDevicesForStrategyChangedListener)}
2226 * to indicate which strategies had preferred devices at the time of registration.</p>
2227 * @see #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAttributes)
2228 * @see #setPreferredDevicesForStrategy(AudioProductStrategy, List)
2229 * @see #removePreferredDeviceForStrategy(AudioProductStrategy)
jiabinf40141d2020-08-07 17:27:48 -07002230 * @see #getPreferredDevicesForStrategy(AudioProductStrategy)
2231 */
2232 @SystemApi
2233 public interface OnPreferredDevicesForStrategyChangedListener {
2234 /**
2235 * Called on the listener to indicate that the preferred audio devices for the given
2236 * strategy has changed.
2237 * @param strategy the {@link AudioProductStrategy} whose preferred device changed
2238 * @param devices a list of newly set preferred audio devices
2239 */
2240 void onPreferredDevicesForStrategyChanged(@NonNull AudioProductStrategy strategy,
2241 @NonNull List<AudioDeviceAttributes> devices);
2242 }
2243
2244 /**
2245 * @hide
2246 * Adds a listener for being notified of changes to the strategy-preferred audio device.
2247 * @param executor
2248 * @param listener
2249 * @throws SecurityException if the caller doesn't hold the required permission
2250 * @deprecated use {@link #addOnPreferredDevicesForStrategyChangedListener(
2251 * Executor, AudioManager.OnPreferredDevicesForStrategyChangedListener)} instead
2252 */
2253 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00002254 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
jiabinf40141d2020-08-07 17:27:48 -07002255 @Deprecated
2256 public void addOnPreferredDeviceForStrategyChangedListener(
2257 @NonNull @CallbackExecutor Executor executor,
2258 @NonNull OnPreferredDeviceForStrategyChangedListener listener)
2259 throws SecurityException {
2260 // No-op, the method is deprecated.
2261 }
2262
2263 /**
2264 * @hide
2265 * Removes a previously added listener of changes to the strategy-preferred audio device.
2266 * @param listener
2267 * @deprecated use {@link #removeOnPreferredDevicesForStrategyChangedListener(
2268 * AudioManager.OnPreferredDevicesForStrategyChangedListener)} instead
2269 */
2270 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00002271 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
jiabinf40141d2020-08-07 17:27:48 -07002272 @Deprecated
2273 public void removeOnPreferredDeviceForStrategyChangedListener(
2274 @NonNull OnPreferredDeviceForStrategyChangedListener listener) {
2275 // No-op, the method is deprecated.
2276 }
2277
2278 /**
2279 * @hide
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08002280 * Adds a listener for being notified of changes to the strategy-preferred audio device.
2281 * @param executor
2282 * @param listener
2283 * @throws SecurityException if the caller doesn't hold the required permission
2284 */
2285 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00002286 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
jiabinf40141d2020-08-07 17:27:48 -07002287 public void addOnPreferredDevicesForStrategyChangedListener(
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08002288 @NonNull @CallbackExecutor Executor executor,
jiabinf40141d2020-08-07 17:27:48 -07002289 @NonNull OnPreferredDevicesForStrategyChangedListener listener)
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08002290 throws SecurityException {
2291 Objects.requireNonNull(executor);
2292 Objects.requireNonNull(listener);
Paul Wang8ee29602022-12-22 03:40:19 +00002293 mPrefDevListenerMgr.addListener(
2294 executor, listener, "addOnPreferredDevicesForStrategyChangedListener",
2295 () -> new StrategyPreferredDevicesDispatcherStub());
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08002296 }
2297
2298 /**
2299 * @hide
2300 * Removes a previously added listener of changes to the strategy-preferred audio device.
2301 * @param listener
2302 */
2303 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00002304 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
jiabinf40141d2020-08-07 17:27:48 -07002305 public void removeOnPreferredDevicesForStrategyChangedListener(
2306 @NonNull OnPreferredDevicesForStrategyChangedListener listener) {
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08002307 Objects.requireNonNull(listener);
Paul Wang8ee29602022-12-22 03:40:19 +00002308 mPrefDevListenerMgr.removeListener(
2309 listener, "removeOnPreferredDevicesForStrategyChangedListener");
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08002310 }
2311
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08002312 /**
Paul Wangee4774a2022-08-23 09:41:03 +00002313 * @hide
2314 * Interface to be notified of changes in the non-default audio devices set for a given audio
2315 * strategy.
2316 * <p>Note that this listener will only be invoked whenever
2317 * {@link #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAttributes)},
2318 * {@link #setPreferredDevicesForStrategy(AudioProductStrategy, List<AudioDeviceAttributes>)},
2319 * {@link #setDeviceAsNonDefaultForStrategy(AudioProductStrategy, AudioDeviceAttributes)},
2320 * {@link #removeDeviceAsNonDefaultForStrategy(AudioProductStrategy, AudioDeviceAttributes)}
2321 * or {@link #removePreferredDeviceForStrategy(AudioProductStrategy)} causes a change in
2322 * non-default device(s). It will not be invoked directly after registration with
2323 * {@link #addOnNonDefaultDevicesForStrategyChangedListener(
2324 * Executor, OnNonDefaultDevicesForStrategyChangedListener)}
2325 * to indicate which strategies had preferred devices at the time of registration.</p>
2326 * @see #setDeviceAsNonDefaultForStrategy(AudioProductStrategy, AudioDeviceAttributes)
2327 * @see #removeDeviceAsNonDefaultForStrategy(AudioProductStrategy, AudioDeviceAttributes)
2328 */
2329 @SystemApi
2330 public interface OnNonDefaultDevicesForStrategyChangedListener {
2331 /**
2332 * Called on the listener to indicate that the non-default audio devices for the given
2333 * strategy has changed.
2334 * @param strategy the {@link AudioProductStrategy} whose non-default device changed
2335 * @param devices a list of newly set non-default audio devices
2336 */
2337 void onNonDefaultDevicesForStrategyChanged(@NonNull AudioProductStrategy strategy,
2338 @NonNull List<AudioDeviceAttributes> devices);
2339 }
2340
2341 /**
2342 * @hide
2343 * Adds a listener for being notified of changes to the non-default audio devices for
2344 * strategies.
2345 * @param executor
2346 * @param listener
2347 * @throws SecurityException if the caller doesn't hold the required permission
2348 */
2349 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00002350 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
Paul Wangee4774a2022-08-23 09:41:03 +00002351 public void addOnNonDefaultDevicesForStrategyChangedListener(
2352 @NonNull @CallbackExecutor Executor executor,
2353 @NonNull OnNonDefaultDevicesForStrategyChangedListener listener)
2354 throws SecurityException {
2355 Objects.requireNonNull(executor);
2356 Objects.requireNonNull(listener);
2357
2358 mNonDefDevListenerMgr.addListener(
2359 executor, listener, "addOnNonDefaultDevicesForStrategyChangedListener",
2360 () -> new StrategyNonDefaultDevicesDispatcherStub());
2361 }
2362
2363 /**
2364 * @hide
2365 * Removes a previously added listener of changes to the non-default audio device for
2366 * strategies.
2367 * @param listener
2368 */
2369 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00002370 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
Paul Wangee4774a2022-08-23 09:41:03 +00002371 public void removeOnNonDefaultDevicesForStrategyChangedListener(
2372 @NonNull OnNonDefaultDevicesForStrategyChangedListener listener) {
2373 Objects.requireNonNull(listener);
2374 mNonDefDevListenerMgr.removeListener(
2375 listener, "removeOnNonDefaultDevicesForStrategyChangedListener");
2376 }
2377
2378 /**
Paul Wang8ee29602022-12-22 03:40:19 +00002379 * Manages the OnPreferredDevicesForStrategyChangedListener listeners and the
2380 * StrategyPreferredDevicesDispatcherStub
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08002381 */
Paul Wang8ee29602022-12-22 03:40:19 +00002382 private final CallbackUtil.LazyListenerManager<OnPreferredDevicesForStrategyChangedListener>
2383 mPrefDevListenerMgr = new CallbackUtil.LazyListenerManager();
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08002384
Paul Wangee4774a2022-08-23 09:41:03 +00002385 /**
2386 * Manages the OnNonDefaultDevicesForStrategyChangedListener listeners and the
2387 * StrategyNonDefaultDevicesDispatcherStub
2388 */
2389 private final CallbackUtil.LazyListenerManager<OnNonDefaultDevicesForStrategyChangedListener>
2390 mNonDefDevListenerMgr = new CallbackUtil.LazyListenerManager();
2391
jiabinf40141d2020-08-07 17:27:48 -07002392 private final class StrategyPreferredDevicesDispatcherStub
Paul Wang8ee29602022-12-22 03:40:19 +00002393 extends IStrategyPreferredDevicesDispatcher.Stub
2394 implements CallbackUtil.DispatcherStub {
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08002395
2396 @Override
jiabinf40141d2020-08-07 17:27:48 -07002397 public void dispatchPrefDevicesChanged(int strategyId,
2398 @NonNull List<AudioDeviceAttributes> devices) {
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08002399 final AudioProductStrategy strategy =
2400 AudioProductStrategy.getAudioProductStrategyWithId(strategyId);
Paul Wang8ee29602022-12-22 03:40:19 +00002401
2402 mPrefDevListenerMgr.callListeners(
2403 (listener) -> listener.onPreferredDevicesForStrategyChanged(strategy, devices));
2404 }
2405
2406 @Override
2407 public void register(boolean register) {
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08002408 try {
Paul Wang8ee29602022-12-22 03:40:19 +00002409 if (register) {
2410 getService().registerStrategyPreferredDevicesDispatcher(this);
2411 } else {
2412 getService().unregisterStrategyPreferredDevicesDispatcher(this);
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08002413 }
Paul Wang8ee29602022-12-22 03:40:19 +00002414 } catch (RemoteException e) {
2415 e.rethrowFromSystemServer();
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08002416 }
2417 }
2418 }
2419
Paul Wangee4774a2022-08-23 09:41:03 +00002420 private final class StrategyNonDefaultDevicesDispatcherStub
2421 extends IStrategyNonDefaultDevicesDispatcher.Stub
2422 implements CallbackUtil.DispatcherStub {
2423
2424 @Override
2425 public void dispatchNonDefDevicesChanged(int strategyId,
2426 @NonNull List<AudioDeviceAttributes> devices) {
2427 final AudioProductStrategy strategy =
2428 AudioProductStrategy.getAudioProductStrategyWithId(strategyId);
2429
2430 mNonDefDevListenerMgr.callListeners(
2431 (listener) -> listener.onNonDefaultDevicesForStrategyChanged(
2432 strategy, devices));
2433 }
2434
2435 @Override
2436 public void register(boolean register) {
2437 try {
2438 if (register) {
2439 getService().registerStrategyNonDefaultDevicesDispatcher(this);
2440 } else {
2441 getService().unregisterStrategyNonDefaultDevicesDispatcher(this);
2442 }
2443 } catch (RemoteException e) {
2444 e.rethrowFromSystemServer();
2445 }
2446 }
2447 }
2448
Jean-Michel Trivi21cd5412019-10-30 08:16:51 -07002449 //====================================================================
Jiabin Huangb55305f2020-09-03 17:54:16 +00002450 // Audio Capture Preset routing
2451
2452 /**
2453 * @hide
2454 * Set the preferred device for a given capture preset, i.e. the audio routing to be used by
2455 * this capture preset. Note that the device may not be available at the time the preferred
2456 * device is set, but it will be used once made available.
2457 * <p>Use {@link #clearPreferredDevicesForCapturePreset(int)} to cancel setting this preference
2458 * for this capture preset.</p>
2459 * @param capturePreset the audio capture preset whose routing will be affected
2460 * @param device the audio device to route to when available
2461 * @return true if the operation was successful, false otherwise
2462 */
2463 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00002464 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
jiabin958faf92021-03-12 20:00:05 +00002465 public boolean setPreferredDeviceForCapturePreset(@MediaRecorder.SystemSource int capturePreset,
Jiabin Huangb55305f2020-09-03 17:54:16 +00002466 @NonNull AudioDeviceAttributes device) {
2467 return setPreferredDevicesForCapturePreset(capturePreset, Arrays.asList(device));
2468 }
2469
2470 /**
2471 * @hide
2472 * Remove all the preferred audio devices previously set
2473 * @param capturePreset the audio capture preset whose routing will be affected
2474 * @return true if the operation was successful, false otherwise (invalid capture preset, or no
2475 * device set for example)
2476 */
2477 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00002478 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
jiabin958faf92021-03-12 20:00:05 +00002479 public boolean clearPreferredDevicesForCapturePreset(
2480 @MediaRecorder.SystemSource int capturePreset) {
Jiabin Huangb55305f2020-09-03 17:54:16 +00002481 if (!MediaRecorder.isValidAudioSource(capturePreset)) {
2482 return false;
2483 }
2484 try {
2485 final int status = getService().clearPreferredDevicesForCapturePreset(capturePreset);
2486 return status == AudioSystem.SUCCESS;
2487 } catch (RemoteException e) {
2488 throw e.rethrowFromSystemServer();
2489 }
2490 }
2491
2492 /**
2493 * @hide
2494 * Return the preferred devices for an audio capture preset, previously set with
2495 * {@link #setPreferredDeviceForCapturePreset(int, AudioDeviceAttributes)}
2496 * @param capturePreset the capture preset to query
2497 * @return a list that contains preferred devices for that capture preset.
2498 */
2499 @NonNull
2500 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00002501 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
jiabin958faf92021-03-12 20:00:05 +00002502 public List<AudioDeviceAttributes> getPreferredDevicesForCapturePreset(
2503 @MediaRecorder.SystemSource int capturePreset) {
Jiabin Huangb55305f2020-09-03 17:54:16 +00002504 if (!MediaRecorder.isValidAudioSource(capturePreset)) {
2505 return new ArrayList<AudioDeviceAttributes>();
2506 }
2507 try {
2508 return getService().getPreferredDevicesForCapturePreset(capturePreset);
2509 } catch (RemoteException e) {
2510 throw e.rethrowFromSystemServer();
2511 }
2512 }
2513
2514 private boolean setPreferredDevicesForCapturePreset(
jiabin958faf92021-03-12 20:00:05 +00002515 @MediaRecorder.SystemSource int capturePreset,
2516 @NonNull List<AudioDeviceAttributes> devices) {
Jiabin Huangb55305f2020-09-03 17:54:16 +00002517 Objects.requireNonNull(devices);
2518 if (!MediaRecorder.isValidAudioSource(capturePreset)) {
2519 return false;
2520 }
2521 if (devices.size() != 1) {
2522 throw new IllegalArgumentException(
2523 "Only support setting one preferred devices for capture preset");
2524 }
2525 for (AudioDeviceAttributes device : devices) {
2526 Objects.requireNonNull(device);
2527 }
2528 try {
2529 final int status =
2530 getService().setPreferredDevicesForCapturePreset(capturePreset, devices);
2531 return status == AudioSystem.SUCCESS;
2532 } catch (RemoteException e) {
2533 throw e.rethrowFromSystemServer();
2534 }
2535 }
2536
2537 /**
2538 * @hide
2539 * Interface to be notified of changes in the preferred audio devices set for a given capture
2540 * preset.
2541 * <p>Note that this listener will only be invoked whenever
2542 * {@link #setPreferredDeviceForCapturePreset(int, AudioDeviceAttributes)} or
2543 * {@link #clearPreferredDevicesForCapturePreset(int)} causes a change in
2544 * preferred device. It will not be invoked directly after registration with
2545 * {@link #addOnPreferredDevicesForCapturePresetChangedListener(
2546 * Executor, OnPreferredDevicesForCapturePresetChangedListener)}
2547 * to indicate which strategies had preferred devices at the time of registration.</p>
2548 * @see #setPreferredDeviceForCapturePreset(int, AudioDeviceAttributes)
2549 * @see #clearPreferredDevicesForCapturePreset(int)
2550 * @see #getPreferredDevicesForCapturePreset(int)
2551 */
2552 @SystemApi
2553 public interface OnPreferredDevicesForCapturePresetChangedListener {
2554 /**
2555 * Called on the listener to indicate that the preferred audio devices for the given
2556 * capture preset has changed.
2557 * @param capturePreset the capture preset whose preferred device changed
2558 * @param devices a list of newly set preferred audio devices
2559 */
2560 void onPreferredDevicesForCapturePresetChanged(
jiabin958faf92021-03-12 20:00:05 +00002561 @MediaRecorder.SystemSource int capturePreset,
2562 @NonNull List<AudioDeviceAttributes> devices);
Jiabin Huangb55305f2020-09-03 17:54:16 +00002563 }
2564
2565 /**
2566 * @hide
2567 * Adds a listener for being notified of changes to the capture-preset-preferred audio device.
2568 * @param executor
2569 * @param listener
2570 * @throws SecurityException if the caller doesn't hold the required permission
2571 */
2572 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00002573 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
Jiabin Huangb55305f2020-09-03 17:54:16 +00002574 public void addOnPreferredDevicesForCapturePresetChangedListener(
2575 @NonNull @CallbackExecutor Executor executor,
2576 @NonNull OnPreferredDevicesForCapturePresetChangedListener listener)
2577 throws SecurityException {
2578 Objects.requireNonNull(executor);
2579 Objects.requireNonNull(listener);
2580 int status = addOnDevRoleForCapturePresetChangedListener(
2581 executor, listener, AudioSystem.DEVICE_ROLE_PREFERRED);
2582 if (status == AudioSystem.ERROR) {
2583 // This must not happen
2584 throw new RuntimeException("Unknown error happened");
2585 }
2586 if (status == AudioSystem.BAD_VALUE) {
2587 throw new IllegalArgumentException(
2588 "attempt to call addOnPreferredDevicesForCapturePresetChangedListener() "
2589 + "on a previously registered listener");
2590 }
2591 }
2592
2593 /**
2594 * @hide
2595 * Removes a previously added listener of changes to the capture-preset-preferred audio device.
2596 * @param listener
2597 */
2598 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00002599 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
Jiabin Huangb55305f2020-09-03 17:54:16 +00002600 public void removeOnPreferredDevicesForCapturePresetChangedListener(
2601 @NonNull OnPreferredDevicesForCapturePresetChangedListener listener) {
2602 Objects.requireNonNull(listener);
2603 int status = removeOnDevRoleForCapturePresetChangedListener(
2604 listener, AudioSystem.DEVICE_ROLE_PREFERRED);
2605 if (status == AudioSystem.ERROR) {
2606 // This must not happen
2607 throw new RuntimeException("Unknown error happened");
2608 }
2609 if (status == AudioSystem.BAD_VALUE) {
2610 throw new IllegalArgumentException(
2611 "attempt to call removeOnPreferredDevicesForCapturePresetChangedListener() "
2612 + "on an unregistered listener");
2613 }
2614 }
2615
2616 private <T> int addOnDevRoleForCapturePresetChangedListener(
2617 @NonNull @CallbackExecutor Executor executor,
2618 @NonNull T listener, int deviceRole) {
2619 Objects.requireNonNull(executor);
2620 Objects.requireNonNull(listener);
2621 DevRoleListeners<T> devRoleListeners =
2622 (DevRoleListeners<T>) mDevRoleForCapturePresetListeners.get(deviceRole);
2623 if (devRoleListeners == null) {
2624 return AudioSystem.ERROR;
2625 }
2626 synchronized (devRoleListeners.mDevRoleListenersLock) {
2627 if (devRoleListeners.hasDevRoleListener(listener)) {
2628 return AudioSystem.BAD_VALUE;
2629 }
2630 // lazy initialization of the list of device role listener
2631 if (devRoleListeners.mListenerInfos == null) {
2632 devRoleListeners.mListenerInfos = new ArrayList<>();
2633 }
2634 final int oldCbCount = devRoleListeners.mListenerInfos.size();
2635 devRoleListeners.mListenerInfos.add(new DevRoleListenerInfo<T>(executor, listener));
2636 if (oldCbCount == 0 && devRoleListeners.mListenerInfos.size() > 0) {
2637 // register binder for callbacks
2638 synchronized (mDevRoleForCapturePresetListenersLock) {
2639 int deviceRoleListenerStatus = mDeviceRoleListenersStatus;
2640 mDeviceRoleListenersStatus |= (1 << deviceRole);
2641 if (deviceRoleListenerStatus != 0) {
2642 // There are already device role changed listeners active.
2643 return AudioSystem.SUCCESS;
2644 }
2645 if (mDevicesRoleForCapturePresetDispatcherStub == null) {
2646 mDevicesRoleForCapturePresetDispatcherStub =
2647 new CapturePresetDevicesRoleDispatcherStub();
2648 }
2649 try {
2650 getService().registerCapturePresetDevicesRoleDispatcher(
2651 mDevicesRoleForCapturePresetDispatcherStub);
2652 } catch (RemoteException e) {
2653 throw e.rethrowFromSystemServer();
2654 }
2655 }
2656 }
2657 }
2658 return AudioSystem.SUCCESS;
2659 }
2660
2661 private <T> int removeOnDevRoleForCapturePresetChangedListener(
2662 @NonNull T listener, int deviceRole) {
2663 Objects.requireNonNull(listener);
2664 DevRoleListeners<T> devRoleListeners =
2665 (DevRoleListeners<T>) mDevRoleForCapturePresetListeners.get(deviceRole);
2666 if (devRoleListeners == null) {
2667 return AudioSystem.ERROR;
2668 }
2669 synchronized (devRoleListeners.mDevRoleListenersLock) {
2670 if (!devRoleListeners.removeDevRoleListener(listener)) {
2671 return AudioSystem.BAD_VALUE;
2672 }
2673 if (devRoleListeners.mListenerInfos.size() == 0) {
2674 // unregister binder for callbacks
2675 synchronized (mDevRoleForCapturePresetListenersLock) {
2676 mDeviceRoleListenersStatus ^= (1 << deviceRole);
2677 if (mDeviceRoleListenersStatus != 0) {
2678 // There are some other device role changed listeners active.
2679 return AudioSystem.SUCCESS;
2680 }
2681 try {
2682 getService().unregisterCapturePresetDevicesRoleDispatcher(
2683 mDevicesRoleForCapturePresetDispatcherStub);
2684 } catch (RemoteException e) {
2685 throw e.rethrowFromSystemServer();
2686 }
2687 }
2688 }
2689 }
2690 return AudioSystem.SUCCESS;
2691 }
2692
Cole Faust7da659b2022-10-15 21:33:29 -07002693 private final Map<Integer, Object> mDevRoleForCapturePresetListeners = Map.of(
2694 AudioSystem.DEVICE_ROLE_PREFERRED,
2695 new DevRoleListeners<OnPreferredDevicesForCapturePresetChangedListener>());
Jiabin Huangb55305f2020-09-03 17:54:16 +00002696
2697 private class DevRoleListenerInfo<T> {
2698 final @NonNull Executor mExecutor;
2699 final @NonNull T mListener;
2700 DevRoleListenerInfo(Executor executor, T listener) {
2701 mExecutor = executor;
2702 mListener = listener;
2703 }
2704 }
2705
2706 private class DevRoleListeners<T> {
2707 private final Object mDevRoleListenersLock = new Object();
2708 @GuardedBy("mDevRoleListenersLock")
2709 private @Nullable ArrayList<DevRoleListenerInfo<T>> mListenerInfos;
2710
2711 @GuardedBy("mDevRoleListenersLock")
2712 private @Nullable DevRoleListenerInfo<T> getDevRoleListenerInfo(T listener) {
2713 if (mListenerInfos == null) {
2714 return null;
2715 }
2716 for (DevRoleListenerInfo<T> listenerInfo : mListenerInfos) {
2717 if (listenerInfo.mListener == listener) {
2718 return listenerInfo;
2719 }
2720 }
2721 return null;
2722 }
2723
2724 @GuardedBy("mDevRoleListenersLock")
2725 private boolean hasDevRoleListener(T listener) {
2726 return getDevRoleListenerInfo(listener) != null;
2727 }
2728
2729 @GuardedBy("mDevRoleListenersLock")
2730 private boolean removeDevRoleListener(T listener) {
2731 final DevRoleListenerInfo<T> infoToRemove = getDevRoleListenerInfo(listener);
2732 if (infoToRemove != null) {
2733 mListenerInfos.remove(infoToRemove);
2734 return true;
2735 }
2736 return false;
2737 }
2738 }
2739
2740 private final Object mDevRoleForCapturePresetListenersLock = new Object();
2741 /**
2742 * Record if there is a listener added for device role change. If there is a listener added for
2743 * a specified device role change, the bit at position `1 << device_role` is set.
2744 */
2745 @GuardedBy("mDevRoleForCapturePresetListenersLock")
2746 private int mDeviceRoleListenersStatus = 0;
2747 @GuardedBy("mDevRoleForCapturePresetListenersLock")
2748 private CapturePresetDevicesRoleDispatcherStub mDevicesRoleForCapturePresetDispatcherStub;
2749
2750 private final class CapturePresetDevicesRoleDispatcherStub
2751 extends ICapturePresetDevicesRoleDispatcher.Stub {
2752
2753 @Override
2754 public void dispatchDevicesRoleChanged(
2755 int capturePreset, int role, List<AudioDeviceAttributes> devices) {
2756 final Object listenersObj = mDevRoleForCapturePresetListeners.get(role);
2757 if (listenersObj == null) {
2758 return;
2759 }
2760 switch (role) {
2761 case AudioSystem.DEVICE_ROLE_PREFERRED: {
2762 final DevRoleListeners<OnPreferredDevicesForCapturePresetChangedListener>
2763 listeners =
2764 (DevRoleListeners<OnPreferredDevicesForCapturePresetChangedListener>)
2765 listenersObj;
2766 final ArrayList<DevRoleListenerInfo<
2767 OnPreferredDevicesForCapturePresetChangedListener>> prefDevListeners;
2768 synchronized (listeners.mDevRoleListenersLock) {
2769 if (listeners.mListenerInfos.isEmpty()) {
2770 return;
2771 }
2772 prefDevListeners = (ArrayList<DevRoleListenerInfo<
2773 OnPreferredDevicesForCapturePresetChangedListener>>)
2774 listeners.mListenerInfos.clone();
2775 }
2776 final long ident = Binder.clearCallingIdentity();
2777 try {
2778 for (DevRoleListenerInfo<
2779 OnPreferredDevicesForCapturePresetChangedListener> info :
2780 prefDevListeners) {
2781 info.mExecutor.execute(() ->
2782 info.mListener.onPreferredDevicesForCapturePresetChanged(
2783 capturePreset, devices));
2784 }
2785 } finally {
2786 Binder.restoreCallingIdentity(ident);
2787 }
2788 } break;
2789 default:
2790 break;
2791 }
2792 }
2793 }
2794
2795 //====================================================================
jiabine22f6aa2021-12-10 01:09:02 +00002796 // Direct playback query
2797
2798 /** Return value for {@link #getDirectPlaybackSupport(AudioFormat, AudioAttributes)}:
2799 direct playback not supported. */
2800 public static final int DIRECT_PLAYBACK_NOT_SUPPORTED = AudioSystem.DIRECT_NOT_SUPPORTED;
2801 /** Return value for {@link #getDirectPlaybackSupport(AudioFormat, AudioAttributes)}:
2802 direct offload playback supported. Compressed offload is a variant of direct playback.
2803 It is the feature that allows audio processing tasks to be done on the Android device but
2804 not on the application processor, instead, it is handled by dedicated hardware such as audio
2805 DSPs. That will allow the application processor to be idle as much as possible, which is
2806 good for power saving. Compressed offload playback supports
2807 {@link AudioTrack.StreamEventCallback} for event notifications. */
2808 public static final int DIRECT_PLAYBACK_OFFLOAD_SUPPORTED =
2809 AudioSystem.DIRECT_OFFLOAD_SUPPORTED;
2810 /** Return value for {@link #getDirectPlaybackSupport(AudioFormat, AudioAttributes)}:
2811 direct offload playback supported with gapless transitions. Compressed offload is a variant
2812 of direct playback. It is the feature that allows audio processing tasks to be done on the
2813 Android device but not on the application processor, instead, it is handled by dedicated
2814 hardware such as audio DSPs. That will allow the application processor to be idle as much as
2815 possible, which is good for power saving. Compressed offload playback supports
2816 {@link AudioTrack.StreamEventCallback} for event notifications. Gapless transitions
2817 indicates the ability to play consecutive audio tracks without an audio silence in
2818 between. */
2819 public static final int DIRECT_PLAYBACK_OFFLOAD_GAPLESS_SUPPORTED =
2820 AudioSystem.DIRECT_OFFLOAD_GAPLESS_SUPPORTED;
2821 /** Return value for {@link #getDirectPlaybackSupport(AudioFormat, AudioAttributes)}:
2822 direct playback supported. This value covers direct playback that is bitstream pass-through
2823 such as compressed pass-through. */
2824 public static final int DIRECT_PLAYBACK_BITSTREAM_SUPPORTED =
2825 AudioSystem.DIRECT_BITSTREAM_SUPPORTED;
2826
2827 /** @hide */
2828 @IntDef(flag = true, prefix = "DIRECT_PLAYBACK_", value = {
2829 DIRECT_PLAYBACK_NOT_SUPPORTED,
2830 DIRECT_PLAYBACK_OFFLOAD_SUPPORTED,
2831 DIRECT_PLAYBACK_OFFLOAD_GAPLESS_SUPPORTED,
2832 DIRECT_PLAYBACK_BITSTREAM_SUPPORTED}
2833 )
2834 @Retention(RetentionPolicy.SOURCE)
2835 public @interface AudioDirectPlaybackMode {}
2836
2837 /**
2838 * Returns a bitfield representing the different forms of direct playback currently available
2839 * for a given audio format.
2840 * <p>Direct playback means that the audio stream is not altered by the framework. The audio
2841 * stream will not be resampled, volume scaled, downmixed or mixed with other content by
2842 * the framework. But it may be wrapped in a higher level protocol such as IEC61937 for
2843 * passthrough.
2844 * <p>Checking for direct support can help the app select the representation of audio content
2845 * that most closely matches the capabilities of the device and peripherals (e.g. A/V receiver)
2846 * connected to it. Note that the provided stream can still be re-encoded or mixed with other
2847 * streams, if needed.
2848 * @param format the audio format (codec, sample rate, channels) being checked.
2849 * @param attributes the {@link AudioAttributes} to be used for playback
2850 * @return the direct playback mode available with given format and attributes. The returned
2851 * value will be {@link #DIRECT_PLAYBACK_NOT_SUPPORTED} or a combination of
2852 * {@link #DIRECT_PLAYBACK_OFFLOAD_SUPPORTED},
2853 * {@link #DIRECT_PLAYBACK_OFFLOAD_GAPLESS_SUPPORTED} and
2854 * {@link #DIRECT_PLAYBACK_BITSTREAM_SUPPORTED}. Note that if
2855 * {@link #DIRECT_PLAYBACK_OFFLOAD_GAPLESS_SUPPORTED} is present in the returned value,
2856 * then {@link #DIRECT_PLAYBACK_OFFLOAD_SUPPORTED} will be too.
2857 */
2858 @AudioDirectPlaybackMode
2859 public static int getDirectPlaybackSupport(@NonNull AudioFormat format,
2860 @NonNull AudioAttributes attributes) {
2861 Objects.requireNonNull(format);
2862 Objects.requireNonNull(attributes);
2863 return AudioSystem.getDirectPlaybackSupport(format, attributes);
2864 }
2865
2866 //====================================================================
Jean-Michel Trivi980d38f2018-01-08 15:43:35 -08002867 // Offload query
2868 /**
Jean-Michel Trivi980d38f2018-01-08 15:43:35 -08002869 * Returns whether offloaded playback of an audio format is supported on the device.
Jean-Michel Trivi03f51392018-08-31 15:47:13 -07002870 * <p>Offloaded playback is the feature where the decoding and playback of an audio stream
2871 * is not competing with other software resources. In general, it is supported by dedicated
2872 * hardware, such as audio DSPs.
2873 * <p>Note that this query only provides information about the support of an audio format,
2874 * it does not indicate whether the resources necessary for the offloaded playback are
2875 * available at that instant.
Jean-Michel Trivi980d38f2018-01-08 15:43:35 -08002876 * @param format the audio format (codec, sample rate, channels) being checked.
Jean-Michel Trivif3fd84a2019-03-21 16:08:50 -07002877 * @param attributes the {@link AudioAttributes} to be used for playback
Jean-Michel Trivi980d38f2018-01-08 15:43:35 -08002878 * @return true if the given audio format can be offloaded.
2879 */
Jean-Michel Trivif3fd84a2019-03-21 16:08:50 -07002880 public static boolean isOffloadedPlaybackSupported(@NonNull AudioFormat format,
2881 @NonNull AudioAttributes attributes) {
Jean-Michel Trivi03f51392018-08-31 15:47:13 -07002882 if (format == null) {
Jean-Michel Trivif3fd84a2019-03-21 16:08:50 -07002883 throw new NullPointerException("Illegal null AudioFormat");
Jean-Michel Trivi03f51392018-08-31 15:47:13 -07002884 }
Jean-Michel Trivif3fd84a2019-03-21 16:08:50 -07002885 if (attributes == null) {
2886 throw new NullPointerException("Illegal null AudioAttributes");
2887 }
Eric Laurentba3b3a62020-11-26 20:10:51 +01002888 return AudioSystem.getOffloadSupport(format, attributes) != PLAYBACK_OFFLOAD_NOT_SUPPORTED;
2889 }
2890
2891 /** Return value for {@link #getPlaybackOffloadSupport(AudioFormat, AudioAttributes)}:
2892 offload playback not supported */
2893 public static final int PLAYBACK_OFFLOAD_NOT_SUPPORTED = AudioSystem.OFFLOAD_NOT_SUPPORTED;
2894 /** Return value for {@link #getPlaybackOffloadSupport(AudioFormat, AudioAttributes)}:
2895 offload playback supported */
2896 public static final int PLAYBACK_OFFLOAD_SUPPORTED = AudioSystem.OFFLOAD_SUPPORTED;
2897 /** Return value for {@link #getPlaybackOffloadSupport(AudioFormat, AudioAttributes)}:
2898 offload playback supported with gapless transitions */
2899 public static final int PLAYBACK_OFFLOAD_GAPLESS_SUPPORTED =
2900 AudioSystem.OFFLOAD_GAPLESS_SUPPORTED;
2901
2902 /** @hide */
2903 @IntDef(flag = false, prefix = "PLAYBACK_OFFLOAD_", value = {
2904 PLAYBACK_OFFLOAD_NOT_SUPPORTED,
2905 PLAYBACK_OFFLOAD_SUPPORTED,
2906 PLAYBACK_OFFLOAD_GAPLESS_SUPPORTED }
2907 )
2908 @Retention(RetentionPolicy.SOURCE)
2909 public @interface AudioOffloadMode {}
2910
2911 /**
2912 * Returns whether offloaded playback of an audio format is supported on the device or not and
2913 * when supported whether gapless transitions are possible or not.
2914 * <p>Offloaded playback is the feature where the decoding and playback of an audio stream
2915 * is not competing with other software resources. In general, it is supported by dedicated
2916 * hardware, such as audio DSPs.
2917 * <p>Note that this query only provides information about the support of an audio format,
2918 * it does not indicate whether the resources necessary for the offloaded playback are
2919 * available at that instant.
2920 * @param format the audio format (codec, sample rate, channels) being checked.
2921 * @param attributes the {@link AudioAttributes} to be used for playback
2922 * @return {@link #PLAYBACK_OFFLOAD_NOT_SUPPORTED} if offload playback if not supported,
2923 * {@link #PLAYBACK_OFFLOAD_SUPPORTED} if offload playback is supported or
2924 * {@link #PLAYBACK_OFFLOAD_GAPLESS_SUPPORTED} if gapless transitions are
2925 * also supported.
jiabine22f6aa2021-12-10 01:09:02 +00002926 * @deprecated Use {@link #getDirectPlaybackSupport(AudioFormat, AudioAttributes)} instead
Eric Laurentba3b3a62020-11-26 20:10:51 +01002927 */
jiabine22f6aa2021-12-10 01:09:02 +00002928 @Deprecated
Eric Laurentba3b3a62020-11-26 20:10:51 +01002929 @AudioOffloadMode
2930 public static int getPlaybackOffloadSupport(@NonNull AudioFormat format,
2931 @NonNull AudioAttributes attributes) {
2932 if (format == null) {
2933 throw new NullPointerException("Illegal null AudioFormat");
2934 }
2935 if (attributes == null) {
2936 throw new NullPointerException("Illegal null AudioAttributes");
2937 }
2938 return AudioSystem.getOffloadSupport(format, attributes);
Jean-Michel Trivi980d38f2018-01-08 15:43:35 -08002939 }
2940
2941 //====================================================================
Jean-Michel Trivie9dd14e2021-07-12 11:10:18 -07002942 // Immersive audio
2943
2944 /**
2945 * Return a handle to the optional platform's {@link Spatializer}
Jean-Michel Trivi838913c2021-09-02 20:55:44 -07002946 * @return the {@code Spatializer} instance.
Jean-Michel Trivic5f69572021-09-14 10:46:55 -07002947 * @see Spatializer#getImmersiveAudioLevel() to check for the level of support of the effect
2948 * on the platform
Jean-Michel Trivie9dd14e2021-07-12 11:10:18 -07002949 */
Jean-Michel Trivic5f69572021-09-14 10:46:55 -07002950 public @NonNull Spatializer getSpatializer() {
Jean-Michel Trivie9dd14e2021-07-12 11:10:18 -07002951 return new Spatializer(this);
2952 }
2953
2954 //====================================================================
Eric Laurent3def1ee2010-03-17 23:26:26 -07002955 // Bluetooth SCO control
2956 /**
Glenn Kastena24e9912017-08-25 08:14:08 -07002957 * Sticky broadcast intent action indicating that the Bluetooth SCO audio
Eric Laurent95b88fb2010-03-18 20:35:49 -07002958 * connection state has changed. The intent contains on extra {@link #EXTRA_SCO_AUDIO_STATE}
Eric Laurent3def1ee2010-03-17 23:26:26 -07002959 * indicating the new state which is either {@link #SCO_AUDIO_STATE_DISCONNECTED}
2960 * or {@link #SCO_AUDIO_STATE_CONNECTED}
2961 *
2962 * @see #startBluetoothSco()
Eric Laurentdc03c612011-04-01 10:59:41 -07002963 * @deprecated Use {@link #ACTION_SCO_AUDIO_STATE_UPDATED} instead
Eric Laurent3def1ee2010-03-17 23:26:26 -07002964 */
Eric Laurentdc03c612011-04-01 10:59:41 -07002965 @Deprecated
Eric Laurent3def1ee2010-03-17 23:26:26 -07002966 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
2967 public static final String ACTION_SCO_AUDIO_STATE_CHANGED =
2968 "android.media.SCO_AUDIO_STATE_CHANGED";
Eric Laurentdc03c612011-04-01 10:59:41 -07002969
2970 /**
Glenn Kastena24e9912017-08-25 08:14:08 -07002971 * Sticky broadcast intent action indicating that the Bluetooth SCO audio
Eric Laurentdc03c612011-04-01 10:59:41 -07002972 * connection state has been updated.
2973 * <p>This intent has two extras:
2974 * <ul>
2975 * <li> {@link #EXTRA_SCO_AUDIO_STATE} - The new SCO audio state. </li>
2976 * <li> {@link #EXTRA_SCO_AUDIO_PREVIOUS_STATE}- The previous SCO audio state. </li>
2977 * </ul>
2978 * <p> EXTRA_SCO_AUDIO_STATE or EXTRA_SCO_AUDIO_PREVIOUS_STATE can be any of:
2979 * <ul>
2980 * <li> {@link #SCO_AUDIO_STATE_DISCONNECTED}, </li>
2981 * <li> {@link #SCO_AUDIO_STATE_CONNECTING} or </li>
2982 * <li> {@link #SCO_AUDIO_STATE_CONNECTED}, </li>
2983 * </ul>
2984 * @see #startBluetoothSco()
2985 */
2986 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
2987 public static final String ACTION_SCO_AUDIO_STATE_UPDATED =
2988 "android.media.ACTION_SCO_AUDIO_STATE_UPDATED";
2989
Eric Laurent3def1ee2010-03-17 23:26:26 -07002990 /**
Eric Laurentdc03c612011-04-01 10:59:41 -07002991 * Extra for intent {@link #ACTION_SCO_AUDIO_STATE_CHANGED} or
2992 * {@link #ACTION_SCO_AUDIO_STATE_UPDATED} containing the new bluetooth SCO connection state.
Eric Laurent3def1ee2010-03-17 23:26:26 -07002993 */
2994 public static final String EXTRA_SCO_AUDIO_STATE =
2995 "android.media.extra.SCO_AUDIO_STATE";
2996
2997 /**
Eric Laurentdc03c612011-04-01 10:59:41 -07002998 * Extra for intent {@link #ACTION_SCO_AUDIO_STATE_UPDATED} containing the previous
2999 * bluetooth SCO connection state.
3000 */
3001 public static final String EXTRA_SCO_AUDIO_PREVIOUS_STATE =
3002 "android.media.extra.SCO_AUDIO_PREVIOUS_STATE";
3003
3004 /**
3005 * Value for extra EXTRA_SCO_AUDIO_STATE or EXTRA_SCO_AUDIO_PREVIOUS_STATE
3006 * indicating that the SCO audio channel is not established
Eric Laurent3def1ee2010-03-17 23:26:26 -07003007 */
3008 public static final int SCO_AUDIO_STATE_DISCONNECTED = 0;
3009 /**
Eric Laurentdc03c612011-04-01 10:59:41 -07003010 * Value for extra {@link #EXTRA_SCO_AUDIO_STATE} or {@link #EXTRA_SCO_AUDIO_PREVIOUS_STATE}
3011 * indicating that the SCO audio channel is established
Eric Laurent3def1ee2010-03-17 23:26:26 -07003012 */
3013 public static final int SCO_AUDIO_STATE_CONNECTED = 1;
3014 /**
Eric Laurentdc03c612011-04-01 10:59:41 -07003015 * Value for extra EXTRA_SCO_AUDIO_STATE or EXTRA_SCO_AUDIO_PREVIOUS_STATE
3016 * indicating that the SCO audio channel is being established
3017 */
3018 public static final int SCO_AUDIO_STATE_CONNECTING = 2;
3019 /**
3020 * Value for extra EXTRA_SCO_AUDIO_STATE indicating that
Eric Laurent3def1ee2010-03-17 23:26:26 -07003021 * there was an error trying to obtain the state
3022 */
3023 public static final int SCO_AUDIO_STATE_ERROR = -1;
3024
3025
3026 /**
Eric Laurent3def1ee2010-03-17 23:26:26 -07003027 * Indicates if current platform supports use of SCO for off call use cases.
3028 * Application wanted to use bluetooth SCO audio when the phone is not in call
Jean-Michel Trivi2ac2afe2012-08-21 11:16:55 -07003029 * must first call this method to make sure that the platform supports this
Eric Laurent3def1ee2010-03-17 23:26:26 -07003030 * feature.
3031 * @return true if bluetooth SCO can be used for audio when not in call
3032 * false otherwise
3033 * @see #startBluetoothSco()
3034 */
3035 public boolean isBluetoothScoAvailableOffCall() {
Marco Nelissen29f16932015-04-17 09:50:56 -07003036 return getContext().getResources().getBoolean(
Eric Laurent3def1ee2010-03-17 23:26:26 -07003037 com.android.internal.R.bool.config_bluetooth_sco_off_call);
3038 }
3039
3040 /**
Eric Laurent3def1ee2010-03-17 23:26:26 -07003041 * Start bluetooth SCO audio connection.
3042 * <p>Requires Permission:
Jean-Michel Trivic4557822023-01-23 18:19:52 +00003043 * {@link Manifest.permission#MODIFY_AUDIO_SETTINGS}.
Eric Laurent3def1ee2010-03-17 23:26:26 -07003044 * <p>This method can be used by applications wanting to send and received audio
3045 * to/from a bluetooth SCO headset while the phone is not in call.
3046 * <p>As the SCO connection establishment can take several seconds,
3047 * applications should not rely on the connection to be available when the method
Eric Laurentdc03c612011-04-01 10:59:41 -07003048 * returns but instead register to receive the intent {@link #ACTION_SCO_AUDIO_STATE_UPDATED}
Eric Laurent3def1ee2010-03-17 23:26:26 -07003049 * and wait for the state to be {@link #SCO_AUDIO_STATE_CONNECTED}.
Eric Laurentdc03c612011-04-01 10:59:41 -07003050 * <p>As the ACTION_SCO_AUDIO_STATE_UPDATED intent is sticky, the application can check the SCO
3051 * audio state before calling startBluetoothSco() by reading the intent returned by the receiver
3052 * registration. If the state is already CONNECTED, no state change will be received via the
3053 * intent after calling startBluetoothSco(). It is however useful to call startBluetoothSco()
3054 * so that the connection stays active in case the current initiator stops the connection.
3055 * <p>Unless the connection is already active as described above, the state will always
3056 * transition from DISCONNECTED to CONNECTING and then either to CONNECTED if the connection
3057 * succeeds or back to DISCONNECTED if the connection fails (e.g no headset is connected).
3058 * <p>When finished with the SCO connection or if the establishment fails, the application must
3059 * call {@link #stopBluetoothSco()} to clear the request and turn down the bluetooth connection.
Eric Laurent3def1ee2010-03-17 23:26:26 -07003060 * <p>Even if a SCO connection is established, the following restrictions apply on audio
3061 * output streams so that they can be routed to SCO headset:
Eric Laurentdc03c612011-04-01 10:59:41 -07003062 * <ul>
3063 * <li> the stream type must be {@link #STREAM_VOICE_CALL} </li>
3064 * <li> the format must be mono </li>
3065 * <li> the sampling must be 16kHz or 8kHz </li>
3066 * </ul>
Eric Laurent3def1ee2010-03-17 23:26:26 -07003067 * <p>The following restrictions apply on input streams:
Eric Laurentdc03c612011-04-01 10:59:41 -07003068 * <ul>
3069 * <li> the format must be mono </li>
3070 * <li> the sampling must be 8kHz </li>
3071 * </ul>
Eric Laurent3def1ee2010-03-17 23:26:26 -07003072 * <p>Note that the phone application always has the priority on the usage of the SCO
3073 * connection for telephony. If this method is called while the phone is in call
3074 * it will be ignored. Similarly, if a call is received or sent while an application
3075 * is using the SCO connection, the connection will be lost for the application and NOT
3076 * returned automatically when the call ends.
Eric Laurent83900752014-05-15 15:14:22 -07003077 * <p>NOTE: up to and including API version
3078 * {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR1}, this method initiates a virtual
3079 * voice call to the bluetooth headset.
3080 * After API version {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2} only a raw SCO audio
3081 * connection is established.
Eric Laurent3def1ee2010-03-17 23:26:26 -07003082 * @see #stopBluetoothSco()
Eric Laurentdc03c612011-04-01 10:59:41 -07003083 * @see #ACTION_SCO_AUDIO_STATE_UPDATED
Eric Laurentf23f1b72022-02-18 10:57:54 +01003084 * @deprecated Use {@link AudioManager#setCommunicationDevice(AudioDeviceInfo)} instead.
Eric Laurent3def1ee2010-03-17 23:26:26 -07003085 */
Eric Laurentf23f1b72022-02-18 10:57:54 +01003086 @Deprecated public void startBluetoothSco() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003087 final IAudioService service = getService();
Eric Laurent3def1ee2010-03-17 23:26:26 -07003088 try {
Marco Nelissen926ebb82015-03-11 09:59:49 -07003089 service.startBluetoothSco(mICallBack,
Marco Nelissen29f16932015-04-17 09:50:56 -07003090 getContext().getApplicationInfo().targetSdkVersion);
Eric Laurent3def1ee2010-03-17 23:26:26 -07003091 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07003092 throw e.rethrowFromSystemServer();
Eric Laurent3def1ee2010-03-17 23:26:26 -07003093 }
3094 }
3095
3096 /**
Jean-Michel Trivi0daab222014-07-18 15:31:29 -07003097 * @hide
Eric Laurent83900752014-05-15 15:14:22 -07003098 * Start bluetooth SCO audio connection in virtual call mode.
3099 * <p>Requires Permission:
Jean-Michel Trivic4557822023-01-23 18:19:52 +00003100 * {@link Manifest.permission#MODIFY_AUDIO_SETTINGS}.
Eric Laurent83900752014-05-15 15:14:22 -07003101 * <p>Similar to {@link #startBluetoothSco()} with explicit selection of virtual call mode.
3102 * Telephony and communication applications (VoIP, Video Chat) should preferably select
3103 * virtual call mode.
3104 * Applications using voice input for search or commands should first try raw audio connection
3105 * with {@link #startBluetoothSco()} and fall back to startBluetoothScoVirtualCall() in case of
3106 * failure.
3107 * @see #startBluetoothSco()
3108 * @see #stopBluetoothSco()
3109 * @see #ACTION_SCO_AUDIO_STATE_UPDATED
3110 */
Mathew Inwood8e742f92020-10-27 11:47:29 +00003111 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
Eric Laurent83900752014-05-15 15:14:22 -07003112 public void startBluetoothScoVirtualCall() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003113 final IAudioService service = getService();
Eric Laurent83900752014-05-15 15:14:22 -07003114 try {
3115 service.startBluetoothScoVirtualCall(mICallBack);
3116 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07003117 throw e.rethrowFromSystemServer();
Eric Laurent83900752014-05-15 15:14:22 -07003118 }
3119 }
3120
3121 /**
Eric Laurent3def1ee2010-03-17 23:26:26 -07003122 * Stop bluetooth SCO audio connection.
3123 * <p>Requires Permission:
Jean-Michel Trivic4557822023-01-23 18:19:52 +00003124 * {@link Manifest.permission#MODIFY_AUDIO_SETTINGS}.
Eric Laurent3def1ee2010-03-17 23:26:26 -07003125 * <p>This method must be called by applications having requested the use of
Jean-Michel Trivi0daab222014-07-18 15:31:29 -07003126 * bluetooth SCO audio with {@link #startBluetoothSco()} when finished with the SCO
3127 * connection or if connection fails.
Eric Laurent3def1ee2010-03-17 23:26:26 -07003128 * @see #startBluetoothSco()
Eric Laurentf23f1b72022-02-18 10:57:54 +01003129 * @deprecated Use {@link AudioManager#clearCommunicationDevice()} instead.
Eric Laurent3def1ee2010-03-17 23:26:26 -07003130 */
Jean-Michel Trivi0daab222014-07-18 15:31:29 -07003131 // Also used for connections started with {@link #startBluetoothScoVirtualCall()}
Eric Laurentf23f1b72022-02-18 10:57:54 +01003132 @Deprecated public void stopBluetoothSco() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003133 final IAudioService service = getService();
Eric Laurent3def1ee2010-03-17 23:26:26 -07003134 try {
3135 service.stopBluetoothSco(mICallBack);
3136 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07003137 throw e.rethrowFromSystemServer();
Eric Laurent3def1ee2010-03-17 23:26:26 -07003138 }
3139 }
3140
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003141 /**
Eric Laurenta553c252009-07-17 12:17:14 -07003142 * Request use of Bluetooth SCO headset for communications.
Jean-Michel Trivifccb25d2009-09-15 16:06:10 -07003143 * <p>
3144 * This method should only be used by applications that replace the platform-wide
3145 * management of audio settings or the main telephony application.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003146 *
Eric Laurenta553c252009-07-17 12:17:14 -07003147 * @param on set <var>true</var> to use bluetooth SCO for communications;
3148 * <var>false</var> to not use bluetooth SCO for communications
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003149 */
3150 public void setBluetoothScoOn(boolean on){
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003151 final IAudioService service = getService();
Eric Laurentc42ac9d2009-07-29 08:53:03 -07003152 try {
3153 service.setBluetoothScoOn(on);
3154 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07003155 throw e.rethrowFromSystemServer();
Eric Laurenta553c252009-07-17 12:17:14 -07003156 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003157 }
3158
3159 /**
Eric Laurenta553c252009-07-17 12:17:14 -07003160 * Checks whether communications use Bluetooth SCO.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003161 *
Eric Laurenta553c252009-07-17 12:17:14 -07003162 * @return true if SCO is used for communications;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003163 * false if otherwise
Eric Laurentf23f1b72022-02-18 10:57:54 +01003164 * @deprecated Use {@link AudioManager#getCommunicationDevice()} instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003165 */
Eric Laurentf23f1b72022-02-18 10:57:54 +01003166 @Deprecated public boolean isBluetoothScoOn() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003167 final IAudioService service = getService();
Eric Laurentc42ac9d2009-07-29 08:53:03 -07003168 try {
3169 return service.isBluetoothScoOn();
3170 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07003171 throw e.rethrowFromSystemServer();
Eric Laurenta553c252009-07-17 12:17:14 -07003172 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003173 }
3174
3175 /**
Santiago Seifert1d8f6172022-08-25 14:34:44 +00003176 * @deprecated Use {@link MediaRouter#selectRoute} instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003177 */
Eric Laurenta553c252009-07-17 12:17:14 -07003178 @Deprecated public void setBluetoothA2dpOn(boolean on){
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003179 }
3180
3181 /**
Eric Laurentc117bea2017-02-07 11:04:18 -08003182 * Checks whether a Bluetooth A2DP audio peripheral is connected or not.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003183 *
Eric Laurentc117bea2017-02-07 11:04:18 -08003184 * @return true if a Bluetooth A2DP peripheral is connected
Eric Laurent242b3382012-06-15 11:48:50 -07003185 * false if otherwise
Eric Laurentc117bea2017-02-07 11:04:18 -08003186 * @deprecated Use {@link AudioManager#getDevices(int)} instead to list available audio devices.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003187 */
3188 public boolean isBluetoothA2dpOn() {
Eric Laurent242b3382012-06-15 11:48:50 -07003189 if (AudioSystem.getDeviceConnectionState(DEVICE_OUT_BLUETOOTH_A2DP,"")
Eric Laurent9656df22016-04-20 16:42:28 -07003190 == AudioSystem.DEVICE_STATE_AVAILABLE) {
3191 return true;
3192 } else if (AudioSystem.getDeviceConnectionState(DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES,"")
3193 == AudioSystem.DEVICE_STATE_AVAILABLE) {
3194 return true;
3195 } else if (AudioSystem.getDeviceConnectionState(DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER,"")
3196 == AudioSystem.DEVICE_STATE_AVAILABLE) {
Eric Laurent242b3382012-06-15 11:48:50 -07003197 return true;
Eric Laurenta553c252009-07-17 12:17:14 -07003198 }
Eric Laurent9656df22016-04-20 16:42:28 -07003199 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003200 }
3201
3202 /**
3203 * Sets audio routing to the wired headset on or off.
3204 *
3205 * @param on set <var>true</var> to route audio to/from wired
3206 * headset; <var>false</var> disable wired headset audio
Eric Laurenta553c252009-07-17 12:17:14 -07003207 * @deprecated Do not use.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003208 */
Eric Laurenta553c252009-07-17 12:17:14 -07003209 @Deprecated public void setWiredHeadsetOn(boolean on){
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003210 }
3211
3212 /**
Eric Laurent497b3fe2011-08-02 17:41:11 -07003213 * Checks whether a wired headset is connected or not.
3214 * <p>This is not a valid indication that audio playback is
3215 * actually over the wired headset as audio routing depends on other conditions.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003216 *
Eric Laurent497b3fe2011-08-02 17:41:11 -07003217 * @return true if a wired headset is connected.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003218 * false if otherwise
Eric Laurentc117bea2017-02-07 11:04:18 -08003219 * @deprecated Use {@link AudioManager#getDevices(int)} instead to list available audio devices.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003220 */
3221 public boolean isWiredHeadsetOn() {
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08003222 if (AudioSystem.getDeviceConnectionState(DEVICE_OUT_WIRED_HEADSET,"")
Eric Laurent6015a972010-02-12 07:41:14 -08003223 == AudioSystem.DEVICE_STATE_UNAVAILABLE &&
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08003224 AudioSystem.getDeviceConnectionState(DEVICE_OUT_WIRED_HEADPHONE,"")
Paul McLean145c9532017-08-04 11:12:19 -06003225 == AudioSystem.DEVICE_STATE_UNAVAILABLE &&
3226 AudioSystem.getDeviceConnectionState(DEVICE_OUT_USB_HEADSET, "")
3227 == AudioSystem.DEVICE_STATE_UNAVAILABLE) {
Eric Laurenta553c252009-07-17 12:17:14 -07003228 return false;
3229 } else {
3230 return true;
3231 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003232 }
3233
3234 /**
3235 * Sets the microphone mute on or off.
Jean-Michel Trivifccb25d2009-09-15 16:06:10 -07003236 * <p>
3237 * This method should only be used by applications that replace the platform-wide
3238 * management of audio settings or the main telephony application.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003239 *
3240 * @param on set <var>true</var> to mute the microphone;
3241 * <var>false</var> to turn mute off
3242 */
Kenny Guy70e0c582015-06-30 19:18:28 +01003243 public void setMicrophoneMute(boolean on) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003244 final IAudioService service = getService();
Emily Bernier22c921a2014-05-28 11:01:32 -04003245 try {
Kenny Guy70e0c582015-06-30 19:18:28 +01003246 service.setMicrophoneMute(on, getContext().getOpPackageName(),
John Wu4f7e5102021-06-22 17:29:11 +00003247 UserHandle.getCallingUserId(), getContext().getAttributionTag());
Emily Bernier22c921a2014-05-28 11:01:32 -04003248 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07003249 throw e.rethrowFromSystemServer();
Emily Bernier22c921a2014-05-28 11:01:32 -04003250 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003251 }
3252
3253 /**
Dmitry Shmidt3d233932019-09-20 15:52:03 -07003254 * @hide
3255 * Sets the microphone from switch mute on or off.
3256 * <p>
3257 * This method should only be used by InputManager to notify
3258 * Audio Subsystem about Microphone Mute switch state.
3259 *
3260 * @param on set <var>true</var> to mute the microphone;
3261 * <var>false</var> to turn mute off
3262 */
Mathew Inwood8e742f92020-10-27 11:47:29 +00003263 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
Dmitry Shmidt3d233932019-09-20 15:52:03 -07003264 public void setMicrophoneMuteFromSwitch(boolean on) {
3265 final IAudioService service = getService();
3266 try {
3267 service.setMicrophoneMuteFromSwitch(on);
3268 } catch (RemoteException e) {
3269 throw e.rethrowFromSystemServer();
3270 }
3271 }
3272
3273 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003274 * Checks whether the microphone mute is on or off.
3275 *
3276 * @return true if microphone is muted, false if it's not
3277 */
3278 public boolean isMicrophoneMute() {
Dmitry Shmidt3d233932019-09-20 15:52:03 -07003279 final IAudioService service = getService();
3280 try {
3281 return service.isMicrophoneMuted();
3282 } catch (RemoteException e) {
3283 throw e.rethrowFromSystemServer();
3284 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003285 }
3286
3287 /**
Jean-Michel Trivi7be17d22017-12-21 18:09:21 -08003288 * Broadcast Action: microphone muting state changed.
3289 *
3290 * You <em>cannot</em> receive this through components declared
3291 * in manifests, only by explicitly registering for it with
3292 * {@link Context#registerReceiver(BroadcastReceiver, IntentFilter)
3293 * Context.registerReceiver()}.
3294 *
3295 * <p>The intent has no extra values, use {@link #isMicrophoneMute} to check whether the
3296 * microphone is muted.
3297 */
3298 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
3299 public static final String ACTION_MICROPHONE_MUTE_CHANGED =
3300 "android.media.action.MICROPHONE_MUTE_CHANGED";
3301
3302 /**
Jean-Michel Trivi90682ff2019-03-18 15:52:00 -07003303 * Broadcast Action: speakerphone state changed.
3304 *
3305 * You <em>cannot</em> receive this through components declared
3306 * in manifests, only by explicitly registering for it with
3307 * {@link Context#registerReceiver(BroadcastReceiver, IntentFilter)
3308 * Context.registerReceiver()}.
3309 *
3310 * <p>The intent has no extra values, use {@link #isSpeakerphoneOn} to check whether the
3311 * speakerphone functionality is enabled or not.
3312 */
3313 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
3314 public static final String ACTION_SPEAKERPHONE_STATE_CHANGED =
3315 "android.media.action.SPEAKERPHONE_STATE_CHANGED";
3316
3317 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003318 * Sets the audio mode.
Jean-Michel Trivifccb25d2009-09-15 16:06:10 -07003319 * <p>
3320 * The audio mode encompasses audio routing AND the behavior of
3321 * the telephony layer. Therefore this method should only be used by applications that
3322 * replace the platform-wide management of audio settings or the main telephony application.
3323 * In particular, the {@link #MODE_IN_CALL} mode should only be used by the telephony
3324 * application when it places a phone call, as it will cause signals from the radio layer
3325 * to feed the platform mixer.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003326 *
Eric Laurent2d7197fc2019-11-06 10:17:06 -08003327 * @param mode the requested audio mode.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003328 * Informs the HAL about the current audio state so that
3329 * it can route the audio appropriately.
3330 */
Eric Laurent2d7197fc2019-11-06 10:17:06 -08003331 public void setMode(@AudioMode int mode) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003332 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003333 try {
Marco Nelissena80ac052015-03-12 16:17:45 -07003334 service.setMode(mode, mICallBack, mApplicationContext.getOpPackageName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003335 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07003336 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003337 }
3338 }
3339
3340 /**
Eric Laurent1c3408f2021-11-09 12:09:54 +01003341 * This change id controls use of audio modes for call audio redirection.
3342 * @hide
3343 */
3344 @ChangeId
3345 @EnabledSince(targetSdkVersion = Build.VERSION_CODES.TIRAMISU)
3346 public static final long CALL_REDIRECTION_AUDIO_MODES = 189472651L; // buganizer id
3347
3348 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003349 * Returns the current audio mode.
3350 *
Eric Laurent2d7197fc2019-11-06 10:17:06 -08003351 * @return the current audio mode.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003352 */
Eric Laurent2d7197fc2019-11-06 10:17:06 -08003353 @AudioMode
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003354 public int getMode() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003355 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003356 try {
Eric Laurent2d7197fc2019-11-06 10:17:06 -08003357 int mode = service.getMode();
3358 int sdk;
3359 try {
3360 sdk = getContext().getApplicationInfo().targetSdkVersion;
3361 } catch (NullPointerException e) {
3362 // some tests don't have a Context
3363 sdk = Build.VERSION.SDK_INT;
3364 }
3365 if (mode == MODE_CALL_SCREENING && sdk <= Build.VERSION_CODES.Q) {
3366 mode = MODE_IN_CALL;
Eric Laurent1c3408f2021-11-09 12:09:54 +01003367 } else if (mode == MODE_CALL_REDIRECT
3368 && !CompatChanges.isChangeEnabled(CALL_REDIRECTION_AUDIO_MODES)) {
3369 mode = MODE_IN_CALL;
3370 } else if (mode == MODE_COMMUNICATION_REDIRECT
3371 && !CompatChanges.isChangeEnabled(CALL_REDIRECTION_AUDIO_MODES)) {
3372 mode = MODE_IN_COMMUNICATION;
Eric Laurent2d7197fc2019-11-06 10:17:06 -08003373 }
3374 return mode;
3375 } catch (RemoteException e) {
3376 throw e.rethrowFromSystemServer();
3377 }
3378 }
3379
3380 /**
Nate Myren08635fe2021-04-20 12:04:39 -07003381 * Interface definition of a callback that is notified when the audio mode changes
3382 */
3383 public interface OnModeChangedListener {
3384 /**
3385 * Called on the listener to indicate that the audio mode has changed
3386 *
3387 * @param mode The current audio mode
3388 */
3389 void onModeChanged(@AudioMode int mode);
3390 }
3391
Nate Myren08635fe2021-04-20 12:04:39 -07003392 /**
Jean-Michel Trivi54d129f2021-12-30 17:43:47 -08003393 * manages the OnModeChangedListener listeners and the ModeDispatcherStub
Nate Myren08635fe2021-04-20 12:04:39 -07003394 */
Jean-Michel Trivi54d129f2021-12-30 17:43:47 -08003395 private final CallbackUtil.LazyListenerManager<OnModeChangedListener> mModeChangedListenerMgr =
3396 new CallbackUtil.LazyListenerManager();
Nate Myren08635fe2021-04-20 12:04:39 -07003397
Nate Myren08635fe2021-04-20 12:04:39 -07003398
Jean-Michel Trivi54d129f2021-12-30 17:43:47 -08003399 final class ModeDispatcherStub extends IAudioModeDispatcher.Stub
3400 implements CallbackUtil.DispatcherStub {
Jean-Michel Trivi91f0baa2021-11-11 16:31:32 -08003401
Jean-Michel Trivi54d129f2021-12-30 17:43:47 -08003402 @Override
Jean-Michel Trivi91f0baa2021-11-11 16:31:32 -08003403 public void register(boolean register) {
3404 try {
3405 if (register) {
3406 getService().registerModeDispatcher(this);
3407 } else {
3408 getService().unregisterModeDispatcher(this);
3409 }
3410 } catch (RemoteException e) {
3411 e.rethrowFromSystemServer();
3412 }
3413 }
Nate Myren08635fe2021-04-20 12:04:39 -07003414
3415 @Override
3416 public void dispatchAudioModeChanged(int mode) {
Jean-Michel Trivi54d129f2021-12-30 17:43:47 -08003417 mModeChangedListenerMgr.callListeners((listener) -> listener.onModeChanged(mode));
Nate Myren08635fe2021-04-20 12:04:39 -07003418 }
3419 }
3420
Nate Myren08635fe2021-04-20 12:04:39 -07003421 /**
3422 * Adds a listener to be notified of changes to the audio mode.
3423 * See {@link #getMode()}
3424 * @param executor
3425 * @param listener
3426 */
3427 public void addOnModeChangedListener(
3428 @NonNull @CallbackExecutor Executor executor,
3429 @NonNull OnModeChangedListener listener) {
Jean-Michel Trivi54d129f2021-12-30 17:43:47 -08003430 mModeChangedListenerMgr.addListener(executor, listener, "addOnModeChangedListener",
3431 () -> new ModeDispatcherStub());
Nate Myren08635fe2021-04-20 12:04:39 -07003432 }
3433
3434 /**
3435 * Removes a previously added listener for changes to audio mode.
3436 * See {@link #getMode()}
3437 * @param listener
3438 */
3439 public void removeOnModeChangedListener(@NonNull OnModeChangedListener listener) {
Jean-Michel Trivi54d129f2021-12-30 17:43:47 -08003440 mModeChangedListenerMgr.removeListener(listener, "removeOnModeChangedListener");
Nate Myren08635fe2021-04-20 12:04:39 -07003441 }
3442
3443 /**
Eric Laurent2d7197fc2019-11-06 10:17:06 -08003444 * Indicates if the platform supports a special call screening and call monitoring mode.
3445 * <p>
3446 * When this mode is supported, it is possible to perform call screening and monitoring
3447 * functions while other use cases like music or movie playback are active.
3448 * <p>
3449 * Use {@link #setMode(int)} with mode {@link #MODE_CALL_SCREENING} to place the platform in
3450 * call screening mode.
3451 * <p>
3452 * If call screening mode is not supported, setting mode to
3453 * MODE_CALL_SCREENING will be ignored and will not change current mode reported by
3454 * {@link #getMode()}.
3455 * @return true if call screening mode is supported, false otherwise.
3456 */
3457 public boolean isCallScreeningModeSupported() {
3458 final IAudioService service = getService();
3459 try {
3460 return service.isCallScreeningModeSupported();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003461 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07003462 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003463 }
3464 }
3465
3466 /* modes for setMode/getMode/setRoute/getRoute */
3467 /**
Becky Siegelbc9744f2024-03-18 22:20:20 +00003468 * Audio hardware modes.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003469 */
3470 /**
3471 * Invalid audio mode.
3472 */
3473 public static final int MODE_INVALID = AudioSystem.MODE_INVALID;
3474 /**
3475 * Current audio mode. Used to apply audio routing to current mode.
3476 */
3477 public static final int MODE_CURRENT = AudioSystem.MODE_CURRENT;
3478 /**
3479 * Normal audio mode: not ringing and no call established.
3480 */
3481 public static final int MODE_NORMAL = AudioSystem.MODE_NORMAL;
3482 /**
3483 * Ringing audio mode. An incoming is being signaled.
3484 */
3485 public static final int MODE_RINGTONE = AudioSystem.MODE_RINGTONE;
3486 /**
Jean-Michel Trivi8f677d62010-11-15 12:11:32 -08003487 * In call audio mode. A telephony call is established.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003488 */
3489 public static final int MODE_IN_CALL = AudioSystem.MODE_IN_CALL;
Jean-Michel Trivi8f677d62010-11-15 12:11:32 -08003490 /**
Jean-Michel Trivi8f677d62010-11-15 12:11:32 -08003491 * In communication audio mode. An audio/video chat or VoIP call is established.
3492 */
3493 public static final int MODE_IN_COMMUNICATION = AudioSystem.MODE_IN_COMMUNICATION;
Eric Laurent2d7197fc2019-11-06 10:17:06 -08003494 /**
3495 * Call screening in progress. Call is connected and audio is accessible to call
3496 * screening applications but other audio use cases are still possible.
3497 */
3498 public static final int MODE_CALL_SCREENING = AudioSystem.MODE_CALL_SCREENING;
3499
Eric Laurent1c3408f2021-11-09 12:09:54 +01003500 /**
3501 * A telephony call is established and its audio is being redirected to another device.
3502 */
3503 public static final int MODE_CALL_REDIRECT = AudioSystem.MODE_CALL_REDIRECT;
3504
3505 /**
Eric Laurent961cd3a2021-11-17 15:02:24 +01003506 * An audio/video chat or VoIP call is established and its audio is being redirected to another
Eric Laurent1c3408f2021-11-09 12:09:54 +01003507 * device.
3508 */
3509 public static final int MODE_COMMUNICATION_REDIRECT = AudioSystem.MODE_COMMUNICATION_REDIRECT;
3510
Eric Laurent2d7197fc2019-11-06 10:17:06 -08003511 /** @hide */
3512 @IntDef(flag = false, prefix = "MODE_", value = {
3513 MODE_NORMAL,
3514 MODE_RINGTONE,
3515 MODE_IN_CALL,
3516 MODE_IN_COMMUNICATION,
Eric Laurent1c3408f2021-11-09 12:09:54 +01003517 MODE_CALL_SCREENING,
3518 MODE_CALL_REDIRECT,
3519 MODE_COMMUNICATION_REDIRECT}
Eric Laurent2d7197fc2019-11-06 10:17:06 -08003520 )
3521 @Retention(RetentionPolicy.SOURCE)
3522 public @interface AudioMode {}
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003523
3524 /* Routing bits for setRouting/getRouting API */
3525 /**
3526 * Routing audio output to earpiece
Dianne Hackborn4a51c202009-08-21 15:14:02 -07003527 * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(),
3528 * setBluetoothScoOn() methods instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003529 */
Eric Laurenta553c252009-07-17 12:17:14 -07003530 @Deprecated public static final int ROUTE_EARPIECE = AudioSystem.ROUTE_EARPIECE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003531 /**
Dianne Hackborn4a51c202009-08-21 15:14:02 -07003532 * Routing audio output to speaker
3533 * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(),
3534 * setBluetoothScoOn() methods instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003535 */
Eric Laurenta553c252009-07-17 12:17:14 -07003536 @Deprecated public static final int ROUTE_SPEAKER = AudioSystem.ROUTE_SPEAKER;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003537 /**
3538 * @deprecated use {@link #ROUTE_BLUETOOTH_SCO}
Dianne Hackborn4a51c202009-08-21 15:14:02 -07003539 * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(),
3540 * setBluetoothScoOn() methods instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003541 */
3542 @Deprecated public static final int ROUTE_BLUETOOTH = AudioSystem.ROUTE_BLUETOOTH_SCO;
3543 /**
3544 * Routing audio output to bluetooth SCO
Dianne Hackborn4a51c202009-08-21 15:14:02 -07003545 * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(),
3546 * setBluetoothScoOn() methods instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003547 */
Eric Laurenta553c252009-07-17 12:17:14 -07003548 @Deprecated public static final int ROUTE_BLUETOOTH_SCO = AudioSystem.ROUTE_BLUETOOTH_SCO;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003549 /**
3550 * Routing audio output to headset
Dianne Hackborn4a51c202009-08-21 15:14:02 -07003551 * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(),
3552 * setBluetoothScoOn() methods instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003553 */
Eric Laurenta553c252009-07-17 12:17:14 -07003554 @Deprecated public static final int ROUTE_HEADSET = AudioSystem.ROUTE_HEADSET;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003555 /**
3556 * Routing audio output to bluetooth A2DP
Dianne Hackborn4a51c202009-08-21 15:14:02 -07003557 * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(),
3558 * setBluetoothScoOn() methods instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003559 */
Eric Laurenta553c252009-07-17 12:17:14 -07003560 @Deprecated public static final int ROUTE_BLUETOOTH_A2DP = AudioSystem.ROUTE_BLUETOOTH_A2DP;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003561 /**
3562 * Used for mask parameter of {@link #setRouting(int,int,int)}.
Dianne Hackborn4a51c202009-08-21 15:14:02 -07003563 * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(),
3564 * setBluetoothScoOn() methods instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003565 */
Eric Laurenta553c252009-07-17 12:17:14 -07003566 @Deprecated public static final int ROUTE_ALL = AudioSystem.ROUTE_ALL;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003567
3568 /**
3569 * Sets the audio routing for a specified mode
3570 *
3571 * @param mode audio mode to change route. E.g., MODE_RINGTONE.
3572 * @param routes bit vector of routes requested, created from one or
3573 * more of ROUTE_xxx types. Set bits indicate that route should be on
3574 * @param mask bit vector of routes to change, created from one or more of
3575 * ROUTE_xxx types. Unset bits indicate the route should be left unchanged
Eric Laurentb9c9d262009-05-06 08:13:20 -07003576 *
3577 * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(),
Eric Laurenta553c252009-07-17 12:17:14 -07003578 * setBluetoothScoOn() methods instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003579 */
Eric Laurenta553c252009-07-17 12:17:14 -07003580 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003581 public void setRouting(int mode, int routes, int mask) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003582 }
3583
3584 /**
3585 * Returns the current audio routing bit vector for a specified mode.
3586 *
3587 * @param mode audio mode to get route (e.g., MODE_RINGTONE)
3588 * @return an audio route bit vector that can be compared with ROUTE_xxx
3589 * bits
Eric Laurentb9c9d262009-05-06 08:13:20 -07003590 * @deprecated Do not query audio routing directly, use isSpeakerphoneOn(),
3591 * isBluetoothScoOn(), isBluetoothA2dpOn() and isWiredHeadsetOn() methods instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003592 */
Eric Laurentb9c9d262009-05-06 08:13:20 -07003593 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003594 public int getRouting(int mode) {
Eric Laurenta553c252009-07-17 12:17:14 -07003595 return -1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003596 }
3597
3598 /**
3599 * Checks whether any music is active.
3600 *
3601 * @return true if any music tracks are active.
3602 */
3603 public boolean isMusicActive() {
Jean-Michel Trivi15e30052020-12-09 11:54:00 -08003604 final IAudioService service = getService();
3605 try {
Eric Laurent89c3a972020-12-16 15:57:56 +01003606 return service.isMusicActive(false /*remotely*/);
Jean-Michel Trivi15e30052020-12-09 11:54:00 -08003607 } catch (RemoteException e) {
3608 throw e.rethrowFromSystemServer();
3609 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003610 }
3611
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003612 /**
3613 * @hide
Jean-Michel Trivi679d5042013-02-04 16:24:09 -08003614 * Checks whether any music or media is actively playing on a remote device (e.g. wireless
3615 * display). Note that BT audio sinks are not considered remote devices.
3616 * @return true if {@link AudioManager#STREAM_MUSIC} is active on a remote device
3617 */
Mathew Inwood8e742f92020-10-27 11:47:29 +00003618 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
Jean-Michel Trivi679d5042013-02-04 16:24:09 -08003619 public boolean isMusicActiveRemotely() {
Eric Laurent89c3a972020-12-16 15:57:56 +01003620 final IAudioService service = getService();
3621 try {
3622 return service.isMusicActive(true /*remotely*/);
3623 } catch (RemoteException e) {
3624 throw e.rethrowFromSystemServer();
3625 }
Jean-Michel Trivi679d5042013-02-04 16:24:09 -08003626 }
3627
3628 /**
3629 * @hide
Jean-Michel Trivi23805662013-07-31 14:19:18 -07003630 * Checks whether the current audio focus is exclusive.
3631 * @return true if the top of the audio focus stack requested focus
3632 * with {@link #AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE}
3633 */
3634 public boolean isAudioFocusExclusive() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003635 final IAudioService service = getService();
Jean-Michel Trivi23805662013-07-31 14:19:18 -07003636 try {
3637 return service.getCurrentAudioFocus() == AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE;
3638 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07003639 throw e.rethrowFromSystemServer();
Jean-Michel Trivi23805662013-07-31 14:19:18 -07003640 }
3641 }
3642
3643 /**
Jean-Michel Trivi8a21f5d2014-06-05 15:03:52 -07003644 * Return a new audio session identifier not associated with any player or effect.
Jean-Michel Trivi9e477e42014-08-25 17:44:28 -07003645 * An audio session identifier is a system wide unique identifier for a set of audio streams
3646 * (one or more mixed together).
3647 * <p>The primary use of the audio session ID is to associate audio effects to audio players,
3648 * such as {@link MediaPlayer} or {@link AudioTrack}: all audio effects sharing the same audio
3649 * session ID will be applied to the mixed audio content of the players that share the same
3650 * audio session.
3651 * <p>This method can for instance be used when creating one of the
3652 * {@link android.media.audiofx.AudioEffect} objects to define the audio session of the effect,
3653 * or to specify a session for a speech synthesis utterance
3654 * in {@link android.speech.tts.TextToSpeech.Engine}.
Jean-Michel Trivi8a21f5d2014-06-05 15:03:52 -07003655 * @return a new unclaimed and unused audio session identifier, or {@link #ERROR} when the
Jean-Michel Trivi9e477e42014-08-25 17:44:28 -07003656 * system failed to generate a new session, a condition in which audio playback or recording
3657 * will subsequently fail as well.
Jean-Michel Trivi8a21f5d2014-06-05 15:03:52 -07003658 */
Dichen Zhangf50b2362018-11-26 13:18:58 -08003659 public int generateAudioSessionId() {
Jean-Michel Trivi8a21f5d2014-06-05 15:03:52 -07003660 int session = AudioSystem.newAudioSessionId();
3661 if (session > 0) {
3662 return session;
3663 } else {
Jean-Michel Trivi289cc8e2014-07-18 18:45:32 -07003664 Log.e(TAG, "Failure to generate a new audio session ID");
Jean-Michel Trivi8a21f5d2014-06-05 15:03:52 -07003665 return ERROR;
3666 }
3667 }
3668
Jean-Michel Trivi289cc8e2014-07-18 18:45:32 -07003669 /**
3670 * A special audio session ID to indicate that the audio session ID isn't known and the
3671 * framework should generate a new value. This can be used when building a new
3672 * {@link AudioTrack} instance with
3673 * {@link AudioTrack#AudioTrack(AudioAttributes, AudioFormat, int, int, int)}.
3674 */
3675 public static final int AUDIO_SESSION_ID_GENERATE = AudioSystem.AUDIO_SESSION_ALLOCATE;
3676
Jean-Michel Trivi8a21f5d2014-06-05 15:03:52 -07003677
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003678 /*
3679 * Sets a generic audio configuration parameter. The use of these parameters
3680 * are platform dependant, see libaudio
3681 *
3682 * ** Temporary interface - DO NOT USE
3683 *
3684 * TODO: Replace with a more generic key:value get/set mechanism
3685 *
3686 * param key name of parameter to set. Must not be null.
3687 * param value value of parameter. Must not be null.
3688 */
3689 /**
3690 * @hide
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07003691 * @deprecated Use {@link #setParameters(String)} instead
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003692 */
Eric Laurenta553c252009-07-17 12:17:14 -07003693 @Deprecated public void setParameter(String key, String value) {
3694 setParameters(key+"="+value);
3695 }
3696
3697 /**
3698 * Sets a variable number of parameter values to audio hardware.
3699 *
3700 * @param keyValuePairs list of parameters key value pairs in the form:
3701 * key1=value1;key2=value2;...
3702 *
3703 */
3704 public void setParameters(String keyValuePairs) {
3705 AudioSystem.setParameters(keyValuePairs);
3706 }
3707
3708 /**
William Escandeef429b62021-10-15 18:37:40 +02003709 * @hide
3710 */
3711 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
Jean-Michel Trivic4557822023-01-23 18:19:52 +00003712 @RequiresPermission(Manifest.permission.BLUETOOTH_STACK)
William Escandeef429b62021-10-15 18:37:40 +02003713 public void setHfpEnabled(boolean enable) {
3714 AudioSystem.setParameters("hfp_enable=" + enable);
3715 }
3716
3717 /**
3718 * @hide
3719 */
3720 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
Jean-Michel Trivic4557822023-01-23 18:19:52 +00003721 @RequiresPermission(Manifest.permission.BLUETOOTH_STACK)
William Escandeef429b62021-10-15 18:37:40 +02003722 public void setHfpVolume(int volume) {
3723 AudioSystem.setParameters("hfp_volume=" + volume);
3724 }
3725
3726 /**
3727 * @hide
3728 */
3729 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
Jean-Michel Trivic4557822023-01-23 18:19:52 +00003730 @RequiresPermission(Manifest.permission.BLUETOOTH_STACK)
William Escandeef429b62021-10-15 18:37:40 +02003731 public void setHfpSamplingRate(int rate) {
3732 AudioSystem.setParameters("hfp_set_sampling_rate=" + rate);
3733 }
3734
3735 /**
3736 * @hide
3737 */
3738 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
Jean-Michel Trivic4557822023-01-23 18:19:52 +00003739 @RequiresPermission(Manifest.permission.BLUETOOTH_STACK)
William Escandeef429b62021-10-15 18:37:40 +02003740 public void setBluetoothHeadsetProperties(@NonNull String name, boolean hasNrecEnabled,
3741 boolean hasWbsEnabled) {
3742 AudioSystem.setParameters("bt_headset_name=" + name
3743 + ";bt_headset_nrec=" + (hasNrecEnabled ? "on" : "off")
3744 + ";bt_wbs=" + (hasWbsEnabled ? "on" : "off"));
3745 }
3746
3747 /**
3748 * @hide
3749 */
3750 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
Jean-Michel Trivic4557822023-01-23 18:19:52 +00003751 @RequiresPermission(Manifest.permission.BLUETOOTH_STACK)
William Escandeef429b62021-10-15 18:37:40 +02003752 public void setA2dpSuspended(boolean enable) {
Eric Laurent808993c2023-05-12 15:56:34 +02003753 final IAudioService service = getService();
3754 try {
3755 service.setA2dpSuspended(enable);
3756 } catch (RemoteException e) {
3757 throw e.rethrowFromSystemServer();
3758 }
William Escandeef429b62021-10-15 18:37:40 +02003759 }
3760
3761 /**
Rahul Sabnis215e5412022-12-21 16:03:07 -08003762 * Suspends the use of LE Audio.
3763 *
3764 * @param enable {@code true} to suspend le audio, {@code false} to unsuspend
3765 *
3766 * @hide
3767 */
3768 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
Jean-Michel Trivic4557822023-01-23 18:19:52 +00003769 @RequiresPermission(Manifest.permission.BLUETOOTH_STACK)
Rahul Sabnis215e5412022-12-21 16:03:07 -08003770 public void setLeAudioSuspended(boolean enable) {
Eric Laurent808993c2023-05-12 15:56:34 +02003771 final IAudioService service = getService();
3772 try {
3773 service.setLeAudioSuspended(enable);
3774 } catch (RemoteException e) {
3775 throw e.rethrowFromSystemServer();
3776 }
Rahul Sabnis215e5412022-12-21 16:03:07 -08003777 }
3778
3779 /**
John Spurlockaac753d2013-02-22 16:33:32 -05003780 * Gets a variable number of parameter values from audio hardware.
Eric Laurenta553c252009-07-17 12:17:14 -07003781 *
3782 * @param keys list of parameters
3783 * @return list of parameters key value pairs in the form:
3784 * key1=value1;key2=value2;...
3785 */
3786 public String getParameters(String keys) {
3787 return AudioSystem.getParameters(keys);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003788 }
3789
3790 /* Sound effect identifiers */
3791 /**
3792 * Keyboard and direction pad click sound
3793 * @see #playSoundEffect(int)
3794 */
3795 public static final int FX_KEY_CLICK = 0;
3796 /**
3797 * Focus has moved up
3798 * @see #playSoundEffect(int)
3799 */
3800 public static final int FX_FOCUS_NAVIGATION_UP = 1;
3801 /**
3802 * Focus has moved down
3803 * @see #playSoundEffect(int)
3804 */
3805 public static final int FX_FOCUS_NAVIGATION_DOWN = 2;
3806 /**
3807 * Focus has moved left
3808 * @see #playSoundEffect(int)
3809 */
3810 public static final int FX_FOCUS_NAVIGATION_LEFT = 3;
3811 /**
3812 * Focus has moved right
3813 * @see #playSoundEffect(int)
3814 */
3815 public static final int FX_FOCUS_NAVIGATION_RIGHT = 4;
3816 /**
3817 * IME standard keypress sound
3818 * @see #playSoundEffect(int)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003819 */
3820 public static final int FX_KEYPRESS_STANDARD = 5;
3821 /**
3822 * IME spacebar keypress sound
3823 * @see #playSoundEffect(int)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003824 */
3825 public static final int FX_KEYPRESS_SPACEBAR = 6;
3826 /**
3827 * IME delete keypress sound
3828 * @see #playSoundEffect(int)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003829 */
3830 public static final int FX_KEYPRESS_DELETE = 7;
3831 /**
3832 * IME return_keypress sound
3833 * @see #playSoundEffect(int)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003834 */
3835 public static final int FX_KEYPRESS_RETURN = 8;
Justin Kohcacfe692013-07-11 17:16:53 -07003836
3837 /**
3838 * Invalid keypress sound
3839 * @see #playSoundEffect(int)
3840 */
3841 public static final int FX_KEYPRESS_INVALID = 9;
Philip Junker7f1fdff2020-12-03 16:10:41 +01003842
3843 /**
3844 * Back sound
3845 * @see #playSoundEffect(int)
3846 */
3847 public static final int FX_BACK = 10;
3848
3849 /**
3850 * @hide Home sound
Philip Junker6d9a0962021-02-18 13:55:54 +01003851 * <p>
3852 * To be played by the framework when the home app becomes active if config_enableHomeSound is
3853 * set to true. This is currently only used on TV devices.
Philip Junker7f1fdff2020-12-03 16:10:41 +01003854 * Note that this sound is only available if a sound file is specified in audio_assets.xml.
3855 * @see #playSoundEffect(int)
3856 */
3857 public static final int FX_HOME = 11;
3858
3859 /**
Philip Junker6d9a0962021-02-18 13:55:54 +01003860 * @hide Navigation repeat sound 1
3861 * <p>
3862 * To be played by the framework when a focus navigation is repeatedly triggered
3863 * (e.g. due to long-pressing) and {@link #areNavigationRepeatSoundEffectsEnabled()} is true.
Philip Junker7f1fdff2020-12-03 16:10:41 +01003864 * This is currently only used on TV devices.
3865 * Note that this sound is only available if a sound file is specified in audio_assets.xml
3866 * @see #playSoundEffect(int)
3867 */
Philip Junker6d9a0962021-02-18 13:55:54 +01003868 public static final int FX_FOCUS_NAVIGATION_REPEAT_1 = 12;
Philip Junker7f1fdff2020-12-03 16:10:41 +01003869
3870 /**
Philip Junker6d9a0962021-02-18 13:55:54 +01003871 * @hide Navigation repeat sound 2
3872 * <p>
3873 * To be played by the framework when a focus navigation is repeatedly triggered
3874 * (e.g. due to long-pressing) and {@link #areNavigationRepeatSoundEffectsEnabled()} is true.
Philip Junker7f1fdff2020-12-03 16:10:41 +01003875 * This is currently only used on TV devices.
3876 * Note that this sound is only available if a sound file is specified in audio_assets.xml
3877 * @see #playSoundEffect(int)
3878 */
Philip Junker6d9a0962021-02-18 13:55:54 +01003879 public static final int FX_FOCUS_NAVIGATION_REPEAT_2 = 13;
Philip Junker7f1fdff2020-12-03 16:10:41 +01003880
3881 /**
Philip Junker6d9a0962021-02-18 13:55:54 +01003882 * @hide Navigation repeat sound 3
3883 * <p>
3884 * To be played by the framework when a focus navigation is repeatedly triggered
3885 * (e.g. due to long-pressing) and {@link #areNavigationRepeatSoundEffectsEnabled()} is true.
Philip Junker7f1fdff2020-12-03 16:10:41 +01003886 * This is currently only used on TV devices.
3887 * Note that this sound is only available if a sound file is specified in audio_assets.xml
3888 * @see #playSoundEffect(int)
3889 */
Philip Junker6d9a0962021-02-18 13:55:54 +01003890 public static final int FX_FOCUS_NAVIGATION_REPEAT_3 = 14;
Philip Junker7f1fdff2020-12-03 16:10:41 +01003891
3892 /**
Philip Junker6d9a0962021-02-18 13:55:54 +01003893 * @hide Navigation repeat sound 4
3894 * <p>
3895 * To be played by the framework when a focus navigation is repeatedly triggered
3896 * (e.g. due to long-pressing) and {@link #areNavigationRepeatSoundEffectsEnabled()} is true.
Philip Junker7f1fdff2020-12-03 16:10:41 +01003897 * This is currently only used on TV devices.
3898 * Note that this sound is only available if a sound file is specified in audio_assets.xml
3899 * @see #playSoundEffect(int)
3900 */
Philip Junker6d9a0962021-02-18 13:55:54 +01003901 public static final int FX_FOCUS_NAVIGATION_REPEAT_4 = 15;
Philip Junker7f1fdff2020-12-03 16:10:41 +01003902
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003903 /**
3904 * @hide Number of sound effects
3905 */
Mathew Inwood8e742f92020-10-27 11:47:29 +00003906 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
Philip Junker7f1fdff2020-12-03 16:10:41 +01003907 public static final int NUM_SOUND_EFFECTS = 16;
3908
Philip Junkerdfcb12b2021-03-17 19:38:50 +01003909 /** @hide */
3910 @IntDef(prefix = { "FX_" }, value = {
3911 FX_KEY_CLICK,
3912 FX_FOCUS_NAVIGATION_UP,
3913 FX_FOCUS_NAVIGATION_DOWN,
3914 FX_FOCUS_NAVIGATION_LEFT,
3915 FX_FOCUS_NAVIGATION_RIGHT,
3916 FX_KEYPRESS_STANDARD,
3917 FX_KEYPRESS_SPACEBAR,
3918 FX_KEYPRESS_DELETE,
3919 FX_KEYPRESS_RETURN,
3920 FX_KEYPRESS_INVALID,
3921 FX_BACK
3922 })
3923 @Retention(RetentionPolicy.SOURCE)
3924 public @interface SystemSoundEffect {}
3925
Philip Junker7f1fdff2020-12-03 16:10:41 +01003926 /**
Philip Junker6d9a0962021-02-18 13:55:54 +01003927 * @hide Number of FX_FOCUS_NAVIGATION_REPEAT_* sound effects
Philip Junker7f1fdff2020-12-03 16:10:41 +01003928 */
Philip Junker6d9a0962021-02-18 13:55:54 +01003929 public static final int NUM_NAVIGATION_REPEAT_SOUND_EFFECTS = 4;
Philip Junker7f1fdff2020-12-03 16:10:41 +01003930
3931 /**
3932 * @hide
Philip Junker6d9a0962021-02-18 13:55:54 +01003933 * @param n a value in [0, {@link #NUM_NAVIGATION_REPEAT_SOUND_EFFECTS}[
3934 * @return The id of a navigation repeat sound effect or -1 if out of bounds
Philip Junker7f1fdff2020-12-03 16:10:41 +01003935 */
Philip Junker6d9a0962021-02-18 13:55:54 +01003936 public static int getNthNavigationRepeatSoundEffect(int n) {
Philip Junker7f1fdff2020-12-03 16:10:41 +01003937 switch (n) {
3938 case 0:
Philip Junker6d9a0962021-02-18 13:55:54 +01003939 return FX_FOCUS_NAVIGATION_REPEAT_1;
Philip Junker7f1fdff2020-12-03 16:10:41 +01003940 case 1:
Philip Junker6d9a0962021-02-18 13:55:54 +01003941 return FX_FOCUS_NAVIGATION_REPEAT_2;
Philip Junker7f1fdff2020-12-03 16:10:41 +01003942 case 2:
Philip Junker6d9a0962021-02-18 13:55:54 +01003943 return FX_FOCUS_NAVIGATION_REPEAT_3;
Philip Junker7f1fdff2020-12-03 16:10:41 +01003944 case 3:
Philip Junker6d9a0962021-02-18 13:55:54 +01003945 return FX_FOCUS_NAVIGATION_REPEAT_4;
Philip Junker7f1fdff2020-12-03 16:10:41 +01003946 default:
Philip Junker6d9a0962021-02-18 13:55:54 +01003947 Log.w(TAG, "Invalid navigation repeat sound effect id: " + n);
Philip Junker7f1fdff2020-12-03 16:10:41 +01003948 return -1;
3949 }
3950 }
3951
3952 /**
3953 * @hide
3954 */
Philip Junker6d9a0962021-02-18 13:55:54 +01003955 public void setNavigationRepeatSoundEffectsEnabled(boolean enabled) {
Philip Junker7f1fdff2020-12-03 16:10:41 +01003956 try {
Philip Junker6d9a0962021-02-18 13:55:54 +01003957 getService().setNavigationRepeatSoundEffectsEnabled(enabled);
Philip Junker7f1fdff2020-12-03 16:10:41 +01003958 } catch (RemoteException e) {
3959
3960 }
3961 }
3962
3963 /**
3964 * @hide
Philip Junker6d9a0962021-02-18 13:55:54 +01003965 * @return true if the navigation repeat sound effects are enabled
Philip Junker7f1fdff2020-12-03 16:10:41 +01003966 */
Philip Junker6d9a0962021-02-18 13:55:54 +01003967 public boolean areNavigationRepeatSoundEffectsEnabled() {
Philip Junker7f1fdff2020-12-03 16:10:41 +01003968 try {
Philip Junker6d9a0962021-02-18 13:55:54 +01003969 return getService().areNavigationRepeatSoundEffectsEnabled();
Philip Junker7f1fdff2020-12-03 16:10:41 +01003970 } catch (RemoteException e) {
3971 throw e.rethrowFromSystemServer();
3972 }
3973 }
3974
3975 /**
3976 * @hide
3977 * @param enabled
3978 */
3979 public void setHomeSoundEffectEnabled(boolean enabled) {
3980 try {
3981 getService().setHomeSoundEffectEnabled(enabled);
3982 } catch (RemoteException e) {
3983
3984 }
3985 }
3986
3987 /**
3988 * @hide
3989 * @return true if the home sound effect is enabled
3990 */
3991 public boolean isHomeSoundEffectEnabled() {
3992 try {
3993 return getService().isHomeSoundEffectEnabled();
3994 } catch (RemoteException e) {
3995 throw e.rethrowFromSystemServer();
3996 }
3997 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003998
3999 /**
4000 * Plays a sound effect (Key clicks, lid open/close...)
Philip Junkerdfcb12b2021-03-17 19:38:50 +01004001 * @param effectType The type of sound effect.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004002 * NOTE: This version uses the UI settings to determine
4003 * whether sounds are heard or not.
4004 */
Philip Junkerdfcb12b2021-03-17 19:38:50 +01004005 public void playSoundEffect(@SystemSoundEffect int effectType) {
Oscar Azucena21f2c4d2021-10-26 18:06:54 -07004006 playSoundEffect(effectType, UserHandle.USER_CURRENT);
Jason Monk0c37ba32014-09-08 15:34:23 -04004007 }
4008
4009 /**
4010 * Plays a sound effect (Key clicks, lid open/close...)
Philip Junkerdfcb12b2021-03-17 19:38:50 +01004011 * @param effectType The type of sound effect.
Jason Monk0c37ba32014-09-08 15:34:23 -04004012 * @param userId The current user to pull sound settings from
4013 * NOTE: This version uses the UI settings to determine
4014 * whether sounds are heard or not.
4015 * @hide
4016 */
Jan Sebechlebskyfb48c022022-12-16 16:26:47 +01004017 public void playSoundEffect(@SystemSoundEffect int effectType, int userId) {
Jason Monk0c37ba32014-09-08 15:34:23 -04004018 if (effectType < 0 || effectType >= NUM_SOUND_EFFECTS) {
4019 return;
4020 }
4021
Jan Sebechlebskyfb48c022022-12-16 16:26:47 +01004022 if (delegateSoundEffectToVdm(effectType)) {
4023 return;
4024 }
4025
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004026 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004027 try {
Oscar Azucena21f2c4d2021-10-26 18:06:54 -07004028 service.playSoundEffect(effectType, userId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004029 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07004030 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004031 }
4032 }
4033
4034 /**
4035 * Plays a sound effect (Key clicks, lid open/close...)
Philip Junkerdfcb12b2021-03-17 19:38:50 +01004036 * @param effectType The type of sound effect.
Eric Laurenta2ef57d2009-09-28 04:46:10 -07004037 * @param volume Sound effect volume.
4038 * The volume value is a raw scalar so UI controls should be scaled logarithmically.
4039 * If a volume of -1 is specified, the AudioManager.STREAM_MUSIC stream volume minus 3dB will be used.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004040 * NOTE: This version is for applications that have their own
4041 * settings panel for enabling and controlling volume.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004042 */
Jan Sebechlebskyfb48c022022-12-16 16:26:47 +01004043 public void playSoundEffect(@SystemSoundEffect int effectType, float volume) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004044 if (effectType < 0 || effectType >= NUM_SOUND_EFFECTS) {
4045 return;
4046 }
4047
Jan Sebechlebskyfb48c022022-12-16 16:26:47 +01004048 if (delegateSoundEffectToVdm(effectType)) {
4049 return;
4050 }
4051
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004052 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004053 try {
4054 service.playSoundEffectVolume(effectType, volume);
4055 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07004056 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004057 }
4058 }
4059
4060 /**
Ján Sebechlebskýdcc49642023-02-07 10:20:59 +00004061 * Checks whether this {@link AudioManager} instance is associated with {@link VirtualDevice}
Jan Sebechlebskyfb48c022022-12-16 16:26:47 +01004062 * configured with custom device policy for audio. If there is such device, request to play
4063 * sound effect is forwarded to {@link VirtualDeviceManager}.
4064 *
4065 * @param effectType - The type of sound effect.
4066 * @return true if the request was forwarded to {@link VirtualDeviceManager} instance,
4067 * false otherwise.
4068 */
4069 private boolean delegateSoundEffectToVdm(@SystemSoundEffect int effectType) {
Ján Sebechlebskýdcc49642023-02-07 10:20:59 +00004070 if (hasCustomPolicyVirtualDeviceContext()) {
Jan Sebechlebskyfb48c022022-12-16 16:26:47 +01004071 VirtualDeviceManager vdm = getVirtualDeviceManager();
tyiu9ac1adb2024-06-07 02:39:11 +00004072 if (vdm != null) {
4073 vdm.playSoundEffect(mOriginalContextDeviceId, effectType);
4074 return true;
4075 }
Jan Sebechlebskyfb48c022022-12-16 16:26:47 +01004076 }
4077 return false;
4078 }
4079
Ján Sebechlebskýdcc49642023-02-07 10:20:59 +00004080 private boolean hasCustomPolicyVirtualDeviceContext() {
4081 if (mOriginalContextDeviceId == DEVICE_ID_DEFAULT) {
4082 return false;
4083 }
4084
4085 VirtualDeviceManager vdm = getVirtualDeviceManager();
4086 return vdm != null && vdm.getDevicePolicy(mOriginalContextDeviceId, POLICY_TYPE_AUDIO)
4087 != DEVICE_POLICY_DEFAULT;
4088 }
4089
Jan Sebechlebskyfb48c022022-12-16 16:26:47 +01004090 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004091 * Load Sound effects.
4092 * This method must be called when sound effects are enabled.
4093 */
4094 public void loadSoundEffects() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004095 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004096 try {
4097 service.loadSoundEffects();
4098 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07004099 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004100 }
4101 }
4102
4103 /**
4104 * Unload Sound effects.
4105 * This method can be called to free some memory when
4106 * sound effects are disabled.
4107 */
4108 public void unloadSoundEffects() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004109 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004110 try {
4111 service.unloadSoundEffects();
4112 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07004113 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004114 }
4115 }
4116
Eric Laurent4050c932009-07-08 02:52:14 -07004117 /**
Andy Hung69836952020-03-26 01:00:15 -07004118 * @hide
4119 */
4120 public static String audioFocusToString(int focus) {
4121 switch (focus) {
4122 case AUDIOFOCUS_NONE:
4123 return "AUDIOFOCUS_NONE";
4124 case AUDIOFOCUS_GAIN:
4125 return "AUDIOFOCUS_GAIN";
4126 case AUDIOFOCUS_GAIN_TRANSIENT:
4127 return "AUDIOFOCUS_GAIN_TRANSIENT";
4128 case AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK:
4129 return "AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK";
4130 case AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE:
4131 return "AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE";
4132 case AUDIOFOCUS_LOSS:
4133 return "AUDIOFOCUS_LOSS";
4134 case AUDIOFOCUS_LOSS_TRANSIENT:
4135 return "AUDIOFOCUS_LOSS_TRANSIENT";
4136 case AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK: // Note CAN_DUCK not MAY_DUCK.
4137 return "AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK";
4138 default:
4139 return "AUDIO_FOCUS_UNKNOWN(" + focus + ")";
4140 }
4141 }
4142
4143 /**
Jean-Michel Trivi0f49f822017-02-16 14:36:43 -08004144 * Used to indicate no audio focus has been gained or lost, or requested.
Jean-Michel Trivi23805662013-07-31 14:19:18 -07004145 */
4146 public static final int AUDIOFOCUS_NONE = 0;
4147
4148 /**
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004149 * Used to indicate a gain of audio focus, or a request of audio focus, of unknown duration.
Jean-Michel Trivi7f7e67f2010-03-31 11:30:24 -07004150 * @see OnAudioFocusChangeListener#onAudioFocusChange(int)
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004151 * @see #requestAudioFocus(OnAudioFocusChangeListener, int, int)
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004152 */
4153 public static final int AUDIOFOCUS_GAIN = 1;
4154 /**
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004155 * Used to indicate a temporary gain or request of audio focus, anticipated to last a short
4156 * amount of time. Examples of temporary changes are the playback of driving directions, or an
4157 * event notification.
Jean-Michel Trivi7f7e67f2010-03-31 11:30:24 -07004158 * @see OnAudioFocusChangeListener#onAudioFocusChange(int)
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004159 * @see #requestAudioFocus(OnAudioFocusChangeListener, int, int)
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004160 */
4161 public static final int AUDIOFOCUS_GAIN_TRANSIENT = 2;
Jean-Michel Trivi078fd472010-03-18 16:51:04 -07004162 /**
Jean-Michel Trivi078fd472010-03-18 16:51:04 -07004163 * Used to indicate a temporary request of audio focus, anticipated to last a short
Jean-Michel Trivi983ac2b2010-03-19 12:09:25 -07004164 * amount of time, and where it is acceptable for other audio applications to keep playing
4165 * after having lowered their output level (also referred to as "ducking").
Jean-Michel Trivi078fd472010-03-18 16:51:04 -07004166 * Examples of temporary changes are the playback of driving directions where playback of music
4167 * in the background is acceptable.
Jean-Michel Trivi7f7e67f2010-03-31 11:30:24 -07004168 * @see OnAudioFocusChangeListener#onAudioFocusChange(int)
Jean-Michel Trivi078fd472010-03-18 16:51:04 -07004169 * @see #requestAudioFocus(OnAudioFocusChangeListener, int, int)
4170 */
4171 public static final int AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK = 3;
4172 /**
Jean-Michel Trivi23805662013-07-31 14:19:18 -07004173 * Used to indicate a temporary request of audio focus, anticipated to last a short
4174 * amount of time, during which no other applications, or system components, should play
4175 * anything. Examples of exclusive and transient audio focus requests are voice
4176 * memo recording and speech recognition, during which the system shouldn't play any
4177 * notifications, and media playback should have paused.
4178 * @see #requestAudioFocus(OnAudioFocusChangeListener, int, int)
4179 */
4180 public static final int AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE = 4;
4181 /**
Jean-Michel Trivi078fd472010-03-18 16:51:04 -07004182 * Used to indicate a loss of audio focus of unknown duration.
Jean-Michel Trivi7f7e67f2010-03-31 11:30:24 -07004183 * @see OnAudioFocusChangeListener#onAudioFocusChange(int)
Jean-Michel Trivi078fd472010-03-18 16:51:04 -07004184 */
4185 public static final int AUDIOFOCUS_LOSS = -1 * AUDIOFOCUS_GAIN;
4186 /**
4187 * Used to indicate a transient loss of audio focus.
Jean-Michel Trivi7f7e67f2010-03-31 11:30:24 -07004188 * @see OnAudioFocusChangeListener#onAudioFocusChange(int)
Jean-Michel Trivi078fd472010-03-18 16:51:04 -07004189 */
4190 public static final int AUDIOFOCUS_LOSS_TRANSIENT = -1 * AUDIOFOCUS_GAIN_TRANSIENT;
4191 /**
Jean-Michel Trivi078fd472010-03-18 16:51:04 -07004192 * Used to indicate a transient loss of audio focus where the loser of the audio focus can
Jean-Michel Trivi983ac2b2010-03-19 12:09:25 -07004193 * lower its output volume if it wants to continue playing (also referred to as "ducking"), as
4194 * the new focus owner doesn't require others to be silent.
Jean-Michel Trivi7f7e67f2010-03-31 11:30:24 -07004195 * @see OnAudioFocusChangeListener#onAudioFocusChange(int)
Jean-Michel Trivi078fd472010-03-18 16:51:04 -07004196 */
4197 public static final int AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK =
4198 -1 * AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK;
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004199
4200 /**
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004201 * Interface definition for a callback to be invoked when the audio focus of the system is
4202 * updated.
4203 */
4204 public interface OnAudioFocusChangeListener {
4205 /**
4206 * Called on the listener to notify it the audio focus for this listener has been changed.
4207 * The focusChange value indicates whether the focus was gained,
4208 * whether the focus was lost, and whether that loss is transient, or whether the new focus
4209 * holder will hold it for an unknown amount of time.
Jean-Michel Trivi983ac2b2010-03-19 12:09:25 -07004210 * When losing focus, listeners can use the focus change information to decide what
4211 * behavior to adopt when losing focus. A music player could for instance elect to lower
4212 * the volume of its music stream (duck) for transient focus losses, and pause otherwise.
4213 * @param focusChange the type of focus change, one of {@link AudioManager#AUDIOFOCUS_GAIN},
Jean-Michel Trivi078fd472010-03-18 16:51:04 -07004214 * {@link AudioManager#AUDIOFOCUS_LOSS}, {@link AudioManager#AUDIOFOCUS_LOSS_TRANSIENT}
Jean-Michel Trivi983ac2b2010-03-19 12:09:25 -07004215 * and {@link AudioManager#AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK}.
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004216 */
Jean-Michel Trivi7f7e67f2010-03-31 11:30:24 -07004217 public void onAudioFocusChange(int focusChange);
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004218 }
4219
4220 /**
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004221 * Internal class to hold the AudioFocusRequest as well as the Handler for the callback
4222 */
4223 private static class FocusRequestInfo {
4224 @NonNull final AudioFocusRequest mRequest;
4225 @Nullable final Handler mHandler;
4226 FocusRequestInfo(@NonNull AudioFocusRequest afr, @Nullable Handler handler) {
4227 mRequest = afr;
4228 mHandler = handler;
4229 }
4230 }
4231
4232 /**
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004233 * Map to convert focus event listener IDs, as used in the AudioService audio focus stack,
4234 * to actual listener objects.
4235 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01004236 @UnsupportedAppUsage
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004237 private final ConcurrentHashMap<String, FocusRequestInfo> mAudioFocusIdListenerMap =
4238 new ConcurrentHashMap<String, FocusRequestInfo>();
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004239
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004240 private FocusRequestInfo findFocusRequestInfo(String id) {
Jean-Michel Trivid327f212010-03-16 21:44:33 -07004241 return mAudioFocusIdListenerMap.get(id);
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004242 }
4243
4244 /**
Jean-Michel Trivi3b61d2d2016-01-07 10:50:09 -08004245 * Handler for events (audio focus change, recording config change) coming from the
4246 * audio service.
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004247 */
Jean-Michel Trivi3b61d2d2016-01-07 10:50:09 -08004248 private final ServiceEventHandlerDelegate mServiceEventHandlerDelegate =
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08004249 new ServiceEventHandlerDelegate(null);
Jean-Michel Trivi078fd472010-03-18 16:51:04 -07004250
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004251 /**
Jean-Michel Trivi3b61d2d2016-01-07 10:50:09 -08004252 * Event types
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004253 */
Jean-Michel Trivi3b61d2d2016-01-07 10:50:09 -08004254 private final static int MSSG_FOCUS_CHANGE = 0;
4255 private final static int MSSG_RECORDING_CONFIG_CHANGE = 1;
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -08004256 private final static int MSSG_PLAYBACK_CONFIG_CHANGE = 2;
Jean-Michel Trivi3b61d2d2016-01-07 10:50:09 -08004257
4258 /**
4259 * Helper class to handle the forwarding of audio service events to the appropriate listener
4260 */
4261 private class ServiceEventHandlerDelegate {
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004262 private final Handler mHandler;
4263
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08004264 ServiceEventHandlerDelegate(Handler handler) {
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004265 Looper looper;
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08004266 if (handler == null) {
4267 if ((looper = Looper.myLooper()) == null) {
4268 looper = Looper.getMainLooper();
4269 }
4270 } else {
4271 looper = handler.getLooper();
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004272 }
4273
4274 if (looper != null) {
Jean-Michel Trivi3b61d2d2016-01-07 10:50:09 -08004275 // implement the event handler delegate to receive events from audio service
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004276 mHandler = new Handler(looper) {
4277 @Override
4278 public void handleMessage(Message msg) {
Jean-Michel Trivi3b61d2d2016-01-07 10:50:09 -08004279 switch (msg.what) {
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -08004280 case MSSG_FOCUS_CHANGE: {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004281 final FocusRequestInfo fri = findFocusRequestInfo((String)msg.obj);
4282 if (fri != null) {
4283 final OnAudioFocusChangeListener listener =
4284 fri.mRequest.getOnAudioFocusChangeListener();
4285 if (listener != null) {
4286 Log.d(TAG, "dispatching onAudioFocusChange("
4287 + msg.arg1 + ") to " + msg.obj);
4288 listener.onAudioFocusChange(msg.arg1);
4289 }
Jean-Michel Trivi3b61d2d2016-01-07 10:50:09 -08004290 }
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -08004291 } break;
4292 case MSSG_RECORDING_CONFIG_CHANGE: {
Jean-Michel Trivi28ff76b2016-03-02 09:36:30 -08004293 final RecordConfigChangeCallbackData cbData =
4294 (RecordConfigChangeCallbackData) msg.obj;
4295 if (cbData.mCb != null) {
Jean-Michel Trivie6a505b2016-04-01 09:56:28 -07004296 cbData.mCb.onRecordingConfigChanged(cbData.mConfigs);
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08004297 }
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -08004298 } break;
4299 case MSSG_PLAYBACK_CONFIG_CHANGE: {
4300 final PlaybackConfigChangeCallbackData cbData =
4301 (PlaybackConfigChangeCallbackData) msg.obj;
4302 if (cbData.mCb != null) {
4303 if (DEBUG) {
4304 Log.d(TAG, "dispatching onPlaybackConfigChanged()");
4305 }
4306 cbData.mCb.onPlaybackConfigChanged(cbData.mConfigs);
4307 }
4308 } break;
Jean-Michel Trivi3b61d2d2016-01-07 10:50:09 -08004309 default:
4310 Log.e(TAG, "Unknown event " + msg.what);
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004311 }
4312 }
4313 };
4314 } else {
4315 mHandler = null;
4316 }
4317 }
4318
4319 Handler getHandler() {
4320 return mHandler;
4321 }
4322 }
4323
Glenn Kasten30c918c2011-11-10 17:56:41 -08004324 private final IAudioFocusDispatcher mAudioFocusDispatcher = new IAudioFocusDispatcher.Stub() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004325 @Override
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004326 public void dispatchAudioFocusChange(int focusChange, String id) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004327 final FocusRequestInfo fri = findFocusRequestInfo(id);
4328 if (fri != null) {
4329 final OnAudioFocusChangeListener listener =
4330 fri.mRequest.getOnAudioFocusChangeListener();
4331 if (listener != null) {
4332 final Handler h = (fri.mHandler == null) ?
4333 mServiceEventHandlerDelegate.getHandler() : fri.mHandler;
4334 final Message m = h.obtainMessage(
4335 MSSG_FOCUS_CHANGE/*what*/, focusChange/*arg1*/, 0/*arg2 ignored*/,
4336 id/*obj*/);
4337 h.sendMessage(m);
4338 }
4339 }
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004340 }
Jean-Michel Trivie2d8aae2018-01-30 15:09:47 -08004341
4342 @Override
4343 public void dispatchFocusResultFromExtPolicy(int requestResult, String clientId) {
4344 synchronized (mFocusRequestsLock) {
4345 // TODO use generation counter as the key instead
4346 final BlockingFocusResultReceiver focusReceiver =
4347 mFocusRequestsAwaitingResult.remove(clientId);
4348 if (focusReceiver != null) {
4349 focusReceiver.notifyResult(requestResult);
4350 } else {
4351 Log.e(TAG, "dispatchFocusResultFromExtPolicy found no result receiver");
4352 }
4353 }
4354 }
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004355 };
4356
Jean-Michel Trivid327f212010-03-16 21:44:33 -07004357 private String getIdForAudioFocusListener(OnAudioFocusChangeListener l) {
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004358 if (l == null) {
Jean-Michel Trivi308e9a52010-03-17 15:04:20 -07004359 return new String(this.toString());
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004360 } else {
4361 return new String(this.toString() + l.toString());
4362 }
4363 }
4364
4365 /**
Xavier Ducrohet5f53f082010-05-11 14:19:40 -07004366 * @hide
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004367 * Registers a listener to be called when audio focus changes and keeps track of the associated
4368 * focus request (including Handler to use for the listener).
4369 * @param afr the full request parameters
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004370 */
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004371 public void registerAudioFocusRequest(@NonNull AudioFocusRequest afr) {
4372 final Handler h = afr.getOnAudioFocusChangeListenerHandler();
4373 final FocusRequestInfo fri = new FocusRequestInfo(afr, (h == null) ? null :
4374 new ServiceEventHandlerDelegate(h).getHandler());
4375 final String key = getIdForAudioFocusListener(afr.getOnAudioFocusChangeListener());
4376 mAudioFocusIdListenerMap.put(key, fri);
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004377 }
4378
4379 /**
Xavier Ducrohet5f53f082010-05-11 14:19:40 -07004380 * @hide
Jean-Michel Trivi46b3a182010-05-11 11:22:54 -07004381 * Causes the specified listener to not be called anymore when focus is gained or lost.
4382 * @param l the listener to unregister.
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004383 */
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004384 public void unregisterAudioFocusRequest(OnAudioFocusChangeListener l) {
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004385 // remove locally
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004386 mAudioFocusIdListenerMap.remove(getIdForAudioFocusListener(l));
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004387 }
4388
4389
4390 /**
Jean-Michel Trivi46b3a182010-05-11 11:22:54 -07004391 * A failed focus change request.
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004392 */
4393 public static final int AUDIOFOCUS_REQUEST_FAILED = 0;
4394 /**
Jean-Michel Trivi46b3a182010-05-11 11:22:54 -07004395 * A successful focus change request.
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004396 */
4397 public static final int AUDIOFOCUS_REQUEST_GRANTED = 1;
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004398 /**
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004399 * A focus change request whose granting is delayed: the request was successful, but the
4400 * requester will only be granted audio focus once the condition that prevented immediate
4401 * granting has ended.
Jean-Michel Trivi3db31ac2017-02-24 11:40:37 -08004402 * See {@link #requestAudioFocus(AudioFocusRequest)} and
4403 * {@link AudioFocusRequest.Builder#setAcceptsDelayedFocusGain(boolean)}
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004404 */
4405 public static final int AUDIOFOCUS_REQUEST_DELAYED = 2;
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004406
Jean-Michel Trivie2d8aae2018-01-30 15:09:47 -08004407 /** @hide */
4408 @IntDef(flag = false, prefix = "AUDIOFOCUS_REQUEST", value = {
4409 AUDIOFOCUS_REQUEST_FAILED,
4410 AUDIOFOCUS_REQUEST_GRANTED,
4411 AUDIOFOCUS_REQUEST_DELAYED }
4412 )
4413 @Retention(RetentionPolicy.SOURCE)
4414 public @interface FocusRequestResult {}
4415
4416 /**
4417 * @hide
4418 * code returned when a synchronous focus request on the client-side is to be blocked
4419 * until the external audio focus policy decides on the response for the client
4420 */
4421 public static final int AUDIOFOCUS_REQUEST_WAITING_FOR_EXT_POLICY = 100;
4422
4423 /**
4424 * Timeout duration in ms when waiting on an external focus policy for the result for a
4425 * focus request
4426 */
Weilin Xu1017d432022-06-08 00:27:52 +00004427 private static final int EXT_FOCUS_POLICY_TIMEOUT_MS = 250;
Jean-Michel Trivie2d8aae2018-01-30 15:09:47 -08004428
4429 private static final String FOCUS_CLIENT_ID_STRING = "android_audio_focus_client_id";
4430
4431 private final Object mFocusRequestsLock = new Object();
4432 /**
4433 * Map of all receivers of focus request results, one per unresolved focus request.
4434 * Receivers are added before sending the request to the external focus policy,
4435 * and are removed either after receiving the result, or after the timeout.
4436 * This variable is lazily initialized.
4437 */
4438 @GuardedBy("mFocusRequestsLock")
4439 private HashMap<String, BlockingFocusResultReceiver> mFocusRequestsAwaitingResult;
4440
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004441
4442 /**
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004443 * Request audio focus.
Jean-Michel Trivi46b3a182010-05-11 11:22:54 -07004444 * Send a request to obtain the audio focus
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004445 * @param l the listener to be notified of audio focus changes
4446 * @param streamType the main audio stream type affected by the focus request
4447 * @param durationHint use {@link #AUDIOFOCUS_GAIN_TRANSIENT} to indicate this focus request
4448 * is temporary, and focus will be abandonned shortly. Examples of transient requests are
Jean-Michel Trivi078fd472010-03-18 16:51:04 -07004449 * for the playback of driving directions, or notifications sounds.
Jean-Michel Trivi983ac2b2010-03-19 12:09:25 -07004450 * Use {@link #AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK} to indicate also that it's ok for
4451 * the previous focus owner to keep playing if it ducks its audio output.
Jean-Michel Trivi9171db22013-07-31 17:11:12 -07004452 * Alternatively use {@link #AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE} for a temporary request
4453 * that benefits from the system not playing disruptive sounds like notifications, for
4454 * usecases such as voice memo recording, or speech recognition.
Jean-Michel Trivi078fd472010-03-18 16:51:04 -07004455 * Use {@link #AUDIOFOCUS_GAIN} for a focus request of unknown duration such
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004456 * as the playback of a song or a video.
4457 * @return {@link #AUDIOFOCUS_REQUEST_FAILED} or {@link #AUDIOFOCUS_REQUEST_GRANTED}
Jean-Michel Trivi36bdb662017-03-09 11:56:51 -08004458 * @deprecated use {@link #requestAudioFocus(AudioFocusRequest)}
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004459 */
4460 public int requestAudioFocus(OnAudioFocusChangeListener l, int streamType, int durationHint) {
Jean-Michel Trivi36bdb662017-03-09 11:56:51 -08004461 PlayerBase.deprecateStreamTypeForPlayback(streamType,
4462 "AudioManager", "requestAudioFocus()");
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004463 int status = AUDIOFOCUS_REQUEST_FAILED;
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004464
4465 try {
4466 // status is guaranteed to be either AUDIOFOCUS_REQUEST_FAILED or
4467 // AUDIOFOCUS_REQUEST_GRANTED as focus is requested without the
4468 // AUDIOFOCUS_FLAG_DELAY_OK flag
4469 status = requestAudioFocus(l,
4470 new AudioAttributes.Builder()
4471 .setInternalLegacyStreamType(streamType).build(),
4472 durationHint,
4473 0 /* flags, legacy behavior */);
4474 } catch (IllegalArgumentException e) {
4475 Log.e(TAG, "Audio focus request denied due to ", e);
4476 }
4477
4478 return status;
4479 }
4480
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004481 // when adding new flags, add them to the relevant AUDIOFOCUS_FLAGS_APPS or SYSTEM masks
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08004482 /**
4483 * @hide
4484 * Use this flag when requesting audio focus to indicate it is ok for the requester to not be
4485 * granted audio focus immediately (as indicated by {@link #AUDIOFOCUS_REQUEST_DELAYED}) when
4486 * the system is in a state where focus cannot change, but be granted focus later when
4487 * this condition ends.
4488 */
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004489 @SystemApi
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004490 public static final int AUDIOFOCUS_FLAG_DELAY_OK = 0x1 << 0;
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08004491 /**
4492 * @hide
4493 * Use this flag when requesting audio focus to indicate that the requester
4494 * will pause its media playback (if applicable) when losing audio focus with
4495 * {@link #AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK}, rather than ducking.
4496 * <br>On some platforms, the ducking may be handled without the application being aware of it
4497 * (i.e. it will not transiently lose focus). For applications that for instance play spoken
4498 * content, such as audio book or podcast players, ducking may never be acceptable, and will
4499 * thus always pause. This flag enables them to be declared as such whenever they request focus.
4500 */
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004501 @SystemApi
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08004502 public static final int AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS = 0x1 << 1;
4503 /**
4504 * @hide
4505 * Use this flag to lock audio focus so granting is temporarily disabled.
4506 * <br>This flag can only be used by owners of a registered
4507 * {@link android.media.audiopolicy.AudioPolicy} in
4508 * {@link #requestAudioFocus(OnAudioFocusChangeListener, AudioAttributes, int, int, AudioPolicy)}
4509 */
4510 @SystemApi
4511 public static final int AUDIOFOCUS_FLAG_LOCK = 0x1 << 2;
Jean-Michel Trivi28602092021-03-24 11:14:47 -07004512
4513 /**
4514 * @hide
4515 * flag set on test API calls,
4516 * see {@link #requestAudioFocusForTest(AudioFocusRequest, String, int, int)},
Jean-Michel Trivibec223b2021-12-08 18:40:08 -08004517 */
Jean-Michel Trivi28602092021-03-24 11:14:47 -07004518 public static final int AUDIOFOCUS_FLAG_TEST = 0x1 << 3;
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004519 /** @hide */
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08004520 public static final int AUDIOFOCUS_FLAGS_APPS = AUDIOFOCUS_FLAG_DELAY_OK
4521 | AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS;
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004522 /** @hide */
4523 public static final int AUDIOFOCUS_FLAGS_SYSTEM = AUDIOFOCUS_FLAG_DELAY_OK
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08004524 | AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS | AUDIOFOCUS_FLAG_LOCK;
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004525
4526 /**
Jean-Michel Trivi3db31ac2017-02-24 11:40:37 -08004527 * Request audio focus.
4528 * See the {@link AudioFocusRequest} for information about the options available to configure
4529 * your request, and notification of focus gain and loss.
4530 * @param focusRequest a {@link AudioFocusRequest} instance used to configure how focus is
4531 * requested.
4532 * @return {@link #AUDIOFOCUS_REQUEST_FAILED}, {@link #AUDIOFOCUS_REQUEST_GRANTED}
4533 * or {@link #AUDIOFOCUS_REQUEST_DELAYED}.
4534 * <br>Note that the return value is never {@link #AUDIOFOCUS_REQUEST_DELAYED} when focus
4535 * is requested without building the {@link AudioFocusRequest} with
4536 * {@link AudioFocusRequest.Builder#setAcceptsDelayedFocusGain(boolean)} set to
4537 * {@code true}.
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004538 * @throws NullPointerException if passed a null argument
Jean-Michel Trivi3db31ac2017-02-24 11:40:37 -08004539 */
4540 public int requestAudioFocus(@NonNull AudioFocusRequest focusRequest) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004541 return requestAudioFocus(focusRequest, null /* no AudioPolicy*/);
Jean-Michel Trivi3db31ac2017-02-24 11:40:37 -08004542 }
4543
4544 /**
4545 * Abandon audio focus. Causes the previous focus owner, if any, to receive focus.
4546 * @param focusRequest the {@link AudioFocusRequest} that was used when requesting focus
4547 * with {@link #requestAudioFocus(AudioFocusRequest)}.
4548 * @return {@link #AUDIOFOCUS_REQUEST_FAILED} or {@link #AUDIOFOCUS_REQUEST_GRANTED}
4549 * @throws IllegalArgumentException if passed a null argument
4550 */
4551 public int abandonAudioFocusRequest(@NonNull AudioFocusRequest focusRequest) {
4552 if (focusRequest == null) {
4553 throw new IllegalArgumentException("Illegal null AudioFocusRequest");
4554 }
4555 return abandonAudioFocus(focusRequest.getOnAudioFocusChangeListener(),
4556 focusRequest.getAudioAttributes());
4557 }
4558
4559 /**
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004560 * @hide
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004561 * Request audio focus.
4562 * Send a request to obtain the audio focus. This method differs from
4563 * {@link #requestAudioFocus(OnAudioFocusChangeListener, int, int)} in that it can express
4564 * that the requester accepts delayed grants of audio focus.
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004565 * @param l the listener to be notified of audio focus changes. It is not allowed to be null
4566 * when the request is flagged with {@link #AUDIOFOCUS_FLAG_DELAY_OK}.
4567 * @param requestAttributes non null {@link AudioAttributes} describing the main reason for
4568 * requesting audio focus.
4569 * @param durationHint use {@link #AUDIOFOCUS_GAIN_TRANSIENT} to indicate this focus request
4570 * is temporary, and focus will be abandonned shortly. Examples of transient requests are
4571 * for the playback of driving directions, or notifications sounds.
4572 * Use {@link #AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK} to indicate also that it's ok for
4573 * the previous focus owner to keep playing if it ducks its audio output.
4574 * Alternatively use {@link #AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE} for a temporary request
4575 * that benefits from the system not playing disruptive sounds like notifications, for
4576 * usecases such as voice memo recording, or speech recognition.
4577 * Use {@link #AUDIOFOCUS_GAIN} for a focus request of unknown duration such
4578 * as the playback of a song or a video.
Jean-Michel Trivi26ae15f2017-08-25 19:20:49 -07004579 * @param flags 0 or a combination of {link #AUDIOFOCUS_FLAG_DELAY_OK},
4580 * {@link #AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS} and {@link #AUDIOFOCUS_FLAG_LOCK}.
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004581 * <br>Use 0 when not using any flags for the request, which behaves like
4582 * {@link #requestAudioFocus(OnAudioFocusChangeListener, int, int)}, where either audio
4583 * focus is granted immediately, or the grant request fails because the system is in a
4584 * state where focus cannot change (e.g. a phone call).
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004585 * @return {@link #AUDIOFOCUS_REQUEST_FAILED}, {@link #AUDIOFOCUS_REQUEST_GRANTED}
4586 * or {@link #AUDIOFOCUS_REQUEST_DELAYED}.
4587 * The return value is never {@link #AUDIOFOCUS_REQUEST_DELAYED} when focus is requested
4588 * without the {@link #AUDIOFOCUS_FLAG_DELAY_OK} flag.
4589 * @throws IllegalArgumentException
4590 */
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004591 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00004592 @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004593 public int requestAudioFocus(OnAudioFocusChangeListener l,
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004594 @NonNull AudioAttributes requestAttributes,
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004595 int durationHint,
4596 int flags) throws IllegalArgumentException {
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004597 if (flags != (flags & AUDIOFOCUS_FLAGS_APPS)) {
4598 throw new IllegalArgumentException("Invalid flags 0x"
4599 + Integer.toHexString(flags).toUpperCase());
4600 }
4601 return requestAudioFocus(l, requestAttributes, durationHint,
4602 flags & AUDIOFOCUS_FLAGS_APPS,
4603 null /* no AudioPolicy*/);
4604 }
4605
4606 /**
4607 * @hide
4608 * Request or lock audio focus.
4609 * This method is to be used by system components that have registered an
4610 * {@link android.media.audiopolicy.AudioPolicy} to request audio focus, but also to "lock" it
4611 * so focus granting is temporarily disabled.
4612 * @param l see the description of the same parameter in
4613 * {@link #requestAudioFocus(OnAudioFocusChangeListener, AudioAttributes, int, int)}
4614 * @param requestAttributes non null {@link AudioAttributes} describing the main reason for
4615 * requesting audio focus.
4616 * @param durationHint see the description of the same parameter in
4617 * {@link #requestAudioFocus(OnAudioFocusChangeListener, AudioAttributes, int, int)}
4618 * @param flags 0 or a combination of {link #AUDIOFOCUS_FLAG_DELAY_OK},
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08004619 * {@link #AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS}, and {@link #AUDIOFOCUS_FLAG_LOCK}.
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004620 * <br>Use 0 when not using any flags for the request, which behaves like
4621 * {@link #requestAudioFocus(OnAudioFocusChangeListener, int, int)}, where either audio
4622 * focus is granted immediately, or the grant request fails because the system is in a
4623 * state where focus cannot change (e.g. a phone call).
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004624 * @param ap a registered {@link android.media.audiopolicy.AudioPolicy} instance when locking
4625 * focus, or null.
4626 * @return see the description of the same return value in
4627 * {@link #requestAudioFocus(OnAudioFocusChangeListener, AudioAttributes, int, int)}
4628 * @throws IllegalArgumentException
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004629 * @deprecated use {@link #requestAudioFocus(AudioFocusRequest, AudioPolicy)}
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004630 */
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08004631 @SystemApi
Jean-Michel Trivi26ae15f2017-08-25 19:20:49 -07004632 @RequiresPermission(anyOf= {
Jean-Michel Trivic4557822023-01-23 18:19:52 +00004633 Manifest.permission.MODIFY_PHONE_STATE,
4634 Manifest.permission.MODIFY_AUDIO_ROUTING
Jean-Michel Trivi26ae15f2017-08-25 19:20:49 -07004635 })
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004636 public int requestAudioFocus(OnAudioFocusChangeListener l,
4637 @NonNull AudioAttributes requestAttributes,
4638 int durationHint,
4639 int flags,
4640 AudioPolicy ap) throws IllegalArgumentException {
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004641 // parameter checking
4642 if (requestAttributes == null) {
4643 throw new IllegalArgumentException("Illegal null AudioAttributes argument");
4644 }
Jean-Michel Trivi3db31ac2017-02-24 11:40:37 -08004645 if (!AudioFocusRequest.isValidFocusGain(durationHint)) {
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004646 throw new IllegalArgumentException("Invalid duration hint");
Jean-Michel Trivi55d1bb32010-04-01 17:40:58 -07004647 }
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004648 if (flags != (flags & AUDIOFOCUS_FLAGS_SYSTEM)) {
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004649 throw new IllegalArgumentException("Illegal flags 0x"
4650 + Integer.toHexString(flags).toUpperCase());
4651 }
4652 if (((flags & AUDIOFOCUS_FLAG_DELAY_OK) == AUDIOFOCUS_FLAG_DELAY_OK) && (l == null)) {
4653 throw new IllegalArgumentException(
4654 "Illegal null focus listener when flagged as accepting delayed focus grant");
4655 }
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004656 if (((flags & AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS)
4657 == AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS) && (l == null)) {
4658 throw new IllegalArgumentException(
4659 "Illegal null focus listener when flagged as pausing instead of ducking");
4660 }
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004661 if (((flags & AUDIOFOCUS_FLAG_LOCK) == AUDIOFOCUS_FLAG_LOCK) && (ap == null)) {
4662 throw new IllegalArgumentException(
4663 "Illegal null audio policy when locking audio focus");
4664 }
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004665
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004666 final AudioFocusRequest afr = new AudioFocusRequest.Builder(durationHint)
Jean-Michel Trivi36728ce2017-05-01 12:33:40 -07004667 .setOnAudioFocusChangeListenerInt(l, null /* no Handler for this legacy API */)
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004668 .setAudioAttributes(requestAttributes)
4669 .setAcceptsDelayedFocusGain((flags & AUDIOFOCUS_FLAG_DELAY_OK)
4670 == AUDIOFOCUS_FLAG_DELAY_OK)
4671 .setWillPauseWhenDucked((flags & AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS)
4672 == AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS)
4673 .setLocksFocus((flags & AUDIOFOCUS_FLAG_LOCK) == AUDIOFOCUS_FLAG_LOCK)
4674 .build();
4675 return requestAudioFocus(afr, ap);
4676 }
4677
4678 /**
4679 * @hide
Jean-Michel Trivi28602092021-03-24 11:14:47 -07004680 * Test API to request audio focus for an arbitrary client operating from a (fake) given UID.
4681 * Used to simulate conditions of the test, not the behavior of the focus requester under test.
4682 * @param afr the parameters of the request
4683 * @param clientFakeId the identifier of the AudioManager the client would be requesting from
4684 * @param clientFakeUid the UID of the client, here an arbitrary int,
4685 * doesn't have to be a real UID
4686 * @param clientTargetSdk the target SDK used by the client
4687 * @return return code indicating status of the request
4688 */
4689 @TestApi
4690 @RequiresPermission("android.permission.QUERY_AUDIO_STATE")
4691 public @FocusRequestResult int requestAudioFocusForTest(@NonNull AudioFocusRequest afr,
4692 @NonNull String clientFakeId, int clientFakeUid, int clientTargetSdk) {
4693 Objects.requireNonNull(afr);
4694 Objects.requireNonNull(clientFakeId);
Oscar Azucena3209c342022-05-13 19:08:14 -07004695 int status;
Weilin Xu1017d432022-06-08 00:27:52 +00004696 BlockingFocusResultReceiver focusReceiver;
4697 synchronized (mFocusRequestsLock) {
Raj Goparaju3c6536f42023-10-03 07:15:02 -07004698 try {
4699 status = getService().requestAudioFocusForTest(afr.getAudioAttributes(),
4700 afr.getFocusGain(),
4701 mICallBack,
4702 mAudioFocusDispatcher,
4703 clientFakeId, "com.android.test.fakeclient",
4704 afr.getFlags() | AudioManager.AUDIOFOCUS_FLAG_TEST,
4705 clientFakeUid, clientTargetSdk);
4706 } catch (RemoteException e) {
4707 throw e.rethrowFromSystemServer();
4708 }
4709 if (status != AudioManager.AUDIOFOCUS_REQUEST_WAITING_FOR_EXT_POLICY) {
4710 // default path with no external focus policy
4711 return status;
4712 }
4713
Weilin Xu1017d432022-06-08 00:27:52 +00004714 focusReceiver = addClientIdToFocusReceiverLocked(clientFakeId);
4715 }
4716
4717 return handleExternalAudioPolicyWaitIfNeeded(clientFakeId, focusReceiver);
Jean-Michel Trivi28602092021-03-24 11:14:47 -07004718 }
4719
4720 /**
4721 * @hide
4722 * Test API to abandon audio focus for an arbitrary client.
4723 * Used to simulate conditions of the test, not the behavior of the focus requester under test.
4724 * @param afr the parameters used for the request
4725 * @param clientFakeId clientFakeId the identifier of the AudioManager from which the client
4726 * would be requesting
4727 * @return return code indicating status of the request
4728 */
4729 @TestApi
4730 @RequiresPermission("android.permission.QUERY_AUDIO_STATE")
4731 public @FocusRequestResult int abandonAudioFocusForTest(@NonNull AudioFocusRequest afr,
4732 @NonNull String clientFakeId) {
4733 Objects.requireNonNull(afr);
4734 Objects.requireNonNull(clientFakeId);
4735 try {
4736 return getService().abandonAudioFocusForTest(mAudioFocusDispatcher,
4737 clientFakeId, afr.getAudioAttributes(), "com.android.test.fakeclient");
4738 } catch (RemoteException e) {
4739 throw e.rethrowFromSystemServer();
4740 }
4741 }
4742
4743 /**
4744 * @hide
4745 * Return the duration of the fade out applied when a player of the given AudioAttributes
4746 * is losing audio focus
4747 * @param aa the AudioAttributes of the player losing focus with {@link #AUDIOFOCUS_LOSS}
4748 * @return a duration in ms, 0 indicates no fade out is applied
4749 */
4750 @TestApi
4751 @RequiresPermission("android.permission.QUERY_AUDIO_STATE")
4752 public @IntRange(from = 0) long getFadeOutDurationOnFocusLossMillis(@NonNull AudioAttributes aa)
4753 {
4754 Objects.requireNonNull(aa);
4755 try {
4756 return getService().getFadeOutDurationOnFocusLossMillis(aa);
4757 } catch (RemoteException e) {
4758 throw e.rethrowFromSystemServer();
4759 }
4760 }
4761
4762 /**
4763 * @hide
Jean-Michel Trivia95a78f2023-06-26 18:51:19 -07004764 * Test method to return the list of UIDs currently marked as ducked because of their
4765 * audio focus status
4766 * @return the list of UIDs, can be empty when no app is being ducked.
4767 */
4768 @TestApi
Jean-Michel Trivid31ca2a2023-10-02 14:32:07 -07004769 @FlaggedApi(FLAG_FOCUS_FREEZE_TEST_API)
Jean-Michel Trivia95a78f2023-06-26 18:51:19 -07004770 @RequiresPermission("android.permission.QUERY_AUDIO_STATE")
4771 public @NonNull List<Integer> getFocusDuckedUidsForTest() {
4772 try {
4773 return getService().getFocusDuckedUidsForTest();
4774 } catch (RemoteException e) {
4775 throw e.rethrowFromSystemServer();
4776 }
4777 }
4778
4779 /**
4780 * @hide
4781 * Test method to return the duration of the fade out applied on the players of a focus loser
4782 * @return the fade out duration in ms
4783 */
4784 @TestApi
Jean-Michel Trivid31ca2a2023-10-02 14:32:07 -07004785 @FlaggedApi(FLAG_FOCUS_FREEZE_TEST_API)
Jean-Michel Trivia95a78f2023-06-26 18:51:19 -07004786 @RequiresPermission("android.permission.QUERY_AUDIO_STATE")
4787 public long getFocusFadeOutDurationForTest() {
4788 try {
4789 return getService().getFocusFadeOutDurationForTest();
4790 } catch (RemoteException e) {
4791 throw e.rethrowFromSystemServer();
4792 }
4793 }
4794
4795 /**
4796 * @hide
4797 * Test method to return the length of time after a fade-out before the focus loser is unmuted
4798 * (and is faded back in).
4799 * @return the time gap after a fade-out completion on focus loss, and fade-in start in ms.
4800 */
4801 @TestApi
Jean-Michel Trivid31ca2a2023-10-02 14:32:07 -07004802 @FlaggedApi(FLAG_FOCUS_FREEZE_TEST_API)
Jean-Michel Trivia95a78f2023-06-26 18:51:19 -07004803 @RequiresPermission("android.permission.QUERY_AUDIO_STATE")
4804 public long getFocusUnmuteDelayAfterFadeOutForTest() {
4805 try {
4806 return getService().getFocusUnmuteDelayAfterFadeOutForTest();
4807 } catch (RemoteException e) {
4808 throw e.rethrowFromSystemServer();
4809 }
4810 }
4811
4812 /**
4813 * @hide
4814 * Test method to start preventing applications from requesting audio focus during a test,
4815 * which could interfere with the functionality/behavior under test.
4816 * Calling this method needs to be paired with a call to {@link #exitAudioFocusFreezeForTest}
4817 * when the testing is done. If this is not the case (e.g. in case of a test crash),
4818 * a death observer mechanism will ensure the system is not left in a bad state, but this should
4819 * not be relied on when implementing tests.
4820 * @param exemptedUids a list of UIDs that are exempt from the freeze. This would for instance
4821 * be those of the test runner and other players used in the test, or the "fake" UIDs used
4822 * for testing with {@link #requestAudioFocusForTest(AudioFocusRequest, String, int, int)}.
4823 * @return true if the focus freeze mode is successfully entered, false if there was an issue,
4824 * such as another freeze in place at the time of invocation.
4825 * A false result should result in a test failure as this would indicate the system is not
4826 * in a proper state with a predictable behavior for audio focus management.
4827 */
4828 @TestApi
Jean-Michel Trivid31ca2a2023-10-02 14:32:07 -07004829 @FlaggedApi(FLAG_FOCUS_FREEZE_TEST_API)
Jean-Michel Trivia95a78f2023-06-26 18:51:19 -07004830 @RequiresPermission("Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED")
4831 public boolean enterAudioFocusFreezeForTest(@NonNull List<Integer> exemptedUids) {
4832 Objects.requireNonNull(exemptedUids);
4833 try {
4834 final int[] uids = exemptedUids.stream().mapToInt(Integer::intValue).toArray();
4835 return getService().enterAudioFocusFreezeForTest(mICallBack, uids);
4836 } catch (RemoteException e) {
4837 throw e.rethrowFromSystemServer();
4838 }
4839 }
4840
4841 /**
4842 * @hide
4843 * Test method to end preventing applications from requesting audio focus during a test.
4844 * @return true if the focus freeze mode is successfully exited, false if there was an issue,
4845 * such as the freeze already having ended, or not started.
4846 */
4847 @TestApi
Jean-Michel Trivid31ca2a2023-10-02 14:32:07 -07004848 @FlaggedApi(FLAG_FOCUS_FREEZE_TEST_API)
Jean-Michel Trivia95a78f2023-06-26 18:51:19 -07004849 @RequiresPermission("Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED")
4850 public boolean exitAudioFocusFreezeForTest() {
4851 try {
4852 return getService().exitAudioFocusFreezeForTest(mICallBack);
4853 } catch (RemoteException e) {
4854 throw e.rethrowFromSystemServer();
4855 }
4856 }
4857
4858 /**
4859 * @hide
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004860 * Request or lock audio focus.
4861 * This method is to be used by system components that have registered an
4862 * {@link android.media.audiopolicy.AudioPolicy} to request audio focus, but also to "lock" it
4863 * so focus granting is temporarily disabled.
4864 * @param afr see the description of the same parameter in
4865 * {@link #requestAudioFocus(AudioFocusRequest)}
4866 * @param ap a registered {@link android.media.audiopolicy.AudioPolicy} instance when locking
4867 * focus, or null.
4868 * @return {@link #AUDIOFOCUS_REQUEST_FAILED}, {@link #AUDIOFOCUS_REQUEST_GRANTED}
4869 * or {@link #AUDIOFOCUS_REQUEST_DELAYED}.
4870 * @throws NullPointerException if the AudioFocusRequest is null
4871 * @throws IllegalArgumentException when trying to lock focus without an AudioPolicy
4872 */
4873 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00004874 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004875 public int requestAudioFocus(@NonNull AudioFocusRequest afr, @Nullable AudioPolicy ap) {
4876 if (afr == null) {
4877 throw new NullPointerException("Illegal null AudioFocusRequest");
4878 }
4879 // this can only be checked now, not during the creation of the AudioFocusRequest instance
4880 if (afr.locksFocus() && ap == null) {
4881 throw new IllegalArgumentException(
4882 "Illegal null audio policy when locking audio focus");
4883 }
Ján Sebechlebskýdcc49642023-02-07 10:20:59 +00004884
4885 if (hasCustomPolicyVirtualDeviceContext()) {
4886 // If the focus request was made within context associated with VirtualDevice
4887 // configured with custom device policy for audio, bypass audio service focus handling.
4888 // The custom device policy for audio means that audio associated with this device
4889 // is likely rerouted to VirtualAudioDevice and playback on the VirtualAudioDevice
4890 // shouldn't affect non-virtual audio tracks (and vice versa).
4891 return AUDIOFOCUS_REQUEST_GRANTED;
4892 }
4893
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004894 registerAudioFocusRequest(afr);
4895 final IAudioService service = getService();
4896 final int status;
Jean-Michel Trivi461922f2017-04-25 15:23:17 -07004897 int sdk;
4898 try {
4899 sdk = getContext().getApplicationInfo().targetSdkVersion;
4900 } catch (NullPointerException e) {
4901 // some tests don't have a Context
4902 sdk = Build.VERSION.SDK_INT;
4903 }
Jean-Michel Trivie2d8aae2018-01-30 15:09:47 -08004904
4905 final String clientId = getIdForAudioFocusListener(afr.getOnAudioFocusChangeListener());
Weilin Xu1017d432022-06-08 00:27:52 +00004906 BlockingFocusResultReceiver focusReceiver;
Jean-Michel Trivie2d8aae2018-01-30 15:09:47 -08004907 synchronized (mFocusRequestsLock) {
Weilin Xu1017d432022-06-08 00:27:52 +00004908
Jean-Michel Trivie2d8aae2018-01-30 15:09:47 -08004909 try {
4910 // TODO status contains result and generation counter for ext policy
4911 status = service.requestAudioFocus(afr.getAudioAttributes(),
4912 afr.getFocusGain(), mICallBack,
4913 mAudioFocusDispatcher,
4914 clientId,
John Wu4f7e5102021-06-22 17:29:11 +00004915 getContext().getOpPackageName() /* package name */,
4916 getContext().getAttributionTag(),
4917 afr.getFlags(),
Jean-Michel Trivie2d8aae2018-01-30 15:09:47 -08004918 ap != null ? ap.cb() : null,
4919 sdk);
4920 } catch (RemoteException e) {
4921 throw e.rethrowFromSystemServer();
4922 }
Weilin Xu1017d432022-06-08 00:27:52 +00004923 if (status != AudioManager.AUDIOFOCUS_REQUEST_WAITING_FOR_EXT_POLICY) {
4924 // default path with no external focus policy
4925 return status;
4926 }
4927 focusReceiver = addClientIdToFocusReceiverLocked(clientId);
Oscar Azucena3209c342022-05-13 19:08:14 -07004928 }
4929
Weilin Xu1017d432022-06-08 00:27:52 +00004930 return handleExternalAudioPolicyWaitIfNeeded(clientId, focusReceiver);
4931 }
4932
4933 @GuardedBy("mFocusRequestsLock")
4934 private BlockingFocusResultReceiver addClientIdToFocusReceiverLocked(String clientId) {
4935 BlockingFocusResultReceiver focusReceiver;
4936 if (mFocusRequestsAwaitingResult == null) {
4937 mFocusRequestsAwaitingResult =
4938 new HashMap<String, BlockingFocusResultReceiver>(1);
4939 }
4940 focusReceiver = new BlockingFocusResultReceiver(clientId);
4941 mFocusRequestsAwaitingResult.put(clientId, focusReceiver);
4942 return focusReceiver;
Oscar Azucena3209c342022-05-13 19:08:14 -07004943 }
4944
4945 private @FocusRequestResult int handleExternalAudioPolicyWaitIfNeeded(String clientId,
Weilin Xu1017d432022-06-08 00:27:52 +00004946 BlockingFocusResultReceiver focusReceiver) {
Jean-Michel Trivie2d8aae2018-01-30 15:09:47 -08004947 focusReceiver.waitForResult(EXT_FOCUS_POLICY_TIMEOUT_MS);
4948 if (DEBUG && !focusReceiver.receivedResult()) {
Oscar Azucena3209c342022-05-13 19:08:14 -07004949 Log.e(TAG, "handleExternalAudioPolicyWaitIfNeeded"
4950 + " response from ext policy timed out, denying request");
Jean-Michel Trivie2d8aae2018-01-30 15:09:47 -08004951 }
Oscar Azucena3209c342022-05-13 19:08:14 -07004952
Jean-Michel Trivie2d8aae2018-01-30 15:09:47 -08004953 synchronized (mFocusRequestsLock) {
4954 mFocusRequestsAwaitingResult.remove(clientId);
4955 }
4956 return focusReceiver.requestResult();
4957 }
4958
4959 // helper class that abstracts out the handling of spurious wakeups in Object.wait()
4960 private static final class SafeWaitObject {
4961 private boolean mQuit = false;
4962
4963 public void safeNotify() {
4964 synchronized (this) {
4965 mQuit = true;
4966 this.notify();
4967 }
4968 }
4969
4970 public void safeWait(long millis) throws InterruptedException {
4971 final long timeOutTime = java.lang.System.currentTimeMillis() + millis;
4972 synchronized (this) {
4973 while (!mQuit) {
4974 final long timeToWait = timeOutTime - java.lang.System.currentTimeMillis();
Shunkai Yao6b1f22f2023-08-31 22:36:28 +00004975 if (timeToWait <= 0) {
4976 break;
4977 }
Jean-Michel Trivie2d8aae2018-01-30 15:09:47 -08004978 this.wait(timeToWait);
4979 }
4980 }
4981 }
4982 }
4983
4984 private static final class BlockingFocusResultReceiver {
4985 private final SafeWaitObject mLock = new SafeWaitObject();
4986 @GuardedBy("mLock")
4987 private boolean mResultReceived = false;
4988 // request denied by default (e.g. timeout)
4989 private int mFocusRequestResult = AudioManager.AUDIOFOCUS_REQUEST_FAILED;
4990 private final String mFocusClientId;
4991
4992 BlockingFocusResultReceiver(String clientId) {
4993 mFocusClientId = clientId;
4994 }
4995
4996 boolean receivedResult() { return mResultReceived; }
4997 int requestResult() { return mFocusRequestResult; }
4998
4999 void notifyResult(int requestResult) {
5000 synchronized (mLock) {
5001 mResultReceived = true;
5002 mFocusRequestResult = requestResult;
5003 mLock.safeNotify();
5004 }
5005 }
5006
5007 public void waitForResult(long timeOutMs) {
5008 synchronized (mLock) {
5009 if (mResultReceived) {
5010 // the result was received before waiting
5011 return;
5012 }
5013 try {
5014 mLock.safeWait(timeOutMs);
5015 } catch (InterruptedException e) { }
5016 }
5017 }
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08005018 }
5019
Jean-Michel Trivi4dd36742012-01-24 09:52:39 -08005020 /**
5021 * @hide
5022 * Used internally by telephony package to request audio focus. Will cause the focus request
5023 * to be associated with the "voice communication" identifier only used in AudioService
5024 * to identify this use case.
5025 * @param streamType use STREAM_RING for focus requests when ringing, VOICE_CALL for
5026 * the establishment of the call
5027 * @param durationHint the type of focus request. AUDIOFOCUS_GAIN_TRANSIENT is recommended so
5028 * media applications resume after a call
5029 */
Mathew Inwood8e742f92020-10-27 11:47:29 +00005030 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
Jean-Michel Trivi4dd36742012-01-24 09:52:39 -08005031 public void requestAudioFocusForCall(int streamType, int durationHint) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07005032 final IAudioService service = getService();
Jean-Michel Trivi4dd36742012-01-24 09:52:39 -08005033 try {
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08005034 service.requestAudioFocus(new AudioAttributes.Builder()
5035 .setInternalLegacyStreamType(streamType).build(),
5036 durationHint, mICallBack, null,
John Spurlock61560172015-02-06 19:46:04 -05005037 AudioSystem.IN_VOICE_COMM_FOCUS_ID,
Marco Nelissen29f16932015-04-17 09:50:56 -07005038 getContext().getOpPackageName(),
John Wu4f7e5102021-06-22 17:29:11 +00005039 getContext().getAttributionTag(),
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08005040 AUDIOFOCUS_FLAG_LOCK,
Jean-Michel Trivi461922f2017-04-25 15:23:17 -07005041 null /* policy token */, 0 /* sdk n/a here*/);
Jean-Michel Trivi4dd36742012-01-24 09:52:39 -08005042 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07005043 throw e.rethrowFromSystemServer();
Jean-Michel Trivi4dd36742012-01-24 09:52:39 -08005044 }
5045 }
5046
5047 /**
5048 * @hide
Jean-Michel Trivi99489cc2017-01-25 19:08:49 -08005049 * Return the volume ramping time for a sound to be played after the given focus request,
5050 * and to play a sound of the given attributes
5051 * @param focusGain
5052 * @param attr
5053 * @return
5054 */
5055 public int getFocusRampTimeMs(int focusGain, AudioAttributes attr) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07005056 final IAudioService service = getService();
Jean-Michel Trivi99489cc2017-01-25 19:08:49 -08005057 try {
5058 return service.getFocusRampTimeMs(focusGain, attr);
5059 } catch (RemoteException e) {
5060 throw e.rethrowFromSystemServer();
5061 }
5062 }
5063
5064 /**
5065 * @hide
Jean-Michel Trivie2d8aae2018-01-30 15:09:47 -08005066 * Set the result to the audio focus request received through
5067 * {@link AudioPolicyFocusListener#onAudioFocusRequest(AudioFocusInfo, int)}.
5068 * @param afi the information about the focus requester
5069 * @param requestResult the result to the focus request to be passed to the requester
5070 * @param ap a valid registered {@link AudioPolicy} configured as a focus policy.
5071 */
5072 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00005073 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
Jean-Michel Trivie2d8aae2018-01-30 15:09:47 -08005074 public void setFocusRequestResult(@NonNull AudioFocusInfo afi,
5075 @FocusRequestResult int requestResult, @NonNull AudioPolicy ap) {
5076 if (afi == null) {
5077 throw new IllegalArgumentException("Illegal null AudioFocusInfo");
5078 }
5079 if (ap == null) {
5080 throw new IllegalArgumentException("Illegal null AudioPolicy");
5081 }
5082 final IAudioService service = getService();
5083 try {
5084 service.setFocusRequestResultFromExtPolicy(afi, requestResult, ap.cb());
5085 } catch (RemoteException e) {
5086 throw e.rethrowFromSystemServer();
5087 }
5088 }
5089
5090 /**
5091 * @hide
Jean-Michel Trivi126cf032017-04-02 23:19:02 -07005092 * Notifies an application with a focus listener of gain or loss of audio focus.
5093 * This method can only be used by owners of an {@link AudioPolicy} configured with
5094 * {@link AudioPolicy.Builder#setIsAudioFocusPolicy(boolean)} set to true.
5095 * @param afi the recipient of the focus change, that has previously requested audio focus, and
5096 * that was received by the {@code AudioPolicy} through
5097 * {@link AudioPolicy.AudioPolicyFocusListener#onAudioFocusRequest(AudioFocusInfo, int)}.
5098 * @param focusChange one of focus gain types ({@link #AUDIOFOCUS_GAIN},
5099 * {@link #AUDIOFOCUS_GAIN_TRANSIENT}, {@link #AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK} or
5100 * {@link #AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE})
5101 * or one of the focus loss types ({@link AudioManager#AUDIOFOCUS_LOSS},
5102 * {@link AudioManager#AUDIOFOCUS_LOSS_TRANSIENT},
5103 * or {@link AudioManager#AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK}).
5104 * <br>For the focus gain, the change type should be the same as the app requested.
5105 * @param ap a valid registered {@link AudioPolicy} configured as a focus policy.
5106 * @return {@link #AUDIOFOCUS_REQUEST_GRANTED} if the dispatch was successfully sent, or
5107 * {@link #AUDIOFOCUS_REQUEST_FAILED} if the focus client didn't have a listener, or
5108 * if there was an error sending the request.
5109 * @throws NullPointerException if the {@link AudioFocusInfo} or {@link AudioPolicy} are null.
5110 */
5111 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00005112 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
Jean-Michel Trivi126cf032017-04-02 23:19:02 -07005113 public int dispatchAudioFocusChange(@NonNull AudioFocusInfo afi, int focusChange,
5114 @NonNull AudioPolicy ap) {
5115 if (afi == null) {
5116 throw new NullPointerException("Illegal null AudioFocusInfo");
5117 }
5118 if (ap == null) {
5119 throw new NullPointerException("Illegal null AudioPolicy");
5120 }
5121 final IAudioService service = getService();
5122 try {
5123 return service.dispatchFocusChange(afi, focusChange, ap.cb());
5124 } catch (RemoteException e) {
5125 throw e.rethrowFromSystemServer();
5126 }
5127 }
5128
5129 /**
Raj Goparaju04285802023-12-01 16:57:51 -08005130 * Notifies an application with a focus listener of gain or loss of audio focus
5131 *
5132 * <p>This is similar to {@link #dispatchAudioFocusChange(AudioFocusInfo, int, AudioPolicy)} but
5133 * with additional functionality of fade. The players of the application with audio focus
5134 * change, provided they meet the active {@link FadeManagerConfiguration} requirements, are
5135 * faded before dispatching the callback to the application. For example, players of the
5136 * application losing audio focus will be faded out, whereas players of the application gaining
5137 * audio focus will be faded in, if needed.
5138 *
5139 * <p>The applicability of fade is decided against the supplied active {@link AudioFocusInfo}.
5140 * This list cannot be {@code null}. The list can be empty if no other active
5141 * {@link AudioFocusInfo} available at the time of the dispatch.
5142 *
5143 * <p>The {@link FadeManagerConfiguration} supplied here is prioritized over existing fade
5144 * configurations. If none supplied, either the {@link FadeManagerConfiguration} set through
5145 * {@link AudioPolicy} or the default will be used to determine the fade properties.
5146 *
5147 * <p>This method can only be used by owners of an {@link AudioPolicy} configured with
5148 * {@link AudioPolicy.Builder#setIsAudioFocusPolicy(boolean)} set to true.
5149 *
5150 * @param afi the recipient of the focus change, that has previously requested audio focus, and
5151 * that was received by the {@code AudioPolicy} through
5152 * {@link AudioPolicy.AudioPolicyFocusListener#onAudioFocusRequest(AudioFocusInfo, int)}
5153 * @param focusChange one of focus gain types ({@link #AUDIOFOCUS_GAIN},
5154 * {@link #AUDIOFOCUS_GAIN_TRANSIENT}, {@link #AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK} or
5155 * {@link #AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE})
5156 * or one of the focus loss types ({@link AudioManager#AUDIOFOCUS_LOSS},
5157 * {@link AudioManager#AUDIOFOCUS_LOSS_TRANSIENT},
5158 * or {@link AudioManager#AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK}).
5159 * <br>For the focus gain, the change type should be the same as the app requested
5160 * @param ap a valid registered {@link AudioPolicy} configured as a focus policy.
5161 * @param otherActiveAfis active {@link AudioFocusInfo} that are granted audio focus at the time
5162 * of dispatch
5163 * @param transientFadeMgrConfig {@link FadeManagerConfiguration} that will be used for fading
5164 * players resulting from this dispatch. This is a transient configuration that is only
5165 * valid for this focus change and shall be discarded after processing this request.
5166 * @return {@link #AUDIOFOCUS_REQUEST_FAILED} if the focus client didn't have a listener or if
5167 * there was an error sending the request, or {@link #AUDIOFOCUS_REQUEST_GRANTED} if the
5168 * dispatch was successfully sent, or {@link #AUDIOFOCUS_REQUEST_DELAYED} if
5169 * the request was successful but the dispatch of focus change was delayed due to a fade
5170 * operation.
Raj Goparaju04285802023-12-01 16:57:51 -08005171 * @hide
5172 */
5173 @FlaggedApi(FLAG_ENABLE_FADE_MANAGER_CONFIGURATION)
5174 @SystemApi
5175 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED)
Raj Goparaju8289cf52024-01-29 14:12:25 -08005176 @FocusRequestResult
Raj Goparaju04285802023-12-01 16:57:51 -08005177 public int dispatchAudioFocusChangeWithFade(@NonNull AudioFocusInfo afi, int focusChange,
5178 @NonNull AudioPolicy ap, @NonNull List<AudioFocusInfo> otherActiveAfis,
5179 @Nullable FadeManagerConfiguration transientFadeMgrConfig) {
5180 Objects.requireNonNull(afi, "AudioFocusInfo cannot be null");
5181 Objects.requireNonNull(ap, "AudioPolicy cannot be null");
5182 Objects.requireNonNull(otherActiveAfis, "Other active AudioFocusInfo list cannot be null");
5183
5184 IAudioService service = getService();
5185 try {
5186 return service.dispatchFocusChangeWithFade(afi, focusChange, ap.cb(), otherActiveAfis,
5187 transientFadeMgrConfig);
5188 } catch (RemoteException e) {
5189 throw e.rethrowFromSystemServer();
5190 }
5191 }
5192
5193 /**
Jean-Michel Trivi126cf032017-04-02 23:19:02 -07005194 * @hide
Jean-Michel Trivi4dd36742012-01-24 09:52:39 -08005195 * Used internally by telephony package to abandon audio focus, typically after a call or
5196 * when ringing ends and the call is rejected or not answered.
5197 * Should match one or more calls to {@link #requestAudioFocusForCall(int, int)}.
5198 */
Mathew Inwood8e742f92020-10-27 11:47:29 +00005199 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
Jean-Michel Trivi4dd36742012-01-24 09:52:39 -08005200 public void abandonAudioFocusForCall() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07005201 final IAudioService service = getService();
Jean-Michel Trivi4dd36742012-01-24 09:52:39 -08005202 try {
John Spurlock61560172015-02-06 19:46:04 -05005203 service.abandonAudioFocus(null, AudioSystem.IN_VOICE_COMM_FOCUS_ID,
Jean-Michel Trivi126cf032017-04-02 23:19:02 -07005204 null /*AudioAttributes, legacy behavior*/, getContext().getOpPackageName());
Jean-Michel Trivi4dd36742012-01-24 09:52:39 -08005205 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07005206 throw e.rethrowFromSystemServer();
Jean-Michel Trivi4dd36742012-01-24 09:52:39 -08005207 }
5208 }
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08005209
5210 /**
Jean-Michel Trivi46b3a182010-05-11 11:22:54 -07005211 * Abandon audio focus. Causes the previous focus owner, if any, to receive focus.
5212 * @param l the listener with which focus was requested.
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08005213 * @return {@link #AUDIOFOCUS_REQUEST_FAILED} or {@link #AUDIOFOCUS_REQUEST_GRANTED}
Jean-Michel Trivi36bdb662017-03-09 11:56:51 -08005214 * @deprecated use {@link #abandonAudioFocusRequest(AudioFocusRequest)}
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08005215 */
5216 public int abandonAudioFocus(OnAudioFocusChangeListener l) {
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08005217 return abandonAudioFocus(l, null /*AudioAttributes, legacy behavior*/);
5218 }
5219
5220 /**
5221 * @hide
5222 * Abandon audio focus. Causes the previous focus owner, if any, to receive focus.
5223 * @param l the listener with which focus was requested.
5224 * @param aa the {@link AudioAttributes} with which audio focus was requested
5225 * @return {@link #AUDIOFOCUS_REQUEST_FAILED} or {@link #AUDIOFOCUS_REQUEST_GRANTED}
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07005226 * @deprecated use {@link #abandonAudioFocusRequest(AudioFocusRequest)}
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08005227 */
5228 @SystemApi
Aurimas Liutikas1394a012020-11-12 18:26:09 -08005229 @SuppressLint("RequiresPermission") // no permission enforcement, but only "undoes" what would
5230 // have been done by a matching requestAudioFocus
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08005231 public int abandonAudioFocus(OnAudioFocusChangeListener l, AudioAttributes aa) {
Ján Sebechlebskýdcc49642023-02-07 10:20:59 +00005232 if (hasCustomPolicyVirtualDeviceContext()) {
5233 // If this AudioManager instance is running within VirtualDevice context configured
5234 // with custom device policy for audio, the audio focus handling is bypassed.
5235 return AUDIOFOCUS_REQUEST_GRANTED;
5236 }
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07005237 unregisterAudioFocusRequest(l);
5238 final IAudioService service = getService();
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08005239 try {
Ján Sebechlebskýdcc49642023-02-07 10:20:59 +00005240 return service.abandonAudioFocus(mAudioFocusDispatcher,
Jean-Michel Trivi126cf032017-04-02 23:19:02 -07005241 getIdForAudioFocusListener(l), aa, getContext().getOpPackageName());
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08005242 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07005243 throw e.rethrowFromSystemServer();
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08005244 }
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08005245 }
5246
Jean-Michel Trivid327f212010-03-16 21:44:33 -07005247 //====================================================================
5248 // Remote Control
5249 /**
Jean-Michel Trivi46b3a182010-05-11 11:22:54 -07005250 * Register a component to be the sole receiver of MEDIA_BUTTON intents.
Jean-Michel Trivid327f212010-03-16 21:44:33 -07005251 * @param eventReceiver identifier of a {@link android.content.BroadcastReceiver}
5252 * that will receive the media button intent. This broadcast receiver must be declared
Jean-Michel Trivif0cff042011-09-14 18:11:09 -07005253 * in the application manifest. The package of the component must match that of
5254 * the context you're registering from.
RoboErikb214efb2014-07-24 13:20:30 -07005255 * @deprecated Use {@link MediaSession#setMediaButtonReceiver(PendingIntent)} instead.
Jean-Michel Trivid327f212010-03-16 21:44:33 -07005256 */
RoboErikb214efb2014-07-24 13:20:30 -07005257 @Deprecated
Jean-Michel Trivid327f212010-03-16 21:44:33 -07005258 public void registerMediaButtonEventReceiver(ComponentName eventReceiver) {
Jean-Michel Trivi8f619182011-07-21 15:10:10 -07005259 if (eventReceiver == null) {
5260 return;
5261 }
Marco Nelissen29f16932015-04-17 09:50:56 -07005262 if (!eventReceiver.getPackageName().equals(getContext().getPackageName())) {
Jean-Michel Trivif0cff042011-09-14 18:11:09 -07005263 Log.e(TAG, "registerMediaButtonEventReceiver() error: " +
5264 "receiver and context package names don't match");
5265 return;
5266 }
5267 // construct a PendingIntent for the media button and register it
5268 Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
5269 // the associated intent will be handled by the component being registered
5270 mediaButtonIntent.setComponent(eventReceiver);
Marco Nelissen29f16932015-04-17 09:50:56 -07005271 PendingIntent pi = PendingIntent.getBroadcast(getContext(),
Jean-Michel Triviec84dae2020-10-22 17:12:37 -07005272 0/*requestCode, ignored*/, mediaButtonIntent,
5273 PendingIntent.FLAG_IMMUTABLE);
Jean-Michel Trivif0cff042011-09-14 18:11:09 -07005274 registerMediaButtonIntent(pi, eventReceiver);
5275 }
5276
5277 /**
Dianne Hackborn961cae92013-03-20 14:59:43 -07005278 * Register a component to be the sole receiver of MEDIA_BUTTON intents. This is like
5279 * {@link #registerMediaButtonEventReceiver(android.content.ComponentName)}, but allows
5280 * the buttons to go to any PendingIntent. Note that you should only use this form if
5281 * you know you will continue running for the full time until unregistering the
5282 * PendingIntent.
5283 * @param eventReceiver target that will receive media button intents. The PendingIntent
RoboErikb214efb2014-07-24 13:20:30 -07005284 * will be sent an {@link Intent#ACTION_MEDIA_BUTTON} event when a media button action
5285 * occurs, with {@link Intent#EXTRA_KEY_EVENT} added and holding the key code of the
5286 * media button that was pressed.
5287 * @deprecated Use {@link MediaSession#setMediaButtonReceiver(PendingIntent)} instead.
Dianne Hackborn961cae92013-03-20 14:59:43 -07005288 */
RoboErikb214efb2014-07-24 13:20:30 -07005289 @Deprecated
Dianne Hackborn961cae92013-03-20 14:59:43 -07005290 public void registerMediaButtonEventReceiver(PendingIntent eventReceiver) {
5291 if (eventReceiver == null) {
5292 return;
5293 }
5294 registerMediaButtonIntent(eventReceiver, null);
5295 }
5296
5297 /**
Jean-Michel Trivif0cff042011-09-14 18:11:09 -07005298 * @hide
5299 * no-op if (pi == null) or (eventReceiver == null)
5300 */
5301 public void registerMediaButtonIntent(PendingIntent pi, ComponentName eventReceiver) {
Dianne Hackborn961cae92013-03-20 14:59:43 -07005302 if (pi == null) {
Jean-Michel Trivif0cff042011-09-14 18:11:09 -07005303 Log.e(TAG, "Cannot call registerMediaButtonIntent() with a null parameter");
5304 return;
5305 }
Marco Nelissen29f16932015-04-17 09:50:56 -07005306 MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(getContext());
5307 helper.addMediaButtonListener(pi, eventReceiver, getContext());
Jean-Michel Trivi722b8082012-05-15 15:18:33 -07005308 }
5309
5310 /**
Jean-Michel Trivi46b3a182010-05-11 11:22:54 -07005311 * Unregister the receiver of MEDIA_BUTTON intents.
5312 * @param eventReceiver identifier of a {@link android.content.BroadcastReceiver}
5313 * that was registered with {@link #registerMediaButtonEventReceiver(ComponentName)}.
RoboErikb214efb2014-07-24 13:20:30 -07005314 * @deprecated Use {@link MediaSession} instead.
Jean-Michel Trivid327f212010-03-16 21:44:33 -07005315 */
RoboErikb214efb2014-07-24 13:20:30 -07005316 @Deprecated
Jean-Michel Trivid327f212010-03-16 21:44:33 -07005317 public void unregisterMediaButtonEventReceiver(ComponentName eventReceiver) {
Jean-Michel Trivi8f619182011-07-21 15:10:10 -07005318 if (eventReceiver == null) {
5319 return;
5320 }
Jean-Michel Trivif0cff042011-09-14 18:11:09 -07005321 // construct a PendingIntent for the media button and unregister it
5322 Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
5323 // the associated intent will be handled by the component being registered
5324 mediaButtonIntent.setComponent(eventReceiver);
Marco Nelissen29f16932015-04-17 09:50:56 -07005325 PendingIntent pi = PendingIntent.getBroadcast(getContext(),
Jean-Michel Triviec84dae2020-10-22 17:12:37 -07005326 0/*requestCode, ignored*/, mediaButtonIntent,
5327 PendingIntent.FLAG_IMMUTABLE);
Jean-Michel Trivib839b832013-03-30 14:17:45 -07005328 unregisterMediaButtonIntent(pi);
Jean-Michel Trivid327f212010-03-16 21:44:33 -07005329 }
5330
Jean-Michel Trivif0cff042011-09-14 18:11:09 -07005331 /**
Dianne Hackborn961cae92013-03-20 14:59:43 -07005332 * Unregister the receiver of MEDIA_BUTTON intents.
5333 * @param eventReceiver same PendingIntent that was registed with
5334 * {@link #registerMediaButtonEventReceiver(PendingIntent)}.
RoboErikb214efb2014-07-24 13:20:30 -07005335 * @deprecated Use {@link MediaSession} instead.
Dianne Hackborn961cae92013-03-20 14:59:43 -07005336 */
RoboErikb214efb2014-07-24 13:20:30 -07005337 @Deprecated
Dianne Hackborn961cae92013-03-20 14:59:43 -07005338 public void unregisterMediaButtonEventReceiver(PendingIntent eventReceiver) {
5339 if (eventReceiver == null) {
5340 return;
5341 }
Jean-Michel Trivib839b832013-03-30 14:17:45 -07005342 unregisterMediaButtonIntent(eventReceiver);
Dianne Hackborn961cae92013-03-20 14:59:43 -07005343 }
5344
5345 /**
Jean-Michel Trivif0cff042011-09-14 18:11:09 -07005346 * @hide
5347 */
Jean-Michel Trivib839b832013-03-30 14:17:45 -07005348 public void unregisterMediaButtonIntent(PendingIntent pi) {
Marco Nelissen29f16932015-04-17 09:50:56 -07005349 MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(getContext());
RoboErik430fc482014-06-12 15:49:20 -07005350 helper.removeMediaButtonListener(pi);
Jean-Michel Trivif0cff042011-09-14 18:11:09 -07005351 }
Jean-Michel Trivi178889e2011-08-15 17:17:52 -07005352
5353 /**
Jean-Michel Trivi178889e2011-08-15 17:17:52 -07005354 * Registers the remote control client for providing information to display on the remote
5355 * controls.
Jean-Michel Trivi466ade52011-09-01 10:02:30 -07005356 * @param rcClient The remote control client from which remote controls will receive
5357 * information to display.
5358 * @see RemoteControlClient
RoboErikb214efb2014-07-24 13:20:30 -07005359 * @deprecated Use {@link MediaSession} instead.
Jean-Michel Trivi8f619182011-07-21 15:10:10 -07005360 */
RoboErikb214efb2014-07-24 13:20:30 -07005361 @Deprecated
Jean-Michel Trivi4426e422011-08-18 19:16:47 -07005362 public void registerRemoteControlClient(RemoteControlClient rcClient) {
Jean-Michel Trivif0cff042011-09-14 18:11:09 -07005363 if ((rcClient == null) || (rcClient.getRcMediaIntent() == null)) {
Jean-Michel Trivi8f619182011-07-21 15:10:10 -07005364 return;
5365 }
Marco Nelissen29f16932015-04-17 09:50:56 -07005366 rcClient.registerWithSession(MediaSessionLegacyHelper.getHelper(getContext()));
Jean-Michel Trivi8f619182011-07-21 15:10:10 -07005367 }
5368
5369 /**
Jean-Michel Trivifcd693a2011-08-11 13:53:55 -07005370 * Unregisters the remote control client that was providing information to display on the
Jean-Michel Trivi466ade52011-09-01 10:02:30 -07005371 * remote controls.
5372 * @param rcClient The remote control client to unregister.
Jean-Michel Trivi4426e422011-08-18 19:16:47 -07005373 * @see #registerRemoteControlClient(RemoteControlClient)
RoboErikb214efb2014-07-24 13:20:30 -07005374 * @deprecated Use {@link MediaSession} instead.
Jean-Michel Trivi8f619182011-07-21 15:10:10 -07005375 */
RoboErikb214efb2014-07-24 13:20:30 -07005376 @Deprecated
Jean-Michel Trivi4426e422011-08-18 19:16:47 -07005377 public void unregisterRemoteControlClient(RemoteControlClient rcClient) {
Jean-Michel Trivif0cff042011-09-14 18:11:09 -07005378 if ((rcClient == null) || (rcClient.getRcMediaIntent() == null)) {
Jean-Michel Trivi8f619182011-07-21 15:10:10 -07005379 return;
5380 }
Marco Nelissen29f16932015-04-17 09:50:56 -07005381 rcClient.unregisterWithSession(MediaSessionLegacyHelper.getHelper(getContext()));
Jean-Michel Trivi8f619182011-07-21 15:10:10 -07005382 }
5383
Jean-Michel Trivi44413e52011-08-23 18:20:03 -07005384 /**
RoboErika66c40b2014-08-15 15:21:41 -07005385 * Registers a {@link RemoteController} instance for it to receive media
5386 * metadata updates and playback state information from applications using
5387 * {@link RemoteControlClient}, and control their playback.
5388 * <p>
John Spurlockee5ad722015-03-03 16:17:21 -05005389 * Registration requires the {@link RemoteController.OnClientUpdateListener} listener to be
RoboErika66c40b2014-08-15 15:21:41 -07005390 * one of the enabled notification listeners (see
Jean-Michel Trivif108cdd92013-09-27 18:37:36 -07005391 * {@link android.service.notification.NotificationListenerService}).
RoboErika66c40b2014-08-15 15:21:41 -07005392 *
Jean-Michel Trivia83487e2013-09-17 21:19:30 -07005393 * @param rctlr the object to register.
RoboErika66c40b2014-08-15 15:21:41 -07005394 * @return true if the {@link RemoteController} was successfully registered,
5395 * false if an error occurred, due to an internal system error, or
5396 * insufficient permissions.
RoboErikb214efb2014-07-24 13:20:30 -07005397 * @deprecated Use
RoboErika66c40b2014-08-15 15:21:41 -07005398 * {@link MediaSessionManager#addOnActiveSessionsChangedListener(android.media.session.MediaSessionManager.OnActiveSessionsChangedListener, ComponentName)}
5399 * and {@link MediaController} instead.
Jean-Michel Trivi7ddd2262013-09-01 18:06:45 -07005400 */
RoboErikb214efb2014-07-24 13:20:30 -07005401 @Deprecated
Jean-Michel Trivi7ddd2262013-09-01 18:06:45 -07005402 public boolean registerRemoteController(RemoteController rctlr) {
5403 if (rctlr == null) {
5404 return false;
5405 }
RoboErik430fc482014-06-12 15:49:20 -07005406 rctlr.startListeningToSessions();
5407 return true;
Jean-Michel Trivi7ddd2262013-09-01 18:06:45 -07005408 }
5409
5410 /**
RoboErika66c40b2014-08-15 15:21:41 -07005411 * Unregisters a {@link RemoteController}, causing it to no longer receive
5412 * media metadata and playback state information, and no longer be capable
5413 * of controlling playback.
5414 *
Jean-Michel Trivia83487e2013-09-17 21:19:30 -07005415 * @param rctlr the object to unregister.
RoboErikb214efb2014-07-24 13:20:30 -07005416 * @deprecated Use
RoboErika66c40b2014-08-15 15:21:41 -07005417 * {@link MediaSessionManager#removeOnActiveSessionsChangedListener(android.media.session.MediaSessionManager.OnActiveSessionsChangedListener)}
5418 * instead.
Jean-Michel Trivi7ddd2262013-09-01 18:06:45 -07005419 */
RoboErikb214efb2014-07-24 13:20:30 -07005420 @Deprecated
Jean-Michel Trivi7ddd2262013-09-01 18:06:45 -07005421 public void unregisterRemoteController(RemoteController rctlr) {
5422 if (rctlr == null) {
5423 return;
5424 }
RoboErik430fc482014-06-12 15:49:20 -07005425 rctlr.stopListeningToSessions();
Jean-Michel Trivi7ddd2262013-09-01 18:06:45 -07005426 }
5427
Jean-Michel Trivic3c4bab2013-04-19 08:56:50 -07005428
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005429 //====================================================================
5430 // Audio policy
Jean-Michel Trivic3c4bab2013-04-19 08:56:50 -07005431 /**
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005432 * @hide
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005433 * Register the given {@link AudioPolicy}.
5434 * This call is synchronous and blocks until the registration process successfully completed
5435 * or failed to complete.
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08005436 * @param policy the non-null {@link AudioPolicy} to register.
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005437 * @return {@link #ERROR} if there was an error communicating with the registration service
5438 * or if the user doesn't have the required
Jean-Michel Trivic4557822023-01-23 18:19:52 +00005439 * {@link Manifest.permission#MODIFY_AUDIO_ROUTING} permission,
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005440 * {@link #SUCCESS} otherwise.
5441 */
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08005442 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00005443 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08005444 public int registerAudioPolicy(@NonNull AudioPolicy policy) {
Robert Berry669be042019-01-22 18:48:35 -05005445 return registerAudioPolicyStatic(policy);
5446 }
5447
5448 static int registerAudioPolicyStatic(@NonNull AudioPolicy policy) {
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005449 if (policy == null) {
5450 throw new IllegalArgumentException("Illegal null AudioPolicy argument");
5451 }
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07005452 final IAudioService service = getService();
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005453 try {
Kevin Rocard2fe8b8b2019-02-20 11:25:23 -08005454 MediaProjection projection = policy.getMediaProjection();
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005455 String regId = service.registerAudioPolicy(policy.getConfig(), policy.cb(),
Jean-Michel Triviee7d2452019-03-19 12:29:27 -07005456 policy.hasFocusListener(), policy.isFocusPolicy(), policy.isTestFocusPolicy(),
5457 policy.isVolumeController(),
Marvin Ramin897fdc12024-03-19 12:19:15 +00005458 projection == null ? null : projection.getProjection(),
5459 policy.getAttributionSource());
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07005460 if (regId == null) {
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005461 return ERROR;
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07005462 } else {
5463 policy.setRegistration(regId);
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005464 }
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07005465 // successful registration
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005466 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07005467 throw e.rethrowFromSystemServer();
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005468 }
5469 return SUCCESS;
5470 }
5471
5472 /**
5473 * @hide
Jean-Michel Trivicada3722019-03-02 16:14:12 -08005474 * Unregisters an {@link AudioPolicy} asynchronously.
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08005475 * @param policy the non-null {@link AudioPolicy} to unregister.
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005476 */
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08005477 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00005478 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08005479 public void unregisterAudioPolicyAsync(@NonNull AudioPolicy policy) {
Robert Berry669be042019-01-22 18:48:35 -05005480 unregisterAudioPolicyAsyncStatic(policy);
5481 }
5482
5483 static void unregisterAudioPolicyAsyncStatic(@NonNull AudioPolicy policy) {
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005484 if (policy == null) {
5485 throw new IllegalArgumentException("Illegal null AudioPolicy argument");
5486 }
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07005487 final IAudioService service = getService();
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005488 try {
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005489 service.unregisterAudioPolicyAsync(policy.cb());
Jean-Michel Trivif5f3e682020-07-29 15:45:48 -07005490 policy.reset();
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005491 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07005492 throw e.rethrowFromSystemServer();
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005493 }
5494 }
5495
Jean-Michel Trivicada3722019-03-02 16:14:12 -08005496 /**
5497 * @hide
5498 * Unregisters an {@link AudioPolicy} synchronously.
5499 * This method also invalidates all {@link AudioRecord} and {@link AudioTrack} objects
5500 * associated with mixes of this policy.
5501 * @param policy the non-null {@link AudioPolicy} to unregister.
5502 */
5503 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00005504 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
Jean-Michel Trivicada3722019-03-02 16:14:12 -08005505 public void unregisterAudioPolicy(@NonNull AudioPolicy policy) {
5506 Preconditions.checkNotNull(policy, "Illegal null AudioPolicy argument");
5507 final IAudioService service = getService();
5508 try {
5509 policy.invalidateCaptorsAndInjectors();
5510 service.unregisterAudioPolicy(policy.cb());
Jean-Michel Trivif5f3e682020-07-29 15:45:48 -07005511 policy.reset();
Jean-Michel Trivicada3722019-03-02 16:14:12 -08005512 } catch (RemoteException e) {
5513 throw e.rethrowFromSystemServer();
5514 }
5515 }
5516
Jean-Michel Trivi0c88f492019-04-12 15:43:56 -07005517 /**
5518 * @hide
Marvin Ramina4c942d2023-11-01 09:08:21 +01005519 * @return All currently registered audio policy mixes.
5520 */
5521 @TestApi
5522 @FlaggedApi(android.media.audiopolicy.Flags.FLAG_AUDIO_MIX_TEST_API)
5523 @NonNull
5524 public List<android.media.audiopolicy.AudioMix> getRegisteredPolicyMixes() {
5525 if (!android.media.audiopolicy.Flags.audioMixTestApi()) {
5526 return Collections.emptyList();
5527 }
5528
5529 final IAudioService service = getService();
5530 try {
5531 return service.getRegisteredPolicyMixes();
5532 } catch (RemoteException e) {
5533 throw e.rethrowFromSystemServer();
5534 }
5535 }
5536
5537 /**
5538 * @hide
Jean-Michel Trivi0c88f492019-04-12 15:43:56 -07005539 * @return true if an AudioPolicy was previously registered
5540 */
5541 @TestApi
5542 public boolean hasRegisteredDynamicPolicy() {
5543 final IAudioService service = getService();
5544 try {
5545 return service.hasRegisteredDynamicPolicy();
5546 } catch (RemoteException e) {
5547 throw e.rethrowFromSystemServer();
5548 }
5549 }
5550
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -08005551 //====================================================================
5552 // Notification of playback activity & playback configuration
5553 /**
5554 * Interface for receiving update notifications about the playback activity on the system.
5555 * Extend this abstract class and register it with
5556 * {@link AudioManager#registerAudioPlaybackCallback(AudioPlaybackCallback, Handler)}
5557 * to be notified.
5558 * Use {@link AudioManager#getActivePlaybackConfigurations()} to query the current
5559 * configuration.
5560 * @see AudioPlaybackConfiguration
5561 */
5562 public static abstract class AudioPlaybackCallback {
5563 /**
5564 * Called whenever the playback activity and configuration has changed.
5565 * @param configs list containing the results of
5566 * {@link AudioManager#getActivePlaybackConfigurations()}.
5567 */
5568 public void onPlaybackConfigChanged(List<AudioPlaybackConfiguration> configs) {}
5569 }
5570
5571 private static class AudioPlaybackCallbackInfo {
5572 final AudioPlaybackCallback mCb;
5573 final Handler mHandler;
5574 AudioPlaybackCallbackInfo(AudioPlaybackCallback cb, Handler handler) {
5575 mCb = cb;
5576 mHandler = handler;
5577 }
5578 }
5579
5580 private final static class PlaybackConfigChangeCallbackData {
5581 final AudioPlaybackCallback mCb;
5582 final List<AudioPlaybackConfiguration> mConfigs;
5583
5584 PlaybackConfigChangeCallbackData(AudioPlaybackCallback cb,
5585 List<AudioPlaybackConfiguration> configs) {
5586 mCb = cb;
5587 mConfigs = configs;
5588 }
5589 }
5590
5591 /**
5592 * Register a callback to be notified of audio playback changes through
5593 * {@link AudioPlaybackCallback}
5594 * @param cb non-null callback to register
5595 * @param handler the {@link Handler} object for the thread on which to execute
5596 * the callback. If <code>null</code>, the {@link Handler} associated with the main
5597 * {@link Looper} will be used.
5598 */
Jean-Michel Trivi1ec66182019-12-30 09:53:04 -08005599 public void registerAudioPlaybackCallback(@NonNull AudioPlaybackCallback cb,
5600 @Nullable Handler handler)
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -08005601 {
5602 if (cb == null) {
5603 throw new IllegalArgumentException("Illegal null AudioPlaybackCallback argument");
5604 }
5605
5606 synchronized(mPlaybackCallbackLock) {
5607 // lazy initialization of the list of playback callbacks
5608 if (mPlaybackCallbackList == null) {
5609 mPlaybackCallbackList = new ArrayList<AudioPlaybackCallbackInfo>();
5610 }
5611 final int oldCbCount = mPlaybackCallbackList.size();
5612 if (!hasPlaybackCallback_sync(cb)) {
5613 mPlaybackCallbackList.add(new AudioPlaybackCallbackInfo(cb,
5614 new ServiceEventHandlerDelegate(handler).getHandler()));
5615 final int newCbCount = mPlaybackCallbackList.size();
5616 if ((oldCbCount == 0) && (newCbCount > 0)) {
5617 // register binder for callbacks
5618 try {
5619 getService().registerPlaybackCallback(mPlayCb);
5620 } catch (RemoteException e) {
5621 throw e.rethrowFromSystemServer();
5622 }
5623 }
5624 } else {
5625 Log.w(TAG, "attempt to call registerAudioPlaybackCallback() on a previously"
5626 + "registered callback");
5627 }
5628 }
5629 }
5630
5631 /**
5632 * Unregister an audio playback callback previously registered with
5633 * {@link #registerAudioPlaybackCallback(AudioPlaybackCallback, Handler)}.
5634 * @param cb non-null callback to unregister
5635 */
5636 public void unregisterAudioPlaybackCallback(@NonNull AudioPlaybackCallback cb) {
5637 if (cb == null) {
5638 throw new IllegalArgumentException("Illegal null AudioPlaybackCallback argument");
5639 }
5640 synchronized(mPlaybackCallbackLock) {
5641 if (mPlaybackCallbackList == null) {
5642 Log.w(TAG, "attempt to call unregisterAudioPlaybackCallback() on a callback"
5643 + " that was never registered");
5644 return;
5645 }
5646 final int oldCbCount = mPlaybackCallbackList.size();
5647 if (removePlaybackCallback_sync(cb)) {
5648 final int newCbCount = mPlaybackCallbackList.size();
5649 if ((oldCbCount > 0) && (newCbCount == 0)) {
5650 // unregister binder for callbacks
5651 try {
5652 getService().unregisterPlaybackCallback(mPlayCb);
5653 } catch (RemoteException e) {
5654 throw e.rethrowFromSystemServer();
5655 }
5656 }
5657 } else {
5658 Log.w(TAG, "attempt to call unregisterAudioPlaybackCallback() on a callback"
5659 + " already unregistered or never registered");
5660 }
5661 }
5662 }
5663
5664 /**
5665 * Returns the current active audio playback configurations of the device
5666 * @return a non-null list of playback configurations. An empty list indicates there is no
5667 * playback active when queried.
5668 * @see AudioPlaybackConfiguration
5669 */
5670 public @NonNull List<AudioPlaybackConfiguration> getActivePlaybackConfigurations() {
5671 final IAudioService service = getService();
5672 try {
5673 return service.getActivePlaybackConfigurations();
5674 } catch (RemoteException e) {
5675 throw e.rethrowFromSystemServer();
5676 }
5677 }
5678
5679 /**
5680 * All operations on this list are sync'd on mPlaybackCallbackLock.
5681 * List is lazy-initialized in
5682 * {@link #registerAudioPlaybackCallback(AudioPlaybackCallback, Handler)}.
5683 * List can be null.
5684 */
5685 private List<AudioPlaybackCallbackInfo> mPlaybackCallbackList;
5686 private final Object mPlaybackCallbackLock = new Object();
5687
5688 /**
5689 * Must be called synchronized on mPlaybackCallbackLock
5690 */
5691 private boolean hasPlaybackCallback_sync(@NonNull AudioPlaybackCallback cb) {
5692 if (mPlaybackCallbackList != null) {
5693 for (int i=0 ; i < mPlaybackCallbackList.size() ; i++) {
5694 if (cb.equals(mPlaybackCallbackList.get(i).mCb)) {
5695 return true;
5696 }
5697 }
5698 }
5699 return false;
5700 }
5701
5702 /**
5703 * Must be called synchronized on mPlaybackCallbackLock
5704 */
5705 private boolean removePlaybackCallback_sync(@NonNull AudioPlaybackCallback cb) {
5706 if (mPlaybackCallbackList != null) {
5707 for (int i=0 ; i < mPlaybackCallbackList.size() ; i++) {
5708 if (cb.equals(mPlaybackCallbackList.get(i).mCb)) {
5709 mPlaybackCallbackList.remove(i);
5710 return true;
5711 }
5712 }
5713 }
5714 return false;
5715 }
5716
5717 private final IPlaybackConfigDispatcher mPlayCb = new IPlaybackConfigDispatcher.Stub() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07005718 @Override
Jean-Michel Trivi776a3992017-09-12 16:45:34 -07005719 public void dispatchPlaybackConfigChange(List<AudioPlaybackConfiguration> configs,
5720 boolean flush) {
5721 if (flush) {
5722 Binder.flushPendingCommands();
5723 }
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -08005724 synchronized(mPlaybackCallbackLock) {
5725 if (mPlaybackCallbackList != null) {
5726 for (int i=0 ; i < mPlaybackCallbackList.size() ; i++) {
5727 final AudioPlaybackCallbackInfo arci = mPlaybackCallbackList.get(i);
5728 if (arci.mHandler != null) {
5729 final Message m = arci.mHandler.obtainMessage(
5730 MSSG_PLAYBACK_CONFIG_CHANGE/*what*/,
5731 new PlaybackConfigChangeCallbackData(arci.mCb, configs)/*obj*/);
5732 arci.mHandler.sendMessage(m);
5733 }
5734 }
5735 }
5736 }
5737 }
5738
5739 };
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005740
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005741 //====================================================================
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -08005742 // Notification of recording activity & recording configuration
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005743 /**
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005744 * Interface for receiving update notifications about the recording configuration. Extend
5745 * this abstract class and register it with
5746 * {@link AudioManager#registerAudioRecordingCallback(AudioRecordingCallback, Handler)}
5747 * to be notified.
Jean-Michel Trivi598c0c92016-03-07 14:13:03 -08005748 * Use {@link AudioManager#getActiveRecordingConfigurations()} to query the current
5749 * configuration.
Jean-Michel Trivi7872aff2016-07-06 14:34:52 -07005750 * @see AudioRecordingConfiguration
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005751 */
5752 public static abstract class AudioRecordingCallback {
5753 /**
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005754 * Called whenever the device recording configuration has changed.
Jean-Michel Trivif04fab12016-05-19 10:42:35 -07005755 * @param configs list containing the results of
Jean-Michel Trivi598c0c92016-03-07 14:13:03 -08005756 * {@link AudioManager#getActiveRecordingConfigurations()}.
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005757 */
Jean-Michel Trivif04fab12016-05-19 10:42:35 -07005758 public void onRecordingConfigChanged(List<AudioRecordingConfiguration> configs) {}
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005759 }
5760
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005761 private static class AudioRecordingCallbackInfo {
5762 final AudioRecordingCallback mCb;
5763 final Handler mHandler;
5764 AudioRecordingCallbackInfo(AudioRecordingCallback cb, Handler handler) {
5765 mCb = cb;
5766 mHandler = handler;
5767 }
5768 }
5769
Jean-Michel Trivi28ff76b2016-03-02 09:36:30 -08005770 private final static class RecordConfigChangeCallbackData {
5771 final AudioRecordingCallback mCb;
Jean-Michel Trivif04fab12016-05-19 10:42:35 -07005772 final List<AudioRecordingConfiguration> mConfigs;
Jean-Michel Trivi28ff76b2016-03-02 09:36:30 -08005773
5774 RecordConfigChangeCallbackData(AudioRecordingCallback cb,
Jean-Michel Trivif04fab12016-05-19 10:42:35 -07005775 List<AudioRecordingConfiguration> configs) {
Jean-Michel Trivi28ff76b2016-03-02 09:36:30 -08005776 mCb = cb;
5777 mConfigs = configs;
5778 }
5779 }
5780
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005781 /**
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005782 * Register a callback to be notified of audio recording changes through
5783 * {@link AudioRecordingCallback}
5784 * @param cb non-null callback to register
5785 * @param handler the {@link Handler} object for the thread on which to execute
5786 * the callback. If <code>null</code>, the {@link Handler} associated with the main
5787 * {@link Looper} will be used.
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005788 */
Jean-Michel Trivi1ec66182019-12-30 09:53:04 -08005789 public void registerAudioRecordingCallback(@NonNull AudioRecordingCallback cb,
5790 @Nullable Handler handler)
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005791 {
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005792 if (cb == null) {
5793 throw new IllegalArgumentException("Illegal null AudioRecordingCallback argument");
5794 }
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005795
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005796 synchronized(mRecordCallbackLock) {
5797 // lazy initialization of the list of recording callbacks
5798 if (mRecordCallbackList == null) {
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005799 mRecordCallbackList = new ArrayList<AudioRecordingCallbackInfo>();
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005800 }
5801 final int oldCbCount = mRecordCallbackList.size();
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005802 if (!hasRecordCallback_sync(cb)) {
5803 mRecordCallbackList.add(new AudioRecordingCallbackInfo(cb,
5804 new ServiceEventHandlerDelegate(handler).getHandler()));
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005805 final int newCbCount = mRecordCallbackList.size();
5806 if ((oldCbCount == 0) && (newCbCount > 0)) {
5807 // register binder for callbacks
5808 final IAudioService service = getService();
5809 try {
5810 service.registerRecordingCallback(mRecCb);
5811 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07005812 throw e.rethrowFromSystemServer();
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005813 }
5814 }
5815 } else {
5816 Log.w(TAG, "attempt to call registerAudioRecordingCallback() on a previously"
5817 + "registered callback");
5818 }
5819 }
5820 }
5821
5822 /**
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005823 * Unregister an audio recording callback previously registered with
5824 * {@link #registerAudioRecordingCallback(AudioRecordingCallback, Handler)}.
5825 * @param cb non-null callback to unregister
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005826 */
5827 public void unregisterAudioRecordingCallback(@NonNull AudioRecordingCallback cb) {
5828 if (cb == null) {
5829 throw new IllegalArgumentException("Illegal null AudioRecordingCallback argument");
5830 }
5831 synchronized(mRecordCallbackLock) {
5832 if (mRecordCallbackList == null) {
5833 return;
5834 }
5835 final int oldCbCount = mRecordCallbackList.size();
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005836 if (removeRecordCallback_sync(cb)) {
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005837 final int newCbCount = mRecordCallbackList.size();
5838 if ((oldCbCount > 0) && (newCbCount == 0)) {
5839 // unregister binder for callbacks
5840 final IAudioService service = getService();
5841 try {
5842 service.unregisterRecordingCallback(mRecCb);
5843 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07005844 throw e.rethrowFromSystemServer();
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005845 }
5846 }
5847 } else {
5848 Log.w(TAG, "attempt to call unregisterAudioRecordingCallback() on a callback"
5849 + " already unregistered or never registered");
5850 }
5851 }
5852 }
5853
5854 /**
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005855 * Returns the current active audio recording configurations of the device.
Jean-Michel Trivif04fab12016-05-19 10:42:35 -07005856 * @return a non-null list of recording configurations. An empty list indicates there is
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005857 * no recording active when queried.
Jean-Michel Trivi7872aff2016-07-06 14:34:52 -07005858 * @see AudioRecordingConfiguration
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005859 */
Jean-Michel Trivif04fab12016-05-19 10:42:35 -07005860 public @NonNull List<AudioRecordingConfiguration> getActiveRecordingConfigurations() {
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005861 final IAudioService service = getService();
5862 try {
Jean-Michel Trivi598c0c92016-03-07 14:13:03 -08005863 return service.getActiveRecordingConfigurations();
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005864 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07005865 throw e.rethrowFromSystemServer();
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005866 }
5867 }
5868
5869 /**
5870 * constants for the recording events, to keep in sync
5871 * with frameworks/av/include/media/AudioPolicy.h
5872 */
5873 /** @hide */
Mikhail Naganova00883d2019-04-18 12:36:27 -07005874 public static final int RECORD_CONFIG_EVENT_NONE = -1;
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005875 /** @hide */
Mikhail Naganova00883d2019-04-18 12:36:27 -07005876 public static final int RECORD_CONFIG_EVENT_START = 0;
5877 /** @hide */
5878 public static final int RECORD_CONFIG_EVENT_STOP = 1;
5879 /** @hide */
5880 public static final int RECORD_CONFIG_EVENT_UPDATE = 2;
5881 /** @hide */
Mikhail Naganovcfe4c262019-05-09 09:02:47 -07005882 public static final int RECORD_CONFIG_EVENT_RELEASE = 3;
Mikhail Naganova00883d2019-04-18 12:36:27 -07005883 /**
5884 * keep in sync with frameworks/native/include/audiomanager/AudioManager.h
5885 */
5886 /** @hide */
5887 public static final int RECORD_RIID_INVALID = -1;
5888 /** @hide */
5889 public static final int RECORDER_STATE_STARTED = 0;
5890 /** @hide */
5891 public static final int RECORDER_STATE_STOPPED = 1;
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005892
5893 /**
5894 * All operations on this list are sync'd on mRecordCallbackLock.
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005895 * List is lazy-initialized in
5896 * {@link #registerAudioRecordingCallback(AudioRecordingCallback, Handler)}.
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005897 * List can be null.
5898 */
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005899 private List<AudioRecordingCallbackInfo> mRecordCallbackList;
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005900 private final Object mRecordCallbackLock = new Object();
5901
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005902 /**
5903 * Must be called synchronized on mRecordCallbackLock
5904 */
5905 private boolean hasRecordCallback_sync(@NonNull AudioRecordingCallback cb) {
5906 if (mRecordCallbackList != null) {
5907 for (int i=0 ; i < mRecordCallbackList.size() ; i++) {
5908 if (cb.equals(mRecordCallbackList.get(i).mCb)) {
5909 return true;
5910 }
5911 }
5912 }
5913 return false;
5914 }
5915
5916 /**
5917 * Must be called synchronized on mRecordCallbackLock
5918 */
5919 private boolean removeRecordCallback_sync(@NonNull AudioRecordingCallback cb) {
5920 if (mRecordCallbackList != null) {
5921 for (int i=0 ; i < mRecordCallbackList.size() ; i++) {
5922 if (cb.equals(mRecordCallbackList.get(i).mCb)) {
5923 mRecordCallbackList.remove(i);
5924 return true;
5925 }
5926 }
5927 }
5928 return false;
5929 }
5930
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005931 private final IRecordingConfigDispatcher mRecCb = new IRecordingConfigDispatcher.Stub() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07005932 @Override
Jean-Michel Trivif04fab12016-05-19 10:42:35 -07005933 public void dispatchRecordingConfigChange(List<AudioRecordingConfiguration> configs) {
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005934 synchronized(mRecordCallbackLock) {
5935 if (mRecordCallbackList != null) {
5936 for (int i=0 ; i < mRecordCallbackList.size() ; i++) {
5937 final AudioRecordingCallbackInfo arci = mRecordCallbackList.get(i);
5938 if (arci.mHandler != null) {
5939 final Message m = arci.mHandler.obtainMessage(
Jean-Michel Trivi28ff76b2016-03-02 09:36:30 -08005940 MSSG_RECORDING_CONFIG_CHANGE/*what*/,
5941 new RecordConfigChangeCallbackData(arci.mCb, configs)/*obj*/);
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005942 arci.mHandler.sendMessage(m);
5943 }
5944 }
5945 }
5946 }
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005947 }
5948
5949 };
5950
5951 //=====================================================================
5952
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005953 /**
Eric Laurent4050c932009-07-08 02:52:14 -07005954 * @hide
5955 * Reload audio settings. This method is called by Settings backup
5956 * agent when audio settings are restored and causes the AudioService
5957 * to read and apply restored settings.
5958 */
Mathew Inwood8e742f92020-10-27 11:47:29 +00005959 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
Eric Laurent4050c932009-07-08 02:52:14 -07005960 public void reloadAudioSettings() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07005961 final IAudioService service = getService();
Eric Laurent4050c932009-07-08 02:52:14 -07005962 try {
5963 service.reloadAudioSettings();
5964 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07005965 throw e.rethrowFromSystemServer();
Eric Laurent4050c932009-07-08 02:52:14 -07005966 }
5967 }
5968
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005969 /**
5970 * {@hide}
5971 */
Glenn Kasten30c918c2011-11-10 17:56:41 -08005972 private final IBinder mICallBack = new Binder();
Glenn Kasten7f9b1fa2010-03-31 11:11:36 -07005973
5974 /**
5975 * Checks whether the phone is in silent mode, with or without vibrate.
5976 *
5977 * @return true if phone is in silent mode, with or without vibrate.
5978 *
5979 * @see #getRingerMode()
5980 *
5981 * @hide pending API Council approval
5982 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01005983 @UnsupportedAppUsage
Glenn Kasten7f9b1fa2010-03-31 11:11:36 -07005984 public boolean isSilentMode() {
5985 int ringerMode = getRingerMode();
5986 boolean silentMode =
5987 (ringerMode == RINGER_MODE_SILENT) ||
5988 (ringerMode == RINGER_MODE_VIBRATE);
5989 return silentMode;
5990 }
5991
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005992 // This section re-defines new output device constants from AudioSystem, because the AudioSystem
5993 // class is not used by other parts of the framework, which instead use definitions and methods
5994 // from AudioManager. AudioSystem is an internal class used by AudioManager and AudioService.
5995
Eric Laurent948d3272014-05-16 15:18:45 -07005996 /** @hide
Wonsik Kimd7c29182014-05-27 10:38:21 +09005997 * The audio device code for representing "no device." */
5998 public static final int DEVICE_NONE = AudioSystem.DEVICE_NONE;
5999 /** @hide
Eric Laurent948d3272014-05-16 15:18:45 -07006000 * The audio output device code for the small speaker at the front of the device used
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08006001 * when placing calls. Does not refer to an in-ear headphone without attached microphone,
6002 * such as earbuds, earphones, or in-ear monitors (IEM). Those would be handled as a
6003 * {@link #DEVICE_OUT_WIRED_HEADPHONE}.
6004 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01006005 @UnsupportedAppUsage
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08006006 public static final int DEVICE_OUT_EARPIECE = AudioSystem.DEVICE_OUT_EARPIECE;
Eric Laurent948d3272014-05-16 15:18:45 -07006007 /** @hide
6008 * The audio output device code for the built-in speaker */
Mathew Inwood31a792a2018-08-17 08:54:26 +01006009 @UnsupportedAppUsage
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08006010 public static final int DEVICE_OUT_SPEAKER = AudioSystem.DEVICE_OUT_SPEAKER;
Eric Laurent948d3272014-05-16 15:18:45 -07006011 /** @hide
6012 * The audio output device code for a wired headset with attached microphone */
Mathew Inwood31a792a2018-08-17 08:54:26 +01006013 @UnsupportedAppUsage
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08006014 public static final int DEVICE_OUT_WIRED_HEADSET = AudioSystem.DEVICE_OUT_WIRED_HEADSET;
Eric Laurent948d3272014-05-16 15:18:45 -07006015 /** @hide
6016 * The audio output device code for a wired headphone without attached microphone */
Mathew Inwood31a792a2018-08-17 08:54:26 +01006017 @UnsupportedAppUsage
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08006018 public static final int DEVICE_OUT_WIRED_HEADPHONE = AudioSystem.DEVICE_OUT_WIRED_HEADPHONE;
Eric Laurent948d3272014-05-16 15:18:45 -07006019 /** @hide
Paul McLean145c9532017-08-04 11:12:19 -06006020 * The audio output device code for a USB headphone with attached microphone */
6021 public static final int DEVICE_OUT_USB_HEADSET = AudioSystem.DEVICE_OUT_USB_HEADSET;
6022 /** @hide
Eric Laurent948d3272014-05-16 15:18:45 -07006023 * The audio output device code for generic Bluetooth SCO, for voice */
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08006024 public static final int DEVICE_OUT_BLUETOOTH_SCO = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO;
Eric Laurent948d3272014-05-16 15:18:45 -07006025 /** @hide
6026 * The audio output device code for Bluetooth SCO Headset Profile (HSP) and
6027 * Hands-Free Profile (HFP), for voice
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08006028 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01006029 @UnsupportedAppUsage
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08006030 public static final int DEVICE_OUT_BLUETOOTH_SCO_HEADSET =
6031 AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_HEADSET;
Eric Laurent948d3272014-05-16 15:18:45 -07006032 /** @hide
6033 * The audio output device code for Bluetooth SCO car audio, for voice */
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08006034 public static final int DEVICE_OUT_BLUETOOTH_SCO_CARKIT =
6035 AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_CARKIT;
Eric Laurent948d3272014-05-16 15:18:45 -07006036 /** @hide
6037 * The audio output device code for generic Bluetooth A2DP, for music */
Mathew Inwood31a792a2018-08-17 08:54:26 +01006038 @UnsupportedAppUsage
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08006039 public static final int DEVICE_OUT_BLUETOOTH_A2DP = AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP;
Eric Laurent948d3272014-05-16 15:18:45 -07006040 /** @hide
6041 * The audio output device code for Bluetooth A2DP headphones, for music */
Mathew Inwood31a792a2018-08-17 08:54:26 +01006042 @UnsupportedAppUsage
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08006043 public static final int DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES =
6044 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES;
Eric Laurent948d3272014-05-16 15:18:45 -07006045 /** @hide
6046 * The audio output device code for Bluetooth A2DP external speaker, for music */
Mathew Inwood31a792a2018-08-17 08:54:26 +01006047 @UnsupportedAppUsage
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08006048 public static final int DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER =
6049 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER;
Eric Laurent948d3272014-05-16 15:18:45 -07006050 /** @hide
6051 * The audio output device code for S/PDIF (legacy) or HDMI
6052 * Deprecated: replaced by {@link #DEVICE_OUT_HDMI} */
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08006053 public static final int DEVICE_OUT_AUX_DIGITAL = AudioSystem.DEVICE_OUT_AUX_DIGITAL;
Eric Laurent948d3272014-05-16 15:18:45 -07006054 /** @hide
6055 * The audio output device code for HDMI */
Mathew Inwood31a792a2018-08-17 08:54:26 +01006056 @UnsupportedAppUsage
Eric Laurent948d3272014-05-16 15:18:45 -07006057 public static final int DEVICE_OUT_HDMI = AudioSystem.DEVICE_OUT_HDMI;
6058 /** @hide
6059 * The audio output device code for an analog wired headset attached via a
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08006060 * docking station
6061 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01006062 @UnsupportedAppUsage
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08006063 public static final int DEVICE_OUT_ANLG_DOCK_HEADSET = AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET;
Eric Laurent948d3272014-05-16 15:18:45 -07006064 /** @hide
6065 * The audio output device code for a digital wired headset attached via a
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08006066 * docking station
6067 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01006068 @UnsupportedAppUsage
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08006069 public static final int DEVICE_OUT_DGTL_DOCK_HEADSET = AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET;
Eric Laurent948d3272014-05-16 15:18:45 -07006070 /** @hide
6071 * The audio output device code for a USB audio accessory. The accessory is in USB host
Eric Laurent59f48272012-04-05 19:42:21 -07006072 * mode and the Android device in USB device mode
6073 */
6074 public static final int DEVICE_OUT_USB_ACCESSORY = AudioSystem.DEVICE_OUT_USB_ACCESSORY;
Eric Laurent948d3272014-05-16 15:18:45 -07006075 /** @hide
6076 * The audio output device code for a USB audio device. The device is in USB device
Eric Laurent59f48272012-04-05 19:42:21 -07006077 * mode and the Android device in USB host mode
6078 */
6079 public static final int DEVICE_OUT_USB_DEVICE = AudioSystem.DEVICE_OUT_USB_DEVICE;
Eric Laurent948d3272014-05-16 15:18:45 -07006080 /** @hide
6081 * The audio output device code for projection output.
6082 */
6083 public static final int DEVICE_OUT_REMOTE_SUBMIX = AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
6084 /** @hide
6085 * The audio output device code the telephony voice TX path.
6086 */
6087 public static final int DEVICE_OUT_TELEPHONY_TX = AudioSystem.DEVICE_OUT_TELEPHONY_TX;
6088 /** @hide
6089 * The audio output device code for an analog jack with line impedance detected.
6090 */
6091 public static final int DEVICE_OUT_LINE = AudioSystem.DEVICE_OUT_LINE;
6092 /** @hide
6093 * The audio output device code for HDMI Audio Return Channel.
6094 */
6095 public static final int DEVICE_OUT_HDMI_ARC = AudioSystem.DEVICE_OUT_HDMI_ARC;
6096 /** @hide
Kuowei Lif898eae2020-10-27 16:41:18 +08006097 * The audio output device code for HDMI enhanced Audio Return Channel.
6098 */
6099 public static final int DEVICE_OUT_HDMI_EARC = AudioSystem.DEVICE_OUT_HDMI_EARC;
6100 /** @hide
Eric Laurent948d3272014-05-16 15:18:45 -07006101 * The audio output device code for S/PDIF digital connection.
6102 */
6103 public static final int DEVICE_OUT_SPDIF = AudioSystem.DEVICE_OUT_SPDIF;
6104 /** @hide
6105 * The audio output device code for built-in FM transmitter.
6106 */
6107 public static final int DEVICE_OUT_FM = AudioSystem.DEVICE_OUT_FM;
6108 /** @hide
Eric Laurentca94af02020-08-07 12:30:44 -07006109 * The audio output device code for echo reference injection point.
6110 */
6111 public static final int DEVICE_OUT_ECHO_CANCELLER = AudioSystem.DEVICE_OUT_ECHO_CANCELLER;
6112 /** @hide
Eric Laurent6239d7e2020-08-07 10:58:14 -07006113 * The audio output device code for a BLE audio headset.
6114 */
6115 public static final int DEVICE_OUT_BLE_HEADSET = AudioSystem.DEVICE_OUT_BLE_HEADSET;
6116 /** @hide
6117 * The audio output device code for a BLE audio speaker.
6118 */
6119 public static final int DEVICE_OUT_BLE_SPEAKER = AudioSystem.DEVICE_OUT_BLE_SPEAKER;
6120 /** @hide
Eric Laurent277373e2022-01-20 14:42:22 +01006121 * The audio output device code for a BLE audio brodcast group.
6122 */
6123 public static final int DEVICE_OUT_BLE_BROADCAST = AudioSystem.DEVICE_OUT_BLE_BROADCAST;
6124 /** @hide
Eric Laurent948d3272014-05-16 15:18:45 -07006125 * This is not used as a returned value from {@link #getDevicesForStream}, but could be
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08006126 * used in the future in a set method to select whatever default device is chosen by the
6127 * platform-specific implementation.
6128 */
6129 public static final int DEVICE_OUT_DEFAULT = AudioSystem.DEVICE_OUT_DEFAULT;
6130
Eric Laurent948d3272014-05-16 15:18:45 -07006131 /** @hide
6132 * The audio input device code for default built-in microphone
6133 */
6134 public static final int DEVICE_IN_BUILTIN_MIC = AudioSystem.DEVICE_IN_BUILTIN_MIC;
6135 /** @hide
6136 * The audio input device code for a Bluetooth SCO headset
6137 */
6138 public static final int DEVICE_IN_BLUETOOTH_SCO_HEADSET =
6139 AudioSystem.DEVICE_IN_BLUETOOTH_SCO_HEADSET;
6140 /** @hide
6141 * The audio input device code for wired headset microphone
6142 */
6143 public static final int DEVICE_IN_WIRED_HEADSET =
6144 AudioSystem.DEVICE_IN_WIRED_HEADSET;
6145 /** @hide
6146 * The audio input device code for HDMI
6147 */
6148 public static final int DEVICE_IN_HDMI =
6149 AudioSystem.DEVICE_IN_HDMI;
6150 /** @hide
Nick Chalko2e1f76a2018-10-25 10:19:10 -07006151 * The audio input device code for HDMI ARC
6152 */
6153 public static final int DEVICE_IN_HDMI_ARC =
6154 AudioSystem.DEVICE_IN_HDMI_ARC;
6155
6156 /** @hide
Kuowei Lif898eae2020-10-27 16:41:18 +08006157 * The audio input device code for HDMI EARC
6158 */
6159 public static final int DEVICE_IN_HDMI_EARC =
6160 AudioSystem.DEVICE_IN_HDMI_EARC;
6161
6162 /** @hide
Eric Laurent948d3272014-05-16 15:18:45 -07006163 * The audio input device code for telephony voice RX path
6164 */
6165 public static final int DEVICE_IN_TELEPHONY_RX =
6166 AudioSystem.DEVICE_IN_TELEPHONY_RX;
6167 /** @hide
6168 * The audio input device code for built-in microphone pointing to the back
6169 */
6170 public static final int DEVICE_IN_BACK_MIC =
6171 AudioSystem.DEVICE_IN_BACK_MIC;
6172 /** @hide
6173 * The audio input device code for analog from a docking station
6174 */
6175 public static final int DEVICE_IN_ANLG_DOCK_HEADSET =
6176 AudioSystem.DEVICE_IN_ANLG_DOCK_HEADSET;
6177 /** @hide
6178 * The audio input device code for digital from a docking station
6179 */
6180 public static final int DEVICE_IN_DGTL_DOCK_HEADSET =
6181 AudioSystem.DEVICE_IN_DGTL_DOCK_HEADSET;
6182 /** @hide
6183 * The audio input device code for a USB audio accessory. The accessory is in USB host
6184 * mode and the Android device in USB device mode
6185 */
6186 public static final int DEVICE_IN_USB_ACCESSORY =
6187 AudioSystem.DEVICE_IN_USB_ACCESSORY;
6188 /** @hide
6189 * The audio input device code for a USB audio device. The device is in USB device
6190 * mode and the Android device in USB host mode
6191 */
6192 public static final int DEVICE_IN_USB_DEVICE =
6193 AudioSystem.DEVICE_IN_USB_DEVICE;
6194 /** @hide
6195 * The audio input device code for a FM radio tuner
6196 */
6197 public static final int DEVICE_IN_FM_TUNER = AudioSystem.DEVICE_IN_FM_TUNER;
6198 /** @hide
6199 * The audio input device code for a TV tuner
6200 */
6201 public static final int DEVICE_IN_TV_TUNER = AudioSystem.DEVICE_IN_TV_TUNER;
6202 /** @hide
6203 * The audio input device code for an analog jack with line impedance detected
6204 */
6205 public static final int DEVICE_IN_LINE = AudioSystem.DEVICE_IN_LINE;
6206 /** @hide
6207 * The audio input device code for a S/PDIF digital connection
6208 */
6209 public static final int DEVICE_IN_SPDIF = AudioSystem.DEVICE_IN_SPDIF;
Terry Heo112c19e2014-07-07 10:25:38 +09006210 /** @hide
6211 * The audio input device code for audio loopback
6212 */
6213 public static final int DEVICE_IN_LOOPBACK = AudioSystem.DEVICE_IN_LOOPBACK;
Eric Laurent6239d7e2020-08-07 10:58:14 -07006214 /** @hide
Eric Laurentca94af02020-08-07 12:30:44 -07006215 * The audio input device code for an echo reference capture point.
6216 */
6217 public static final int DEVICE_IN_ECHO_REFERENCE = AudioSystem.DEVICE_IN_ECHO_REFERENCE;
6218 /** @hide
Eric Laurent6239d7e2020-08-07 10:58:14 -07006219 * The audio input device code for a BLE audio headset.
6220 */
6221 public static final int DEVICE_IN_BLE_HEADSET = AudioSystem.DEVICE_IN_BLE_HEADSET;
Eric Laurent948d3272014-05-16 15:18:45 -07006222
6223 /**
6224 * Return true if the device code corresponds to an output device.
6225 * @hide
6226 */
6227 public static boolean isOutputDevice(int device)
6228 {
Eric Laurent12bf3212023-08-25 19:59:22 +02006229 return !AudioSystem.isInputDevice(device);
Eric Laurent948d3272014-05-16 15:18:45 -07006230 }
6231
6232 /**
6233 * Return true if the device code corresponds to an input device.
6234 * @hide
6235 */
6236 public static boolean isInputDevice(int device)
6237 {
Eric Laurent12bf3212023-08-25 19:59:22 +02006238 return AudioSystem.isInputDevice(device);
Eric Laurent948d3272014-05-16 15:18:45 -07006239 }
6240
6241
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08006242 /**
6243 * Return the enabled devices for the specified output stream type.
6244 *
6245 * @param streamType The stream type to query. One of
6246 * {@link #STREAM_VOICE_CALL},
6247 * {@link #STREAM_SYSTEM},
6248 * {@link #STREAM_RING},
6249 * {@link #STREAM_MUSIC},
6250 * {@link #STREAM_ALARM},
6251 * {@link #STREAM_NOTIFICATION},
Jean-Michel Trivi8e0bc782016-11-25 10:22:23 -08006252 * {@link #STREAM_DTMF},
6253 * {@link #STREAM_ACCESSIBILITY}.
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08006254 *
6255 * @return The bit-mask "or" of audio output device codes for all enabled devices on this
6256 * stream. Zero or more of
6257 * {@link #DEVICE_OUT_EARPIECE},
6258 * {@link #DEVICE_OUT_SPEAKER},
6259 * {@link #DEVICE_OUT_WIRED_HEADSET},
6260 * {@link #DEVICE_OUT_WIRED_HEADPHONE},
6261 * {@link #DEVICE_OUT_BLUETOOTH_SCO},
6262 * {@link #DEVICE_OUT_BLUETOOTH_SCO_HEADSET},
6263 * {@link #DEVICE_OUT_BLUETOOTH_SCO_CARKIT},
6264 * {@link #DEVICE_OUT_BLUETOOTH_A2DP},
6265 * {@link #DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES},
6266 * {@link #DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER},
Eric Laurent948d3272014-05-16 15:18:45 -07006267 * {@link #DEVICE_OUT_HDMI},
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08006268 * {@link #DEVICE_OUT_ANLG_DOCK_HEADSET},
6269 * {@link #DEVICE_OUT_DGTL_DOCK_HEADSET}.
Eric Laurent948d3272014-05-16 15:18:45 -07006270 * {@link #DEVICE_OUT_USB_ACCESSORY}.
6271 * {@link #DEVICE_OUT_USB_DEVICE}.
6272 * {@link #DEVICE_OUT_REMOTE_SUBMIX}.
6273 * {@link #DEVICE_OUT_TELEPHONY_TX}.
6274 * {@link #DEVICE_OUT_LINE}.
6275 * {@link #DEVICE_OUT_HDMI_ARC}.
Kuowei Lif898eae2020-10-27 16:41:18 +08006276 * {@link #DEVICE_OUT_HDMI_EARC}.
Eric Laurent948d3272014-05-16 15:18:45 -07006277 * {@link #DEVICE_OUT_SPDIF}.
6278 * {@link #DEVICE_OUT_FM}.
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08006279 * {@link #DEVICE_OUT_DEFAULT} is not used here.
6280 *
6281 * The implementation may support additional device codes beyond those listed, so
6282 * the application should ignore any bits which it does not recognize.
6283 * Note that the information may be imprecise when the implementation
6284 * cannot distinguish whether a particular device is enabled.
6285 *
Andy Hungb11e4c72021-04-13 19:31:00 -07006286 * @deprecated on {@link android.os.Build.VERSION_CODES#T} as new devices
6287 * will have multi-bit device types.
6288 * Prefer to use {@link #getDevicesForAttributes()} instead,
6289 * noting that getDevicesForStream() has a few small discrepancies
6290 * for better volume handling.
6291 * @hide
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08006292 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01006293 @UnsupportedAppUsage
Andy Hungb11e4c72021-04-13 19:31:00 -07006294 @Deprecated
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08006295 public int getDevicesForStream(int streamType) {
6296 switch (streamType) {
Andy Hungb11e4c72021-04-13 19:31:00 -07006297 case STREAM_VOICE_CALL:
6298 case STREAM_SYSTEM:
6299 case STREAM_RING:
6300 case STREAM_MUSIC:
6301 case STREAM_ALARM:
6302 case STREAM_NOTIFICATION:
6303 case STREAM_DTMF:
6304 case STREAM_ACCESSIBILITY:
6305 final IAudioService service = getService();
6306 try {
6307 return service.getDeviceMaskForStream(streamType);
6308 } catch (RemoteException e) {
6309 throw e.rethrowFromSystemServer();
6310 }
6311 default:
6312 return 0;
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08006313 }
6314 }
6315
Jean-Michel Trivi56b97b72020-01-07 14:18:05 -08006316 /**
6317 * @hide
6318 * Get the audio devices that would be used for the routing of the given audio attributes.
6319 * @param attributes the {@link AudioAttributes} for which the routing is being queried
6320 * @return an empty list if there was an issue with the request, a list of audio devices
6321 * otherwise (typically one device, except for duplicated paths).
6322 */
6323 @SystemApi
kholoud mohamed37839212021-03-15 16:49:06 +00006324 @RequiresPermission(anyOf = {
Jean-Michel Trivic4557822023-01-23 18:19:52 +00006325 Manifest.permission.MODIFY_AUDIO_ROUTING,
6326 Manifest.permission.QUERY_AUDIO_STATE
kholoud mohamed37839212021-03-15 16:49:06 +00006327 })
Jean-Michel Trivi0e87bca2020-02-18 14:30:29 -08006328 public @NonNull List<AudioDeviceAttributes> getDevicesForAttributes(
Jean-Michel Trivi56b97b72020-01-07 14:18:05 -08006329 @NonNull AudioAttributes attributes) {
6330 Objects.requireNonNull(attributes);
6331 final IAudioService service = getService();
6332 try {
6333 return service.getDevicesForAttributes(attributes);
6334 } catch (RemoteException e) {
6335 throw e.rethrowFromSystemServer();
6336 }
6337 }
6338
Paul Wangebadb692022-12-15 20:40:19 +00006339 // Each listener corresponds to a unique callback stub because each listener can subscribe to
6340 // different AudioAttributes.
6341 private final ConcurrentHashMap<OnDevicesForAttributesChangedListener,
6342 IDevicesForAttributesCallbackStub> mDevicesForAttributesListenerToStub =
6343 new ConcurrentHashMap<>();
6344
6345 private static final class IDevicesForAttributesCallbackStub
6346 extends IDevicesForAttributesCallback.Stub {
6347 ListenerInfo<OnDevicesForAttributesChangedListener> mInfo;
6348
6349 IDevicesForAttributesCallbackStub(@NonNull OnDevicesForAttributesChangedListener listener,
6350 @NonNull Executor executor) {
6351 mInfo = new ListenerInfo<>(listener, executor);
6352 }
6353
6354 public void register(boolean register, AudioAttributes attributes) {
6355 try {
6356 if (register) {
6357 getService().addOnDevicesForAttributesChangedListener(attributes, this);
6358 } else {
6359 getService().removeOnDevicesForAttributesChangedListener(this);
6360 }
6361 } catch (RemoteException e) {
6362 throw e.rethrowFromSystemServer();
6363 }
6364 }
6365
6366 @Override
6367 public void onDevicesForAttributesChanged(AudioAttributes attributes, boolean forVolume,
6368 List<AudioDeviceAttributes> devices) {
6369 // forVolume is ignored. The case where it is `true` is not handled.
6370 mInfo.mExecutor.execute(() ->
6371 mInfo.mListener.onDevicesForAttributesChanged(
6372 attributes, devices));
6373 }
6374 }
6375
6376 /**
6377 * @hide
6378 * Interface to be notified of when routing changes for the registered audio attributes.
6379 */
6380 @SystemApi
6381 public interface OnDevicesForAttributesChangedListener {
6382 /**
6383 * Called on the listener to indicate that the audio devices for the given audio
6384 * attributes have changed.
6385 * @param attributes the {@link AudioAttributes} whose routing changed
6386 * @param devices a list of newly routed audio devices
6387 */
6388 void onDevicesForAttributesChanged(@NonNull AudioAttributes attributes,
6389 @NonNull List<AudioDeviceAttributes> devices);
6390 }
6391
6392 /**
6393 * @hide
6394 * Adds a listener for being notified of routing changes for the given {@link AudioAttributes}.
6395 * @param attributes the {@link AudioAttributes} to listen for routing changes
6396 * @param executor
6397 * @param listener
6398 */
6399 @SystemApi
6400 @RequiresPermission(anyOf = {
Jean-Michel Trivic4557822023-01-23 18:19:52 +00006401 Manifest.permission.MODIFY_AUDIO_ROUTING,
6402 Manifest.permission.QUERY_AUDIO_STATE
Paul Wangebadb692022-12-15 20:40:19 +00006403 })
6404 public void addOnDevicesForAttributesChangedListener(@NonNull AudioAttributes attributes,
6405 @NonNull @CallbackExecutor Executor executor,
6406 @NonNull OnDevicesForAttributesChangedListener listener) {
6407 Objects.requireNonNull(attributes);
6408 Objects.requireNonNull(executor);
6409 Objects.requireNonNull(listener);
6410
6411 synchronized (mDevicesForAttributesListenerToStub) {
6412 IDevicesForAttributesCallbackStub callbackStub =
6413 mDevicesForAttributesListenerToStub.get(listener);
6414
6415 if (callbackStub == null) {
6416 callbackStub = new IDevicesForAttributesCallbackStub(listener, executor);
6417 mDevicesForAttributesListenerToStub.put(listener, callbackStub);
6418 }
6419
6420 callbackStub.register(true, attributes);
6421 }
6422 }
6423
6424 /**
6425 * @hide
6426 * Removes a previously registered listener for being notified of routing changes for the given
6427 * {@link AudioAttributes}.
6428 * @param listener
6429 */
6430 @SystemApi
6431 @RequiresPermission(anyOf = {
Jean-Michel Trivic4557822023-01-23 18:19:52 +00006432 Manifest.permission.MODIFY_AUDIO_ROUTING,
6433 Manifest.permission.QUERY_AUDIO_STATE
Paul Wangebadb692022-12-15 20:40:19 +00006434 })
6435 public void removeOnDevicesForAttributesChangedListener(
6436 @NonNull OnDevicesForAttributesChangedListener listener) {
6437 Objects.requireNonNull(listener);
6438
6439 synchronized (mDevicesForAttributesListenerToStub) {
6440 IDevicesForAttributesCallbackStub callbackStub =
6441 mDevicesForAttributesListenerToStub.get(listener);
6442 if (callbackStub != null) {
6443 callbackStub.register(false, null /* attributes */);
6444 }
6445
6446 mDevicesForAttributesListenerToStub.remove(listener);
6447 }
6448 }
6449
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07006450 /**
Dorin Drimusdaeb6a92021-12-22 11:46:26 +01006451 * Get the audio devices that would be used for the routing of the given audio attributes.
6452 * These are the devices anticipated to play sound from an {@link AudioTrack} created with
6453 * the specified {@link AudioAttributes}.
6454 * The audio routing can change if audio devices are physically connected or disconnected or
6455 * concurrently through {@link AudioRouting} or {@link MediaRouter}.
6456 * @param attributes the {@link AudioAttributes} for which the routing is being queried
6457 * @return an empty list if there was an issue with the request, a list of
6458 * {@link AudioDeviceInfo} otherwise (typically one device, except for duplicated paths).
6459 */
6460 public @NonNull List<AudioDeviceInfo> getAudioDevicesForAttributes(
6461 @NonNull AudioAttributes attributes) {
6462 final List<AudioDeviceAttributes> devicesForAttributes;
6463 try {
6464 Objects.requireNonNull(attributes);
6465 final IAudioService service = getService();
6466 devicesForAttributes = service.getDevicesForAttributesUnprotected(attributes);
6467 } catch (Exception e) {
6468 Log.i(TAG, "No audio devices available for specified attributes.");
6469 return Collections.emptyList();
6470 }
6471
6472 // Map from AudioDeviceAttributes to AudioDeviceInfo
6473 AudioDeviceInfo[] outputDeviceInfos = getDevicesStatic(GET_DEVICES_OUTPUTS);
6474 List<AudioDeviceInfo> deviceInfosForAttributes = new ArrayList<>();
6475 for (AudioDeviceAttributes deviceForAttributes : devicesForAttributes) {
6476 for (AudioDeviceInfo deviceInfo : outputDeviceInfos) {
6477 if (deviceForAttributes.getType() == deviceInfo.getType()
6478 && TextUtils.equals(deviceForAttributes.getAddress(),
6479 deviceInfo.getAddress())) {
6480 deviceInfosForAttributes.add(deviceInfo);
6481 }
6482 }
6483 }
6484 return Collections.unmodifiableList(deviceInfosForAttributes);
6485 }
6486
6487 /**
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07006488 * @hide
Madhava Srinivasanb5ed6002020-06-11 21:49:24 +00006489 * Volume behavior for an audio device that has no particular volume behavior set. Invalid as
Marvin Ramin5495cc92020-07-23 11:58:33 +02006490 * an argument to {@link #setDeviceVolumeBehavior(AudioDeviceAttributes, int)} and should not
6491 * be returned by {@link #getDeviceVolumeBehavior(AudioDeviceAttributes)}.
Madhava Srinivasanb5ed6002020-06-11 21:49:24 +00006492 */
6493 public static final int DEVICE_VOLUME_BEHAVIOR_UNSET = -1;
6494 /**
6495 * @hide
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07006496 * Volume behavior for an audio device where a software attenuation is applied
Marvin Ramin5495cc92020-07-23 11:58:33 +02006497 * @see #setDeviceVolumeBehavior(AudioDeviceAttributes, int)
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07006498 */
Marvin Ramin5495cc92020-07-23 11:58:33 +02006499 @SystemApi
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07006500 public static final int DEVICE_VOLUME_BEHAVIOR_VARIABLE = 0;
6501 /**
6502 * @hide
6503 * Volume behavior for an audio device where the volume is always set to provide no attenuation
6504 * nor gain (e.g. unit gain).
Marvin Ramin5495cc92020-07-23 11:58:33 +02006505 * @see #setDeviceVolumeBehavior(AudioDeviceAttributes, int)
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07006506 */
Marvin Ramin5495cc92020-07-23 11:58:33 +02006507 @SystemApi
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07006508 public static final int DEVICE_VOLUME_BEHAVIOR_FULL = 1;
6509 /**
6510 * @hide
6511 * Volume behavior for an audio device where the volume is either set to muted, or to provide
6512 * no attenuation nor gain (e.g. unit gain).
Marvin Ramin5495cc92020-07-23 11:58:33 +02006513 * @see #setDeviceVolumeBehavior(AudioDeviceAttributes, int)
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07006514 */
Marvin Ramin5495cc92020-07-23 11:58:33 +02006515 @SystemApi
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07006516 public static final int DEVICE_VOLUME_BEHAVIOR_FIXED = 2;
6517 /**
6518 * @hide
6519 * Volume behavior for an audio device where no software attenuation is applied, and
6520 * the volume is kept synchronized between the host and the device itself through a
6521 * device-specific protocol such as BT AVRCP.
Jean-Michel Trivi4ec406a2023-03-20 22:44:34 +00006522 * @see #setDeviceVolumeBehavior(AudioDeviceAttributes, int)
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07006523 */
Marvin Ramin5495cc92020-07-23 11:58:33 +02006524 @SystemApi
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07006525 public static final int DEVICE_VOLUME_BEHAVIOR_ABSOLUTE = 3;
6526 /**
6527 * @hide
6528 * Volume behavior for an audio device where no software attenuation is applied, and
6529 * the volume is kept synchronized between the host and the device itself through a
6530 * device-specific protocol (such as for hearing aids), based on the audio mode (e.g.
6531 * normal vs in phone call).
6532 * @see #setMode(int)
Jean-Michel Trivi4ec406a2023-03-20 22:44:34 +00006533 * @see #setDeviceVolumeBehavior(AudioDeviceAttributes, int)
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07006534 */
Marvin Ramin5495cc92020-07-23 11:58:33 +02006535 @SystemApi
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07006536 public static final int DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE = 4;
6537
Yan Han6f96eec2023-01-20 14:22:15 +01006538 /**
6539 * @hide
6540 * A variant of {@link #DEVICE_VOLUME_BEHAVIOR_ABSOLUTE} where the host cannot reliably set
6541 * the volume percentage of the audio device. Specifically, {@link #setStreamVolume} will have
6542 * no effect, or an unreliable effect.
6543 */
6544 @SystemApi
6545 public static final int DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_ADJUST_ONLY = 5;
6546
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07006547 /** @hide */
6548 @IntDef({
6549 DEVICE_VOLUME_BEHAVIOR_VARIABLE,
6550 DEVICE_VOLUME_BEHAVIOR_FULL,
6551 DEVICE_VOLUME_BEHAVIOR_FIXED,
6552 DEVICE_VOLUME_BEHAVIOR_ABSOLUTE,
6553 DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE,
Yan Han6f96eec2023-01-20 14:22:15 +01006554 DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_ADJUST_ONLY,
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07006555 })
6556 @Retention(RetentionPolicy.SOURCE)
6557 public @interface DeviceVolumeBehavior {}
6558
Madhava Srinivasanb5ed6002020-06-11 21:49:24 +00006559 /** @hide */
6560 @IntDef({
6561 DEVICE_VOLUME_BEHAVIOR_UNSET,
6562 DEVICE_VOLUME_BEHAVIOR_VARIABLE,
6563 DEVICE_VOLUME_BEHAVIOR_FULL,
6564 DEVICE_VOLUME_BEHAVIOR_FIXED,
6565 DEVICE_VOLUME_BEHAVIOR_ABSOLUTE,
6566 DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE,
Yan Han6f96eec2023-01-20 14:22:15 +01006567 DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_ADJUST_ONLY,
Madhava Srinivasanb5ed6002020-06-11 21:49:24 +00006568 })
6569 @Retention(RetentionPolicy.SOURCE)
6570 public @interface DeviceVolumeBehaviorState {}
6571
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07006572 /**
Yan Han6f96eec2023-01-20 14:22:15 +01006573 * Variants of absolute volume behavior that are set in {@link AudioDeviceVolumeManager}.
6574 * @hide
6575 */
6576 @IntDef({
6577 DEVICE_VOLUME_BEHAVIOR_ABSOLUTE,
6578 DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_ADJUST_ONLY,
6579 })
6580 @Retention(RetentionPolicy.SOURCE)
6581 public @interface AbsoluteDeviceVolumeBehavior {}
6582
6583 /**
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07006584 * @hide
Jean-Michel Trivi4ec406a2023-03-20 22:44:34 +00006585 * Throws IAE on an invalid volume behavior value
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07006586 * @param volumeBehavior behavior value to check
6587 */
Jean-Michel Trivi4ec406a2023-03-20 22:44:34 +00006588 public static void enforceValidVolumeBehavior(int volumeBehavior) {
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07006589 switch (volumeBehavior) {
6590 case DEVICE_VOLUME_BEHAVIOR_VARIABLE:
6591 case DEVICE_VOLUME_BEHAVIOR_FULL:
6592 case DEVICE_VOLUME_BEHAVIOR_FIXED:
Jean-Michel Trivi4ec406a2023-03-20 22:44:34 +00006593 case DEVICE_VOLUME_BEHAVIOR_ABSOLUTE:
6594 case DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE:
6595 case DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_ADJUST_ONLY:
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07006596 return;
6597 default:
6598 throw new IllegalArgumentException("Illegal volume behavior " + volumeBehavior);
6599 }
6600 }
6601
6602 /**
6603 * @hide
6604 * Sets the volume behavior for an audio output device.
Jean-Michel Trivi4ec406a2023-03-20 22:44:34 +00006605 * @see #DEVICE_VOLUME_BEHAVIOR_VARIABLE
6606 * @see #DEVICE_VOLUME_BEHAVIOR_FULL
6607 * @see #DEVICE_VOLUME_BEHAVIOR_FIXED
6608 * @see #DEVICE_VOLUME_BEHAVIOR_ABSOLUTE
6609 * @see #DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE
Marvin Ramin5495cc92020-07-23 11:58:33 +02006610 * @param device the device to be affected
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07006611 * @param deviceVolumeBehavior one of the device behaviors
6612 */
Marvin Ramin5495cc92020-07-23 11:58:33 +02006613 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00006614 @RequiresPermission(anyOf = {
6615 Manifest.permission.MODIFY_AUDIO_ROUTING,
Jean-Michel Trivi10fd2d72023-02-13 18:06:36 +00006616 Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED
Jean-Michel Trivic4557822023-01-23 18:19:52 +00006617 })
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07006618 public void setDeviceVolumeBehavior(@NonNull AudioDeviceAttributes device,
Jean-Michel Trivi4ec406a2023-03-20 22:44:34 +00006619 @DeviceVolumeBehavior int deviceVolumeBehavior) {
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07006620 // verify arguments (validity of device type is enforced in server)
6621 Objects.requireNonNull(device);
Jean-Michel Trivi4ec406a2023-03-20 22:44:34 +00006622 enforceValidVolumeBehavior(deviceVolumeBehavior);
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07006623 // communicate with service
6624 final IAudioService service = getService();
6625 try {
6626 service.setDeviceVolumeBehavior(device, deviceVolumeBehavior,
6627 mApplicationContext.getOpPackageName());
6628 } catch (RemoteException e) {
6629 throw e.rethrowFromSystemServer();
6630 }
6631 }
6632
6633 /**
6634 * @hide
Yan Han6f96eec2023-01-20 14:22:15 +01006635 * Controls whether DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_ADJUST_ONLY may be returned by
6636 * getDeviceVolumeBehavior. If this is disabled, DEVICE_VOLUME_BEHAVIOR_FULL is returned
6637 * in its place.
6638 */
6639 @ChangeId
6640 @EnabledSince(targetSdkVersion = android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
Yan Han31b10112023-02-13 17:25:46 +01006641 @Overridable
Yan Han6f96eec2023-01-20 14:22:15 +01006642 public static final long RETURN_DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_ADJUST_ONLY = 240663182L;
6643
6644 /**
6645 * @hide
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07006646 * Returns the volume device behavior for the given audio device
6647 * @param device the audio device
6648 * @return the volume behavior for the device
6649 */
Marvin Ramin5495cc92020-07-23 11:58:33 +02006650 @SystemApi
kholoud mohamed37839212021-03-15 16:49:06 +00006651 @RequiresPermission(anyOf = {
Jean-Michel Trivic4557822023-01-23 18:19:52 +00006652 Manifest.permission.MODIFY_AUDIO_ROUTING,
6653 Manifest.permission.QUERY_AUDIO_STATE,
Jean-Michel Trivi10fd2d72023-02-13 18:06:36 +00006654 Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED
kholoud mohamed37839212021-03-15 16:49:06 +00006655 })
Marvin Ramin5495cc92020-07-23 11:58:33 +02006656 public @DeviceVolumeBehavior
6657 int getDeviceVolumeBehavior(@NonNull AudioDeviceAttributes device) {
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07006658 // verify arguments (validity of device type is enforced in server)
6659 Objects.requireNonNull(device);
6660 // communicate with service
6661 final IAudioService service = getService();
6662 try {
Yan Han6f96eec2023-01-20 14:22:15 +01006663 int behavior = service.getDeviceVolumeBehavior(device);
6664 if (!CompatChanges.isChangeEnabled(RETURN_DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_ADJUST_ONLY)
6665 && behavior == DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_ADJUST_ONLY) {
6666 return AudioManager.DEVICE_VOLUME_BEHAVIOR_FULL;
6667 }
6668 return behavior;
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07006669 } catch (RemoteException e) {
6670 throw e.rethrowFromSystemServer();
6671 }
6672 }
6673
kholoud mohamed37839212021-03-15 16:49:06 +00006674 /**
6675 * @hide
6676 * Returns {@code true} if the volume device behavior is {@link #DEVICE_VOLUME_BEHAVIOR_FULL}.
6677 */
6678 @TestApi
6679 @RequiresPermission(anyOf = {
Jean-Michel Trivic4557822023-01-23 18:19:52 +00006680 Manifest.permission.MODIFY_AUDIO_ROUTING,
6681 Manifest.permission.QUERY_AUDIO_STATE,
Jean-Michel Trivi10fd2d72023-02-13 18:06:36 +00006682 Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED
kholoud mohamed37839212021-03-15 16:49:06 +00006683 })
6684 public boolean isFullVolumeDevice() {
6685 final AudioAttributes attributes = new AudioAttributes.Builder()
6686 .setUsage(AudioAttributes.USAGE_MEDIA)
6687 .build();
6688 final List<AudioDeviceAttributes> devices = getDevicesForAttributes(attributes);
6689 for (AudioDeviceAttributes device : devices) {
6690 if (getDeviceVolumeBehavior(device) == DEVICE_VOLUME_BEHAVIOR_FULL) {
6691 return true;
6692 }
6693 }
6694 return false;
6695 }
6696
Nathalie Le Clair517a1322021-10-15 14:22:41 +02006697 /**
Eric Laurentb1fbaac2012-05-29 09:24:28 -07006698 * Indicate wired accessory connection state change.
6699 * @param device type of device connected/disconnected (AudioManager.DEVICE_OUT_xxx)
6700 * @param state new connection state: 1 connected, 0 disconnected
6701 * @param name device name
6702 * {@hide}
6703 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01006704 @UnsupportedAppUsage
Jean-Michel Trivic4557822023-01-23 18:19:52 +00006705 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
Nathalie Le Clair7b72c392022-04-04 13:25:46 +02006706 public void setWiredDeviceConnectionState(int device, int state, String address, String name) {
6707 AudioDeviceAttributes attributes = new AudioDeviceAttributes(device, address, name);
Nathalie Le Clair517a1322021-10-15 14:22:41 +02006708 setWiredDeviceConnectionState(attributes, state);
6709 }
6710
6711 /**
6712 * Indicate wired accessory connection state change and attributes.
6713 * @param state new connection state: 1 connected, 0 disconnected
6714 * @param attributes attributes of the connected device
6715 * {@hide}
6716 */
6717 @UnsupportedAppUsage
Jean-Michel Trivic4557822023-01-23 18:19:52 +00006718 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
Nathalie Le Clair517a1322021-10-15 14:22:41 +02006719 public void setWiredDeviceConnectionState(AudioDeviceAttributes attributes, int state) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07006720 final IAudioService service = getService();
Eric Laurentb1fbaac2012-05-29 09:24:28 -07006721 try {
Nathalie Le Clair517a1322021-10-15 14:22:41 +02006722 service.setWiredDeviceConnectionState(attributes, state,
Marco Nelissena80ac052015-03-12 16:17:45 -07006723 mApplicationContext.getOpPackageName());
Eric Laurentb1fbaac2012-05-29 09:24:28 -07006724 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07006725 throw e.rethrowFromSystemServer();
Eric Laurentb1fbaac2012-05-29 09:24:28 -07006726 }
6727 }
6728
Grzegorz Kołodziejczyk59b2baa2021-05-14 12:19:07 +00006729 /**
Jean-Michel Trivi4da775d2021-12-03 15:33:46 -08006730 * Indicate wired accessory connection state change.
6731 * @param device {@link AudioDeviceAttributes} of the device to "fake-connect"
6732 * @param connected true for connected, false for disconnected
6733 * {@hide}
6734 */
6735 @TestApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00006736 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
Jean-Michel Trivi4da775d2021-12-03 15:33:46 -08006737 public void setTestDeviceConnectionState(@NonNull AudioDeviceAttributes device,
6738 boolean connected) {
6739 try {
6740 getService().setTestDeviceConnectionState(device, connected);
6741 } catch (RemoteException e) {
6742 throw e.rethrowFromSystemServer();
6743 }
6744 }
6745
6746 /**
wescande7c17ba0c2021-07-30 16:46:14 +02006747 * Indicate Bluetooth profile connection state change.
6748 * Configuration changes for A2DP are indicated by having the same <code>newDevice</code> and
6749 * <code>previousDevice</code>
6750 * This operation is asynchronous.
6751 *
6752 * @param newDevice Bluetooth device connected or null if there is no new devices
6753 * @param previousDevice Bluetooth device disconnected or null if there is no disconnected
6754 * devices
William Escandeac11d772022-01-25 18:01:15 +01006755 * @param info contain all info related to the device. {@link BluetoothProfileConnectionInfo}
Pavlin Radoslavov82e06462018-01-19 18:20:04 -08006756 * {@hide}
6757 */
wescande7c17ba0c2021-07-30 16:46:14 +02006758 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
Jean-Michel Trivic4557822023-01-23 18:19:52 +00006759 @RequiresPermission(Manifest.permission.BLUETOOTH_STACK)
wescande7c17ba0c2021-07-30 16:46:14 +02006760 public void handleBluetoothActiveDeviceChanged(@Nullable BluetoothDevice newDevice,
William Escandeac11d772022-01-25 18:01:15 +01006761 @Nullable BluetoothDevice previousDevice,
6762 @NonNull BluetoothProfileConnectionInfo info) {
Pavlin Radoslavov82e06462018-01-19 18:20:04 -08006763 final IAudioService service = getService();
Pavlin Radoslavov82e06462018-01-19 18:20:04 -08006764 try {
wescande7c17ba0c2021-07-30 16:46:14 +02006765 service.handleBluetoothActiveDeviceChanged(newDevice, previousDevice, info);
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -08006766 } catch (RemoteException e) {
6767 throw e.rethrowFromSystemServer();
6768 }
6769 }
6770
Jeff Sharkey098d5802012-04-26 17:30:34 -07006771 /** {@hide} */
6772 public IRingtonePlayer getRingtonePlayer() {
6773 try {
6774 return getService().getRingtonePlayer();
6775 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07006776 throw e.rethrowFromSystemServer();
Jeff Sharkey098d5802012-04-26 17:30:34 -07006777 }
6778 }
Glenn Kasten228c9842012-09-14 08:48:47 -07006779
6780 /**
Glenn Kasten62796aa2012-09-20 08:08:07 -07006781 * Used as a key for {@link #getProperty} to request the native or optimal output sample rate
Glenn Kastenc3de5142016-07-15 12:14:24 -07006782 * for this device's low latency output stream, in decimal Hz. Latency-sensitive apps
6783 * should use this value as a default, and offer the user the option to override it.
6784 * The low latency output stream is typically either the device's primary output stream,
6785 * or another output stream with smaller buffers.
Glenn Kasten228c9842012-09-14 08:48:47 -07006786 */
Glenn Kasten1cbf9b32016-02-02 12:04:09 -08006787 // FIXME Deprecate
Glenn Kasten228c9842012-09-14 08:48:47 -07006788 public static final String PROPERTY_OUTPUT_SAMPLE_RATE =
6789 "android.media.property.OUTPUT_SAMPLE_RATE";
6790
6791 /**
Glenn Kasten62796aa2012-09-20 08:08:07 -07006792 * Used as a key for {@link #getProperty} to request the native or optimal output buffer size
Glenn Kastenc3de5142016-07-15 12:14:24 -07006793 * for this device's low latency output stream, in decimal PCM frames. Latency-sensitive apps
6794 * should use this value as a minimum, and offer the user the option to override it.
6795 * The low latency output stream is typically either the device's primary output stream,
6796 * or another output stream with smaller buffers.
Glenn Kasten228c9842012-09-14 08:48:47 -07006797 */
Glenn Kasten1cbf9b32016-02-02 12:04:09 -08006798 // FIXME Deprecate
Glenn Kasten228c9842012-09-14 08:48:47 -07006799 public static final String PROPERTY_OUTPUT_FRAMES_PER_BUFFER =
6800 "android.media.property.OUTPUT_FRAMES_PER_BUFFER";
6801
6802 /**
Arunesh Mishrad08715e52015-04-23 22:39:40 -07006803 * Used as a key for {@link #getProperty} to determine if the default microphone audio source
6804 * supports near-ultrasound frequencies (range of 18 - 21 kHz).
6805 */
6806 public static final String PROPERTY_SUPPORT_MIC_NEAR_ULTRASOUND =
6807 "android.media.property.SUPPORT_MIC_NEAR_ULTRASOUND";
6808
6809 /**
6810 * Used as a key for {@link #getProperty} to determine if the default speaker audio path
6811 * supports near-ultrasound frequencies (range of 18 - 21 kHz).
6812 */
6813 public static final String PROPERTY_SUPPORT_SPEAKER_NEAR_ULTRASOUND =
6814 "android.media.property.SUPPORT_SPEAKER_NEAR_ULTRASOUND";
6815
6816 /**
ragoa7cc59c2015-12-02 11:31:15 -08006817 * Used as a key for {@link #getProperty} to determine if the unprocessed audio source is
6818 * available and supported with the expected frequency range and level response.
6819 */
6820 public static final String PROPERTY_SUPPORT_AUDIO_SOURCE_UNPROCESSED =
6821 "android.media.property.SUPPORT_AUDIO_SOURCE_UNPROCESSED";
6822 /**
Glenn Kasten62796aa2012-09-20 08:08:07 -07006823 * Returns the value of the property with the specified key.
Glenn Kasten228c9842012-09-14 08:48:47 -07006824 * @param key One of the strings corresponding to a property key: either
Glenn Kasten0b986af2015-10-30 18:24:04 -07006825 * {@link #PROPERTY_OUTPUT_SAMPLE_RATE},
6826 * {@link #PROPERTY_OUTPUT_FRAMES_PER_BUFFER},
ragoa7cc59c2015-12-02 11:31:15 -08006827 * {@link #PROPERTY_SUPPORT_MIC_NEAR_ULTRASOUND},
6828 * {@link #PROPERTY_SUPPORT_SPEAKER_NEAR_ULTRASOUND}, or
6829 * {@link #PROPERTY_SUPPORT_AUDIO_SOURCE_UNPROCESSED}.
Glenn Kasten228c9842012-09-14 08:48:47 -07006830 * @return A string representing the associated value for that property key,
6831 * or null if there is no value for that key.
Glenn Kasten228c9842012-09-14 08:48:47 -07006832 */
6833 public String getProperty(String key) {
Glenn Kastenc6c43652012-09-24 17:32:30 -07006834 if (PROPERTY_OUTPUT_SAMPLE_RATE.equals(key)) {
6835 int outputSampleRate = AudioSystem.getPrimaryOutputSamplingRate();
6836 return outputSampleRate > 0 ? Integer.toString(outputSampleRate) : null;
6837 } else if (PROPERTY_OUTPUT_FRAMES_PER_BUFFER.equals(key)) {
6838 int outputFramesPerBuffer = AudioSystem.getPrimaryOutputFrameCount();
6839 return outputFramesPerBuffer > 0 ? Integer.toString(outputFramesPerBuffer) : null;
Arunesh Mishrabc922272015-04-27 09:39:00 -07006840 } else if (PROPERTY_SUPPORT_MIC_NEAR_ULTRASOUND.equals(key)) {
Arunesh Mishra6e4fb342015-06-02 13:23:41 -07006841 // Will throw a RuntimeException Resources.NotFoundException if this config value is
6842 // not found.
6843 return String.valueOf(getContext().getResources().getBoolean(
6844 com.android.internal.R.bool.config_supportMicNearUltrasound));
Arunesh Mishrabc922272015-04-27 09:39:00 -07006845 } else if (PROPERTY_SUPPORT_SPEAKER_NEAR_ULTRASOUND.equals(key)) {
Arunesh Mishra6e4fb342015-06-02 13:23:41 -07006846 return String.valueOf(getContext().getResources().getBoolean(
6847 com.android.internal.R.bool.config_supportSpeakerNearUltrasound));
ragoa7cc59c2015-12-02 11:31:15 -08006848 } else if (PROPERTY_SUPPORT_AUDIO_SOURCE_UNPROCESSED.equals(key)) {
6849 return String.valueOf(getContext().getResources().getBoolean(
6850 com.android.internal.R.bool.config_supportAudioSourceUnprocessed));
Glenn Kastenc6c43652012-09-24 17:32:30 -07006851 } else {
6852 // null or unknown key
6853 return null;
6854 }
Glenn Kasten228c9842012-09-14 08:48:47 -07006855 }
6856
Oliver Woodman61dcdf32013-06-26 12:43:36 +01006857 /**
Andy Hung97aa07f82020-01-17 14:05:06 -08006858 * @hide
6859 * Sets an additional audio output device delay in milliseconds.
6860 *
6861 * The additional output delay is a request to the output device to
6862 * delay audio presentation (generally with respect to video presentation for better
6863 * synchronization).
6864 * It may not be supported by all output devices,
6865 * and typically increases the audio latency by the amount of additional
6866 * audio delay requested.
6867 *
6868 * If additional audio delay is supported by an audio output device,
6869 * it is expected to be supported for all output streams (and configurations)
6870 * opened on that device.
6871 *
6872 * @param device an instance of {@link AudioDeviceInfo} returned from {@link getDevices()}.
Andy Hung120c1c42020-03-26 12:01:33 -07006873 * @param delayMillis delay in milliseconds desired. This should be in range of {@code 0}
Andy Hung97aa07f82020-01-17 14:05:06 -08006874 * to the value returned by {@link #getMaxAdditionalOutputDeviceDelay()}.
6875 * @return true if successful, false if the device does not support output device delay
6876 * or the delay is not in range of {@link #getMaxAdditionalOutputDeviceDelay()}.
6877 */
6878 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00006879 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
Andy Hung97aa07f82020-01-17 14:05:06 -08006880 public boolean setAdditionalOutputDeviceDelay(
Andy Hung120c1c42020-03-26 12:01:33 -07006881 @NonNull AudioDeviceInfo device, @IntRange(from = 0) long delayMillis) {
Andy Hung97aa07f82020-01-17 14:05:06 -08006882 Objects.requireNonNull(device);
Kuowei Lif50ac2e32020-08-13 14:34:17 +08006883 try {
6884 return getService().setAdditionalOutputDeviceDelay(
6885 new AudioDeviceAttributes(device), delayMillis);
6886 } catch (RemoteException e) {
6887 throw e.rethrowFromSystemServer();
6888 }
Andy Hung97aa07f82020-01-17 14:05:06 -08006889 }
6890
6891 /**
6892 * @hide
6893 * Returns the current additional audio output device delay in milliseconds.
6894 *
6895 * @param device an instance of {@link AudioDeviceInfo} returned from {@link getDevices()}.
6896 * @return the additional output device delay. This is a non-negative number.
6897 * {@code 0} is returned if unsupported.
6898 */
6899 @SystemApi
6900 @IntRange(from = 0)
Andy Hung120c1c42020-03-26 12:01:33 -07006901 public long getAdditionalOutputDeviceDelay(@NonNull AudioDeviceInfo device) {
Andy Hung97aa07f82020-01-17 14:05:06 -08006902 Objects.requireNonNull(device);
Kuowei Lif50ac2e32020-08-13 14:34:17 +08006903 try {
6904 return getService().getAdditionalOutputDeviceDelay(new AudioDeviceAttributes(device));
6905 } catch (RemoteException e) {
6906 throw e.rethrowFromSystemServer();
6907 }
Andy Hung97aa07f82020-01-17 14:05:06 -08006908 }
6909
6910 /**
6911 * @hide
6912 * Returns the maximum additional audio output device delay in milliseconds.
6913 *
6914 * @param device an instance of {@link AudioDeviceInfo} returned from {@link getDevices()}.
6915 * @return the maximum output device delay in milliseconds that can be set.
6916 * This is a non-negative number
6917 * representing the additional audio delay supported for the device.
6918 * {@code 0} is returned if unsupported.
6919 */
6920 @SystemApi
6921 @IntRange(from = 0)
Andy Hung120c1c42020-03-26 12:01:33 -07006922 public long getMaxAdditionalOutputDeviceDelay(@NonNull AudioDeviceInfo device) {
Andy Hung97aa07f82020-01-17 14:05:06 -08006923 Objects.requireNonNull(device);
Kuowei Lif50ac2e32020-08-13 14:34:17 +08006924 try {
6925 return getService().getMaxAdditionalOutputDeviceDelay(
6926 new AudioDeviceAttributes(device));
6927 } catch (RemoteException e) {
6928 throw e.rethrowFromSystemServer();
6929 }
Andy Hung97aa07f82020-01-17 14:05:06 -08006930 }
6931
6932 /**
Oliver Woodman61dcdf32013-06-26 12:43:36 +01006933 * Returns the estimated latency for the given stream type in milliseconds.
6934 *
6935 * DO NOT UNHIDE. The existing approach for doing A/V sync has too many problems. We need
6936 * a better solution.
6937 * @hide
6938 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01006939 @UnsupportedAppUsage
Oliver Woodman61dcdf32013-06-26 12:43:36 +01006940 public int getOutputLatency(int streamType) {
6941 return AudioSystem.getOutputLatency(streamType);
6942 }
6943
John Spurlock3346a802014-05-20 16:25:37 -04006944 /**
6945 * Registers a global volume controller interface. Currently limited to SystemUI.
6946 *
6947 * @hide
6948 */
6949 public void setVolumeController(IVolumeController controller) {
6950 try {
6951 getService().setVolumeController(controller);
6952 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07006953 throw e.rethrowFromSystemServer();
John Spurlock3346a802014-05-20 16:25:37 -04006954 }
6955 }
6956
6957 /**
Vlad Popa4e9d10b2023-01-13 12:03:48 +01006958 * Returns the registered volume controller interface.
6959 *
6960 * @hide
6961 */
6962 @Nullable
6963 public IVolumeController getVolumeController() {
6964 try {
6965 return getService().getVolumeController();
6966 } catch (RemoteException e) {
6967 throw e.rethrowFromSystemServer();
6968 }
6969 }
6970
6971 /**
John Spurlock33f4e042014-07-11 13:10:58 -04006972 * Notify audio manager about volume controller visibility changes.
6973 * Currently limited to SystemUI.
6974 *
6975 * @hide
6976 */
6977 public void notifyVolumeControllerVisible(IVolumeController controller, boolean visible) {
6978 try {
6979 getService().notifyVolumeControllerVisible(controller, visible);
6980 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07006981 throw e.rethrowFromSystemServer();
John Spurlock33f4e042014-07-11 13:10:58 -04006982 }
6983 }
6984
6985 /**
John Spurlock3346a802014-05-20 16:25:37 -04006986 * Only useful for volume controllers.
6987 * @hide
6988 */
John Spurlock3346a802014-05-20 16:25:37 -04006989 public boolean isStreamAffectedByRingerMode(int streamType) {
6990 try {
6991 return getService().isStreamAffectedByRingerMode(streamType);
6992 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07006993 throw e.rethrowFromSystemServer();
John Spurlock3346a802014-05-20 16:25:37 -04006994 }
6995 }
6996
6997 /**
6998 * Only useful for volume controllers.
6999 * @hide
7000 */
John Spurlocka9dfbe8b2015-02-17 11:01:51 -05007001 public boolean isStreamAffectedByMute(int streamType) {
7002 try {
7003 return getService().isStreamAffectedByMute(streamType);
7004 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07007005 throw e.rethrowFromSystemServer();
John Spurlocka9dfbe8b2015-02-17 11:01:51 -05007006 }
7007 }
7008
7009 /**
Vlad Popafb8a0692024-06-26 16:45:02 -07007010 * Check whether a user can mute this stream type from a given UI element.
7011 *
7012 * <p>Only useful for volume controllers.
7013 *
7014 * @param streamType type of stream to check if it's mutable from UI
7015 *
7016 * @hide
7017 */
7018 public boolean isStreamMutableByUi(int streamType) {
7019 try {
7020 return getService().isStreamMutableByUi(streamType);
7021 } catch (RemoteException e) {
7022 throw e.rethrowFromSystemServer();
7023 }
7024 }
7025
7026 /**
John Spurlocka9dfbe8b2015-02-17 11:01:51 -05007027 * Only useful for volume controllers.
7028 * @hide
7029 */
John Spurlock3346a802014-05-20 16:25:37 -04007030 public void disableSafeMediaVolume() {
7031 try {
Marco Nelissena80ac052015-03-12 16:17:45 -07007032 getService().disableSafeMediaVolume(mApplicationContext.getOpPackageName());
John Spurlock3346a802014-05-20 16:25:37 -04007033 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07007034 throw e.rethrowFromSystemServer();
John Spurlock3346a802014-05-20 16:25:37 -04007035 }
7036 }
Eric Laurenta198a292014-02-18 16:26:17 -08007037
7038 /**
Jean-Michel Trivia5321ff2022-12-14 22:11:38 +00007039 * @hide
Vlad Popa95930622023-03-16 18:35:29 +01007040 * Lower media volume to RS1 interval
Jean-Michel Trivia5321ff2022-12-14 22:11:38 +00007041 */
7042 public void lowerVolumeToRs1() {
7043 try {
7044 getService().lowerVolumeToRs1(mApplicationContext.getOpPackageName());
7045 } catch (RemoteException e) {
7046 throw e.rethrowFromSystemServer();
7047 }
7048 }
7049
7050 /**
7051 * @hide
Vlad Popa95930622023-03-16 18:35:29 +01007052 * @return the RS2 upper bound used for momentary exposure warnings
Vlad Popa4e9d10b2023-01-13 12:03:48 +01007053 */
7054 @TestApi
Jean-Michel Trivi10fd2d72023-02-13 18:06:36 +00007055 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED)
Vlad Popa4e9d10b2023-01-13 12:03:48 +01007056 public float getRs2Value() {
7057 try {
Vlad Popa95930622023-03-16 18:35:29 +01007058 return getService().getOutputRs2UpperBound();
Vlad Popa4e9d10b2023-01-13 12:03:48 +01007059 } catch (RemoteException e) {
7060 throw e.rethrowFromSystemServer();
7061 }
7062 }
7063
7064 /**
7065 * @hide
Vlad Popa95930622023-03-16 18:35:29 +01007066 * Sets the RS2 upper bound used for momentary exposure warnings
Vlad Popa4e9d10b2023-01-13 12:03:48 +01007067 */
7068 @TestApi
Jean-Michel Trivi10fd2d72023-02-13 18:06:36 +00007069 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED)
Vlad Popa4e9d10b2023-01-13 12:03:48 +01007070 public void setRs2Value(float rs2Value) {
7071 try {
Vlad Popa95930622023-03-16 18:35:29 +01007072 getService().setOutputRs2UpperBound(rs2Value);
Vlad Popa4e9d10b2023-01-13 12:03:48 +01007073 } catch (RemoteException e) {
7074 throw e.rethrowFromSystemServer();
7075 }
7076 }
7077
7078 /**
7079 * @hide
7080 * @return the current computed sound dose value
7081 */
7082 @TestApi
Jean-Michel Trivi10fd2d72023-02-13 18:06:36 +00007083 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED)
Vlad Popa4e9d10b2023-01-13 12:03:48 +01007084 public float getCsd() {
7085 try {
7086 return getService().getCsd();
7087 } catch (RemoteException e) {
7088 throw e.rethrowFromSystemServer();
7089 }
7090 }
7091
7092 /**
7093 * @hide
Vlad Popa6a05f252023-03-09 15:25:52 +01007094 * Sets the computed sound dose value to {@code csd}. A negative value will
7095 * reset all the CSD related timeouts: after a momentary exposure warning and
7096 * before the momentary exposure reaches RS2 (see IEC62368-1 10.6.5)
Vlad Popa4e9d10b2023-01-13 12:03:48 +01007097 */
7098 @TestApi
Jean-Michel Trivi10fd2d72023-02-13 18:06:36 +00007099 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED)
Vlad Popa4e9d10b2023-01-13 12:03:48 +01007100 public void setCsd(float csd) {
7101 try {
7102 getService().setCsd(csd);
7103 } catch (RemoteException e) {
7104 throw e.rethrowFromSystemServer();
7105 }
7106 }
7107
7108 /**
7109 * @hide
7110 * Forces the computation of MEL values (used for CSD) on framework level. This will have the
7111 * result of ignoring the MEL values computed on HAL level. Should only be used in testing
7112 * since this can affect the certification of a device with EN50332-3 regulation.
7113 */
7114 @TestApi
Jean-Michel Trivi10fd2d72023-02-13 18:06:36 +00007115 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED)
Vlad Popa4e9d10b2023-01-13 12:03:48 +01007116 public void forceUseFrameworkMel(boolean useFrameworkMel) {
7117 try {
7118 getService().forceUseFrameworkMel(useFrameworkMel);
7119 } catch (RemoteException e) {
7120 throw e.rethrowFromSystemServer();
7121 }
7122 }
7123
7124 /**
7125 * @hide
7126 * Forces the computation of CSD on all output devices.
7127 */
7128 @TestApi
Jean-Michel Trivi10fd2d72023-02-13 18:06:36 +00007129 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED)
Vlad Popa4e9d10b2023-01-13 12:03:48 +01007130 public void forceComputeCsdOnAllDevices(boolean computeCsdOnAllDevices) {
7131 try {
7132 getService().forceComputeCsdOnAllDevices(computeCsdOnAllDevices);
7133 } catch (RemoteException e) {
7134 throw e.rethrowFromSystemServer();
7135 }
7136 }
7137
7138 /**
7139 * @hide
Vlad Popa4db07a22023-08-07 18:57:00 -07007140 * Returns whether CSD is enabled and supported by the current active audio module HAL.
7141 * This method will return {@code false) for setups in which CSD as a feature is available
7142 * (see {@link AudioManager#isCsdAsAFeatureAvailable()}) and not enabled (see
7143 * {@link AudioManager#isCsdAsAFeatureEnabled()}).
Vlad Popa4e9d10b2023-01-13 12:03:48 +01007144 */
7145 @TestApi
Jean-Michel Trivi10fd2d72023-02-13 18:06:36 +00007146 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED)
Vlad Popa4e9d10b2023-01-13 12:03:48 +01007147 public boolean isCsdEnabled() {
7148 try {
7149 return getService().isCsdEnabled();
7150 } catch (RemoteException e) {
7151 throw e.rethrowFromSystemServer();
7152 }
7153 }
7154
7155 /**
7156 * @hide
Vlad Popa4db07a22023-08-07 18:57:00 -07007157 * Returns whether CSD as a feature can be manipulated by a client. This method
7158 * returns {@code true} in countries where there isn't a safe hearing regulation
7159 * enforced.
7160 */
7161 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED)
7162 public boolean isCsdAsAFeatureAvailable() {
7163 try {
7164 return getService().isCsdAsAFeatureAvailable();
7165 } catch (RemoteException e) {
7166 throw e.rethrowFromSystemServer();
7167 }
7168 }
7169
7170 /**
7171 * @hide
7172 * Returns {@code true} if the client has enabled CSD. This function should only
7173 * be called if {@link AudioManager#isCsdAsAFeatureAvailable()} returns {@code true}.
7174 */
7175 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED)
7176 public boolean isCsdAsAFeatureEnabled() {
7177 try {
7178 return getService().isCsdAsAFeatureEnabled();
7179 } catch (RemoteException e) {
7180 throw e.rethrowFromSystemServer();
7181 }
7182 }
7183
7184 /**
7185 * @hide
7186 * Enables/disables the CSD feature. This function should only be called if
7187 * {@link AudioManager#isCsdAsAFeatureAvailable()} returns {@code true}.
7188 */
7189 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED)
7190 public void setCsdAsAFeatureEnabled(boolean csdToggleValue) {
7191 try {
7192 getService().setCsdAsAFeatureEnabled(csdToggleValue);
7193 } catch (RemoteException e) {
7194 throw e.rethrowFromSystemServer();
7195 }
7196 }
7197
7198 /**
7199 * @hide
Vlad Popa2ea196a2023-07-19 16:29:46 -07007200 * Describes an audio device that has not been categorized with a specific
7201 * audio type.
7202 */
7203 public static final int AUDIO_DEVICE_CATEGORY_UNKNOWN = 0;
7204
7205 /**
7206 * @hide
7207 * Describes an audio device which is categorized as something different.
7208 */
7209 public static final int AUDIO_DEVICE_CATEGORY_OTHER = 1;
7210
7211 /**
7212 * @hide
7213 * Describes an audio device which was categorized as speakers.
7214 */
7215 public static final int AUDIO_DEVICE_CATEGORY_SPEAKER = 2;
7216
7217 /**
7218 * @hide
7219 * Describes an audio device which was categorized as headphones.
7220 */
7221 public static final int AUDIO_DEVICE_CATEGORY_HEADPHONES = 3;
7222
7223 /**
7224 * @hide
7225 * Describes an audio device which was categorized as car-kit.
7226 */
7227 public static final int AUDIO_DEVICE_CATEGORY_CARKIT = 4;
7228
7229 /**
7230 * @hide
7231 * Describes an audio device which was categorized as watch.
7232 */
7233 public static final int AUDIO_DEVICE_CATEGORY_WATCH = 5;
7234
7235 /**
7236 * @hide
7237 * Describes an audio device which was categorized as hearing aid.
7238 */
7239 public static final int AUDIO_DEVICE_CATEGORY_HEARING_AID = 6;
7240
7241 /**
7242 * @hide
7243 * Describes an audio device which was categorized as receiver.
7244 */
7245 public static final int AUDIO_DEVICE_CATEGORY_RECEIVER = 7;
7246
7247 /** @hide */
7248 @IntDef(flag = false, prefix = "AUDIO_DEVICE_CATEGORY", value = {
7249 AUDIO_DEVICE_CATEGORY_UNKNOWN,
7250 AUDIO_DEVICE_CATEGORY_OTHER,
7251 AUDIO_DEVICE_CATEGORY_SPEAKER,
7252 AUDIO_DEVICE_CATEGORY_HEADPHONES,
7253 AUDIO_DEVICE_CATEGORY_CARKIT,
7254 AUDIO_DEVICE_CATEGORY_WATCH,
7255 AUDIO_DEVICE_CATEGORY_HEARING_AID,
7256 AUDIO_DEVICE_CATEGORY_RECEIVER }
7257 )
7258 @Retention(RetentionPolicy.SOURCE)
7259 public @interface AudioDeviceCategory {}
7260
7261 /** @hide */
7262 public static String audioDeviceCategoryToString(int audioDeviceCategory) {
7263 switch (audioDeviceCategory) {
7264 case AUDIO_DEVICE_CATEGORY_UNKNOWN: return "AUDIO_DEVICE_CATEGORY_UNKNOWN";
7265 case AUDIO_DEVICE_CATEGORY_OTHER: return "AUDIO_DEVICE_CATEGORY_OTHER";
7266 case AUDIO_DEVICE_CATEGORY_SPEAKER: return "AUDIO_DEVICE_CATEGORY_SPEAKER";
7267 case AUDIO_DEVICE_CATEGORY_HEADPHONES: return "AUDIO_DEVICE_CATEGORY_HEADPHONES";
7268 case AUDIO_DEVICE_CATEGORY_CARKIT: return "AUDIO_DEVICE_CATEGORY_CARKIT";
7269 case AUDIO_DEVICE_CATEGORY_WATCH: return "AUDIO_DEVICE_CATEGORY_WATCH";
7270 case AUDIO_DEVICE_CATEGORY_HEARING_AID: return "AUDIO_DEVICE_CATEGORY_HEARING_AID";
7271 case AUDIO_DEVICE_CATEGORY_RECEIVER: return "AUDIO_DEVICE_CATEGORY_RECEIVER";
7272 default:
7273 return new StringBuilder("unknown AudioDeviceCategory ").append(
7274 audioDeviceCategory).toString();
7275 }
7276 }
7277
7278 /**
7279 * @hide
7280 * Sets the audio device type of a Bluetooth device given its MAC address
7281 */
7282 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED)
Vlad Popae1dae842023-11-28 19:04:03 -08007283 public void setBluetoothAudioDeviceCategory_legacy(@NonNull String address, boolean isBle,
Vlad Popa2ea196a2023-07-19 16:29:46 -07007284 @AudioDeviceCategory int btAudioDeviceType) {
Vlad Popae1dae842023-11-28 19:04:03 -08007285 if (automaticBtDeviceType()) {
7286 // do nothing
7287 return;
7288 }
Vlad Popa2ea196a2023-07-19 16:29:46 -07007289 try {
Vlad Popae1dae842023-11-28 19:04:03 -08007290 getService().setBluetoothAudioDeviceCategory_legacy(address, isBle, btAudioDeviceType);
Vlad Popa2ea196a2023-07-19 16:29:46 -07007291 } catch (RemoteException e) {
7292 throw e.rethrowFromSystemServer();
7293 }
7294 }
7295
7296 /**
7297 * @hide
7298 * Gets the audio device type of a Bluetooth device given its MAC address
7299 */
7300 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED)
7301 @AudioDeviceCategory
Vlad Popae1dae842023-11-28 19:04:03 -08007302 public int getBluetoothAudioDeviceCategory_legacy(@NonNull String address, boolean isBle) {
7303 if (automaticBtDeviceType()) {
7304 return AUDIO_DEVICE_CATEGORY_UNKNOWN;
7305 }
Vlad Popa2ea196a2023-07-19 16:29:46 -07007306 try {
Vlad Popae1dae842023-11-28 19:04:03 -08007307 return getService().getBluetoothAudioDeviceCategory_legacy(address, isBle);
7308 } catch (RemoteException e) {
7309 throw e.rethrowFromSystemServer();
7310 }
7311 }
7312
7313 /**
7314 * @hide
7315 * Sets the audio device type of a Bluetooth device given its MAC address
7316 *
7317 * @return {@code true} if the device type was set successfully. If the
7318 * audio device type was automatically identified this method will
7319 * return {@code false}.
7320 */
7321 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED)
7322 public boolean setBluetoothAudioDeviceCategory(@NonNull String address,
7323 @AudioDeviceCategory int btAudioDeviceCategory) {
7324 if (!automaticBtDeviceType()) {
7325 return false;
7326 }
7327 try {
7328 return getService().setBluetoothAudioDeviceCategory(address, btAudioDeviceCategory);
7329 } catch (RemoteException e) {
7330 throw e.rethrowFromSystemServer();
7331 }
7332 }
7333
7334 /**
7335 * @hide
7336 * Gets the audio device type of a Bluetooth device given its MAC address
7337 */
7338 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED)
7339 @AudioDeviceCategory
7340 public int getBluetoothAudioDeviceCategory(@NonNull String address) {
7341 if (!automaticBtDeviceType()) {
7342 return AUDIO_DEVICE_CATEGORY_UNKNOWN;
7343 }
7344 try {
7345 return getService().getBluetoothAudioDeviceCategory(address);
7346 } catch (RemoteException e) {
7347 throw e.rethrowFromSystemServer();
7348 }
7349 }
7350
7351 /**
7352 * @hide
7353 * Returns {@code true} if the audio device type of a Bluetooth device can
7354 * be automatically identified
7355 */
7356 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED)
7357 public boolean isBluetoothAudioDeviceCategoryFixed(@NonNull String address) {
7358 if (!automaticBtDeviceType()) {
7359 return false;
7360 }
7361 try {
7362 return getService().isBluetoothAudioDeviceCategoryFixed(address);
Vlad Popa2ea196a2023-07-19 16:29:46 -07007363 } catch (RemoteException e) {
7364 throw e.rethrowFromSystemServer();
7365 }
7366 }
7367
7368 /**
7369 * @hide
Jean-Michel Trivia5321ff2022-12-14 22:11:38 +00007370 * Sound dose warning at every 100% of dose during integration window
7371 */
7372 public static final int CSD_WARNING_DOSE_REACHED_1X = 1;
7373 /**
7374 * @hide
7375 * Sound dose warning when 500% of dose is reached during integration window
7376 */
7377 public static final int CSD_WARNING_DOSE_REPEATED_5X = 2;
7378 /**
7379 * @hide
7380 * Sound dose warning after a momentary exposure event
7381 */
7382 public static final int CSD_WARNING_MOMENTARY_EXPOSURE = 3;
7383 /**
7384 * @hide
7385 * Sound dose warning at every 100% of dose during integration window
7386 */
7387 public static final int CSD_WARNING_ACCUMULATION_START = 4;
7388
7389 /** @hide */
7390 @IntDef(flag = false, value = {
7391 CSD_WARNING_DOSE_REACHED_1X,
7392 CSD_WARNING_DOSE_REPEATED_5X,
7393 CSD_WARNING_MOMENTARY_EXPOSURE,
7394 CSD_WARNING_ACCUMULATION_START }
7395 )
7396 @Retention(RetentionPolicy.SOURCE)
7397 public @interface CsdWarning {}
7398
7399 /**
John Spurlock661f2cf42014-11-17 10:29:10 -05007400 * Only useful for volume controllers.
7401 * @hide
7402 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01007403 @UnsupportedAppUsage
John Spurlock661f2cf42014-11-17 10:29:10 -05007404 public void setRingerModeInternal(int ringerMode) {
7405 try {
Marco Nelissen29f16932015-04-17 09:50:56 -07007406 getService().setRingerModeInternal(ringerMode, getContext().getOpPackageName());
John Spurlock661f2cf42014-11-17 10:29:10 -05007407 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07007408 throw e.rethrowFromSystemServer();
John Spurlock661f2cf42014-11-17 10:29:10 -05007409 }
7410 }
7411
7412 /**
7413 * Only useful for volume controllers.
7414 * @hide
7415 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01007416 @UnsupportedAppUsage
John Spurlock661f2cf42014-11-17 10:29:10 -05007417 public int getRingerModeInternal() {
7418 try {
7419 return getService().getRingerModeInternal();
7420 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07007421 throw e.rethrowFromSystemServer();
John Spurlock661f2cf42014-11-17 10:29:10 -05007422 }
7423 }
7424
7425 /**
John Spurlocka48d7792015-03-03 17:35:57 -05007426 * Only useful for volume controllers.
7427 * @hide
7428 */
7429 public void setVolumePolicy(VolumePolicy policy) {
7430 try {
7431 getService().setVolumePolicy(policy);
7432 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07007433 throw e.rethrowFromSystemServer();
John Spurlocka48d7792015-03-03 17:35:57 -05007434 }
7435 }
7436
7437 /**
Jean-Michel Trivi2f942c42024-07-03 15:01:12 -07007438 * @hide
7439 * Queries the volume policy
7440 * @return the volume policy currently in use
7441 */
7442 @TestApi
7443 @SuppressLint("UnflaggedApi") // @TestApi without associated feature.
7444 public @NonNull VolumePolicy getVolumePolicy() {
7445 try {
7446 return getService().getVolumePolicy();
7447 } catch (RemoteException e) {
7448 throw e.rethrowFromSystemServer();
7449 }
7450 }
7451
7452 /**
Jungshik Jang41d97462014-06-30 22:26:29 +09007453 * Set Hdmi Cec system audio mode.
7454 *
7455 * @param on whether to be on system audio mode
Jungshik Jang6f34f5a2014-07-08 21:17:29 +09007456 * @return output device type. 0 (DEVICE_NONE) if failed to set device.
Jungshik Jang41d97462014-06-30 22:26:29 +09007457 * @hide
7458 */
Jungshik Jang12307ca2014-07-15 19:27:56 +09007459 public int setHdmiSystemAudioSupported(boolean on) {
Jungshik Jang41d97462014-06-30 22:26:29 +09007460 try {
Jungshik Jang12307ca2014-07-15 19:27:56 +09007461 return getService().setHdmiSystemAudioSupported(on);
Jungshik Jang41d97462014-06-30 22:26:29 +09007462 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07007463 throw e.rethrowFromSystemServer();
Jungshik Jang41d97462014-06-30 22:26:29 +09007464 }
7465 }
7466
7467 /**
Terry Heoe7d6d972014-09-04 21:05:28 +09007468 * Returns true if Hdmi Cec system audio mode is supported.
7469 *
7470 * @hide
7471 */
7472 @SystemApi
Aurimas Liutikas1394a012020-11-12 18:26:09 -08007473 @SuppressLint("RequiresPermission") // FIXME is this still used?
Terry Heoe7d6d972014-09-04 21:05:28 +09007474 public boolean isHdmiSystemAudioSupported() {
7475 try {
7476 return getService().isHdmiSystemAudioSupported();
7477 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07007478 throw e.rethrowFromSystemServer();
Terry Heoe7d6d972014-09-04 21:05:28 +09007479 }
7480 }
7481
7482 /**
Eric Laurenta198a292014-02-18 16:26:17 -08007483 * Return codes for listAudioPorts(), createAudioPatch() ...
7484 */
7485
Jean-Michel Trivid6f65de2018-12-18 18:49:14 -08007486 /** @hide */
7487 @SystemApi
Eric Laurenta198a292014-02-18 16:26:17 -08007488 public static final int SUCCESS = AudioSystem.SUCCESS;
Jean-Michel Trivi8a21f5d2014-06-05 15:03:52 -07007489 /**
7490 * A default error code.
Eric Laurenta198a292014-02-18 16:26:17 -08007491 */
7492 public static final int ERROR = AudioSystem.ERROR;
7493 /** @hide
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07007494 * CANDIDATE FOR PUBLIC API
Eric Laurenta198a292014-02-18 16:26:17 -08007495 */
7496 public static final int ERROR_BAD_VALUE = AudioSystem.BAD_VALUE;
7497 /** @hide
7498 */
7499 public static final int ERROR_INVALID_OPERATION = AudioSystem.INVALID_OPERATION;
7500 /** @hide
7501 */
7502 public static final int ERROR_PERMISSION_DENIED = AudioSystem.PERMISSION_DENIED;
7503 /** @hide
7504 */
7505 public static final int ERROR_NO_INIT = AudioSystem.NO_INIT;
Eric Laurentff0d9f02014-06-09 17:23:02 -07007506 /**
7507 * An error code indicating that the object reporting it is no longer valid and needs to
7508 * be recreated.
Eric Laurenta198a292014-02-18 16:26:17 -08007509 */
7510 public static final int ERROR_DEAD_OBJECT = AudioSystem.DEAD_OBJECT;
7511
7512 /**
7513 * Returns a list of descriptors for all audio ports managed by the audio framework.
7514 * Audio ports are nodes in the audio framework or audio hardware that can be configured
7515 * or connected and disconnected with createAudioPatch() or releaseAudioPatch().
7516 * See AudioPort for a list of attributes of each audio port.
7517 * @param ports An AudioPort ArrayList where the list will be returned.
7518 * @hide
7519 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01007520 @UnsupportedAppUsage
Eric Laurent4bcdba82015-05-01 11:37:49 -07007521 public static int listAudioPorts(ArrayList<AudioPort> ports) {
Eric Laurent8a1e7a82015-05-08 11:43:05 -07007522 return updateAudioPortCache(ports, null, null);
7523 }
7524
7525 /**
7526 * Returns a list of descriptors for all audio ports managed by the audio framework as
7527 * it was before the last update calback.
7528 * @param ports An AudioPort ArrayList where the list will be returned.
7529 * @hide
7530 */
7531 public static int listPreviousAudioPorts(ArrayList<AudioPort> ports) {
7532 return updateAudioPortCache(null, null, ports);
Eric Laurenta198a292014-02-18 16:26:17 -08007533 }
7534
7535 /**
7536 * Specialized version of listAudioPorts() listing only audio devices (AudioDevicePort)
7537 * @see listAudioPorts(ArrayList<AudioPort>)
7538 * @hide
7539 */
Eric Laurent4bcdba82015-05-01 11:37:49 -07007540 public static int listAudioDevicePorts(ArrayList<AudioDevicePort> devices) {
Eric Laurent8a1e7a82015-05-08 11:43:05 -07007541 if (devices == null) {
7542 return ERROR_BAD_VALUE;
7543 }
Eric Laurentb69681c2014-05-19 19:02:51 -07007544 ArrayList<AudioPort> ports = new ArrayList<AudioPort>();
Eric Laurent8a1e7a82015-05-08 11:43:05 -07007545 int status = updateAudioPortCache(ports, null, null);
Eric Laurentb69681c2014-05-19 19:02:51 -07007546 if (status == SUCCESS) {
Eric Laurent8a1e7a82015-05-08 11:43:05 -07007547 filterDevicePorts(ports, devices);
Eric Laurentb69681c2014-05-19 19:02:51 -07007548 }
7549 return status;
Eric Laurenta198a292014-02-18 16:26:17 -08007550 }
7551
7552 /**
Eric Laurent8a1e7a82015-05-08 11:43:05 -07007553 * Specialized version of listPreviousAudioPorts() listing only audio devices (AudioDevicePort)
7554 * @see listPreviousAudioPorts(ArrayList<AudioPort>)
7555 * @hide
7556 */
7557 public static int listPreviousAudioDevicePorts(ArrayList<AudioDevicePort> devices) {
7558 if (devices == null) {
7559 return ERROR_BAD_VALUE;
7560 }
7561 ArrayList<AudioPort> ports = new ArrayList<AudioPort>();
7562 int status = updateAudioPortCache(null, null, ports);
7563 if (status == SUCCESS) {
7564 filterDevicePorts(ports, devices);
7565 }
7566 return status;
7567 }
7568
7569 private static void filterDevicePorts(ArrayList<AudioPort> ports,
7570 ArrayList<AudioDevicePort> devices) {
7571 devices.clear();
7572 for (int i = 0; i < ports.size(); i++) {
7573 if (ports.get(i) instanceof AudioDevicePort) {
7574 devices.add((AudioDevicePort)ports.get(i));
7575 }
7576 }
7577 }
7578
7579 /**
Eric Laurenta198a292014-02-18 16:26:17 -08007580 * Create a connection between two or more devices. The framework will reject the request if
7581 * device types are not compatible or the implementation does not support the requested
7582 * configuration.
7583 * NOTE: current implementation is limited to one source and one sink per patch.
7584 * @param patch AudioPatch array where the newly created patch will be returned.
7585 * As input, if patch[0] is not null, the specified patch will be replaced by the
7586 * new patch created. This avoids calling releaseAudioPatch() when modifying a
7587 * patch and allows the implementation to optimize transitions.
7588 * @param sources List of source audio ports. All must be AudioPort.ROLE_SOURCE.
7589 * @param sinks List of sink audio ports. All must be AudioPort.ROLE_SINK.
7590 *
7591 * @return - {@link #SUCCESS} if connection is successful.
7592 * - {@link #ERROR_BAD_VALUE} if incompatible device types are passed.
7593 * - {@link #ERROR_INVALID_OPERATION} if the requested connection is not supported.
7594 * - {@link #ERROR_PERMISSION_DENIED} if the client does not have permission to create
7595 * a patch.
7596 * - {@link #ERROR_DEAD_OBJECT} if the server process is dead
7597 * - {@link #ERROR} if patch cannot be connected for any other reason.
7598 *
7599 * patch[0] contains the newly created patch
7600 * @hide
7601 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01007602 @UnsupportedAppUsage
Eric Laurent4bcdba82015-05-01 11:37:49 -07007603 public static int createAudioPatch(AudioPatch[] patch,
Eric Laurenta198a292014-02-18 16:26:17 -08007604 AudioPortConfig[] sources,
7605 AudioPortConfig[] sinks) {
Eric Laurentb69681c2014-05-19 19:02:51 -07007606 return AudioSystem.createAudioPatch(patch, sources, sinks);
Eric Laurenta198a292014-02-18 16:26:17 -08007607 }
7608
7609 /**
7610 * Releases an existing audio patch connection.
7611 * @param patch The audio patch to disconnect.
7612 * @return - {@link #SUCCESS} if disconnection is successful.
7613 * - {@link #ERROR_BAD_VALUE} if the specified patch does not exist.
7614 * - {@link #ERROR_PERMISSION_DENIED} if the client does not have permission to release
7615 * a patch.
7616 * - {@link #ERROR_DEAD_OBJECT} if the server process is dead
7617 * - {@link #ERROR} if patch cannot be released for any other reason.
7618 * @hide
7619 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01007620 @UnsupportedAppUsage
Eric Laurent4bcdba82015-05-01 11:37:49 -07007621 public static int releaseAudioPatch(AudioPatch patch) {
Eric Laurentb69681c2014-05-19 19:02:51 -07007622 return AudioSystem.releaseAudioPatch(patch);
Eric Laurenta198a292014-02-18 16:26:17 -08007623 }
7624
7625 /**
7626 * List all existing connections between audio ports.
7627 * @param patches An AudioPatch array where the list will be returned.
7628 * @hide
7629 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01007630 @UnsupportedAppUsage
Eric Laurent4bcdba82015-05-01 11:37:49 -07007631 public static int listAudioPatches(ArrayList<AudioPatch> patches) {
Eric Laurent8a1e7a82015-05-08 11:43:05 -07007632 return updateAudioPortCache(null, patches, null);
Eric Laurenta198a292014-02-18 16:26:17 -08007633 }
7634
7635 /**
7636 * Set the gain on the specified AudioPort. The AudioGainConfig config is build by
7637 * AudioGain.buildConfig()
7638 * @hide
7639 */
Eric Laurent4bcdba82015-05-01 11:37:49 -07007640 public static int setAudioPortGain(AudioPort port, AudioGainConfig gain) {
Eric Laurent3a241992014-05-19 19:33:26 -07007641 if (port == null || gain == null) {
7642 return ERROR_BAD_VALUE;
7643 }
7644 AudioPortConfig activeConfig = port.activeConfig();
7645 AudioPortConfig config = new AudioPortConfig(port, activeConfig.samplingRate(),
7646 activeConfig.channelMask(), activeConfig.format(), gain);
7647 config.mConfigMask = AudioPortConfig.GAIN;
7648 return AudioSystem.setAudioPortConfig(config);
Eric Laurenta198a292014-02-18 16:26:17 -08007649 }
7650
7651 /**
7652 * Listener registered by client to be notified upon new audio port connections,
7653 * disconnections or attributes update.
7654 * @hide
7655 */
7656 public interface OnAudioPortUpdateListener {
7657 /**
7658 * Callback method called upon audio port list update.
7659 * @param portList the updated list of audio ports
7660 */
Eric Laurentfdaed9d2014-07-29 09:29:30 -07007661 public void onAudioPortListUpdate(AudioPort[] portList);
Eric Laurenta198a292014-02-18 16:26:17 -08007662
7663 /**
7664 * Callback method called upon audio patch list update.
7665 * @param patchList the updated list of audio patches
7666 */
Eric Laurentfdaed9d2014-07-29 09:29:30 -07007667 public void onAudioPatchListUpdate(AudioPatch[] patchList);
Eric Laurenta198a292014-02-18 16:26:17 -08007668
7669 /**
7670 * Callback method called when the mediaserver dies
7671 */
Eric Laurentfdaed9d2014-07-29 09:29:30 -07007672 public void onServiceDied();
Eric Laurenta198a292014-02-18 16:26:17 -08007673 }
7674
7675 /**
Eric Laurent700e7342014-05-02 18:33:15 -07007676 * Register an audio port list update listener.
Eric Laurenta198a292014-02-18 16:26:17 -08007677 * @hide
7678 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01007679 @UnsupportedAppUsage
Eric Laurenta198a292014-02-18 16:26:17 -08007680 public void registerAudioPortUpdateListener(OnAudioPortUpdateListener l) {
Eric Laurentc573bc52015-06-26 10:01:12 -07007681 sAudioPortEventHandler.init();
Eric Laurentf076db42015-01-14 13:23:27 -08007682 sAudioPortEventHandler.registerListener(l);
Eric Laurenta198a292014-02-18 16:26:17 -08007683 }
7684
7685 /**
Eric Laurent700e7342014-05-02 18:33:15 -07007686 * Unregister an audio port list update listener.
Eric Laurenta198a292014-02-18 16:26:17 -08007687 * @hide
7688 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01007689 @UnsupportedAppUsage
Eric Laurenta198a292014-02-18 16:26:17 -08007690 public void unregisterAudioPortUpdateListener(OnAudioPortUpdateListener l) {
Eric Laurentf076db42015-01-14 13:23:27 -08007691 sAudioPortEventHandler.unregisterListener(l);
Eric Laurenta198a292014-02-18 16:26:17 -08007692 }
Eric Laurentb69681c2014-05-19 19:02:51 -07007693
7694 //
7695 // AudioPort implementation
7696 //
7697
Cole Faust7da659b2022-10-15 21:33:29 -07007698 private static final int AUDIOPORT_GENERATION_INIT = 0;
7699 private static Object sAudioPortGenerationLock = new Object();
7700 @GuardedBy("sAudioPortGenerationLock")
7701 private static int sAudioPortGeneration = AUDIOPORT_GENERATION_INIT;
7702 private static ArrayList<AudioPort> sAudioPortsCached = new ArrayList<AudioPort>();
7703 private static ArrayList<AudioPort> sPreviousAudioPortsCached = new ArrayList<AudioPort>();
7704 private static ArrayList<AudioPatch> sAudioPatchesCached = new ArrayList<AudioPatch>();
Eric Laurentb69681c2014-05-19 19:02:51 -07007705
Eric Laurentf076db42015-01-14 13:23:27 -08007706 static int resetAudioPortGeneration() {
Eric Laurentb69681c2014-05-19 19:02:51 -07007707 int generation;
Cole Faust7da659b2022-10-15 21:33:29 -07007708 synchronized (sAudioPortGenerationLock) {
Eric Laurentf076db42015-01-14 13:23:27 -08007709 generation = sAudioPortGeneration;
7710 sAudioPortGeneration = AUDIOPORT_GENERATION_INIT;
Eric Laurentb69681c2014-05-19 19:02:51 -07007711 }
7712 return generation;
7713 }
7714
Eric Laurent8a1e7a82015-05-08 11:43:05 -07007715 static int updateAudioPortCache(ArrayList<AudioPort> ports, ArrayList<AudioPatch> patches,
7716 ArrayList<AudioPort> previousPorts) {
Eric Laurentc573bc52015-06-26 10:01:12 -07007717 sAudioPortEventHandler.init();
Cole Faust7da659b2022-10-15 21:33:29 -07007718 synchronized (sAudioPortGenerationLock) {
Eric Laurentb69681c2014-05-19 19:02:51 -07007719
Eric Laurentf076db42015-01-14 13:23:27 -08007720 if (sAudioPortGeneration == AUDIOPORT_GENERATION_INIT) {
Eric Laurentb69681c2014-05-19 19:02:51 -07007721 int[] patchGeneration = new int[1];
7722 int[] portGeneration = new int[1];
7723 int status;
7724 ArrayList<AudioPort> newPorts = new ArrayList<AudioPort>();
7725 ArrayList<AudioPatch> newPatches = new ArrayList<AudioPatch>();
7726
7727 do {
7728 newPorts.clear();
7729 status = AudioSystem.listAudioPorts(newPorts, portGeneration);
Eric Laurentb69681c2014-05-19 19:02:51 -07007730 if (status != SUCCESS) {
Wonsik Kimb561cce2015-01-30 17:48:51 +09007731 Log.w(TAG, "updateAudioPortCache: listAudioPorts failed");
Eric Laurentb69681c2014-05-19 19:02:51 -07007732 return status;
7733 }
7734 newPatches.clear();
7735 status = AudioSystem.listAudioPatches(newPatches, patchGeneration);
Eric Laurentb69681c2014-05-19 19:02:51 -07007736 if (status != SUCCESS) {
Wonsik Kimb561cce2015-01-30 17:48:51 +09007737 Log.w(TAG, "updateAudioPortCache: listAudioPatches failed");
Eric Laurentb69681c2014-05-19 19:02:51 -07007738 return status;
7739 }
jiabinc4ecaa52017-09-26 14:28:41 -07007740 // Loop until patch generation is the same as port generation unless audio ports
7741 // and audio patches are not null.
7742 } while (patchGeneration[0] != portGeneration[0]
7743 && (ports == null || patches == null));
7744 // If the patch generation doesn't equal port generation, return ERROR here in case
7745 // of mismatch between audio ports and audio patches.
7746 if (patchGeneration[0] != portGeneration[0]) {
7747 return ERROR;
7748 }
Eric Laurentb69681c2014-05-19 19:02:51 -07007749
7750 for (int i = 0; i < newPatches.size(); i++) {
7751 for (int j = 0; j < newPatches.get(i).sources().length; j++) {
Eric Laurentb4e09092014-06-02 19:18:43 -07007752 AudioPortConfig portCfg = updatePortConfig(newPatches.get(i).sources()[j],
7753 newPorts);
Eric Laurentb69681c2014-05-19 19:02:51 -07007754 newPatches.get(i).sources()[j] = portCfg;
7755 }
7756 for (int j = 0; j < newPatches.get(i).sinks().length; j++) {
Eric Laurentb4e09092014-06-02 19:18:43 -07007757 AudioPortConfig portCfg = updatePortConfig(newPatches.get(i).sinks()[j],
7758 newPorts);
Eric Laurentb69681c2014-05-19 19:02:51 -07007759 newPatches.get(i).sinks()[j] = portCfg;
7760 }
7761 }
Wonsik Kimb561cce2015-01-30 17:48:51 +09007762 for (Iterator<AudioPatch> i = newPatches.iterator(); i.hasNext(); ) {
7763 AudioPatch newPatch = i.next();
7764 boolean hasInvalidPort = false;
7765 for (AudioPortConfig portCfg : newPatch.sources()) {
7766 if (portCfg == null) {
7767 hasInvalidPort = true;
7768 break;
7769 }
7770 }
7771 for (AudioPortConfig portCfg : newPatch.sinks()) {
7772 if (portCfg == null) {
7773 hasInvalidPort = true;
7774 break;
7775 }
7776 }
7777 if (hasInvalidPort) {
7778 // Temporarily remove patches with invalid ports. One who created the patch
7779 // is responsible for dealing with the port change.
7780 i.remove();
7781 }
7782 }
Eric Laurentb69681c2014-05-19 19:02:51 -07007783
Eric Laurent8a1e7a82015-05-08 11:43:05 -07007784 sPreviousAudioPortsCached = sAudioPortsCached;
Eric Laurentf076db42015-01-14 13:23:27 -08007785 sAudioPortsCached = newPorts;
7786 sAudioPatchesCached = newPatches;
7787 sAudioPortGeneration = portGeneration[0];
Eric Laurentb69681c2014-05-19 19:02:51 -07007788 }
7789 if (ports != null) {
7790 ports.clear();
Eric Laurentf076db42015-01-14 13:23:27 -08007791 ports.addAll(sAudioPortsCached);
Eric Laurentb69681c2014-05-19 19:02:51 -07007792 }
7793 if (patches != null) {
7794 patches.clear();
Eric Laurentf076db42015-01-14 13:23:27 -08007795 patches.addAll(sAudioPatchesCached);
Eric Laurentb69681c2014-05-19 19:02:51 -07007796 }
Eric Laurent8a1e7a82015-05-08 11:43:05 -07007797 if (previousPorts != null) {
7798 previousPorts.clear();
7799 previousPorts.addAll(sPreviousAudioPortsCached);
7800 }
Eric Laurentb69681c2014-05-19 19:02:51 -07007801 }
7802 return SUCCESS;
7803 }
7804
Eric Laurentf076db42015-01-14 13:23:27 -08007805 static AudioPortConfig updatePortConfig(AudioPortConfig portCfg, ArrayList<AudioPort> ports) {
Eric Laurentb69681c2014-05-19 19:02:51 -07007806 AudioPort port = portCfg.port();
7807 int k;
7808 for (k = 0; k < ports.size(); k++) {
7809 // compare handles because the port returned by JNI is not of the correct
7810 // subclass
7811 if (ports.get(k).handle().equals(port.handle())) {
Eric Laurentb69681c2014-05-19 19:02:51 -07007812 port = ports.get(k);
7813 break;
7814 }
7815 }
7816 if (k == ports.size()) {
Darwin Huangbb111732022-10-21 13:14:32 +00007817 // This can happen in case of stale audio patch referring to a removed device and is
7818 // handled by the caller.
Eric Laurentb69681c2014-05-19 19:02:51 -07007819 return null;
7820 }
7821 AudioGainConfig gainCfg = portCfg.gain();
7822 if (gainCfg != null) {
7823 AudioGain gain = port.gain(gainCfg.index());
7824 gainCfg = gain.buildConfig(gainCfg.mode(),
7825 gainCfg.channelMask(),
7826 gainCfg.values(),
7827 gainCfg.rampDurationMs());
7828 }
7829 return port.buildConfig(portCfg.samplingRate(),
7830 portCfg.channelMask(),
7831 portCfg.format(),
7832 gainCfg);
7833 }
Paul McLeane3383cc2015-05-08 11:41:20 -07007834
7835 private OnAmPortUpdateListener mPortListener = null;
7836
7837 /**
7838 * The message sent to apps when the contents of the device list changes if they provide
Paul Wang9b2d0482022-05-17 10:18:01 +00007839 * a {@link Handler} object to {@link registerAudioDeviceCallback}.
Paul McLeane3383cc2015-05-08 11:41:20 -07007840 */
Paul McLeancbeb8a22015-06-10 08:21:27 -07007841 private final static int MSG_DEVICES_CALLBACK_REGISTERED = 0;
7842 private final static int MSG_DEVICES_DEVICES_ADDED = 1;
7843 private final static int MSG_DEVICES_DEVICES_REMOVED = 2;
Paul McLeane3383cc2015-05-08 11:41:20 -07007844
Paul McLean8e6c9f42015-05-19 11:13:41 -07007845 /**
7846 * The list of {@link AudioDeviceCallback} objects to receive add/remove notifications.
7847 */
Jack He89f97982018-05-02 19:10:56 -07007848 private final ArrayMap<AudioDeviceCallback, NativeEventHandlerDelegate> mDeviceCallbacks =
Paul McLean03346882015-05-12 15:36:56 -07007849 new ArrayMap<AudioDeviceCallback, NativeEventHandlerDelegate>();
Paul McLeane3383cc2015-05-08 11:41:20 -07007850
7851 /**
Paul McLean8e6c9f42015-05-19 11:13:41 -07007852 * The following are flags to allow users of {@link AudioManager#getDevices(int)} to filter
7853 * the results list to only those device types they are interested in.
7854 */
7855 /**
Paul McLeane3383cc2015-05-08 11:41:20 -07007856 * Specifies to the {@link AudioManager#getDevices(int)} method to include
7857 * source (i.e. input) audio devices.
7858 */
7859 public static final int GET_DEVICES_INPUTS = 0x0001;
7860
7861 /**
7862 * Specifies to the {@link AudioManager#getDevices(int)} method to include
7863 * sink (i.e. output) audio devices.
7864 */
7865 public static final int GET_DEVICES_OUTPUTS = 0x0002;
7866
Jean-Michel Trivi21cd5412019-10-30 08:16:51 -07007867 /** @hide */
7868 @IntDef(flag = true, prefix = "GET_DEVICES", value = {
7869 GET_DEVICES_INPUTS,
7870 GET_DEVICES_OUTPUTS }
7871 )
7872 @Retention(RetentionPolicy.SOURCE)
7873 public @interface AudioDeviceRole {}
7874
Paul McLeane3383cc2015-05-08 11:41:20 -07007875 /**
7876 * Specifies to the {@link AudioManager#getDevices(int)} method to include both
7877 * source and sink devices.
7878 */
7879 public static final int GET_DEVICES_ALL = GET_DEVICES_OUTPUTS | GET_DEVICES_INPUTS;
7880
7881 /**
7882 * Determines if a given AudioDevicePort meets the specified filter criteria.
7883 * @param port The port to test.
7884 * @param flags A set of bitflags specifying the criteria to test.
7885 * @see {@link GET_DEVICES_OUTPUTS} and {@link GET_DEVICES_INPUTS}
7886 **/
7887 private static boolean checkFlags(AudioDevicePort port, int flags) {
7888 return port.role() == AudioPort.ROLE_SINK && (flags & GET_DEVICES_OUTPUTS) != 0 ||
7889 port.role() == AudioPort.ROLE_SOURCE && (flags & GET_DEVICES_INPUTS) != 0;
7890 }
7891
Paul McLean11354572015-08-07 12:50:48 -06007892 private static boolean checkTypes(AudioDevicePort port) {
7893 return AudioDeviceInfo.convertInternalDeviceToDeviceType(port.type()) !=
jiabin9697c6c2018-03-20 17:13:04 -07007894 AudioDeviceInfo.TYPE_UNKNOWN;
Paul McLean11354572015-08-07 12:50:48 -06007895 }
7896
Paul McLeane3383cc2015-05-08 11:41:20 -07007897 /**
Paul McLeanb5dd7b52024-01-23 21:29:59 +00007898 * Returns a Set of unique Integers corresponding to audio device type identifiers that can
7899 * <i>potentially</i> be connected to the system and meeting the criteria specified in the
7900 * <code>direction</code> parameter.
7901 * Note that this set contains {@link AudioDeviceInfo} device type identifiers for both devices
7902 * currently available <i>and</i> those that can be available if the user connects an audio
7903 * peripheral. Examples include TYPE_WIRED_HEADSET if the Android device supports an analog
7904 * headset jack or TYPE_USB_DEVICE if the Android device supports a USB host-mode port.
7905 * These are generally a superset of device type identifiers associated with the
7906 * AudioDeviceInfo objects returned from AudioManager.getDevices().
7907 * @param direction The constant specifying whether input or output devices are queried.
7908 * @see #GET_DEVICES_OUTPUTS
7909 * @see #GET_DEVICES_INPUTS
7910 * @return A (possibly zero-length) Set of Integer objects corresponding to the audio
7911 * device types of devices supported by the implementation.
7912 * @throws IllegalArgumentException If an invalid direction constant is specified.
7913 */
7914 @FlaggedApi(FLAG_SUPPORTED_DEVICE_TYPES_API)
7915 public @NonNull Set<Integer>
Paul McLean52352962024-02-29 21:22:00 +00007916 getSupportedDeviceTypes(@AudioDeviceRole int direction) {
Paul McLeanb5dd7b52024-01-23 21:29:59 +00007917 if (direction != GET_DEVICES_OUTPUTS && direction != GET_DEVICES_INPUTS) {
Paul McLean52352962024-02-29 21:22:00 +00007918 throw new IllegalArgumentException("AudioManager.getSupportedDeviceTypes(0x"
Paul McLeanb5dd7b52024-01-23 21:29:59 +00007919 + Integer.toHexString(direction) + ") - Invalid.");
7920 }
7921
7922 IntArray internalDeviceTypes = new IntArray();
7923 int status = AudioSystem.getSupportedDeviceTypes(direction, internalDeviceTypes);
7924 if (status != AudioManager.SUCCESS) {
7925 Log.e(TAG, "AudioManager.getSupportedDeviceTypes(" + direction + ") failed. status:"
7926 + status);
7927 }
7928
7929 // convert to external (AudioDeviceInfo.getType()) device IDs
7930 HashSet<Integer> externalDeviceTypes = new HashSet<Integer>();
7931 for (int index = 0; index < internalDeviceTypes.size(); index++) {
7932 // Set will eliminate any duplicates which AudioSystem.getSupportedDeviceTypes()
7933 // returns
7934 externalDeviceTypes.add(
7935 AudioDeviceInfo.convertInternalDeviceToDeviceType(
7936 internalDeviceTypes.get(index)));
7937 }
7938
7939 return externalDeviceTypes;
7940 }
7941
7942 /**
Paul McLean8e6c9f42015-05-19 11:13:41 -07007943 * Returns an array of {@link AudioDeviceInfo} objects corresponding to the audio devices
7944 * currently connected to the system and meeting the criteria specified in the
7945 * <code>flags</code> parameter.
jiabin83221092023-01-10 00:15:47 +00007946 * Notes that Android audio framework only support one device per device type. In that case,
7947 * if there are multiple audio device with the same device type connected to the Android device,
7948 * only the last reported device will be known by Android audio framework and returned by this
7949 * API.
Paul McLeane3383cc2015-05-08 11:41:20 -07007950 * @param flags A set of bitflags specifying the criteria to test.
Elliot Waite54de77472017-01-11 15:30:35 -08007951 * @see #GET_DEVICES_OUTPUTS
7952 * @see #GET_DEVICES_INPUTS
7953 * @see #GET_DEVICES_ALL
Paul McLeane3383cc2015-05-08 11:41:20 -07007954 * @return A (possibly zero-length) array of AudioDeviceInfo objects.
7955 */
Jean-Michel Trivi21cd5412019-10-30 08:16:51 -07007956 public AudioDeviceInfo[] getDevices(@AudioDeviceRole int flags) {
Paul McLeane3383cc2015-05-08 11:41:20 -07007957 return getDevicesStatic(flags);
7958 }
7959
Paul McLean8e6c9f42015-05-19 11:13:41 -07007960 /**
7961 * Does the actual computation to generate an array of (externally-visible) AudioDeviceInfo
7962 * objects from the current (internal) AudioDevicePort list.
7963 */
Paul McLean03346882015-05-12 15:36:56 -07007964 private static AudioDeviceInfo[]
7965 infoListFromPortList(ArrayList<AudioDevicePort> ports, int flags) {
Paul McLeane3383cc2015-05-08 11:41:20 -07007966
Paul McLean8e6c9f42015-05-19 11:13:41 -07007967 // figure out how many AudioDeviceInfo we need space for...
Paul McLeane3383cc2015-05-08 11:41:20 -07007968 int numRecs = 0;
7969 for (AudioDevicePort port : ports) {
Paul McLean11354572015-08-07 12:50:48 -06007970 if (checkTypes(port) && checkFlags(port, flags)) {
Paul McLeane3383cc2015-05-08 11:41:20 -07007971 numRecs++;
7972 }
7973 }
7974
Paul McLean8e6c9f42015-05-19 11:13:41 -07007975 // Now load them up...
Paul McLeane3383cc2015-05-08 11:41:20 -07007976 AudioDeviceInfo[] deviceList = new AudioDeviceInfo[numRecs];
7977 int slot = 0;
7978 for (AudioDevicePort port : ports) {
Paul McLean11354572015-08-07 12:50:48 -06007979 if (checkTypes(port) && checkFlags(port, flags)) {
Paul McLeane3383cc2015-05-08 11:41:20 -07007980 deviceList[slot++] = new AudioDeviceInfo(port);
7981 }
7982 }
7983
7984 return deviceList;
7985 }
7986
Paul McLean03346882015-05-12 15:36:56 -07007987 /*
Paul McLean8e6c9f42015-05-19 11:13:41 -07007988 * Calculate the list of ports that are in ports_B, but not in ports_A. This is used by
7989 * the add/remove callback mechanism to provide a list of the newly added or removed devices
7990 * rather than the whole list and make the app figure it out.
7991 * Note that calling this method with:
7992 * ports_A == PREVIOUS_ports and ports_B == CURRENT_ports will calculated ADDED ports.
7993 * ports_A == CURRENT_ports and ports_B == PREVIOUS_ports will calculated REMOVED ports.
Paul McLean03346882015-05-12 15:36:56 -07007994 */
7995 private static AudioDeviceInfo[] calcListDeltas(
7996 ArrayList<AudioDevicePort> ports_A, ArrayList<AudioDevicePort> ports_B, int flags) {
7997
7998 ArrayList<AudioDevicePort> delta_ports = new ArrayList<AudioDevicePort>();
7999
8000 AudioDevicePort cur_port = null;
8001 for (int cur_index = 0; cur_index < ports_B.size(); cur_index++) {
8002 boolean cur_port_found = false;
8003 cur_port = ports_B.get(cur_index);
8004 for (int prev_index = 0;
8005 prev_index < ports_A.size() && !cur_port_found;
8006 prev_index++) {
8007 cur_port_found = (cur_port.id() == ports_A.get(prev_index).id());
8008 }
8009
8010 if (!cur_port_found) {
8011 delta_ports.add(cur_port);
8012 }
8013 }
8014
8015 return infoListFromPortList(delta_ports, flags);
8016 }
8017
Paul McLeane3383cc2015-05-08 11:41:20 -07008018 /**
Paul McLean03346882015-05-12 15:36:56 -07008019 * Generates a list of AudioDeviceInfo objects corresponding to the audio devices currently
8020 * connected to the system and meeting the criteria specified in the <code>flags</code>
8021 * parameter.
Paul McLean8e6c9f42015-05-19 11:13:41 -07008022 * This is an internal function. The public API front is getDevices(int).
Paul McLean03346882015-05-12 15:36:56 -07008023 * @param flags A set of bitflags specifying the criteria to test.
Elliot Waite54de77472017-01-11 15:30:35 -08008024 * @see #GET_DEVICES_OUTPUTS
8025 * @see #GET_DEVICES_INPUTS
8026 * @see #GET_DEVICES_ALL
Paul McLean03346882015-05-12 15:36:56 -07008027 * @return A (possibly zero-length) array of AudioDeviceInfo objects.
8028 * @hide
8029 */
8030 public static AudioDeviceInfo[] getDevicesStatic(int flags) {
8031 ArrayList<AudioDevicePort> ports = new ArrayList<AudioDevicePort>();
8032 int status = AudioManager.listAudioDevicePorts(ports);
8033 if (status != AudioManager.SUCCESS) {
8034 // fail and bail!
Paul McLean8e6c9f42015-05-19 11:13:41 -07008035 return new AudioDeviceInfo[0]; // Always return an array.
Paul McLean03346882015-05-12 15:36:56 -07008036 }
8037
8038 return infoListFromPortList(ports, flags);
8039 }
8040
8041 /**
Eric Laurentb36d4a12020-10-09 09:52:49 -07008042 * Returns an {@link AudioDeviceInfo} corresponding to the specified {@link AudioPort} ID.
8043 * @param portId The audio port ID to look up for.
8044 * @param flags A set of bitflags specifying the criteria to test.
8045 * @see #GET_DEVICES_OUTPUTS
8046 * @see #GET_DEVICES_INPUTS
8047 * @see #GET_DEVICES_ALL
8048 * @return An AudioDeviceInfo or null if no device with matching port ID is found.
8049 * @hide
8050 */
8051 public static AudioDeviceInfo getDeviceForPortId(int portId, int flags) {
8052 if (portId == 0) {
8053 return null;
8054 }
8055 AudioDeviceInfo[] devices = getDevicesStatic(flags);
8056 for (AudioDeviceInfo device : devices) {
8057 if (device.getId() == portId) {
8058 return device;
8059 }
8060 }
8061 return null;
8062 }
8063
8064 /**
Paul McLean8e6c9f42015-05-19 11:13:41 -07008065 * Registers an {@link AudioDeviceCallback} object to receive notifications of changes
Paul McLeane3383cc2015-05-08 11:41:20 -07008066 * to the set of connected audio devices.
Paul McLean8e6c9f42015-05-19 11:13:41 -07008067 * @param callback The {@link AudioDeviceCallback} object to receive connect/disconnect
8068 * notifications.
8069 * @param handler Specifies the {@link Handler} object for the thread on which to execute
8070 * the callback. If <code>null</code>, the {@link Handler} associated with the main
8071 * {@link Looper} will be used.
Paul McLeane3383cc2015-05-08 11:41:20 -07008072 */
Paul McLean03346882015-05-12 15:36:56 -07008073 public void registerAudioDeviceCallback(AudioDeviceCallback callback,
Jean-Michel Trivi1ec66182019-12-30 09:53:04 -08008074 @Nullable Handler handler) {
Eric Laurent1691f732015-07-14 16:27:54 -07008075 synchronized (mDeviceCallbacks) {
8076 if (callback != null && !mDeviceCallbacks.containsKey(callback)) {
Eric Laurentc573bc52015-06-26 10:01:12 -07008077 if (mDeviceCallbacks.size() == 0) {
8078 if (mPortListener == null) {
8079 mPortListener = new OnAmPortUpdateListener();
8080 }
8081 registerAudioPortUpdateListener(mPortListener);
8082 }
Paul McLeancbeb8a22015-06-10 08:21:27 -07008083 NativeEventHandlerDelegate delegate =
8084 new NativeEventHandlerDelegate(callback, handler);
8085 mDeviceCallbacks.put(callback, delegate);
jiabin8c3a7672018-05-22 15:44:21 -07008086 broadcastDeviceListChange_sync(delegate.getHandler());
Paul McLeane3383cc2015-05-08 11:41:20 -07008087 }
8088 }
8089 }
8090
8091 /**
Paul McLean8e6c9f42015-05-19 11:13:41 -07008092 * Unregisters an {@link AudioDeviceCallback} object which has been previously registered
Paul McLeane3383cc2015-05-08 11:41:20 -07008093 * to receive notifications of changes to the set of connected audio devices.
Paul McLean8e6c9f42015-05-19 11:13:41 -07008094 * @param callback The {@link AudioDeviceCallback} object that was previously registered
Elliot Waite54de77472017-01-11 15:30:35 -08008095 * with {@link AudioManager#registerAudioDeviceCallback} to be unregistered.
Paul McLeane3383cc2015-05-08 11:41:20 -07008096 */
Paul McLean03346882015-05-12 15:36:56 -07008097 public void unregisterAudioDeviceCallback(AudioDeviceCallback callback) {
8098 synchronized (mDeviceCallbacks) {
8099 if (mDeviceCallbacks.containsKey(callback)) {
8100 mDeviceCallbacks.remove(callback);
Eric Laurentc573bc52015-06-26 10:01:12 -07008101 if (mDeviceCallbacks.size() == 0) {
8102 unregisterAudioPortUpdateListener(mPortListener);
8103 }
Paul McLeane3383cc2015-05-08 11:41:20 -07008104 }
8105 }
8106 }
8107
jiabinc0f49442018-01-05 10:23:50 -08008108 /**
8109 * Set port id for microphones by matching device type and address.
8110 * @hide
8111 */
8112 public static void setPortIdForMicrophones(ArrayList<MicrophoneInfo> microphones) {
8113 AudioDeviceInfo[] devices = getDevicesStatic(AudioManager.GET_DEVICES_INPUTS);
8114 for (int i = microphones.size() - 1; i >= 0; i--) {
8115 boolean foundPortId = false;
8116 for (AudioDeviceInfo device : devices) {
8117 if (device.getPort().type() == microphones.get(i).getInternalDeviceType()
8118 && TextUtils.equals(device.getAddress(), microphones.get(i).getAddress())) {
8119 microphones.get(i).setId(device.getId());
8120 foundPortId = true;
8121 break;
8122 }
8123 }
8124 if (!foundPortId) {
8125 Log.i(TAG, "Failed to find port id for device with type:"
8126 + microphones.get(i).getType() + " address:"
8127 + microphones.get(i).getAddress());
8128 microphones.remove(i);
8129 }
8130 }
8131 }
8132
8133 /**
jiabin589a2362018-02-22 16:21:53 -08008134 * Convert {@link AudioDeviceInfo} to {@link MicrophoneInfo}.
8135 * @hide
8136 */
8137 public static MicrophoneInfo microphoneInfoFromAudioDeviceInfo(AudioDeviceInfo deviceInfo) {
8138 int deviceType = deviceInfo.getType();
8139 int micLocation = (deviceType == AudioDeviceInfo.TYPE_BUILTIN_MIC
8140 || deviceType == AudioDeviceInfo.TYPE_TELEPHONY) ? MicrophoneInfo.LOCATION_MAINBODY
8141 : deviceType == AudioDeviceInfo.TYPE_UNKNOWN ? MicrophoneInfo.LOCATION_UNKNOWN
8142 : MicrophoneInfo.LOCATION_PERIPHERAL;
8143 MicrophoneInfo microphone = new MicrophoneInfo(
8144 deviceInfo.getPort().name() + deviceInfo.getId(),
8145 deviceInfo.getPort().type(), deviceInfo.getAddress(), micLocation,
8146 MicrophoneInfo.GROUP_UNKNOWN, MicrophoneInfo.INDEX_IN_THE_GROUP_UNKNOWN,
8147 MicrophoneInfo.POSITION_UNKNOWN, MicrophoneInfo.ORIENTATION_UNKNOWN,
8148 new ArrayList<Pair<Float, Float>>(), new ArrayList<Pair<Integer, Integer>>(),
8149 MicrophoneInfo.SENSITIVITY_UNKNOWN, MicrophoneInfo.SPL_UNKNOWN,
8150 MicrophoneInfo.SPL_UNKNOWN, MicrophoneInfo.DIRECTIONALITY_UNKNOWN);
8151 microphone.setId(deviceInfo.getId());
8152 return microphone;
8153 }
8154
8155 /**
jiabind0be5b22018-04-10 14:10:04 -07008156 * Add {@link MicrophoneInfo} by device information while filtering certain types.
8157 */
8158 private void addMicrophonesFromAudioDeviceInfo(ArrayList<MicrophoneInfo> microphones,
8159 HashSet<Integer> filterTypes) {
8160 AudioDeviceInfo[] devices = getDevicesStatic(GET_DEVICES_INPUTS);
8161 for (AudioDeviceInfo device : devices) {
8162 if (filterTypes.contains(device.getType())) {
8163 continue;
8164 }
8165 MicrophoneInfo microphone = microphoneInfoFromAudioDeviceInfo(device);
8166 microphones.add(microphone);
8167 }
8168 }
8169
8170 /**
jiabinc0f49442018-01-05 10:23:50 -08008171 * Returns a list of {@link MicrophoneInfo} that corresponds to the characteristics
8172 * of all available microphones. The list is empty when no microphones are available
8173 * on the device. An error during the query will result in an IOException being thrown.
8174 *
8175 * @return a list that contains all microphones' characteristics
8176 * @throws IOException if an error occurs.
8177 */
8178 public List<MicrophoneInfo> getMicrophones() throws IOException {
8179 ArrayList<MicrophoneInfo> microphones = new ArrayList<MicrophoneInfo>();
8180 int status = AudioSystem.getMicrophones(microphones);
jiabind0be5b22018-04-10 14:10:04 -07008181 HashSet<Integer> filterTypes = new HashSet<>();
8182 filterTypes.add(AudioDeviceInfo.TYPE_TELEPHONY);
jiabinc0f49442018-01-05 10:23:50 -08008183 if (status != AudioManager.SUCCESS) {
jiabind0be5b22018-04-10 14:10:04 -07008184 // fail and populate microphones with unknown characteristics by device information.
jiabina26a7622018-04-11 15:38:46 -07008185 if (status != AudioManager.ERROR_INVALID_OPERATION) {
8186 Log.e(TAG, "getMicrophones failed:" + status);
8187 }
8188 Log.i(TAG, "fallback on device info");
jiabind0be5b22018-04-10 14:10:04 -07008189 addMicrophonesFromAudioDeviceInfo(microphones, filterTypes);
8190 return microphones;
jiabinc0f49442018-01-05 10:23:50 -08008191 }
8192 setPortIdForMicrophones(microphones);
jiabind0be5b22018-04-10 14:10:04 -07008193 filterTypes.add(AudioDeviceInfo.TYPE_BUILTIN_MIC);
8194 addMicrophonesFromAudioDeviceInfo(microphones, filterTypes);
jiabinc0f49442018-01-05 10:23:50 -08008195 return microphones;
8196 }
8197
Arun Mirpuricb102fa2019-01-11 18:39:21 -08008198 /**
8199 * Returns a list of audio formats that corresponds to encoding formats
William Escandea05cb452021-12-08 14:14:19 +01008200 * supported on offload path for A2DP playback.
Arun Mirpuricb102fa2019-01-11 18:39:21 -08008201 *
8202 * @return a list of {@link BluetoothCodecConfig} objects containing encoding formats
William Escandea05cb452021-12-08 14:14:19 +01008203 * supported for offload A2DP playback
Arun Mirpuricb102fa2019-01-11 18:39:21 -08008204 * @hide
8205 */
William Escandea05cb452021-12-08 14:14:19 +01008206 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
8207 public @NonNull List<BluetoothCodecConfig> getHwOffloadFormatsSupportedForA2dp() {
8208 ArrayList<Integer> formatsList = new ArrayList<>();
8209 ArrayList<BluetoothCodecConfig> codecConfigList = new ArrayList<>();
Arun Mirpuricb102fa2019-01-11 18:39:21 -08008210
William Escandea05cb452021-12-08 14:14:19 +01008211 int status = AudioSystem.getHwOffloadFormatsSupportedForBluetoothMedia(
8212 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, formatsList);
Arun Mirpuricb102fa2019-01-11 18:39:21 -08008213 if (status != AudioManager.SUCCESS) {
William Escandea05cb452021-12-08 14:14:19 +01008214 Log.e(TAG, "getHwOffloadEncodingFormatsSupportedForA2DP failed:" + status);
8215 return codecConfigList;
Arun Mirpuricb102fa2019-01-11 18:39:21 -08008216 }
8217
William Escandea05cb452021-12-08 14:14:19 +01008218 for (Integer format : formatsList) {
8219 int btSourceCodec = AudioSystem.audioFormatToBluetoothSourceCodec(format);
8220 if (btSourceCodec != BluetoothCodecConfig.SOURCE_CODEC_TYPE_INVALID) {
Etienne Ruffieux2c5180a2022-03-08 13:31:41 +00008221 codecConfigList.add(
8222 new BluetoothCodecConfig.Builder().setCodecType(btSourceCodec).build());
Arun Mirpuricb102fa2019-01-11 18:39:21 -08008223 }
William Escandea05cb452021-12-08 14:14:19 +01008224 }
8225 return codecConfigList;
8226 }
8227
Patty Huang1dc21e12022-07-06 00:12:03 +08008228 private List<BluetoothLeAudioCodecConfig> getHwOffloadFormatsSupportedForLeAudio(
8229 @AudioSystem.BtOffloadDeviceType int deviceType) {
William Escandea05cb452021-12-08 14:14:19 +01008230 ArrayList<Integer> formatsList = new ArrayList<>();
8231 ArrayList<BluetoothLeAudioCodecConfig> leAudioCodecConfigList = new ArrayList<>();
8232
8233 int status = AudioSystem.getHwOffloadFormatsSupportedForBluetoothMedia(
Patty Huang1dc21e12022-07-06 00:12:03 +08008234 deviceType, formatsList);
William Escandea05cb452021-12-08 14:14:19 +01008235 if (status != AudioManager.SUCCESS) {
8236 Log.e(TAG, "getHwOffloadEncodingFormatsSupportedForLeAudio failed:" + status);
Patty46694212021-11-04 21:03:32 +08008237 return leAudioCodecConfigList;
Arun Mirpuricb102fa2019-01-11 18:39:21 -08008238 }
William Escandea05cb452021-12-08 14:14:19 +01008239
8240 for (Integer format : formatsList) {
8241 int btLeAudioCodec = AudioSystem.audioFormatToBluetoothLeAudioSourceCodec(format);
8242 if (btLeAudioCodec != BluetoothLeAudioCodecConfig.SOURCE_CODEC_TYPE_INVALID) {
8243 leAudioCodecConfigList.add(new BluetoothLeAudioCodecConfig.Builder()
8244 .setCodecType(btLeAudioCodec)
8245 .build());
8246 }
8247 }
8248 return leAudioCodecConfigList;
Arun Mirpuricb102fa2019-01-11 18:39:21 -08008249 }
8250
Patty Huang1dc21e12022-07-06 00:12:03 +08008251 /**
8252 * Returns a list of audio formats that corresponds to encoding formats
8253 * supported on offload path for Le audio playback.
8254 *
8255 * @return a list of {@link BluetoothLeAudioCodecConfig} objects containing encoding formats
8256 * supported for offload Le Audio playback
8257 * @hide
8258 */
8259 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
8260 @NonNull
8261 public List<BluetoothLeAudioCodecConfig> getHwOffloadFormatsSupportedForLeAudio() {
8262 return getHwOffloadFormatsSupportedForLeAudio(AudioSystem.DEVICE_OUT_BLE_HEADSET);
8263 }
8264
8265 /**
8266 * Returns a list of audio formats that corresponds to encoding formats
8267 * supported on offload path for Le Broadcast playback.
8268 *
8269 * @return a list of {@link BluetoothLeAudioCodecConfig} objects containing encoding formats
8270 * supported for offload Le Broadcast playback
8271 * @hide
8272 */
8273 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
8274 @NonNull
8275 public List<BluetoothLeAudioCodecConfig> getHwOffloadFormatsSupportedForLeBroadcast() {
8276 return getHwOffloadFormatsSupportedForLeAudio(AudioSystem.DEVICE_OUT_BLE_BROADCAST);
8277 }
8278
Paul McLeancbeb8a22015-06-10 08:21:27 -07008279 // Since we need to calculate the changes since THE LAST NOTIFICATION, and not since the
8280 // (unpredictable) last time updateAudioPortCache() was called by someone, keep a list
8281 // of the ports that exist at the time of the last notification.
8282 private ArrayList<AudioDevicePort> mPreviousPorts = new ArrayList<AudioDevicePort>();
8283
Paul McLeane3383cc2015-05-08 11:41:20 -07008284 /**
Paul McLean8e6c9f42015-05-19 11:13:41 -07008285 * Internal method to compute and generate add/remove messages and then send to any
jiabin8c3a7672018-05-22 15:44:21 -07008286 * registered callbacks. Must be called synchronized on mDeviceCallbacks.
Paul McLeane3383cc2015-05-08 11:41:20 -07008287 */
jiabin8c3a7672018-05-22 15:44:21 -07008288 private void broadcastDeviceListChange_sync(Handler handler) {
Paul McLean03346882015-05-12 15:36:56 -07008289 int status;
8290
Paul McLeancbeb8a22015-06-10 08:21:27 -07008291 // Get the new current set of ports
Paul McLean03346882015-05-12 15:36:56 -07008292 ArrayList<AudioDevicePort> current_ports = new ArrayList<AudioDevicePort>();
8293 status = AudioManager.listAudioDevicePorts(current_ports);
8294 if (status != AudioManager.SUCCESS) {
8295 return;
8296 }
8297
Paul McLeancbeb8a22015-06-10 08:21:27 -07008298 if (handler != null) {
8299 // This is the callback for the registration, so send the current list
8300 AudioDeviceInfo[] deviceList =
8301 infoListFromPortList(current_ports, GET_DEVICES_ALL);
8302 handler.sendMessage(
8303 Message.obtain(handler, MSG_DEVICES_CALLBACK_REGISTERED, deviceList));
8304 } else {
8305 AudioDeviceInfo[] added_devices =
8306 calcListDeltas(mPreviousPorts, current_ports, GET_DEVICES_ALL);
8307 AudioDeviceInfo[] removed_devices =
8308 calcListDeltas(current_ports, mPreviousPorts, GET_DEVICES_ALL);
Paul McLeancbeb8a22015-06-10 08:21:27 -07008309 if (added_devices.length != 0 || removed_devices.length != 0) {
jiabin8c3a7672018-05-22 15:44:21 -07008310 for (int i = 0; i < mDeviceCallbacks.size(); i++) {
8311 handler = mDeviceCallbacks.valueAt(i).getHandler();
8312 if (handler != null) {
8313 if (removed_devices.length != 0) {
8314 handler.sendMessage(Message.obtain(handler,
8315 MSG_DEVICES_DEVICES_REMOVED,
8316 removed_devices));
8317 }
8318 if (added_devices.length != 0) {
8319 handler.sendMessage(Message.obtain(handler,
8320 MSG_DEVICES_DEVICES_ADDED,
8321 added_devices));
Paul McLeancbeb8a22015-06-10 08:21:27 -07008322 }
Paul McLean03346882015-05-12 15:36:56 -07008323 }
8324 }
Paul McLeane3383cc2015-05-08 11:41:20 -07008325 }
8326 }
Paul McLeancbeb8a22015-06-10 08:21:27 -07008327
8328 mPreviousPorts = current_ports;
Paul McLeane3383cc2015-05-08 11:41:20 -07008329 }
8330
8331 /**
8332 * Handles Port list update notifications from the AudioManager
8333 */
8334 private class OnAmPortUpdateListener implements AudioManager.OnAudioPortUpdateListener {
8335 static final String TAG = "OnAmPortUpdateListener";
8336 public void onAudioPortListUpdate(AudioPort[] portList) {
jiabin8c3a7672018-05-22 15:44:21 -07008337 synchronized (mDeviceCallbacks) {
8338 broadcastDeviceListChange_sync(null);
8339 }
Paul McLeane3383cc2015-05-08 11:41:20 -07008340 }
8341
8342 /**
8343 * Callback method called upon audio patch list update.
Paul McLean8e6c9f42015-05-19 11:13:41 -07008344 * Note: We don't do anything with Patches at this time, so ignore this notification.
8345 * @param patchList the updated list of audio patches.
Paul McLeane3383cc2015-05-08 11:41:20 -07008346 */
8347 public void onAudioPatchListUpdate(AudioPatch[] patchList) {}
8348
8349 /**
8350 * Callback method called when the mediaserver dies
8351 */
8352 public void onServiceDied() {
jiabin8c3a7672018-05-22 15:44:21 -07008353 synchronized (mDeviceCallbacks) {
8354 broadcastDeviceListChange_sync(null);
8355 }
Paul McLeane3383cc2015-05-08 11:41:20 -07008356 }
8357 }
8358
Eric Laurent1d3cdce2018-01-20 10:31:21 -08008359
8360 /**
8361 * @hide
8362 * Abstract class to receive event notification about audioserver process state.
8363 */
8364 @SystemApi
8365 public abstract static class AudioServerStateCallback {
8366 public void onAudioServerDown() { }
8367 public void onAudioServerUp() { }
8368 }
8369
8370 private Executor mAudioServerStateExec;
8371 private AudioServerStateCallback mAudioServerStateCb;
8372 private final Object mAudioServerStateCbLock = new Object();
8373
8374 private final IAudioServerStateDispatcher mAudioServerStateDispatcher =
8375 new IAudioServerStateDispatcher.Stub() {
8376 @Override
8377 public void dispatchAudioServerStateChange(boolean state) {
8378 Executor exec;
8379 AudioServerStateCallback cb;
8380
8381 synchronized (mAudioServerStateCbLock) {
8382 exec = mAudioServerStateExec;
8383 cb = mAudioServerStateCb;
8384 }
8385
8386 if ((exec == null) || (cb == null)) {
8387 return;
8388 }
8389 if (state) {
8390 exec.execute(() -> cb.onAudioServerUp());
8391 } else {
8392 exec.execute(() -> cb.onAudioServerDown());
8393 }
8394 }
8395 };
8396
8397 /**
8398 * @hide
8399 * Registers a callback for notification of audio server state changes.
8400 * @param executor {@link Executor} to handle the callbacks
8401 * @param stateCallback the callback to receive the audio server state changes
8402 * To remove the callabck, pass a null reference for both executor and stateCallback.
8403 */
8404 @SystemApi
8405 public void setAudioServerStateCallback(@NonNull Executor executor,
8406 @NonNull AudioServerStateCallback stateCallback) {
8407 if (stateCallback == null) {
8408 throw new IllegalArgumentException("Illegal null AudioServerStateCallback");
8409 }
8410 if (executor == null) {
8411 throw new IllegalArgumentException(
8412 "Illegal null Executor for the AudioServerStateCallback");
8413 }
8414
8415 synchronized (mAudioServerStateCbLock) {
8416 if (mAudioServerStateCb != null) {
8417 throw new IllegalStateException(
8418 "setAudioServerStateCallback called with already registered callabck");
8419 }
8420 final IAudioService service = getService();
8421 try {
8422 service.registerAudioServerStateDispatcher(mAudioServerStateDispatcher);
8423 } catch (RemoteException e) {
8424 throw e.rethrowFromSystemServer();
8425 }
8426 mAudioServerStateExec = executor;
8427 mAudioServerStateCb = stateCallback;
8428 }
8429 }
8430
8431 /**
8432 * @hide
8433 * Unregisters the callback for notification of audio server state changes.
8434 */
8435 @SystemApi
8436 public void clearAudioServerStateCallback() {
8437 synchronized (mAudioServerStateCbLock) {
8438 if (mAudioServerStateCb != null) {
8439 final IAudioService service = getService();
8440 try {
8441 service.unregisterAudioServerStateDispatcher(
8442 mAudioServerStateDispatcher);
8443 } catch (RemoteException e) {
8444 throw e.rethrowFromSystemServer();
8445 }
8446 }
8447 mAudioServerStateExec = null;
8448 mAudioServerStateCb = null;
8449 }
8450 }
8451
8452 /**
8453 * @hide
8454 * Checks if native audioservice is running or not.
8455 * @return true if native audioservice runs, false otherwise.
8456 */
8457 @SystemApi
8458 public boolean isAudioServerRunning() {
8459 final IAudioService service = getService();
8460 try {
8461 return service.isAudioServerRunning();
8462 } catch (RemoteException e) {
8463 throw e.rethrowFromSystemServer();
8464 }
8465 }
8466
jiabin39940752018-04-02 18:18:45 -07008467 /**
Kriti Dang527e66c2021-03-04 10:37:22 +01008468 * Sets the surround sound mode.
8469 *
8470 * @return true if successful, otherwise false
8471 */
Jean-Michel Trivic4557822023-01-23 18:19:52 +00008472 @RequiresPermission(Manifest.permission.WRITE_SETTINGS)
Kriti Dang527e66c2021-03-04 10:37:22 +01008473 public boolean setEncodedSurroundMode(@EncodedSurroundOutputMode int mode) {
8474 try {
8475 return getService().setEncodedSurroundMode(mode);
8476 } catch (RemoteException e) {
8477 throw e.rethrowFromSystemServer();
8478 }
8479 }
8480
8481 /**
8482 * Gets the surround sound mode.
8483 *
8484 * @return true if successful, otherwise false
8485 */
Kriti Dang527e66c2021-03-04 10:37:22 +01008486 public @EncodedSurroundOutputMode int getEncodedSurroundMode() {
8487 try {
Kriti Dang98fdb262021-04-01 13:26:00 +02008488 return getService().getEncodedSurroundMode(
8489 getContext().getApplicationInfo().targetSdkVersion);
Kriti Dang527e66c2021-03-04 10:37:22 +01008490 } catch (RemoteException e) {
8491 throw e.rethrowFromSystemServer();
8492 }
8493 }
8494
8495 /**
jiabin39940752018-04-02 18:18:45 -07008496 * @hide
8497 * Returns all surround formats.
8498 * @return a map where the key is a surround format and
8499 * the value indicates the surround format is enabled or not
8500 */
Marin Shalamanov49e778e2021-06-02 14:12:41 +02008501 @TestApi
8502 @NonNull
jiabin39940752018-04-02 18:18:45 -07008503 public Map<Integer, Boolean> getSurroundFormats() {
Kriti Dang1380c0e2021-06-04 14:51:48 +02008504 try {
8505 return getService().getSurroundFormats();
8506 } catch (RemoteException e) {
8507 throw e.rethrowFromSystemServer();
jiabin39940752018-04-02 18:18:45 -07008508 }
jiabin39940752018-04-02 18:18:45 -07008509 }
8510
8511 /**
Kriti Dang3f296bd2021-05-31 15:54:44 +02008512 * Sets and persists a certain surround format as enabled or not.
8513 * <p>
8514 * This API is called by TvSettings surround sound menu when user enables or disables a
8515 * surround sound format. This setting is persisted as global user setting.
8516 * Applications should revert their changes to surround sound settings unless they intend to
8517 * modify the global user settings across all apps. The framework does not auto-revert an
8518 * application's settings after a lifecycle event. Audio focus is not required to apply these
8519 * settings.
Kriti Dang1985c452021-05-10 17:06:44 +02008520 *
jiabin39940752018-04-02 18:18:45 -07008521 * @param enabled the required surround format state, true for enabled, false for disabled
8522 * @return true if successful, otherwise false
8523 */
Jean-Michel Trivic4557822023-01-23 18:19:52 +00008524 @RequiresPermission(Manifest.permission.WRITE_SETTINGS)
jiabin39940752018-04-02 18:18:45 -07008525 public boolean setSurroundFormatEnabled(
8526 @AudioFormat.SurroundSoundEncoding int audioFormat, boolean enabled) {
Kriti Dang527e66c2021-03-04 10:37:22 +01008527 try {
8528 return getService().setSurroundFormatEnabled(audioFormat, enabled);
8529 } catch (RemoteException e) {
8530 throw e.rethrowFromSystemServer();
8531 }
8532 }
8533
8534 /**
8535 * Gets whether a certain surround format is enabled or not.
8536 * @param audioFormat a surround format
8537 *
8538 * @return whether the required surround format is enabled
8539 */
Kriti Dang527e66c2021-03-04 10:37:22 +01008540 public boolean isSurroundFormatEnabled(@AudioFormat.SurroundSoundEncoding int audioFormat) {
8541 try {
8542 return getService().isSurroundFormatEnabled(audioFormat);
8543 } catch (RemoteException e) {
8544 throw e.rethrowFromSystemServer();
8545 }
jiabin39940752018-04-02 18:18:45 -07008546 }
8547
8548 /**
8549 * @hide
8550 * Returns all surround formats that are reported by the connected HDMI device.
Kriti Dang01924232021-03-02 13:51:09 +01008551 * The return values are not affected by calling setSurroundFormatEnabled.
jiabin39940752018-04-02 18:18:45 -07008552 *
Kriti Dang01924232021-03-02 13:51:09 +01008553 * @return a list of surround formats
jiabin39940752018-04-02 18:18:45 -07008554 */
Kriti Dang1380c0e2021-06-04 14:51:48 +02008555 @TestApi
8556 @NonNull
8557 public List<Integer> getReportedSurroundFormats() {
8558 try {
8559 return getService().getReportedSurroundFormats();
8560 } catch (RemoteException e) {
8561 throw e.rethrowFromSystemServer();
jiabin39940752018-04-02 18:18:45 -07008562 }
jiabin39940752018-04-02 18:18:45 -07008563 }
8564
jiabin66f9e722018-11-02 16:20:19 -07008565 /**
8566 * Return if audio haptic coupled playback is supported or not.
8567 *
8568 * @return whether audio haptic playback supported.
8569 */
8570 public static boolean isHapticPlaybackSupported() {
8571 return AudioSystem.isHapticPlaybackSupported();
8572 }
8573
François Gaffie0699fec2018-07-09 14:35:10 +02008574 /**
8575 * @hide
Carter Hsu2065d1e2022-01-19 19:54:50 +08008576 * Indicates whether a platform supports the Ultrasound feature which covers the playback
8577 * and recording of 20kHz~ sounds. If platform supports Ultrasound, then the
8578 * usage will be
8579 * To start the Ultrasound playback:
8580 * - Create an AudioTrack with {@link AudioAttributes.CONTENT_TYPE_ULTRASOUND}.
8581 * To start the Ultrasound capture:
8582 * - Create an AudioRecord with {@link MediaRecorder.AudioSource.ULTRASOUND}.
8583 *
8584 * @return whether the ultrasound feature is supported, true when platform supports both
8585 * Ultrasound playback and capture, false otherwise.
8586 */
8587 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00008588 @RequiresPermission(Manifest.permission.ACCESS_ULTRASOUND)
Carter Hsu3ea30de42022-02-15 15:59:00 +08008589 public boolean isUltrasoundSupported() {
8590 try {
8591 return getService().isUltrasoundSupported();
8592 } catch (RemoteException e) {
8593 throw e.rethrowFromSystemServer();
8594 }
Carter Hsu2065d1e2022-01-19 19:54:50 +08008595 }
8596
8597 /**
8598 * @hide
Atneya Naireeab0a72022-12-15 09:32:51 -08008599 * Indicates whether the platform supports capturing content from the hotword recognition
8600 * pipeline. To capture content of this type, create an AudioRecord with
8601 * {@link AudioRecord.Builder.setRequestHotwordStream(boolean, boolean)}.
8602 * @param lookbackAudio Query if the hotword stream additionally supports providing buffered
8603 * audio prior to stream open.
8604 * @return True if the platform supports capturing hotword content, and if lookbackAudio
8605 * is true, if it additionally supports capturing buffered hotword content prior to stream
8606 * open. False otherwise.
8607 */
8608 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00008609 @RequiresPermission(Manifest.permission.CAPTURE_AUDIO_HOTWORD)
Atneya Naireeab0a72022-12-15 09:32:51 -08008610 public boolean isHotwordStreamSupported(boolean lookbackAudio) {
8611 try {
8612 return getService().isHotwordStreamSupported(lookbackAudio);
8613 } catch (RemoteException e) {
8614 return false;
8615 }
8616 }
8617
8618 /**
8619 * @hide
François Gaffie0699fec2018-07-09 14:35:10 +02008620 * Introspection API to retrieve audio product strategies.
8621 * When implementing {Car|Oem}AudioManager, use this method to retrieve the collection of
8622 * audio product strategies, which is indexed by a weakly typed index in order to be extended
8623 * by OEM without any needs of AOSP patches.
8624 * The {Car|Oem}AudioManager can expose API to build {@link AudioAttributes} for a given product
8625 * strategy refered either by its index or human readable string. It will allow clients
8626 * application to start streaming data using these {@link AudioAttributes} on the selected
8627 * device by Audio Policy Engine.
8628 * @return a (possibly zero-length) array of
8629 * {@see android.media.audiopolicy.AudioProductStrategy} objects.
8630 */
8631 @SystemApi
Hayden Gomes6d69bde2019-04-04 13:10:13 -07008632 @NonNull
Jean-Michel Trivic4557822023-01-23 18:19:52 +00008633 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
Hayden Gomes6d69bde2019-04-04 13:10:13 -07008634 public static List<AudioProductStrategy> getAudioProductStrategies() {
François Gaffie0699fec2018-07-09 14:35:10 +02008635 final IAudioService service = getService();
8636 try {
8637 return service.getAudioProductStrategies();
8638 } catch (RemoteException e) {
8639 throw e.rethrowFromSystemServer();
8640 }
8641 }
8642
François Gaffieadcd00a2018-09-18 17:06:26 +02008643 /**
8644 * @hide
8645 * Introspection API to retrieve audio volume groups.
8646 * When implementing {Car|Oem}AudioManager, use this method to retrieve the collection of
8647 * audio volume groups.
Hayden Gomesebd6aaa2019-04-04 13:14:21 -07008648 * @return a (possibly zero-length) List of
8649 * {@see android.media.audiopolicy.AudioVolumeGroup} objects.
François Gaffieadcd00a2018-09-18 17:06:26 +02008650 */
8651 @SystemApi
Hayden Gomesebd6aaa2019-04-04 13:14:21 -07008652 @NonNull
Jean-Michel Trivic4557822023-01-23 18:19:52 +00008653 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
Jean-Michel Trivi8d4310e2024-05-20 14:30:05 -07008654 // TODO also open to MODIFY_AUDIO_SETTINGS_PRIVILEGED b/341780042
Hayden Gomesebd6aaa2019-04-04 13:14:21 -07008655 public static List<AudioVolumeGroup> getAudioVolumeGroups() {
François Gaffie9c362102018-09-21 17:43:52 +02008656 final IAudioService service = getService();
8657 try {
Hayden Gomesebd6aaa2019-04-04 13:14:21 -07008658 return service.getAudioVolumeGroups();
François Gaffie9c362102018-09-21 17:43:52 +02008659 } catch (RemoteException e) {
8660 throw e.rethrowFromSystemServer();
8661 }
François Gaffieadcd00a2018-09-18 17:06:26 +02008662 }
8663
8664 /**
8665 * @hide
8666 * Callback registered by client to be notified upon volume group change.
8667 */
8668 @SystemApi
8669 public abstract static class VolumeGroupCallback {
8670 /**
8671 * Callback method called upon audio volume group change.
8672 * @param group the group for which the volume has changed
8673 */
8674 public void onAudioVolumeGroupChanged(int group, int flags) {}
8675 }
8676
8677 /**
8678 * @hide
8679 * Register an audio volume group change listener.
8680 * @param callback the {@link VolumeGroupCallback} to register
8681 */
8682 @SystemApi
8683 public void registerVolumeGroupCallback(
8684 @NonNull Executor executor,
8685 @NonNull VolumeGroupCallback callback) {
8686 Preconditions.checkNotNull(executor, "executor must not be null");
8687 Preconditions.checkNotNull(callback, "volume group change cb must not be null");
8688 sAudioAudioVolumeGroupChangedHandler.init();
8689 // TODO: make use of executor
8690 sAudioAudioVolumeGroupChangedHandler.registerListener(callback);
8691 }
8692
8693 /**
8694 * @hide
8695 * Unregister an audio volume group change listener.
8696 * @param callback the {@link VolumeGroupCallback} to unregister
8697 */
8698 @SystemApi
8699 public void unregisterVolumeGroupCallback(
8700 @NonNull VolumeGroupCallback callback) {
8701 Preconditions.checkNotNull(callback, "volume group change cb must not be null");
8702 sAudioAudioVolumeGroupChangedHandler.unregisterListener(callback);
8703 }
jiabin39940752018-04-02 18:18:45 -07008704
jiabinad225202019-03-20 15:22:50 -07008705 /**
8706 * Return if an asset contains haptic channels or not.
jiabincfcf1032021-07-01 16:30:50 -07008707 *
8708 * @param context the {@link Context} to resolve the uri.
jiabinad225202019-03-20 15:22:50 -07008709 * @param uri the {@link Uri} of the asset.
8710 * @return true if the assert contains haptic channels.
8711 * @hide
8712 */
jiabincfcf1032021-07-01 16:30:50 -07008713 public static boolean hasHapticChannelsImpl(@NonNull Context context, @NonNull Uri uri) {
8714 MediaExtractor extractor = new MediaExtractor();
jiabinad225202019-03-20 15:22:50 -07008715 try {
jiabincfcf1032021-07-01 16:30:50 -07008716 extractor.setDataSource(context, uri, null);
8717 for (int i = 0; i < extractor.getTrackCount(); i++) {
8718 MediaFormat format = extractor.getTrackFormat(i);
8719 if (format.containsKey(MediaFormat.KEY_HAPTIC_CHANNEL_COUNT)
8720 && format.getInteger(MediaFormat.KEY_HAPTIC_CHANNEL_COUNT) > 0) {
8721 return true;
8722 }
8723 }
8724 } catch (IOException e) {
8725 Log.e(TAG, "hasHapticChannels failure:" + e);
8726 }
8727 return false;
8728 }
8729
8730 /**
8731 * Return if an asset contains haptic channels or not.
8732 *
8733 * @param context the {@link Context} to resolve the uri.
8734 * @param uri the {@link Uri} of the asset.
8735 * @return true if the assert contains haptic channels.
8736 * @hide
8737 */
8738 public static boolean hasHapticChannels(@Nullable Context context, @NonNull Uri uri) {
8739 Objects.requireNonNull(uri);
jiabin0f3339c2021-07-09 11:50:07 -07008740
jiabincfcf1032021-07-01 16:30:50 -07008741 if (context != null) {
8742 return hasHapticChannelsImpl(context, uri);
jiabin0f3339c2021-07-09 11:50:07 -07008743 }
8744
8745 Context cachedContext = sContext.get();
8746 if (cachedContext != null) {
jiabincfcf1032021-07-01 16:30:50 -07008747 if (DEBUG) {
8748 Log.d(TAG, "Try to use static context to query if having haptic channels");
8749 }
jiabin0f3339c2021-07-09 11:50:07 -07008750 return hasHapticChannelsImpl(cachedContext, uri);
8751 }
8752
8753 // Try with audio service context, this may fail to get correct result.
8754 if (DEBUG) {
8755 Log.d(TAG, "Try to use audio service context to query if having haptic channels");
8756 }
8757 try {
8758 return getService().hasHapticChannels(uri);
8759 } catch (RemoteException e) {
8760 throw e.rethrowFromSystemServer();
jiabinad225202019-03-20 15:22:50 -07008761 }
8762 }
8763
Kohsuke Yatoh900e1f12020-03-25 08:05:49 -07008764 /**
8765 * Set whether or not there is an active RTT call.
8766 * This method should be called by Telecom service.
8767 * @hide
8768 * TODO: make this a @SystemApi
8769 */
8770 public static void setRttEnabled(boolean rttEnabled) {
8771 try {
8772 getService().setRttEnabled(rttEnabled);
8773 } catch (RemoteException e) {
8774 throw e.rethrowFromSystemServer();
8775 }
8776 }
8777
Jin Seok Park16aeba382020-08-06 12:52:54 +09008778 /**
8779 * Adjusts the volume of the most relevant stream, or the given fallback
8780 * stream.
8781 * <p>
8782 * This method should only be used by applications that replace the
8783 * platform-wide management of audio settings or the main telephony
8784 * application.
8785 * <p>
8786 * This method has no effect if the device implements a fixed volume policy
8787 * as indicated by {@link #isVolumeFixed()}.
8788 * <p>This API checks if the caller has the necessary permissions based on the provided
8789 * component name, uid, and pid values.
8790 * See {@link #adjustSuggestedStreamVolume(int, int, int)}.
8791 *
8792 * @param suggestedStreamType The stream type that will be used if there
8793 * isn't a relevant stream. {@link #USE_DEFAULT_STREAM_TYPE} is
8794 * valid here.
8795 * @param direction The direction to adjust the volume. One of
8796 * {@link #ADJUST_LOWER}, {@link #ADJUST_RAISE},
8797 * {@link #ADJUST_SAME}, {@link #ADJUST_MUTE},
8798 * {@link #ADJUST_UNMUTE}, or {@link #ADJUST_TOGGLE_MUTE}.
Jean-Michel Trivi48f99852023-03-31 18:47:58 -07008799 * @param flags
Jin Seok Park16aeba382020-08-06 12:52:54 +09008800 * @param packageName the package name of client application
8801 * @param uid the uid of client application
8802 * @param pid the pid of client application
8803 * @param targetSdkVersion the target sdk version of client application
8804 * @see #adjustVolume(int, int)
8805 * @see #adjustStreamVolume(int, int, int)
8806 * @see #setStreamVolume(int, int, int)
8807 * @see #isVolumeFixed()
8808 *
8809 * @hide
8810 */
8811 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
Jean-Michel Trivi48f99852023-03-31 18:47:58 -07008812 public void adjustSuggestedStreamVolumeForUid(int suggestedStreamType, int direction,
8813 @SystemVolumeFlags int flags,
Jin Seok Park16aeba382020-08-06 12:52:54 +09008814 @NonNull String packageName, int uid, int pid, int targetSdkVersion) {
8815 try {
8816 getService().adjustSuggestedStreamVolumeForUid(suggestedStreamType, direction, flags,
8817 packageName, uid, pid, UserHandle.getUserHandleForUid(uid), targetSdkVersion);
8818 } catch (RemoteException e) {
8819 throw e.rethrowFromSystemServer();
8820 }
8821 }
8822
8823 /**
8824 * Adjusts the volume of a particular stream by one step in a direction.
8825 * <p>
8826 * This method should only be used by applications that replace the platform-wide
8827 * management of audio settings or the main telephony application.
8828 * <p>This method has no effect if the device implements a fixed volume policy
8829 * as indicated by {@link #isVolumeFixed()}.
8830 * <p>From N onward, ringer mode adjustments that would toggle Do Not Disturb are not allowed
8831 * unless the app has been granted Do Not Disturb Access.
8832 * See {@link NotificationManager#isNotificationPolicyAccessGranted()}.
8833 * <p>This API checks if the caller has the necessary permissions based on the provided
8834 * component name, uid, and pid values.
8835 * See {@link #adjustStreamVolume(int, int, int)}.
8836 *
8837 * @param streamType The stream type to adjust. One of {@link #STREAM_VOICE_CALL},
8838 * {@link #STREAM_SYSTEM}, {@link #STREAM_RING}, {@link #STREAM_MUSIC},
8839 * {@link #STREAM_ALARM} or {@link #STREAM_ACCESSIBILITY}.
8840 * @param direction The direction to adjust the volume. One of
8841 * {@link #ADJUST_LOWER}, {@link #ADJUST_RAISE}, or
8842 * {@link #ADJUST_SAME}.
Jean-Michel Trivi48f99852023-03-31 18:47:58 -07008843 * @param flags
Jin Seok Park16aeba382020-08-06 12:52:54 +09008844 * @param packageName the package name of client application
8845 * @param uid the uid of client application
8846 * @param pid the pid of client application
8847 * @param targetSdkVersion the target sdk version of client application
8848 * @see #adjustVolume(int, int)
8849 * @see #setStreamVolume(int, int, int)
8850 * @throws SecurityException if the adjustment triggers a Do Not Disturb change
8851 * and the caller is not granted notification policy access.
8852 *
8853 * @hide
8854 */
8855 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
Jean-Michel Trivi48f99852023-03-31 18:47:58 -07008856 public void adjustStreamVolumeForUid(int streamType, int direction,
8857 @SystemVolumeFlags int flags,
Jin Seok Park16aeba382020-08-06 12:52:54 +09008858 @NonNull String packageName, int uid, int pid, int targetSdkVersion) {
8859 try {
8860 getService().adjustStreamVolumeForUid(streamType, direction, flags, packageName, uid,
8861 pid, UserHandle.getUserHandleForUid(uid), targetSdkVersion);
8862 } catch (RemoteException e) {
8863 throw e.rethrowFromSystemServer();
8864 }
8865 }
8866
8867 /**
8868 * Sets the volume index for a particular stream.
8869 * <p>This method has no effect if the device implements a fixed volume policy
8870 * as indicated by {@link #isVolumeFixed()}.
8871 * <p>From N onward, volume adjustments that would toggle Do Not Disturb are not allowed unless
8872 * the app has been granted Do Not Disturb Access.
8873 * See {@link NotificationManager#isNotificationPolicyAccessGranted()}.
8874 * <p>This API checks if the caller has the necessary permissions based on the provided
8875 * component name, uid, and pid values.
8876 * See {@link #setStreamVolume(int, int, int)}.
8877 *
8878 * @param streamType The stream whose volume index should be set.
8879 * @param index The volume index to set. See
8880 * {@link #getStreamMaxVolume(int)} for the largest valid value.
Jean-Michel Trivi48f99852023-03-31 18:47:58 -07008881 * @param flags
Jin Seok Park16aeba382020-08-06 12:52:54 +09008882 * @param packageName the package name of client application
8883 * @param uid the uid of client application
8884 * @param pid the pid of client application
8885 * @param targetSdkVersion the target sdk version of client application
8886 * @see #getStreamMaxVolume(int)
8887 * @see #getStreamVolume(int)
8888 * @see #isVolumeFixed()
8889 * @throws SecurityException if the volume change triggers a Do Not Disturb change
8890 * and the caller is not granted notification policy access.
8891 *
8892 * @hide
8893 */
8894 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
Jean-Michel Trivi48f99852023-03-31 18:47:58 -07008895 public void setStreamVolumeForUid(int streamType, int index,
8896 @SystemVolumeFlags int flags,
Jin Seok Park16aeba382020-08-06 12:52:54 +09008897 @NonNull String packageName, int uid, int pid, int targetSdkVersion) {
8898 try {
8899 getService().setStreamVolumeForUid(streamType, index, flags, packageName, uid, pid,
8900 UserHandle.getUserHandleForUid(uid), targetSdkVersion);
8901 } catch (RemoteException e) {
8902 throw e.rethrowFromSystemServer();
8903 }
8904 }
8905
8906
hjin81.lee4e984e52019-12-05 14:34:52 +09008907 /** @hide
8908 * TODO: make this a @SystemApi */
Jean-Michel Trivic4557822023-01-23 18:19:52 +00008909 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
hjin81.lee4e984e52019-12-05 14:34:52 +09008910 public void setMultiAudioFocusEnabled(boolean enabled) {
8911 try {
8912 getService().setMultiAudioFocusEnabled(enabled);
8913 } catch (RemoteException e) {
8914 throw e.rethrowFromSystemServer();
8915 }
8916 }
8917
Eric Laurent43a78de2020-07-24 17:11:15 -07008918
8919 /**
8920 * Retrieves the Hardware A/V synchronization ID corresponding to the given audio session ID.
8921 * For more details on Hardware A/V synchronization please refer to
8922 * <a href="https://source.android.com/devices/tv/multimedia-tunneling/">
8923 * media tunneling documentation</a>.
8924 * @param sessionId the audio session ID for which the HW A/V sync ID is retrieved.
8925 * @return the HW A/V sync ID for this audio session (an integer different from 0).
8926 * @throws UnsupportedOperationException if HW A/V synchronization is not supported.
8927 */
8928 public int getAudioHwSyncForSession(int sessionId) {
8929 int hwSyncId = AudioSystem.getAudioHwSyncForSession(sessionId);
8930 if (hwSyncId == AudioSystem.AUDIO_HW_SYNC_INVALID) {
8931 throw new UnsupportedOperationException("HW A/V synchronization is not supported.");
8932 }
8933 return hwSyncId;
8934 }
8935
Eric Laurentb36d4a12020-10-09 09:52:49 -07008936 /**
8937 * Selects the audio device that should be used for communication use cases, for instance voice
8938 * or video calls. This method can be used by voice or video chat applications to select a
8939 * different audio device than the one selected by default by the platform.
Eric Laurent7412f572021-02-11 15:10:31 +01008940 * <p>The device selection is expressed as an {@link AudioDeviceInfo} among devices returned by
Eric Laurent6aa23612022-11-18 16:08:20 +01008941 * {@link #getAvailableCommunicationDevices()}. Note that only devices in a sink role
8942 * (AKA output devices, see {@link AudioDeviceInfo#isSink()}) can be specified. The matching
8943 * source device is selected automatically by the platform.
8944 * <p>The selection is active as long as the requesting application process lives, until
Eric Laurent7412f572021-02-11 15:10:31 +01008945 * {@link #clearCommunicationDevice} is called or until the device is disconnected.
Eric Laurentb36d4a12020-10-09 09:52:49 -07008946 * It is therefore important for applications to clear the request when a call ends or the
Eric Laurent7412f572021-02-11 15:10:31 +01008947 * the requesting activity or service is stopped or destroyed.
Eric Laurentb36d4a12020-10-09 09:52:49 -07008948 * <p>In case of simultaneous requests by multiple applications the priority is given to the
8949 * application currently controlling the audio mode (see {@link #setMode(int)}). This is the
8950 * latest application having selected mode {@link #MODE_IN_COMMUNICATION} or mode
8951 * {@link #MODE_IN_CALL}. Note that <code>MODE_IN_CALL</code> can only be selected by the main
8952 * telephony application with permission
Jean-Michel Trivic4557822023-01-23 18:19:52 +00008953 * {@link Manifest.permission#MODIFY_PHONE_STATE}.
Eric Laurentb36d4a12020-10-09 09:52:49 -07008954 * <p> If the requested devices is not currently available, the request will be rejected and
8955 * the method will return false.
8956 * <p>This API replaces the following deprecated APIs:
8957 * <ul>
8958 * <li> {@link #startBluetoothSco()}
8959 * <li> {@link #stopBluetoothSco()}
8960 * <li> {@link #setSpeakerphoneOn(boolean)}
8961 * </ul>
8962 * <h4>Example</h4>
8963 * <p>The example below shows how to enable and disable speakerphone mode.
8964 * <pre class="prettyprint">
8965 * // Get an AudioManager instance
8966 * AudioManager audioManager = Context.getSystemService(AudioManager.class);
Eric Laurent9a404482021-03-09 19:58:39 +01008967 * AudioDeviceInfo speakerDevice = null;
8968 * List<AudioDeviceInfo> devices = audioManager.getAvailableCommunicationDevices();
8969 * for (AudioDeviceInfo device : devices) {
8970 * if (device.getType() == AudioDeviceInfo.TYPE_BUILTIN_SPEAKER) {
8971 * speakerDevice = device;
8972 * break;
Eric Laurentb36d4a12020-10-09 09:52:49 -07008973 * }
Eric Laurent9a404482021-03-09 19:58:39 +01008974 * }
8975 * if (speakerDevice != null) {
8976 * // Turn speakerphone ON.
8977 * boolean result = audioManager.setCommunicationDevice(speakerDevice);
8978 * if (!result) {
8979 * // Handle error.
Eric Laurentb36d4a12020-10-09 09:52:49 -07008980 * }
Eric Laurent9a404482021-03-09 19:58:39 +01008981 * // Turn speakerphone OFF.
8982 * audioManager.clearCommunicationDevice();
Eric Laurentb36d4a12020-10-09 09:52:49 -07008983 * }
8984 * </pre>
8985 * @param device the requested audio device.
8986 * @return <code>true</code> if the request was accepted, <code>false</code> otherwise.
8987 * @throws IllegalArgumentException If an invalid device is specified.
8988 */
Eric Laurent7412f572021-02-11 15:10:31 +01008989 public boolean setCommunicationDevice(@NonNull AudioDeviceInfo device) {
Eric Laurentb36d4a12020-10-09 09:52:49 -07008990 Objects.requireNonNull(device);
8991 try {
8992 if (device.getId() == 0) {
Eric Laurentc18e5a12023-01-20 19:30:09 +01008993 Log.w(TAG, "setCommunicationDevice: device not found: " + device);
8994 return false;
Eric Laurentb36d4a12020-10-09 09:52:49 -07008995 }
Eric Laurent7412f572021-02-11 15:10:31 +01008996 return getService().setCommunicationDevice(mICallBack, device.getId());
Eric Laurentb36d4a12020-10-09 09:52:49 -07008997 } catch (RemoteException e) {
8998 throw e.rethrowFromSystemServer();
8999 }
9000 }
9001
9002 /**
9003 * Cancels previous communication device selection made with
Eric Laurent7412f572021-02-11 15:10:31 +01009004 * {@link #setCommunicationDevice(AudioDeviceInfo)}.
Eric Laurentb36d4a12020-10-09 09:52:49 -07009005 */
Eric Laurent7412f572021-02-11 15:10:31 +01009006 public void clearCommunicationDevice() {
Eric Laurentb36d4a12020-10-09 09:52:49 -07009007 try {
Eric Laurent7412f572021-02-11 15:10:31 +01009008 getService().setCommunicationDevice(mICallBack, 0);
Eric Laurentb36d4a12020-10-09 09:52:49 -07009009 } catch (RemoteException e) {
9010 throw e.rethrowFromSystemServer();
9011 }
9012 }
9013
9014 /**
9015 * Returns currently selected audio device for communication.
9016 * <p>This API replaces the following deprecated APIs:
9017 * <ul>
9018 * <li> {@link #isBluetoothScoOn()}
9019 * <li> {@link #isSpeakerphoneOn()}
9020 * </ul>
9021 * @return an {@link AudioDeviceInfo} indicating which audio device is
Eric Laurent7412f572021-02-11 15:10:31 +01009022 * currently selected for communication use cases. Can be null on platforms
9023 * not supporting {@link android.content.pm.PackageManager#FEATURE_TELEPHONY}.
Eric Laurentb36d4a12020-10-09 09:52:49 -07009024 * is used.
9025 */
9026 @Nullable
Eric Laurent7412f572021-02-11 15:10:31 +01009027 public AudioDeviceInfo getCommunicationDevice() {
Eric Laurentb36d4a12020-10-09 09:52:49 -07009028 try {
9029 return getDeviceForPortId(
Eric Laurent7412f572021-02-11 15:10:31 +01009030 getService().getCommunicationDevice(), GET_DEVICES_OUTPUTS);
9031 } catch (RemoteException e) {
9032 throw e.rethrowFromSystemServer();
9033 }
9034 }
9035
9036 /**
9037 * Returns a list of audio devices that can be selected for communication use cases via
9038 * {@link #setCommunicationDevice(AudioDeviceInfo)}.
9039 * @return a list of {@link AudioDeviceInfo} suitable for use with setCommunicationDevice().
9040 */
9041 @NonNull
9042 public List<AudioDeviceInfo> getAvailableCommunicationDevices() {
9043 try {
9044 ArrayList<AudioDeviceInfo> devices = new ArrayList<>();
9045 int[] portIds = getService().getAvailableCommunicationDeviceIds();
9046 for (int portId : portIds) {
9047 AudioDeviceInfo device = getDeviceForPortId(portId, GET_DEVICES_OUTPUTS);
9048 if (device == null) {
9049 continue;
9050 }
9051 devices.add(device);
9052 }
9053 return devices;
Eric Laurentb36d4a12020-10-09 09:52:49 -07009054 } catch (RemoteException e) {
9055 throw e.rethrowFromSystemServer();
9056 }
9057 }
9058
9059 /**
Dorin Drimuseb9bf642022-01-03 12:05:37 +01009060 * Returns a list of direct {@link AudioProfile} that are supported for the specified
9061 * {@link AudioAttributes}. This can be empty in case of an error or if no direct playback
9062 * is possible.
9063 *
9064 * <p>Direct playback means that the audio stream is not resampled or downmixed
9065 * by the framework. Checking for direct support can help the app select the representation
9066 * of audio content that most closely matches the capabilities of the device and peripherals
9067 * (e.g. A/V receiver) connected to it. Note that the provided stream can still be re-encoded
9068 * or mixed with other streams, if needed.
9069 * <p>When using this information to inform your application which audio format to play,
9070 * query again whenever audio output devices change (see {@link AudioDeviceCallback}).
9071 * @param attributes a non-null {@link AudioAttributes} instance.
9072 * @return a list of {@link AudioProfile}
9073 */
9074 @NonNull
9075 public List<AudioProfile> getDirectProfilesForAttributes(@NonNull AudioAttributes attributes) {
9076 Objects.requireNonNull(attributes);
9077 ArrayList<AudioProfile> audioProfilesList = new ArrayList<>();
9078 int status = AudioSystem.getDirectProfilesForAttributes(attributes, audioProfilesList);
9079 if (status != SUCCESS) {
9080 Log.w(TAG, "getDirectProfilesForAttributes failed.");
9081 return new ArrayList<>();
9082 }
9083 return audioProfilesList;
9084 }
9085
9086 /**
Eric Laurentb36d4a12020-10-09 09:52:49 -07009087 * @hide
9088 * Returns an {@link AudioDeviceInfo} corresponding to a connected device of the type provided.
9089 * The type must be a valid output type defined in <code>AudioDeviceInfo</code> class,
9090 * for instance {@link AudioDeviceInfo#TYPE_BUILTIN_SPEAKER}.
9091 * The method will return null if no device of the provided type is connected.
9092 * If more than one device of the provided type is connected, an object corresponding to the
9093 * first device encountered in the enumeration list will be returned.
9094 * @param deviceType The device device for which an <code>AudioDeviceInfo</code>
Eric Laurent7412f572021-02-11 15:10:31 +01009095 * object is queried.
Eric Laurentb36d4a12020-10-09 09:52:49 -07009096 * @return An AudioDeviceInfo object or null if no device with the requested type is connected.
9097 * @throws IllegalArgumentException If an invalid device type is specified.
9098 */
9099 @TestApi
9100 @Nullable
9101 public static AudioDeviceInfo getDeviceInfoFromType(
9102 @AudioDeviceInfo.AudioDeviceTypeOut int deviceType) {
Eric Laurent7412f572021-02-11 15:10:31 +01009103 return getDeviceInfoFromTypeAndAddress(deviceType, null);
9104 }
9105
Eric Laurent78eef3a2021-11-09 16:10:42 +01009106 /**
Eric Laurent7412f572021-02-11 15:10:31 +01009107 * @hide
9108 * Returns an {@link AudioDeviceInfo} corresponding to a connected device of the type and
9109 * address provided.
9110 * The type must be a valid output type defined in <code>AudioDeviceInfo</code> class,
9111 * for instance {@link AudioDeviceInfo#TYPE_BUILTIN_SPEAKER}.
9112 * If a null address is provided, the matching will happen on the type only.
9113 * The method will return null if no device of the provided type and address is connected.
9114 * If more than one device of the provided type is connected, an object corresponding to the
9115 * first device encountered in the enumeration list will be returned.
9116 * @param type The device device for which an <code>AudioDeviceInfo</code>
9117 * object is queried.
9118 * @param address The device address for which an <code>AudioDeviceInfo</code>
9119 * object is queried or null if requesting match on type only.
9120 * @return An AudioDeviceInfo object or null if no matching device is connected.
9121 * @throws IllegalArgumentException If an invalid device type is specified.
9122 */
9123 @Nullable
9124 public static AudioDeviceInfo getDeviceInfoFromTypeAndAddress(
9125 @AudioDeviceInfo.AudioDeviceTypeOut int type, @Nullable String address) {
Eric Laurentb36d4a12020-10-09 09:52:49 -07009126 AudioDeviceInfo[] devices = getDevicesStatic(GET_DEVICES_OUTPUTS);
Eric Laurent7412f572021-02-11 15:10:31 +01009127 AudioDeviceInfo deviceForType = null;
Eric Laurentb36d4a12020-10-09 09:52:49 -07009128 for (AudioDeviceInfo device : devices) {
Eric Laurent7412f572021-02-11 15:10:31 +01009129 if (device.getType() == type) {
9130 deviceForType = device;
9131 if (address == null || address.equals(device.getAddress())) {
9132 return device;
9133 }
Eric Laurentb36d4a12020-10-09 09:52:49 -07009134 }
9135 }
Eric Laurent7412f572021-02-11 15:10:31 +01009136 return deviceForType;
Eric Laurentb36d4a12020-10-09 09:52:49 -07009137 }
9138
9139 /**
9140 * Listener registered by client to be notified upon communication audio device change.
Eric Laurent7412f572021-02-11 15:10:31 +01009141 * See {@link #setCommunicationDevice(AudioDeviceInfo)}.
Eric Laurentb36d4a12020-10-09 09:52:49 -07009142 */
9143 public interface OnCommunicationDeviceChangedListener {
9144 /**
9145 * Callback method called upon communication audio device change.
Eric Laurent7412f572021-02-11 15:10:31 +01009146 * @param device the audio device requested for communication use cases.
9147 * Can be null on platforms not supporting
9148 * {@link android.content.pm.PackageManager#FEATURE_TELEPHONY}.
Eric Laurentb36d4a12020-10-09 09:52:49 -07009149 */
9150 void onCommunicationDeviceChanged(@Nullable AudioDeviceInfo device);
9151 }
9152
9153 /**
Jean-Michel Trivi54d129f2021-12-30 17:43:47 -08009154 * manages the OnCommunicationDeviceChangedListener listeners and the
9155 * CommunicationDeviceDispatcherStub
9156 */
9157 private final CallbackUtil.LazyListenerManager<OnCommunicationDeviceChangedListener>
9158 mCommDeviceChangedListenerMgr = new CallbackUtil.LazyListenerManager();
9159 /**
Eric Laurentb36d4a12020-10-09 09:52:49 -07009160 * Adds a listener for being notified of changes to the communication audio device.
Eric Laurent7412f572021-02-11 15:10:31 +01009161 * See {@link #setCommunicationDevice(AudioDeviceInfo)}.
Eric Laurentb36d4a12020-10-09 09:52:49 -07009162 * @param executor
9163 * @param listener
9164 */
9165 public void addOnCommunicationDeviceChangedListener(
9166 @NonNull @CallbackExecutor Executor executor,
9167 @NonNull OnCommunicationDeviceChangedListener listener) {
Jean-Michel Trivi54d129f2021-12-30 17:43:47 -08009168 mCommDeviceChangedListenerMgr.addListener(
9169 executor, listener, "addOnCommunicationDeviceChangedListener",
9170 () -> new CommunicationDeviceDispatcherStub());
Eric Laurentb36d4a12020-10-09 09:52:49 -07009171 }
9172
9173 /**
9174 * Removes a previously added listener of changes to the communication audio device.
Eric Laurent7412f572021-02-11 15:10:31 +01009175 * See {@link #setCommunicationDevice(AudioDeviceInfo)}.
Eric Laurentb36d4a12020-10-09 09:52:49 -07009176 * @param listener
9177 */
9178 public void removeOnCommunicationDeviceChangedListener(
9179 @NonNull OnCommunicationDeviceChangedListener listener) {
Jean-Michel Trivi54d129f2021-12-30 17:43:47 -08009180 mCommDeviceChangedListenerMgr.removeListener(listener,
9181 "removeOnCommunicationDeviceChangedListener");
Eric Laurentb36d4a12020-10-09 09:52:49 -07009182 }
9183
Eric Laurentb36d4a12020-10-09 09:52:49 -07009184 private final class CommunicationDeviceDispatcherStub
Jean-Michel Trivi54d129f2021-12-30 17:43:47 -08009185 extends ICommunicationDeviceDispatcher.Stub implements CallbackUtil.DispatcherStub {
Eric Laurentb36d4a12020-10-09 09:52:49 -07009186
Jean-Michel Trivi54d129f2021-12-30 17:43:47 -08009187 @Override
Jean-Michel Trivi91f0baa2021-11-11 16:31:32 -08009188 public void register(boolean register) {
Eric Laurentb36d4a12020-10-09 09:52:49 -07009189 try {
Jean-Michel Trivi91f0baa2021-11-11 16:31:32 -08009190 if (register) {
9191 getService().registerCommunicationDeviceDispatcher(this);
9192 } else {
9193 getService().unregisterCommunicationDeviceDispatcher(this);
Eric Laurentb36d4a12020-10-09 09:52:49 -07009194 }
Jean-Michel Trivi91f0baa2021-11-11 16:31:32 -08009195 } catch (RemoteException e) {
9196 e.rethrowFromSystemServer();
Eric Laurentb36d4a12020-10-09 09:52:49 -07009197 }
9198 }
Eric Laurentb36d4a12020-10-09 09:52:49 -07009199
Jean-Michel Trivi91f0baa2021-11-11 16:31:32 -08009200 @Override
Jean-Michel Trivi91f0baa2021-11-11 16:31:32 -08009201 public void dispatchCommunicationDeviceChanged(int portId) {
9202 AudioDeviceInfo device = getDeviceForPortId(portId, GET_DEVICES_OUTPUTS);
Jean-Michel Trivi54d129f2021-12-30 17:43:47 -08009203 mCommDeviceChangedListenerMgr.callListeners(
Jean-Michel Trivi91f0baa2021-11-11 16:31:32 -08009204 (listener) -> listener.onCommunicationDeviceChanged(device));
Eric Laurentb36d4a12020-10-09 09:52:49 -07009205 }
Eric Laurentb36d4a12020-10-09 09:52:49 -07009206 }
9207
Eric Laurent78eef3a2021-11-09 16:10:42 +01009208
9209 /**
9210 * @hide
9211 * Indicates if the platform allows accessing the uplink and downlink audio of an ongoing
9212 * PSTN call.
9213 * When true, {@link getCallUplinkInjectionAudioTrack(AudioFormat)} can be used to obtain
9214 * an AudioTrack for call uplink audio injection and
9215 * {@link getCallDownlinkExtractionAudioRecord(AudioFormat)} can be used to obtain
9216 * an AudioRecord for call downlink audio extraction.
9217 * @return true if PSTN call audio is accessible, false otherwise.
9218 */
9219 @TestApi
9220 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00009221 @RequiresPermission(Manifest.permission.CALL_AUDIO_INTERCEPTION)
Eric Laurent78eef3a2021-11-09 16:10:42 +01009222 public boolean isPstnCallAudioInterceptable() {
9223 final IAudioService service = getService();
9224 try {
9225 return service.isPstnCallAudioInterceptable();
9226 } catch (RemoteException e) {
9227 throw e.rethrowFromSystemServer();
9228 }
9229 }
9230
9231 /** @hide */
9232 @IntDef(flag = false, prefix = "CALL_REDIRECT_", value = {
9233 CALL_REDIRECT_NONE,
9234 CALL_REDIRECT_PSTN,
9235 CALL_REDIRECT_VOIP }
9236 )
9237 @Retention(RetentionPolicy.SOURCE)
9238 public @interface CallRedirectionMode {}
9239
9240 /**
9241 * Not used for call redirection
9242 * @hide
9243 */
9244 public static final int CALL_REDIRECT_NONE = 0;
9245 /**
9246 * Used to redirect PSTN call
9247 * @hide
9248 */
9249 public static final int CALL_REDIRECT_PSTN = 1;
9250 /**
9251 * Used to redirect VoIP call
9252 * @hide
9253 */
9254 public static final int CALL_REDIRECT_VOIP = 2;
9255
9256
9257 private @CallRedirectionMode int getCallRedirectMode() {
9258 int mode = getMode();
9259 if (mode == MODE_IN_CALL || mode == MODE_CALL_SCREENING
9260 || mode == MODE_CALL_REDIRECT) {
9261 return CALL_REDIRECT_PSTN;
9262 } else if (mode == MODE_IN_COMMUNICATION || mode == MODE_COMMUNICATION_REDIRECT) {
9263 return CALL_REDIRECT_VOIP;
9264 }
9265 return CALL_REDIRECT_NONE;
9266 }
9267
9268 private void checkCallRedirectionFormat(AudioFormat format, boolean isOutput) {
9269 if (format.getEncoding() != AudioFormat.ENCODING_PCM_16BIT
9270 && format.getEncoding() != AudioFormat.ENCODING_PCM_FLOAT) {
9271 throw new UnsupportedOperationException(" Unsupported encoding ");
9272 }
9273 if (format.getSampleRate() < 8000
9274 || format.getSampleRate() > 48000) {
9275 throw new UnsupportedOperationException(" Unsupported sample rate ");
9276 }
9277 if (isOutput && format.getChannelMask() != AudioFormat.CHANNEL_OUT_MONO
9278 && format.getChannelMask() != AudioFormat.CHANNEL_OUT_STEREO) {
9279 throw new UnsupportedOperationException(" Unsupported output channel mask ");
9280 }
9281 if (!isOutput && format.getChannelMask() != AudioFormat.CHANNEL_IN_MONO
9282 && format.getChannelMask() != AudioFormat.CHANNEL_IN_STEREO) {
9283 throw new UnsupportedOperationException(" Unsupported input channel mask ");
9284 }
9285 }
9286
9287 class CallIRedirectionClientInfo {
9288 public WeakReference trackOrRecord;
9289 public int redirectMode;
9290 }
9291
9292 private Object mCallRedirectionLock = new Object();
9293 @GuardedBy("mCallRedirectionLock")
9294 private CallInjectionModeChangedListener mCallRedirectionModeListener;
9295 @GuardedBy("mCallRedirectionLock")
9296 private ArrayList<CallIRedirectionClientInfo> mCallIRedirectionClients;
9297
9298 /**
9299 * @hide
9300 * Returns an AudioTrack that can be used to inject audio to an active call uplink.
9301 * This can be used for functions like call screening or call audio redirection and is reserved
9302 * to system apps with privileged permission.
9303 * @param format the desired audio format for audio playback.
9304 * p>Formats accepted are:
9305 * <ul>
9306 * <li><em>Sampling rate</em> - 8kHz to 48kHz. </li>
9307 * <li><em>Channel mask</em> - Mono or Stereo </li>
9308 * <li><em>Sample format</em> - PCM 16 bit or FLOAT 32 bit </li>
9309 * </ul>
9310 *
9311 * @return The AudioTrack used for audio injection
9312 * @throws NullPointerException if AudioFormat argument is null.
9313 * @throws UnsupportedOperationException if on unsupported AudioFormat is specified.
9314 * @throws IllegalArgumentException if an invalid AudioFormat is specified.
9315 * @throws SecurityException if permission CALL_AUDIO_INTERCEPTION is missing .
9316 * @throws IllegalStateException if current audio mode is not MODE_IN_CALL,
9317 * MODE_IN_COMMUNICATION, MODE_CALL_SCREENING, MODE_CALL_REDIRECT
9318 * or MODE_COMMUNICATION_REDIRECT.
9319 */
9320 @TestApi
9321 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00009322 @RequiresPermission(Manifest.permission.CALL_AUDIO_INTERCEPTION)
Eric Laurent78eef3a2021-11-09 16:10:42 +01009323 public @NonNull AudioTrack getCallUplinkInjectionAudioTrack(@NonNull AudioFormat format) {
9324 Objects.requireNonNull(format);
9325 checkCallRedirectionFormat(format, true /* isOutput */);
9326
9327 AudioTrack track = null;
9328 int redirectMode = getCallRedirectMode();
9329 if (redirectMode == CALL_REDIRECT_NONE) {
9330 throw new IllegalStateException(
9331 " not available in mode " + AudioSystem.modeToString(getMode()));
9332 } else if (redirectMode == CALL_REDIRECT_PSTN && !isPstnCallAudioInterceptable()) {
9333 throw new UnsupportedOperationException(" PSTN Call audio not accessible ");
9334 }
9335
9336 track = new AudioTrack.Builder()
9337 .setAudioAttributes(new AudioAttributes.Builder()
9338 .setSystemUsage(AudioAttributes.USAGE_CALL_ASSISTANT)
9339 .setContentType(AudioAttributes.CONTENT_TYPE_SPEECH)
9340 .build())
9341 .setAudioFormat(format)
9342 .setCallRedirectionMode(redirectMode)
9343 .build();
9344
9345 if (track != null && track.getState() != AudioTrack.STATE_UNINITIALIZED) {
9346 synchronized (mCallRedirectionLock) {
9347 if (mCallRedirectionModeListener == null) {
9348 mCallRedirectionModeListener = new CallInjectionModeChangedListener();
9349 try {
9350 addOnModeChangedListener(
9351 Executors.newSingleThreadExecutor(), mCallRedirectionModeListener);
9352 } catch (Exception e) {
9353 Log.e(TAG, "addOnModeChangedListener failed with exception: " + e);
9354 mCallRedirectionModeListener = null;
9355 throw new UnsupportedOperationException(" Cannot register mode listener ");
9356 }
9357 mCallIRedirectionClients = new ArrayList<CallIRedirectionClientInfo>();
9358 }
9359 CallIRedirectionClientInfo info = new CallIRedirectionClientInfo();
9360 info.redirectMode = redirectMode;
9361 info.trackOrRecord = new WeakReference<AudioTrack>(track);
9362 mCallIRedirectionClients.add(info);
9363 }
9364 } else {
9365 throw new UnsupportedOperationException(" Cannot create the AudioTrack");
9366 }
9367 return track;
9368 }
9369
9370 /**
9371 * @hide
9372 * Returns an AudioRecord that can be used to extract audio from an active call downlink.
9373 * This can be used for functions like call screening or call audio redirection and is reserved
9374 * to system apps with privileged permission.
9375 * @param format the desired audio format for audio capture.
9376 *<p>Formats accepted are:
9377 * <ul>
9378 * <li><em>Sampling rate</em> - 8kHz to 48kHz. </li>
9379 * <li><em>Channel mask</em> - Mono or Stereo </li>
9380 * <li><em>Sample format</em> - PCM 16 bit or FLOAT 32 bit </li>
9381 * </ul>
9382 *
9383 * @return The AudioRecord used for audio extraction
9384 * @throws UnsupportedOperationException if on unsupported AudioFormat is specified.
9385 * @throws IllegalArgumentException if an invalid AudioFormat is specified.
9386 * @throws NullPointerException if AudioFormat argument is null.
9387 * @throws SecurityException if permission CALL_AUDIO_INTERCEPTION is missing .
9388 * @throws IllegalStateException if current audio mode is not MODE_IN_CALL,
9389 * MODE_IN_COMMUNICATION, MODE_CALL_SCREENING, MODE_CALL_REDIRECT
9390 * or MODE_COMMUNICATION_REDIRECT.
9391 */
9392 @TestApi
9393 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00009394 @RequiresPermission(Manifest.permission.CALL_AUDIO_INTERCEPTION)
Eric Laurent78eef3a2021-11-09 16:10:42 +01009395 public @NonNull AudioRecord getCallDownlinkExtractionAudioRecord(@NonNull AudioFormat format) {
9396 Objects.requireNonNull(format);
9397 checkCallRedirectionFormat(format, false /* isOutput */);
9398
9399 AudioRecord record = null;
9400 int redirectMode = getCallRedirectMode();
9401 if (redirectMode == CALL_REDIRECT_NONE) {
9402 throw new IllegalStateException(
9403 " not available in mode " + AudioSystem.modeToString(getMode()));
9404 } else if (redirectMode == CALL_REDIRECT_PSTN && !isPstnCallAudioInterceptable()) {
9405 throw new UnsupportedOperationException(" PSTN Call audio not accessible ");
9406 }
9407
9408 record = new AudioRecord.Builder()
9409 .setAudioAttributes(new AudioAttributes.Builder()
9410 .setInternalCapturePreset(MediaRecorder.AudioSource.VOICE_DOWNLINK)
9411 .build())
9412 .setAudioFormat(format)
9413 .setCallRedirectionMode(redirectMode)
9414 .build();
9415
9416 if (record != null && record.getState() != AudioRecord.STATE_UNINITIALIZED) {
9417 synchronized (mCallRedirectionLock) {
9418 if (mCallRedirectionModeListener == null) {
9419 mCallRedirectionModeListener = new CallInjectionModeChangedListener();
9420 try {
9421 addOnModeChangedListener(
9422 Executors.newSingleThreadExecutor(), mCallRedirectionModeListener);
9423 } catch (Exception e) {
9424 Log.e(TAG, "addOnModeChangedListener failed with exception: " + e);
9425 mCallRedirectionModeListener = null;
9426 throw new UnsupportedOperationException(" Cannot register mode listener ");
9427 }
9428 mCallIRedirectionClients = new ArrayList<CallIRedirectionClientInfo>();
9429 }
9430 CallIRedirectionClientInfo info = new CallIRedirectionClientInfo();
9431 info.redirectMode = redirectMode;
9432 info.trackOrRecord = new WeakReference<AudioRecord>(record);
9433 mCallIRedirectionClients.add(info);
9434 }
9435 } else {
9436 throw new UnsupportedOperationException(" Cannot create the AudioRecord");
9437 }
9438 return record;
9439 }
9440
9441 class CallInjectionModeChangedListener implements OnModeChangedListener {
9442 @Override
9443 public void onModeChanged(@AudioMode int mode) {
9444 synchronized (mCallRedirectionLock) {
9445 final ArrayList<CallIRedirectionClientInfo> clientInfos =
9446 (ArrayList<CallIRedirectionClientInfo>) mCallIRedirectionClients.clone();
9447 for (CallIRedirectionClientInfo info : clientInfos) {
9448 Object trackOrRecord = info.trackOrRecord.get();
9449 if (trackOrRecord != null) {
9450 if ((info.redirectMode == CALL_REDIRECT_PSTN
9451 && mode != MODE_IN_CALL && mode != MODE_CALL_SCREENING
9452 && mode != MODE_CALL_REDIRECT)
9453 || (info.redirectMode == CALL_REDIRECT_VOIP
9454 && mode != MODE_IN_COMMUNICATION
9455 && mode != MODE_COMMUNICATION_REDIRECT)) {
9456 if (trackOrRecord instanceof AudioTrack) {
9457 AudioTrack track = (AudioTrack) trackOrRecord;
9458 track.release();
9459 } else {
9460 AudioRecord record = (AudioRecord) trackOrRecord;
9461 record.release();
9462 }
9463 mCallIRedirectionClients.remove(info);
9464 }
9465 }
9466 }
9467 if (mCallIRedirectionClients.isEmpty()) {
9468 try {
9469 if (mCallRedirectionModeListener != null) {
9470 removeOnModeChangedListener(mCallRedirectionModeListener);
9471 }
9472 } catch (Exception e) {
9473 Log.e(TAG, "removeOnModeChangedListener failed with exception: " + e);
9474 } finally {
9475 mCallRedirectionModeListener = null;
9476 mCallIRedirectionClients = null;
9477 }
9478 }
9479 }
9480 }
9481 }
9482
Paul McLeane3383cc2015-05-08 11:41:20 -07009483 //---------------------------------------------------------
Jean-Michel Trivi933bf142021-11-19 16:18:52 -08009484 // audio device connection-dependent muting
9485 /**
9486 * @hide
9487 * Mute a set of playback use cases until a given audio device is connected.
9488 * Automatically unmute upon connection of the device, or after the given timeout, whichever
9489 * happens first.
9490 * @param usagesToMute non-empty array of {@link AudioAttributes} usages (for example
9491 * {@link AudioAttributes#USAGE_MEDIA}) to mute until the
9492 * device connects
9493 * @param device the audio device expected to connect within the timeout duration
9494 * @param timeout the maximum amount of time to wait for the device connection
9495 * @param timeUnit the unit for the timeout
9496 * @throws IllegalStateException when trying to issue the command while another is already in
9497 * progress and hasn't been cancelled by
9498 * {@link #cancelMuteAwaitConnection(AudioDeviceAttributes)}. See
9499 * {@link #getMutingExpectedDevice()} to check if a muting command is active.
9500 * @see #registerMuteAwaitConnectionCallback(Executor, AudioManager.MuteAwaitConnectionCallback)
9501 */
9502 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00009503 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
Jean-Michel Trivi933bf142021-11-19 16:18:52 -08009504 public void muteAwaitConnection(@NonNull int[] usagesToMute,
9505 @NonNull AudioDeviceAttributes device,
9506 long timeout, @NonNull TimeUnit timeUnit) throws IllegalStateException {
9507 if (timeout <= 0) {
9508 throw new IllegalArgumentException("Timeout must be greater than 0");
9509 }
9510 Objects.requireNonNull(usagesToMute);
9511 if (usagesToMute.length == 0) {
9512 throw new IllegalArgumentException("Array of usages to mute cannot be empty");
9513 }
9514 Objects.requireNonNull(device);
9515 Objects.requireNonNull(timeUnit);
9516 try {
9517 getService().muteAwaitConnection(usagesToMute, device, timeUnit.toMillis(timeout));
9518 } catch (RemoteException e) {
9519 throw e.rethrowFromSystemServer();
9520 }
9521 }
9522
9523 /**
9524 * @hide
9525 * Query which audio device, if any, is causing some playback use cases to be muted until it
9526 * connects.
9527 * @return the audio device used in
9528 * {@link #muteAwaitConnection(int[], AudioDeviceAttributes, long, TimeUnit)}, or null
9529 * if there is no active muting command (either because the muting command was not issued
9530 * or because it timed out)
9531 */
9532 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00009533 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
Jean-Michel Trivi933bf142021-11-19 16:18:52 -08009534 public @Nullable AudioDeviceAttributes getMutingExpectedDevice() {
9535 try {
9536 return getService().getMutingExpectedDevice();
9537 } catch (RemoteException e) {
9538 throw e.rethrowFromSystemServer();
9539 }
9540 }
9541
9542 /**
9543 * @hide
9544 * Cancel a {@link #muteAwaitConnection(int[], AudioDeviceAttributes, long, TimeUnit)}
9545 * command.
9546 * @param device the device whose connection was expected when the {@code muteAwaitConnection}
9547 * command was issued.
9548 * @throws IllegalStateException when trying to issue the command for a device whose connection
9549 * is not anticipated by a previous call to
9550 * {@link #muteAwaitConnection(int[], AudioDeviceAttributes, long, TimeUnit)}
9551 */
9552 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00009553 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
Jean-Michel Trivi933bf142021-11-19 16:18:52 -08009554 public void cancelMuteAwaitConnection(@NonNull AudioDeviceAttributes device)
9555 throws IllegalStateException {
9556 Objects.requireNonNull(device);
9557 try {
9558 getService().cancelMuteAwaitConnection(device);
9559 } catch (RemoteException e) {
9560 throw e.rethrowFromSystemServer();
9561 }
9562 }
9563
9564 /**
9565 * @hide
9566 * A callback class to receive events about the muting and unmuting of playback use cases
9567 * conditional on the upcoming connection of an audio device.
9568 * @see #registerMuteAwaitConnectionCallback(Executor, AudioManager.MuteAwaitConnectionCallback)
9569 */
9570 @SystemApi
9571 public abstract static class MuteAwaitConnectionCallback {
9572
9573 /**
9574 * An event where the expected audio device connected
9575 * @see MuteAwaitConnectionCallback#onUnmutedEvent(int, AudioDeviceAttributes, int[])
9576 */
9577 public static final int EVENT_CONNECTION = 1;
9578 /**
9579 * An event where the expected audio device failed connect before the timeout happened
9580 * @see MuteAwaitConnectionCallback#onUnmutedEvent(int, AudioDeviceAttributes, int[])
9581 */
9582 public static final int EVENT_TIMEOUT = 2;
9583 /**
9584 * An event where the {@code muteAwaitConnection()} command
9585 * was cancelled with {@link #cancelMuteAwaitConnection(AudioDeviceAttributes)}
9586 * @see MuteAwaitConnectionCallback#onUnmutedEvent(int, AudioDeviceAttributes, int[])
9587 */
9588 public static final int EVENT_CANCEL = 3;
9589
9590 /** @hide */
9591 @IntDef(flag = false, prefix = "EVENT_", value = {
9592 EVENT_CONNECTION,
9593 EVENT_TIMEOUT,
9594 EVENT_CANCEL }
9595 )
9596 @Retention(RetentionPolicy.SOURCE)
9597 public @interface UnmuteEvent {}
9598
9599 /**
9600 * Called when a number of playback use cases are muted in response to a call to
9601 * {@link #muteAwaitConnection(int[], AudioDeviceAttributes, long, TimeUnit)}.
9602 * @param device the audio device whose connection is expected. Playback use cases are
9603 * unmuted when that device connects
9604 * @param mutedUsages an array of {@link AudioAttributes} usages that describe the affected
9605 * playback use cases.
9606 */
9607 public void onMutedUntilConnection(
9608 @NonNull AudioDeviceAttributes device,
9609 @NonNull int[] mutedUsages) {}
9610
9611 /**
9612 * Called when an event occurred that caused playback uses cases to be unmuted
9613 * @param unmuteEvent the nature of the event
9614 * @param device the device that was expected to connect
9615 * @param mutedUsages the array of {@link AudioAttributes} usages that were muted until
9616 * the event occurred
9617 */
9618 public void onUnmutedEvent(
9619 @UnmuteEvent int unmuteEvent,
9620 @NonNull AudioDeviceAttributes device, @NonNull int[] mutedUsages) {}
9621 }
9622
9623
9624 /**
9625 * @hide
9626 * Register a callback to receive updates on the playback muting conditional on a specific
9627 * audio device connection.
9628 * @param executor the {@link Executor} handling the callback
9629 * @param callback the callback to register
9630 */
9631 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00009632 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
Jean-Michel Trivi933bf142021-11-19 16:18:52 -08009633 public void registerMuteAwaitConnectionCallback(
9634 @NonNull @CallbackExecutor Executor executor,
9635 @NonNull MuteAwaitConnectionCallback callback) {
9636 synchronized (mMuteAwaitConnectionListenerLock) {
9637 final Pair<ArrayList<ListenerInfo<MuteAwaitConnectionCallback>>,
9638 MuteAwaitConnectionDispatcherStub> res =
9639 CallbackUtil.addListener("registerMuteAwaitConnectionCallback",
9640 executor, callback, mMuteAwaitConnectionListeners,
9641 mMuteAwaitConnDispatcherStub,
9642 () -> new MuteAwaitConnectionDispatcherStub(),
9643 stub -> stub.register(true));
9644 mMuteAwaitConnectionListeners = res.first;
9645 mMuteAwaitConnDispatcherStub = res.second;
9646 }
9647 }
9648
9649 /**
9650 * @hide
9651 * Unregister a previously registered callback for playback muting conditional on device
9652 * connection.
9653 * @param callback the callback to unregister
9654 */
9655 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00009656 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
Jean-Michel Trivi933bf142021-11-19 16:18:52 -08009657 public void unregisterMuteAwaitConnectionCallback(
9658 @NonNull MuteAwaitConnectionCallback callback) {
9659 synchronized (mMuteAwaitConnectionListenerLock) {
9660 final Pair<ArrayList<ListenerInfo<MuteAwaitConnectionCallback>>,
9661 MuteAwaitConnectionDispatcherStub> res =
9662 CallbackUtil.removeListener("unregisterMuteAwaitConnectionCallback",
9663 callback, mMuteAwaitConnectionListeners, mMuteAwaitConnDispatcherStub,
9664 stub -> stub.register(false));
9665 mMuteAwaitConnectionListeners = res.first;
9666 mMuteAwaitConnDispatcherStub = res.second;
9667 }
9668 }
9669
Oscar Azucena3ef3f582022-01-31 19:07:14 -08009670 /**
Oscar Azucena88467fe2022-02-15 21:55:11 +00009671 * Add UIDs that can be considered as assistant.
Oscar Azucena3ef3f582022-01-31 19:07:14 -08009672 *
Oscar Azucena88467fe2022-02-15 21:55:11 +00009673 * @param assistantUids UIDs of the services that can be considered as assistant.
Oscar Azucena3ef3f582022-01-31 19:07:14 -08009674 *
9675 * @hide
9676 */
9677 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00009678 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
Oscar Azucena88467fe2022-02-15 21:55:11 +00009679 public void addAssistantServicesUids(@NonNull int[] assistantUids) {
Oscar Azucena3ef3f582022-01-31 19:07:14 -08009680 try {
Oscar Azucena88467fe2022-02-15 21:55:11 +00009681 getService().addAssistantServicesUids(assistantUids);
Oscar Azucena3ef3f582022-01-31 19:07:14 -08009682 } catch (RemoteException e) {
9683 throw e.rethrowFromSystemServer();
9684 }
9685 }
9686
9687 /**
Oscar Azucena88467fe2022-02-15 21:55:11 +00009688 * Remove UIDs that can be considered as assistant.
Oscar Azucena3ef3f582022-01-31 19:07:14 -08009689 *
Oscar Azucena88467fe2022-02-15 21:55:11 +00009690 * @param assistantUids UIDs of the services that should be remove.
Oscar Azucena3ef3f582022-01-31 19:07:14 -08009691 *
9692 * @hide
9693 */
9694 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00009695 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
Oscar Azucena88467fe2022-02-15 21:55:11 +00009696 public void removeAssistantServicesUids(@NonNull int[] assistantUids) {
Oscar Azucena3ef3f582022-01-31 19:07:14 -08009697 try {
Oscar Azucena88467fe2022-02-15 21:55:11 +00009698 getService().removeAssistantServicesUids(assistantUids);
Oscar Azucena3ef3f582022-01-31 19:07:14 -08009699 } catch (RemoteException e) {
9700 throw e.rethrowFromSystemServer();
9701 }
9702 }
9703
9704 /**
Oscar Azucena88467fe2022-02-15 21:55:11 +00009705 * Get the assistants UIDs that been added with the
9706 * {@link #addAssistantServicesUids(int[])} and not yet removed with
9707 * {@link #removeAssistantServicesUids(int[])}
Oscar Azucena3ef3f582022-01-31 19:07:14 -08009708 *
Oscar Azucena3ae33762022-03-04 04:44:59 +00009709 * <p> Note that during native audioserver crash and after boot up the list of assistant
9710 * UIDs will be reset to an empty list (i.e. no UID will be considered as assistant)
9711 * Just after user switch, the list of assistant will also reset to empty.
9712 * In both cases,The component's UID of the assistiant role or assistant setting will be
9713 * automitically added to the list by the audio service.
9714 *
Oscar Azucena88467fe2022-02-15 21:55:11 +00009715 * @return array of assistants UIDs
Oscar Azucena3ef3f582022-01-31 19:07:14 -08009716 *
9717 * @hide
9718 */
9719 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00009720 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
Oscar Azucena88467fe2022-02-15 21:55:11 +00009721 public @NonNull int[] getAssistantServicesUids() {
Oscar Azucena3ef3f582022-01-31 19:07:14 -08009722 try {
9723 int[] uids = getService().getAssistantServicesUids();
Oscar Azucena88467fe2022-02-15 21:55:11 +00009724 return Arrays.copyOf(uids, uids.length);
Oscar Azucena3ef3f582022-01-31 19:07:14 -08009725 } catch (RemoteException e) {
9726 throw e.rethrowFromSystemServer();
9727 }
9728 }
9729
9730 /**
Oscar Azucena88467fe2022-02-15 21:55:11 +00009731 * Sets UIDs that can be considered as active assistant. Calling the API with a new array will
9732 * overwrite previous UIDs. If the array of UIDs is empty then no UID will be considered active.
9733 * In this manner calling the API with an empty array will remove all UIDs previously set.
Oscar Azucena3ef3f582022-01-31 19:07:14 -08009734 *
Oscar Azucena88467fe2022-02-15 21:55:11 +00009735 * @param assistantUids UIDs of the services that can be considered active assistant. Can be
9736 * an empty array, for this no UID will be considered active.
Oscar Azucena3ef3f582022-01-31 19:07:14 -08009737 *
9738 * <p> Note that during audio service crash reset and after boot up the list of active assistant
Oscar Azucena88467fe2022-02-15 21:55:11 +00009739 * UIDs will be reset to an empty list (i.e. no UID will be considered as an active assistant).
Oscar Azucena3ef3f582022-01-31 19:07:14 -08009740 * Just after user switch the list of active assistant will also reset to empty.
9741 *
9742 * @hide
9743 */
9744 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00009745 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
Oscar Azucena88467fe2022-02-15 21:55:11 +00009746 public void setActiveAssistantServiceUids(@NonNull int[] assistantUids) {
Oscar Azucena3ef3f582022-01-31 19:07:14 -08009747 try {
Oscar Azucena88467fe2022-02-15 21:55:11 +00009748 getService().setActiveAssistantServiceUids(assistantUids);
Oscar Azucena3ef3f582022-01-31 19:07:14 -08009749 } catch (RemoteException e) {
9750 throw e.rethrowFromSystemServer();
9751 }
9752 }
9753
9754 /**
Oscar Azucena88467fe2022-02-15 21:55:11 +00009755 * Get active assistant UIDs last set with the
9756 * {@link #setActiveAssistantServiceUids(int[])}
Oscar Azucena3ef3f582022-01-31 19:07:14 -08009757 *
Oscar Azucena88467fe2022-02-15 21:55:11 +00009758 * @return array of active assistants UIDs
Oscar Azucena3ef3f582022-01-31 19:07:14 -08009759 *
9760 * @hide
9761 */
9762 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00009763 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
Oscar Azucena88467fe2022-02-15 21:55:11 +00009764 public @NonNull int[] getActiveAssistantServicesUids() {
Oscar Azucena3ef3f582022-01-31 19:07:14 -08009765 try {
9766 int[] uids = getService().getActiveAssistantServiceUids();
Oscar Azucena88467fe2022-02-15 21:55:11 +00009767 return Arrays.copyOf(uids, uids.length);
Oscar Azucena3ef3f582022-01-31 19:07:14 -08009768 } catch (RemoteException e) {
9769 throw e.rethrowFromSystemServer();
9770 }
9771 }
9772
jiabinfe6b7f12022-02-04 18:45:44 +00009773 /**
Shunkai Yao601b6132022-11-22 01:47:48 +00009774 * Returns an {@link AudioHalVersionInfo} indicating the Audio Hal Version. If there is no audio
9775 * HAL found, null will be returned.
jiabinfe6b7f12022-02-04 18:45:44 +00009776 *
Shunkai Yao601b6132022-11-22 01:47:48 +00009777 * @return @see @link #AudioHalVersionInfo The version of Audio HAL.
jiabinfe6b7f12022-02-04 18:45:44 +00009778 * @hide
9779 */
9780 @TestApi
Shunkai Yao601b6132022-11-22 01:47:48 +00009781 public static @Nullable AudioHalVersionInfo getHalVersion() {
jiabinfe6b7f12022-02-04 18:45:44 +00009782 try {
9783 return getService().getHalVersion();
9784 } catch (RemoteException e) {
9785 Log.e(TAG, "Error querying getHalVersion", e);
9786 throw e.rethrowFromSystemServer();
9787 }
9788 }
9789
jiabin89f87ed2022-12-01 22:55:05 +00009790 //====================================================================
9791 // Preferred mixer attributes
9792
9793 /**
Jiabin Huang11285ff2023-02-03 01:04:58 +00009794 * Returns the {@link AudioMixerAttributes} that can be used to set as preferred mixer
jiabin89f87ed2022-12-01 22:55:05 +00009795 * attributes via {@link #setPreferredMixerAttributes(
9796 * AudioAttributes, AudioDeviceInfo, AudioMixerAttributes)}.
Jiabin Huang11285ff2023-02-03 01:04:58 +00009797 * <p>Note that only USB devices are guaranteed to expose configurable mixer attributes. An
9798 * empty list may be returned for all other types of devices as they may not allow dynamic
9799 * configuration.
jiabin89f87ed2022-12-01 22:55:05 +00009800 *
9801 * @param device the device to query
9802 * @return a list of {@link AudioMixerAttributes} that can be used as preferred mixer attributes
9803 * for the given device.
9804 * @see #setPreferredMixerAttributes(AudioAttributes, AudioDeviceInfo, AudioMixerAttributes)
9805 */
9806 @NonNull
9807 public List<AudioMixerAttributes> getSupportedMixerAttributes(@NonNull AudioDeviceInfo device) {
9808 Objects.requireNonNull(device);
9809 List<AudioMixerAttributes> mixerAttrs = new ArrayList<>();
9810 return (AudioSystem.getSupportedMixerAttributes(device.getId(), mixerAttrs)
9811 == AudioSystem.SUCCESS) ? mixerAttrs : new ArrayList<>();
9812 }
9813
9814 /**
9815 * Configures the mixer attributes for a particular {@link AudioAttributes} over a given
9816 * {@link AudioDeviceInfo}.
Jiabin Huang11285ff2023-02-03 01:04:58 +00009817 * <p>Call {@link #getSupportedMixerAttributes(AudioDeviceInfo)} to determine which mixer
9818 * attributes can be used with the given device.
jiabin89f87ed2022-12-01 22:55:05 +00009819 * <p>The ownership of preferred mixer attributes is recognized by uid. When a playback from the
9820 * same uid is routed to the given audio device when calling this API, the output mixer/stream
9821 * will be configured with the values previously set via this API.
9822 * <p>Use {@link #clearPreferredMixerAttributes(AudioAttributes, AudioDeviceInfo)}
9823 * to cancel setting mixer attributes for this {@link AudioAttributes}.
9824 *
9825 * @param attributes the {@link AudioAttributes} whose mixer attributes should be set.
9826 * Currently, only {@link AudioAttributes#USAGE_MEDIA} is supported. When
9827 * playing audio targeted at the given device, use the same attributes for
9828 * playback.
9829 * @param device the device to be routed. Currently, only USB device will be allowed.
9830 * @param mixerAttributes the preferred mixer attributes. When playing audio targeted at the
9831 * given device, use the same {@link AudioFormat} for both playback
9832 * and the mixer attributes.
9833 * @return true only if the preferred mixer attributes are set successfully.
9834 * @see #getPreferredMixerAttributes(AudioAttributes, AudioDeviceInfo)
9835 * @see #clearPreferredMixerAttributes(AudioAttributes, AudioDeviceInfo)
9836 */
Jean-Michel Trivic4557822023-01-23 18:19:52 +00009837 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_SETTINGS)
jiabin89f87ed2022-12-01 22:55:05 +00009838 public boolean setPreferredMixerAttributes(@NonNull AudioAttributes attributes,
9839 @NonNull AudioDeviceInfo device,
9840 @NonNull AudioMixerAttributes mixerAttributes) {
9841 Objects.requireNonNull(attributes);
9842 Objects.requireNonNull(device);
9843 Objects.requireNonNull(mixerAttributes);
9844 try {
9845 final int status = getService().setPreferredMixerAttributes(
9846 attributes, device.getId(), mixerAttributes);
9847 return status == AudioSystem.SUCCESS;
9848 } catch (RemoteException e) {
9849 throw e.rethrowFromSystemServer();
9850 }
9851 }
9852
9853 /**
9854 * Returns current preferred mixer attributes that is set via
9855 * {@link #setPreferredMixerAttributes(AudioAttributes, AudioDeviceInfo, AudioMixerAttributes)}
9856 *
9857 * @param attributes the {@link AudioAttributes} whose mixer attributes should be set.
9858 * @param device the expected routing device
9859 * @return the preferred mixer attributes, which will be null when no preferred mixer attributes
9860 * have been set, or when they have been cleared.
9861 * @see #setPreferredMixerAttributes(AudioAttributes, AudioDeviceInfo, AudioMixerAttributes)
9862 * @see #clearPreferredMixerAttributes(AudioAttributes, AudioDeviceInfo)
9863 */
9864 @Nullable
9865 public AudioMixerAttributes getPreferredMixerAttributes(
9866 @NonNull AudioAttributes attributes,
9867 @NonNull AudioDeviceInfo device) {
9868 Objects.requireNonNull(attributes);
9869 Objects.requireNonNull(device);
9870 List<AudioMixerAttributes> mixerAttrList = new ArrayList<>();
9871 int ret = AudioSystem.getPreferredMixerAttributes(
9872 attributes, device.getId(), mixerAttrList);
9873 if (ret == AudioSystem.SUCCESS) {
9874 return mixerAttrList.isEmpty() ? null : mixerAttrList.get(0);
9875 } else {
9876 Log.e(TAG, "Failed calling getPreferredMixerAttributes, ret=" + ret);
9877 return null;
9878 }
9879 }
9880
9881 /**
9882 * Clears the current preferred mixer attributes that were previously set via
9883 * {@link #setPreferredMixerAttributes(AudioAttributes, AudioDeviceInfo, AudioMixerAttributes)}
9884 *
9885 * @param attributes the {@link AudioAttributes} whose mixer attributes should be cleared.
9886 * @param device the expected routing device
9887 * @return true only if the preferred mixer attributes are removed successfully.
9888 * @see #setPreferredMixerAttributes(AudioAttributes, AudioDeviceInfo, AudioMixerAttributes)
9889 * @see #getPreferredMixerAttributes(AudioAttributes, AudioDeviceInfo)
9890 */
Jean-Michel Trivic4557822023-01-23 18:19:52 +00009891 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_SETTINGS)
jiabin89f87ed2022-12-01 22:55:05 +00009892 public boolean clearPreferredMixerAttributes(
9893 @NonNull AudioAttributes attributes,
9894 @NonNull AudioDeviceInfo device) {
9895 Objects.requireNonNull(attributes);
9896 Objects.requireNonNull(device);
9897 try {
9898 final int status = getService().clearPreferredMixerAttributes(
9899 attributes, device.getId());
9900 return status == AudioSystem.SUCCESS;
9901 } catch (RemoteException e) {
9902 throw e.rethrowFromSystemServer();
9903 }
9904 }
9905
9906 /**
9907 * Interface to be notified of changes in the preferred mixer attributes.
9908 * <p>Note that this listener will only be invoked whenever
9909 * {@link #setPreferredMixerAttributes(AudioAttributes, AudioDeviceInfo, AudioMixerAttributes)}
9910 * or {@link #clearPreferredMixerAttributes(AudioAttributes, AudioDeviceInfo)} or device
9911 * disconnection causes a change in preferred mixer attributes.
9912 * @see #setPreferredMixerAttributes(AudioAttributes, AudioDeviceInfo, AudioMixerAttributes)
9913 * @see #clearPreferredMixerAttributes(AudioAttributes, AudioDeviceInfo)
9914 */
9915 public interface OnPreferredMixerAttributesChangedListener {
9916 /**
9917 * Called on the listener to indicate that the preferred mixer attributes for the audio
9918 * attributes over the given device has changed.
9919 *
9920 * @param attributes the audio attributes for playback
9921 * @param device the targeted device
9922 * @param mixerAttributes the {@link AudioMixerAttributes} that contains information for
9923 * preferred mixer attributes or null if preferred mixer attributes
9924 * is cleared
9925 */
9926 void onPreferredMixerAttributesChanged(
9927 @NonNull AudioAttributes attributes,
9928 @NonNull AudioDeviceInfo device,
9929 @Nullable AudioMixerAttributes mixerAttributes);
9930 }
9931
9932 /**
9933 * Manage the {@link OnPreferredMixerAttributesChangedListener} listeners and the
9934 * {@link PreferredMixerAttributesDispatcherStub}.
9935 */
9936 private final CallbackUtil.LazyListenerManager<OnPreferredMixerAttributesChangedListener>
9937 mPrefMixerAttributesListenerMgr = new CallbackUtil.LazyListenerManager();
9938
9939 /**
9940 * Adds a listener for being notified of changes to the preferred mixer attributes.
9941 * @param executor the executor to execute the callback
9942 * @param listener the listener to be notified of changes in the preferred mixer attributes.
9943 */
9944 public void addOnPreferredMixerAttributesChangedListener(
9945 @NonNull @CallbackExecutor Executor executor,
9946 @NonNull OnPreferredMixerAttributesChangedListener listener) {
9947 Objects.requireNonNull(executor);
9948 Objects.requireNonNull(listener);
9949 mPrefMixerAttributesListenerMgr.addListener(executor, listener,
9950 "addOnPreferredMixerAttributesChangedListener",
9951 () -> new PreferredMixerAttributesDispatcherStub());
9952 }
9953
9954 /**
9955 * Removes a previously added listener of changes to the preferred mixer attributes.
9956 * @param listener the listener to be notified of changes in the preferred mixer attributes,
9957 * which were added via {@link #addOnPreferredMixerAttributesChangedListener(
9958 * Executor, OnPreferredMixerAttributesChangedListener)}.
9959 */
9960 public void removeOnPreferredMixerAttributesChangedListener(
9961 @NonNull OnPreferredMixerAttributesChangedListener listener) {
9962 Objects.requireNonNull(listener);
9963 mPrefMixerAttributesListenerMgr.removeListener(listener,
9964 "removeOnPreferredMixerAttributesChangedListener");
9965 }
9966
9967 private final class PreferredMixerAttributesDispatcherStub
9968 extends IPreferredMixerAttributesDispatcher.Stub
9969 implements CallbackUtil.DispatcherStub {
9970
9971 @Override
9972 public void register(boolean register) {
9973 try {
9974 if (register) {
9975 getService().registerPreferredMixerAttributesDispatcher(this);
9976 } else {
9977 getService().unregisterPreferredMixerAttributesDispatcher(this);
9978 }
9979 } catch (RemoteException e) {
9980 e.rethrowFromSystemServer();
9981 }
9982 }
9983
9984 @Override
9985 public void dispatchPrefMixerAttributesChanged(@NonNull AudioAttributes attr,
9986 int deviceId,
9987 @Nullable AudioMixerAttributes mixerAttr) {
9988 // TODO: If the device is disconnected, we may not be able to find the device with
9989 // given device id. We need a better to carry the device information via binder.
9990 AudioDeviceInfo device = getDeviceForPortId(deviceId, GET_DEVICES_OUTPUTS);
9991 if (device == null) {
9992 Log.d(TAG, "Drop preferred mixer attributes changed as the device("
9993 + deviceId + ") is disconnected");
9994 return;
9995 }
9996 mPrefMixerAttributesListenerMgr.callListeners(
9997 (listener) -> listener.onPreferredMixerAttributesChanged(
9998 attr, device, mixerAttr));
9999 }
10000 }
10001
Eric Laurent3c474bc2022-12-16 17:24:32 +010010002 /**
10003 * Requests if the implementation supports controlling the latency modes
10004 * over the Bluetooth A2DP or LE Audio links.
10005 *
10006 * @return true if supported, false otherwise
10007 *
10008 * @hide
10009 */
10010 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +000010011 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
Eric Laurent3c474bc2022-12-16 17:24:32 +010010012 public boolean supportsBluetoothVariableLatency() {
10013 try {
10014 return getService().supportsBluetoothVariableLatency();
10015 } catch (RemoteException e) {
10016 throw e.rethrowFromSystemServer();
10017 }
10018 }
10019
10020 /**
10021 * Enables or disables the variable Bluetooth latency control mechanism in the
10022 * audio framework and the audio HAL. This does not apply to the latency mode control
10023 * on the spatializer output as this is a built-in feature.
10024 *
10025 * @hide
10026 */
10027 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +000010028 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
Eric Laurent3c474bc2022-12-16 17:24:32 +010010029 public void setBluetoothVariableLatencyEnabled(boolean enabled) {
10030 try {
10031 getService().setBluetoothVariableLatencyEnabled(enabled);
10032 } catch (RemoteException e) {
10033 throw e.rethrowFromSystemServer();
10034 }
10035 }
10036
10037 /**
10038 * Indicates if the variable Bluetooth latency control mechanism is enabled or disabled.
10039 * @hide
10040 */
10041 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +000010042 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
Eric Laurent3c474bc2022-12-16 17:24:32 +010010043 public boolean isBluetoothVariableLatencyEnabled() {
10044 try {
10045 return getService().isBluetoothVariableLatencyEnabled();
10046 } catch (RemoteException e) {
10047 throw e.rethrowFromSystemServer();
10048 }
10049 }
10050
jiabin89f87ed2022-12-01 22:55:05 +000010051 //====================================================================
Jean-Michel Trivi5017dd82023-01-19 18:51:19 +000010052 // Stream aliasing changed listener, getter for stream alias or independent streams
10053
10054 /**
10055 * manages the stream aliasing listeners and StreamAliasingDispatcherStub
10056 */
10057 private final CallbackUtil.LazyListenerManager<Runnable> mStreamAliasingListenerMgr =
10058 new CallbackUtil.LazyListenerManager();
10059
10060
10061 final class StreamAliasingDispatcherStub extends IStreamAliasingDispatcher.Stub
10062 implements CallbackUtil.DispatcherStub {
10063
10064 @Override
10065 public void register(boolean register) {
10066 try {
10067 getService().registerStreamAliasingDispatcher(this, register);
10068 } catch (RemoteException e) {
10069 e.rethrowFromSystemServer();
10070 }
10071 }
10072
10073 @Override
10074 public void dispatchStreamAliasingChanged() {
10075 mStreamAliasingListenerMgr.callListeners((listener) -> listener.run());
10076 }
10077 }
10078
10079 /**
10080 * @hide
10081 * Adds a listener to be notified of changes to volume stream type aliasing.
10082 * See {@link #getIndependentStreamTypes()} and {@link #getStreamTypeAlias(int)}
10083 * @param executor the Executor running the listener
10084 * @param onStreamAliasingChangedListener the listener to add for the aliasing changes
10085 */
10086 @SystemApi
Jean-Michel Trivi10fd2d72023-02-13 18:06:36 +000010087 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED)
Jean-Michel Trivi5017dd82023-01-19 18:51:19 +000010088 public void addOnStreamAliasingChangedListener(
10089 @NonNull @CallbackExecutor Executor executor,
10090 @NonNull Runnable onStreamAliasingChangedListener) {
10091 mStreamAliasingListenerMgr.addListener(executor, onStreamAliasingChangedListener,
10092 "addOnStreamAliasingChangedListener",
10093 () -> new StreamAliasingDispatcherStub());
10094 }
10095
10096 /**
10097 * @hide
10098 * Removes a previously added listener for changes to stream aliasing.
10099 * See {@link #getIndependentStreamTypes()} and {@link #getStreamTypeAlias(int)}
10100 * @see #addOnStreamAliasingChangedListener(Executor, Runnable)
10101 * @param onStreamAliasingChangedListener the previously added listener of aliasing changes
10102 */
10103 @SystemApi
Jean-Michel Trivi10fd2d72023-02-13 18:06:36 +000010104 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED)
Jean-Michel Trivi5017dd82023-01-19 18:51:19 +000010105 public void removeOnStreamAliasingChangedListener(
10106 @NonNull Runnable onStreamAliasingChangedListener) {
10107 mStreamAliasingListenerMgr.removeListener(onStreamAliasingChangedListener,
10108 "removeOnStreamAliasingChangedListener");
10109 }
10110
10111 /**
10112 * @hide
10113 * Test method to temporarily override whether STREAM_NOTIFICATION is aliased to STREAM_RING,
10114 * volumes will be updated in case of a change.
10115 * @param isAliased if true, STREAM_NOTIFICATION is aliased to STREAM_RING
10116 */
10117 @TestApi
Jean-Michel Trivi10fd2d72023-02-13 18:06:36 +000010118 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED)
Jean-Michel Trivi5017dd82023-01-19 18:51:19 +000010119 public void setNotifAliasRingForTest(boolean isAliased) {
10120 final IAudioService service = getService();
10121 try {
10122 service.setNotifAliasRingForTest(isAliased);
10123 } catch (RemoteException e) {
10124 throw e.rethrowFromSystemServer();
10125 }
10126 }
10127
10128 /**
10129 * @hide
10130 * Return the list of independent stream types for volume control.
10131 * A stream type is considered independent when the volume changes of that type do not
10132 * affect any other independent volume control stream type.
10133 * An independent stream type is its own alias when using {@link #getStreamTypeAlias(int)}.
Jean-Michel Trivif8d51e22023-03-08 23:57:03 +000010134 * @return list of independent stream types, where each value can be one of
10135 * {@link #STREAM_VOICE_CALL}, {@link #STREAM_SYSTEM}, {@link #STREAM_RING},
10136 * {@link #STREAM_MUSIC}, {@link #STREAM_ALARM}, {@link #STREAM_NOTIFICATION},
10137 * {@link #STREAM_DTMF} and {@link #STREAM_ACCESSIBILITY}.
Jean-Michel Trivi5017dd82023-01-19 18:51:19 +000010138 */
10139 @SystemApi
Jean-Michel Trivi10fd2d72023-02-13 18:06:36 +000010140 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED)
Jean-Michel Trivi5017dd82023-01-19 18:51:19 +000010141 public @NonNull List<Integer> getIndependentStreamTypes() {
10142 final IAudioService service = getService();
10143 try {
10144 return service.getIndependentStreamTypes();
10145 } catch (RemoteException e) {
10146 throw e.rethrowFromSystemServer();
10147 }
10148 }
10149
10150 /**
10151 * @hide
10152 * Return the stream type that a given stream is aliased to.
10153 * A stream alias means that any change to the source stream will also be applied to the alias,
10154 * and vice-versa.
10155 * If a stream is independent (i.e. part of the stream types returned by
10156 * {@link #getIndependentStreamTypes()}), its alias is itself.
10157 * @param sourceStreamType the stream type to query for the alias.
10158 * @return the stream type the source type is aliased to.
10159 */
10160 @SystemApi
Jean-Michel Trivi10fd2d72023-02-13 18:06:36 +000010161 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED)
Jean-Michel Trivi5017dd82023-01-19 18:51:19 +000010162 public @PublicStreamTypes int getStreamTypeAlias(@PublicStreamTypes int sourceStreamType) {
10163 final IAudioService service = getService();
10164 try {
10165 return service.getStreamTypeAlias(sourceStreamType);
10166 } catch (RemoteException e) {
10167 throw e.rethrowFromSystemServer();
10168 }
10169 }
10170
10171 /**
10172 * @hide
10173 * Returns whether the system uses {@link AudioVolumeGroup} for volume control
10174 * @return true when volume control is performed through volume groups, false if it uses
10175 * stream types.
10176 */
10177 @TestApi
Jean-Michel Trivi10fd2d72023-02-13 18:06:36 +000010178 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED)
Jean-Michel Trivi5017dd82023-01-19 18:51:19 +000010179 public boolean isVolumeControlUsingVolumeGroups() {
10180 final IAudioService service = getService();
10181 try {
10182 return service.isVolumeControlUsingVolumeGroups();
10183 } catch (RemoteException e) {
10184 throw e.rethrowFromSystemServer();
10185 }
10186 }
10187
Jean-Michel Trivia97cd682023-12-15 08:43:35 -080010188 /**
10189 * @hide
10190 * Checks whether a notification sound should be played or not, as reported by the state
10191 * of the audio framework. Querying whether playback should proceed is favored over
10192 * playing and letting the sound be muted or not.
10193 * @param aa the {@link AudioAttributes} of the notification about to maybe play
10194 * @return true if the audio framework state is such that the notification should be played
10195 * because at time of checking, and the notification will be heard,
10196 * false otherwise
10197 */
10198 @TestApi
10199 @FlaggedApi(FLAG_FOCUS_EXCLUSIVE_WITH_RECORDING)
10200 @RequiresPermission(android.Manifest.permission.QUERY_AUDIO_STATE)
10201 public boolean shouldNotificationSoundPlay(@NonNull final AudioAttributes aa) {
10202 final IAudioService service = getService();
10203 try {
10204 return service.shouldNotificationSoundPlay(Objects.requireNonNull(aa));
10205 } catch (RemoteException e) {
10206 throw e.rethrowFromSystemServer();
10207 }
10208 }
10209
Jean-Michel Trivi5017dd82023-01-19 18:51:19 +000010210 //====================================================================
jiabin89f87ed2022-12-01 22:55:05 +000010211 // Mute await connection
10212
Jean-Michel Trivi933bf142021-11-19 16:18:52 -080010213 private final Object mMuteAwaitConnectionListenerLock = new Object();
10214
10215 @GuardedBy("mMuteAwaitConnectionListenerLock")
10216 private @Nullable ArrayList<ListenerInfo<MuteAwaitConnectionCallback>>
10217 mMuteAwaitConnectionListeners;
10218
10219 @GuardedBy("mMuteAwaitConnectionListenerLock")
10220 private MuteAwaitConnectionDispatcherStub mMuteAwaitConnDispatcherStub;
10221
10222 private final class MuteAwaitConnectionDispatcherStub
10223 extends IMuteAwaitConnectionCallback.Stub {
10224 public void register(boolean register) {
10225 try {
10226 getService().registerMuteAwaitConnectionDispatcher(this, register);
10227 } catch (RemoteException e) {
10228 throw e.rethrowFromSystemServer();
10229 }
10230 }
10231
10232 @Override
10233 @SuppressLint("GuardedBy") // lock applied inside callListeners method
10234 public void dispatchOnMutedUntilConnection(AudioDeviceAttributes device,
10235 int[] mutedUsages) {
10236 CallbackUtil.callListeners(mMuteAwaitConnectionListeners,
10237 mMuteAwaitConnectionListenerLock,
10238 (listener) -> listener.onMutedUntilConnection(device, mutedUsages));
10239 }
10240
10241 @Override
10242 @SuppressLint("GuardedBy") // lock applied inside callListeners method
10243 public void dispatchOnUnmutedEvent(int event, AudioDeviceAttributes device,
10244 int[] mutedUsages) {
10245 CallbackUtil.callListeners(mMuteAwaitConnectionListeners,
10246 mMuteAwaitConnectionListenerLock,
10247 (listener) -> listener.onUnmutedEvent(event, device, mutedUsages));
10248 }
10249 }
10250
Jean-Michel Trivi31323ab2023-11-22 17:44:29 +000010251 //====================================================================
10252 // Flag related utilities
10253
10254 private boolean mIsAutomotive = false;
10255
10256 private void initPlatform() {
10257 try {
10258 final Context context = getContext();
10259 if (context != null) {
10260 mIsAutomotive = context.getPackageManager()
10261 .hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE);
10262 }
10263 } catch (Exception e) {
10264 Log.e(TAG, "Error querying system feature for AUTOMOTIVE", e);
10265 }
10266 }
10267
10268 private boolean applyAutoHardening() {
10269 if (mIsAutomotive && autoPublicVolumeApiHardening()) {
10270 return true;
10271 }
10272 return false;
10273 }
10274
Jean-Michel Trivi933bf142021-11-19 16:18:52 -080010275 //---------------------------------------------------------
Paul McLeane3383cc2015-05-08 11:41:20 -070010276 // Inner classes
10277 //--------------------
10278 /**
10279 * Helper class to handle the forwarding of native events to the appropriate listener
10280 * (potentially) handled in a different thread.
10281 */
10282 private class NativeEventHandlerDelegate {
10283 private final Handler mHandler;
10284
Paul McLean03346882015-05-12 15:36:56 -070010285 NativeEventHandlerDelegate(final AudioDeviceCallback callback,
Paul McLeane3383cc2015-05-08 11:41:20 -070010286 Handler handler) {
10287 // find the looper for our new event handler
10288 Looper looper;
10289 if (handler != null) {
10290 looper = handler.getLooper();
10291 } else {
10292 // no given handler, use the looper the addListener call was called in
10293 looper = Looper.getMainLooper();
10294 }
10295
10296 // construct the event handler with this looper
10297 if (looper != null) {
10298 // implement the event handler delegate
10299 mHandler = new Handler(looper) {
10300 @Override
10301 public void handleMessage(Message msg) {
10302 switch(msg.what) {
Paul McLeancbeb8a22015-06-10 08:21:27 -070010303 case MSG_DEVICES_CALLBACK_REGISTERED:
Paul McLean03346882015-05-12 15:36:56 -070010304 case MSG_DEVICES_DEVICES_ADDED:
Paul McLean03346882015-05-12 15:36:56 -070010305 if (callback != null) {
10306 callback.onAudioDevicesAdded((AudioDeviceInfo[])msg.obj);
Paul McLeane3383cc2015-05-08 11:41:20 -070010307 }
10308 break;
Paul McLean03346882015-05-12 15:36:56 -070010309
10310 case MSG_DEVICES_DEVICES_REMOVED:
10311 if (callback != null) {
10312 callback.onAudioDevicesRemoved((AudioDeviceInfo[])msg.obj);
10313 }
10314 break;
10315
Paul McLeane3383cc2015-05-08 11:41:20 -070010316 default:
10317 Log.e(TAG, "Unknown native event type: " + msg.what);
10318 break;
10319 }
10320 }
10321 };
10322 } else {
10323 mHandler = null;
10324 }
10325 }
10326
10327 Handler getHandler() {
10328 return mHandler;
10329 }
10330 }
Carter Hsu2065d1e2022-01-19 19:54:50 +080010331}